refs #5328 mod funcion createTicketRefund #1498

Merged
carlossa merged 11 commits from 5328-abonarTodoTicket into dev 2023-05-30 07:47:48 +00:00
253 changed files with 9131 additions and 6808 deletions
Showing only changes of commit cb664ecec4 - Show all commits

View File

@ -5,11 +5,12 @@ 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).
## [2320.01] - 2023-05-25 ## [2324.01] - 2023-06-08
### Added ### Added
- -
### Changed ### Changed
- -
@ -18,15 +19,45 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [2322.01] - 2023-06-01
### Added
- (Tickets -> Crear Factura) Al facturar se envia automáticamente el pdf al cliente
- (Artículos -> Histórico) Filtro para mostrar lo anterior al inventario
### Changed
- (Trabajadores -> Nuevo trabajador) Los clientes se crean sin 'TR' pero se añade tipo de negocio 'Trabajador'
### Fixed
- (Tickets -> Líneas) Se permite hacer split de líneas al mismo ticket
## [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 ## [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 - (Trabajadores -> Dar de alta) Permite elegir el método de pago
### Changed ### Changed
- (Artículo -> Precio fijado) Modificado el buscador superior por uno lateral - (Artículo -> Precio fijado) Modificado el buscador superior por uno lateral
- (Trabajadores -> Dar de alta) Quitada obligatoriedad del iban
### Fixed ### Fixed
- (Ticket -> Boxing) Arreglado selección de horas - (Ticket -> Boxing) Arreglado selección de horas

View File

@ -4,25 +4,25 @@ module.exports = Self => {
Self.remoteMethodCtx('deliveryNoteEmail', { Self.remoteMethodCtx('deliveryNoteEmail', {
description: 'Sends the delivery note email with an docuware attached PDF', description: 'Sends the delivery note email with an docuware attached PDF',
accessType: 'WRITE', accessType: 'WRITE',
accessScopes: ['docuwareDeliveryNoteEmail'],
accepts: [ accepts: [
{ {
arg: 'id', arg: 'id',
type: 'string', type: 'number',
required: true, required: true,
description: 'The ticket id', description: 'The ticket id',
http: {source: 'path'}
},
{
arg: 'recipient',
type: 'string',
description: 'The recipient email',
required: true,
}, },
{ {
arg: 'recipientId', arg: 'recipientId',
type: 'number', type: 'number',
description: 'The client id', description: 'The client id',
required: false required: true
},
{
arg: 'recipient',
type: 'string',
description: 'The recipient email',
required: false,
} }
], ],
returns: [ returns: [
@ -41,12 +41,13 @@ module.exports = Self => {
} }
], ],
http: { http: {
path: '/:id/delivery-note-email', path: '/delivery-note-email',
verb: 'POST' verb: 'POST'
} }
}); });
Self.deliveryNoteEmail = async(ctx, id) => { Self.deliveryNoteEmail = async(ctx, id, recipientId, recipient) => {
const models = Self.app.models;
const args = Object.assign({}, ctx.args); const args = Object.assign({}, ctx.args);
const params = { const params = {
recipient: args.recipient, recipient: args.recipient,
@ -57,9 +58,14 @@ module.exports = Self => {
for (const param in args) for (const param in args)
params[param] = args[param]; params[param] = args[param];
if (!recipient) {
client = await models.Client.findById(recipientId, {fields: ['email']});
params.recipient = client.email;
}
const email = new Email('delivery-note', params); const email = new Email('delivery-note', params);
const docuwareFile = await Self.app.models.Docuware.download(ctx, id, 'deliveryNote'); const docuwareFile = await models.Docuware.download(ctx, id, 'deliveryNote');
return email.send({ return email.send({
overrideAttachments: true, overrideAttachments: true,

View File

@ -67,7 +67,7 @@ module.exports = Self => {
if (!image) return false; if (!image) return false;
const hasReadRole = models.ImageCollection.hasReadRole(ctx, collection); const hasReadRole = await models.ImageCollection.hasReadRole(ctx, collection);
if (!hasReadRole) if (!hasReadRole)
throw new UserError(`You don't have enough privileges`); throw new UserError(`You don't have enough privileges`);

View File

@ -23,13 +23,7 @@ module.exports = Self => {
let models = Self.app.models; let models = Self.app.models;
let user = await Self.findById(userId, { let user = await Self.findById(userId, {
fields: ['id', 'name', 'nickname', 'email', 'lang'], fields: ['id', 'name', 'nickname', 'email', 'lang']
include: {
relation: 'userConfig',
scope: {
fields: ['darkMode']
}
}
}); });
let roles = await models.RoleMapping.find({ let roles = await models.RoleMapping.find({

View File

@ -9,10 +9,11 @@ module.exports = Self => {
* @return {boolean} True for user with read privileges * @return {boolean} True for user with read privileges
*/ */
Self.hasReadRole = async(ctx, name, options) => { Self.hasReadRole = async(ctx, name, options) => {
const collection = await Self.findOne({where: {name}}, { const collection = await Self.findOne({
include: { include: {
relation: 'readRole' relation: 'readRole'
} },
where: {name}
}, options); }, options);
return await hasRole(ctx, collection, options); return await hasRole(ctx, collection, options);

View File

@ -55,7 +55,7 @@ async function test() {
const JunitReporter = require('jasmine-reporters'); const JunitReporter = require('jasmine-reporters');
jasmine.addReporter(new JunitReporter.JUnitXmlReporter()); jasmine.addReporter(new JunitReporter.JUnitXmlReporter());
jasmine.jasmine.DEFAULT_TIMEOUT_INTERVAL = 5000; jasmine.jasmine.DEFAULT_TIMEOUT_INTERVAL = 90000;
jasmine.exitOnCompletion = true; jasmine.exitOnCompletion = true;
} }

View File

@ -1,9 +1,10 @@
FROM mariadb:10.7.3 FROM mariadb:10.7.5
ENV MYSQL_ROOT_PASSWORD root ENV MYSQL_ROOT_PASSWORD root
ENV TZ Europe/Madrid ENV TZ Europe/Madrid
ARG MOCKDATE=2001-01-01 11:00:00
ARG DEBIAN_FRONTEND=noninteractive ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get update \ RUN apt-get update \
&& apt-get install -y --no-install-recommends curl ca-certificates \ && apt-get install -y --no-install-recommends curl ca-certificates \
&& curl -sL https://apt.verdnatura.es/conf/verdnatura.gpg | apt-key add - \ && curl -sL https://apt.verdnatura.es/conf/verdnatura.gpg | apt-key add - \
@ -31,14 +32,15 @@ COPY \
import-changes.sh \ import-changes.sh \
config.ini \ config.ini \
dump/mysqlPlugins.sql \ dump/mysqlPlugins.sql \
dump/mockDate.sql \
dump/structure.sql \ dump/structure.sql \
dump/mockDate.sql \
dump/dumpedFixtures.sql \ dump/dumpedFixtures.sql \
./ ./
RUN gosu mysql docker-init.sh \ RUN gosu mysql docker-init.sh \
&& docker-dump.sh mysqlPlugins \ && docker-dump.sh mysqlPlugins \
&& docker-dump.sh mockDate \
&& docker-dump.sh structure \ && docker-dump.sh structure \
&& sed -i -e 's/@mockDate/'"$MOCKDATE"'/g' mockDate.sql \
&& docker-dump.sh mockDate \
&& docker-dump.sh dumpedFixtures \ && docker-dump.sh dumpedFixtures \
&& gosu mysql docker-temp-stop.sh && gosu mysql docker-temp-stop.sh

View File

@ -27,7 +27,6 @@ INSERT INTO `salix`.`ACL` (model, property, accessType, permission, principalTyp
('Client', 'summary', '*', 'ALLOW', 'ROLE', 'employee'), ('Client', 'summary', '*', 'ALLOW', 'ROLE', 'employee'),
('Client', 'updateAddress', '*', 'ALLOW', 'ROLE', 'employee'), ('Client', 'updateAddress', '*', 'ALLOW', 'ROLE', 'employee'),
('Client', 'updateFiscalData', '*', 'ALLOW', 'ROLE', 'employee'), ('Client', 'updateFiscalData', '*', 'ALLOW', 'ROLE', 'employee'),
('Client', 'updateUser', '*', 'ALLOW', 'ROLE', 'employee'),
('Client', 'uploadFile', '*', 'ALLOW', 'ROLE', 'employee'), ('Client', 'uploadFile', '*', 'ALLOW', 'ROLE', 'employee'),
('Client', 'campaignMetricsPdf', '*', 'ALLOW', 'ROLE', 'employee'), ('Client', 'campaignMetricsPdf', '*', 'ALLOW', 'ROLE', 'employee'),
('Client', 'campaignMetricsEmail', '*', 'ALLOW', 'ROLE', 'employee'), ('Client', 'campaignMetricsEmail', '*', 'ALLOW', 'ROLE', 'employee'),

View File

@ -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`()));

View File

@ -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 ;

View File

@ -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';

View File

@ -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 ;

View File

@ -0,0 +1,127 @@
DELIMITER $$
$$
CREATE OR REPLACE 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,
origin.classColor,
dest.classColor futureClassColor
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,
st.classColor
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`,
st.classColor
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 ;

View File

@ -0,0 +1,72 @@
DELIMITER $$
$$
CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`ticket_canbePostponed`(vOriginDated DATE, vFutureDated DATE, vWarehouseFk INT)
BEGIN
/**
* Devuelve un listado de tickets susceptibles de fusionarse con otros tickets en el futuro
*
* @param vOriginDated Fecha en cuestión
* @param vFutureDated Fecha en el futuro a sondear
* @param vWarehouseFk Identificador de vn.warehouse
*/
DROP TEMPORARY TABLE IF EXISTS tmp.filter;
CREATE TEMPORARY TABLE tmp.filter
(INDEX (id))
SELECT sv.ticketFk id,
sub2.id futureId,
GROUP_CONCAT(DISTINCT i.itemPackingTypeFk ORDER BY i.itemPackingTypeFk) ipt,
CAST(sum(litros) AS DECIMAL(10,0)) liters,
CAST(count(*) AS DECIMAL(10,0)) `lines`,
st.name state,
sub2.iptd futureIpt,
sub2.state futureState,
t.clientFk,
t.warehouseFk,
ts.alertLevel,
t.shipped,
sub2.shipped futureShipped,
t.workerFk,
st.code stateCode,
sub2.code futureStateCode,
st.classColor
FROM vn.saleVolume sv
JOIN vn.sale s ON s.id = sv.saleFk
JOIN vn.item i ON i.id = s.itemFk
JOIN vn.ticket t ON t.id = sv.ticketFk
JOIN vn.address a ON a.id = t.addressFk
JOIN vn.province p ON p.id = a.provinceFk
JOIN vn.country c ON c.id = p.countryFk
JOIN vn.ticketState ts ON ts.ticketFk = t.id
JOIN vn.state st ON st.id = ts.stateFk
JOIN vn.alertLevel al ON al.id = ts.alertLevel
LEFT JOIN vn.ticketParking tp ON tp.ticketFk = t.id
LEFT JOIN (
SELECT *
FROM (
SELECT
t.addressFk,
t.id,
t.shipped,
st.name state,
st.code code,
GROUP_CONCAT(DISTINCT i.itemPackingTypeFk ORDER BY i.itemPackingTypeFk) iptd
FROM vn.ticket t
JOIN vn.ticketState ts ON ts.ticketFk = t.id
JOIN vn.state st ON st.id = ts.stateFk
JOIN vn.sale s ON s.ticketFk = t.id
JOIN vn.item i ON i.id = s.itemFk
WHERE t.shipped BETWEEN vFutureDated
AND util.dayend(vFutureDated)
AND t.warehouseFk = vWarehouseFk
GROUP BY t.id
) sub
GROUP BY sub.addressFk
) sub2 ON sub2.addressFk = t.addressFk AND t.id != sub2.id
WHERE t.shipped BETWEEN vOriginDated AND util.dayend(vOriginDated)
AND t.warehouseFk = vWarehouseFk
AND al.code = 'FREE'
AND tp.ticketFk IS NULL
GROUP BY sv.ticketFk
HAVING futureId;
END$$
DELIMITER ;

View File

@ -0,0 +1,20 @@
-- vn.defaulter source
CREATE OR REPLACE
ALGORITHM = UNDEFINED VIEW `vn`.`defaulter` AS
select
`d`.`clientFk` AS `clientFk`,
`d`.`created` AS `created`,
`d`.`amount` AS `amount`,
`d`.`defaulterSinced` AS `defaulterSinced`,
`d`.`hasChanged` AS `hasChanged`,
`c`.`countryFk` AS `country`,
`c`.`payMethodFk` AS `payMethod`
from
(((`bs`.`defaulter` `d`
join `vn`.`client` `c` on
(`c`.`id` = `d`.`clientFk`))
join `vn`.`country` `co` on
(`co`.`id` = `c`.`countryFk`))
join `vn`.`payMethod` `pm` on
(`pm`.`id` = `c`.`payMethodFk`));

View File

@ -0,0 +1,7 @@
ALTER TABLE `vn`.`workerConfig` ADD payMethodFk tinyint(3) unsigned NULL;
ALTER TABLE `vn`.`workerConfig` ADD CONSTRAINT workerConfig_FK FOREIGN KEY (roleFk) REFERENCES account.`role`(id) ON DELETE RESTRICT ON UPDATE CASCADE;
ALTER TABLE `vn`.`workerConfig` ADD CONSTRAINT workerConfig_FK_1 FOREIGN KEY (payMethodFk) REFERENCES `vn`.`payMethod`(id) ON DELETE SET NULL ON UPDATE CASCADE;
-- Cuando se apruebe el PR quitar y poner en redmine para hacerse manualmente
UPDATE `vn`.`workerConfig`
SET payMethodFk = 4
WHERE id=1;

View File

@ -0,0 +1,121 @@
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
VALUES
('Ticket', 'editDiscount', 'WRITE', 'ALLOW', 'ROLE', 'claimManager'),
('Ticket', 'editDiscount', 'WRITE', 'ALLOW', 'ROLE', 'salesPerson'),
('Ticket', 'isRoleAdvanced', '*', 'ALLOW', 'ROLE', 'salesAssistant'),
('Ticket', 'isRoleAdvanced', '*', 'ALLOW', 'ROLE', 'deliveryBoss'),
('Ticket', 'isRoleAdvanced', '*', 'ALLOW', 'ROLE', 'buyer'),
('Ticket', 'isRoleAdvanced', '*', 'ALLOW', 'ROLE', 'claimManager'),
('Ticket', 'deleteTicketWithPartPrepared', 'WRITE', 'ALLOW', 'ROLE', 'salesAssistant'),
('Ticket', 'editZone', 'WRITE', 'ALLOW', 'ROLE', 'deliveryBoss'),
('State', 'editableStates', 'READ', 'ALLOW', 'ROLE', 'employee'),
('State', 'seeEditableStates', 'READ', 'ALLOW', 'ROLE', 'administrative'),
('State', 'seeEditableStates', 'READ', 'ALLOW', 'ROLE', 'production'),
('State', 'isSomeEditable', 'READ', 'ALLOW', 'ROLE', 'salesPerson'),
('State', 'isAllEditable', 'READ', 'ALLOW', 'ROLE', 'production'),
('State', 'isAllEditable', 'READ', 'ALLOW', 'ROLE', 'administrative'),
('Agency', 'seeExpired', 'READ', 'ALLOW', 'ROLE', 'administrative'),
('Agency', 'seeExpired', 'READ', 'ALLOW', 'ROLE', 'productionBoss'),
('Claim', 'createAfterDeadline', 'WRITE', 'ALLOW', 'ROLE', 'claimManager'),
('Client', 'editAddressLogifloraAllowed', 'WRITE', 'ALLOW', 'ROLE', 'salesAssistant'),
('Client', 'editFiscalDataWithoutTaxDataCheck', 'WRITE', 'ALLOW', 'ROLE', 'salesAssistant'),
('Client', 'editVerifiedDataWithoutTaxDataCheck', 'WRITE', 'ALLOW', 'ROLE', 'salesAssistant'),
('Client', 'editCredit', 'WRITE', 'ALLOW', 'ROLE', 'financialBoss'),
('Client', 'isNotEditableCredit', 'WRITE', 'ALLOW', 'ROLE', 'financialBoss'),
('InvoiceOut', 'canCreatePdf', 'WRITE', 'ALLOW', 'ROLE', 'invoicing'),
('Supplier', 'editPayMethodCheck', 'WRITE', 'ALLOW', 'ROLE', 'financial'),
('Worker', 'isTeamBoss', 'WRITE', 'ALLOW', 'ROLE', 'teamBoss'),
('Worker', 'forceIsSubordinate', 'READ', 'ALLOW', 'ROLE', 'hr'),
('Claim', 'editState', 'WRITE', 'ALLOW', 'ROLE', 'claimManager');
DELETE FROM `salix`.`ACL`
WHERE
model = 'Claim'
AND property = '*'
AND accessType = '*';
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
VALUES
('Claim', 'find', 'READ', 'ALLOW', 'ROLE', 'salesPerson'),
('Claim', 'findById', 'READ', 'ALLOW', 'ROLE', 'salesPerson'),
('Claim', 'findOne', 'READ', 'ALLOW', 'ROLE', 'salesPerson'),
('Claim', 'getSummary', 'READ', 'ALLOW', 'ROLE', 'salesPerson'),
('Claim', 'updateClaim', 'WRITE', 'ALLOW', 'ROLE', 'salesPerson'),
('Claim', 'regularizeClaim', 'WRITE', 'ALLOW', 'ROLE', 'claimManager'),
('Claim', 'updateClaimDestination', 'WRITE', 'ALLOW', 'ROLE', 'claimManager'),
('Claim', 'downloadFile', 'READ', 'ALLOW', 'ROLE', 'claimManager'),
('Claim', 'deleteById', 'WRITE', 'ALLOW', 'ROLE', 'claimManager'),
('Claim', 'filter', 'READ', 'ALLOW', 'ROLE', 'salesPerson'),
('Claim', 'logs', 'READ', 'ALLOW', 'ROLE', 'claimManager');
DELETE FROM `salix`.`ACL`
WHERE
model = 'Ticket'
AND property = '*'
AND accessType = '*';
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
VALUES
('Ticket', 'find', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Ticket', 'findById', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Ticket', 'findOne', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Ticket', 'getVolume', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Ticket', 'getTotalVolume', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Ticket', 'summary', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Ticket', 'priceDifference', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Ticket', 'componentUpdate', 'WRITE', 'ALLOW', 'ROLE', 'employee'),
('Ticket', 'new', 'WRITE', 'ALLOW', 'ROLE', 'employee'),
('Ticket', 'isEditable', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Ticket', 'setDeleted', 'WRITE', 'ALLOW', 'ROLE', 'employee'),
('Ticket', 'restore', 'WRITE', 'ALLOW', 'ROLE', 'employee'),
('Ticket', 'getSales', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Ticket', 'getSalesPersonMana', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Ticket', 'filter', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Ticket', 'makeInvoice', 'WRITE', 'ALLOW', 'ROLE', 'employee'),
('Ticket', 'updateEditableTicket', 'WRITE', 'ALLOW', 'ROLE', 'employee'),
('Ticket', 'updateDiscount', 'WRITE', 'ALLOW', 'ROLE', 'employee'),
('Ticket', 'transferSales', 'WRITE', 'ALLOW', 'ROLE', 'employee'),
('Ticket', 'sendSms', 'WRITE', 'ALLOW', 'ROLE', 'employee'),
('Ticket', 'isLocked', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Ticket', 'freightCost', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Ticket', 'getComponentsSum', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Ticket', 'updateAttributes', 'WRITE', 'ALLOW', 'ROLE', 'delivery'), -- Change Priority in Route tickets
('Ticket', 'deliveryNoteCsv', 'READ', 'ALLOW', 'ROLE', 'employee');
DELETE FROM `salix`.`ACL`
WHERE
model = 'State'
AND property = '*'
AND accessType = 'READ';
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
VALUES
('State', 'find', 'READ', 'ALLOW', 'ROLE', 'employee'),
('State', 'findById', 'READ', 'ALLOW', 'ROLE', 'employee'),
('State', 'findOne', 'READ', 'ALLOW', 'ROLE', 'employee');
DELETE FROM `salix`.`ACL`
WHERE
model = 'Worker'
AND property = '*'
AND accessType = 'READ';
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
VALUES
('Worker', 'find', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Worker', 'findById', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Worker', 'findOne', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Worker', 'filter', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Worker', 'getWorkedHours', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Worker', 'active', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Worker', 'activeWithRole', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Worker', 'uploadFile', 'WRITE', 'ALLOW', 'ROLE', 'hr'),
('Worker', 'contracts', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Worker', 'holidays', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Worker', 'activeContract', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Worker', 'activeWithInheritedRole', 'READ', 'ALLOW', 'ROLE', 'employee');
DELETE FROM `salix`.`ACL`
WHERE model = 'Client'
AND property = 'updateUser'
AND accessType = '*';

File diff suppressed because one or more lines are too long

View File

@ -349,20 +349,20 @@ INSERT INTO `vn`.`contactChannel`(`id`, `name`)
(4, 'GCN Channel'), (4, 'GCN Channel'),
(5, 'The Newspaper'); (5, 'The Newspaper');
INSERT INTO `vn`.`client`(`id`,`name`,`fi`,`socialName`,`contact`,`street`,`city`,`postcode`,`phone`,`mobile`,`isRelevant`,`email`,`iban`,`dueDay`,`accountingAccount`,`isEqualizated`,`provinceFk`,`hasToInvoice`,`credit`,`countryFk`,`isActive`,`gestdocFk`,`quality`,`payMethodFk`,`created`,`isToBeMailed`,`contactChannelFk`,`hasSepaVnl`,`hasCoreVnl`,`hasCoreVnh`,`riskCalculated`,`clientTypeFk`,`mailAddress`,`hasToInvoiceByAddress`,`isTaxDataChecked`,`isFreezed`,`creditInsurance`,`isCreatedAsServed`,`hasInvoiceSimplified`,`salesPersonFk`,`isVies`,`eypbc`, `businessTypeFk`) INSERT INTO `vn`.`client`(`id`,`name`,`fi`,`socialName`,`contact`,`street`,`city`,`postcode`,`phone`,`mobile`,`isRelevant`,`email`,`iban`,`dueDay`,`accountingAccount`,`isEqualizated`,`provinceFk`,`hasToInvoice`,`credit`,`countryFk`,`isActive`,`gestdocFk`,`quality`,`payMethodFk`,`created`,`isToBeMailed`,`contactChannelFk`,`hasSepaVnl`,`hasCoreVnl`,`hasCoreVnh`,`riskCalculated`,`clientTypeFk`, `hasToInvoiceByAddress`,`isTaxDataChecked`,`isFreezed`,`creditInsurance`,`isCreatedAsServed`,`hasInvoiceSimplified`,`salesPersonFk`,`isVies`,`eypbc`, `businessTypeFk`)
VALUES VALUES
(1101, 'Bruce Wayne', '84612325V', 'Batman', 'Alfred', '1007 Mountain Drive, Gotham', 'Gotham', 46460, 1111111111, 222222222, 1, 'BruceWayne@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1, 'florist'), (1101, 'Bruce Wayne', '84612325V', 'Batman', 'Alfred', '1007 Mountain Drive, Gotham', 'Gotham', 46460, 1111111111, 222222222, 1, 'BruceWayne@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1, 'florist'),
(1102, 'Petter Parker', '87945234L', 'Spider man', 'Aunt May', '20 Ingram Street, Queens, USA', 'Gotham', 46460, 1111111111, 222222222, 1, 'PetterParker@mydomain.com', NULL, 0, 1234567890, 0, 2, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1, 'florist'), (1102, 'Petter Parker', '87945234L', 'Spider man', 'Aunt May', '20 Ingram Street, Queens, USA', 'Gotham', 46460, 1111111111, 222222222, 1, 'PetterParker@mydomain.com', NULL, 0, 1234567890, 0, 2, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1, 'florist'),
(1103, 'Clark Kent', '06815934E', 'Super man', 'lois lane', '344 Clinton Street, Apartament 3-D', 'Gotham', 46460, 1111111111, 222222222, 1, 'ClarkKent@mydomain.com', NULL, 0, 1234567890, 0, 3, 1, 0, 19, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1, 'florist'), (1103, 'Clark Kent', '06815934E', 'Super man', 'lois lane', '344 Clinton Street, Apartament 3-D', 'Gotham', 46460, 1111111111, 222222222, 1, 'ClarkKent@mydomain.com', NULL, 0, 1234567890, 0, 3, 1, 0, 19, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1, 'florist'),
(1104, 'Tony Stark', '06089160W', 'Iron man', 'Pepper Potts', '10880 Malibu Point, 90265', 'Gotham', 46460, 1111111111, 222222222, 1, 'TonyStark@mydomain.com', NULL, 0, 1234567890, 0, 2, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1, 'florist'), (1104, 'Tony Stark', '06089160W', 'Iron man', 'Pepper Potts', '10880 Malibu Point, 90265', 'Gotham', 46460, 1111111111, 222222222, 1, 'TonyStark@mydomain.com', NULL, 0, 1234567890, 0, 2, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1, 'florist'),
(1105, 'Max Eisenhardt', '251628698', 'Magneto', 'Rogue', 'Unknown Whereabouts', 'Gotham', 46460, 1111111111, 222222222, 1, 'MaxEisenhardt@mydomain.com', NULL, 0, 1234567890, 0, 3, 1, 300, 8, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 1, 1, NULL, 0, 0, 18, 0, 1, 'florist'), (1105, 'Max Eisenhardt', '251628698', 'Magneto', 'Rogue', 'Unknown Whereabouts', 'Gotham', 46460, 1111111111, 222222222, 1, 'MaxEisenhardt@mydomain.com', NULL, 0, 1234567890, 0, 3, 1, 300, 8, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 1, NULL, 0, 0, 18, 0, 1, 'florist'),
(1106, 'DavidCharlesHaller', '53136686Q', 'Legion', 'Charles Xavier', 'City of New York, New York, USA', 'Gotham', 46460, 1111111111, 222222222, 1, 'DavidCharlesHaller@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 0, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 1, 0, NULL, 0, 0, 19, 0, 1, 'florist'), (1106, 'DavidCharlesHaller', '53136686Q', 'Legion', 'Charles Xavier', 'City of New York, New York, USA', 'Gotham', 46460, 1111111111, 222222222, 1, 'DavidCharlesHaller@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 0, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 0, NULL, 0, 0, 19, 0, 1, 'florist'),
(1107, 'Hank Pym', '09854837G', 'Ant man', 'Hawk', 'Anthill, San Francisco, California', 'Gotham', 46460, 1111111111, 222222222, 1, 'HankPym@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 0, 0, NULL, 0, 0, 19, 0, 1, 'florist'), (1107, 'Hank Pym', '09854837G', 'Ant man', 'Hawk', 'Anthill, San Francisco, California', 'Gotham', 46460, 1111111111, 222222222, 1, 'HankPym@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 0, 0, NULL, 0, 0, 19, 0, 1, 'florist'),
(1108, 'Charles Xavier', '22641921P', 'Professor X', 'Beast', '3800 Victory Pkwy, Cincinnati, OH 45207, USA', 'Gotham', 46460, 1111111111, 222222222, 1, 'CharlesXavier@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 1, 1, NULL, 0, 0, 19, 0, 1, 'florist'), (1108, 'Charles Xavier', '22641921P', 'Professor X', 'Beast', '3800 Victory Pkwy, Cincinnati, OH 45207, USA', 'Gotham', 46460, 1111111111, 222222222, 1, 'CharlesXavier@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 1, NULL, 0, 0, 19, 0, 1, 'florist'),
(1109, 'Bruce Banner', '16104829E', 'Hulk', 'Black widow', 'Somewhere in New York', 'Gotham', 46460, 1111111111, 222222222, 1, 'BruceBanner@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 0, 0, NULL, 0, 0, 9, 0, 1, 'florist'), (1109, 'Bruce Banner', '16104829E', 'Hulk', 'Black widow', 'Somewhere in New York', 'Gotham', 46460, 1111111111, 222222222, 1, 'BruceBanner@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 0, 0, NULL, 0, 0, 9, 0, 1, 'florist'),
(1110, 'Jessica Jones', '58282869H', 'Jessica Jones', 'Luke Cage', 'NYCC 2015 Poster', 'Gotham', 46460, 1111111111, 222222222, 1, 'JessicaJones@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 0, 0, NULL, 0, 0, NULL, 0, 1, 'florist'), (1110, 'Jessica Jones', '58282869H', 'Jessica Jones', 'Luke Cage', 'NYCC 2015 Poster', 'Gotham', 46460, 1111111111, 222222222, 1, 'JessicaJones@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 0, 0, NULL, 0, 0, NULL, 0, 1, 'florist'),
(1111, 'Missing', NULL, 'Missing man', 'Anton', 'The space, Universe far away', 'Gotham', 46460, 1111111111, 222222222, 1, NULL, NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 4, 1, 0, 1, 0, NULL, 1, 0, NULL, 0, 1, 'others'), (1111, 'Missing', NULL, 'Missing man', 'Anton', 'The space, Universe far away', 'Gotham', 46460, 1111111111, 222222222, 1, NULL, NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 4, 0, 1, 0, NULL, 1, 0, NULL, 0, 1, 'others'),
(1112, 'Trash', NULL, 'Garbage man', 'Unknown name', 'New York city, Underground', 'Gotham', 46460, 1111111111, 222222222, 1, NULL, NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 4, 1, 0, 1, 0, NULL, 1, 0, NULL, 0, 1, 'others'); (1112, 'Trash', NULL, 'Garbage man', 'Unknown name', 'New York city, Underground', 'Gotham', 46460, 1111111111, 222222222, 1, NULL, NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 4, 0, 1, 0, NULL, 1, 0, NULL, 0, 1, 'others');
INSERT INTO `vn`.`client`(`id`, `name`, `fi`, `socialName`, `contact`, `street`, `city`, `postcode`, `isRelevant`, `email`, `iban`,`dueDay`,`accountingAccount`, `isEqualizated`, `provinceFk`, `hasToInvoice`, `credit`, `countryFk`, `isActive`, `gestdocFk`, `quality`, `payMethodFk`,`created`, `isTaxDataChecked`) INSERT INTO `vn`.`client`(`id`, `name`, `fi`, `socialName`, `contact`, `street`, `city`, `postcode`, `isRelevant`, `email`, `iban`,`dueDay`,`accountingAccount`, `isEqualizated`, `provinceFk`, `hasToInvoice`, `credit`, `countryFk`, `isActive`, `gestdocFk`, `quality`, `payMethodFk`,`created`, `isTaxDataChecked`)
SELECT id, name, CONCAT(RPAD(CONCAT(id,9),8,id),'A'), CONCAT(name, 'Social'), CONCAT(name, 'Contact'), CONCAT(name, 'Street'), 'GOTHAM', 46460, 1, CONCAT(name,'@mydomain.com'), NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1,NULL, 10, 5, util.VN_CURDATE(), 1 SELECT id, name, CONCAT(RPAD(CONCAT(id,9),8,id),'A'), CONCAT(name, 'Social'), CONCAT(name, 'Contact'), CONCAT(name, 'Street'), 'GOTHAM', 46460, 1, CONCAT(name,'@mydomain.com'), NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1,NULL, 10, 5, util.VN_CURDATE(), 1
@ -707,7 +707,7 @@ INSERT INTO `vn`.`ticket`(`id`, `priority`, `agencyModeFk`,`warehouseFk`,`routeF
(15, 1, 7, 1, 6, util.VN_CURDATE(), DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), 1105, 'An incredibly long alias for testing purposes', 125, NULL, 0, 3, 5, 1, util.VN_CURDATE()), (15, 1, 7, 1, 6, util.VN_CURDATE(), DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), 1105, 'An incredibly long alias for testing purposes', 125, NULL, 0, 3, 5, 1, util.VN_CURDATE()),
(16, 1, 7, 1, 6, util.VN_CURDATE(), DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), 1106, 'Many Places', 126, NULL, 0, 3, 5, 1, util.VN_CURDATE()), (16, 1, 7, 1, 6, util.VN_CURDATE(), DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), 1106, 'Many Places', 126, NULL, 0, 3, 5, 1, util.VN_CURDATE()),
(17, 1, 7, 2, 6, util.VN_CURDATE(), DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), 1106, 'Many Places', 126, NULL, 0, 3, 5, 1, util.VN_CURDATE()), (17, 1, 7, 2, 6, util.VN_CURDATE(), DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), 1106, 'Many Places', 126, NULL, 0, 3, 5, 1, util.VN_CURDATE()),
(18, 1, 4, 4, 4, util.VN_CURDATE(), DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), 1108, 'Cerebro', 128, NULL, 0, 12, 5, 1, util.VN_CURDATE()), (18, 1, 4, 4, 4, util.VN_CURDATE(), DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), 1108, 'Cerebro', 128, NULL, 0, 12, 5, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL +12 HOUR)),
(19, 1, 5, 5, NULL, util.VN_CURDATE(), DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), 1109, 'Somewhere in Thailand', 129, NULL, 1, NULL, 5, 1, util.VN_CURDATE()), (19, 1, 5, 5, NULL, util.VN_CURDATE(), DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), 1109, 'Somewhere in Thailand', 129, NULL, 1, NULL, 5, 1, util.VN_CURDATE()),
(20, 1, 5, 5, 3, DATE_ADD(util.VN_CURDATE(), INTERVAL +1 MONTH), DATE_ADD(DATE_ADD(util.VN_CURDATE(),INTERVAL +1 MONTH), INTERVAL +1 DAY), 1109, 'Somewhere in Thailand', 129, NULL, 0, 13, 5, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL +1 MONTH)), (20, 1, 5, 5, 3, DATE_ADD(util.VN_CURDATE(), INTERVAL +1 MONTH), DATE_ADD(DATE_ADD(util.VN_CURDATE(),INTERVAL +1 MONTH), INTERVAL +1 DAY), 1109, 'Somewhere in Thailand', 129, NULL, 0, 13, 5, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL +1 MONTH)),
(21, NULL, 5, 5, 5, DATE_ADD(util.VN_CURDATE(), INTERVAL +1 MONTH), DATE_ADD(DATE_ADD(util.VN_CURDATE(),INTERVAL +1 MONTH), INTERVAL +1 DAY), 1109, 'Somewhere in Holland', 102, NULL, 0, 13, 5, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL +1 MONTH)), (21, NULL, 5, 5, 5, DATE_ADD(util.VN_CURDATE(), INTERVAL +1 MONTH), DATE_ADD(DATE_ADD(util.VN_CURDATE(),INTERVAL +1 MONTH), INTERVAL +1 DAY), 1109, 'Somewhere in Holland', 102, NULL, 0, 13, 5, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL +1 MONTH)),
@ -1940,6 +1940,16 @@ INSERT INTO `pbx`.`sip`(`user_id`, `extension`)
(5, 1102), (5, 1102),
(9, 1201); (9, 1201);
INSERT INTO `vn`.`professionalCategory` (`id`, `name`, `level`, `dayBreak`)
VALUES
(1, 'employee', NULL, NULL),
(2, 'florist', NULL, NULL);
INSERT INTO `vn`.`calendarType` (`id`, `description`, `hoursWeek`, `isPartial`)
VALUES
(1, 'General schedule', 40, 0);
DROP TEMPORARY TABLE IF EXISTS tmp.worker; DROP TEMPORARY TABLE IF EXISTS tmp.worker;
CREATE TEMPORARY TABLE tmp.worker CREATE TEMPORARY TABLE tmp.worker
(PRIMARY KEY (id)) (PRIMARY KEY (id))
@ -1968,7 +1978,7 @@ UPDATE `vn`.`business`
WHERE `id`= 1106; WHERE `id`= 1106;
UPDATE `vn`.`business` b UPDATE `vn`.`business` b
SET b.`workerBusinessProfessionalCategoryFk` = 31 SET b.`workerBusinessProfessionalCategoryFk` = 2
WHERE b.`workerFk` = 1110; WHERE b.`workerFk` = 1110;
UPDATE `vn`.`business` b UPDATE `vn`.`business` b
@ -2775,6 +2785,19 @@ INSERT INTO `vn`.`ticketLog` (`originFk`, userFk, `action`, changedModel, oldIns
(7, 18, 'update', 'Sale', '{"price":3}', '{"price":5}', 1, NULL), (7, 18, 'update', 'Sale', '{"price":3}', '{"price":5}', 1, NULL),
(7, 18, 'update', NULL, NULL, NULL, NULL, "Cambio cantidad Melee weapon heavy shield 1x0.5m de '5' a '10'"); (7, 18, 'update', NULL, NULL, NULL, NULL, "Cambio cantidad Melee weapon heavy shield 1x0.5m de '5' a '10'");
INSERT INTO `vn`.`ticketLog` (originFk, userFk, `action`, creationDate, changedModel, changedModelId, changedModelValue, oldInstance, newInstance, description)
VALUES
(1, NULL, 'delete', '2001-06-09 11:00:04', 'Ticket', 45, 'Spider Man' , NULL, NULL, NULL),
(1, 18, 'select', '2001-06-09 11:00:03', 'Ticket', 45, 'Spider Man' , NULL, NULL, NULL),
(1, NULL, 'update', '2001-05-09 10:00:02', 'Sale', 69854, 'Armor' , '{"isPicked": false}','{"isPicked": true}', NULL),
(1, 18, 'update', '2001-01-01 10:05:01', 'Sale', 69854, 'Armor' , NULL, NULL, 'Armor quantity changed from ''15'' to ''10'''),
(1, NULL, 'delete', '2001-01-01 10:00:10', 'Sale', 5689, 'Shield' , '{"quantity":10,"concept":"Shield"}', NULL, NULL),
(1, 18, 'insert', '2000-12-31 15:00:05', 'Sale', 69854, 'Armor' , NULL,'{"quantity":15,"concept":"Armor", "price": 345.99, "itemFk": 2}', NULL),
(1, 18, 'update', '2000-12-28 08:40:45', 'Ticket', 45, 'Spider Man' , '{"warehouseFk":60,"shipped":"2023-05-16T22:00:00.000Z","nickname":"Super Man","isSigned":true,"isLabeled":true,"isPrinted":true,"packages":0,"hour":0,"isBlocked":false,"hasPriority":false,"companyFk":442,"landed":"2023-05-17T22:00:00.000Z","isBoxed":true,"isDeleted":true,"zoneFk":713,"zonePrice":13,"zoneBonus":0}','{"warehouseFk":61,"shipped":"2023-05-17T22:00:00.000Z","nickname":"Spider Man","isSigned":false,"isLabeled":false,"isPrinted":false,"packages":1,"hour":0,"isBlocked":true,"hasPriority":true,"companyFk":443,"landed":"2023-05-18T22:00:00.000Z","isBoxed":false,"isDeleted":false,"zoneFk":713,"zonePrice":13,"zoneBonus":1}', NULL),
(1, 18, 'select', '2000-12-27 03:40:30', 'Ticket', 45, NULL , NULL, NULL, NULL),
(1, 18, 'insert', '2000-04-10 09:40:15', 'Sale', 5689, 'Shield' , NULL, '{"quantity":10,"concept":"Shield", "price": 10.5, "itemFk": 1}', NULL),
(1, 18, 'insert', '1999-05-09 10:00:00', 'Ticket', 45, 'Super Man' , NULL, '{"id":45,"clientFk":8608,"warehouseFk":60,"shipped":"2023-05-16T22:00:00.000Z","nickname":"Super Man","addressFk":48637,"isSigned":true,"isLabeled":true,"isPrinted":true,"packages":0,"hour":0,"created":"2023-05-16T11:42:56.000Z","isBlocked":false,"hasPriority":false,"companyFk":442,"agencyModeFk":639,"landed":"2023-05-17T22:00:00.000Z","isBoxed":true,"isDeleted":true,"zoneFk":713,"zonePrice":13,"zoneBonus":0}', NULL);
INSERT INTO `vn`.`osTicketConfig` (`id`, `host`, `user`, `password`, `oldStatus`, `newStatusId`, `day`, `comment`, `hostDb`, `userDb`, `passwordDb`, `portDb`, `responseType`, `fromEmailId`, `replyTo`) INSERT INTO `vn`.`osTicketConfig` (`id`, `host`, `user`, `password`, `oldStatus`, `newStatusId`, `day`, `comment`, `hostDb`, `userDb`, `passwordDb`, `portDb`, `responseType`, `fromEmailId`, `replyTo`)
VALUES VALUES
(0, 'http://localhost:56596/scp', 'ostadmin', 'Admin1', '1,6', 3, 60, 'Este CAU se ha cerrado automáticamente. Si el problema persiste responda a este mensaje.', 'localhost', 'osticket', 'osticket', 40003, 'reply', 1, 'all'); (0, 'http://localhost:56596/scp', 'ostadmin', 'Admin1', '1,6', 3, 60, 'Este CAU se ha cerrado automáticamente. Si el problema persiste responda a este mensaje.', 'localhost', 'osticket', 'osticket', 40003, 'reply', 1, 'all');
@ -2801,9 +2824,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`, `payMethodFk`, `businessTypeFk`)
VALUES VALUES
(1, NULL, 1); (1, NULL, 1, 4, 'worker');
INSERT INTO `vn`.`ticketRefund`(`refundTicketFk`, `originalTicketFk`) INSERT INTO `vn`.`ticketRefund`(`refundTicketFk`, `originalTicketFk`)
VALUES VALUES

View File

@ -1,42 +1,33 @@
CREATE SCHEMA IF NOT EXISTS `util`; DROP FUNCTION IF EXISTS `util`.`mockTime`;
USE `util`;
DELIMITER ;; DELIMITER $$
DROP FUNCTION IF EXISTS `util`.`mockedDate`; $$
CREATE FUNCTION `util`.`mockedDate`() CREATE DEFINER=`root`@`localhost` FUNCTION `util`.`mockTime`() RETURNS datetime
RETURNS DATETIME DETERMINISTIC
DETERMINISTIC
BEGIN BEGIN
RETURN CONVERT_TZ('2001-01-01 11:00:00', 'utc', 'Europe/Madrid'); RETURN CONVERT_TZ('@mockDate', 'utc', 'Europe/Madrid');
END ;; END$$
DELIMITER ; DELIMITER ;
DELIMITER ;; DROP FUNCTION IF EXISTS `util`.`mockUtcTime`;
DROP FUNCTION IF EXISTS `util`.`VN_CURDATE`;
CREATE FUNCTION `util`.`VN_CURDATE`() DELIMITER $$
RETURNS DATE $$
DETERMINISTIC CREATE DEFINER=`root`@`localhost` FUNCTION `util`.`mockUtcTime`() RETURNS datetime
DETERMINISTIC
BEGIN BEGIN
RETURN DATE(mockedDate()); RETURN CONVERT_TZ('@mockDate', 'utc', 'Europe/Madrid');
END ;; END$$
DELIMITER ; DELIMITER ;
DELIMITER ;; DROP FUNCTION IF EXISTS `util`.`mockTimeBase`;
DROP FUNCTION IF EXISTS `util`.`VN_CURTIME`;
CREATE FUNCTION `util`.`VN_CURTIME`() DELIMITER $$
RETURNS TIME $$
DETERMINISTIC CREATE DEFINER=`root`@`localhost` FUNCTION `util`.`mockTimeBase`(vIsUtc BOOL) RETURNS datetime
DETERMINISTIC
BEGIN BEGIN
RETURN TIME(mockedDate()); RETURN CONVERT_TZ('@mockDate', 'utc', 'Europe/Madrid');
END ;; END$$
DELIMITER ; DELIMITER ;
DELIMITER ;;
DROP FUNCTION IF EXISTS `util`.`VN_NOW`;
CREATE FUNCTION `util`.`VN_NOW`()
RETURNS DATETIME
DETERMINISTIC
BEGIN
RETURN mockedDate();
END ;;
DELIMITER ;

File diff suppressed because it is too large Load Diff

View File

@ -100,11 +100,8 @@ dump_tables ${TABLES[@]}
TABLES=( TABLES=(
postgresql postgresql
calendar_labour_type
labour_agreement labour_agreement
media_type media_type
professional_category
profile_type
) )
dump_tables ${TABLES[@]} dump_tables ${TABLES[@]}

View File

@ -93,12 +93,5 @@ mysqldump \
--databases \ --databases \
${SCHEMAS[@]} \ ${SCHEMAS[@]} \
${IGNORETABLES[@]} \ ${IGNORETABLES[@]} \
| sed 's/\bCURDATE\b/util.VN_CURDATE/ig'\
| sed 's/\bCURTIME\b/util.VN_CURTIME/ig' \
| sed 's/\bNOW\b/util.VN_NOW/ig' \
| sed 's/\bCURRENT_DATE\b/util.VN_CURDATE/ig' \
| sed 's/\bCURRENT_TIME\b/util.VN_CURTIME/ig' \
| sed 's/\bLOCALTIME\b/util.VN_NOW/ig' \
| sed 's/\bLOCALTIMESTAMP\b/util.VN_NOW/ig' \
| sed 's/ AUTO_INCREMENT=[0-9]* //g' \ | sed 's/ AUTO_INCREMENT=[0-9]* //g' \
> dump/structure.sql > dump/structure.sql

View File

@ -313,7 +313,7 @@ export default {
anyClient: 'vn-client-defaulter tbody > tr', anyClient: 'vn-client-defaulter tbody > tr',
firstClientName: 'vn-client-defaulter tbody > tr:nth-child(1) > td:nth-child(2) > span', firstClientName: 'vn-client-defaulter tbody > tr:nth-child(1) > td:nth-child(2) > span',
firstSalesPersonName: 'vn-client-defaulter tbody > tr:nth-child(1) > td:nth-child(3) > span', firstSalesPersonName: 'vn-client-defaulter tbody > tr:nth-child(1) > td:nth-child(3) > span',
firstObservation: 'vn-client-defaulter tbody > tr:nth-child(1) > td:nth-child(6) > vn-textarea[ng-model="defaulter.observation"]', firstObservation: 'vn-client-defaulter tbody > tr:nth-child(1) > td:nth-child(8) > vn-textarea[ng-model="defaulter.observation"]',
allDefaulterCheckbox: 'vn-client-defaulter thead vn-multi-check', allDefaulterCheckbox: 'vn-client-defaulter thead vn-multi-check',
addObservationButton: 'vn-client-defaulter vn-button[icon="icon-notes"]', addObservationButton: 'vn-client-defaulter vn-button[icon="icon-notes"]',
observation: '.vn-dialog.shown vn-textarea[ng-model="$ctrl.defaulter.observation"]', observation: '.vn-dialog.shown vn-textarea[ng-model="$ctrl.defaulter.observation"]',
@ -625,6 +625,7 @@ export default {
selectAllSalesCheckbox: 'vn-ticket-sale vn-thead vn-check', selectAllSalesCheckbox: 'vn-ticket-sale vn-thead vn-check',
secondSaleCheckbox: 'vn-ticket-sale vn-tr:nth-child(2) vn-check[ng-model="sale.checked"]', secondSaleCheckbox: 'vn-ticket-sale vn-tr:nth-child(2) vn-check[ng-model="sale.checked"]',
thirdSaleCheckbox: 'vn-ticket-sale vn-tr:nth-child(3) vn-check[ng-model="sale.checked"]', thirdSaleCheckbox: 'vn-ticket-sale vn-tr:nth-child(3) vn-check[ng-model="sale.checked"]',
fourthSaleCheckbox: 'vn-ticket-sale vn-tr:nth-child(4) vn-check[ng-model="sale.checked"]',
deleteSaleButton: 'vn-ticket-sale vn-tool-bar > vn-button[icon="delete"]', deleteSaleButton: 'vn-ticket-sale vn-tool-bar > vn-button[icon="delete"]',
transferSaleButton: 'vn-ticket-sale vn-tool-bar > vn-button[icon="call_split"]', transferSaleButton: 'vn-ticket-sale vn-tool-bar > vn-button[icon="call_split"]',
moveToTicketInput: 'form vn-input-number[ng-model="$ctrl.transfer.ticketId"] input', moveToTicketInput: 'form vn-input-number[ng-model="$ctrl.transfer.ticketId"] input',

View File

@ -5,8 +5,8 @@ const $ = {
userName: 'vn-client-web-access vn-textfield[ng-model="$ctrl.account.name"]', userName: 'vn-client-web-access vn-textfield[ng-model="$ctrl.account.name"]',
email: 'vn-client-web-access vn-textfield[ng-model="$ctrl.account.email"]', email: 'vn-client-web-access vn-textfield[ng-model="$ctrl.account.email"]',
saveButton: 'vn-client-web-access button[type=submit]', saveButton: 'vn-client-web-access button[type=submit]',
nameValue: 'vn-client-log .change:nth-child(1) .basic-json:nth-child(1) vn-json-value', nameValue: 'vn-client-log .change:nth-child(1) .basic-json:nth-child(2) vn-json-value',
activeValue: 'vn-client-log .change:nth-child(2) .basic-json:nth-child(2) vn-json-value' activeValue: 'vn-client-log .change:nth-child(2) .basic-json:nth-child(1) vn-json-value'
}; };
describe('Client web access path', () => { describe('Client web access path', () => {

View File

@ -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'

View File

@ -17,7 +17,7 @@ describe('Claim summary path', () => {
}); });
it('should navigate to the target claim summary section', async() => { it('should navigate to the target claim summary section', async() => {
await page.loginAndModule('employee', 'claim'); await page.loginAndModule('salesPerson', 'claim');
await page.accessToSearchResult(claimId); await page.accessToSearchResult(claimId);
await page.waitForState('claim.card.summary'); await page.waitForState('claim.card.summary');
}); });

View File

@ -16,7 +16,7 @@ describe('Claim descriptor path', () => {
}); });
it('should now navigate to the target claim summary section', async() => { it('should now navigate to the target claim summary section', async() => {
await page.loginAndModule('employee', 'claim'); await page.loginAndModule('salesPerson', 'claim');
await page.accessToSearchResult(claimId); await page.accessToSearchResult(claimId);
await page.waitForState('claim.card.summary'); await page.waitForState('claim.card.summary');
}); });

View File

@ -1,5 +1,20 @@
import getBrowser from '../../helpers/puppeteer'; import getBrowser from '../../helpers/puppeteer';
const $ = {
saveButton: 'vn-supplier-fiscal-data button[type="submit"]',
};
const $inputs = {
province: 'vn-supplier-fiscal-data [name="province"]',
country: 'vn-supplier-fiscal-data [name="country"]',
postcode: 'vn-supplier-fiscal-data [name="postcode"]',
city: 'vn-supplier-fiscal-data [name="city"]',
socialName: 'vn-supplier-fiscal-data [name="socialName"]',
taxNumber: 'vn-supplier-fiscal-data [name="taxNumber"]',
account: 'vn-supplier-fiscal-data [name="account"]',
sageWithholding: 'vn-supplier-fiscal-data [ng-model="$ctrl.supplier.sageWithholdingFk"]',
sageTaxType: 'vn-supplier-fiscal-data [ng-model="$ctrl.supplier.sageTaxTypeFk"]'
};
describe('Supplier fiscal data path', () => { describe('Supplier fiscal data path', () => {
let browser; let browser;
let page; let page;

View File

@ -1,5 +1,6 @@
import ngModule from '../../module'; import ngModule from '../../module';
import Component from 'core/lib/component'; import Component from 'core/lib/component';
import {hashToColor} from '../../lib/string';
import './style.scss'; import './style.scss';
/** /**
@ -16,13 +17,8 @@ export default class Avatar extends Component {
this._val = value; this._val = value;
const val = value || ''; const val = value || '';
let hash = 0;
for (let i = 0; i < val.length; i++)
hash += val.charCodeAt(i);
const color = '#' + colors[hash % colors.length];
const el = this.element; const el = this.element;
el.style.backgroundColor = color; el.style.backgroundColor = hashToColor(val);
el.title = val; el.title = val;
} }
} }
@ -35,29 +31,3 @@ ngModule.vnComponent('vnAvatar', {
}, },
transclude: true transclude: true
}); });
const colors = [
'e2553d', // Coral
'FFA07A', // Salmon
'FFDAB9', // Peach
'a17077', // Pink
'bf0e99', // Pink light
'52a500', // Green chartreuse
'00aeae', // Cian
'b754cf', // Purple middle
'8a69cd', // Blue lavender
'1fa8a1', // Green ocean
'DC143C', // Red crimson
'5681cf', // Blue steel
'FF1493', // Ping intense
'02ba02', // Green lime
'1E90FF', // Blue sky
'8B008B', // Purple dark
'cc7000', // Orange bright
'00b5b8', // Turquoise
'8B0000', // Red dark
'008080', // Green bluish
'2F4F4F', // Gray board
'7e7e7e', // Gray
'5d5d5d', // Gray dark
];

View File

@ -139,7 +139,7 @@ export default class CrudModel extends ModelProxy {
filter.limit = this.page * this.limit; filter.limit = this.page * this.limit;
} }
return this.sendRequest(filter, append, true); return this.sendRequest(filter, append);
} }
clear() { clear() {
@ -231,12 +231,12 @@ export default class CrudModel extends ModelProxy {
return params; return params;
} }
sendRequest(filter, append, loadMore) { sendRequest(filter, append) {
this.cancelRequest(); this.cancelRequest();
this.canceler = this.$q.defer(); this.canceler = this.$q.defer();
this.isPaging = append; this.isPaging = append;
if (!loadMore) if (!append && this.status != 'ready')
this.status = 'loading'; this.status = 'loading';
let params = Object.assign( let params = Object.assign(

View File

@ -150,7 +150,7 @@ describe('Component vnCrudModel', () => {
controller.loadMore(true); controller.loadMore(true);
expect(controller.sendRequest).toHaveBeenCalledWith({'skip': 2}, true, true); expect(controller.sendRequest).toHaveBeenCalledWith({'skip': 2}, true);
}); });
}); });

View File

@ -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)

View File

@ -2,7 +2,7 @@ import ngModule from '../../module';
import Component from 'core/lib/component'; import Component from 'core/lib/component';
import './style.scss'; import './style.scss';
const maxStrLen = 50; const maxStrLen = 512;
/** /**
* Displays pretty JSON value. * Displays pretty JSON value.
@ -28,6 +28,12 @@ export default class Controller extends Component {
} else { } else {
cssClass = type; cssClass = type;
switch (type) { switch (type) {
case 'number':
if (Number.isInteger(value))
text = value;
else
text = Math.round((value + Number.EPSILON) * 1000) / 1000;
break;
case 'boolean': case 'boolean':
text = value ? '✓' : '✗'; text = value ? '✓' : '✗';
cssClass = value ? 'true' : 'false'; cssClass = value ? 'true' : 'false';

View File

@ -75,5 +75,19 @@ describe('Component vnJsonValue', () => {
expect(el.textContent).toEqual('2050'); expect(el.textContent).toEqual('2050');
expect(el.className).toContain('json-number'); expect(el.className).toContain('json-number');
}); });
it('should display number when value is decimal', () => {
controller.value = 10.1;
expect(el.textContent).toEqual('10.1');
expect(el.className).toContain('json-number');
});
it('should display rounded number when value is decimal with lot of decimals', () => {
controller.value = 10.124323234;
expect(el.textContent).toEqual('10.124');
expect(el.className).toContain('json-number');
});
}); });
}); });

View File

@ -1,3 +1,3 @@
SelectAllRows: Seleccionar las {{rows}} fila(s) SelectAllRows: Seleccionar las {{rows}} fila(s)
All: Se han seleccionado Have been selected: Se han seleccionado
row(s) have been selected.: fila(s). row(s) have been selected.: fila(s).

View File

@ -203,7 +203,7 @@ export default class Searchbar extends Component {
doSearch(filter, source) { doSearch(filter, source) {
if (filter === this.filter && !this.isIndex) return; if (filter === this.filter && !this.isIndex) return;
let promise = this.onSearch({$params: filter}); let promise = this.onSearch({$params: filter}, source);
promise = promise || this.$q.resolve(); promise = promise || this.$q.resolve();
promise.then(data => this.onFilter(filter, source, data)); promise.then(data => this.onFilter(filter, source, data));
this.toBar(filter); this.toBar(filter);
@ -259,12 +259,6 @@ export default class Searchbar extends Component {
this.filter = filter; this.filter = filter;
if (source == 'removeBar') {
delete params[this.toRemove];
delete this.model.userParams[this.toRemove];
this.model.refresh();
}
if (!filter && this.model) if (!filter && this.model)
this.model.clear(); this.model.clear();
if (source != 'state') if (source != 'state')
@ -279,7 +273,7 @@ export default class Searchbar extends Component {
return {id: params.$row.id}; return {id: params.$row.id};
} }
onSearch(args) { onSearch(args, source) {
if (!this.model) return; if (!this.model) return;
let filter = args.$params; let filter = args.$params;
@ -325,6 +319,12 @@ export default class Searchbar extends Component {
for (let param in stateFilter.tableQ) for (let param in stateFilter.tableQ)
params[param] = stateFilter.tableQ[param]; params[param] = stateFilter.tableQ[param];
if (source == 'removeBar') {
delete params[this.toRemove];
delete this.model.userParams[this.toRemove];
delete stateFilter[this.toRemove];
}
const newParams = Object.assign(stateFilter, params); const newParams = Object.assign(stateFilter, params);
return this.model.applyParams(newParams) return this.model.applyParams(newParams)
.then(() => this.model.data); .then(() => this.model.data);

View File

@ -197,7 +197,7 @@ describe('Component vnSearchbar', () => {
controller.doSearch(filter, 'any'); controller.doSearch(filter, 'any');
$scope.$apply(); $scope.$apply();
expect(controller.onSearch).toHaveBeenCalledWith({$params: filter}); expect(controller.onSearch).toHaveBeenCalledWith({$params: filter}, 'any');
expect(controller.onFilter).toHaveBeenCalledWith(filter, 'any', undefined); expect(controller.onFilter).toHaveBeenCalledWith(filter, 'any', undefined);
}); });
}); });

View File

@ -30,3 +30,39 @@ export function camelToKebab(str) {
export function firstUpper(str) { export function firstUpper(str) {
return str.charAt(0).toUpperCase() + str.substr(1); return str.charAt(0).toUpperCase() + str.substr(1);
} }
export function djb2a(string) {
let hash = 5381;
for (let i = 0; i < string.length; i++)
hash = ((hash << 5) + hash) ^ string.charCodeAt(i);
return hash >>> 0;
}
export function hashToColor(value) {
return '#' + colors[djb2a(value || '') % colors.length];
}
const colors = [
'b5b941', // Yellow
'ae9681', // Peach
'd78767', // Salmon
'cc7000', // Orange bright
'e2553d', // Coral
'8B0000', // Red dark
'de4362', // Red crimson
'FF1493', // Ping intense
'be39a2', // Pink light
'b754cf', // Purple middle
'a87ba8', // Pink
'8a69cd', // Blue lavender
'ab20ab', // Purple dark
'00b5b8', // Turquoise
'1fa8a1', // Green ocean
'5681cf', // Blue steel
'3399fe', // Blue sky
'6d9c3e', // Green chartreuse
'51bb51', // Green lime
'518b8b', // Gray board
'7e7e7e', // Gray
'5d5d5d', // Gray dark
];

View File

@ -38,6 +38,9 @@
.text-overline { .text-overline {
font-size: .8rem; font-size: .8rem;
} }
.text-capitalize {
text-transform: capitalize;
}
h1, h2, h3, h4, h5, h6 { h1, h2, h3, h4, h5, h6 {
padding: 0; padding: 0;

View File

@ -7,11 +7,13 @@ vn-descriptor-content {
.photo { .photo {
position: relative; position: relative;
width: 100%;
text-align: center;
overflow: hidden;
& > img[ng-src] { & > img[ng-src] {
min-height: 16em; min-height: 16em;
display: block; display: block;
max-width: 100%;
height: 256px; height: 256px;
} }

View File

@ -10,16 +10,18 @@
</vn-crud-model> </vn-crud-model>
<vn-crud-model <vn-crud-model
url="{{$ctrl.url}}/{{$ctrl.originId}}/models" url="{{$ctrl.url}}/{{$ctrl.originId}}/models"
data="models" data="$ctrl.models"
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"
class="vn-w-sm 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 : $ctrl.$t('System')}}"
ng-click="$ctrl.showWorkerDescriptor($event, log)"> ng-click="$ctrl.showWorkerDescriptor($event, log)">
<img <img
ng-if="::log.user.image" ng-if="::log.user.image"
@ -29,61 +31,55 @@
<div class="arrow bg-panel"></div> <div class="arrow bg-panel"></div>
<div class="line"></div> <div class="line"></div>
</div> </div>
<vn-card class="detail vn-pa-sm"> <vn-card class="detail">
<div class="header vn-mb-sm"> <div class="header vn-pa-sm">
<div <div
class="date text-secondary text-caption" class="action-date text-secondary text-caption vn-mr-sm"
title="{{::log.creationDate | date:'dd/MM/yyyy HH:mm'}}"> title="{{::log.creationDate | date:'dd/MM/yyyy HH:mm:ss'}}">
<vn-icon
class="action vn-mr-xs"
ng-class="::$ctrl.actionsClass[log.action]"
icon="{{::$ctrl.actionsIcon[log.action]}}"
translate-attr="::{title: $ctrl.actionsText[log.action]}">
</vn-icon>
{{::$ctrl.relativeDate(log.creationDate)}} {{::$ctrl.relativeDate(log.creationDate)}}
</div> </div>
<span class="chip" ng-class="::$ctrl.actionsClass[log.action]" translate> <div class="action-model">
{{::$ctrl.actionsText[log.action]}}
</span>
</div>
<div
class="model vn-mb-sm"
title="{{::log.changedModelValue}}"
ng-if="::log.changedModel || log.changedModelValue">
<span class="model-name" <span class="model-name"
ng-if="::$ctrl.showModelName" ng-if="::$ctrl.showModelName && log.changedModel"
ng-style="::{backgroundColor: $ctrl.hashToColor(log.changedModel)}"
title="{{::log.changedModel}}"> title="{{::log.changedModel}}">
{{::log.changedModelI18n}} {{::log.changedModelI18n}}
</span> </span>
<span class="model-id"
ng-if="::log.changedModelId">
#{{::log.changedModelId}}
</span>
<span class="model-value">
{{::log.changedModelValue}}
</span>
</div> </div>
<div class="changes" </div>
ng-class="::log.props.length ? 'props' : 'no-props'" <div
vn-id="changes"> class="model vn-pb-sm vn-px-sm"
<vn-icon icon="visibility" title="{{::log.changedModelValue}}"
class="expand-button" ng-if="::log.changedModelId || log.changedModelValue">
ng-click="$ctrl.toggleAttributes(log, changes, true)"> <span class="model-id" ng-if="::log.changedModelId">#{{::log.changedModelId}}</span>
<span class="model-value">{{::log.changedModelValue}}</span>
</div>
<div class="changes vn-pa-sm"
ng-class="{expanded: log.expand}"
ng-if="::log.props.length || log.description">
<vn-icon
icon="expand_more"
translate-attr="{title: 'Details'}"
ng-click="log.expand = !log.expand">
</vn-icon> </vn-icon>
<vn-icon icon="visibility_off"
class="shrink-button"
ng-click="$ctrl.toggleAttributes(log, changes, false)">
</vn-icon>
<div class="changes-wrapper">
<span ng-if="::log.props.length" <span ng-if="::log.props.length"
class="attributes"> class="attributes">
<span ng-if="!log.expand" ng-repeat="prop in ::log.props" <span ng-if="!log.expand" ng-repeat="prop in ::log.props"
class="basic-json"> class="basic-json">
<span class="json-field" <span class="json-field" title="{{::prop.name}}">
title="{{::prop.name}}">
{{::prop.nameI18n}}: {{::prop.nameI18n}}:
</span> </span>
<vn-json-value value="::$ctrl.mainVal(prop, log.action)"></vn-json-value><span ng-if="::!$last">,</span> <vn-json-value value="::$ctrl.mainVal(prop, log.action)"></vn-json-value><span ng-if="::!$last">,</span>
</span> </span>
<div ng-if="log.expand" <div ng-if="log.expand" class="expanded-json">
class="expanded-json">
<div ng-repeat="prop in ::log.props"> <div ng-repeat="prop in ::log.props">
<span class="json-field" <span class="json-field" title="{{::prop.name}}">
title="{{::prop.name}}">
{{::prop.nameI18n}}: {{::prop.nameI18n}}:
</span> </span>
<vn-json-value value="::$ctrl.mainVal(prop, log.action)"></vn-json-value> <vn-json-value value="::$ctrl.mainVal(prop, log.action)"></vn-json-value>
@ -93,16 +89,9 @@
</div> </div>
</div> </div>
</span> </span>
<span ng-if="::!log.props.length" <span ng-if="::!log.props.length" class="description">
class="description">
{{::log.description}} {{::log.description}}
</span> </span>
<span ng-if="::!log.description && !log.props.length"
class="no-changes"
translate>
No changes
</span>
</div>
</vn-card> </vn-card>
</div> </div>
</div> </div>
@ -111,10 +100,6 @@
<form vn-vertical <form vn-vertical
ng-model-options="{updateOn: 'change blur'}" ng-model-options="{updateOn: 'change blur'}"
class="vn-pa-md filter"> class="vn-pa-md filter">
<vn-textfield
label="Name"
ng-model="filter.changedModelValue">
</vn-textfield>
<vn-vertical> <vn-vertical>
<vn-radio <vn-radio
label="All" label="All"
@ -131,7 +116,7 @@
val="system" val="system"
ng-model="filter.who"> ng-model="filter.who">
</vn-radio> </vn-radio>
</div> </vn-vertical>
<vn-autocomplete <vn-autocomplete
ng-show="filter.who != 'system'" ng-show="filter.who != 'system'"
label="User" label="User"
@ -159,24 +144,38 @@
</div> </div>
</tpl-item> </tpl-item>
</vn-autocomplete> </vn-autocomplete>
<vn-textfield
label="Search"
ng-model="filter.search">
<append>
<vn-icon
icon="info_outline"
vn-tooltip="Search by id or concept"
pointer>
</vn-icon>
</append>
</vn-textfield>
<vn-autocomplete <vn-autocomplete
label="Model" label="Entity"
ng-model="filter.changedModel" ng-model="filter.changedModel"
value-field="changedModel" value-field="changedModel"
show-field="changedModel" show-field="changedModelI18n"
data="models"> data="$ctrl.models"
class="changed-model">
</vn-autocomplete> </vn-autocomplete>
<!-- FIXME: Cannot use LIKE with JSON columns
<vn-textfield <vn-textfield
label="Id" label="Changes"
ng-model="filter.changedModelId"> ng-model="filter.changes">
</vn-textfield> </vn-textfield>
-->
<vn-vertical> <vn-vertical>
<vn-check <vn-check
label="Creates" label="Creates"
ng-model="filter.actions.insert"> ng-model="filter.actions.insert">
</vn-check> </vn-check>
<vn-check <vn-check
label="Updates" label="Edits"
ng-model="filter.actions.update"> ng-model="filter.actions.update">
</vn-check> </vn-check>
<vn-check <vn-check
@ -184,10 +183,10 @@
ng-model="filter.actions.delete"> ng-model="filter.actions.delete">
</vn-check> </vn-check>
<vn-check <vn-check
label="Views" label="Accesses"
ng-model="filter.actions.select"> ng-model="filter.actions.select">
</vn-check> </vn-check>
</div> </vn-vertical>
<vn-date-picker <vn-date-picker
label="Date" label="Date"
ng-model="filter.from"> ng-model="filter.from">
@ -196,7 +195,7 @@
label="To" label="To"
ng-model="filter.to"> ng-model="filter.to">
</vn-date-picker> </vn-date-picker>
<vn-button-bar vn-vertical class="vn-mt-sm"> <vn-button-bar vn-vertical>
<vn-button <vn-button
label="Filter" label="Filter"
ng-click="$ctrl.applyFilter(filter)"> ng-click="$ctrl.applyFilter(filter)">

View File

@ -1,5 +1,6 @@
import ngModule from '../../module'; import ngModule from '../../module';
import Section from '../section'; import Section from '../section';
import {hashToColor} from 'core/lib/string';
import './style.scss'; import './style.scss';
const validDate = /^(-?(?:[1-9][0-9]*)?[0-9]{4})-(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9])T(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])(.[0-9]+)?(Z)?$/; const validDate = /^(-?(?:[1-9][0-9]*)?[0-9]{4})-(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9])T(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])(.[0-9]+)?(Z)?$/;
@ -7,11 +8,12 @@ const validDate = /^(-?(?:[1-9][0-9]*)?[0-9]{4})-(1[0-2]|0[1-9])-(3[01]|0[1-9]|[
export default class Controller extends Section { export default class Controller extends Section {
constructor($element, $) { constructor($element, $) {
super($element, $); super($element, $);
this.hashToColor = hashToColor;
this.actionsText = { this.actionsText = {
insert: 'Creates', insert: 'Creates',
update: 'Updates', update: 'Edits',
delete: 'Deletes', delete: 'Deletes',
select: 'Views' select: 'Accesses'
}; };
this.actionsClass = { this.actionsClass = {
insert: 'success', insert: 'success',
@ -19,6 +21,12 @@ export default class Controller extends Section {
delete: 'alert', delete: 'alert',
select: 'notice' select: 'notice'
}; };
this.actionsIcon = {
insert: 'add',
update: 'edit',
delete: 'remove',
select: 'visibility'
};
this.filter = { this.filter = {
include: [{ include: [{
relation: 'user', relation: 'user',
@ -55,14 +63,14 @@ export default class Controller extends Section {
set logs(value) { set logs(value) {
this._logs = value; this._logs = value;
if (!this.logs) return; if (!value) return;
const empty = {}; const empty = {};
const validations = window.validations; const validations = window.validations;
for (const log of value) { for (const log of value) {
const oldValues = log.oldInstance || empty; const oldValues = log.oldInstance || empty;
const newValues = log.newInstance || empty; const newValues = log.newInstance || empty;
const locale = validations[log.changedModel]?.locale || empty; const locale = validations[log.changedModel]?.locale || empty;
log.changedModelI18n = locale.name || log.changedModel; log.changedModelI18n = firstUpper(locale.name) || log.changedModel;
let props = Object.keys(oldValues).concat(Object.keys(newValues)); let props = Object.keys(oldValues).concat(Object.keys(newValues));
props = [...new Set(props)]; props = [...new Set(props)];
@ -71,11 +79,27 @@ export default class Controller extends Section {
for (const prop of props) { for (const prop of props) {
log.props.push({ log.props.push({
name: prop, name: prop,
nameI18n: locale.columns?.[prop] || prop, nameI18n: firstUpper(locale.columns?.[prop]) || prop,
old: this.castJsonValue(oldValues[prop]), old: this.castJsonValue(oldValues[prop]),
new: this.castJsonValue(newValues[prop]) new: this.castJsonValue(newValues[prop])
}); });
} }
log.props.sort(
(a, b) => a.nameI18n.localeCompare(b.nameI18n));
}
}
get models() {
return this._models;
}
set models(value) {
this._models = value;
if (!value) return;
for (const model of value) {
const name = model.changedModel;
model.changedModelI18n =
firstUpper(window.validations[name]?.locale?.name) || name;
} }
} }
@ -93,11 +117,6 @@ export default class Controller extends Section {
return action == 'delete' ? prop.old : prop.new; return action == 'delete' ? prop.old : prop.new;
} }
toggleAttributes(log, changesEl, force) {
log.expand = force;
changesEl.classList.toggle('expanded', force);
}
relativeDate(dateVal) { relativeDate(dateVal) {
if (dateVal == null) return ''; if (dateVal == null) return '';
const date = new Date(dateVal); const date = new Date(dateVal);
@ -130,8 +149,17 @@ export default class Controller extends Section {
function getParam(prop, value) { function getParam(prop, value) {
if (value == null || value == '') return null; if (value == null || value == '') return null;
switch (prop) { switch (prop) {
case 'changedModelValue': case 'search':
return {[prop]: {like: `%${value}%`}}; const or = [{changedModelId: value}];
if (!/^[0-9]+$/.test(value))
or.push({changedModelValue: {like: `%${value}%`}});
return {or};
case 'changes':
return {or: [
{oldInstance: {like: `%${value}%`}},
{newInstance: {like: `%${value}%`}},
{description: {like: `%${value}%`}}
]};
case 'who': case 'who':
switch (value) { switch (value) {
case 'all': case 'all':
@ -195,6 +223,10 @@ export default class Controller extends Section {
} }
} }
function firstUpper(str) {
return str && str.charAt(0).toUpperCase() + str.substr(1);
}
ngModule.vnComponent('vnLog', { ngModule.vnComponent('vnLog', {
controller: Controller, controller: Controller,
template: require('./index.html'), template: require('./index.html'),

View File

@ -1,5 +1,8 @@
Date: Fecha Date: Fecha
Model: Modelo Concept: Concepto
Search: Buscar
Search by id or concept: Buscar por identificador o concepto
Entity: Entidad
Action: Acción Action: Acción
Author: Autor Author: Autor
Before: Antes Before: Antes
@ -7,12 +10,12 @@ After: Despues
History: Historial History: Historial
Name: Nombre Name: Nombre
Creates: Crea Creates: Crea
Updates: Actualiza Edits: Modifica
Deletes: Elimina Deletes: Elimina
Views: Visualiza Accesses: Accede
System: Sistema System: Sistema
Details: Detalles
note: nota note: nota
Changes: Cambios Changes: Cambios
No changes: No hay cambios
today: hoy today: hoy
yesterday: ayer yesterday: ayer

View File

@ -1,10 +1,11 @@
@import "variables"; @import "variables";
@import "effects";
vn-log { vn-log {
.change { .change {
display: flex; display: flex;
& > .user-wrapper { & > .left {
position: relative; position: relative;
padding-right: 10px; padding-right: 10px;
@ -34,7 +35,7 @@ vn-log {
bottom: -8px; bottom: -8px;
} }
} }
&:last-child > .user-wrapper > .line { &:last-child > .left > .line {
display: none; display: none;
} }
.detail { .detail {
@ -45,18 +46,41 @@ vn-log {
overflow: hidden; overflow: hidden;
& > .header { & > .header {
display: flex;
justify-content: space-between;
align-items: center;
overflow: hidden;
& > .action-model {
display: inline-flex;
overflow: hidden;
& > .model-name {
display: inline-block;
padding: 2px 5px;
color: $color-font-dark;
border-radius: 8px;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
}
}
& > .action-date {
white-space: nowrap;
& > .chip { & > .action {
padding: 2px 4px; display: inline-flex;
border-radius: 4px; align-items: center;
display: inline-block; justify-content: center;
color: $color-font-bg; color: $color-font-bg;
vertical-align: middle;
border-radius: 50%;
width: 24px;
height: 24px;
font-size: 1.4em;
&.notice { &.notice {
background-color: $color-notice-medium; background-color: $color-notice-medium
} }
&.success { &.success {
background-color: $color-success-medium; background-color: $color-success-medium;
@ -68,8 +92,6 @@ vn-log {
background-color: lighten($color-alert, 5%); background-color: lighten($color-alert, 5%);
} }
} }
.date {
float: right;
} }
} }
& > .model { & > .model {
@ -77,16 +99,12 @@ vn-log {
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
& > .model-name {
text-transform: capitalize;
}
& > .model-value { & > .model-value {
font-style: italic; font-style: italic;
color: #c7bd2b;
} }
& > .model-id { & > .model-id {
color: $color-font-secondary; color: $color-font-secondary;
font-size: .9em; font-size: .9rem;
} }
} }
} }
@ -94,59 +112,35 @@ vn-log {
.changes { .changes {
overflow: hidden; overflow: hidden;
background-color: rgba(255, 255, 255, .05); background-color: rgba(255, 255, 255, .05);
border-radius: 4px; color: $color-font-light;
color: $color-font-secondary;
transition: max-height 150ms ease-in-out;
max-height: 28px;
position: relative; position: relative;
& > .expand-button,
& > .shrink-button {
display: none;
}
&.props {
padding-right: 24px;
& > .expand-button,
& > .shrink-button {
position: absolute;
top: 6px;
right: 8px;
font-size: inherit;
float: right;
cursor: pointer;
}
& > .expand-button {
display: block;
}
&.expanded {
max-height: 500px;
padding-right: 0;
& > .changes-wrapper {
text-overflow: initial;
white-space: initial;
}
& > .shrink-button {
display: block;
}
& > .expand-button {
display: none;
}
}
}
& > .changes-wrapper {
padding: 4px 6px;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
min-height: 34px;
box-sizing: border-box;
& > vn-icon {
@extend %clickable;
float: right;
position: relative;
transition-property: transform, background-color;
transition-duration: 150ms;
margin: -5px;
margin-left: 4px;
padding: 1px;
border-radius: 50%;
}
&.expanded {
text-overflow: initial;
white-space: initial;
& > vn-icon {
transform: rotate(180deg);
}
}
& > .no-changes { & > .no-changes {
font-style: italic; font-style: italic;
} }
.json-field {
text-transform: capitalize;
}
}
} }
} }

View File

@ -33,7 +33,7 @@ export default class Controller {
const newPassword = this.newPassword; const newPassword = this.newPassword;
this.$http.post('users/reset-password', {newPassword}, {headers}) this.$http.post('VnUsers/reset-password', {newPassword}, {headers})
.then(() => { .then(() => {
this.vnApp.showSuccess(this.$translate.instant('Password changed!')); this.vnApp.showSuccess(this.$translate.instant('Password changed!'));
this.$state.go('login'); this.$state.go('login');

View File

@ -171,5 +171,7 @@
"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" "A claim with that sale already exists": "A claim with that sale already exists",
"Can't transfer claimed sales": "Can't transfer claimed sales",
"Invalid quantity": "Invalid quantity"
} }

View File

@ -84,6 +84,7 @@
"The current ticket can't be modified": "El ticket actual no puede ser modificado", "The current ticket can't be modified": "El ticket actual no puede ser modificado",
"The current claim can't be modified": "La reclamación actual no puede ser modificada", "The current claim can't be modified": "La reclamación actual no puede ser modificada",
"The sales of this ticket can't be modified": "Las lineas de este ticket no pueden ser modificadas", "The sales of this ticket can't be modified": "Las lineas de este ticket no pueden ser modificadas",
"The sales do not exists": "La(s) línea(s) seleccionada(s) no existe(n)",
"Please select at least one sale": "Por favor selecciona al menos una linea", "Please select at least one sale": "Por favor selecciona al menos una linea",
"All sales must belong to the same ticket": "Todas las lineas deben pertenecer al mismo ticket", "All sales must belong to the same ticket": "Todas las lineas deben pertenecer al mismo ticket",
"NO_ZONE_FOR_THIS_PARAMETERS": "Para este día no hay ninguna zona configurada", "NO_ZONE_FOR_THIS_PARAMETERS": "Para este día no hay ninguna zona configurada",
@ -290,5 +291,7 @@
"isTaxDataChecked": "Datos comprobados", "isTaxDataChecked": "Datos comprobados",
"comercialId": "Id comercial", "comercialId": "Id comercial",
"comercialName": "Comercial", "comercialName": "Comercial",
"Invalid NIF for VIES": "Invalid NIF for VIES" "Invalid NIF for VIES": "Invalid NIF for VIES",
"Ticket does not exist": "Este ticket no existe",
"Ticket is already signed": "Este ticket ya ha sido firmado"
} }

View File

@ -0,0 +1,4 @@
name: mail forward
columns:
account: account
forwardTo: forward to

View File

@ -0,0 +1,4 @@
name: reenvio de correo
columns:
account: cuenta
forwardTo: reenviar a

View File

@ -1,4 +1,4 @@
name: mail name: correo electrónico
columns: columns:
id: id id: id
receiver: receptor receiver: receptor

View File

@ -0,0 +1,4 @@
name: subrole
columns:
role: rol
inheritsFrom: inherits

View File

@ -0,0 +1,4 @@
name: subrol
columns:
role: rol
inheritsFrom: hereda

View File

@ -0,0 +1,5 @@
name: role
columns:
id: id
name: name
description: description

View File

@ -0,0 +1,5 @@
name: rol
columns:
id: id
name: nombre
description: descripción

View File

@ -1,4 +1,4 @@
name: account name: user
columns: columns:
id: id id: id
name: name name: name
@ -6,7 +6,7 @@ columns:
nickname: nickname nickname: nickname
lang: lang lang: lang
password: password password: password
bcryptPassword: bcrypt password bcryptPassword: BCRYPT password
active: active active: active
email: email email: email
emailVerified: email verified emailVerified: email verified

View File

@ -1,4 +1,4 @@
name: cuenta name: usuario
columns: columns:
id: id id: id
name: nombre name: nombre
@ -6,12 +6,12 @@ columns:
nickname: apodo nickname: apodo
lang: idioma lang: idioma
password: contraseña password: contraseña
bcryptPassword: contraseña bcrypt bcryptPassword: contraseña BCRYPT
active: activo active: activo
email: email email: correo electrónico
emailVerified: email verificado emailVerified: correo verificado
created: creado created: creado
updated: actualizado updated: actualizado
image: imagen image: imagen
hasGrant: tiene permiso hasGrant: puede delegar
userFk: usuario userFk: usuario

View File

@ -1,4 +1,4 @@
name: claim beginning name: beginning
columns: columns:
id: id id: id
quantity: quantity quantity: quantity

View File

@ -1,4 +1,4 @@
name: comienzo reclamación name: comienzo
columns: columns:
id: id id: id
quantity: cantidad quantity: cantidad

View File

@ -1,4 +1,4 @@
name: claim development name: development
columns: columns:
id: id id: id
claimFk: claim claimFk: claim

View File

@ -1,4 +1,4 @@
name: desarrollo reclamación name: desarrollo
columns: columns:
id: id id: id
claimFk: reclamación claimFk: reclamación

View File

@ -1,4 +1,4 @@
name: claim dms name: document
columns: columns:
dmsFk: dms dmsFk: dms
claimFk: claim claimFk: claim

View File

@ -1,4 +1,4 @@
name: documento reclamación name: documento
columns: columns:
dmsFk: dms dmsFk: dms
claimFk: reclamación claimFk: reclamación

View File

@ -1,4 +1,4 @@
name: claim end name: end
columns: columns:
id: id id: id
claimFk: claim claimFk: claim

View File

@ -1,4 +1,4 @@
name: final reclamación name: finalización
columns: columns:
id: id id: id
claimFk: reclamación claimFk: reclamación

View File

@ -1,4 +1,4 @@
name: claim observation name: observation
columns: columns:
id: id id: id
claimFk: claim claimFk: claim

View File

@ -1,4 +1,4 @@
name: observación reclamación name: observación
columns: columns:
id: id id: id
claimFk: reclamación claimFk: reclamación

View File

@ -59,12 +59,14 @@ module.exports = Self => {
const landedPlusWeek = new Date(ticket.landed); const landedPlusWeek = new Date(ticket.landed);
landedPlusWeek.setDate(landedPlusWeek.getDate() + 7); landedPlusWeek.setDate(landedPlusWeek.getDate() + 7);
const hasClaimManagerRole = await models.VnUser.hasRole(userId, 'claimManager', myOptions);
const isClaimable = landedPlusWeek >= Date.vnNew(); const isClaimable = landedPlusWeek >= Date.vnNew();
const canCreateClaimAfterDeadline =
await models.ACL.checkAccessAcl(ctx, 'Claim', 'createAfterDeadline', 'WRITE');
if (ticket.isDeleted) if (ticket.isDeleted)
throw new UserError(`You can't create a claim for a removed ticket`); throw new UserError(`You can't create a claim for a removed ticket`);
if (!isClaimable && !hasClaimManagerRole) if (!isClaimable && !canCreateClaimAfterDeadline)
throw new UserError(`You can't create a claim from a ticket delivered more than seven days ago`); throw new UserError(`You can't create a claim from a ticket delivered more than seven days ago`);
const newClaim = await Self.create({ const newClaim = await Self.create({

View File

@ -46,7 +46,6 @@ module.exports = Self => {
Self.updateClaim = async(ctx, id, options) => { Self.updateClaim = async(ctx, id, options) => {
const models = Self.app.models; const models = Self.app.models;
const userId = ctx.req.accessToken.userId;
const args = ctx.args; const args = ctx.args;
let tx; let tx;
const myOptions = {}; const myOptions = {};
@ -81,9 +80,9 @@ module.exports = Self => {
if (args.claimStateFk) { if (args.claimStateFk) {
const canEditOldState = await models.ClaimState.isEditable(ctx, claim.claimStateFk, myOptions); const canEditOldState = await models.ClaimState.isEditable(ctx, claim.claimStateFk, myOptions);
const canEditNewState = await models.ClaimState.isEditable(ctx, args.claimStateFk, myOptions); const canEditNewState = await models.ClaimState.isEditable(ctx, args.claimStateFk, myOptions);
const isClaimManager = await models.VnUser.hasRole(userId, 'claimManager', myOptions); const canEditState = await models.ACL.checkAccessAcl(ctx, 'Claim', 'editState', 'WRITE');
if (!canEditOldState || !canEditNewState || changedHasToPickUp && !isClaimManager) if (!canEditOldState || !canEditNewState || changedHasToPickUp && !canEditState)
throw new UserError(`You don't have enough privileges to change that field`); throw new UserError(`You don't have enough privileges to change that field`);
} }

View File

@ -18,3 +18,4 @@ columns:
addressFk: address addressFk: address
incotermsFk: incoterms incotermsFk: incoterms
customsAgentFk: customs agent customsAgentFk: customs agent
isDefaultAddress: default

View File

@ -18,3 +18,4 @@ columns:
addressFk: dirección addressFk: dirección
incotermsFk: incoterms incotermsFk: incoterms
customsAgentFk: agente adunanas customsAgentFk: agente adunanas
isDefaultAddress: predeterminada

View File

@ -1,4 +1,4 @@
name: client contact name: contact
columns: columns:
id: id id: id
name: name name: name

View File

@ -1,4 +1,4 @@
name: contacto cliente name: contacto
columns: columns:
id: id id: id
name: nombre name: nombre

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