Merge pull request '7863-devToTest_2434' (!2852) from 7863-devToTest_2434 into test
gitea/salix/pipeline/head This commit looks good
Details
gitea/salix/pipeline/head This commit looks good
Details
Reviewed-on: #2852 Reviewed-by: Guillermo Bonet <guillermo@verdnatura.es>
This commit is contained in:
commit
25b3e36b18
|
@ -0,0 +1,50 @@
|
||||||
|
module.exports = Self => {
|
||||||
|
Self.remoteMethodCtx('add', {
|
||||||
|
description: 'Add activity if the activity is different or is the same but have exceed time for break',
|
||||||
|
accessType: 'WRITE',
|
||||||
|
accepts: [
|
||||||
|
{
|
||||||
|
arg: 'code',
|
||||||
|
type: 'string',
|
||||||
|
description: 'Code for activity'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
arg: 'model',
|
||||||
|
type: 'string',
|
||||||
|
description: 'Origin model from insert'
|
||||||
|
},
|
||||||
|
|
||||||
|
],
|
||||||
|
http: {
|
||||||
|
path: `/add`,
|
||||||
|
verb: 'POST'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Self.add = async(ctx, code, model, options) => {
|
||||||
|
const userId = ctx.req.accessToken.userId;
|
||||||
|
const myOptions = {};
|
||||||
|
|
||||||
|
if (typeof options == 'object')
|
||||||
|
Object.assign(myOptions, options);
|
||||||
|
|
||||||
|
return await Self.rawSql(`
|
||||||
|
INSERT INTO workerActivity (workerFk, workerActivityTypeFk, model)
|
||||||
|
SELECT ?, ?, ?
|
||||||
|
FROM workerTimeControlParams wtcp
|
||||||
|
LEFT JOIN (
|
||||||
|
SELECT wa.workerFk,
|
||||||
|
wa.created,
|
||||||
|
wat.code
|
||||||
|
FROM workerActivity wa
|
||||||
|
LEFT JOIN workerActivityType wat ON wat.code = wa.workerActivityTypeFk
|
||||||
|
WHERE wa.workerFk = ?
|
||||||
|
ORDER BY wa.created DESC
|
||||||
|
LIMIT 1
|
||||||
|
) sub ON TRUE
|
||||||
|
WHERE sub.workerFk IS NULL
|
||||||
|
OR sub.code <> ?
|
||||||
|
OR TIMESTAMPDIFF(SECOND, sub.created, util.VN_NOW()) > wtcp.dayBreak;`
|
||||||
|
, [userId, code, model, userId, code], myOptions);
|
||||||
|
};
|
||||||
|
};
|
|
@ -0,0 +1,30 @@
|
||||||
|
const {models} = require('vn-loopback');
|
||||||
|
|
||||||
|
describe('workerActivity insert()', () => {
|
||||||
|
const ctx = beforeAll.getCtx(1106);
|
||||||
|
|
||||||
|
it('should insert in workerActivity', async() => {
|
||||||
|
const tx = await models.WorkerActivity.beginTransaction({});
|
||||||
|
let count = 0;
|
||||||
|
const options = {transaction: tx};
|
||||||
|
|
||||||
|
try {
|
||||||
|
await models.WorkerActivityType.create(
|
||||||
|
{'code': 'STOP', 'description': 'STOP'}, options
|
||||||
|
);
|
||||||
|
|
||||||
|
await models.WorkerActivity.add(ctx, 'STOP', 'APP', options);
|
||||||
|
|
||||||
|
count = await models.WorkerActivity.count(
|
||||||
|
{'workerFK': 1106}, options
|
||||||
|
);
|
||||||
|
|
||||||
|
await tx.rollback();
|
||||||
|
} catch (e) {
|
||||||
|
await tx.rollback();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(count).toEqual(1);
|
||||||
|
});
|
||||||
|
});
|
|
@ -28,6 +28,9 @@
|
||||||
"Company": {
|
"Company": {
|
||||||
"dataSource": "vn"
|
"dataSource": "vn"
|
||||||
},
|
},
|
||||||
|
"Config": {
|
||||||
|
"dataSource": "vn"
|
||||||
|
},
|
||||||
"Continent": {
|
"Continent": {
|
||||||
"dataSource": "vn"
|
"dataSource": "vn"
|
||||||
},
|
},
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
{
|
||||||
|
"name": "Config",
|
||||||
|
"base": "VnModel",
|
||||||
|
"options": {
|
||||||
|
"mysql": {
|
||||||
|
"table": "config"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"properties": {
|
||||||
|
"inventoried": {
|
||||||
|
"type": "date"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"acls": [
|
||||||
|
{
|
||||||
|
"accessType": "READ",
|
||||||
|
"principalType": "ROLE",
|
||||||
|
"principalId": "$authenticated",
|
||||||
|
"permission": "ALLOW"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
module.exports = Self => {
|
||||||
|
require('../methods/workerActivity/add')(Self);
|
||||||
|
};
|
|
@ -22,18 +22,18 @@
|
||||||
},
|
},
|
||||||
"description": {
|
"description": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"relations": {
|
||||||
|
"workerFk": {
|
||||||
|
"type": "belongsTo",
|
||||||
|
"model": "Worker",
|
||||||
|
"foreignKey": "workerFk"
|
||||||
},
|
},
|
||||||
"relations": {
|
"workerActivityTypeFk": {
|
||||||
"workerFk": {
|
"type": "belongsTo",
|
||||||
"type": "belongsTo",
|
"model": "WorkerActivityType",
|
||||||
"model": "Worker",
|
"foreignKey": "workerActivityTypeFk"
|
||||||
"foreignKey": "workerFk"
|
|
||||||
},
|
|
||||||
"workerActivityTypeFk": {
|
|
||||||
"type": "belongsTo",
|
|
||||||
"model": "WorkerActivityType",
|
|
||||||
"foreignKey": "workerActivityTypeFk"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,59 +1,62 @@
|
||||||
DELIMITER $$
|
DELIMITER $$
|
||||||
CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `hedera`.`order_confirmWithUser`(vSelf INT, vUserId INT)
|
CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `hedera`.`order_confirmWithUser`(
|
||||||
|
vSelf INT,
|
||||||
|
vUserFk INT
|
||||||
|
)
|
||||||
BEGIN
|
BEGIN
|
||||||
/**
|
/**
|
||||||
* Confirms an order, creating each of its tickets on the corresponding
|
* Confirms an order, creating each of its tickets
|
||||||
* date, store and user.
|
* on the corresponding date, store and user.
|
||||||
*
|
*
|
||||||
* @param vSelf The order identifier
|
* @param vSelf The order identifier
|
||||||
* @param vUser The user identifier
|
* @param vUser The user identifier
|
||||||
*/
|
*/
|
||||||
DECLARE vOk BOOL;
|
DECLARE vHasRows BOOL;
|
||||||
DECLARE vDone BOOL DEFAULT FALSE;
|
DECLARE vDone BOOL;
|
||||||
DECLARE vWarehouse INT;
|
DECLARE vWarehouseFk INT;
|
||||||
DECLARE vShipment DATE;
|
DECLARE vShipment DATE;
|
||||||
DECLARE vTicket INT;
|
DECLARE vShipmentDayEnd DATETIME;
|
||||||
|
DECLARE vTicketFk INT;
|
||||||
DECLARE vNotes VARCHAR(255);
|
DECLARE vNotes VARCHAR(255);
|
||||||
DECLARE vItem INT;
|
DECLARE vItemFk INT;
|
||||||
DECLARE vConcept VARCHAR(30);
|
DECLARE vConcept VARCHAR(30);
|
||||||
DECLARE vAmount INT;
|
DECLARE vAmount INT;
|
||||||
|
DECLARE vAvailable INT;
|
||||||
DECLARE vPrice DECIMAL(10,2);
|
DECLARE vPrice DECIMAL(10,2);
|
||||||
DECLARE vSale INT;
|
DECLARE vSaleFk INT;
|
||||||
DECLARE vRate INT;
|
DECLARE vRowFk INT;
|
||||||
DECLARE vRowId INT;
|
|
||||||
DECLARE vPriceFixed DECIMAL(10,2);
|
DECLARE vPriceFixed DECIMAL(10,2);
|
||||||
DECLARE vDelivery DATE;
|
DECLARE vLanded DATE;
|
||||||
DECLARE vAddress INT;
|
DECLARE vAddressFk INT;
|
||||||
DECLARE vIsConfirmed BOOL;
|
DECLARE vClientFk INT;
|
||||||
DECLARE vClientId INT;
|
DECLARE vCompanyFk INT;
|
||||||
DECLARE vCompanyId INT;
|
DECLARE vAgencyModeFk INT;
|
||||||
DECLARE vAgencyModeId INT;
|
DECLARE vCalcFk INT;
|
||||||
DECLARE TICKET_FREE INT DEFAULT 2;
|
|
||||||
DECLARE vCalc INT;
|
|
||||||
DECLARE vIsLogifloraItem BOOL;
|
|
||||||
DECLARE vOldQuantity INT;
|
|
||||||
DECLARE vNewQuantity INT;
|
|
||||||
DECLARE vIsTaxDataChecked BOOL;
|
DECLARE vIsTaxDataChecked BOOL;
|
||||||
|
|
||||||
DECLARE cDates CURSOR FOR
|
DECLARE vDates CURSOR FOR
|
||||||
SELECT zgs.shipped, r.warehouse_id
|
SELECT zgs.shipped, r.warehouseFk
|
||||||
FROM `order` o
|
FROM `order` o
|
||||||
JOIN order_row r ON r.order_id = o.id
|
JOIN orderRow r ON r.orderFk = o.id
|
||||||
LEFT JOIN tmp.zoneGetShipped zgs ON zgs.warehouseFk = r.warehouse_id
|
LEFT JOIN tmp.zoneGetShipped zgs ON zgs.warehouseFk = r.warehouseFk
|
||||||
WHERE o.id = vSelf AND r.amount != 0
|
WHERE o.id = vSelf
|
||||||
GROUP BY r.warehouse_id;
|
AND r.amount
|
||||||
|
GROUP BY r.warehouseFk;
|
||||||
|
|
||||||
DECLARE cRows CURSOR FOR
|
DECLARE vRows CURSOR FOR
|
||||||
SELECT r.id, r.item_id, i.name, r.amount, r.price, r.rate, i.isFloramondo
|
SELECT r.id,
|
||||||
FROM order_row r
|
r.itemFk,
|
||||||
JOIN vn.item i ON i.id = r.item_id
|
i.name,
|
||||||
WHERE r.amount != 0
|
r.amount,
|
||||||
AND r.warehouse_id = vWarehouse
|
r.price
|
||||||
AND r.order_id = vSelf
|
FROM orderRow r
|
||||||
|
JOIN vn.item i ON i.id = r.itemFk
|
||||||
|
WHERE r.amount
|
||||||
|
AND r.warehouseFk = vWarehouseFk
|
||||||
|
AND r.orderFk = vSelf
|
||||||
ORDER BY r.rate DESC;
|
ORDER BY r.rate DESC;
|
||||||
|
|
||||||
DECLARE CONTINUE HANDLER FOR NOT FOUND
|
DECLARE CONTINUE HANDLER FOR NOT FOUND SET vDone = TRUE;
|
||||||
SET vDone = TRUE;
|
|
||||||
|
|
||||||
DECLARE EXIT HANDLER FOR SQLEXCEPTION
|
DECLARE EXIT HANDLER FOR SQLEXCEPTION
|
||||||
BEGIN
|
BEGIN
|
||||||
|
@ -62,26 +65,36 @@ BEGIN
|
||||||
END;
|
END;
|
||||||
|
|
||||||
-- Carga los datos del pedido
|
-- Carga los datos del pedido
|
||||||
SELECT o.date_send, o.address_id, o.note, a.clientFk,
|
SELECT o.date_send,
|
||||||
o.company_id, o.agency_id, c.isTaxDataChecked
|
o.address_id,
|
||||||
INTO vDelivery, vAddress, vNotes, vClientId,
|
o.note,
|
||||||
vCompanyId, vAgencyModeId, vIsTaxDataChecked
|
a.clientFk,
|
||||||
FROM hedera.`order` o
|
o.company_id,
|
||||||
|
o.agency_id,
|
||||||
|
c.isTaxDataChecked
|
||||||
|
INTO vLanded,
|
||||||
|
vAddressFk,
|
||||||
|
vNotes,
|
||||||
|
vClientFk,
|
||||||
|
vCompanyFk,
|
||||||
|
vAgencyModeFk,
|
||||||
|
vIsTaxDataChecked
|
||||||
|
FROM `order` o
|
||||||
JOIN vn.address a ON a.id = o.address_id
|
JOIN vn.address a ON a.id = o.address_id
|
||||||
JOIN vn.client c ON c.id = a.clientFk
|
JOIN vn.client c ON c.id = a.clientFk
|
||||||
WHERE o.id = vSelf;
|
WHERE o.id = vSelf;
|
||||||
|
|
||||||
-- Verifica si el cliente tiene los datos comprobados
|
-- Verifica si el cliente tiene los datos comprobados
|
||||||
IF NOT vIsTaxDataChecked THEN
|
IF NOT vIsTaxDataChecked THEN
|
||||||
CALL util.throw ('clientNotVerified');
|
CALL util.throw('clientNotVerified');
|
||||||
END IF;
|
END IF;
|
||||||
|
|
||||||
-- Carga las fechas de salida de cada almacen
|
-- Carga las fechas de salida de cada almacen
|
||||||
CALL vn.zone_getShipped (vDelivery, vAddress, vAgencyModeId, FALSE);
|
CALL vn.zone_getShipped(vLanded, vAddressFk, vAgencyModeFk, FALSE);
|
||||||
|
|
||||||
-- Trabajador que realiza la accion
|
-- Trabajador que realiza la accion
|
||||||
IF vUserId IS NULL THEN
|
IF vUserFk IS NULL THEN
|
||||||
SELECT employeeFk INTO vUserId FROM orderConfig;
|
SELECT employeeFk INTO vUserFk FROM orderConfig;
|
||||||
END IF;
|
END IF;
|
||||||
|
|
||||||
START TRANSACTION;
|
START TRANSACTION;
|
||||||
|
@ -89,207 +102,188 @@ BEGIN
|
||||||
CALL order_checkEditable(vSelf);
|
CALL order_checkEditable(vSelf);
|
||||||
|
|
||||||
-- Check order is not empty
|
-- Check order is not empty
|
||||||
|
SELECT COUNT(*) > 0 INTO vHasRows
|
||||||
|
FROM orderRow
|
||||||
|
WHERE orderFk = vSelf
|
||||||
|
AND amount > 0;
|
||||||
|
|
||||||
SELECT COUNT(*) > 0 INTO vOk
|
IF NOT vHasRows THEN
|
||||||
FROM order_row WHERE order_id = vSelf AND amount > 0;
|
CALL util.throw('ORDER_EMPTY');
|
||||||
|
|
||||||
IF NOT vOk THEN
|
|
||||||
CALL util.throw ('ORDER_EMPTY');
|
|
||||||
END IF;
|
END IF;
|
||||||
|
|
||||||
-- Crea los tickets del pedido
|
-- Crea los tickets del pedido
|
||||||
|
OPEN vDates;
|
||||||
OPEN cDates;
|
lDates: LOOP
|
||||||
|
SET vTicketFk = NULL;
|
||||||
lDates:
|
|
||||||
LOOP
|
|
||||||
SET vTicket = NULL;
|
|
||||||
SET vDone = FALSE;
|
SET vDone = FALSE;
|
||||||
FETCH cDates INTO vShipment, vWarehouse;
|
FETCH vDates INTO vShipment, vWarehouseFk;
|
||||||
|
|
||||||
IF vDone THEN
|
IF vDone THEN
|
||||||
LEAVE lDates;
|
LEAVE lDates;
|
||||||
END IF;
|
END IF;
|
||||||
|
|
||||||
-- Busca un ticket existente que coincida con los parametros
|
SET vShipmentDayEnd = util.dayEnd(vShipment);
|
||||||
WITH tPrevia AS
|
|
||||||
(SELECT DISTINCT s.ticketFk
|
-- Busca un ticket libre disponible
|
||||||
|
WITH tPrevia AS (
|
||||||
|
SELECT DISTINCT s.ticketFk
|
||||||
FROM vn.sale s
|
FROM vn.sale s
|
||||||
JOIN vn.saleGroupDetail sgd ON sgd.saleFk = s.id
|
JOIN vn.saleGroupDetail sgd ON sgd.saleFk = s.id
|
||||||
JOIN vn.ticket t ON t.id = s.ticketFk
|
JOIN vn.ticket t ON t.id = s.ticketFk
|
||||||
WHERE t.shipped BETWEEN vShipment AND util.dayend(vShipment)
|
WHERE t.shipped BETWEEN vShipment AND vShipmentDayEnd
|
||||||
)
|
)
|
||||||
SELECT t.id INTO vTicket
|
SELECT t.id INTO vTicketFk
|
||||||
FROM vn.ticket t
|
FROM vn.ticket t
|
||||||
JOIN vn.alertLevel al ON al.code = 'FREE'
|
JOIN vn.alertLevel al ON al.code = 'FREE'
|
||||||
LEFT JOIN tPrevia tp ON tp.ticketFk = t.id
|
LEFT JOIN tPrevia tp ON tp.ticketFk = t.id
|
||||||
LEFT JOIN vn.ticketState tls on tls.ticketFk = t.id
|
LEFT JOIN vn.ticketState tls ON tls.ticketFk = t.id
|
||||||
JOIN hedera.`order` o
|
JOIN hedera.`order` o ON o.address_id = t.addressFk
|
||||||
ON o.address_id = t.addressFk
|
AND t.shipped BETWEEN vShipment AND vShipmentDayEnd
|
||||||
AND vWarehouse = t.warehouseFk
|
AND t.warehouseFk = vWarehouseFk
|
||||||
AND o.date_send = t.landed
|
AND o.date_send = t.landed
|
||||||
AND DATE(t.shipped) = vShipment
|
|
||||||
WHERE o.id = vSelf
|
WHERE o.id = vSelf
|
||||||
AND t.refFk IS NULL
|
AND t.refFk IS NULL
|
||||||
AND tp.ticketFk IS NULL
|
AND tp.ticketFk IS NULL
|
||||||
AND (tls.alertLevel IS NULL OR tls.alertLevel = al.id)
|
AND (tls.alertLevel IS NULL OR tls.alertLevel = al.id)
|
||||||
LIMIT 1;
|
LIMIT 1;
|
||||||
|
|
||||||
|
-- Comprobamos si hay un ticket de previa disponible
|
||||||
|
IF vTicketFk IS NULL THEN
|
||||||
|
WITH tItemPackingTypeOrder AS (
|
||||||
|
SELECT GROUP_CONCAT(
|
||||||
|
DISTINCT i.itemPackingTypeFk ORDER BY i.itemPackingTypeFk
|
||||||
|
) distinctItemPackingTypes,
|
||||||
|
o.address_id
|
||||||
|
FROM vn.item i
|
||||||
|
JOIN hedera.orderRow oro ON oro.itemFk = i.id
|
||||||
|
JOIN hedera.`order` o ON o.id = oro.orderFk
|
||||||
|
WHERE oro.orderFk = vSelf
|
||||||
|
),
|
||||||
|
tItemPackingTypeTicket AS (
|
||||||
|
SELECT t.id,
|
||||||
|
GROUP_CONCAT(
|
||||||
|
DISTINCT i.itemPackingTypeFk ORDER BY i.itemPackingTypeFk
|
||||||
|
) distinctItemPackingTypes
|
||||||
|
FROM vn.ticket t
|
||||||
|
JOIN vn.ticketState tls ON tls.ticketFk = t.id
|
||||||
|
JOIN vn.alertLevel al ON al.id = tls.alertLevel
|
||||||
|
JOIN vn.sale s ON s.ticketFk = t.id
|
||||||
|
JOIN vn.item i ON i.id = s.itemFk
|
||||||
|
JOIN tItemPackingTypeOrder ipto
|
||||||
|
WHERE t.shipped BETWEEN vShipment AND vShipmentDayEnd
|
||||||
|
AND t.refFk IS NULL
|
||||||
|
AND t.warehouseFk = vWarehouseFk
|
||||||
|
AND t.addressFk = ipto.address_id
|
||||||
|
AND al.code = 'ON_PREVIOUS'
|
||||||
|
GROUP BY t.id
|
||||||
|
)
|
||||||
|
SELECT iptt.id INTO vTicketFk
|
||||||
|
FROM tItemPackingTypeTicket iptt
|
||||||
|
JOIN tItemPackingTypeOrder ipto
|
||||||
|
WHERE INSTR(iptt.distinctItemPackingTypes, ipto.distinctItemPackingTypes)
|
||||||
|
LIMIT 1;
|
||||||
|
END IF;
|
||||||
|
|
||||||
-- Crea el ticket en el caso de no existir uno adecuado
|
-- Crea el ticket en el caso de no existir uno adecuado
|
||||||
IF vTicket IS NULL
|
IF vTicketFk IS NULL THEN
|
||||||
THEN
|
|
||||||
|
|
||||||
SET vShipment = IFNULL(vShipment, util.VN_CURDATE());
|
SET vShipment = IFNULL(vShipment, util.VN_CURDATE());
|
||||||
|
|
||||||
CALL vn.ticket_add(
|
CALL vn.ticket_add(
|
||||||
vClientId,
|
vClientFk,
|
||||||
vShipment,
|
vShipment,
|
||||||
vWarehouse,
|
vWarehouseFk,
|
||||||
vCompanyId,
|
vCompanyFk,
|
||||||
vAddress,
|
vAddressFk,
|
||||||
vAgencyModeId,
|
vAgencyModeFk,
|
||||||
NULL,
|
NULL,
|
||||||
vDelivery,
|
vLanded,
|
||||||
vUserId,
|
vUserFk,
|
||||||
TRUE,
|
TRUE,
|
||||||
vTicket
|
vTicketFk
|
||||||
);
|
);
|
||||||
ELSE
|
ELSE
|
||||||
INSERT INTO vn.ticketTracking
|
INSERT INTO vn.ticketTracking
|
||||||
SET ticketFk = vTicket,
|
SET ticketFk = vTicketFk,
|
||||||
userFk = vUserId,
|
userFk = vUserFk,
|
||||||
stateFk = TICKET_FREE;
|
stateFk = (SELECT id FROM vn.state WHERE code = 'FREE');
|
||||||
END IF;
|
END IF;
|
||||||
|
|
||||||
INSERT IGNORE INTO vn.orderTicket
|
INSERT IGNORE INTO vn.orderTicket
|
||||||
SET orderFk = vSelf,
|
SET orderFk = vSelf,
|
||||||
ticketFk = vTicket;
|
ticketFk = vTicketFk;
|
||||||
|
|
||||||
-- Añade las notas
|
-- Añade las notas
|
||||||
|
IF vNotes IS NOT NULL AND vNotes <> '' THEN
|
||||||
IF vNotes IS NOT NULL AND vNotes != ''
|
INSERT INTO vn.ticketObservation
|
||||||
THEN
|
SET ticketFk = vTicketFk,
|
||||||
INSERT INTO vn.ticketObservation SET
|
observationTypeFk = (SELECT id FROM vn.observationType WHERE code = 'salesPerson'),
|
||||||
ticketFk = vTicket,
|
|
||||||
observationTypeFk = 4 /* salesperson */ ,
|
|
||||||
`description` = vNotes
|
`description` = vNotes
|
||||||
ON DUPLICATE KEY UPDATE
|
ON DUPLICATE KEY UPDATE
|
||||||
`description` = CONCAT(VALUES(`description`),'. ', `description`);
|
`description` = CONCAT(VALUES(`description`),'. ', `description`);
|
||||||
END IF;
|
END IF;
|
||||||
|
|
||||||
-- Añade los movimientos y sus componentes
|
-- Añade los movimientos y sus componentes
|
||||||
|
OPEN vRows;
|
||||||
OPEN cRows;
|
|
||||||
|
|
||||||
lRows: LOOP
|
lRows: LOOP
|
||||||
|
SET vSaleFk = NULL;
|
||||||
SET vDone = FALSE;
|
SET vDone = FALSE;
|
||||||
FETCH cRows INTO vRowId, vItem, vConcept, vAmount, vPrice, vRate, vIsLogifloraItem;
|
FETCH vRows INTO vRowFk, vItemFk, vConcept, vAmount, vPrice;
|
||||||
|
|
||||||
IF vDone THEN
|
IF vDone THEN
|
||||||
LEAVE lRows;
|
LEAVE lRows;
|
||||||
END IF;
|
END IF;
|
||||||
|
|
||||||
SET vSale = NULL;
|
SELECT s.id INTO vSaleFk
|
||||||
|
|
||||||
SELECT s.id, s.quantity INTO vSale, vOldQuantity
|
|
||||||
FROM vn.sale s
|
FROM vn.sale s
|
||||||
WHERE ticketFk = vTicket
|
WHERE ticketFk = vTicketFk
|
||||||
AND price = vPrice
|
AND price = vPrice
|
||||||
AND itemFk = vItem
|
AND itemFk = vItemFk
|
||||||
AND discount = 0
|
AND discount = 0
|
||||||
LIMIT 1;
|
LIMIT 1;
|
||||||
|
|
||||||
IF vSale THEN
|
IF vSaleFk THEN
|
||||||
UPDATE vn.sale
|
UPDATE vn.sale
|
||||||
SET quantity = quantity + vAmount,
|
SET quantity = quantity + vAmount,
|
||||||
originalQuantity = quantity
|
originalQuantity = quantity
|
||||||
WHERE id = vSale;
|
WHERE id = vSaleFk;
|
||||||
|
|
||||||
SELECT s.quantity INTO vNewQuantity
|
|
||||||
FROM vn.sale s
|
|
||||||
WHERE id = vSale;
|
|
||||||
ELSE
|
ELSE
|
||||||
-- Obtiene el coste
|
-- Obtiene el coste
|
||||||
SELECT SUM(rc.`price`) valueSum INTO vPriceFixed
|
SELECT SUM(rc.`price`) valueSum INTO vPriceFixed
|
||||||
FROM orderRowComponent rc
|
FROM orderRowComponent rc
|
||||||
JOIN vn.component c ON c.id = rc.componentFk
|
JOIN vn.component c ON c.id = rc.componentFk
|
||||||
JOIN vn.componentType ct ON ct.id = c.typeFk AND ct.isBase
|
JOIN vn.componentType ct ON ct.id = c.typeFk
|
||||||
WHERE rc.rowFk = vRowId;
|
AND ct.isBase
|
||||||
|
WHERE rc.rowFk = vRowFk;
|
||||||
|
|
||||||
INSERT INTO vn.sale
|
INSERT INTO vn.sale
|
||||||
SET itemFk = vItem,
|
SET itemFk = vItemFk,
|
||||||
ticketFk = vTicket,
|
ticketFk = vTicketFk,
|
||||||
concept = vConcept,
|
concept = vConcept,
|
||||||
quantity = vAmount,
|
quantity = vAmount,
|
||||||
price = vPrice,
|
price = vPrice,
|
||||||
priceFixed = vPriceFixed,
|
priceFixed = vPriceFixed,
|
||||||
isPriceFixed = TRUE;
|
isPriceFixed = TRUE;
|
||||||
|
|
||||||
SET vSale = LAST_INSERT_ID();
|
SET vSaleFk = LAST_INSERT_ID();
|
||||||
|
|
||||||
INSERT INTO vn.saleComponent
|
INSERT INTO vn.saleComponent (saleFk, componentFk, `value`)
|
||||||
(saleFk, componentFk, `value`)
|
SELECT vSaleFk, rc.componentFk, rc.price
|
||||||
SELECT vSale, rc.componentFk, rc.price
|
|
||||||
FROM orderRowComponent rc
|
FROM orderRowComponent rc
|
||||||
JOIN vn.component c ON c.id = rc.componentFk
|
JOIN vn.component c ON c.id = rc.componentFk
|
||||||
WHERE rc.rowFk = vRowId
|
WHERE rc.rowFk = vRowFk
|
||||||
GROUP BY vSale, rc.componentFk;
|
GROUP BY vSaleFk, rc.componentFk;
|
||||||
END IF;
|
END IF;
|
||||||
|
|
||||||
UPDATE order_row SET Id_Movimiento = vSale
|
UPDATE orderRow
|
||||||
WHERE id = vRowId;
|
SET saleFk = vSaleFk
|
||||||
|
WHERE id = vRowFk;
|
||||||
-- Inserta en putOrder si la compra es de Floramondo
|
|
||||||
IF vIsLogifloraItem THEN
|
|
||||||
CALL cache.availableNoRaids_refresh(vCalc,FALSE,vWarehouse,vShipment);
|
|
||||||
|
|
||||||
SET @available := 0;
|
|
||||||
|
|
||||||
SELECT GREATEST(0,available) INTO @available
|
|
||||||
FROM cache.availableNoRaids
|
|
||||||
WHERE calc_id = vCalc
|
|
||||||
AND item_id = vItem;
|
|
||||||
|
|
||||||
UPDATE cache.availableNoRaids
|
|
||||||
SET available = GREATEST(0,available - vAmount)
|
|
||||||
WHERE item_id = vItem
|
|
||||||
AND calc_id = vCalc;
|
|
||||||
|
|
||||||
INSERT INTO edi.putOrder (
|
|
||||||
deliveryInformationID,
|
|
||||||
supplyResponseId,
|
|
||||||
quantity ,
|
|
||||||
EndUserPartyId,
|
|
||||||
EndUserPartyGLN,
|
|
||||||
FHAdminNumber,
|
|
||||||
saleFk
|
|
||||||
)
|
|
||||||
SELECT di.ID,
|
|
||||||
i.supplyResponseFk,
|
|
||||||
CEIL((vAmount - @available)/ sr.NumberOfItemsPerCask),
|
|
||||||
o.address_id ,
|
|
||||||
vClientId,
|
|
||||||
IFNULL(ca.fhAdminNumber, fhc.defaultAdminNumber),
|
|
||||||
vSale
|
|
||||||
FROM edi.deliveryInformation di
|
|
||||||
JOIN vn.item i ON i.supplyResponseFk = di.supplyResponseID
|
|
||||||
JOIN edi.supplyResponse sr ON sr.ID = i.supplyResponseFk
|
|
||||||
LEFT JOIN edi.clientFHAdminNumber ca ON ca.clientFk = vClientId
|
|
||||||
JOIN edi.floraHollandConfig fhc
|
|
||||||
JOIN hedera.`order` o ON o.id = vSelf
|
|
||||||
WHERE i.id = vItem
|
|
||||||
AND di.LatestOrderDateTime > util.VN_NOW()
|
|
||||||
AND vAmount > @available
|
|
||||||
LIMIT 1;
|
|
||||||
END IF;
|
|
||||||
END LOOP;
|
END LOOP;
|
||||||
|
CLOSE vRows;
|
||||||
CLOSE cRows;
|
|
||||||
END LOOP;
|
END LOOP;
|
||||||
|
CLOSE vDates;
|
||||||
|
|
||||||
CLOSE cDates;
|
UPDATE `order`
|
||||||
|
SET confirmed = TRUE,
|
||||||
UPDATE `order` SET confirmed = TRUE, confirm_date = util.VN_NOW()
|
confirm_date = util.VN_NOW()
|
||||||
WHERE id = vSelf;
|
WHERE id = vSelf;
|
||||||
|
|
||||||
COMMIT;
|
COMMIT;
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
DELIMITER $$
|
||||||
|
CREATE OR REPLACE DEFINER=`root`@`localhost` TRIGGER `salix`.`ACL_afterDelete`
|
||||||
|
AFTER DELETE ON `ACL`
|
||||||
|
FOR EACH ROW
|
||||||
|
BEGIN
|
||||||
|
INSERT INTO ACL
|
||||||
|
SET `action` = 'delete',
|
||||||
|
`changedModel` = 'Acl',
|
||||||
|
`changedModelId` = OLD.id,
|
||||||
|
`userFk` = account.myUser_getId();
|
||||||
|
END$$
|
||||||
|
DELIMITER ;
|
|
@ -0,0 +1,8 @@
|
||||||
|
DELIMITER $$
|
||||||
|
CREATE OR REPLACE DEFINER=`root`@`localhost` TRIGGER `salix`.`ACL_beforeInsert`
|
||||||
|
BEFORE INSERT ON `ACL`
|
||||||
|
FOR EACH ROW
|
||||||
|
BEGIN
|
||||||
|
SET NEW.editorFk = account.myUser_getId();
|
||||||
|
END$$
|
||||||
|
DELIMITER ;
|
|
@ -0,0 +1,8 @@
|
||||||
|
DELIMITER $$
|
||||||
|
CREATE OR REPLACE DEFINER=`root`@`localhost` TRIGGER `salix`.`ACL_beforeUpdate`
|
||||||
|
BEFORE UPDATE ON `ACL`
|
||||||
|
FOR EACH ROW
|
||||||
|
BEGIN
|
||||||
|
SET NEW.editorFk = account.myUser_getId();
|
||||||
|
END$$
|
||||||
|
DELIMITER ;
|
|
@ -189,7 +189,7 @@ BEGIN
|
||||||
SELECT * FROM sales
|
SELECT * FROM sales
|
||||||
UNION ALL
|
UNION ALL
|
||||||
SELECT * FROM orders
|
SELECT * FROM orders
|
||||||
ORDER BY shipped,
|
ORDER BY shipped DESC,
|
||||||
(inventorySupplierFk = entityId) DESC,
|
(inventorySupplierFk = entityId) DESC,
|
||||||
alertLevel DESC,
|
alertLevel DESC,
|
||||||
isTicket,
|
isTicket,
|
||||||
|
@ -240,7 +240,7 @@ BEGIN
|
||||||
NULL reference,
|
NULL reference,
|
||||||
NULL entityType,
|
NULL entityType,
|
||||||
NULL entityId,
|
NULL entityId,
|
||||||
'Inventario calculado',
|
'Inventario calculado' entityName,
|
||||||
@a invalue,
|
@a invalue,
|
||||||
NULL `out`,
|
NULL `out`,
|
||||||
@a balance,
|
@a balance,
|
||||||
|
|
|
@ -1,139 +0,0 @@
|
||||||
DELIMITER $$
|
|
||||||
CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`supplier_statement`(
|
|
||||||
vSupplierFk INT,
|
|
||||||
vCurrencyFk INT,
|
|
||||||
vCompanyFk INT,
|
|
||||||
vOrderBy VARCHAR(15),
|
|
||||||
vIsConciliated BOOL
|
|
||||||
)
|
|
||||||
BEGIN
|
|
||||||
/**
|
|
||||||
* Crea un estado de cuenta de proveedores calculando
|
|
||||||
* los saldos en euros y en la moneda especificada.
|
|
||||||
*
|
|
||||||
* @param vSupplierFk Id del proveedor
|
|
||||||
* @param vCurrencyFk Id de la moneda
|
|
||||||
* @param vCompanyFk Id de la empresa
|
|
||||||
* @param vOrderBy Criterio de ordenación
|
|
||||||
* @param vIsConciliated Indica si está conciliado o no
|
|
||||||
* @return tmp.supplierStatement
|
|
||||||
*/
|
|
||||||
SET @euroBalance:= 0;
|
|
||||||
SET @currencyBalance:= 0;
|
|
||||||
|
|
||||||
CREATE OR REPLACE TEMPORARY TABLE tmp.supplierStatement
|
|
||||||
ENGINE = MEMORY
|
|
||||||
SELECT *,
|
|
||||||
@euroBalance:= ROUND(
|
|
||||||
@euroBalance + IFNULL(paymentEuros, 0) -
|
|
||||||
IFNULL(invoiceEuros, 0), 2
|
|
||||||
) euroBalance,
|
|
||||||
@currencyBalance:= ROUND(
|
|
||||||
@currencyBalance + IFNULL(paymentCurrency, 0) -
|
|
||||||
IFNULL(invoiceCurrency, 0), 2
|
|
||||||
) currencyBalance
|
|
||||||
FROM (
|
|
||||||
SELECT * FROM
|
|
||||||
(
|
|
||||||
SELECT NULL bankFk,
|
|
||||||
ii.companyFk,
|
|
||||||
ii.serial,
|
|
||||||
ii.id,
|
|
||||||
CASE
|
|
||||||
WHEN vOrderBy = 'issued' THEN ii.issued
|
|
||||||
WHEN vOrderBy = 'bookEntried' THEN ii.bookEntried
|
|
||||||
WHEN vOrderBy = 'booked' THEN ii.booked
|
|
||||||
WHEN vOrderBy = 'dueDate' THEN iid.dueDated
|
|
||||||
END dated,
|
|
||||||
CONCAT('S/Fra ', ii.supplierRef) sref,
|
|
||||||
IF(ii.currencyFk > 1,
|
|
||||||
ROUND(SUM(iid.foreignValue) / SUM(iid.amount), 3),
|
|
||||||
NULL
|
|
||||||
) changeValue,
|
|
||||||
CAST(SUM(iid.amount) AS DECIMAL(10,2)) invoiceEuros,
|
|
||||||
CAST(SUM(iid.foreignValue) AS DECIMAL(10,2)) invoiceCurrency,
|
|
||||||
NULL paymentEuros,
|
|
||||||
NULL paymentCurrency,
|
|
||||||
ii.currencyFk,
|
|
||||||
ii.isBooked,
|
|
||||||
c.code,
|
|
||||||
'invoiceIn' statementType
|
|
||||||
FROM invoiceIn ii
|
|
||||||
JOIN invoiceInDueDay iid ON iid.invoiceInFk = ii.id
|
|
||||||
JOIN currency c ON c.id = ii.currencyFk
|
|
||||||
WHERE ii.issued > '2014-12-31'
|
|
||||||
AND ii.supplierFk = vSupplierFk
|
|
||||||
AND vCurrencyFk IN (ii.currencyFk, 0)
|
|
||||||
AND vCompanyFk IN (ii.companyFk, 0)
|
|
||||||
AND (vIsConciliated = ii.isBooked OR NOT vIsConciliated)
|
|
||||||
GROUP BY iid.id
|
|
||||||
UNION ALL
|
|
||||||
SELECT p.bankFk,
|
|
||||||
p.companyFk,
|
|
||||||
NULL,
|
|
||||||
p.id,
|
|
||||||
CASE
|
|
||||||
WHEN vOrderBy = 'issued' THEN p.received
|
|
||||||
WHEN vOrderBy = 'bookEntried' THEN p.received
|
|
||||||
WHEN vOrderBy = 'booked' THEN p.received
|
|
||||||
WHEN vOrderBy = 'dueDate' THEN p.dueDated
|
|
||||||
END,
|
|
||||||
CONCAT(IFNULL(pm.name, ''),
|
|
||||||
IF(pn.concept <> '',
|
|
||||||
CONCAT(' : ', pn.concept),
|
|
||||||
'')
|
|
||||||
),
|
|
||||||
IF(p.currencyFk > 1, p.divisa / p.amount, NULL),
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
p.amount,
|
|
||||||
p.divisa,
|
|
||||||
p.currencyFk,
|
|
||||||
p.isConciliated,
|
|
||||||
c.code,
|
|
||||||
'payment'
|
|
||||||
FROM payment p
|
|
||||||
LEFT JOIN currency c ON c.id = p.currencyFk
|
|
||||||
LEFT JOIN accounting a ON a.id = p.bankFk
|
|
||||||
LEFT JOIN payMethod pm ON pm.id = p.payMethodFk
|
|
||||||
LEFT JOIN promissoryNote pn ON pn.paymentFk = p.id
|
|
||||||
WHERE p.received > '2014-12-31'
|
|
||||||
AND p.supplierFk = vSupplierFk
|
|
||||||
AND vCurrencyFk IN (p.currencyFk, 0)
|
|
||||||
AND vCompanyFk IN (p.companyFk, 0)
|
|
||||||
AND (vIsConciliated = p.isConciliated OR NOT vIsConciliated)
|
|
||||||
UNION ALL
|
|
||||||
SELECT NULL,
|
|
||||||
companyFk,
|
|
||||||
NULL,
|
|
||||||
se.id,
|
|
||||||
CASE
|
|
||||||
WHEN vOrderBy = 'issued' THEN se.dated
|
|
||||||
WHEN vOrderBy = 'bookEntried' THEN se.dated
|
|
||||||
WHEN vOrderBy = 'booked' THEN se.dated
|
|
||||||
WHEN vOrderBy = 'dueDate' THEN se.dueDated
|
|
||||||
END,
|
|
||||||
se.description,
|
|
||||||
1,
|
|
||||||
amount,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
currencyFk,
|
|
||||||
isConciliated,
|
|
||||||
c.`code`,
|
|
||||||
'expense'
|
|
||||||
FROM supplierExpense se
|
|
||||||
JOIN currency c ON c.id = se.currencyFk
|
|
||||||
WHERE se.supplierFk = vSupplierFk
|
|
||||||
AND vCurrencyFk IN (se.currencyFk,0)
|
|
||||||
AND vCompanyFk IN (se.companyFk,0)
|
|
||||||
AND (vIsConciliated = se.isConciliated OR NOT vIsConciliated)
|
|
||||||
) sub
|
|
||||||
ORDER BY (dated IS NULL AND NOT isBooked),
|
|
||||||
dated,
|
|
||||||
IF(vOrderBy = 'dueDate', id, NULL)
|
|
||||||
LIMIT 10000000000000000000
|
|
||||||
) t;
|
|
||||||
END$$
|
|
||||||
DELIMITER ;
|
|
|
@ -0,0 +1,166 @@
|
||||||
|
DELIMITER $$
|
||||||
|
CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE vn.supplier_statementWithEntries(
|
||||||
|
vSupplierFk INT,
|
||||||
|
vCurrencyFk INT,
|
||||||
|
vCompanyFk INT,
|
||||||
|
vOrderBy VARCHAR(15),
|
||||||
|
vIsConciliated BOOL,
|
||||||
|
vHasEntries BOOL
|
||||||
|
)
|
||||||
|
BEGIN
|
||||||
|
/**
|
||||||
|
* Creates a supplier statement, calculating balances in euros and the specified currency.
|
||||||
|
*
|
||||||
|
* @param vSupplierFk Supplier ID
|
||||||
|
* @param vCurrencyFk Currency ID
|
||||||
|
* @param vCompanyFk Company ID
|
||||||
|
* @param vOrderBy Order by criteria
|
||||||
|
* @param vIsConciliated Indicates whether it is reconciled or not
|
||||||
|
* @param vHasEntries Indicates if future entries must be shown
|
||||||
|
* @return tmp.supplierStatement
|
||||||
|
*/
|
||||||
|
DECLARE vBalanceStartingDate DATETIME;
|
||||||
|
|
||||||
|
SET @euroBalance:= 0;
|
||||||
|
SET @currencyBalance:= 0;
|
||||||
|
|
||||||
|
SELECT balanceStartingDate
|
||||||
|
INTO vBalanceStartingDate
|
||||||
|
FROM invoiceInConfig;
|
||||||
|
|
||||||
|
CREATE OR REPLACE TEMPORARY TABLE tmp.supplierStatement
|
||||||
|
ENGINE = MEMORY
|
||||||
|
SELECT *,
|
||||||
|
@euroBalance:= ROUND(
|
||||||
|
@euroBalance + IFNULL(paymentEuros, 0) -
|
||||||
|
IFNULL(invoiceEuros, 0), 2
|
||||||
|
) euroBalance,
|
||||||
|
@currencyBalance:= ROUND(
|
||||||
|
@currencyBalance + IFNULL(paymentCurrency, 0) -
|
||||||
|
IFNULL(invoiceCurrency, 0), 2
|
||||||
|
) currencyBalance
|
||||||
|
FROM (
|
||||||
|
SELECT NULL bankFk,
|
||||||
|
ii.companyFk,
|
||||||
|
ii.serial,
|
||||||
|
ii.id,
|
||||||
|
CASE
|
||||||
|
WHEN vOrderBy = 'issued' THEN ii.issued
|
||||||
|
WHEN vOrderBy = 'bookEntried' THEN ii.bookEntried
|
||||||
|
WHEN vOrderBy = 'booked' THEN ii.booked
|
||||||
|
WHEN vOrderBy = 'dueDate' THEN iid.dueDated
|
||||||
|
END dated,
|
||||||
|
CONCAT('S/Fra ', ii.supplierRef) sref,
|
||||||
|
IF(ii.currencyFk > 1,
|
||||||
|
ROUND(SUM(iid.foreignValue) / SUM(iid.amount), 3),
|
||||||
|
NULL
|
||||||
|
) changeValue,
|
||||||
|
CAST(SUM(iid.amount) AS DECIMAL(10,2)) invoiceEuros,
|
||||||
|
CAST(SUM(iid.foreignValue) AS DECIMAL(10,2)) invoiceCurrency,
|
||||||
|
NULL paymentEuros,
|
||||||
|
NULL paymentCurrency,
|
||||||
|
ii.currencyFk,
|
||||||
|
ii.isBooked,
|
||||||
|
c.code,
|
||||||
|
'invoiceIn' statementType
|
||||||
|
FROM invoiceIn ii
|
||||||
|
JOIN invoiceInDueDay iid ON iid.invoiceInFk = ii.id
|
||||||
|
JOIN currency c ON c.id = ii.currencyFk
|
||||||
|
WHERE ii.issued >= vBalanceStartingDate
|
||||||
|
AND ii.supplierFk = vSupplierFk
|
||||||
|
AND vCurrencyFk IN (ii.currencyFk, 0)
|
||||||
|
AND vCompanyFk IN (ii.companyFk, 0)
|
||||||
|
AND (vIsConciliated = ii.isBooked OR NOT vIsConciliated)
|
||||||
|
GROUP BY iid.id
|
||||||
|
UNION ALL
|
||||||
|
SELECT p.bankFk,
|
||||||
|
p.companyFk,
|
||||||
|
NULL,
|
||||||
|
p.id,
|
||||||
|
CASE
|
||||||
|
WHEN vOrderBy = 'issued' THEN p.received
|
||||||
|
WHEN vOrderBy = 'bookEntried' THEN p.received
|
||||||
|
WHEN vOrderBy = 'booked' THEN p.received
|
||||||
|
WHEN vOrderBy = 'dueDate' THEN p.dueDated
|
||||||
|
END,
|
||||||
|
CONCAT(IFNULL(pm.name, ''),
|
||||||
|
IF(pn.concept <> '',
|
||||||
|
CONCAT(' : ', pn.concept),
|
||||||
|
'')
|
||||||
|
),
|
||||||
|
IF(p.currencyFk > 1, p.divisa / p.amount, NULL),
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
p.amount,
|
||||||
|
p.divisa,
|
||||||
|
p.currencyFk,
|
||||||
|
p.isConciliated,
|
||||||
|
c.code,
|
||||||
|
'payment'
|
||||||
|
FROM payment p
|
||||||
|
LEFT JOIN currency c ON c.id = p.currencyFk
|
||||||
|
LEFT JOIN accounting a ON a.id = p.bankFk
|
||||||
|
LEFT JOIN payMethod pm ON pm.id = p.payMethodFk
|
||||||
|
LEFT JOIN promissoryNote pn ON pn.paymentFk = p.id
|
||||||
|
WHERE p.received >= vBalanceStartingDate
|
||||||
|
AND p.supplierFk = vSupplierFk
|
||||||
|
AND vCurrencyFk IN (p.currencyFk, 0)
|
||||||
|
AND vCompanyFk IN (p.companyFk, 0)
|
||||||
|
AND (vIsConciliated = p.isConciliated OR NOT vIsConciliated)
|
||||||
|
UNION ALL
|
||||||
|
SELECT NULL,
|
||||||
|
companyFk,
|
||||||
|
NULL,
|
||||||
|
se.id,
|
||||||
|
CASE
|
||||||
|
WHEN vOrderBy = 'issued' THEN se.dated
|
||||||
|
WHEN vOrderBy = 'bookEntried' THEN se.dated
|
||||||
|
WHEN vOrderBy = 'booked' THEN se.dated
|
||||||
|
WHEN vOrderBy = 'dueDate' THEN se.dueDated
|
||||||
|
END,
|
||||||
|
se.description,
|
||||||
|
1,
|
||||||
|
amount,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
currencyFk,
|
||||||
|
isConciliated,
|
||||||
|
c.`code`,
|
||||||
|
'expense'
|
||||||
|
FROM supplierExpense se
|
||||||
|
JOIN currency c ON c.id = se.currencyFk
|
||||||
|
WHERE se.supplierFk = vSupplierFk
|
||||||
|
AND vCurrencyFk IN (se.currencyFk,0)
|
||||||
|
AND vCompanyFk IN (se.companyFk,0)
|
||||||
|
AND (vIsConciliated = se.isConciliated OR NOT vIsConciliated)
|
||||||
|
UNION ALL
|
||||||
|
SELECT NULL bankFk,
|
||||||
|
e.companyFk,
|
||||||
|
'E' serial,
|
||||||
|
e.invoiceNumber id,
|
||||||
|
tr.landed dated,
|
||||||
|
CONCAT('Ent. ',e.id) sref,
|
||||||
|
1 / ((e.commission/100)+1) changeValue,
|
||||||
|
e.invoiceAmount * (1 + (e.commission/100)),
|
||||||
|
e.invoiceAmount,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
e.currencyFk,
|
||||||
|
FALSE isBooked,
|
||||||
|
c.code,
|
||||||
|
'order'
|
||||||
|
FROM entry e
|
||||||
|
JOIN travel tr ON tr.id = e.travelFk
|
||||||
|
JOIN currency c ON c.id = e.currencyFk
|
||||||
|
WHERE e.supplierFk = vSupplierFk
|
||||||
|
AND tr.landed >= CURDATE()
|
||||||
|
AND e.invoiceInFk IS NULL
|
||||||
|
AND vHasEntries
|
||||||
|
ORDER BY (dated IS NULL AND NOT isBooked),
|
||||||
|
dated,
|
||||||
|
IF(vOrderBy = 'dueDate', id, NULL)
|
||||||
|
LIMIT 10000000000000000000
|
||||||
|
) t;
|
||||||
|
END$$
|
||||||
|
DELIMITER ;
|
|
@ -4,7 +4,6 @@ CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`ticket_cloneWeekly`
|
||||||
vDateTo DATE
|
vDateTo DATE
|
||||||
)
|
)
|
||||||
BEGIN
|
BEGIN
|
||||||
DECLARE vIsDone BOOL;
|
|
||||||
DECLARE vLanding DATE;
|
DECLARE vLanding DATE;
|
||||||
DECLARE vShipment DATE;
|
DECLARE vShipment DATE;
|
||||||
DECLARE vWarehouseFk INT;
|
DECLARE vWarehouseFk INT;
|
||||||
|
@ -15,36 +14,37 @@ BEGIN
|
||||||
DECLARE vAgencyModeFk INT;
|
DECLARE vAgencyModeFk INT;
|
||||||
DECLARE vNewTicket INT;
|
DECLARE vNewTicket INT;
|
||||||
DECLARE vYear INT;
|
DECLARE vYear INT;
|
||||||
DECLARE vSalesPersonFK INT;
|
DECLARE vObservationSalesPersonFk INT
|
||||||
DECLARE vItemPicker INT;
|
DEFAULT (SELECT id FROM observationType WHERE code = 'salesPerson');
|
||||||
|
DECLARE vObservationItemPickerFk INT
|
||||||
|
DEFAULT (SELECT id FROM observationType WHERE code = 'itemPicker');
|
||||||
|
DECLARE vEmail VARCHAR(255);
|
||||||
|
DECLARE vIsDuplicateMail BOOL;
|
||||||
|
DECLARE vSubject VARCHAR(100);
|
||||||
|
DECLARE vMessage TEXT;
|
||||||
|
DECLARE vDone BOOL;
|
||||||
|
|
||||||
DECLARE rsTicket CURSOR FOR
|
DECLARE vTickets CURSOR FOR
|
||||||
SELECT tt.ticketFk,
|
SELECT tt.ticketFk,
|
||||||
t.clientFk,
|
t.clientFk,
|
||||||
t.warehouseFk,
|
t.warehouseFk,
|
||||||
t.companyFk,
|
t.companyFk,
|
||||||
t.addressFk,
|
t.addressFk,
|
||||||
tt.agencyModeFk,
|
tt.agencyModeFk,
|
||||||
ti.dated
|
ti.dated
|
||||||
FROM ticketWeekly tt
|
FROM ticketWeekly tt
|
||||||
JOIN ticket t ON tt.ticketFk = t.id
|
JOIN ticket t ON tt.ticketFk = t.id
|
||||||
JOIN tmp.time ti
|
JOIN tmp.time ti
|
||||||
WHERE WEEKDAY(ti.dated) = tt.weekDay;
|
WHERE WEEKDAY(ti.dated) = tt.weekDay;
|
||||||
|
|
||||||
DECLARE CONTINUE HANDLER FOR NOT FOUND SET vIsDone = TRUE;
|
DECLARE CONTINUE HANDLER FOR NOT FOUND SET vDone = TRUE;
|
||||||
|
|
||||||
CALL `util`.`time_generate`(vDateFrom,vDateTo);
|
|
||||||
|
|
||||||
OPEN rsTicket;
|
|
||||||
myLoop: LOOP
|
|
||||||
BEGIN
|
|
||||||
DECLARE vSalesPersonEmail VARCHAR(150);
|
|
||||||
DECLARE vIsDuplicateMail BOOL;
|
|
||||||
DECLARE vSubject VARCHAR(150);
|
|
||||||
DECLARE vMessage TEXT;
|
|
||||||
|
|
||||||
SET vIsDone = FALSE;
|
CALL `util`.`time_generate`(vDateFrom, vDateTo);
|
||||||
FETCH rsTicket INTO
|
|
||||||
|
OPEN vTickets;
|
||||||
|
l: LOOP
|
||||||
|
SET vDone = FALSE;
|
||||||
|
FETCH vTickets INTO
|
||||||
vTicketFk,
|
vTicketFk,
|
||||||
vClientFk,
|
vClientFk,
|
||||||
vWarehouseFk,
|
vWarehouseFk,
|
||||||
|
@ -53,11 +53,11 @@ BEGIN
|
||||||
vAgencyModeFk,
|
vAgencyModeFk,
|
||||||
vShipment;
|
vShipment;
|
||||||
|
|
||||||
IF vIsDone THEN
|
IF vDone THEN
|
||||||
LEAVE myLoop;
|
LEAVE l;
|
||||||
END IF;
|
END IF;
|
||||||
|
|
||||||
-- busca si el ticket ya ha sido clonado
|
-- Busca si el ticket ya ha sido clonado
|
||||||
IF EXISTS (SELECT TRUE FROM ticket tOrig
|
IF EXISTS (SELECT TRUE FROM ticket tOrig
|
||||||
JOIN sale saleOrig ON tOrig.id = saleOrig.ticketFk
|
JOIN sale saleOrig ON tOrig.id = saleOrig.ticketFk
|
||||||
JOIN saleCloned sc ON sc.saleOriginalFk = saleOrig.id
|
JOIN saleCloned sc ON sc.saleOriginalFk = saleOrig.id
|
||||||
|
@ -67,7 +67,7 @@ BEGIN
|
||||||
AND tClon.isDeleted = FALSE
|
AND tClon.isDeleted = FALSE
|
||||||
AND DATE(tClon.shipped) = vShipment)
|
AND DATE(tClon.shipped) = vShipment)
|
||||||
THEN
|
THEN
|
||||||
ITERATE myLoop;
|
ITERATE l;
|
||||||
END IF;
|
END IF;
|
||||||
|
|
||||||
IF vAgencyModeFk IS NULL THEN
|
IF vAgencyModeFk IS NULL THEN
|
||||||
|
@ -107,15 +107,15 @@ BEGIN
|
||||||
priceFixed,
|
priceFixed,
|
||||||
isPriceFixed)
|
isPriceFixed)
|
||||||
SELECT vNewTicket,
|
SELECT vNewTicket,
|
||||||
saleOrig.itemFk,
|
itemFk,
|
||||||
saleOrig.concept,
|
concept,
|
||||||
saleOrig.quantity,
|
quantity,
|
||||||
saleOrig.price,
|
price,
|
||||||
saleOrig.discount,
|
discount,
|
||||||
saleOrig.priceFixed,
|
priceFixed,
|
||||||
saleOrig.isPriceFixed
|
isPriceFixed
|
||||||
FROM sale saleOrig
|
FROM sale
|
||||||
WHERE saleOrig.ticketFk = vTicketFk;
|
WHERE ticketFk = vTicketFk;
|
||||||
|
|
||||||
INSERT IGNORE INTO saleCloned(saleOriginalFk, saleClonedFk)
|
INSERT IGNORE INTO saleCloned(saleOriginalFk, saleClonedFk)
|
||||||
SELECT saleOriginal.id, saleClon.id
|
SELECT saleOriginal.id, saleClon.id
|
||||||
|
@ -152,15 +152,7 @@ BEGIN
|
||||||
attenderFk,
|
attenderFk,
|
||||||
vNewTicket
|
vNewTicket
|
||||||
FROM ticketRequest
|
FROM ticketRequest
|
||||||
WHERE ticketFk =vTicketFk;
|
WHERE ticketFk = vTicketFk;
|
||||||
|
|
||||||
SELECT id INTO vSalesPersonFK
|
|
||||||
FROM observationType
|
|
||||||
WHERE code = 'salesPerson';
|
|
||||||
|
|
||||||
SELECT id INTO vItemPicker
|
|
||||||
FROM observationType
|
|
||||||
WHERE code = 'itemPicker';
|
|
||||||
|
|
||||||
INSERT INTO ticketObservation(
|
INSERT INTO ticketObservation(
|
||||||
ticketFk,
|
ticketFk,
|
||||||
|
@ -168,7 +160,7 @@ BEGIN
|
||||||
description)
|
description)
|
||||||
VALUES(
|
VALUES(
|
||||||
vNewTicket,
|
vNewTicket,
|
||||||
vSalesPersonFK,
|
vObservationSalesPersonFk,
|
||||||
CONCAT('turno desde ticket: ',vTicketFk))
|
CONCAT('turno desde ticket: ',vTicketFk))
|
||||||
ON DUPLICATE KEY UPDATE description =
|
ON DUPLICATE KEY UPDATE description =
|
||||||
CONCAT(ticketObservation.description,VALUES(description),' ');
|
CONCAT(ticketObservation.description,VALUES(description),' ');
|
||||||
|
@ -178,16 +170,17 @@ BEGIN
|
||||||
description)
|
description)
|
||||||
VALUES(
|
VALUES(
|
||||||
vNewTicket,
|
vNewTicket,
|
||||||
vItemPicker,
|
vObservationItemPickerFk,
|
||||||
'ATENCION: Contiene lineas de TURNO')
|
'ATENCION: Contiene lineas de TURNO')
|
||||||
ON DUPLICATE KEY UPDATE description =
|
ON DUPLICATE KEY UPDATE description =
|
||||||
CONCAT(ticketObservation.description,VALUES(description),' ');
|
CONCAT(ticketObservation.description,VALUES(description),' ');
|
||||||
|
|
||||||
IF (vLanding IS NULL) THEN
|
IF vLanding IS NULL THEN
|
||||||
|
SELECT IFNULL(d.notificationEmail, e.email) INTO vEmail
|
||||||
SELECT e.email INTO vSalesPersonEmail
|
|
||||||
FROM client c
|
FROM client c
|
||||||
JOIN account.emailUser e ON e.userFk = c.salesPersonFk
|
JOIN account.emailUser e ON e.userFk = c.salesPersonFk
|
||||||
|
LEFT JOIN workerDepartment wd ON wd.workerFk = c.salesPersonFk
|
||||||
|
LEFT JOIN department d ON d.id = wd.departmentFk
|
||||||
WHERE c.id = vClientFk;
|
WHERE c.id = vClientFk;
|
||||||
|
|
||||||
SET vSubject = CONCAT('Turnos - No se ha podido clonar correctamente el ticket ',
|
SET vSubject = CONCAT('Turnos - No se ha podido clonar correctamente el ticket ',
|
||||||
|
@ -199,20 +192,21 @@ BEGIN
|
||||||
|
|
||||||
SELECT COUNT(*) INTO vIsDuplicateMail
|
SELECT COUNT(*) INTO vIsDuplicateMail
|
||||||
FROM mail
|
FROM mail
|
||||||
WHERE receiver = vSalesPersonEmail
|
WHERE receiver = vEmail
|
||||||
AND subject = vSubject;
|
AND subject = vSubject;
|
||||||
|
|
||||||
IF NOT vIsDuplicateMail THEN
|
IF NOT vIsDuplicateMail THEN
|
||||||
CALL mail_insert(vSalesPersonEmail, NULL, vSubject, vMessage);
|
CALL mail_insert(vEmail, NULL, vSubject, vMessage);
|
||||||
END IF;
|
END IF;
|
||||||
CALL ticket_setState(vNewTicket, 'FIXING');
|
CALL ticket_setState(vNewTicket, 'FIXING');
|
||||||
ELSE
|
ELSE
|
||||||
CALL ticketCalculateClon(vNewTicket, vTicketFk);
|
CALL ticketCalculateClon(vNewTicket, vTicketFk);
|
||||||
END IF;
|
END IF;
|
||||||
|
|
||||||
END;
|
|
||||||
END LOOP;
|
END LOOP;
|
||||||
CLOSE rsTicket;
|
CLOSE vTickets;
|
||||||
DROP TEMPORARY TABLE IF EXISTS tmp.time, tmp.zoneGetLanded;
|
|
||||||
|
DROP TEMPORARY TABLE IF EXISTS
|
||||||
|
tmp.time,
|
||||||
|
tmp.zoneGetLanded;
|
||||||
END$$
|
END$$
|
||||||
DELIMITER ;
|
DELIMITER ;
|
||||||
|
|
|
@ -1,55 +1,57 @@
|
||||||
DELIMITER $$
|
DELIMITER $$
|
||||||
CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`zone_getAddresses`(
|
CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`zone_getAddresses`(
|
||||||
vSelf INT,
|
vSelf INT,
|
||||||
vLanded DATE
|
vShipped DATE,
|
||||||
|
vDepartmentFk INT
|
||||||
)
|
)
|
||||||
BEGIN
|
BEGIN
|
||||||
/**
|
/**
|
||||||
* Devuelve un listado de todos los clientes activos
|
* Devuelve un listado de todos los clientes activos
|
||||||
* con consignatarios a los que se les puede
|
* con consignatarios a los que se les puede
|
||||||
* vender producto para esa zona y no tiene un ticket
|
* vender producto para esa zona.
|
||||||
* para ese día.
|
|
||||||
*
|
*
|
||||||
* @param vSelf Id de zona
|
* @param vSelf Id de zona
|
||||||
* @param vDated Fecha de entrega
|
* @param vShipped Fecha de envio
|
||||||
|
* @param vDepartmentFk Id de departamento
|
||||||
* @return Un select
|
* @return Un select
|
||||||
*/
|
*/
|
||||||
CALL zone_getPostalCode(vSelf);
|
CALL zone_getPostalCode(vSelf);
|
||||||
|
|
||||||
WITH notHasTicket AS (
|
WITH clientWithTicket AS (
|
||||||
SELECT id
|
SELECT clientFk
|
||||||
FROM vn.client
|
FROM vn.ticket
|
||||||
WHERE id NOT IN (
|
WHERE shipped BETWEEN vShipped AND util.dayEnd(vShipped)
|
||||||
SELECT clientFk
|
|
||||||
FROM vn.ticket
|
|
||||||
WHERE landed BETWEEN vLanded AND util.dayEnd(vLanded)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
SELECT c.id clientFk,
|
SELECT c.id,
|
||||||
c.name,
|
c.name,
|
||||||
c.phone,
|
c.phone,
|
||||||
bt.description,
|
bt.description,
|
||||||
c.salesPersonFk,
|
c.salesPersonFk,
|
||||||
u.name username,
|
u.name username,
|
||||||
aai.invoiced,
|
aai.invoiced,
|
||||||
cnb.lastShipped
|
cnb.lastShipped,
|
||||||
FROM vn.client c
|
cwt.clientFk
|
||||||
JOIN notHasTicket ON notHasTicket.id = c.id
|
FROM vn.client c
|
||||||
LEFT JOIN account.`user` u ON u.id = c.salesPersonFk
|
JOIN vn.worker w ON w.id = c.salesPersonFk
|
||||||
JOIN vn.`address` a ON a.clientFk = c.id
|
JOIN vn.workerDepartment wd ON wd.workerFk = w.id
|
||||||
JOIN vn.postCode pc ON pc.code = a.postalCode
|
JOIN vn.department d ON d.id = wd.departmentFk
|
||||||
JOIN vn.town t ON t.id = pc.townFk AND t.provinceFk = a.provinceFk
|
LEFT JOIN clientWithTicket cwt ON cwt.clientFk = c.id
|
||||||
JOIN vn.zoneGeo zg ON zg.name = a.postalCode
|
LEFT JOIN account.`user` u ON u.id = c.salesPersonFk
|
||||||
JOIN tmp.zoneNodes zn ON zn.geoFk = pc.geoFk
|
JOIN vn.`address` a ON a.clientFk = c.id
|
||||||
LEFT JOIN bs.clientNewBorn cnb ON cnb.clientFk = c.id
|
JOIN vn.postCode pc ON pc.code = a.postalCode
|
||||||
LEFT JOIN vn.annualAverageInvoiced aai ON aai.clientFk = c.id
|
JOIN vn.town t ON t.id = pc.townFk AND t.provinceFk = a.provinceFk
|
||||||
JOIN vn.clientType ct ON ct.code = c.typeFk
|
JOIN vn.zoneGeo zg ON zg.name = a.postalCode
|
||||||
JOIN vn.businessType bt ON bt.code = c.businessTypeFk
|
JOIN tmp.zoneNodes zn ON zn.geoFk = pc.geoFk
|
||||||
WHERE a.isActive
|
LEFT JOIN bs.clientNewBorn cnb ON cnb.clientFk = c.id
|
||||||
AND c.isActive
|
LEFT JOIN vn.annualAverageInvoiced aai ON aai.clientFk = c.id
|
||||||
AND ct.code = 'normal'
|
JOIN vn.clientType ct ON ct.code = c.typeFk
|
||||||
AND bt.code <> 'worker'
|
JOIN vn.businessType bt ON bt.code = c.businessTypeFk
|
||||||
GROUP BY c.id;
|
WHERE a.isActive
|
||||||
|
AND c.isActive
|
||||||
|
AND ct.code = 'normal'
|
||||||
|
AND bt.code <> 'worker'
|
||||||
|
AND (d.id = vDepartmentFk OR NOT vDepartmentFk)
|
||||||
|
GROUP BY c.id;
|
||||||
|
|
||||||
DROP TEMPORARY TABLE tmp.zoneNodes;
|
DROP TEMPORARY TABLE tmp.zoneNodes;
|
||||||
END$$
|
END$$
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
ALTER TABLE vn.productionConfig
|
||||||
|
DROP COLUMN scannableCodeType,
|
||||||
|
DROP COLUMN scannablePreviusCodeType;
|
|
@ -0,0 +1,25 @@
|
||||||
|
CREATE OR REPLACE TABLE `salix`.`ACLLog` (
|
||||||
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||||
|
`originFk` int(11) DEFAULT NULL,
|
||||||
|
`userFk` int(10) unsigned DEFAULT NULL,
|
||||||
|
`action` set('insert','update','delete','select') NOT NULL,
|
||||||
|
`creationDate` timestamp NULL DEFAULT current_timestamp(),
|
||||||
|
`description` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL,
|
||||||
|
`changedModel` enum('Acl') NOT NULL DEFAULT 'Acl',
|
||||||
|
`oldInstance` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL CHECK (json_valid(`oldInstance`)),
|
||||||
|
`newInstance` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL CHECK (json_valid(`newInstance`)),
|
||||||
|
`changedModelId` int(11) NOT NULL,
|
||||||
|
`changedModelValue` varchar(45) DEFAULT NULL,
|
||||||
|
`summaryId` varchar(30) DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `logRateuserFk` (`userFk`),
|
||||||
|
KEY `ACLLog_changedModel` (`changedModel`,`changedModelId`,`creationDate`),
|
||||||
|
KEY `ACLLog_originFk` (`originFk`,`creationDate`),
|
||||||
|
CONSTRAINT `aclUserFk` FOREIGN KEY (`userFk`) REFERENCES `account`.`user` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
|
||||||
|
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;
|
||||||
|
|
||||||
|
ALTER TABLE salix.ACL
|
||||||
|
ADD editorFk int(10) unsigned DEFAULT NULL NULL;
|
||||||
|
|
||||||
|
ALTER TABLE vn.ticket
|
||||||
|
CHANGE editorFk editorFk int(10) unsigned DEFAULT NULL NULL AFTER risk;
|
|
@ -0,0 +1,2 @@
|
||||||
|
RENAME TABLE vn.silexACL TO vn.silexACL__;
|
||||||
|
ALTER TABLE vn.silexACL__ COMMENT='@deprecated 2024-08-05 refs #7820';
|
|
@ -0,0 +1,2 @@
|
||||||
|
-- Place your SQL code here
|
||||||
|
ALTER TABLE vn.invoiceInConfig ADD balanceStartingDate DATE DEFAULT '2015-01-01' NOT NULL;
|
|
@ -738,69 +738,6 @@ export default {
|
||||||
worker: 'vn-worker-autocomplete[ng-model="$ctrl.userFk"]',
|
worker: 'vn-worker-autocomplete[ng-model="$ctrl.userFk"]',
|
||||||
saveStateButton: `button[type=submit]`
|
saveStateButton: `button[type=submit]`
|
||||||
},
|
},
|
||||||
claimsIndex: {
|
|
||||||
searchResult: 'vn-claim-index vn-card > vn-table > div > vn-tbody > a'
|
|
||||||
},
|
|
||||||
claimDescriptor: {
|
|
||||||
moreMenu: 'vn-claim-descriptor vn-icon-button[icon=more_vert]',
|
|
||||||
moreMenuDeleteClaim: '.vn-menu [name="deleteClaim"]',
|
|
||||||
acceptDeleteClaim: '.vn-confirm.shown button[response="accept"]'
|
|
||||||
},
|
|
||||||
claimSummary: {
|
|
||||||
header: 'vn-claim-summary > vn-card > h5',
|
|
||||||
state: 'vn-claim-summary vn-label-value[label="State"] > section > span',
|
|
||||||
observation: 'vn-claim-summary vn-horizontal.text',
|
|
||||||
firstSaleItemId: 'vn-claim-summary vn-horizontal > vn-auto:nth-child(5) vn-table > div > vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(1) > span',
|
|
||||||
firstSaleDescriptorImage: '.vn-popover.shown vn-item-descriptor img',
|
|
||||||
itemDescriptorPopover: '.vn-popover.shown vn-item-descriptor',
|
|
||||||
itemDescriptorPopoverItemDiaryButton: '.vn-popover vn-item-descriptor vn-quick-link[icon="icon-transaction"] > a',
|
|
||||||
firstDevelopmentWorker: 'vn-claim-summary vn-horizontal > vn-auto:nth-child(4) vn-table > div > vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(4) > span',
|
|
||||||
firstDevelopmentWorkerGoToClientButton: '.vn-popover vn-worker-descriptor vn-quick-link[icon="person"] > a',
|
|
||||||
firstActionTicketId: 'vn-claim-summary > vn-card > vn-horizontal > vn-auto:nth-child(5) vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(2) > span',
|
|
||||||
firstActionTicketDescriptor: '.vn-popover.shown vn-ticket-descriptor'
|
|
||||||
},
|
|
||||||
claimBasicData: {
|
|
||||||
claimState: 'vn-claim-basic-data vn-autocomplete[ng-model="$ctrl.claim.claimStateFk"]',
|
|
||||||
packages: 'vn-input-number[ng-model="$ctrl.claim.packages"]',
|
|
||||||
saveButton: `button[type=submit]`
|
|
||||||
},
|
|
||||||
claimDetail: {
|
|
||||||
secondItemDiscount: 'vn-claim-detail > vn-vertical > vn-card > vn-vertical > vn-table > div > vn-tbody > vn-tr:nth-child(2) > vn-td:nth-child(6) > span',
|
|
||||||
discount: '.vn-popover.shown vn-input-number[ng-model="$ctrl.newDiscount"]',
|
|
||||||
discoutPopoverMana: '.vn-popover.shown .content > div > vn-horizontal > h5',
|
|
||||||
addItemButton: 'vn-claim-detail a vn-float-button',
|
|
||||||
firstClaimableSaleFromTicket: '.vn-dialog.shown vn-tbody > vn-tr',
|
|
||||||
claimDetailLine: 'vn-claim-detail > vn-vertical > vn-card > vn-vertical > vn-table > div > vn-tbody > vn-tr',
|
|
||||||
totalClaimed: 'vn-claim-detail > vn-vertical > vn-card > vn-vertical > vn-horizontal > div > vn-label-value:nth-child(2) > section > span',
|
|
||||||
secondItemDeleteButton: 'vn-claim-detail > vn-vertical > vn-card > vn-vertical > vn-table > div > vn-tbody > vn-tr:nth-child(2) > vn-td:nth-child(8) > vn-icon-button > button > vn-icon > i'
|
|
||||||
},
|
|
||||||
claimDevelopment: {
|
|
||||||
addDevelopmentButton: 'vn-claim-development > vn-vertical > vn-card > vn-vertical > vn-one > vn-icon-button > button > vn-icon',
|
|
||||||
firstDeleteDevelopmentButton: 'vn-claim-development > vn-vertical > vn-card > vn-vertical > form > vn-horizontal:nth-child(2) > vn-icon-button > button > vn-icon',
|
|
||||||
firstClaimReason: 'vn-claim-development vn-horizontal:nth-child(1) vn-autocomplete[ng-model="claimDevelopment.claimReasonFk"]',
|
|
||||||
firstClaimResult: 'vn-claim-development vn-horizontal:nth-child(1) vn-autocomplete[ng-model="claimDevelopment.claimResultFk"]',
|
|
||||||
firstClaimResponsible: 'vn-claim-development vn-horizontal:nth-child(1) vn-autocomplete[ng-model="claimDevelopment.claimResponsibleFk"]',
|
|
||||||
firstClaimWorker: 'vn-claim-development vn-horizontal:nth-child(1) vn-worker-autocomplete[ng-model="claimDevelopment.workerFk"]',
|
|
||||||
firstClaimRedelivery: 'vn-claim-development vn-horizontal:nth-child(1) vn-autocomplete[ng-model="claimDevelopment.claimRedeliveryFk"]',
|
|
||||||
secondClaimReason: 'vn-claim-development vn-horizontal:nth-child(2) vn-autocomplete[ng-model="claimDevelopment.claimReasonFk"]',
|
|
||||||
secondClaimResult: 'vn-claim-development vn-horizontal:nth-child(2) vn-autocomplete[ng-model="claimDevelopment.claimResultFk"]',
|
|
||||||
secondClaimResponsible: 'vn-claim-development vn-horizontal:nth-child(2) vn-autocomplete[ng-model="claimDevelopment.claimResponsibleFk"]',
|
|
||||||
secondClaimWorker: 'vn-claim-development vn-horizontal:nth-child(2) vn-worker-autocomplete[ng-model="claimDevelopment.workerFk"]',
|
|
||||||
secondClaimRedelivery: 'vn-claim-development vn-horizontal:nth-child(2) vn-autocomplete[ng-model="claimDevelopment.claimRedeliveryFk"]',
|
|
||||||
saveDevelopmentButton: 'button[type=submit]'
|
|
||||||
},
|
|
||||||
claimNote: {
|
|
||||||
addNoteFloatButton: 'vn-float-button',
|
|
||||||
note: 'vn-textarea[ng-model="$ctrl.note.text"]',
|
|
||||||
saveButton: 'button[type=submit]',
|
|
||||||
firstNoteText: 'vn-claim-note .text'
|
|
||||||
},
|
|
||||||
claimAction: {
|
|
||||||
importClaimButton: 'vn-claim-action vn-button[label="Import claim"]',
|
|
||||||
anyLine: 'vn-claim-action vn-tbody > vn-tr',
|
|
||||||
firstDeleteLine: 'vn-claim-action tr:nth-child(2) vn-icon-button[icon="delete"]',
|
|
||||||
isPaidWithManaCheckbox: 'vn-claim-action vn-check[ng-model="$ctrl.claim.isChargedToMana"]'
|
|
||||||
},
|
|
||||||
ordersIndex: {
|
ordersIndex: {
|
||||||
secondSearchResultTotal: 'vn-order-index vn-card > vn-table > div > vn-tbody .vn-tr:nth-child(2) vn-td:nth-child(9)',
|
secondSearchResultTotal: 'vn-order-index vn-card > vn-table > div > vn-tbody .vn-tr:nth-child(2) vn-td:nth-child(9)',
|
||||||
advancedSearchButton: 'vn-order-search-panel vn-submit[label="Search"]',
|
advancedSearchButton: 'vn-order-search-panel vn-submit[label="Search"]',
|
||||||
|
|
|
@ -1,29 +0,0 @@
|
||||||
import selectors from '../../../helpers/selectors.js';
|
|
||||||
import getBrowser from '../../../helpers/puppeteer';
|
|
||||||
|
|
||||||
describe('department summary path', () => {
|
|
||||||
let browser;
|
|
||||||
let page;
|
|
||||||
beforeAll(async() => {
|
|
||||||
browser = await getBrowser();
|
|
||||||
page = browser.page;
|
|
||||||
await page.loginAndModule('hr', 'worker');
|
|
||||||
await page.accessToSection('worker.department');
|
|
||||||
await page.doSearch('INFORMATICA');
|
|
||||||
await page.click(selectors.department.firstDepartment);
|
|
||||||
});
|
|
||||||
|
|
||||||
afterAll(async() => {
|
|
||||||
await browser.close();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should reach the employee summary section and check all properties', async() => {
|
|
||||||
expect(await page.waitToGetProperty(selectors.departmentSummary.header, 'innerText')).toEqual('INFORMATICA');
|
|
||||||
expect(await page.getProperty(selectors.departmentSummary.name, 'innerText')).toEqual('INFORMATICA');
|
|
||||||
expect(await page.getProperty(selectors.departmentSummary.code, 'innerText')).toEqual('it');
|
|
||||||
expect(await page.getProperty(selectors.departmentSummary.chat, 'innerText')).toEqual('informatica-cau');
|
|
||||||
expect(await page.getProperty(selectors.departmentSummary.bossDepartment, 'innerText')).toEqual('');
|
|
||||||
expect(await page.getProperty(selectors.departmentSummary.email, 'innerText')).toEqual('-');
|
|
||||||
expect(await page.getProperty(selectors.departmentSummary.clientFk, 'innerText')).toEqual('-');
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,43 +0,0 @@
|
||||||
import getBrowser from '../../../helpers/puppeteer';
|
|
||||||
import selectors from '../../../helpers/selectors.js';
|
|
||||||
|
|
||||||
const $ = {
|
|
||||||
form: 'vn-worker-department-basic-data form',
|
|
||||||
};
|
|
||||||
|
|
||||||
describe('department summary path', () => {
|
|
||||||
let browser;
|
|
||||||
let page;
|
|
||||||
beforeAll(async() => {
|
|
||||||
browser = await getBrowser();
|
|
||||||
page = browser.page;
|
|
||||||
await page.loginAndModule('hr', 'worker');
|
|
||||||
await page.accessToSection('worker.department');
|
|
||||||
await page.doSearch('INFORMATICA');
|
|
||||||
await page.click(selectors.department.firstDepartment);
|
|
||||||
});
|
|
||||||
|
|
||||||
beforeEach(async() => {
|
|
||||||
await page.accessToSection('worker.department.card.basicData');
|
|
||||||
});
|
|
||||||
|
|
||||||
afterAll(async() => {
|
|
||||||
await browser.close();
|
|
||||||
});
|
|
||||||
|
|
||||||
it(`should edit the department basic data and confirm the department data was edited`, async() => {
|
|
||||||
const values = {
|
|
||||||
Name: 'Informatica',
|
|
||||||
Code: 'IT',
|
|
||||||
Chat: 'informatica-cau',
|
|
||||||
Email: 'it@verdnatura.es',
|
|
||||||
};
|
|
||||||
|
|
||||||
await page.fillForm($.form, values);
|
|
||||||
const formValues = await page.fetchForm($.form, Object.keys(values));
|
|
||||||
const message = await page.sendForm($.form, values);
|
|
||||||
|
|
||||||
expect(message.isSuccess).toBeTrue();
|
|
||||||
expect(formValues).toEqual(values);
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,34 +0,0 @@
|
||||||
import selectors from '../../helpers/selectors.js';
|
|
||||||
import getBrowser from '../../helpers/puppeteer';
|
|
||||||
|
|
||||||
describe('Worker summary path', () => {
|
|
||||||
const workerId = 3;
|
|
||||||
let browser;
|
|
||||||
let page;
|
|
||||||
beforeAll(async() => {
|
|
||||||
browser = await getBrowser();
|
|
||||||
page = browser.page;
|
|
||||||
await page.loginAndModule('employee', 'worker');
|
|
||||||
const httpDataResponse = page.waitForResponse(response => {
|
|
||||||
return response.status() === 200 && response.url().includes(`Workers/${workerId}`);
|
|
||||||
});
|
|
||||||
await page.accessToSearchResult('agencyNick');
|
|
||||||
await httpDataResponse;
|
|
||||||
});
|
|
||||||
|
|
||||||
afterAll(async() => {
|
|
||||||
await browser.close();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should reach the employee summary section and check all properties', async() => {
|
|
||||||
expect(await page.getProperty(selectors.workerSummary.header, 'innerText')).toEqual('agency agency');
|
|
||||||
expect(await page.getProperty(selectors.workerSummary.id, 'innerText')).toEqual('3');
|
|
||||||
expect(await page.getProperty(selectors.workerSummary.email, 'innerText')).toEqual('agency@verdnatura.es');
|
|
||||||
expect(await page.getProperty(selectors.workerSummary.department, 'innerText')).toEqual('CAMARA');
|
|
||||||
expect(await page.getProperty(selectors.workerSummary.userId, 'innerText')).toEqual('3');
|
|
||||||
expect(await page.getProperty(selectors.workerSummary.userName, 'innerText')).toEqual('agency');
|
|
||||||
expect(await page.getProperty(selectors.workerSummary.role, 'innerText')).toEqual('agency');
|
|
||||||
expect(await page.getProperty(selectors.workerSummary.extension, 'innerText')).toEqual('1101');
|
|
||||||
expect(await page.getProperty(selectors.workerSummary.locker, 'innerText')).toEqual('-');
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,40 +0,0 @@
|
||||||
import selectors from '../../helpers/selectors.js';
|
|
||||||
import getBrowser from '../../helpers/puppeteer';
|
|
||||||
|
|
||||||
describe('Worker basic data path', () => {
|
|
||||||
const workerId = 1106;
|
|
||||||
let browser;
|
|
||||||
let page;
|
|
||||||
beforeAll(async() => {
|
|
||||||
browser = await getBrowser();
|
|
||||||
page = browser.page;
|
|
||||||
await page.loginAndModule('hr', 'worker');
|
|
||||||
const httpDataResponse = page.waitForResponse(response => {
|
|
||||||
return response.status() === 200 && response.url().includes(`Workers/${workerId}`);
|
|
||||||
});
|
|
||||||
await page.accessToSearchResult('David Charles Haller');
|
|
||||||
await httpDataResponse;
|
|
||||||
await page.accessToSection('worker.card.basicData');
|
|
||||||
});
|
|
||||||
|
|
||||||
afterAll(async() => {
|
|
||||||
await browser.close();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should edit the form and then reload the section and check the data was edited', async() => {
|
|
||||||
await page.overwrite(selectors.workerBasicData.name, 'David C.');
|
|
||||||
await page.overwrite(selectors.workerBasicData.surname, 'H.');
|
|
||||||
await page.overwrite(selectors.workerBasicData.phone, '444332211');
|
|
||||||
await page.click(selectors.workerBasicData.saveButton);
|
|
||||||
|
|
||||||
const message = await page.waitForSnackbar();
|
|
||||||
|
|
||||||
expect(message.text).toContain('Data saved!');
|
|
||||||
|
|
||||||
await page.reloadSection('worker.card.basicData');
|
|
||||||
|
|
||||||
expect(await page.waitToGetProperty(selectors.workerBasicData.name, 'value')).toEqual('David C.');
|
|
||||||
expect(await page.waitToGetProperty(selectors.workerBasicData.surname, 'value')).toEqual('H.');
|
|
||||||
expect(await page.waitToGetProperty(selectors.workerBasicData.phone, 'value')).toEqual('444332211');
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,32 +0,0 @@
|
||||||
import selectors from '../../helpers/selectors.js';
|
|
||||||
import getBrowser from '../../helpers/puppeteer';
|
|
||||||
|
|
||||||
describe('Worker pbx path', () => {
|
|
||||||
let browser;
|
|
||||||
let page;
|
|
||||||
beforeAll(async() => {
|
|
||||||
browser = await getBrowser();
|
|
||||||
page = browser.page;
|
|
||||||
await page.loginAndModule('hr', 'worker');
|
|
||||||
await page.accessToSearchResult('employee');
|
|
||||||
await page.accessToSection('worker.card.pbx');
|
|
||||||
});
|
|
||||||
|
|
||||||
afterAll(async() => {
|
|
||||||
await browser.close();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should receive an error when the extension exceeds 4 characters and then sucessfully save the changes', async() => {
|
|
||||||
await page.write(selectors.workerPbx.extension, '55555');
|
|
||||||
await page.click(selectors.workerPbx.saveButton);
|
|
||||||
let message = await page.waitForSnackbar();
|
|
||||||
|
|
||||||
expect(message.text).toContain('Extension format is invalid');
|
|
||||||
|
|
||||||
await page.overwrite(selectors.workerPbx.extension, '4444');
|
|
||||||
await page.click(selectors.workerPbx.saveButton);
|
|
||||||
message = await page.waitForSnackbar();
|
|
||||||
|
|
||||||
expect(message.text).toContain('Data saved! User must access web');
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,65 +0,0 @@
|
||||||
/* eslint max-len: ["error", { "code": 150 }]*/
|
|
||||||
import selectors from '../../helpers/selectors.js';
|
|
||||||
import getBrowser from '../../helpers/puppeteer';
|
|
||||||
|
|
||||||
describe('Worker time control path', () => {
|
|
||||||
let browser;
|
|
||||||
let page;
|
|
||||||
beforeAll(async() => {
|
|
||||||
browser = await getBrowser();
|
|
||||||
page = browser.page;
|
|
||||||
await page.loginAndModule('salesBoss', 'worker');
|
|
||||||
await page.accessToSearchResult('HankPym');
|
|
||||||
await page.accessToSection('worker.card.timeControl');
|
|
||||||
});
|
|
||||||
|
|
||||||
afterAll(async() => {
|
|
||||||
await browser.close();
|
|
||||||
});
|
|
||||||
|
|
||||||
const eightAm = '08:00';
|
|
||||||
const fourPm = '16:00';
|
|
||||||
const hankPymId = 1107;
|
|
||||||
|
|
||||||
it('should go to the next month, go to current month and go 1 month in the past', async() => {
|
|
||||||
let date = Date.vnNew();
|
|
||||||
date.setDate(1);
|
|
||||||
date.setMonth(date.getMonth() + 1);
|
|
||||||
let month = date.toLocaleString('default', {month: 'long'});
|
|
||||||
|
|
||||||
await page.waitToClick(selectors.workerTimeControl.nextMonthButton);
|
|
||||||
let result = await page.getProperty(selectors.workerTimeControl.monthName, 'innerText');
|
|
||||||
|
|
||||||
expect(result).toContain(month);
|
|
||||||
|
|
||||||
date = Date.vnNew();
|
|
||||||
date.setDate(1);
|
|
||||||
month = date.toLocaleString('default', {month: 'long'});
|
|
||||||
|
|
||||||
await page.waitToClick(selectors.workerTimeControl.previousMonthButton);
|
|
||||||
result = await page.getProperty(selectors.workerTimeControl.monthName, 'innerText');
|
|
||||||
|
|
||||||
expect(result).toContain(month);
|
|
||||||
|
|
||||||
date = Date.vnNew();
|
|
||||||
date.setDate(1);
|
|
||||||
date.setMonth(date.getMonth() - 1);
|
|
||||||
const timestamp = Math.round(date.getTime() / 1000);
|
|
||||||
month = date.toLocaleString('default', {month: 'long'});
|
|
||||||
|
|
||||||
await page.loginAndModule('salesBoss', 'worker');
|
|
||||||
await page.goto(`http://localhost:5000/#!/worker/${hankPymId}/time-control?timestamp=${timestamp}`);
|
|
||||||
await page.waitToClick(selectors.workerTimeControl.secondWeekDay);
|
|
||||||
|
|
||||||
result = await page.getProperty(selectors.workerTimeControl.monthName, 'innerText');
|
|
||||||
|
|
||||||
expect(result).toContain(month);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should change week of month', async() => {
|
|
||||||
await page.click(selectors.workerTimeControl.thrirdWeekDay);
|
|
||||||
const result = await page.getProperty(selectors.workerTimeControl.mondayWorkedHours, 'innerText');
|
|
||||||
|
|
||||||
expect(result).toEqual('00:00 h.');
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,114 +0,0 @@
|
||||||
/* eslint-disable max-len */
|
|
||||||
import selectors from '../../helpers/selectors.js';
|
|
||||||
import getBrowser from '../../helpers/puppeteer';
|
|
||||||
|
|
||||||
describe('Worker calendar path', () => {
|
|
||||||
const reasonableTimeBetweenClicks = 300;
|
|
||||||
const date = Date.vnNew();
|
|
||||||
const lastYear = (date.getFullYear() - 1).toString();
|
|
||||||
|
|
||||||
let browser;
|
|
||||||
let page;
|
|
||||||
|
|
||||||
async function accessAs(user) {
|
|
||||||
await page.loginAndModule(user, 'worker');
|
|
||||||
await page.accessToSearchResult('Charles Xavier');
|
|
||||||
await page.accessToSection('worker.card.calendar');
|
|
||||||
}
|
|
||||||
|
|
||||||
beforeAll(async() => {
|
|
||||||
browser = await getBrowser();
|
|
||||||
page = browser.page;
|
|
||||||
accessAs('hr');
|
|
||||||
});
|
|
||||||
|
|
||||||
afterAll(async() => {
|
|
||||||
await browser.close();
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('as hr', () => {
|
|
||||||
it('should set two days as holidays on the calendar and check the total holidays increased by 1.5', async() => {
|
|
||||||
await page.waitToClick(selectors.workerCalendar.holidays);
|
|
||||||
await page.waitForTimeout(reasonableTimeBetweenClicks);
|
|
||||||
await page.click(selectors.workerCalendar.penultimateMondayOfJanuary);
|
|
||||||
|
|
||||||
await page.waitForTimeout(reasonableTimeBetweenClicks);
|
|
||||||
await page.click(selectors.workerCalendar.absence);
|
|
||||||
await page.waitForTimeout(reasonableTimeBetweenClicks);
|
|
||||||
await page.click(selectors.workerCalendar.lastMondayOfMarch);
|
|
||||||
|
|
||||||
await page.waitForTimeout(reasonableTimeBetweenClicks);
|
|
||||||
await page.click(selectors.workerCalendar.halfHoliday);
|
|
||||||
await page.waitForTimeout(reasonableTimeBetweenClicks);
|
|
||||||
await page.click(selectors.workerCalendar.fistMondayOfMay);
|
|
||||||
|
|
||||||
await page.waitForTimeout(reasonableTimeBetweenClicks);
|
|
||||||
await page.click(selectors.workerCalendar.furlough);
|
|
||||||
await page.waitForTimeout(reasonableTimeBetweenClicks);
|
|
||||||
await page.click(selectors.workerCalendar.secondTuesdayOfMay);
|
|
||||||
await page.waitForTimeout(reasonableTimeBetweenClicks);
|
|
||||||
await page.click(selectors.workerCalendar.secondWednesdayOfMay);
|
|
||||||
await page.waitForTimeout(reasonableTimeBetweenClicks);
|
|
||||||
await page.click(selectors.workerCalendar.secondThursdayOfMay);
|
|
||||||
|
|
||||||
await page.waitForTimeout(reasonableTimeBetweenClicks);
|
|
||||||
await page.click(selectors.workerCalendar.halfFurlough);
|
|
||||||
await page.waitForTimeout(reasonableTimeBetweenClicks);
|
|
||||||
await page.click(selectors.workerCalendar.secondFridayOfJun);
|
|
||||||
|
|
||||||
expect(await page.getProperty(selectors.workerCalendar.totalHolidaysUsed, 'innerText')).toContain(' 1.5 ');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe(`as salesBoss`, () => {
|
|
||||||
it(`should log in, get to Charles Xavier's calendar, undo what was done here, and check the total holidays used are back to what it was`, async() => {
|
|
||||||
accessAs('salesBoss');
|
|
||||||
|
|
||||||
await page.waitToClick(selectors.workerCalendar.holidays);
|
|
||||||
await page.waitForTimeout(reasonableTimeBetweenClicks);
|
|
||||||
await page.waitToClick(selectors.workerCalendar.penultimateMondayOfJanuary);
|
|
||||||
|
|
||||||
await page.waitForTimeout(reasonableTimeBetweenClicks);
|
|
||||||
await page.waitToClick(selectors.workerCalendar.absence);
|
|
||||||
await page.waitForTimeout(reasonableTimeBetweenClicks);
|
|
||||||
await page.waitToClick(selectors.workerCalendar.lastMondayOfMarch);
|
|
||||||
|
|
||||||
await page.waitForTimeout(reasonableTimeBetweenClicks);
|
|
||||||
await page.waitToClick(selectors.workerCalendar.halfHoliday);
|
|
||||||
await page.waitForTimeout(reasonableTimeBetweenClicks);
|
|
||||||
await page.waitToClick(selectors.workerCalendar.fistMondayOfMay);
|
|
||||||
|
|
||||||
await page.waitForTimeout(reasonableTimeBetweenClicks);
|
|
||||||
await page.waitToClick(selectors.workerCalendar.furlough);
|
|
||||||
await page.waitForTimeout(reasonableTimeBetweenClicks);
|
|
||||||
await page.waitToClick(selectors.workerCalendar.secondTuesdayOfMay);
|
|
||||||
await page.waitForTimeout(reasonableTimeBetweenClicks);
|
|
||||||
await page.waitToClick(selectors.workerCalendar.secondWednesdayOfMay);
|
|
||||||
await page.waitForTimeout(reasonableTimeBetweenClicks);
|
|
||||||
await page.waitToClick(selectors.workerCalendar.secondThursdayOfMay);
|
|
||||||
|
|
||||||
await page.waitForTimeout(reasonableTimeBetweenClicks);
|
|
||||||
await page.waitToClick(selectors.workerCalendar.halfFurlough);
|
|
||||||
await page.waitForTimeout(reasonableTimeBetweenClicks);
|
|
||||||
await page.waitToClick(selectors.workerCalendar.secondFridayOfJun);
|
|
||||||
|
|
||||||
expect(await page.getProperty(selectors.workerCalendar.totalHolidaysUsed, 'innerText')).toContain(' 0 ');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe(`as Charles Xavier`, () => {
|
|
||||||
it('should log in and get to his calendar, make a futile attempt to add holidays, check the total holidays used are now the initial ones and use the year selector to go to the previous year', async() => {
|
|
||||||
accessAs('CharlesXavier');
|
|
||||||
await page.waitToClick(selectors.workerCalendar.holidays);
|
|
||||||
await page.waitForTimeout(reasonableTimeBetweenClicks);
|
|
||||||
|
|
||||||
await page.click(selectors.workerCalendar.penultimateMondayOfJanuary);
|
|
||||||
|
|
||||||
expect(await page.getProperty(selectors.workerCalendar.totalHolidaysUsed, 'innerText')).toContain(' 0 ');
|
|
||||||
|
|
||||||
await page.autocompleteSearch(selectors.workerCalendar.year, lastYear);
|
|
||||||
|
|
||||||
expect(await page.getProperty(selectors.workerCalendar.totalHolidaysUsed, 'innerText')).toContain(' 0 ');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,73 +0,0 @@
|
||||||
import selectors from '../../helpers/selectors.js';
|
|
||||||
import getBrowser from '../../helpers/puppeteer';
|
|
||||||
|
|
||||||
describe('Worker create path', () => {
|
|
||||||
let browser;
|
|
||||||
let page;
|
|
||||||
let newWorker;
|
|
||||||
beforeAll(async() => {
|
|
||||||
browser = await getBrowser();
|
|
||||||
page = browser.page;
|
|
||||||
await page.loginAndModule('hr', 'worker');
|
|
||||||
await page.waitToClick(selectors.workerCreate.newWorkerButton);
|
|
||||||
await page.waitForState('worker.create');
|
|
||||||
});
|
|
||||||
|
|
||||||
afterAll(async() => {
|
|
||||||
await browser.close();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should insert default data', async() => {
|
|
||||||
await page.write(selectors.workerCreate.firstname, 'Victor');
|
|
||||||
await page.write(selectors.workerCreate.lastname, 'Von Doom');
|
|
||||||
await page.write(selectors.workerCreate.fi, '78457139E');
|
|
||||||
await page.write(selectors.workerCreate.phone, '12356789');
|
|
||||||
await page.write(selectors.workerCreate.postcode, '46680');
|
|
||||||
await page.write(selectors.workerCreate.street, 'S/ DOOMSTADT');
|
|
||||||
await page.write(selectors.workerCreate.email, 'doctorDoom@marvel.com');
|
|
||||||
await page.write(selectors.workerCreate.iban, 'ES9121000418450200051332');
|
|
||||||
|
|
||||||
// should check for autocompleted worker code and worker user name
|
|
||||||
const workerCode = await page
|
|
||||||
.waitToGetProperty(selectors.workerCreate.code, 'value');
|
|
||||||
|
|
||||||
newWorker = await page
|
|
||||||
.waitToGetProperty(selectors.workerCreate.user, 'value');
|
|
||||||
|
|
||||||
expect(workerCode).toEqual('VVD');
|
|
||||||
expect(newWorker).toContain('victorvd');
|
|
||||||
|
|
||||||
// should fail if necessary data is void
|
|
||||||
await page.waitToClick(selectors.workerCreate.createButton);
|
|
||||||
let message = await page.waitForSnackbar();
|
|
||||||
|
|
||||||
expect(message.text).toContain('is a required argument');
|
|
||||||
|
|
||||||
// should create a new worker and go to worker basic data'
|
|
||||||
await page.pickDate(selectors.workerCreate.birth, new Date(1962, 8, 5));
|
|
||||||
await page.autocompleteSearch(selectors.workerCreate.boss, 'deliveryAssistant');
|
|
||||||
await page.waitToClick(selectors.workerCreate.createButton);
|
|
||||||
message = await page.waitForSnackbar();
|
|
||||||
await page.waitForState('worker.card.basicData');
|
|
||||||
|
|
||||||
expect(message.text).toContain('Data saved!');
|
|
||||||
|
|
||||||
// 'rollback'
|
|
||||||
await page.loginAndModule('itManagement', 'account');
|
|
||||||
await page.accessToSearchResult(newWorker);
|
|
||||||
|
|
||||||
await page.waitToClick(selectors.accountDescriptor.menuButton);
|
|
||||||
await page.waitToClick(selectors.accountDescriptor.deactivateUser);
|
|
||||||
await page.waitToClick(selectors.accountDescriptor.acceptButton);
|
|
||||||
message = await page.waitForSnackbar();
|
|
||||||
|
|
||||||
expect(message.text).toContain('User deactivated!');
|
|
||||||
|
|
||||||
await page.waitToClick(selectors.accountDescriptor.menuButton);
|
|
||||||
await page.waitToClick(selectors.accountDescriptor.disableAccount);
|
|
||||||
await page.waitToClick(selectors.accountDescriptor.acceptButton);
|
|
||||||
message = await page.waitForSnackbar();
|
|
||||||
|
|
||||||
expect(message.text).toContain('Account disabled!');
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,42 +0,0 @@
|
||||||
import selectors from '../../helpers/selectors';
|
|
||||||
import getBrowser from '../../helpers/puppeteer';
|
|
||||||
|
|
||||||
describe('Worker Add notes path', () => {
|
|
||||||
let browser;
|
|
||||||
let page;
|
|
||||||
beforeAll(async() => {
|
|
||||||
browser = await getBrowser();
|
|
||||||
page = browser.page;
|
|
||||||
await page.loginAndModule('hr', 'worker');
|
|
||||||
await page.accessToSearchResult('Bruce Banner');
|
|
||||||
await page.accessToSection('worker.card.note.index');
|
|
||||||
});
|
|
||||||
|
|
||||||
afterAll(async() => {
|
|
||||||
await browser.close();
|
|
||||||
});
|
|
||||||
|
|
||||||
it(`should reach the notes index`, async() => {
|
|
||||||
await page.waitForState('worker.card.note.index');
|
|
||||||
});
|
|
||||||
|
|
||||||
it(`should click on the add note button`, async() => {
|
|
||||||
await page.waitToClick(selectors.workerNotes.addNoteFloatButton);
|
|
||||||
await page.waitForState('worker.card.note.create');
|
|
||||||
});
|
|
||||||
|
|
||||||
it(`should create a note`, async() => {
|
|
||||||
await page.waitForSelector(selectors.workerNotes.note);
|
|
||||||
await page.type(`${selectors.workerNotes.note} textarea`, 'Meeting with Black Widow 21st 9am');
|
|
||||||
await page.waitToClick(selectors.workerNotes.saveButton);
|
|
||||||
const message = await page.waitForSnackbar();
|
|
||||||
|
|
||||||
expect(message.text).toContain('Data saved!');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should confirm the note was created', async() => {
|
|
||||||
const result = await page.waitToGetProperty(selectors.workerNotes.firstNoteText, 'innerText');
|
|
||||||
|
|
||||||
expect(result).toEqual('Meeting with Black Widow 21st 9am');
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -19,7 +19,9 @@ describe('Ticket Edit sale path', () => {
|
||||||
|
|
||||||
it(`should click on the first sale claim icon to navigate over there`, async() => {
|
it(`should click on the first sale claim icon to navigate over there`, async() => {
|
||||||
await page.waitToClick(selectors.ticketSales.firstSaleClaimIcon);
|
await page.waitToClick(selectors.ticketSales.firstSaleClaimIcon);
|
||||||
await page.waitForState('claim.card.basicData');
|
await page.waitForNavigation();
|
||||||
|
await page.goBack();
|
||||||
|
await page.goBack();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should navigate to the tickets index', async() => {
|
it('should navigate to the tickets index', async() => {
|
||||||
|
@ -243,29 +245,13 @@ describe('Ticket Edit sale path', () => {
|
||||||
await page.waitToClick(selectors.ticketSales.moreMenu);
|
await page.waitToClick(selectors.ticketSales.moreMenu);
|
||||||
await page.waitToClick(selectors.ticketSales.moreMenuCreateClaim);
|
await page.waitToClick(selectors.ticketSales.moreMenuCreateClaim);
|
||||||
await page.waitToClick(selectors.globalItems.acceptButton);
|
await page.waitToClick(selectors.globalItems.acceptButton);
|
||||||
await page.waitForState('claim.card.basicData');
|
await page.waitForNavigation();
|
||||||
});
|
|
||||||
|
|
||||||
it('should click on the Claims button of the top bar menu', async() => {
|
|
||||||
await page.waitToClick(selectors.globalItems.applicationsMenuButton);
|
|
||||||
await page.waitForSelector(selectors.globalItems.applicationsMenuVisible);
|
|
||||||
await page.waitToClick(selectors.globalItems.claimsButton);
|
|
||||||
await page.waitForState('claim.index');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should search for the claim with id 4', async() => {
|
|
||||||
await page.accessToSearchResult('4');
|
|
||||||
await page.waitForState('claim.card.summary');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should click the Tickets button of the top bar menu', async() => {
|
|
||||||
await page.waitToClick(selectors.globalItems.applicationsMenuButton);
|
|
||||||
await page.waitForSelector(selectors.globalItems.applicationsMenuVisible);
|
|
||||||
await page.waitToClick(selectors.globalItems.ticketsButton);
|
|
||||||
await page.waitForState('ticket.index');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should search for a ticket then access to the sales section', async() => {
|
it('should search for a ticket then access to the sales section', async() => {
|
||||||
|
await page.goBack();
|
||||||
|
await page.goBack();
|
||||||
|
await page.loginAndModule('salesPerson', 'ticket');
|
||||||
await page.accessToSearchResult('16');
|
await page.accessToSearchResult('16');
|
||||||
await page.accessToSection('ticket.card.sale');
|
await page.accessToSection('ticket.card.sale');
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,61 +0,0 @@
|
||||||
import selectors from '../../helpers/selectors.js';
|
|
||||||
import getBrowser from '../../helpers/puppeteer';
|
|
||||||
|
|
||||||
describe('Claim edit basic data path', () => {
|
|
||||||
let browser;
|
|
||||||
let page;
|
|
||||||
|
|
||||||
beforeAll(async() => {
|
|
||||||
browser = await getBrowser();
|
|
||||||
page = browser.page;
|
|
||||||
});
|
|
||||||
|
|
||||||
afterAll(async() => {
|
|
||||||
await browser.close();
|
|
||||||
});
|
|
||||||
|
|
||||||
it(`should log in as claimManager then reach basic data of the target claim`, async() => {
|
|
||||||
await page.loginAndModule('claimManager', 'claim');
|
|
||||||
await page.accessToSearchResult('1');
|
|
||||||
await page.accessToSection('claim.card.basicData');
|
|
||||||
});
|
|
||||||
|
|
||||||
it(`should edit claim state and observation fields`, async() => {
|
|
||||||
await page.autocompleteSearch(selectors.claimBasicData.claimState, 'Resuelto');
|
|
||||||
await page.clearInput(selectors.claimBasicData.packages);
|
|
||||||
await page.write(selectors.claimBasicData.packages, '2');
|
|
||||||
await page.waitToClick(selectors.claimBasicData.saveButton);
|
|
||||||
const message = await page.waitForSnackbar();
|
|
||||||
|
|
||||||
expect(message.text).toContain('Data saved!');
|
|
||||||
});
|
|
||||||
|
|
||||||
it(`should have been redirected to the next section of claims as the role is claimManager`, async() => {
|
|
||||||
await page.waitForState('claim.card.detail');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should confirm the claim state was edited', async() => {
|
|
||||||
await page.reloadSection('claim.card.basicData');
|
|
||||||
await page.waitForSelector(selectors.claimBasicData.claimState);
|
|
||||||
const result = await page.waitToGetProperty(selectors.claimBasicData.claimState, 'value');
|
|
||||||
|
|
||||||
expect(result).toEqual('Resuelto');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should confirm the claim packages was edited', async() => {
|
|
||||||
const result = await page
|
|
||||||
.waitToGetProperty(selectors.claimBasicData.packages, 'value');
|
|
||||||
|
|
||||||
expect(result).toEqual('2');
|
|
||||||
});
|
|
||||||
|
|
||||||
it(`should edit the claim to leave it untainted`, async() => {
|
|
||||||
await page.autocompleteSearch(selectors.claimBasicData.claimState, 'Pendiente');
|
|
||||||
await page.clearInput(selectors.claimBasicData.packages);
|
|
||||||
await page.write(selectors.claimBasicData.packages, '0');
|
|
||||||
await page.waitToClick(selectors.claimBasicData.saveButton);
|
|
||||||
const message = await page.waitForSnackbar();
|
|
||||||
|
|
||||||
expect(message.text).toContain('Data saved!');
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,54 +0,0 @@
|
||||||
import selectors from '../../helpers/selectors.js';
|
|
||||||
import getBrowser from '../../helpers/puppeteer.js';
|
|
||||||
|
|
||||||
describe('Claim action path', () => {
|
|
||||||
let browser;
|
|
||||||
let page;
|
|
||||||
|
|
||||||
beforeAll(async() => {
|
|
||||||
browser = await getBrowser();
|
|
||||||
page = browser.page;
|
|
||||||
await page.loginAndModule('claimManager', 'claim');
|
|
||||||
await page.accessToSearchResult('2');
|
|
||||||
await page.accessToSection('claim.card.action');
|
|
||||||
});
|
|
||||||
|
|
||||||
afterAll(async() => {
|
|
||||||
await browser.close();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should import the claim', async() => {
|
|
||||||
await page.waitToClick(selectors.claimAction.importClaimButton);
|
|
||||||
const message = await page.waitForSnackbar();
|
|
||||||
|
|
||||||
expect(message.text).toContain('Data saved!');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should delete the first line', async() => {
|
|
||||||
await page.waitToClick(selectors.claimAction.firstDeleteLine);
|
|
||||||
const message = await page.waitForSnackbar();
|
|
||||||
|
|
||||||
expect(message.text).toContain('Data saved!');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should refresh the view to check not have lines', async() => {
|
|
||||||
await page.reloadSection('claim.card.action');
|
|
||||||
const result = await page.countElement(selectors.claimAction.anyLine);
|
|
||||||
|
|
||||||
expect(result).toEqual(0);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should check the "is paid with mana" checkbox', async() => {
|
|
||||||
await page.waitToClick(selectors.claimAction.isPaidWithManaCheckbox);
|
|
||||||
const message = await page.waitForSnackbar();
|
|
||||||
|
|
||||||
expect(message.text).toContain('Data saved!');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should confirm the "is paid with mana" is checked', async() => {
|
|
||||||
await page.reloadSection('claim.card.action');
|
|
||||||
const isPaidWithManaCheckbox = await page.checkboxState(selectors.claimAction.isPaidWithManaCheckbox);
|
|
||||||
|
|
||||||
expect(isPaidWithManaCheckbox).toBe('checked');
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,96 +0,0 @@
|
||||||
|
|
||||||
import selectors from '../../helpers/selectors.js';
|
|
||||||
import getBrowser from '../../helpers/puppeteer.js';
|
|
||||||
|
|
||||||
describe('Claim summary path', () => {
|
|
||||||
let browser;
|
|
||||||
let page;
|
|
||||||
const claimId = '4';
|
|
||||||
|
|
||||||
beforeAll(async() => {
|
|
||||||
browser = await getBrowser();
|
|
||||||
page = browser.page;
|
|
||||||
});
|
|
||||||
|
|
||||||
afterAll(async() => {
|
|
||||||
await browser.close();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should navigate to the target claim summary section', async() => {
|
|
||||||
await page.loginAndModule('salesPerson', 'claim');
|
|
||||||
await page.accessToSearchResult(claimId);
|
|
||||||
await page.waitForState('claim.card.summary');
|
|
||||||
});
|
|
||||||
|
|
||||||
it(`should display details from the claim and it's client on the top of the header`, async() => {
|
|
||||||
await page.waitForTextInElement(selectors.claimSummary.header, 'Tony Stark');
|
|
||||||
const result = await page.waitToGetProperty(selectors.claimSummary.header, 'innerText');
|
|
||||||
|
|
||||||
expect(result).toContain('4 -');
|
|
||||||
expect(result).toContain('Tony Stark');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should display the claim state', async() => {
|
|
||||||
const result = await page.waitToGetProperty(selectors.claimSummary.state, 'innerText');
|
|
||||||
|
|
||||||
expect(result).toContain('Resuelto');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should display the observation', async() => {
|
|
||||||
const result = await page.waitToGetProperty(selectors.claimSummary.observation, 'innerText');
|
|
||||||
|
|
||||||
expect(result).toContain('Wisi forensibus mnesarchum in cum. Per id impetus abhorreant');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should display the claimed line(s)', async() => {
|
|
||||||
const result = await page.waitToGetProperty(selectors.claimSummary.firstSaleItemId, 'innerText');
|
|
||||||
|
|
||||||
expect(result).toContain('2');
|
|
||||||
});
|
|
||||||
|
|
||||||
it(`should click on the first sale ID making the item descriptor visible`, async() => {
|
|
||||||
const firstItem = selectors.claimSummary.firstSaleItemId;
|
|
||||||
await page.evaluate(selectors => {
|
|
||||||
document.querySelector(selectors).scrollIntoView();
|
|
||||||
}, firstItem);
|
|
||||||
await page.click(firstItem);
|
|
||||||
await page.waitImgLoad(selectors.claimSummary.firstSaleDescriptorImage);
|
|
||||||
const visible = await page.isVisible(selectors.claimSummary.itemDescriptorPopover);
|
|
||||||
|
|
||||||
expect(visible).toBeTruthy();
|
|
||||||
});
|
|
||||||
|
|
||||||
it(`should check the url for the item diary link of the descriptor is for the right item id`, async() => {
|
|
||||||
await page.waitForSelector(selectors.claimSummary.itemDescriptorPopoverItemDiaryButton, {visible: true});
|
|
||||||
|
|
||||||
await page.closePopup();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should display the claim development details', async() => {
|
|
||||||
const result = await page.waitToGetProperty(selectors.claimSummary.firstDevelopmentWorker, 'innerText');
|
|
||||||
|
|
||||||
expect(result).toContain('salesAssistantNick');
|
|
||||||
});
|
|
||||||
|
|
||||||
it(`should click on the first development worker making the worker descriptor visible`, async() => {
|
|
||||||
await page.waitToClick(selectors.claimSummary.firstDevelopmentWorker);
|
|
||||||
|
|
||||||
const visible = await page.isVisible(selectors.claimSummary.firstDevelopmentWorkerGoToClientButton);
|
|
||||||
|
|
||||||
expect(visible).toBeTruthy();
|
|
||||||
});
|
|
||||||
|
|
||||||
it(`should check the url for the go to clientlink of the descriptor is for the right client id`, async() => {
|
|
||||||
await page.waitForSelector(selectors.claimSummary.firstDevelopmentWorkerGoToClientButton, {visible: true});
|
|
||||||
|
|
||||||
await page.closePopup();
|
|
||||||
});
|
|
||||||
|
|
||||||
it(`should click on the first action ticket ID making the ticket descriptor visible`, async() => {
|
|
||||||
await page.waitToClick(selectors.claimSummary.firstActionTicketId);
|
|
||||||
await page.waitForSelector(selectors.claimSummary.firstActionTicketDescriptor);
|
|
||||||
const visible = await page.isVisible(selectors.claimSummary.firstActionTicketDescriptor);
|
|
||||||
|
|
||||||
expect(visible).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,58 +0,0 @@
|
||||||
import selectors from '../../helpers/selectors.js';
|
|
||||||
import getBrowser from '../../helpers/puppeteer.js';
|
|
||||||
|
|
||||||
describe('Claim descriptor path', () => {
|
|
||||||
let browser;
|
|
||||||
let page;
|
|
||||||
const claimId = '1';
|
|
||||||
|
|
||||||
beforeAll(async() => {
|
|
||||||
browser = await getBrowser();
|
|
||||||
page = browser.page;
|
|
||||||
});
|
|
||||||
|
|
||||||
afterAll(async() => {
|
|
||||||
await browser.close();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should now navigate to the target claim summary section', async() => {
|
|
||||||
await page.loginAndModule('salesPerson', 'claim');
|
|
||||||
await page.accessToSearchResult(claimId);
|
|
||||||
await page.waitForState('claim.card.summary');
|
|
||||||
});
|
|
||||||
|
|
||||||
it(`should not be able to see the delete claim button of the descriptor more menu`, async() => {
|
|
||||||
await page.waitToClick(selectors.claimDescriptor.moreMenu);
|
|
||||||
await page.waitForSelector(selectors.claimDescriptor.moreMenuDeleteClaim, {hidden: true});
|
|
||||||
});
|
|
||||||
|
|
||||||
it(`should log in as claimManager and navigate to the target claim`, async() => {
|
|
||||||
await page.loginAndModule('claimManager', 'claim');
|
|
||||||
await page.accessToSearchResult(claimId);
|
|
||||||
await page.waitForState('claim.card.summary');
|
|
||||||
});
|
|
||||||
|
|
||||||
it(`should be able to see the delete claim button of the descriptor more menu`, async() => {
|
|
||||||
await page.waitToClick(selectors.claimDescriptor.moreMenu);
|
|
||||||
await page.waitForSelector(selectors.claimDescriptor.moreMenuDeleteClaim, {visible: true});
|
|
||||||
});
|
|
||||||
|
|
||||||
it(`should delete the claim`, async() => {
|
|
||||||
await page.waitToClick(selectors.claimDescriptor.moreMenuDeleteClaim);
|
|
||||||
await page.waitToClick(selectors.claimDescriptor.acceptDeleteClaim);
|
|
||||||
const message = await page.waitForSnackbar();
|
|
||||||
|
|
||||||
expect(message.text).toContain('Claim deleted!');
|
|
||||||
});
|
|
||||||
|
|
||||||
it(`should have been relocated to the claim index`, async() => {
|
|
||||||
await page.waitForState('claim.index');
|
|
||||||
});
|
|
||||||
|
|
||||||
it(`should search for the deleted claim to find no results`, async() => {
|
|
||||||
await page.doSearch(claimId);
|
|
||||||
const nResults = await page.countElement(selectors.claimsIndex.searchResult);
|
|
||||||
|
|
||||||
expect(nResults).toEqual(0);
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,46 +0,0 @@
|
||||||
import selectors from '../../helpers/selectors';
|
|
||||||
import getBrowser from '../../helpers/puppeteer';
|
|
||||||
|
|
||||||
describe('Claim Add note path', () => {
|
|
||||||
let browser;
|
|
||||||
let page;
|
|
||||||
beforeAll(async() => {
|
|
||||||
browser = await getBrowser();
|
|
||||||
page = browser.page;
|
|
||||||
await page.loginAndModule('salesPerson', 'claim');
|
|
||||||
await page.accessToSearchResult('2');
|
|
||||||
await page.accessToSection('claim.card.note.index');
|
|
||||||
});
|
|
||||||
|
|
||||||
afterAll(async() => {
|
|
||||||
await browser.close();
|
|
||||||
});
|
|
||||||
|
|
||||||
it(`should reach the claim note index`, async() => {
|
|
||||||
await page.waitForState('claim.card.note.index');
|
|
||||||
});
|
|
||||||
|
|
||||||
it(`should click on the add new note button`, async() => {
|
|
||||||
await page.waitToClick(selectors.claimNote.addNoteFloatButton);
|
|
||||||
await page.waitForState('claim.card.note.create');
|
|
||||||
});
|
|
||||||
|
|
||||||
it(`should create a new note`, async() => {
|
|
||||||
await page.waitForSelector(selectors.claimNote.note);
|
|
||||||
await page.type(`${selectors.claimNote.note} textarea`, 'The delivery was unsuccessful');
|
|
||||||
await page.waitToClick(selectors.claimNote.saveButton);
|
|
||||||
const message = await page.waitForSnackbar();
|
|
||||||
|
|
||||||
expect(message.text).toContain('Data saved!');
|
|
||||||
});
|
|
||||||
|
|
||||||
it(`should redirect back to the claim notes page`, async() => {
|
|
||||||
await page.waitForState('claim.card.note.index');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should confirm the note was created', async() => {
|
|
||||||
const result = await page.waitToGetProperty(selectors.claimNote.firstNoteText, 'innerText');
|
|
||||||
|
|
||||||
expect(result).toEqual('The delivery was unsuccessful');
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -41,7 +41,6 @@ async function test() {
|
||||||
`./e2e/paths/03*/*[sS]pec.js`,
|
`./e2e/paths/03*/*[sS]pec.js`,
|
||||||
`./e2e/paths/04*/*[sS]pec.js`,
|
`./e2e/paths/04*/*[sS]pec.js`,
|
||||||
`./e2e/paths/05*/*[sS]pec.js`,
|
`./e2e/paths/05*/*[sS]pec.js`,
|
||||||
`./e2e/paths/06*/*[sS]pec.js`,
|
|
||||||
`./e2e/paths/07*/*[sS]pec.js`,
|
`./e2e/paths/07*/*[sS]pec.js`,
|
||||||
`./e2e/paths/08*/*[sS]pec.js`,
|
`./e2e/paths/08*/*[sS]pec.js`,
|
||||||
`./e2e/paths/09*/*[sS]pec.js`,
|
`./e2e/paths/09*/*[sS]pec.js`,
|
||||||
|
|
|
@ -1,188 +0,0 @@
|
||||||
<vn-crud-model vn-id="model"
|
|
||||||
url="ClaimEnds/filter"
|
|
||||||
link="{claimFk: $ctrl.$params.id}"
|
|
||||||
data="$ctrl.salesClaimed"
|
|
||||||
auto-load="true"
|
|
||||||
on-save="$ctrl.onSave()">
|
|
||||||
</vn-crud-model>
|
|
||||||
<vn-crud-model
|
|
||||||
auto-load="true"
|
|
||||||
url="ClaimDestinations"
|
|
||||||
data="claimDestinations">
|
|
||||||
</vn-crud-model>
|
|
||||||
<vn-card class="vn-mb-md vn-pa-lg vn-w-lg" style="text-align: right"
|
|
||||||
ng-if="$ctrl.salesClaimed.length > 0">
|
|
||||||
<vn-label-value label="Total claimed"
|
|
||||||
value="{{$ctrl.claimedTotal | currency: 'EUR':2}}">
|
|
||||||
</vn-label-value>
|
|
||||||
</vn-card>
|
|
||||||
<vn-card class="vn-pa-md vn-w-lg">
|
|
||||||
<smart-table
|
|
||||||
model="model"
|
|
||||||
options="$ctrl.smartTableOptions"
|
|
||||||
expr-builder="$ctrl.exprBuilder(param, value)">
|
|
||||||
<slot-actions>
|
|
||||||
<section class="header">
|
|
||||||
<vn-tool-bar class="vn-mb-md">
|
|
||||||
<vn-button
|
|
||||||
label="Import claim"
|
|
||||||
disabled="$ctrl.claim.claimStateFk == $ctrl.resolvedStateId"
|
|
||||||
vn-http-click="$ctrl.importToNewRefundTicket()"
|
|
||||||
translate-attr="{title: 'Imports claim details'}">
|
|
||||||
</vn-button>
|
|
||||||
<vn-button
|
|
||||||
label="Change destination"
|
|
||||||
disabled="$ctrl.checked.length == 0"
|
|
||||||
ng-click="changeDestination.show()">
|
|
||||||
</vn-button>
|
|
||||||
<vn-range
|
|
||||||
label="Responsability"
|
|
||||||
min-label="Company"
|
|
||||||
max-label="Sales/Client"
|
|
||||||
ng-model="$ctrl.claim.responsibility"
|
|
||||||
max="$ctrl.maxResponsibility"
|
|
||||||
min="1"
|
|
||||||
step="1"
|
|
||||||
on-change="$ctrl.save({responsibility: value})">
|
|
||||||
</vn-range>
|
|
||||||
<vn-check class="right"
|
|
||||||
vn-one
|
|
||||||
label="Is paid with mana"
|
|
||||||
ng-model="$ctrl.claim.isChargedToMana"
|
|
||||||
on-change="$ctrl.save({isChargedToMana: value})">
|
|
||||||
</vn-check>
|
|
||||||
</vn-tool-bar>
|
|
||||||
</section>
|
|
||||||
</slot-actions>
|
|
||||||
<slot-table>
|
|
||||||
<table model="model">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th shrink>
|
|
||||||
<vn-multi-check
|
|
||||||
model="model"
|
|
||||||
check-field="$checked">
|
|
||||||
</vn-multi-check>
|
|
||||||
</th>
|
|
||||||
<th number field="itemFk">Id</th>
|
|
||||||
<th number field="ticketFk">Ticket</th>
|
|
||||||
<th field="claimDestinationFk">
|
|
||||||
<span translate>Destination</span>
|
|
||||||
</th>
|
|
||||||
<th expand field="landed">
|
|
||||||
<span translate>Landed</span>
|
|
||||||
</th>
|
|
||||||
<th number field="quantity">
|
|
||||||
<span translate>Quantity</span>
|
|
||||||
</th>
|
|
||||||
<th field="concept">
|
|
||||||
<span translate>Description</span>
|
|
||||||
</th>
|
|
||||||
<th number field="price">
|
|
||||||
<span translate>Price</span>
|
|
||||||
</th>
|
|
||||||
<th number field="discount">
|
|
||||||
<span translate>Disc.</span>
|
|
||||||
</th>
|
|
||||||
<th number field="total">Total</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr
|
|
||||||
ng-repeat="saleClaimed in $ctrl.salesClaimed"
|
|
||||||
vn-repeat-last on-last="$ctrl.focusLastInput()">
|
|
||||||
<td>
|
|
||||||
<vn-check
|
|
||||||
ng-model="saleClaimed.$checked"
|
|
||||||
vn-click-stop>
|
|
||||||
</vn-check>
|
|
||||||
</td>
|
|
||||||
<td number>
|
|
||||||
<vn-span
|
|
||||||
ng-click="itemDescriptor.show($event, saleClaimed.itemFk)"
|
|
||||||
class="link">
|
|
||||||
{{::saleClaimed.itemFk}}
|
|
||||||
</vn-span>
|
|
||||||
</td>
|
|
||||||
<td number>
|
|
||||||
<vn-span
|
|
||||||
class="link"
|
|
||||||
ng-click="ticketDescriptor.show($event, saleClaimed.ticketFk)">
|
|
||||||
{{::saleClaimed.ticketFk}}
|
|
||||||
</vn-span>
|
|
||||||
</td>
|
|
||||||
<td expand>
|
|
||||||
<vn-autocomplete vn-one id="claimDestinationFk"
|
|
||||||
ng-model="saleClaimed.claimDestinationFk"
|
|
||||||
data="claimDestinations"
|
|
||||||
on-change="$ctrl.updateDestination(saleClaimed, value)"
|
|
||||||
fields="['id','description']"
|
|
||||||
value-field="id"
|
|
||||||
show-field="description">
|
|
||||||
</vn-autocomplete>
|
|
||||||
</td>
|
|
||||||
<td expand>{{::saleClaimed.landed | date: 'dd/MM/yyyy'}}</td>
|
|
||||||
<td number>{{::saleClaimed.quantity}}</td>
|
|
||||||
<td expand>{{::saleClaimed.concept}}</td>
|
|
||||||
<td number>{{::saleClaimed.price | currency: 'EUR':2}}</td>
|
|
||||||
<td number>{{::saleClaimed.discount}} %</td>
|
|
||||||
<td number>{{saleClaimed.total | currency: 'EUR':2}}</td>
|
|
||||||
<td shrink>
|
|
||||||
<vn-icon-button
|
|
||||||
vn-tooltip="Remove line"
|
|
||||||
icon="delete"
|
|
||||||
ng-click="$ctrl.removeSales(saleClaimed)"
|
|
||||||
tabindex="-1">
|
|
||||||
</vn-icon-button>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</slot-table>
|
|
||||||
</smart-table>
|
|
||||||
<button-bar class="vn-pa-md">
|
|
||||||
<vn-button
|
|
||||||
label="Regularize"
|
|
||||||
disabled="$ctrl.claim.claimStateFk == $ctrl.resolvedStateId"
|
|
||||||
vn-http-click="$ctrl.regularize()">
|
|
||||||
</vn-button>
|
|
||||||
</button-bar>
|
|
||||||
</vn-card>
|
|
||||||
<vn-item-descriptor-popover
|
|
||||||
vn-id="item-descriptor"
|
|
||||||
warehouse-fk="$ctrl.vnConfig.warehouseFk">
|
|
||||||
</vn-item-descriptor-popover>
|
|
||||||
<vn-ticket-descriptor-popover
|
|
||||||
vn-id="ticket-descriptor">
|
|
||||||
</vn-ticket-descriptor-popover>
|
|
||||||
<vn-confirm
|
|
||||||
vn-id="update-greuge"
|
|
||||||
question="Insert greuges on client card"
|
|
||||||
message="Do you want to insert greuges?"
|
|
||||||
on-accept="$ctrl.onUpdateGreugeAccept()">
|
|
||||||
</vn-confirm>
|
|
||||||
|
|
||||||
<!-- Dialog of change destionation -->
|
|
||||||
<vn-dialog
|
|
||||||
vn-id="changeDestination"
|
|
||||||
on-accept="$ctrl.onResponse()">
|
|
||||||
<tpl-body>
|
|
||||||
<section class="SMSDialog">
|
|
||||||
<h5 class="vn-py-sm">{{$ctrl.$t('Change destination to all selected rows', {total: $ctrl.checked.length})}}</h5>
|
|
||||||
<vn-horizontal>
|
|
||||||
<vn-autocomplete vn-one id="claimDestinationFk"
|
|
||||||
ng-model="$ctrl.newDestination"
|
|
||||||
data="claimDestinations"
|
|
||||||
fields="['id','description']"
|
|
||||||
value-field="id"
|
|
||||||
show-field="description"
|
|
||||||
vn-focus>
|
|
||||||
</vn-autocomplete>
|
|
||||||
</vn-horizontal>
|
|
||||||
</section>
|
|
||||||
</tpl-body>
|
|
||||||
<tpl-buttons>
|
|
||||||
<input type="button" response="cancel" translate-attr="{value: 'Cancel'}"/>
|
|
||||||
<button response="accept" translate>Save</button>
|
|
||||||
</tpl-buttons>
|
|
||||||
</vn-dialog>
|
|
|
@ -1,233 +0,0 @@
|
||||||
import ngModule from '../module';
|
|
||||||
import Section from 'salix/components/section';
|
|
||||||
import './style.scss';
|
|
||||||
|
|
||||||
export default class Controller extends Section {
|
|
||||||
constructor($element, $) {
|
|
||||||
super($element, $);
|
|
||||||
this.newDestination;
|
|
||||||
this.filter = {
|
|
||||||
include: [
|
|
||||||
{relation: 'sale',
|
|
||||||
scope: {
|
|
||||||
fields: ['concept', 'ticketFk', 'price', 'quantity', 'discount', 'itemFk'],
|
|
||||||
include: {
|
|
||||||
relation: 'ticket'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{relation: 'claimBeggining'},
|
|
||||||
{relation: 'claimDestination'}
|
|
||||||
]
|
|
||||||
};
|
|
||||||
this.getResolvedState();
|
|
||||||
this.maxResponsibility = 5;
|
|
||||||
this.smartTableOptions = {
|
|
||||||
activeButtons: {
|
|
||||||
search: true
|
|
||||||
},
|
|
||||||
columns: [
|
|
||||||
{
|
|
||||||
field: 'claimDestinationFk',
|
|
||||||
autocomplete: {
|
|
||||||
url: 'ClaimDestinations',
|
|
||||||
showField: 'description',
|
|
||||||
valueField: 'id'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
field: 'landed',
|
|
||||||
searchable: false
|
|
||||||
}
|
|
||||||
]
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
exprBuilder(param, value) {
|
|
||||||
switch (param) {
|
|
||||||
case 'itemFk':
|
|
||||||
case 'ticketFk':
|
|
||||||
case 'claimDestinationFk':
|
|
||||||
case 'quantity':
|
|
||||||
case 'price':
|
|
||||||
case 'discount':
|
|
||||||
case 'total':
|
|
||||||
return {[param]: value};
|
|
||||||
case 'concept':
|
|
||||||
return {[param]: {like: `%${value}%`}};
|
|
||||||
case 'landed':
|
|
||||||
return {[param]: {between: this.dateRange(value)}};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dateRange(value) {
|
|
||||||
const minHour = new Date(value);
|
|
||||||
minHour.setHours(0, 0, 0, 0);
|
|
||||||
const maxHour = new Date(value);
|
|
||||||
maxHour.setHours(23, 59, 59, 59);
|
|
||||||
|
|
||||||
return [minHour, maxHour];
|
|
||||||
}
|
|
||||||
|
|
||||||
get checked() {
|
|
||||||
const salesClaimed = this.$.model.data || [];
|
|
||||||
|
|
||||||
const checkedSalesClaimed = [];
|
|
||||||
for (let saleClaimed of salesClaimed) {
|
|
||||||
if (saleClaimed.$checked)
|
|
||||||
checkedSalesClaimed.push(saleClaimed);
|
|
||||||
}
|
|
||||||
|
|
||||||
return checkedSalesClaimed;
|
|
||||||
}
|
|
||||||
|
|
||||||
updateDestination(saleClaimed, claimDestinationFk) {
|
|
||||||
const data = {rows: [saleClaimed], claimDestinationFk: claimDestinationFk};
|
|
||||||
this.$http.post(`Claims/updateClaimDestination`, data).then(() => {
|
|
||||||
this.vnApp.showSuccess(this.$t('Data saved!'));
|
|
||||||
}).catch(e => {
|
|
||||||
this.$.model.refresh();
|
|
||||||
throw e;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
removeSales(saleClaimed) {
|
|
||||||
const params = {sales: [saleClaimed]};
|
|
||||||
this.$http.post(`ClaimEnds/deleteClamedSales`, params).then(() => {
|
|
||||||
this.$.model.refresh();
|
|
||||||
this.vnApp.showSuccess(this.$t('Data saved!'));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
getResolvedState() {
|
|
||||||
const query = `ClaimStates/findOne`;
|
|
||||||
const params = {
|
|
||||||
filter: {
|
|
||||||
where: {
|
|
||||||
code: 'resolved'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
this.$http.get(query, params).then(res =>
|
|
||||||
this.resolvedStateId = res.data.id
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
importToNewRefundTicket() {
|
|
||||||
let query = `ClaimBeginnings/${this.$params.id}/importToNewRefundTicket`;
|
|
||||||
return this.$http.post(query).then(() => {
|
|
||||||
this.$.model.refresh();
|
|
||||||
this.vnApp.showSuccess(this.$t('Data saved!'));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
focusLastInput() {
|
|
||||||
let inputs = document.querySelectorAll('#claimDestinationFk');
|
|
||||||
inputs[inputs.length - 1].querySelector('input').focus();
|
|
||||||
this.calculateTotals();
|
|
||||||
}
|
|
||||||
|
|
||||||
calculateTotals() {
|
|
||||||
this.claimedTotal = 0;
|
|
||||||
this.salesClaimed.forEach(sale => {
|
|
||||||
const price = sale.quantity * sale.price;
|
|
||||||
const discount = (sale.discount * (sale.quantity * sale.price)) / 100;
|
|
||||||
this.claimedTotal += price - discount;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
regularize() {
|
|
||||||
const query = `Claims/${this.$params.id}/regularizeClaim`;
|
|
||||||
return this.$http.post(query).then(() => {
|
|
||||||
if (this.claim.responsibility >= Math.ceil(this.maxResponsibility) / 2)
|
|
||||||
this.$.updateGreuge.show();
|
|
||||||
else
|
|
||||||
this.vnApp.showSuccess(this.$t('Data saved!'));
|
|
||||||
|
|
||||||
this.card.reload();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
getGreugeTypeId() {
|
|
||||||
const params = {filter: {where: {code: 'freightPickUp'}}};
|
|
||||||
const query = `GreugeTypes/findOne`;
|
|
||||||
return this.$http.get(query, {params}).then(res => {
|
|
||||||
this.greugeTypeFreightId = res.data.id;
|
|
||||||
|
|
||||||
return res;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
getGreugeConfig() {
|
|
||||||
const query = `GreugeConfigs/findOne`;
|
|
||||||
return this.$http.get(query).then(res => {
|
|
||||||
this.freightPickUpPrice = res.data.freightPickUpPrice;
|
|
||||||
|
|
||||||
return res;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
onUpdateGreugeAccept() {
|
|
||||||
const promises = [];
|
|
||||||
promises.push(this.getGreugeTypeId());
|
|
||||||
promises.push(this.getGreugeConfig());
|
|
||||||
|
|
||||||
return Promise.all(promises).then(() => {
|
|
||||||
return this.updateGreuge({
|
|
||||||
clientFk: this.claim.clientFk,
|
|
||||||
description: this.$t('ClaimGreugeDescription', {
|
|
||||||
claimId: this.claim.id
|
|
||||||
}).toUpperCase(),
|
|
||||||
amount: this.freightPickUpPrice,
|
|
||||||
greugeTypeFk: this.greugeTypeFreightId,
|
|
||||||
ticketFk: this.claim.ticketFk
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
updateGreuge(data) {
|
|
||||||
return this.$http.post(`Greuges`, data).then(() => {
|
|
||||||
this.vnApp.showSuccess(this.$t('Data saved!'));
|
|
||||||
this.vnApp.showMessage(this.$t('Greuge added'));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
save(data) {
|
|
||||||
const query = `Claims/${this.$params.id}/updateClaimAction`;
|
|
||||||
this.$http.patch(query, data)
|
|
||||||
.then(() => this.vnApp.showSuccess(this.$t('Data saved!')));
|
|
||||||
}
|
|
||||||
|
|
||||||
onSave() {
|
|
||||||
this.vnApp.showSuccess(this.$t('Data saved!'));
|
|
||||||
}
|
|
||||||
|
|
||||||
onResponse() {
|
|
||||||
const rowsToEdit = [];
|
|
||||||
for (let row of this.checked)
|
|
||||||
rowsToEdit.push({id: row.id});
|
|
||||||
|
|
||||||
const data = {
|
|
||||||
rows: rowsToEdit,
|
|
||||||
claimDestinationFk: this.newDestination
|
|
||||||
};
|
|
||||||
|
|
||||||
const query = `Claims/updateClaimDestination`;
|
|
||||||
this.$http.post(query, data)
|
|
||||||
.then(() => {
|
|
||||||
this.$.model.refresh();
|
|
||||||
this.vnApp.showSuccess(this.$t('Data saved!'));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ngModule.vnComponent('vnClaimAction', {
|
|
||||||
template: require('./index.html'),
|
|
||||||
controller: Controller,
|
|
||||||
bindings: {
|
|
||||||
claim: '<'
|
|
||||||
},
|
|
||||||
require: {
|
|
||||||
card: '^vnClaimCard'
|
|
||||||
}
|
|
||||||
});
|
|
|
@ -1,167 +0,0 @@
|
||||||
import './index.js';
|
|
||||||
import crudModel from 'core/mocks/crud-model';
|
|
||||||
|
|
||||||
describe('claim', () => {
|
|
||||||
describe('Component vnClaimAction', () => {
|
|
||||||
let controller;
|
|
||||||
let $httpBackend;
|
|
||||||
let $state;
|
|
||||||
|
|
||||||
beforeEach(ngModule('claim'));
|
|
||||||
|
|
||||||
beforeEach(inject(($componentController, _$state_, _$httpBackend_) => {
|
|
||||||
$httpBackend = _$httpBackend_;
|
|
||||||
$state = _$state_;
|
|
||||||
$state.params.id = 1;
|
|
||||||
|
|
||||||
controller = $componentController('vnClaimAction', {$element: null});
|
|
||||||
controller.claim = {ticketFk: 1};
|
|
||||||
controller.$.model = {refresh: () => {}};
|
|
||||||
controller.$.addSales = {
|
|
||||||
hide: () => {},
|
|
||||||
show: () => {}
|
|
||||||
};
|
|
||||||
controller.$.lastTicketsModel = crudModel;
|
|
||||||
controller.$.lastTicketsPopover = {
|
|
||||||
hide: () => {},
|
|
||||||
show: () => {}
|
|
||||||
};
|
|
||||||
controller.card = {reload: () => {}};
|
|
||||||
$httpBackend.expectGET(`ClaimStates/findOne`).respond({});
|
|
||||||
}));
|
|
||||||
|
|
||||||
describe('getResolvedState()', () => {
|
|
||||||
it('should return the resolved state id', () => {
|
|
||||||
$httpBackend.expectGET(`ClaimStates/findOne`).respond({id: 1});
|
|
||||||
controller.getResolvedState();
|
|
||||||
$httpBackend.flush();
|
|
||||||
|
|
||||||
expect(controller.resolvedStateId).toEqual(1);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('calculateTotals()', () => {
|
|
||||||
it('should calculate the total price of the items claimed', () => {
|
|
||||||
controller.salesClaimed = [
|
|
||||||
{quantity: 5, price: 2, discount: 0},
|
|
||||||
{quantity: 10, price: 2, discount: 0},
|
|
||||||
{quantity: 10, price: 2, discount: 0}
|
|
||||||
];
|
|
||||||
controller.calculateTotals();
|
|
||||||
|
|
||||||
expect(controller.claimedTotal).toEqual(50);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('importToNewRefundTicket()', () => {
|
|
||||||
it('should perform a post query and add lines from a new ticket', () => {
|
|
||||||
jest.spyOn(controller.$.model, 'refresh');
|
|
||||||
jest.spyOn(controller.vnApp, 'showSuccess');
|
|
||||||
|
|
||||||
$httpBackend.expect('POST', `ClaimBeginnings/1/importToNewRefundTicket`).respond({});
|
|
||||||
controller.importToNewRefundTicket();
|
|
||||||
$httpBackend.flush();
|
|
||||||
|
|
||||||
expect(controller.$.model.refresh).toHaveBeenCalled();
|
|
||||||
expect(controller.vnApp.showSuccess).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('regularize()', () => {
|
|
||||||
it('should perform a post query and reload the claim card', () => {
|
|
||||||
jest.spyOn(controller.card, 'reload');
|
|
||||||
jest.spyOn(controller.vnApp, 'showSuccess');
|
|
||||||
|
|
||||||
$httpBackend.expect('POST', `Claims/1/regularizeClaim`).respond({});
|
|
||||||
controller.regularize();
|
|
||||||
$httpBackend.flush();
|
|
||||||
|
|
||||||
expect(controller.card.reload).toHaveBeenCalledWith();
|
|
||||||
expect(controller.vnApp.showSuccess).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('save()', () => {
|
|
||||||
it('should perform a patch query and show a success message', () => {
|
|
||||||
jest.spyOn(controller.vnApp, 'showSuccess');
|
|
||||||
|
|
||||||
const data = {pickup: 'agency'};
|
|
||||||
$httpBackend.expect('PATCH', `Claims/1/updateClaimAction`, data).respond({});
|
|
||||||
controller.save(data);
|
|
||||||
$httpBackend.flush();
|
|
||||||
|
|
||||||
expect(controller.vnApp.showSuccess).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('onUpdateGreugeAccept()', () => {
|
|
||||||
const greugeTypeId = 7;
|
|
||||||
const freightPickUpPrice = 11;
|
|
||||||
|
|
||||||
it('should make a query and get the greugeTypeId and greuge config', () => {
|
|
||||||
$httpBackend.expectRoute('GET', `GreugeTypes/findOne`).respond({id: greugeTypeId});
|
|
||||||
$httpBackend.expectGET(`GreugeConfigs/findOne`).respond({freightPickUpPrice});
|
|
||||||
controller.onUpdateGreugeAccept();
|
|
||||||
$httpBackend.flush();
|
|
||||||
|
|
||||||
expect(controller.greugeTypeFreightId).toEqual(greugeTypeId);
|
|
||||||
expect(controller.freightPickUpPrice).toEqual(freightPickUpPrice);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should perform a insert into greuges', done => {
|
|
||||||
jest.spyOn(controller, 'getGreugeTypeId').mockReturnValue(new Promise(resolve => {
|
|
||||||
return resolve({id: greugeTypeId});
|
|
||||||
}));
|
|
||||||
jest.spyOn(controller, 'getGreugeConfig').mockReturnValue(new Promise(resolve => {
|
|
||||||
return resolve({freightPickUpPrice});
|
|
||||||
}));
|
|
||||||
jest.spyOn(controller, 'updateGreuge').mockReturnValue(new Promise(resolve => {
|
|
||||||
return resolve(true);
|
|
||||||
}));
|
|
||||||
|
|
||||||
controller.claim.clientFk = 1101;
|
|
||||||
controller.claim.id = 11;
|
|
||||||
|
|
||||||
controller.onUpdateGreugeAccept().then(() => {
|
|
||||||
expect(controller.updateGreuge).toHaveBeenCalledWith(jasmine.any(Object));
|
|
||||||
done();
|
|
||||||
}).catch(done.fail);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('updateGreuge()', () => {
|
|
||||||
it('should make a query and then call to showSuccess() and showMessage() methods', () => {
|
|
||||||
jest.spyOn(controller.vnApp, 'showSuccess');
|
|
||||||
jest.spyOn(controller.vnApp, 'showMessage');
|
|
||||||
|
|
||||||
const freightPickUpPrice = 11;
|
|
||||||
const greugeTypeId = 7;
|
|
||||||
const expectedData = {
|
|
||||||
clientFk: 1101,
|
|
||||||
description: `claim: ${controller.claim.id}`,
|
|
||||||
amount: freightPickUpPrice,
|
|
||||||
greugeTypeFk: greugeTypeId,
|
|
||||||
ticketFk: controller.claim.ticketFk
|
|
||||||
};
|
|
||||||
$httpBackend.expect('POST', `Greuges`, expectedData).respond(200);
|
|
||||||
controller.updateGreuge(expectedData);
|
|
||||||
$httpBackend.flush();
|
|
||||||
|
|
||||||
expect(controller.vnApp.showSuccess).toHaveBeenCalledWith('Data saved!');
|
|
||||||
expect(controller.vnApp.showMessage).toHaveBeenCalledWith('Greuge added');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('onResponse()', () => {
|
|
||||||
it('should perform a post query and show a success message', () => {
|
|
||||||
jest.spyOn(controller.vnApp, 'showSuccess');
|
|
||||||
|
|
||||||
$httpBackend.expect('POST', `Claims/updateClaimDestination`).respond({});
|
|
||||||
controller.onResponse();
|
|
||||||
$httpBackend.flush();
|
|
||||||
|
|
||||||
expect(controller.vnApp.showSuccess).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1 +0,0 @@
|
||||||
ClaimGreugeDescription: Claim id {{claimId}}
|
|
|
@ -1,13 +0,0 @@
|
||||||
Destination: Destino
|
|
||||||
Action: Actuaciones
|
|
||||||
Total claimed: Total Reclamado
|
|
||||||
Import claim: Importar reclamacion
|
|
||||||
Imports claim details: Importa detalles de la reclamacion
|
|
||||||
Regularize: Regularizar
|
|
||||||
Do you want to insert greuges?: Desea insertar greuges?
|
|
||||||
Insert greuges on client card: Insertar greuges en la ficha del cliente
|
|
||||||
Greuge added: Greuge añadido
|
|
||||||
ClaimGreugeDescription: Reclamación id {{claimId}}
|
|
||||||
Change destination: Cambiar destino
|
|
||||||
Change destination to all selected rows: Cambiar destino a {{total}} fila(s) seleccionada(s)
|
|
||||||
Add observation to all selected clients: Añadir observación a {{total}} cliente(s) seleccionado(s)
|
|
|
@ -1,46 +0,0 @@
|
||||||
vn-claim-action {
|
|
||||||
.header {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
align-content: center;
|
|
||||||
|
|
||||||
vn-tool-bar {
|
|
||||||
flex: none
|
|
||||||
}
|
|
||||||
|
|
||||||
.vn-check {
|
|
||||||
flex: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
vn-dialog[vn-id=addSales] {
|
|
||||||
tpl-body {
|
|
||||||
width: 950px;
|
|
||||||
div {
|
|
||||||
div.buttons {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
vn-table{
|
|
||||||
min-width: 950px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
vn-popover.lastTicketsPopover {
|
|
||||||
vn-table {
|
|
||||||
min-width: 650px;
|
|
||||||
overflow: auto
|
|
||||||
}
|
|
||||||
|
|
||||||
div.ticketList {
|
|
||||||
overflow: auto;
|
|
||||||
max-height: 350px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.right {
|
|
||||||
margin-left: 370px;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,66 +0,0 @@
|
||||||
<mg-ajax path="Claims/updateClaim/{{patch.params.id}}" options="vnPatch"></mg-ajax>
|
|
||||||
<vn-watcher
|
|
||||||
vn-id="watcher"
|
|
||||||
data="$ctrl.claim"
|
|
||||||
form="form"
|
|
||||||
save="patch">
|
|
||||||
</vn-watcher>
|
|
||||||
<vn-crud-model
|
|
||||||
auto-load="true"
|
|
||||||
url="ClaimStates"
|
|
||||||
data="claimStates">
|
|
||||||
</vn-crud-model>
|
|
||||||
<form name="form" ng-submit="$ctrl.onSubmit()" class="vn-w-md">
|
|
||||||
<vn-card class="vn-pa-lg">
|
|
||||||
<vn-horizontal>
|
|
||||||
<vn-textfield
|
|
||||||
label="Client"
|
|
||||||
ng-model="$ctrl.claim.client.name"
|
|
||||||
readonly="true">
|
|
||||||
</vn-textfield>
|
|
||||||
<vn-textfield
|
|
||||||
label="Created"
|
|
||||||
field="::$ctrl.claim.created | date:'yyyy-MM-dd HH:mm'"
|
|
||||||
readonly="true">
|
|
||||||
</vn-textfield>
|
|
||||||
</vn-horizontal>
|
|
||||||
<vn-horizontal>
|
|
||||||
<vn-worker-autocomplete
|
|
||||||
disabled="false"
|
|
||||||
show-field="nickname"
|
|
||||||
ng-model="$ctrl.claim.workerFk"
|
|
||||||
departments="['VT']"
|
|
||||||
label="Attended by">
|
|
||||||
</vn-worker-autocomplete>
|
|
||||||
<vn-autocomplete
|
|
||||||
ng-model="$ctrl.claim.claimStateFk"
|
|
||||||
data="claimStates"
|
|
||||||
show-field="description"
|
|
||||||
value-field="id"
|
|
||||||
label="Claim state"
|
|
||||||
order="priority ASC"
|
|
||||||
vn-focus>
|
|
||||||
</vn-autocomplete>
|
|
||||||
</vn-horizontal>
|
|
||||||
<vn-horizontal>
|
|
||||||
<vn-input-number vn-one
|
|
||||||
min="0"
|
|
||||||
type="number"
|
|
||||||
label="Packages received"
|
|
||||||
ng-model="$ctrl.claim.packages">
|
|
||||||
</vn-input-number>
|
|
||||||
</vn-horizontal>
|
|
||||||
</vn-card>
|
|
||||||
<vn-button-bar>
|
|
||||||
<vn-submit
|
|
||||||
disabled="!watcher.dataChanged()"
|
|
||||||
label="Save">
|
|
||||||
</vn-submit>
|
|
||||||
<vn-button
|
|
||||||
class="cancel"
|
|
||||||
label="Undo changes"
|
|
||||||
disabled="!watcher.dataChanged()"
|
|
||||||
ng-click="watcher.loadOriginalData()">
|
|
||||||
</vn-button>
|
|
||||||
</vn-button-bar>
|
|
||||||
</form>
|
|
|
@ -1,20 +0,0 @@
|
||||||
import ngModule from '../module';
|
|
||||||
import Section from 'salix/components/section';
|
|
||||||
import './style.scss';
|
|
||||||
|
|
||||||
class Controller extends Section {
|
|
||||||
onSubmit() {
|
|
||||||
this.$.watcher.submit().then(() => {
|
|
||||||
if (this.aclService.hasAny(['claimManager']))
|
|
||||||
this.$state.go('claim.card.detail');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ngModule.vnComponent('vnClaimBasicData', {
|
|
||||||
template: require('./index.html'),
|
|
||||||
controller: Controller,
|
|
||||||
bindings: {
|
|
||||||
claim: '<'
|
|
||||||
}
|
|
||||||
});
|
|
|
@ -1,28 +0,0 @@
|
||||||
import './index.js';
|
|
||||||
import watcher from 'core/mocks/watcher';
|
|
||||||
|
|
||||||
describe('Claim', () => {
|
|
||||||
describe('Component vnClaimBasicData', () => {
|
|
||||||
let controller;
|
|
||||||
let $scope;
|
|
||||||
|
|
||||||
beforeEach(ngModule('claim'));
|
|
||||||
|
|
||||||
beforeEach(inject(($componentController, $rootScope) => {
|
|
||||||
$scope = $rootScope.$new();
|
|
||||||
$scope.watcher = watcher;
|
|
||||||
const $element = angular.element('<vn-claim-basic-data></vn-claim-basic-data>');
|
|
||||||
controller = $componentController('vnClaimBasicData', {$element, $scope});
|
|
||||||
}));
|
|
||||||
|
|
||||||
describe('onSubmit()', () => {
|
|
||||||
it(`should redirect to 'claim.card.detail' state`, () => {
|
|
||||||
jest.spyOn(controller.aclService, 'hasAny').mockReturnValue(true);
|
|
||||||
jest.spyOn(controller.$state, 'go');
|
|
||||||
controller.onSubmit();
|
|
||||||
|
|
||||||
expect(controller.$state.go).toHaveBeenCalledWith('claim.card.detail');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,9 +0,0 @@
|
||||||
Contact: Contacto
|
|
||||||
Claim state: Estado de la reclamación
|
|
||||||
Is paid with mana: Cargado al maná
|
|
||||||
Responsability: Responsabilidad
|
|
||||||
Company: Empresa
|
|
||||||
Sales/Client: Comercial/Cliente
|
|
||||||
Pick up: Recoger
|
|
||||||
When checked will notify to the salesPerson: Cuando se marque enviará una notificación de recogida al comercial
|
|
||||||
Packages received: Bultos recibidos
|
|
|
@ -1,3 +0,0 @@
|
||||||
vn-claim-basic-data vn-date-picker {
|
|
||||||
padding-left: 80px;
|
|
||||||
}
|
|
|
@ -1,5 +0,0 @@
|
||||||
<vn-portal slot="menu">
|
|
||||||
<vn-claim-descriptor claim="$ctrl.claim"></vn-claim-descriptor>
|
|
||||||
<vn-left-menu source="card"></vn-left-menu>
|
|
||||||
</vn-portal>
|
|
||||||
<ui-view></ui-view>
|
|
|
@ -1,68 +0,0 @@
|
||||||
import ngModule from '../module';
|
|
||||||
import ModuleCard from 'salix/components/module-card';
|
|
||||||
|
|
||||||
class Controller extends ModuleCard {
|
|
||||||
reload() {
|
|
||||||
let filter = {
|
|
||||||
include: [
|
|
||||||
{
|
|
||||||
relation: 'worker',
|
|
||||||
scope: {
|
|
||||||
fields: ['id'],
|
|
||||||
include: {
|
|
||||||
relation: 'user',
|
|
||||||
scope: {
|
|
||||||
fields: ['name']
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
relation: 'ticket',
|
|
||||||
scope: {
|
|
||||||
fields: ['zoneFk', 'addressFk'],
|
|
||||||
include: [
|
|
||||||
{
|
|
||||||
relation: 'zone',
|
|
||||||
scope: {
|
|
||||||
fields: ['name']
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
relation: 'address',
|
|
||||||
scope: {
|
|
||||||
fields: ['provinceFk'],
|
|
||||||
include: {
|
|
||||||
relation: 'province',
|
|
||||||
scope: {
|
|
||||||
fields: ['name']
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
relation: 'claimState',
|
|
||||||
scope: {
|
|
||||||
fields: ['id', 'description']
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
relation: 'client',
|
|
||||||
scope: {
|
|
||||||
fields: ['salesPersonFk', 'name', 'email'],
|
|
||||||
include: {
|
|
||||||
relation: 'salesPersonUser'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
};
|
|
||||||
|
|
||||||
this.$http.get(`Claims/${this.$params.id}`, {filter})
|
|
||||||
.then(res => this.claim = res.data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ngModule.vnComponent('vnClaimCard', {
|
|
||||||
template: require('./index.html'),
|
|
||||||
controller: Controller
|
|
||||||
});
|
|
|
@ -1,29 +0,0 @@
|
||||||
import './index.js';
|
|
||||||
|
|
||||||
describe('Claim', () => {
|
|
||||||
describe('Component vnClaimCard', () => {
|
|
||||||
let controller;
|
|
||||||
let $httpBackend;
|
|
||||||
let data = {id: 1, name: 'fooName'};
|
|
||||||
|
|
||||||
beforeEach(ngModule('claim'));
|
|
||||||
|
|
||||||
beforeEach(inject(($componentController, _$httpBackend_, $stateParams) => {
|
|
||||||
$httpBackend = _$httpBackend_;
|
|
||||||
|
|
||||||
let $element = angular.element('<div></div>');
|
|
||||||
controller = $componentController('vnClaimCard', {$element});
|
|
||||||
|
|
||||||
$stateParams.id = data.id;
|
|
||||||
$httpBackend.whenRoute('GET', 'Claims/:id').respond(data);
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should request data and set it on the controller', () => {
|
|
||||||
controller.reload();
|
|
||||||
$httpBackend.flush();
|
|
||||||
|
|
||||||
expect(controller.claim).toEqual(data);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
|
@ -29,9 +29,9 @@ class Controller extends Descriptor {
|
||||||
|
|
||||||
deleteClaim() {
|
deleteClaim() {
|
||||||
return this.$http.delete(`Claims/${this.claim.id}`)
|
return this.$http.delete(`Claims/${this.claim.id}`)
|
||||||
.then(() => {
|
.then(async() => {
|
||||||
this.vnApp.showSuccess(this.$t('Claim deleted!'));
|
this.vnApp.showSuccess(this.$t('Claim deleted!'));
|
||||||
this.$state.go('claim.index');
|
window.location.href = await this.vnApp.getUrl(`claim/`);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,14 +53,12 @@ describe('Item Component vnClaimDescriptor', () => {
|
||||||
describe('deleteClaim()', () => {
|
describe('deleteClaim()', () => {
|
||||||
it('should perform a query and call showSuccess if the response is accept', () => {
|
it('should perform a query and call showSuccess if the response is accept', () => {
|
||||||
jest.spyOn(controller.vnApp, 'showSuccess');
|
jest.spyOn(controller.vnApp, 'showSuccess');
|
||||||
jest.spyOn(controller.$state, 'go');
|
|
||||||
|
|
||||||
$httpBackend.expectDELETE(`Claims/${claim.id}`).respond();
|
$httpBackend.expectDELETE(`Claims/${claim.id}`).respond();
|
||||||
controller.deleteClaim();
|
controller.deleteClaim();
|
||||||
$httpBackend.flush();
|
$httpBackend.flush();
|
||||||
|
|
||||||
expect(controller.vnApp.showSuccess).toHaveBeenCalled();
|
expect(controller.vnApp.showSuccess).toHaveBeenCalled();
|
||||||
expect(controller.$state.go).toHaveBeenCalledWith('claim.index');
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,178 +0,0 @@
|
||||||
<vn-crud-model
|
|
||||||
vn-id="model"
|
|
||||||
auto-load="true"
|
|
||||||
url="ClaimBeginnings"
|
|
||||||
filter="$ctrl.filter"
|
|
||||||
data="$ctrl.salesClaimed"
|
|
||||||
on-data-change="$ctrl.calculateTotals()">
|
|
||||||
</vn-crud-model>
|
|
||||||
<vn-card
|
|
||||||
class="vn-mb-md vn-pa-lg vn-w-lg"
|
|
||||||
style="text-align: right"
|
|
||||||
ng-if="$ctrl.salesClaimed.length > 0">
|
|
||||||
<vn-label-value label="Total"
|
|
||||||
value="{{$ctrl.paidTotal | currency: 'EUR':2}}">
|
|
||||||
</vn-label-value>
|
|
||||||
<vn-label-value label="Total claimed"
|
|
||||||
value="{{$ctrl.claimedTotal | currency: 'EUR':2}}">
|
|
||||||
</vn-label-value>
|
|
||||||
</vn-card>
|
|
||||||
<vn-data-viewer model="model">
|
|
||||||
<vn-card>
|
|
||||||
<vn-table model="model">
|
|
||||||
<vn-thead>
|
|
||||||
<vn-tr>
|
|
||||||
<vn-th center expand>Landed</vn-th>
|
|
||||||
<vn-th number>Quantity</vn-th>
|
|
||||||
<vn-th>Claimed</vn-th>
|
|
||||||
<vn-th>Description</vn-th>
|
|
||||||
<vn-th number>Price</vn-th>
|
|
||||||
<vn-th number>Disc.</vn-th>
|
|
||||||
<vn-th number>Total</vn-th>
|
|
||||||
<vn-th></vn-th>
|
|
||||||
</vn-tr>
|
|
||||||
</vn-thead>
|
|
||||||
<vn-tbody>
|
|
||||||
<vn-tr ng-repeat="saleClaimed in $ctrl.salesClaimed" vn-repeat-last>
|
|
||||||
<vn-td center expand>{{::saleClaimed.sale.ticket.landed | date:'dd/MM/yyyy'}}</vn-td>
|
|
||||||
<vn-td number>{{::saleClaimed.sale.quantity}}</vn-td>
|
|
||||||
<vn-td>
|
|
||||||
<vn-input-number
|
|
||||||
min="0"
|
|
||||||
step="1"
|
|
||||||
disabled="!$ctrl.isRewritable"
|
|
||||||
ng-model="saleClaimed.quantity"
|
|
||||||
on-change="$ctrl.setClaimedQuantity(saleClaimed.id, saleClaimed.quantity)"
|
|
||||||
class="dense">
|
|
||||||
</vn-input-number>
|
|
||||||
</vn-td>
|
|
||||||
<vn-td expand title="{{::saleClaimed.sale.concept}}">
|
|
||||||
<span
|
|
||||||
ng-click="itemDescriptor.show($event, saleClaimed.sale.itemFk)"
|
|
||||||
class="link">
|
|
||||||
{{::saleClaimed.sale.concept}}
|
|
||||||
</span>
|
|
||||||
</vn-td>
|
|
||||||
<vn-td number>{{::saleClaimed.sale.price | currency: 'EUR':2}}</vn-td>
|
|
||||||
<vn-td number>
|
|
||||||
<span ng-class="{'link': $ctrl.isRewritable && $ctrl.isClaimManager}"
|
|
||||||
translate-attr="{title: $ctrl.isRewritable && $ctrl.isClaimManager ? 'Edit discount' : ''}"
|
|
||||||
ng-click="$ctrl.showEditPopover($event, saleClaimed)">
|
|
||||||
{{saleClaimed.sale.discount}} %
|
|
||||||
</span>
|
|
||||||
</vn-td>
|
|
||||||
<vn-td number>
|
|
||||||
{{$ctrl.getSaleTotal(saleClaimed.sale) | currency: 'EUR':2}}
|
|
||||||
</vn-td>
|
|
||||||
<vn-td shrink>
|
|
||||||
<vn-icon-button
|
|
||||||
vn-tooltip="Remove sale"
|
|
||||||
ng-if ="$ctrl.isRewritable"
|
|
||||||
icon="delete"
|
|
||||||
ng-click="$ctrl.showDeleteConfirm($index)"
|
|
||||||
tabindex="-1">
|
|
||||||
</vn-icon-button>
|
|
||||||
</vn-td>
|
|
||||||
</vn-tr>
|
|
||||||
</vn-tbody>
|
|
||||||
</vn-table>
|
|
||||||
</vn-card>
|
|
||||||
</vn-data-viewer>
|
|
||||||
<vn-button
|
|
||||||
label="Next"
|
|
||||||
class="next"
|
|
||||||
ui-sref="claim.card.photos">
|
|
||||||
</vn-button>
|
|
||||||
<vn-float-button
|
|
||||||
icon="add"
|
|
||||||
ng-if="$ctrl.isRewritable"
|
|
||||||
ng-click="$ctrl.openAddSalesDialog()"
|
|
||||||
vn-tooltip="Add sale item" vn-bind="+"
|
|
||||||
fixed-bottom-right>
|
|
||||||
</vn-float-button>
|
|
||||||
<!-- Add Lines Dialog -->
|
|
||||||
<vn-dialog vn-id="add-sales" class="modal-form">
|
|
||||||
<tpl-title>
|
|
||||||
<span translate>Claimable sales from ticket</span> {{$ctrl.claim.ticketFk}}
|
|
||||||
</tpl-title>
|
|
||||||
<tpl-body>
|
|
||||||
<vn-horizontal class="vn-pa-md">
|
|
||||||
<vn-table>
|
|
||||||
<vn-thead>
|
|
||||||
<vn-tr>
|
|
||||||
<vn-th number>Landed</vn-th>
|
|
||||||
<vn-th number>Quantity</vn-th>
|
|
||||||
<vn-th number>Description</vn-th>
|
|
||||||
<vn-th number>Price</vn-th>
|
|
||||||
<vn-th number>Disc.</vn-th>
|
|
||||||
<vn-th number>Total</vn-th>
|
|
||||||
</vn-tr>
|
|
||||||
</vn-thead>
|
|
||||||
<vn-tbody>
|
|
||||||
<vn-tr
|
|
||||||
ng-repeat="sale in $ctrl.salesToClaim"
|
|
||||||
ng-click="$ctrl.addClaimedSale($index)"
|
|
||||||
class="clickable">
|
|
||||||
<vn-td number>{{sale.landed | date: 'dd/MM/yyyy'}}</vn-td>
|
|
||||||
<vn-td number>{{sale.quantity}}</vn-td>
|
|
||||||
<vn-td expand title="{{::sale.concept}}">
|
|
||||||
<span
|
|
||||||
vn-click-stop="itemDescriptor.show($event, sale.itemFk)"
|
|
||||||
class="link">
|
|
||||||
{{sale.itemFk}} - {{sale.concept}}
|
|
||||||
</span>
|
|
||||||
</vn-td>
|
|
||||||
<vn-td number>{{sale.price | currency: 'EUR':2}}</vn-td>
|
|
||||||
<vn-td number>{{sale.discount}} %</vn-td>
|
|
||||||
<vn-td number>
|
|
||||||
{{(sale.quantity * sale.price) - ((sale.discount * (sale.quantity * sale.price))/100) | currency: 'EUR':2}}
|
|
||||||
</vn-td>
|
|
||||||
</vn-tr>
|
|
||||||
</vn-tbody>
|
|
||||||
</vn-table>
|
|
||||||
</vn-horizontal>
|
|
||||||
</tpl-body>
|
|
||||||
</vn-dialog>
|
|
||||||
<vn-item-descriptor-popover
|
|
||||||
vn-id="item-descriptor"
|
|
||||||
warehouse-fk="$ctrl.vnConfig.warehouseFk">
|
|
||||||
</vn-item-descriptor-popover>
|
|
||||||
<vn-popover
|
|
||||||
class="edit"
|
|
||||||
vn-id="edit-popover"
|
|
||||||
on-open="$ctrl.getSalespersonMana()"
|
|
||||||
on-close="$ctrl.mana = null">
|
|
||||||
<div class="discount-popover">
|
|
||||||
<vn-spinner
|
|
||||||
ng-if="$ctrl.mana == null"
|
|
||||||
style="padding: 1em;"
|
|
||||||
enable="true">
|
|
||||||
</vn-spinner>
|
|
||||||
<div ng-if="$ctrl.mana != null">
|
|
||||||
<vn-horizontal class="header vn-pa-md">
|
|
||||||
<h5>MANÁ: {{$ctrl.mana | currency: 'EUR':0}}</h5>
|
|
||||||
</vn-horizontal>
|
|
||||||
<div class="vn-pa-md">
|
|
||||||
<vn-input-number
|
|
||||||
vn-focus
|
|
||||||
label="Discount"
|
|
||||||
ng-model="$ctrl.newDiscount"
|
|
||||||
type="text"
|
|
||||||
step="0.01"
|
|
||||||
on-change="$ctrl.updateDiscount()"
|
|
||||||
suffix="€">
|
|
||||||
</vn-input-number>
|
|
||||||
<div class="simulator">
|
|
||||||
<p class="simulatorTitle" translate>Total claimed price</p>
|
|
||||||
<p>{{$ctrl.newPrice | currency: 'EUR':2}}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</vn-popover>
|
|
||||||
<vn-confirm
|
|
||||||
vn-id="confirm"
|
|
||||||
question="Delete sale from claim?"
|
|
||||||
on-accept="$ctrl.deleteClaimedSale()">
|
|
||||||
</vn-confirm>
|
|
|
@ -1,203 +0,0 @@
|
||||||
import ngModule from '../module';
|
|
||||||
import Section from 'salix/components/section';
|
|
||||||
import './style.scss';
|
|
||||||
|
|
||||||
class Controller extends Section {
|
|
||||||
constructor($element, $) {
|
|
||||||
super($element, $);
|
|
||||||
this.edit = {};
|
|
||||||
this.filter = {
|
|
||||||
where: {claimFk: this.$params.id},
|
|
||||||
include: [
|
|
||||||
{
|
|
||||||
relation: 'sale',
|
|
||||||
scope: {
|
|
||||||
fields: ['concept', 'ticketFk', 'price', 'quantity', 'discount', 'itemFk'],
|
|
||||||
include: {
|
|
||||||
relation: 'ticket'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
get claim() {
|
|
||||||
return this._claim;
|
|
||||||
}
|
|
||||||
|
|
||||||
set claim(value) {
|
|
||||||
this._claim = value;
|
|
||||||
|
|
||||||
if (value) {
|
|
||||||
this.isClaimEditable();
|
|
||||||
this.isTicketEditable();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
set salesClaimed(value) {
|
|
||||||
this._salesClaimed = value;
|
|
||||||
|
|
||||||
if (value) this.calculateTotals();
|
|
||||||
}
|
|
||||||
|
|
||||||
get salesClaimed() {
|
|
||||||
return this._salesClaimed;
|
|
||||||
}
|
|
||||||
|
|
||||||
get newDiscount() {
|
|
||||||
return this._newDiscount;
|
|
||||||
}
|
|
||||||
|
|
||||||
set newDiscount(value) {
|
|
||||||
this._newDiscount = value;
|
|
||||||
this.updateNewPrice();
|
|
||||||
}
|
|
||||||
|
|
||||||
get isClaimManager() {
|
|
||||||
return this.aclService.hasAny(['claimManager']);
|
|
||||||
}
|
|
||||||
|
|
||||||
openAddSalesDialog() {
|
|
||||||
this.getClaimableFromTicket();
|
|
||||||
this.$.addSales.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
getClaimableFromTicket() {
|
|
||||||
let config = {params: {ticketFk: this.claim.ticketFk}};
|
|
||||||
let query = `Sales/getClaimableFromTicket`;
|
|
||||||
this.$http.get(query, config).then(res => {
|
|
||||||
if (res.data)
|
|
||||||
this.salesToClaim = res.data;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
addClaimedSale(index) {
|
|
||||||
let sale = this.salesToClaim[index];
|
|
||||||
let saleToAdd = {saleFk: sale.saleFk, claimFk: this.claim.id, quantity: sale.quantity};
|
|
||||||
let query = `ClaimBeginnings/`;
|
|
||||||
this.$http.post(query, saleToAdd).then(() => {
|
|
||||||
this.$.addSales.hide();
|
|
||||||
this.$.model.refresh();
|
|
||||||
this.vnApp.showSuccess(this.$t('Data saved!'));
|
|
||||||
|
|
||||||
if (this.aclService.hasAny(['claimManager']))
|
|
||||||
this.$state.go('claim.card.development');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
showDeleteConfirm($index) {
|
|
||||||
this.claimedIndex = $index;
|
|
||||||
this.$.confirm.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
deleteClaimedSale() {
|
|
||||||
this.$.model.remove(this.claimedIndex);
|
|
||||||
this.$.model.save().then(() => {
|
|
||||||
this.vnApp.showSuccess(this.$t('Data saved!'));
|
|
||||||
this.calculateTotals();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
setClaimedQuantity(id, claimedQuantity) {
|
|
||||||
let params = {quantity: claimedQuantity};
|
|
||||||
let query = `ClaimBeginnings/${id}`;
|
|
||||||
this.$http.patch(query, params).then(() => {
|
|
||||||
this.vnApp.showSuccess(this.$t('Data saved!'));
|
|
||||||
this.calculateTotals();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
calculateTotals() {
|
|
||||||
this.paidTotal = 0.0;
|
|
||||||
this.claimedTotal = 0.0;
|
|
||||||
if (!this._salesClaimed) return;
|
|
||||||
|
|
||||||
this._salesClaimed.forEach(sale => {
|
|
||||||
let orgSale = sale.sale;
|
|
||||||
this.paidTotal += this.getSaleTotal(orgSale);
|
|
||||||
|
|
||||||
const price = sale.quantity * orgSale.price;
|
|
||||||
const discount = ((orgSale.discount * price) / 100);
|
|
||||||
|
|
||||||
this.claimedTotal += price - discount;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
getSaleTotal(sale) {
|
|
||||||
let total = 0.0;
|
|
||||||
|
|
||||||
const price = sale.quantity * sale.price;
|
|
||||||
const discount = ((sale.discount * price) / 100);
|
|
||||||
|
|
||||||
total += price - discount;
|
|
||||||
return total;
|
|
||||||
}
|
|
||||||
|
|
||||||
getSalespersonMana() {
|
|
||||||
this.$http.get(`Tickets/${this.claim.ticketFk}/getSalesPersonMana`).then(res => {
|
|
||||||
this.mana = res.data;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
isTicketEditable() {
|
|
||||||
if (!this.claim) return;
|
|
||||||
|
|
||||||
this.$http.get(`Tickets/${this.claim.ticketFk}/isEditable`).then(res => {
|
|
||||||
this.isEditable = res.data;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
isClaimEditable() {
|
|
||||||
if (!this.claim) return;
|
|
||||||
|
|
||||||
this.$http.get(`ClaimStates/${this.claim.claimStateFk}/isEditable`).then(res => {
|
|
||||||
this.isRewritable = res.data;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
showEditPopover(event, saleClaimed) {
|
|
||||||
if (this.aclService.hasAny(['claimManager'])) {
|
|
||||||
this.saleClaimed = saleClaimed;
|
|
||||||
this.$.editPopover.parent = event.target;
|
|
||||||
this.$.editPopover.show();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
updateDiscount() {
|
|
||||||
const claimedSale = this.saleClaimed.sale;
|
|
||||||
if (this.newDiscount != claimedSale.discount) {
|
|
||||||
const params = {salesIds: [claimedSale.id], newDiscount: this.newDiscount};
|
|
||||||
const query = `Tickets/${claimedSale.ticketFk}/updateDiscount`;
|
|
||||||
|
|
||||||
this.$http.post(query, params).then(() => {
|
|
||||||
claimedSale.discount = this.newDiscount;
|
|
||||||
this.calculateTotals();
|
|
||||||
this.clearDiscount();
|
|
||||||
|
|
||||||
this.vnApp.showSuccess(this.$t('Data saved!'));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
this.$.editPopover.hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
updateNewPrice() {
|
|
||||||
this.newPrice = (this.saleClaimed.quantity * this.saleClaimed.sale.price) -
|
|
||||||
((this.newDiscount * (this.saleClaimed.quantity * this.saleClaimed.sale.price)) / 100);
|
|
||||||
}
|
|
||||||
|
|
||||||
clearDiscount() {
|
|
||||||
this.newDiscount = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Controller.$inject = ['$element', '$scope'];
|
|
||||||
|
|
||||||
ngModule.vnComponent('vnClaimDetail', {
|
|
||||||
template: require('./index.html'),
|
|
||||||
controller: Controller,
|
|
||||||
bindings: {
|
|
||||||
claim: '<'
|
|
||||||
}
|
|
||||||
});
|
|
|
@ -1,150 +0,0 @@
|
||||||
import './index.js';
|
|
||||||
import crudModel from 'core/mocks/crud-model';
|
|
||||||
|
|
||||||
describe('claim', () => {
|
|
||||||
describe('Component vnClaimDetail', () => {
|
|
||||||
let $scope;
|
|
||||||
let controller;
|
|
||||||
let $httpBackend;
|
|
||||||
|
|
||||||
beforeEach(ngModule('claim'));
|
|
||||||
|
|
||||||
beforeEach(inject(($componentController, _$httpBackend_, $rootScope) => {
|
|
||||||
$scope = $rootScope.$new();
|
|
||||||
$scope.descriptor = {
|
|
||||||
show: () => {}
|
|
||||||
};
|
|
||||||
$httpBackend = _$httpBackend_;
|
|
||||||
$httpBackend.whenGET('Claims/ClaimBeginnings').respond({});
|
|
||||||
$httpBackend.whenGET(`Tickets/1/isEditable`).respond(true);
|
|
||||||
$httpBackend.whenGET(`ClaimStates/2/isEditable`).respond(true);
|
|
||||||
const $element = angular.element('<vn-claim-detail></vn-claim-detail>');
|
|
||||||
controller = $componentController('vnClaimDetail', {$element, $scope});
|
|
||||||
controller.claim = {
|
|
||||||
ticketFk: 1,
|
|
||||||
id: 2,
|
|
||||||
claimStateFk: 2}
|
|
||||||
;
|
|
||||||
controller.salesToClaim = [{saleFk: 1}, {saleFk: 2}];
|
|
||||||
controller.salesClaimed = [{id: 1, sale: {}}];
|
|
||||||
controller.$.model = crudModel;
|
|
||||||
controller.$.addSales = {
|
|
||||||
hide: () => {},
|
|
||||||
show: () => {}
|
|
||||||
};
|
|
||||||
controller.$.editPopover = {
|
|
||||||
hide: () => {}
|
|
||||||
};
|
|
||||||
jest.spyOn(controller.aclService, 'hasAny').mockReturnValue(true);
|
|
||||||
}));
|
|
||||||
|
|
||||||
describe('openAddSalesDialog()', () => {
|
|
||||||
it('should call getClaimableFromTicket and $.addSales.show', () => {
|
|
||||||
jest.spyOn(controller, 'getClaimableFromTicket');
|
|
||||||
jest.spyOn(controller.$.addSales, 'show');
|
|
||||||
controller.openAddSalesDialog();
|
|
||||||
|
|
||||||
expect(controller.getClaimableFromTicket).toHaveBeenCalledWith();
|
|
||||||
expect(controller.$.addSales.show).toHaveBeenCalledWith();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('getClaimableFromTicket()', () => {
|
|
||||||
it('should make a query and set salesToClaim', () => {
|
|
||||||
$httpBackend.expectGET(`Sales/getClaimableFromTicket?ticketFk=1`).respond(200, 1);
|
|
||||||
controller.getClaimableFromTicket();
|
|
||||||
$httpBackend.flush();
|
|
||||||
|
|
||||||
expect(controller.salesToClaim).toEqual(1);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('addClaimedSale(index)', () => {
|
|
||||||
it('should make a post and call refresh, hide and showSuccess', () => {
|
|
||||||
jest.spyOn(controller.$.addSales, 'hide');
|
|
||||||
jest.spyOn(controller.$state, 'go');
|
|
||||||
$httpBackend.expectPOST(`ClaimBeginnings/`).respond({});
|
|
||||||
controller.addClaimedSale(1);
|
|
||||||
$httpBackend.flush();
|
|
||||||
|
|
||||||
expect(controller.$.addSales.hide).toHaveBeenCalledWith();
|
|
||||||
expect(controller.$state.go).toHaveBeenCalledWith('claim.card.development');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('deleteClaimedSale()', () => {
|
|
||||||
it('should make a delete and call refresh and showSuccess', () => {
|
|
||||||
const claimedIndex = 1;
|
|
||||||
controller.claimedIndex = claimedIndex;
|
|
||||||
jest.spyOn(controller.$.model, 'remove');
|
|
||||||
jest.spyOn(controller.$.model, 'save');
|
|
||||||
jest.spyOn(controller.vnApp, 'showSuccess');
|
|
||||||
|
|
||||||
controller.deleteClaimedSale();
|
|
||||||
|
|
||||||
expect(controller.$.model.remove).toHaveBeenCalledWith(claimedIndex);
|
|
||||||
expect(controller.$.model.save).toHaveBeenCalledWith();
|
|
||||||
expect(controller.vnApp.showSuccess).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('setClaimedQuantity(id, claimedQuantity)', () => {
|
|
||||||
it('should make a patch and call refresh and showSuccess', () => {
|
|
||||||
const id = 1;
|
|
||||||
const claimedQuantity = 1;
|
|
||||||
|
|
||||||
jest.spyOn(controller.vnApp, 'showSuccess');
|
|
||||||
$httpBackend.expectPATCH(`ClaimBeginnings/${id}`).respond({});
|
|
||||||
controller.setClaimedQuantity(id, claimedQuantity);
|
|
||||||
$httpBackend.flush();
|
|
||||||
|
|
||||||
expect(controller.vnApp.showSuccess).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('calculateTotals()', () => {
|
|
||||||
it('should set paidTotal and claimedTotal to 0 if salesClaimed has no data', () => {
|
|
||||||
controller.salesClaimed = [];
|
|
||||||
controller.calculateTotals();
|
|
||||||
|
|
||||||
expect(controller.paidTotal).toEqual(0);
|
|
||||||
expect(controller.claimedTotal).toEqual(0);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('updateDiscount()', () => {
|
|
||||||
it('should perform a query if the new discount differs from the claim discount', () => {
|
|
||||||
controller.saleClaimed = {sale: {
|
|
||||||
discount: 5,
|
|
||||||
id: 7,
|
|
||||||
ticketFk: 1,
|
|
||||||
price: 2,
|
|
||||||
quantity: 10}};
|
|
||||||
controller.newDiscount = 10;
|
|
||||||
|
|
||||||
jest.spyOn(controller.vnApp, 'showSuccess');
|
|
||||||
jest.spyOn(controller, 'calculateTotals');
|
|
||||||
jest.spyOn(controller, 'clearDiscount');
|
|
||||||
jest.spyOn(controller.$.editPopover, 'hide');
|
|
||||||
|
|
||||||
$httpBackend.when('POST', 'Tickets/1/updateDiscount').respond({});
|
|
||||||
controller.updateDiscount();
|
|
||||||
$httpBackend.flush();
|
|
||||||
|
|
||||||
expect(controller.calculateTotals).toHaveBeenCalledWith();
|
|
||||||
expect(controller.clearDiscount).toHaveBeenCalledWith();
|
|
||||||
expect(controller.vnApp.showSuccess).toHaveBeenCalled();
|
|
||||||
expect(controller.$.editPopover.hide).toHaveBeenCalledWith();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('isTicketEditable()', () => {
|
|
||||||
it('should check if the ticket assigned to the claim is editable', () => {
|
|
||||||
controller.isTicketEditable();
|
|
||||||
$httpBackend.flush();
|
|
||||||
|
|
||||||
expect(controller.isEditable).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,11 +0,0 @@
|
||||||
Claimed: Reclamados
|
|
||||||
Disc.: Dto.
|
|
||||||
Attended by: Atendida por
|
|
||||||
Landed: F. entrega
|
|
||||||
Price: Precio
|
|
||||||
Claimable sales from ticket: Lineas reclamables del ticket
|
|
||||||
Detail: Detalles
|
|
||||||
Add sale item: Añadir artículo
|
|
||||||
Insuficient permisos: Permisos insuficientes
|
|
||||||
Total claimed price: Precio total reclamado
|
|
||||||
Delete sale from claim?: ¿Borrar la linea de la reclamación?
|
|
|
@ -1,30 +0,0 @@
|
||||||
@import "variables";
|
|
||||||
|
|
||||||
.vn-popover .discount-popover {
|
|
||||||
width: 256px;
|
|
||||||
|
|
||||||
.header {
|
|
||||||
background-color: $color-main;
|
|
||||||
color: $color-font-dark;
|
|
||||||
|
|
||||||
h5 {
|
|
||||||
color: inherit;
|
|
||||||
margin: 0 auto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.simulatorTitle {
|
|
||||||
margin-bottom: 0;
|
|
||||||
font-size: .75rem;
|
|
||||||
color: $color-main;
|
|
||||||
}
|
|
||||||
vn-label-value {
|
|
||||||
padding-bottom: 20px;
|
|
||||||
}
|
|
||||||
.simulator{
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.next{
|
|
||||||
float: right;
|
|
||||||
}
|
|
|
@ -1,2 +0,0 @@
|
||||||
<vn-card>
|
|
||||||
</vn-card>
|
|
|
@ -1,21 +0,0 @@
|
||||||
import ngModule from '../module';
|
|
||||||
import Section from 'salix/components/section';
|
|
||||||
|
|
||||||
class Controller extends Section {
|
|
||||||
constructor($element, $) {
|
|
||||||
super($element, $);
|
|
||||||
}
|
|
||||||
|
|
||||||
async $onInit() {
|
|
||||||
this.$state.go('claim.card.summary', {id: this.$params.id});
|
|
||||||
window.location.href = await this.vnApp.getUrl(`claim/${this.$params.id}/development`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ngModule.vnComponent('vnClaimDevelopment', {
|
|
||||||
template: require('./index.html'),
|
|
||||||
controller: Controller,
|
|
||||||
bindings: {
|
|
||||||
claim: '<'
|
|
||||||
}
|
|
||||||
});
|
|
|
@ -1,16 +1,4 @@
|
||||||
export * from './module';
|
export * from './module';
|
||||||
|
|
||||||
import './main';
|
import './main';
|
||||||
import './index/';
|
|
||||||
import './action';
|
|
||||||
import './basic-data';
|
|
||||||
import './card';
|
|
||||||
import './detail';
|
|
||||||
import './descriptor';
|
import './descriptor';
|
||||||
import './development';
|
|
||||||
import './search-panel';
|
|
||||||
import './summary';
|
|
||||||
import './photos';
|
|
||||||
import './log';
|
|
||||||
import './note/index';
|
|
||||||
import './note/create';
|
|
||||||
|
|
|
@ -1,83 +0,0 @@
|
||||||
<vn-auto-search
|
|
||||||
model="model">
|
|
||||||
</vn-auto-search>
|
|
||||||
<vn-card>
|
|
||||||
<smart-table
|
|
||||||
model="model"
|
|
||||||
options="$ctrl.smartTableOptions"
|
|
||||||
expr-builder="$ctrl.exprBuilder(param, value)">
|
|
||||||
<slot-table>
|
|
||||||
<table>
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th field="clientFk" shrink>
|
|
||||||
<span translate>Id</span>
|
|
||||||
</th>
|
|
||||||
<th field="clientName">
|
|
||||||
<span translate>Client</span>
|
|
||||||
</th>
|
|
||||||
<th field="created" center shrink-date>
|
|
||||||
<span translate>Created</span>
|
|
||||||
</th>
|
|
||||||
<th field="workerFk">
|
|
||||||
<span translate>Worker</span>
|
|
||||||
</th>
|
|
||||||
<th field="claimStateFk">
|
|
||||||
<span translate>State</span>
|
|
||||||
</th>
|
|
||||||
<th></th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr
|
|
||||||
ng-repeat="claim in model.data"
|
|
||||||
vn-anchor="::{
|
|
||||||
state: 'claim.card.summary',
|
|
||||||
params: {id: claim.id}
|
|
||||||
}">
|
|
||||||
<td>{{::claim.id}}</td>
|
|
||||||
<td>
|
|
||||||
<span
|
|
||||||
vn-click-stop="clientDescriptor.show($event, claim.clientFk)"
|
|
||||||
class="link">
|
|
||||||
{{::claim.clientName}}
|
|
||||||
</span>
|
|
||||||
</td>
|
|
||||||
<td center shrink-date>{{::claim.created | date:'dd/MM/yyyy'}}</td>
|
|
||||||
<td>
|
|
||||||
<span
|
|
||||||
vn-click-stop="workerDescriptor.show($event, claim.workerFk)"
|
|
||||||
class="link" >
|
|
||||||
{{::claim.workerName}}
|
|
||||||
</span>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<span class="chip {{::$ctrl.stateColor(claim.stateCode)}}">
|
|
||||||
{{::claim.stateDescription}}
|
|
||||||
</span>
|
|
||||||
</td>
|
|
||||||
<td shrink>
|
|
||||||
<vn-icon-button
|
|
||||||
vn-click-stop="$ctrl.preview(claim)"
|
|
||||||
vn-tooltip="Preview"
|
|
||||||
icon="preview">
|
|
||||||
</vn-icon-button>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</slot-table>
|
|
||||||
</smart-table>
|
|
||||||
</vn-card>
|
|
||||||
<vn-client-descriptor-popover
|
|
||||||
vn-id="clientDescriptor">
|
|
||||||
</vn-client-descriptor-popover>
|
|
||||||
<vn-worker-descriptor-popover
|
|
||||||
vn-id="workerDescriptor">
|
|
||||||
</vn-worker-descriptor-popover>
|
|
||||||
<vn-popup vn-id="summary">
|
|
||||||
<vn-claim-summary
|
|
||||||
claim="$ctrl.claimSelected"
|
|
||||||
parent-reload="$ctrl.reload()">
|
|
||||||
</vn-claim-summary>
|
|
||||||
</vn-popup>
|
|
|
@ -1,82 +0,0 @@
|
||||||
import ngModule from '../module';
|
|
||||||
import Section from 'salix/components/section';
|
|
||||||
|
|
||||||
class Controller extends Section {
|
|
||||||
constructor($element, $) {
|
|
||||||
super($element, $);
|
|
||||||
|
|
||||||
this.smartTableOptions = {
|
|
||||||
activeButtons: {
|
|
||||||
search: true
|
|
||||||
},
|
|
||||||
columns: [
|
|
||||||
{
|
|
||||||
field: 'clientName',
|
|
||||||
autocomplete: {
|
|
||||||
url: 'Clients',
|
|
||||||
showField: 'name',
|
|
||||||
valueField: 'name'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
field: 'workerFk',
|
|
||||||
autocomplete: {
|
|
||||||
url: 'Workers/activeWithInheritedRole',
|
|
||||||
where: `{role: 'salesPerson'}`,
|
|
||||||
searchFunction: '{firstName: $search}',
|
|
||||||
showField: 'name',
|
|
||||||
valueField: 'id',
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
field: 'claimStateFk',
|
|
||||||
autocomplete: {
|
|
||||||
url: 'ClaimStates',
|
|
||||||
showField: 'description',
|
|
||||||
valueField: 'id',
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
field: 'created',
|
|
||||||
searchable: false
|
|
||||||
}
|
|
||||||
]
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
exprBuilder(param, value) {
|
|
||||||
switch (param) {
|
|
||||||
case 'clientName':
|
|
||||||
return {'cl.clientName': {like: `%${value}%`}};
|
|
||||||
case 'clientFk':
|
|
||||||
case 'claimStateFk':
|
|
||||||
case 'workerFk':
|
|
||||||
return {[`cl.${param}`]: value};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stateColor(code) {
|
|
||||||
switch (code) {
|
|
||||||
case 'pending':
|
|
||||||
return 'warning';
|
|
||||||
case 'managed':
|
|
||||||
return 'notice';
|
|
||||||
case 'resolved':
|
|
||||||
return 'success';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
preview(claim) {
|
|
||||||
this.claimSelected = claim;
|
|
||||||
this.$.summary.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
reload() {
|
|
||||||
this.$.model.refresh();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ngModule.vnComponent('vnClaimIndex', {
|
|
||||||
template: require('./index.html'),
|
|
||||||
controller: Controller
|
|
||||||
});
|
|
|
@ -1,4 +0,0 @@
|
||||||
<vn-log
|
|
||||||
url="ClaimLogs"
|
|
||||||
origin-id="$ctrl.$params.id">
|
|
||||||
</vn-log>
|
|
|
@ -1,7 +0,0 @@
|
||||||
import ngModule from '../module';
|
|
||||||
import Section from 'salix/components/section';
|
|
||||||
|
|
||||||
ngModule.vnComponent('vnClaimLog', {
|
|
||||||
template: require('./index.html'),
|
|
||||||
controller: Section,
|
|
||||||
});
|
|
|
@ -1,19 +0,0 @@
|
||||||
<vn-crud-model
|
|
||||||
vn-id="model"
|
|
||||||
url="Claims/filter"
|
|
||||||
limit="20"
|
|
||||||
order="priority ASC, created DESC"
|
|
||||||
auto-load="true">
|
|
||||||
</vn-crud-model>
|
|
||||||
<vn-portal slot="topbar">
|
|
||||||
<vn-searchbar
|
|
||||||
vn-focus
|
|
||||||
panel="vn-claim-search-panel"
|
|
||||||
info="Search claim by id or client name"
|
|
||||||
model="model">
|
|
||||||
</vn-searchbar>
|
|
||||||
</vn-portal>
|
|
||||||
<vn-portal slot="menu">
|
|
||||||
<vn-left-menu></vn-left-menu>
|
|
||||||
</vn-portal>
|
|
||||||
<ui-view></ui-view>
|
|
|
@ -1,7 +1,18 @@
|
||||||
import ngModule from '../module';
|
import ngModule from '../module';
|
||||||
import ModuleMain from 'salix/components/module-main';
|
import ModuleMain from 'salix/components/module-main';
|
||||||
|
|
||||||
|
export default class Claim extends ModuleMain {
|
||||||
|
constructor($element, $) {
|
||||||
|
super($element, $);
|
||||||
|
}
|
||||||
|
async $onInit() {
|
||||||
|
this.$state.go('home');
|
||||||
|
window.location.href = await this.vnApp.getUrl(`Claim/`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ngModule.vnComponent('vnClaim', {
|
ngModule.vnComponent('vnClaim', {
|
||||||
controller: ModuleMain,
|
controller: Claim,
|
||||||
template: require('./index.html')
|
template: require('./index.html')
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,30 +0,0 @@
|
||||||
<vn-watcher
|
|
||||||
vn-id="watcher"
|
|
||||||
url="claimObservations"
|
|
||||||
id-field="id"
|
|
||||||
data="$ctrl.note"
|
|
||||||
insert-mode="true"
|
|
||||||
form="form">
|
|
||||||
</vn-watcher>
|
|
||||||
<form name="form" ng-submit="watcher.submitGo('claim.card.note.index')" class="vn-w-md">
|
|
||||||
<vn-card class="vn-pa-lg">
|
|
||||||
<vn-horizontal>
|
|
||||||
<vn-textarea
|
|
||||||
vn-one
|
|
||||||
label="Note"
|
|
||||||
ng-model="$ctrl.note.text"
|
|
||||||
vn-focus>
|
|
||||||
</vn-textarea>
|
|
||||||
</vn-horizontal>
|
|
||||||
</vn-card>
|
|
||||||
<vn-button-bar>
|
|
||||||
<vn-submit
|
|
||||||
ng-if="watcher.dataChanged()"
|
|
||||||
label="Save">
|
|
||||||
</vn-submit>
|
|
||||||
<vn-button
|
|
||||||
ng-click="$ctrl.cancel()"
|
|
||||||
label="Cancel">
|
|
||||||
</vn-button>
|
|
||||||
</vn-button-bar>
|
|
||||||
</form>
|
|
|
@ -1,22 +0,0 @@
|
||||||
import ngModule from '../../module';
|
|
||||||
import Section from 'salix/components/section';
|
|
||||||
|
|
||||||
export default class Controller extends Section {
|
|
||||||
constructor($element, $) {
|
|
||||||
super($element, $);
|
|
||||||
this.note = {
|
|
||||||
claimFk: parseInt(this.$params.id),
|
|
||||||
workerFk: window.localStorage.currentUserWorkerId,
|
|
||||||
text: null
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
cancel() {
|
|
||||||
this.$state.go('claim.card.note.index', {id: this.$params.id});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ngModule.vnComponent('vnClaimNoteCreate', {
|
|
||||||
template: require('./index.html'),
|
|
||||||
controller: Controller
|
|
||||||
});
|
|
|
@ -1,32 +0,0 @@
|
||||||
<vn-crud-model
|
|
||||||
vn-id="model"
|
|
||||||
url="ClaimObservations"
|
|
||||||
filter="$ctrl.filter"
|
|
||||||
where="{claimFk: $ctrl.$params.id}"
|
|
||||||
include="$ctrl.include"
|
|
||||||
data="notes"
|
|
||||||
auto-load="true">
|
|
||||||
</vn-crud-model>
|
|
||||||
<vn-data-viewer
|
|
||||||
model="model"
|
|
||||||
class="vn-w-md">
|
|
||||||
<vn-card class="vn-pa-md">
|
|
||||||
<div
|
|
||||||
ng-repeat="note in notes"
|
|
||||||
class="note vn-pa-sm border-solid border-radius vn-mb-md">
|
|
||||||
<vn-horizontal class="vn-mb-sm" style="color: #666">
|
|
||||||
<vn-one>{{::note.worker.firstName}} {{::note.worker.lastName}}</vn-one>
|
|
||||||
<vn-auto>{{::note.created | date:'dd/MM/yyyy HH:mm'}}</vn-auto>
|
|
||||||
</vn-horizontal>
|
|
||||||
<vn-horizontal class="text">
|
|
||||||
{{::note.text}}
|
|
||||||
</vn-horizontal>
|
|
||||||
</div>
|
|
||||||
</vn-card>
|
|
||||||
</vn-data-viewer>
|
|
||||||
<a vn-tooltip="New note"
|
|
||||||
ui-sref="claim.card.note.create({id: $ctrl.$params.id})"
|
|
||||||
vn-bind="+"
|
|
||||||
fixed-bottom-right>
|
|
||||||
<vn-float-button icon="add"></vn-float-button>
|
|
||||||
</a>
|
|
|
@ -1,25 +0,0 @@
|
||||||
import ngModule from '../../module';
|
|
||||||
import Section from 'salix/components/section';
|
|
||||||
import './style.scss';
|
|
||||||
|
|
||||||
export default class Controller extends Section {
|
|
||||||
constructor($element, $) {
|
|
||||||
super($element, $);
|
|
||||||
this.filter = {
|
|
||||||
order: 'created DESC',
|
|
||||||
};
|
|
||||||
this.include = {
|
|
||||||
relation: 'worker',
|
|
||||||
scope: {
|
|
||||||
fields: ['id', 'firstName', 'lastName']
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Controller.$inject = ['$element', '$scope'];
|
|
||||||
|
|
||||||
ngModule.vnComponent('vnClaimNote', {
|
|
||||||
template: require('./index.html'),
|
|
||||||
controller: Controller,
|
|
||||||
});
|
|
|
@ -1,5 +0,0 @@
|
||||||
vn-client-note {
|
|
||||||
.note:last-child {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1 +0,0 @@
|
||||||
|
|
|
@ -1,21 +0,0 @@
|
||||||
import ngModule from '../module';
|
|
||||||
import Section from 'salix/components/section';
|
|
||||||
|
|
||||||
class Controller extends Section {
|
|
||||||
constructor($element, $) {
|
|
||||||
super($element, $);
|
|
||||||
}
|
|
||||||
|
|
||||||
async $onInit() {
|
|
||||||
const url = await this.vnApp.getUrl(`claim/${this.$params.id}/photos`);
|
|
||||||
window.location.href = url;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ngModule.vnComponent('vnClaimPhotos', {
|
|
||||||
template: require('./index.html'),
|
|
||||||
controller: Controller,
|
|
||||||
bindings: {
|
|
||||||
claim: '<'
|
|
||||||
}
|
|
||||||
});
|
|
|
@ -1,84 +0,0 @@
|
||||||
<div class="search-panel">
|
|
||||||
<form ng-submit="$ctrl.onSearch()">
|
|
||||||
<vn-horizontal>
|
|
||||||
<vn-textfield
|
|
||||||
vn-one
|
|
||||||
label="General search"
|
|
||||||
ng-model="filter.search"
|
|
||||||
info="Search claim by id or client name"
|
|
||||||
vn-focus>
|
|
||||||
</vn-textfield>
|
|
||||||
</vn-horizontal>
|
|
||||||
<vn-horizontal>
|
|
||||||
<vn-textfield
|
|
||||||
vn-one
|
|
||||||
label="Client Id"
|
|
||||||
ng-model="filter.clientFk">
|
|
||||||
</vn-textfield>
|
|
||||||
<vn-textfield
|
|
||||||
vn-one
|
|
||||||
label="Client"
|
|
||||||
ng-model="filter.clientName">
|
|
||||||
</vn-textfield>
|
|
||||||
</vn-horizontal>
|
|
||||||
<vn-horizontal>
|
|
||||||
<vn-worker-autocomplete
|
|
||||||
vn-one
|
|
||||||
ng-model="filter.salesPersonFk"
|
|
||||||
departments="['VT']"
|
|
||||||
label="Salesperson">
|
|
||||||
</vn-worker-autocomplete>
|
|
||||||
<vn-worker-autocomplete
|
|
||||||
vn-one
|
|
||||||
ng-model="filter.attenderFk"
|
|
||||||
departments="['VT']"
|
|
||||||
label="Attended by">
|
|
||||||
</vn-worker-autocomplete>
|
|
||||||
</vn-horizontal>
|
|
||||||
<vn-horizontal>
|
|
||||||
<vn-autocomplete vn-one
|
|
||||||
label="State"
|
|
||||||
ng-model="filter.claimStateFk"
|
|
||||||
url="ClaimStates"
|
|
||||||
show-field="description"
|
|
||||||
value-field="id">
|
|
||||||
<tpl-item>{{description}}</tpl-item>
|
|
||||||
</vn-autocomplete>
|
|
||||||
<vn-date-picker
|
|
||||||
vn-one
|
|
||||||
label="Created"
|
|
||||||
ng-model="filter.created">
|
|
||||||
</vn-date-picker>
|
|
||||||
</vn-horizontal>
|
|
||||||
<vn-horizontal>
|
|
||||||
<vn-autocomplete vn-one class="dense"
|
|
||||||
label="Item"
|
|
||||||
url="Items/withName"
|
|
||||||
ng-model="filter.itemFk"
|
|
||||||
show-field="name"
|
|
||||||
value-field="id"
|
|
||||||
search-function="$ctrl.itemSearchFunc($search)"
|
|
||||||
order="id DESC">
|
|
||||||
<tpl-item>{{::id}} - {{::name}}</tpl-item>
|
|
||||||
</vn-autocomplete>
|
|
||||||
<vn-autocomplete
|
|
||||||
vn-one
|
|
||||||
ng-model="filter.claimResponsibleFk"
|
|
||||||
url="ClaimResponsibles"
|
|
||||||
show-field="description"
|
|
||||||
value-field="id"
|
|
||||||
label="Responsible">
|
|
||||||
</vn-autocomplete>
|
|
||||||
</vn-horizontal>
|
|
||||||
<vn-horizontal>
|
|
||||||
<vn-check
|
|
||||||
vn-one
|
|
||||||
label="My team"
|
|
||||||
ng-model="filter.myTeam"
|
|
||||||
triple-state="true">
|
|
||||||
</vn-horizontal>
|
|
||||||
<vn-horizontal class="vn-mt-lg">
|
|
||||||
<vn-submit label="Search"></vn-submit>
|
|
||||||
</vn-horizontal>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
|
@ -1,14 +0,0 @@
|
||||||
import ngModule from '../module';
|
|
||||||
import SearchPanel from 'core/components/searchbar/search-panel';
|
|
||||||
|
|
||||||
class Controller extends SearchPanel {
|
|
||||||
itemSearchFunc($search) {
|
|
||||||
return /^\d+$/.test($search)
|
|
||||||
? {id: $search}
|
|
||||||
: {name: {like: '%' + $search + '%'}};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ngModule.vnComponent('vnClaimSearchPanel', {
|
|
||||||
template: require('./index.html'),
|
|
||||||
controller: Controller
|
|
||||||
});
|
|
|
@ -1,7 +0,0 @@
|
||||||
Ticket id: Id ticket
|
|
||||||
Client id: Id cliente
|
|
||||||
Nickname: Alias
|
|
||||||
From: Desde
|
|
||||||
To: Hasta
|
|
||||||
Agency: Agencia
|
|
||||||
Warehouse: Almacén
|
|
|
@ -1,273 +0,0 @@
|
||||||
<vn-crud-model
|
|
||||||
vn-id="model"
|
|
||||||
url="ClaimDms"
|
|
||||||
filter="::$ctrl.filter"
|
|
||||||
data="photos">
|
|
||||||
</vn-crud-model>
|
|
||||||
<vn-card class="summary">
|
|
||||||
<h5>
|
|
||||||
<a
|
|
||||||
ng-if="::$ctrl.summary.claim.id"
|
|
||||||
vn-tooltip="Go to the claim"
|
|
||||||
ui-sref="claim.card.summary({id: {{::$ctrl.summary.claim.id}}})"
|
|
||||||
name="goToSummary">
|
|
||||||
<vn-icon-button icon="launch"></vn-icon-button>
|
|
||||||
</a>
|
|
||||||
<span>{{::$ctrl.summary.claim.id}} - {{::$ctrl.summary.claim.client.name}}</span>
|
|
||||||
<vn-button-menu
|
|
||||||
disabled="!$ctrl.summary.isEditable"
|
|
||||||
class="message"
|
|
||||||
label="Change state"
|
|
||||||
value-field="id"
|
|
||||||
show-field="description"
|
|
||||||
url="claimStates"
|
|
||||||
on-change="$ctrl.changeState(value)">
|
|
||||||
</vn-button-menu>
|
|
||||||
</h5>
|
|
||||||
<vn-horizontal>
|
|
||||||
<vn-auto>
|
|
||||||
<h4>
|
|
||||||
<a
|
|
||||||
ui-sref="claim.card.basicData({id:$ctrl.claim.id})"
|
|
||||||
target="_self">
|
|
||||||
<span translate vn-tooltip="Go to">Basic data</span>
|
|
||||||
</a>
|
|
||||||
</h4>
|
|
||||||
<vn-label-value
|
|
||||||
label="Created"
|
|
||||||
value="{{$ctrl.summary.claim.created | date: 'dd/MM/yyyy'}}">
|
|
||||||
</vn-label-value>
|
|
||||||
<vn-label-value
|
|
||||||
label="State"
|
|
||||||
value="{{$ctrl.summary.claim.claimState.description}}">
|
|
||||||
</vn-label-value>
|
|
||||||
<vn-label-value
|
|
||||||
label="Salesperson"
|
|
||||||
value="{{$ctrl.summary.claim.client.salesPersonUser.name}}">
|
|
||||||
</vn-label-value>
|
|
||||||
<vn-label-value
|
|
||||||
label="Attended by"
|
|
||||||
value="{{$ctrl.summary.claim.worker.user.nickname}}">
|
|
||||||
</vn-label-value>
|
|
||||||
</vn-auto>
|
|
||||||
<vn-auto>
|
|
||||||
<h4 ng-show="$ctrl.isSalesPerson && $ctrl.summary.observations.length">
|
|
||||||
<a
|
|
||||||
ui-sref="claim.card.note.index({id:$ctrl.claim.id})"
|
|
||||||
target="_self">
|
|
||||||
<span translate vn-tooltip="Go to">Observations</span>
|
|
||||||
</a>
|
|
||||||
</h4>
|
|
||||||
<h4
|
|
||||||
ng-show="!$ctrl.isSalesPerson && $ctrl.summary.observations.length"
|
|
||||||
translate>
|
|
||||||
Observations
|
|
||||||
</h4>
|
|
||||||
<div
|
|
||||||
ng-repeat="note in $ctrl.summary.observations"
|
|
||||||
class="note vn-pa-sm border-solid border-radius vn-mb-md">
|
|
||||||
<vn-horizontal class="vn-mb-sm" style="color: #666">
|
|
||||||
<vn-one>{{::note.worker.firstName}} {{::note.worker.lastName}}</vn-one>
|
|
||||||
<vn-auto>{{::note.created | date:'dd/MM/yyyy HH:mm'}}</vn-auto>
|
|
||||||
</vn-horizontal>
|
|
||||||
<vn-horizontal class="text">
|
|
||||||
{{::note.text}}
|
|
||||||
</vn-horizontal>
|
|
||||||
</div>
|
|
||||||
</vn-auto>
|
|
||||||
<vn-auto>
|
|
||||||
<h4 ng-show="$ctrl.isSalesPerson">
|
|
||||||
<a
|
|
||||||
ui-sref="claim.card.detail({id:$ctrl.claim.id})"
|
|
||||||
target="_self">
|
|
||||||
<span translate vn-tooltip="Go to">Detail</span>
|
|
||||||
</a>
|
|
||||||
</h4>
|
|
||||||
<h4
|
|
||||||
ng-show="!$ctrl.isSalesPerson"
|
|
||||||
translate>
|
|
||||||
Detail
|
|
||||||
</h4>
|
|
||||||
<vn-data-viewer data="::$ctrl.summary.salesClaimed">
|
|
||||||
<vn-table>
|
|
||||||
<vn-thead>
|
|
||||||
<vn-tr>
|
|
||||||
<vn-th number>Item</vn-th>
|
|
||||||
<vn-th expand>Landed</vn-th>
|
|
||||||
<vn-th number>Quantity</vn-th>
|
|
||||||
<vn-th number>Claimed</vn-th>
|
|
||||||
<vn-th>Description</vn-th>
|
|
||||||
<vn-th number>Price</vn-th>
|
|
||||||
<vn-th number>Disc.</vn-th>
|
|
||||||
<vn-th number>Total</vn-th>
|
|
||||||
</vn-tr>
|
|
||||||
</vn-thead>
|
|
||||||
<vn-tbody>
|
|
||||||
<vn-tr ng-repeat="saleClaimed in $ctrl.summary.salesClaimed">
|
|
||||||
<vn-td number>
|
|
||||||
<span
|
|
||||||
ng-click="itemDescriptor.show($event, saleClaimed.sale.itemFk, saleClaimed.sale.id)"
|
|
||||||
class="link">
|
|
||||||
{{::saleClaimed.sale.itemFk}}
|
|
||||||
</span>
|
|
||||||
</vn-td>
|
|
||||||
<vn-td expand>{{::saleClaimed.sale.ticket.landed | date: 'dd/MM/yyyy'}}</vn-td>
|
|
||||||
<vn-td number>{{::saleClaimed.sale.quantity}}</vn-td>
|
|
||||||
<vn-td number>{{::saleClaimed.quantity}}</vn-td>
|
|
||||||
<vn-td expand>{{::saleClaimed.sale.concept}}</vn-td>
|
|
||||||
<vn-td number>{{::saleClaimed.sale.price | currency: 'EUR':2}}</vn-td>
|
|
||||||
<vn-td number>{{::saleClaimed.sale.discount}} %</vn-td>
|
|
||||||
<vn-td number>
|
|
||||||
{{saleClaimed.sale.quantity * saleClaimed.sale.price *
|
|
||||||
((100 - saleClaimed.sale.discount) / 100) | currency: 'EUR':2}}
|
|
||||||
</vn-td>
|
|
||||||
</vn-tr>
|
|
||||||
</vn-tbody>
|
|
||||||
</vn-table>
|
|
||||||
</vn-data-viewer>
|
|
||||||
</vn-auto>
|
|
||||||
<vn-auto ng-if="photos.length > 0">
|
|
||||||
<h4 translate>Photos</h4>
|
|
||||||
<vn-horizontal class="photo-list">
|
|
||||||
<section class="photo" ng-repeat="photo in photos">
|
|
||||||
<section class="image" on-error-src
|
|
||||||
ng-style="{'background': 'url(' + $ctrl.getImagePath(photo.dmsFk) + ')'}"
|
|
||||||
zoom-image="{{$ctrl.getImagePath(photo.dmsFk)}}"
|
|
||||||
ng-if="photo.dms.contentType != 'video/mp4'">
|
|
||||||
</section>
|
|
||||||
<video id="videobcg" muted="muted" controls ng-if="photo.dms.contentType == 'video/mp4'"
|
|
||||||
class="video">
|
|
||||||
<source src="{{$ctrl.getImagePath(photo.dmsFk)}}" type="video/mp4">
|
|
||||||
</video>
|
|
||||||
</section>
|
|
||||||
</vn-horizontal>
|
|
||||||
</vn-auto>
|
|
||||||
<vn-auto>
|
|
||||||
<h4 ng-show="$ctrl.isClaimManager">
|
|
||||||
<a
|
|
||||||
ui-sref="claim.card.development({id:$ctrl.claim.id})"
|
|
||||||
target="_self">
|
|
||||||
<span translate vn-tooltip="Go to">Development</span>
|
|
||||||
</a>
|
|
||||||
</h4>
|
|
||||||
<h4
|
|
||||||
translate
|
|
||||||
ng-show="!$ctrl.isClaimManager">
|
|
||||||
Development
|
|
||||||
</h4>
|
|
||||||
<vn-data-viewer data="::$ctrl.summary.developments">
|
|
||||||
<vn-table>
|
|
||||||
<vn-thead>
|
|
||||||
<vn-tr>
|
|
||||||
<vn-th>Reason</vn-th>
|
|
||||||
<vn-th>Result</vn-th>
|
|
||||||
<vn-th>Responsible</vn-th>
|
|
||||||
<vn-th>Worker</vn-th>
|
|
||||||
<vn-th>Redelivery</vn-th>
|
|
||||||
</vn-tr>
|
|
||||||
</vn-thead>
|
|
||||||
<vn-tbody>
|
|
||||||
<vn-tr ng-repeat="development in $ctrl.summary.developments">
|
|
||||||
<vn-td>{{::development.claimReason.description}}</vn-td>
|
|
||||||
<vn-td>{{::development.claimResult.description}}</vn-td>
|
|
||||||
<vn-td>{{::development.claimResponsible.description}}</vn-td>
|
|
||||||
<vn-td expand>
|
|
||||||
<span
|
|
||||||
class="link"
|
|
||||||
ng-click="workerDescriptor.show($event, development.workerFk)">
|
|
||||||
{{::development.worker.user.nickname}}
|
|
||||||
</span>
|
|
||||||
</vn-td>
|
|
||||||
<vn-td>{{::development.claimRedelivery.description}}</vn-td>
|
|
||||||
</vn-tr>
|
|
||||||
</vn-tbody>
|
|
||||||
</vn-table>
|
|
||||||
</vn-data-viewer>
|
|
||||||
</vn-auto>
|
|
||||||
<vn-auto>
|
|
||||||
<h4 ng-show="$ctrl.isClaimManager">
|
|
||||||
<a
|
|
||||||
ui-sref="claim.card.action({id:$ctrl.claim.id})"
|
|
||||||
target="_self">
|
|
||||||
<span translate vn-tooltip="Go to">Action</span>
|
|
||||||
</a>
|
|
||||||
</h4>
|
|
||||||
<h4
|
|
||||||
translate
|
|
||||||
ng-show="!$ctrl.isClaimManager">
|
|
||||||
Action
|
|
||||||
</h4>
|
|
||||||
<vn-horizontal>
|
|
||||||
<vn-one>
|
|
||||||
<vn-range
|
|
||||||
vn-one
|
|
||||||
disabled="true"
|
|
||||||
label="Responsability"
|
|
||||||
min-label="Company"
|
|
||||||
max-label="Sales/Client"
|
|
||||||
ng-model="$ctrl.summary.claim.responsibility"
|
|
||||||
max="5"
|
|
||||||
min="1"
|
|
||||||
step="1"
|
|
||||||
vn-acl="claimManager">
|
|
||||||
</vn-range>
|
|
||||||
</vn-one>
|
|
||||||
</vn-horizontal>
|
|
||||||
<vn-data-viewer data="::$ctrl.summary.actions">
|
|
||||||
<vn-table>
|
|
||||||
<vn-thead>
|
|
||||||
<vn-tr>
|
|
||||||
<vn-th number>Item</vn-th>
|
|
||||||
<vn-th number>Ticket</vn-th>
|
|
||||||
<vn-th>Destination</vn-th>
|
|
||||||
<vn-th number>Landed</vn-th>
|
|
||||||
<vn-th number>Quantity</vn-th>
|
|
||||||
<vn-th>Description</vn-th>
|
|
||||||
<vn-th number>Price</vn-th>
|
|
||||||
<vn-th number>Disc.</vn-th>
|
|
||||||
<vn-th number>Total</vn-th>
|
|
||||||
</vn-tr>
|
|
||||||
</vn-thead>
|
|
||||||
<vn-tbody>
|
|
||||||
<vn-tr ng-repeat="action in $ctrl.summary.actions">
|
|
||||||
<vn-td number>
|
|
||||||
<span
|
|
||||||
ng-click="itemDescriptor.show($event, action.sale.itemFk, action.sale.id)"
|
|
||||||
class="link">
|
|
||||||
{{::action.sale.itemFk}}
|
|
||||||
</span>
|
|
||||||
</vn-td>
|
|
||||||
<vn-td number>
|
|
||||||
<span
|
|
||||||
ng-click="ticketDescriptor.show($event, action.sale.ticket.id)"
|
|
||||||
class="link">
|
|
||||||
{{::action.sale.ticket.id}}
|
|
||||||
</span>
|
|
||||||
</vn-td>
|
|
||||||
<vn-td expand>{{::action.claimBeggining.description}}</vn-td>
|
|
||||||
<vn-td number>{{::action.sale.ticket.landed | date: 'dd/MM/yyyy'}}</vn-td>
|
|
||||||
<vn-td number>{{::action.sale.quantity}}</vn-td>
|
|
||||||
<vn-td expand>{{::action.sale.concept}}</vn-td>
|
|
||||||
<vn-td number>{{::action.sale.price}}</vn-td>
|
|
||||||
<vn-td number>{{::action.sale.discount}} %</vn-td>
|
|
||||||
<vn-td number>
|
|
||||||
{{action.sale.quantity * action.sale.price *
|
|
||||||
((100 - action.sale.discount) / 100) | currency: 'EUR':2}}
|
|
||||||
</vn-td>
|
|
||||||
</vn-tr>
|
|
||||||
</vn-tbody>
|
|
||||||
</vn-table>
|
|
||||||
</vn-data-viewer>
|
|
||||||
</vn-auto>
|
|
||||||
</vn-horizontal>
|
|
||||||
</vn-card>
|
|
||||||
<vn-item-descriptor-popover
|
|
||||||
vn-id="item-descriptor"
|
|
||||||
warehouse-fk="$ctrl.vnConfig.warehouseFk">
|
|
||||||
</vn-item-descriptor-popover>
|
|
||||||
<vn-worker-descriptor-popover
|
|
||||||
vn-id="worker-descriptor">
|
|
||||||
</vn-worker-descriptor-popover>
|
|
||||||
<vn-ticket-descriptor-popover
|
|
||||||
vn-id="ticket-descriptor">
|
|
||||||
</vn-ticket-descriptor-popover>
|
|
|
@ -1,103 +0,0 @@
|
||||||
import ngModule from '../module';
|
|
||||||
import Summary from 'salix/components/summary';
|
|
||||||
import './style.scss';
|
|
||||||
|
|
||||||
class Controller extends Summary {
|
|
||||||
constructor($element, $, vnFile) {
|
|
||||||
super($element, $);
|
|
||||||
this.vnFile = vnFile;
|
|
||||||
this.filter = {
|
|
||||||
include: [
|
|
||||||
{
|
|
||||||
relation: 'dms'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
$onChanges() {
|
|
||||||
if (this.claim && this.claim.id)
|
|
||||||
this.loadData();
|
|
||||||
}
|
|
||||||
|
|
||||||
loadData() {
|
|
||||||
return this.$http.get(`Claims/${this.claim.id}/getSummary`).then(res => {
|
|
||||||
if (res && res.data)
|
|
||||||
this.summary = res.data;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
reload() {
|
|
||||||
this.loadData()
|
|
||||||
.then(() => {
|
|
||||||
if (this.card)
|
|
||||||
this.card.reload();
|
|
||||||
|
|
||||||
if (this.parentReload)
|
|
||||||
this.parentReload();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
get isSalesPerson() {
|
|
||||||
return this.aclService.hasAny(['salesPerson']);
|
|
||||||
}
|
|
||||||
|
|
||||||
get isClaimManager() {
|
|
||||||
return this.aclService.hasAny(['claimManager']);
|
|
||||||
}
|
|
||||||
|
|
||||||
get claim() {
|
|
||||||
return this._claim;
|
|
||||||
}
|
|
||||||
|
|
||||||
set claim(value) {
|
|
||||||
this._claim = value;
|
|
||||||
|
|
||||||
// Get DMS on summary load
|
|
||||||
if (value) {
|
|
||||||
this.$.$applyAsync(() => this.loadDms());
|
|
||||||
this.loadData();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
loadDms() {
|
|
||||||
this.$.model.where = {
|
|
||||||
claimFk: this.claim.id
|
|
||||||
};
|
|
||||||
this.$.model.refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
getImagePath(dmsId) {
|
|
||||||
return this.vnFile.getPath(`/api/dms/${dmsId}/downloadFile`);
|
|
||||||
}
|
|
||||||
|
|
||||||
changeState(value) {
|
|
||||||
const params = {
|
|
||||||
id: this.claim.id,
|
|
||||||
claimStateFk: value
|
|
||||||
};
|
|
||||||
|
|
||||||
this.$http.patch(`Claims/updateClaim/${this.claim.id}`, params)
|
|
||||||
.then(() => {
|
|
||||||
this.reload();
|
|
||||||
})
|
|
||||||
.then(() => {
|
|
||||||
this.vnApp.showSuccess(this.$t('Data saved!'));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Controller.$inject = ['$element', '$scope', 'vnFile'];
|
|
||||||
|
|
||||||
ngModule.vnComponent('vnClaimSummary', {
|
|
||||||
template: require('./index.html'),
|
|
||||||
controller: Controller,
|
|
||||||
bindings: {
|
|
||||||
claim: '<',
|
|
||||||
model: '<?',
|
|
||||||
parentReload: '&'
|
|
||||||
},
|
|
||||||
require: {
|
|
||||||
card: '?^vnClaimCard'
|
|
||||||
}
|
|
||||||
});
|
|
|
@ -1,55 +0,0 @@
|
||||||
import './index.js';
|
|
||||||
import crudModel from 'core/mocks/crud-model';
|
|
||||||
|
|
||||||
describe('Claim', () => {
|
|
||||||
describe('Component summary', () => {
|
|
||||||
let controller;
|
|
||||||
let $httpBackend;
|
|
||||||
let $scope;
|
|
||||||
|
|
||||||
beforeEach(ngModule('claim'));
|
|
||||||
|
|
||||||
beforeEach(inject(($componentController, _$httpBackend_, $rootScope) => {
|
|
||||||
$scope = $rootScope.$new();
|
|
||||||
$httpBackend = _$httpBackend_;
|
|
||||||
const $element = angular.element('<vn-claim-summary></vn-claim-summary>');
|
|
||||||
controller = $componentController('vnClaimSummary', {$element, $scope});
|
|
||||||
controller.claim = {id: 1};
|
|
||||||
controller.$.model = crudModel;
|
|
||||||
}));
|
|
||||||
|
|
||||||
describe('loadData()', () => {
|
|
||||||
it('should perform a query to set summary', () => {
|
|
||||||
$httpBackend.when('GET', `Claims/1/getSummary`).respond(200, 24);
|
|
||||||
controller.loadData();
|
|
||||||
$httpBackend.flush();
|
|
||||||
|
|
||||||
expect(controller.summary).toEqual(24);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('changeState()', () => {
|
|
||||||
it('should make an HTTP post query, then call the showSuccess()', () => {
|
|
||||||
jest.spyOn(controller.vnApp, 'showSuccess').mockReturnThis();
|
|
||||||
|
|
||||||
const expectedParams = {id: 1, claimStateFk: 1};
|
|
||||||
$httpBackend.when('GET', `Claims/1/getSummary`).respond(200, 24);
|
|
||||||
$httpBackend.expect('PATCH', `Claims/updateClaim/1`, expectedParams).respond(200);
|
|
||||||
controller.changeState(1);
|
|
||||||
$httpBackend.flush();
|
|
||||||
|
|
||||||
expect(controller.vnApp.showSuccess).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('$onChanges()', () => {
|
|
||||||
it('should call loadData when $onChanges is called', () => {
|
|
||||||
jest.spyOn(controller, 'loadData');
|
|
||||||
|
|
||||||
controller.$onChanges();
|
|
||||||
|
|
||||||
expect(controller.loadData).toHaveBeenCalledWith();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,28 +0,0 @@
|
||||||
@import "./variables";
|
|
||||||
|
|
||||||
vn-claim-summary {
|
|
||||||
section.photo {
|
|
||||||
height: 248px;
|
|
||||||
}
|
|
||||||
.photo .image {
|
|
||||||
border-radius: 3px;
|
|
||||||
}
|
|
||||||
vn-textarea *{
|
|
||||||
height: 80px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.video {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
object-fit: cover;
|
|
||||||
cursor: pointer;
|
|
||||||
box-shadow: 0 2px 2px 0 rgba(0,0,0,.14),
|
|
||||||
0 3px 1px -2px rgba(0,0,0,.2),
|
|
||||||
0 1px 5px 0 rgba(0,0,0,.12);
|
|
||||||
border: 2px solid transparent;
|
|
||||||
|
|
||||||
}
|
|
||||||
.video:hover {
|
|
||||||
border: 2px solid $color-primary
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -119,6 +119,7 @@ module.exports = Self => {
|
||||||
}
|
}
|
||||||
|
|
||||||
let correctings;
|
let correctings;
|
||||||
|
|
||||||
let correcteds;
|
let correcteds;
|
||||||
if (args.correctedFk) {
|
if (args.correctedFk) {
|
||||||
correctings = await models.InvoiceInCorrection.find({
|
correctings = await models.InvoiceInCorrection.find({
|
||||||
|
@ -154,6 +155,7 @@ module.exports = Self => {
|
||||||
case 'awbCode':
|
case 'awbCode':
|
||||||
return {'sub.code': value};
|
return {'sub.code': value};
|
||||||
case 'correctingFk':
|
case 'correctingFk':
|
||||||
|
if (!correcteds.length && !args.correctingFk) return;
|
||||||
return args.correctingFk
|
return args.correctingFk
|
||||||
? {'ii.id': {inq: correcteds.map(x => x.correctingFk)}}
|
? {'ii.id': {inq: correcteds.map(x => x.correctingFk)}}
|
||||||
: {'ii.id': {nin: correcteds.map(x => x.correctingFk)}};
|
: {'ii.id': {nin: correcteds.map(x => x.correctingFk)}};
|
||||||
|
|
|
@ -59,6 +59,10 @@ module.exports = Self => {
|
||||||
arg: 'showEmpty',
|
arg: 'showEmpty',
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
description: 'Show empty orders'
|
description: 'Show empty orders'
|
||||||
|
}, {
|
||||||
|
arg: 'sourceApp',
|
||||||
|
type: 'string',
|
||||||
|
description: 'Application'
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
returns: {
|
returns: {
|
||||||
|
|
|
@ -81,7 +81,7 @@
|
||||||
</vn-check>
|
</vn-check>
|
||||||
</vn-td>
|
</vn-td>
|
||||||
<vn-td shrink>
|
<vn-td shrink>
|
||||||
<a ui-sref="claim.card.basicData({id: sale.claim.claimFk})">
|
<a ng-click="$ctrl.goToLilium('basic-data', sale.claim.claimFk)">
|
||||||
<vn-icon icon="icon-claims"
|
<vn-icon icon="icon-claims"
|
||||||
ng-show="sale.claim.claimFk"
|
ng-show="sale.claim.claimFk"
|
||||||
vn-tooltip="{{::$ctrl.$t('Claim')}}: {{::sale.claim.claimFk}}">
|
vn-tooltip="{{::$ctrl.$t('Claim')}}: {{::sale.claim.claimFk}}">
|
||||||
|
|
|
@ -214,7 +214,7 @@ class Controller extends Section {
|
||||||
const params = {ticketId: this.ticket.id, sales: sales};
|
const params = {ticketId: this.ticket.id, sales: sales};
|
||||||
this.resetChanges();
|
this.resetChanges();
|
||||||
this.$http.post(`Claims/createFromSales`, params)
|
this.$http.post(`Claims/createFromSales`, params)
|
||||||
.then(res => this.$state.go('claim.card.basicData', {id: res.data.id}));
|
.then(async res => window.location.href = await this.vnApp.getUrl(`claim/${res.data.id}/basic-data`));
|
||||||
}
|
}
|
||||||
|
|
||||||
showTransferPopover(event) {
|
showTransferPopover(event) {
|
||||||
|
@ -558,6 +558,10 @@ class Controller extends Section {
|
||||||
changedModelId: saleId
|
changedModelId: saleId
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async goToLilium(section, id) {
|
||||||
|
window.location.href = await this.vnApp.getUrl(`claim/${id}/${section}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ngModule.vnComponent('vnTicketSale', {
|
ngModule.vnComponent('vnTicketSale', {
|
||||||
|
|
|
@ -295,20 +295,26 @@ describe('Ticket', () => {
|
||||||
describe('onCreateClaimAccepted()', () => {
|
describe('onCreateClaimAccepted()', () => {
|
||||||
it('should perform a query and call window open', () => {
|
it('should perform a query and call window open', () => {
|
||||||
jest.spyOn(controller, 'resetChanges').mockReturnThis();
|
jest.spyOn(controller, 'resetChanges').mockReturnThis();
|
||||||
jest.spyOn(controller.$state, 'go').mockReturnThis();
|
jest.spyOn(controller.vnApp, 'getUrl').mockReturnThis();
|
||||||
|
Object.defineProperty(window, 'location', {
|
||||||
|
value: {
|
||||||
|
href: () => {}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
jest.spyOn(controller.window.location, 'href');
|
||||||
|
|
||||||
const newEmptySale = {quantity: 10};
|
const newEmptySale = {quantity: 10};
|
||||||
controller.sales.push(newEmptySale);
|
controller.sales.push(newEmptySale);
|
||||||
const firstSale = controller.sales[0];
|
const firstSale = controller.sales[0];
|
||||||
|
const claimId = 1;
|
||||||
firstSale.checked = true;
|
firstSale.checked = true;
|
||||||
|
|
||||||
const expectedParams = {ticketId: 1, sales: [firstSale]};
|
const expectedParams = {ticketId: 1, sales: [firstSale]};
|
||||||
$httpBackend.expect('POST', `Claims/createFromSales`, expectedParams).respond(200, {id: 1});
|
$httpBackend.expect('POST', `Claims/createFromSales`, expectedParams).respond(200, {id: claimId});
|
||||||
controller.onCreateClaimAccepted();
|
controller.onCreateClaimAccepted();
|
||||||
$httpBackend.flush();
|
$httpBackend.flush();
|
||||||
|
|
||||||
expect(controller.resetChanges).toHaveBeenCalledWith();
|
expect(controller.resetChanges).toHaveBeenCalledWith();
|
||||||
expect(controller.$state.go).toHaveBeenCalledWith('claim.card.basicData', {id: 1});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -152,13 +152,13 @@
|
||||||
<vn-tbody>
|
<vn-tbody>
|
||||||
<vn-tr ng-repeat="sale in $ctrl.summary.sales track by sale.id">
|
<vn-tr ng-repeat="sale in $ctrl.summary.sales track by sale.id">
|
||||||
<vn-td shrink>
|
<vn-td shrink>
|
||||||
<a ui-sref="claim.card.basicData({id: sale.claim.claimFk})">
|
<a ng-click="$ctrl.goToLilium('basic-data', sale.claim.claimFk)">
|
||||||
<vn-icon icon="icon-claims"
|
<vn-icon icon="icon-claims"
|
||||||
ng-show="sale.claim.claimFk"
|
ng-show="sale.claim.claimFk"
|
||||||
vn-tooltip="{{::$ctrl.$t('Claim')}}: {{::sale.claim.claimFk}}">
|
vn-tooltip="{{::$ctrl.$t('Claim')}}: {{::sale.claim.claimFk}}">
|
||||||
</vn-icon>
|
</vn-icon>
|
||||||
</a>
|
</a>
|
||||||
<a ui-sref="claim.card.basicData({id: sale.claimBeginning.claimFk})">
|
<a ng-click="$ctrl.goToLilium('basic-data', sale.claimBeginning.claimFk)">
|
||||||
<vn-icon
|
<vn-icon
|
||||||
ng-show="sale.claimBeginning.claimFk"
|
ng-show="sale.claimBeginning.claimFk"
|
||||||
icon="icon-claims"
|
icon="icon-claims"
|
||||||
|
|
|
@ -83,6 +83,10 @@ class Controller extends Summary {
|
||||||
return 'Acepted';
|
return 'Acepted';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async goToLilium(section, id) {
|
||||||
|
window.location.href = await this.vnApp.getUrl(`claim/${id}/${section}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ngModule.vnComponent('vnTicketSummary', {
|
ngModule.vnComponent('vnTicketSummary', {
|
||||||
|
|
|
@ -1,93 +0,0 @@
|
||||||
<mg-ajax path="Workers/{{patch.params.id}}" options="vnPatch"></mg-ajax>
|
|
||||||
<vn-watcher
|
|
||||||
vn-id="watcher"
|
|
||||||
data="$ctrl.worker"
|
|
||||||
form="form"
|
|
||||||
save="patch">
|
|
||||||
</vn-watcher>
|
|
||||||
<form name="form" ng-submit="$ctrl.onSubmit()" class="vn-w-md">
|
|
||||||
<vn-card class="vn-pa-lg">
|
|
||||||
<vn-vertical>
|
|
||||||
<vn-horizontal>
|
|
||||||
<vn-textfield
|
|
||||||
vn-one
|
|
||||||
label="Name"
|
|
||||||
ng-model="$ctrl.worker.firstName"
|
|
||||||
rule>
|
|
||||||
</vn-textfield>
|
|
||||||
<vn-textfield
|
|
||||||
vn-one
|
|
||||||
label="Last name"
|
|
||||||
ng-model="$ctrl.worker.lastName"
|
|
||||||
rule>
|
|
||||||
</vn-textfield>
|
|
||||||
</vn-horizontal>
|
|
||||||
<vn-horizontal>
|
|
||||||
<vn-textfield
|
|
||||||
vn-one
|
|
||||||
label="Business phone"
|
|
||||||
ng-model="$ctrl.worker.phone"
|
|
||||||
rule>
|
|
||||||
</vn-textfield>
|
|
||||||
<vn-textfield
|
|
||||||
vn-one
|
|
||||||
label="Mobile extension"
|
|
||||||
ng-model="$ctrl.worker.mobileExtension"
|
|
||||||
rule>
|
|
||||||
</vn-textfield>
|
|
||||||
</vn-horizontal>
|
|
||||||
<vn-horizontal>
|
|
||||||
<vn-worker-autocomplete
|
|
||||||
ng-model="$ctrl.worker.bossFk"
|
|
||||||
show-field="nickname"
|
|
||||||
label="Boss">
|
|
||||||
</vn-worker-autocomplete>
|
|
||||||
<vn-autocomplete
|
|
||||||
label="Marital status"
|
|
||||||
data="$ctrl.maritalStatus"
|
|
||||||
show-field="name"
|
|
||||||
value-field="code"
|
|
||||||
ng-model="$ctrl.worker.maritalStatus">
|
|
||||||
</vn-autocomplete>
|
|
||||||
</vn-horizontal>
|
|
||||||
<vn-horizontal>
|
|
||||||
<vn-autocomplete
|
|
||||||
ng-model="$ctrl.worker.originCountryFk"
|
|
||||||
url="Countries"
|
|
||||||
fields="['id', 'name', 'code']"
|
|
||||||
show-field="name"
|
|
||||||
value-field="id"
|
|
||||||
label="Origin country">
|
|
||||||
</vn-autocomplete>
|
|
||||||
<vn-autocomplete
|
|
||||||
ng-model="$ctrl.worker.educationLevelFk"
|
|
||||||
url="EducationLevels"
|
|
||||||
fields="['id', 'name']"
|
|
||||||
show-field="name"
|
|
||||||
value-field="id"
|
|
||||||
label="Education level">
|
|
||||||
</vn-autocomplete>
|
|
||||||
</vn-horizontal>
|
|
||||||
<vn-horizontal>
|
|
||||||
<vn-textfield
|
|
||||||
vn-one
|
|
||||||
label="SSN"
|
|
||||||
ng-model="$ctrl.worker.SSN"
|
|
||||||
rule>
|
|
||||||
</vn-textfield>
|
|
||||||
</vn-horizontal>
|
|
||||||
</vn-vertical>
|
|
||||||
</vn-card>
|
|
||||||
<vn-button-bar>
|
|
||||||
<vn-submit
|
|
||||||
disabled="!watcher.dataChanged()"
|
|
||||||
label="Save">
|
|
||||||
</vn-submit>
|
|
||||||
<vn-button
|
|
||||||
class="cancel"
|
|
||||||
label="Undo changes"
|
|
||||||
disabled="!watcher.dataChanged()"
|
|
||||||
ng-click="watcher.loadOriginalData()">
|
|
||||||
</vn-button>
|
|
||||||
</vn-button-bar>
|
|
||||||
</form>
|
|
|
@ -1,27 +0,0 @@
|
||||||
import ngModule from '../module';
|
|
||||||
import Section from 'salix/components/section';
|
|
||||||
|
|
||||||
class Controller extends Section {
|
|
||||||
constructor($element, $) {
|
|
||||||
super($element, $);
|
|
||||||
this.maritalStatus = [
|
|
||||||
{code: 'M', name: this.$t('Married')},
|
|
||||||
{code: 'S', name: this.$t('Single')}
|
|
||||||
];
|
|
||||||
}
|
|
||||||
onSubmit() {
|
|
||||||
return this.$.watcher.submit()
|
|
||||||
.then(() => this.card.reload());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ngModule.vnComponent('vnWorkerBasicData', {
|
|
||||||
template: require('./index.html'),
|
|
||||||
controller: Controller,
|
|
||||||
bindings: {
|
|
||||||
worker: '<'
|
|
||||||
},
|
|
||||||
require: {
|
|
||||||
card: '^vnWorkerCard'
|
|
||||||
}
|
|
||||||
});
|
|
|
@ -1,9 +0,0 @@
|
||||||
Marital status: Estado civil
|
|
||||||
Origin country: País origen
|
|
||||||
Education level: Nivel educación
|
|
||||||
SSN: NSS
|
|
||||||
Married: Casado/a
|
|
||||||
Single: Soltero/a
|
|
||||||
Business phone: Teléfono de empresa
|
|
||||||
Mobile extension: Extensión móvil
|
|
||||||
Locker: Taquilla
|
|
|
@ -1,114 +0,0 @@
|
||||||
<vn-crud-model
|
|
||||||
url="AbsenceTypes"
|
|
||||||
data="absenceTypes"
|
|
||||||
auto-load="true">
|
|
||||||
</vn-crud-model>
|
|
||||||
<div ng-if="$ctrl.card.hasWorkCenter">
|
|
||||||
<div class="vn-w-lg">
|
|
||||||
<vn-card class="vn-pa-sm calendars">
|
|
||||||
<vn-icon ng-if="::$ctrl.isSubordinate" icon="info" color-marginal
|
|
||||||
vn-tooltip="To start adding absences, click an absence type from the right menu and then on the day you want to add an absence">
|
|
||||||
</vn-icon>
|
|
||||||
<vn-calendar
|
|
||||||
ng-repeat="month in $ctrl.months"
|
|
||||||
data="$ctrl.events"
|
|
||||||
default-date="month"
|
|
||||||
format-day="$ctrl.formatDay($day, $element)"
|
|
||||||
display-controls="false"
|
|
||||||
hide-contiguous="true"
|
|
||||||
hide-year="true"
|
|
||||||
on-selection="$ctrl.onSelection($event, $days)">
|
|
||||||
</vn-calendar>
|
|
||||||
</vn-card>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
ng-if="!$ctrl.card.hasWorkCenter"
|
|
||||||
class="bg-title"
|
|
||||||
translate>
|
|
||||||
Autonomous worker
|
|
||||||
</div>
|
|
||||||
<vn-side-menu side="right">
|
|
||||||
<div class="vn-pa-md">
|
|
||||||
<div class="totalBox vn-mb-sm" style="text-align: center;">
|
|
||||||
<h6>{{'Contract' | translate}} #{{$ctrl.businessId}}</h6>
|
|
||||||
<div>
|
|
||||||
{{'Used' | translate}} {{$ctrl.contractHolidays.holidaysEnjoyed || 0}}
|
|
||||||
{{'of' | translate}} {{$ctrl.contractHolidays.totalHolidays || 0}} {{'days' | translate}}
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
{{'Spent' | translate}} {{$ctrl.contractHolidays.hoursEnjoyed || 0}}
|
|
||||||
{{'of' | translate}} {{$ctrl.contractHolidays.totalHours || 0}} {{'hours' | translate}}
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
{{'Paid holidays' | translate}} {{$ctrl.contractHolidays.payedHolidays || 0}} {{'days' | translate}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="totalBox" style="text-align: center;">
|
|
||||||
<h6>{{'Year' | translate}} {{$ctrl.year}}</h6>
|
|
||||||
<div>
|
|
||||||
{{'Used' | translate}} {{$ctrl.yearHolidays.holidaysEnjoyed || 0}}
|
|
||||||
{{'of' | translate}} {{$ctrl.yearHolidays.totalHolidays || 0}} {{'days' | translate}}
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
{{'Spent' | translate}} {{$ctrl.yearHolidays.hoursEnjoyed || 0}}
|
|
||||||
{{'of' | translate}} {{$ctrl.yearHolidays.totalHours || 0}} {{'hours' | translate}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="vn-pt-md">
|
|
||||||
<vn-autocomplete label="Year"
|
|
||||||
data="$ctrl.yearFilter"
|
|
||||||
ng-model="$ctrl.year"
|
|
||||||
show-field="year"
|
|
||||||
value-field="year"
|
|
||||||
order="DESC">
|
|
||||||
</vn-autocomplete>
|
|
||||||
<vn-autocomplete label="Contract"
|
|
||||||
url="Workers/{{$ctrl.$params.id}}/contracts"
|
|
||||||
fields="['started', 'ended']"
|
|
||||||
ng-model="$ctrl.businessId"
|
|
||||||
search-function="{businessFk: $search}"
|
|
||||||
show-field="businessFk"
|
|
||||||
value-field="businessFk"
|
|
||||||
order="businessFk DESC"
|
|
||||||
limit="5">
|
|
||||||
<tpl-item>
|
|
||||||
<div>#{{businessFk}}</div>
|
|
||||||
<div class="text-caption text-secondary">
|
|
||||||
{{started | date: 'dd/MM/yyyy'}} - {{ended ? (ended | date: 'dd/MM/yyyy') : 'Indef.'}}
|
|
||||||
</div>
|
|
||||||
</tpl-item>
|
|
||||||
</vn-autocomplete>
|
|
||||||
</div>
|
|
||||||
<div name="absenceTypes" class="input vn-py-md" style="overflow: hidden;">
|
|
||||||
<vn-chip ng-repeat="absenceType in absenceTypes" ng-class="::{'selectable': $ctrl.isSubordinate}" ng-click="$ctrl.pick(absenceType)">
|
|
||||||
<vn-avatar ng-style="{backgroundColor: absenceType.rgb}">
|
|
||||||
<vn-icon class="check" icon="check" ng-if="absenceType.id == $ctrl.absenceType.id"></vn-icon>
|
|
||||||
|
|
||||||
</vn-avatar>
|
|
||||||
{{absenceType.name}}
|
|
||||||
</vn-chip>
|
|
||||||
</div>
|
|
||||||
<div class="vn-py-md">
|
|
||||||
<vn-chip>
|
|
||||||
<vn-avatar class="festive">
|
|
||||||
</vn-avatar>
|
|
||||||
<span translate>Festive</span>
|
|
||||||
</vn-chip>
|
|
||||||
<vn-chip>
|
|
||||||
<vn-avatar class="today">
|
|
||||||
</vn-avatar>
|
|
||||||
<span translate>Current day</span>
|
|
||||||
</vn-chip>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</vn-side-menu>
|
|
||||||
|
|
||||||
<vn-confirm
|
|
||||||
vn-id="confirm"
|
|
||||||
message="This item will be deleted"
|
|
||||||
question="Are you sure you want to continue?">
|
|
||||||
</vn-confirm>
|
|
||||||
|
|
|
@ -1,302 +0,0 @@
|
||||||
import ngModule from '../module';
|
|
||||||
import Section from 'salix/components/section';
|
|
||||||
import './style.scss';
|
|
||||||
|
|
||||||
class Controller extends Section {
|
|
||||||
constructor($element, $) {
|
|
||||||
super($element, $);
|
|
||||||
this.date = Date.vnNew();
|
|
||||||
this.events = {};
|
|
||||||
this.buildYearFilter();
|
|
||||||
}
|
|
||||||
|
|
||||||
get year() {
|
|
||||||
return this.date.getFullYear();
|
|
||||||
}
|
|
||||||
|
|
||||||
set year(value) {
|
|
||||||
const newYear = Date.vnNew();
|
|
||||||
newYear.setFullYear(value);
|
|
||||||
|
|
||||||
this.date = newYear;
|
|
||||||
|
|
||||||
this.refresh()
|
|
||||||
.then(() => this.repaint())
|
|
||||||
.then(() => this.getContractHolidays())
|
|
||||||
.then(() => this.getYearHolidays());
|
|
||||||
}
|
|
||||||
|
|
||||||
get businessId() {
|
|
||||||
return this._businessId;
|
|
||||||
}
|
|
||||||
|
|
||||||
set businessId(value) {
|
|
||||||
if (!this.card.hasWorkCenter) return;
|
|
||||||
|
|
||||||
this._businessId = value;
|
|
||||||
if (value) {
|
|
||||||
this.refresh()
|
|
||||||
.then(() => this.repaint())
|
|
||||||
.then(() => this.getContractHolidays())
|
|
||||||
.then(() => this.getYearHolidays());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
get date() {
|
|
||||||
return this._date;
|
|
||||||
}
|
|
||||||
|
|
||||||
set date(value) {
|
|
||||||
this._date = value;
|
|
||||||
value.setHours(0, 0, 0, 0);
|
|
||||||
|
|
||||||
this.months = new Array(12);
|
|
||||||
|
|
||||||
for (let i = 0; i < this.months.length; i++) {
|
|
||||||
const now = new Date(value.getTime());
|
|
||||||
now.setDate(1);
|
|
||||||
now.setMonth(i);
|
|
||||||
this.months[i] = now;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
get worker() {
|
|
||||||
return this._worker;
|
|
||||||
}
|
|
||||||
|
|
||||||
set worker(value) {
|
|
||||||
this._worker = value;
|
|
||||||
if (value) {
|
|
||||||
this.getIsSubordinate();
|
|
||||||
this.getActiveContract();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
buildYearFilter() {
|
|
||||||
const now = Date.vnNew();
|
|
||||||
now.setFullYear(now.getFullYear() + 1);
|
|
||||||
|
|
||||||
const maxYear = now.getFullYear();
|
|
||||||
const minRange = maxYear - 5;
|
|
||||||
|
|
||||||
const years = [];
|
|
||||||
for (let i = maxYear; i > minRange; i--)
|
|
||||||
years.push({year: i});
|
|
||||||
|
|
||||||
this.yearFilter = years;
|
|
||||||
}
|
|
||||||
|
|
||||||
getIsSubordinate() {
|
|
||||||
this.$http.get(`Workers/${this.worker.id}/isSubordinate`)
|
|
||||||
.then(res => this.isSubordinate = res.data);
|
|
||||||
}
|
|
||||||
|
|
||||||
getActiveContract() {
|
|
||||||
this.$http.get(`Workers/${this.worker.id}/activeContract`)
|
|
||||||
.then(res => {
|
|
||||||
if (res.data) this.businessId = res.data.businessFk;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
getContractHolidays() {
|
|
||||||
this.getHolidays({
|
|
||||||
businessFk: this.businessId,
|
|
||||||
year: this.year
|
|
||||||
}, data => this.contractHolidays = data);
|
|
||||||
}
|
|
||||||
|
|
||||||
getYearHolidays() {
|
|
||||||
this.getHolidays({
|
|
||||||
year: this.year
|
|
||||||
}, data => this.yearHolidays = data);
|
|
||||||
}
|
|
||||||
|
|
||||||
getHolidays(params, cb) {
|
|
||||||
this.$http.get(`Workers/${this.worker.id}/holidays`, {params})
|
|
||||||
.then(res => cb(res.data));
|
|
||||||
}
|
|
||||||
|
|
||||||
onData(data) {
|
|
||||||
this.events = {};
|
|
||||||
this.calendar = data.calendar;
|
|
||||||
|
|
||||||
let addEvent = (day, newEvent) => {
|
|
||||||
const timestamp = new Date(day).getTime();
|
|
||||||
const event = this.events[timestamp];
|
|
||||||
|
|
||||||
if (event) {
|
|
||||||
const oldName = event.name;
|
|
||||||
Object.assign(event, newEvent);
|
|
||||||
event.name = `${oldName}, ${event.name}`;
|
|
||||||
} else
|
|
||||||
this.events[timestamp] = newEvent;
|
|
||||||
};
|
|
||||||
|
|
||||||
if (data.holidays) {
|
|
||||||
data.holidays.forEach(holiday => {
|
|
||||||
const holidayDetail = holiday.detail && holiday.detail.name;
|
|
||||||
const holidayType = holiday.type && holiday.type.name;
|
|
||||||
const holidayName = holidayDetail || holidayType;
|
|
||||||
|
|
||||||
addEvent(holiday.dated, {
|
|
||||||
name: holidayName,
|
|
||||||
className: 'festive'
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (data.absences) {
|
|
||||||
data.absences.forEach(absence => {
|
|
||||||
let type = absence.absenceType;
|
|
||||||
addEvent(absence.dated, {
|
|
||||||
name: type.name,
|
|
||||||
color: type.rgb,
|
|
||||||
type: type.code,
|
|
||||||
absenceId: absence.id
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
repaint() {
|
|
||||||
let calendars = this.element.querySelectorAll('vn-calendar');
|
|
||||||
for (let calendar of calendars)
|
|
||||||
calendar.$ctrl.repaint();
|
|
||||||
}
|
|
||||||
|
|
||||||
formatDay(day, element) {
|
|
||||||
let event = this.events[day.getTime()];
|
|
||||||
if (!event) return;
|
|
||||||
|
|
||||||
let dayNumber = element.firstElementChild;
|
|
||||||
dayNumber.title = event.name;
|
|
||||||
dayNumber.style.backgroundColor = event.color;
|
|
||||||
|
|
||||||
if (event.border)
|
|
||||||
dayNumber.style.border = event.border;
|
|
||||||
|
|
||||||
if (event.className)
|
|
||||||
dayNumber.classList.add(event.className);
|
|
||||||
}
|
|
||||||
|
|
||||||
pick(absenceType) {
|
|
||||||
if (!this.isSubordinate) return;
|
|
||||||
if (absenceType == this.absenceType)
|
|
||||||
absenceType = null;
|
|
||||||
|
|
||||||
this.absenceType = absenceType;
|
|
||||||
}
|
|
||||||
|
|
||||||
onSelection($event, $days) {
|
|
||||||
if (!this.absenceType)
|
|
||||||
return this.vnApp.showMessage(this.$t('Choose an absence type from the right menu'));
|
|
||||||
|
|
||||||
const day = $days[0];
|
|
||||||
const stamp = day.getTime();
|
|
||||||
const event = this.events[stamp];
|
|
||||||
const calendar = $event.target.closest('vn-calendar').$ctrl;
|
|
||||||
|
|
||||||
if (event && event.absenceId) {
|
|
||||||
if (event.type == this.absenceType.code)
|
|
||||||
this.delete(calendar, day, event);
|
|
||||||
else
|
|
||||||
this.edit(calendar, event);
|
|
||||||
} else
|
|
||||||
this.create(calendar, day);
|
|
||||||
}
|
|
||||||
|
|
||||||
create(calendar, dated) {
|
|
||||||
const absenceType = this.absenceType;
|
|
||||||
const params = {
|
|
||||||
dated: dated,
|
|
||||||
absenceTypeId: absenceType.id,
|
|
||||||
businessFk: this.businessId
|
|
||||||
};
|
|
||||||
|
|
||||||
const path = `Workers/${this.$params.id}/createAbsence`;
|
|
||||||
this.$http.post(path, params).then(res => {
|
|
||||||
const newEvent = res.data;
|
|
||||||
this.events[dated.getTime()] = {
|
|
||||||
name: absenceType.name,
|
|
||||||
color: absenceType.rgb,
|
|
||||||
type: absenceType.code,
|
|
||||||
absenceId: newEvent.id
|
|
||||||
};
|
|
||||||
|
|
||||||
this.repaintCanceller(() =>
|
|
||||||
this.refresh()
|
|
||||||
.then(calendar.repaint())
|
|
||||||
.then(() => this.getContractHolidays())
|
|
||||||
.then(() => this.getYearHolidays())
|
|
||||||
.then(() => this.repaint())
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
edit(calendar, event) {
|
|
||||||
const absenceType = this.absenceType;
|
|
||||||
const params = {
|
|
||||||
absenceId: event.absenceId,
|
|
||||||
absenceTypeId: absenceType.id
|
|
||||||
};
|
|
||||||
const path = `Workers/${this.$params.id}/updateAbsence`;
|
|
||||||
this.$http.patch(path, params).then(() => {
|
|
||||||
event.color = absenceType.rgb;
|
|
||||||
event.name = absenceType.name;
|
|
||||||
event.type = absenceType.code;
|
|
||||||
|
|
||||||
this.repaintCanceller(() =>
|
|
||||||
this.refresh()
|
|
||||||
.then(calendar.repaint())
|
|
||||||
.then(() => this.getContractHolidays())
|
|
||||||
.then(() => this.getYearHolidays())
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
delete(calendar, day, event) {
|
|
||||||
const params = {absenceId: event.absenceId};
|
|
||||||
const path = `Workers/${this.$params.id}/deleteAbsence`;
|
|
||||||
this.$http.delete(path, {params}).then(() => {
|
|
||||||
delete this.events[day.getTime()];
|
|
||||||
|
|
||||||
this.repaintCanceller(() =>
|
|
||||||
this.refresh()
|
|
||||||
.then(calendar.repaint())
|
|
||||||
.then(() => this.getContractHolidays())
|
|
||||||
.then(() => this.getYearHolidays())
|
|
||||||
.then(() => this.repaint())
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
repaintCanceller(cb) {
|
|
||||||
if (this.canceller) {
|
|
||||||
clearTimeout(this.canceller);
|
|
||||||
this.canceller = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.canceller = setTimeout(
|
|
||||||
() => cb(), 500);
|
|
||||||
}
|
|
||||||
|
|
||||||
refresh() {
|
|
||||||
const params = {
|
|
||||||
workerFk: this.$params.id,
|
|
||||||
businessFk: this.businessId,
|
|
||||||
year: this.year
|
|
||||||
};
|
|
||||||
return this.$http.get(`Calendars/absences`, {params})
|
|
||||||
.then(res => this.onData(res.data));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ngModule.vnComponent('vnWorkerCalendar', {
|
|
||||||
template: require('./index.html'),
|
|
||||||
controller: Controller,
|
|
||||||
bindings: {
|
|
||||||
worker: '<'
|
|
||||||
},
|
|
||||||
require: {
|
|
||||||
card: '^vnWorkerCard'
|
|
||||||
}
|
|
||||||
});
|
|
|
@ -1,346 +0,0 @@
|
||||||
import './index';
|
|
||||||
|
|
||||||
describe('Worker', () => {
|
|
||||||
describe('Component vnWorkerCalendar', () => {
|
|
||||||
let $httpBackend;
|
|
||||||
let $httpParamSerializer;
|
|
||||||
let $scope;
|
|
||||||
let controller;
|
|
||||||
let year = Date.vnNew().getFullYear();
|
|
||||||
|
|
||||||
beforeEach(ngModule('worker'));
|
|
||||||
|
|
||||||
beforeEach(inject(($componentController, $rootScope, _$httpParamSerializer_, _$httpBackend_) => {
|
|
||||||
$scope = $rootScope.$new();
|
|
||||||
$httpBackend = _$httpBackend_;
|
|
||||||
$httpParamSerializer = _$httpParamSerializer_;
|
|
||||||
const $element = angular.element('<vn-worker-calendar></vn-worker-calendar>');
|
|
||||||
controller = $componentController('vnWorkerCalendar', {$element, $scope});
|
|
||||||
controller.isSubordinate = true;
|
|
||||||
controller.absenceType = {id: 1, name: 'Holiday', code: 'holiday', rgb: 'red'};
|
|
||||||
controller.$params.id = 1106;
|
|
||||||
controller._worker = {id: 1106};
|
|
||||||
controller.card = {
|
|
||||||
hasWorkCenter: true
|
|
||||||
};
|
|
||||||
}));
|
|
||||||
|
|
||||||
describe('year() getter', () => {
|
|
||||||
it(`should return the year number of the calendar date`, () => {
|
|
||||||
expect(controller.year).toEqual(year);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('year() setter', () => {
|
|
||||||
it(`should set the year of the calendar date`, () => {
|
|
||||||
jest.spyOn(controller, 'refresh').mockReturnValue(Promise.resolve());
|
|
||||||
|
|
||||||
const previousYear = year - 1;
|
|
||||||
controller.year = previousYear;
|
|
||||||
|
|
||||||
expect(controller.year).toEqual(previousYear);
|
|
||||||
expect(controller.date.getFullYear()).toEqual(previousYear);
|
|
||||||
expect(controller.refresh).toHaveBeenCalledWith();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('businessId() setter', () => {
|
|
||||||
it(`should set the contract id and then call to the refresh method`, () => {
|
|
||||||
jest.spyOn(controller, 'refresh').mockReturnValue(Promise.resolve());
|
|
||||||
|
|
||||||
controller.businessId = 1106;
|
|
||||||
|
|
||||||
expect(controller.refresh).toHaveBeenCalledWith();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('months property', () => {
|
|
||||||
it(`should return an array of twelve months length`, () => {
|
|
||||||
const started = new Date(year, 0, 1);
|
|
||||||
const ended = new Date(year, 11, 1);
|
|
||||||
|
|
||||||
expect(controller.months.length).toEqual(12);
|
|
||||||
expect(controller.months[0]).toEqual(started);
|
|
||||||
expect(controller.months[11]).toEqual(ended);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('worker() setter', () => {
|
|
||||||
it(`should perform a get query and set the reponse data on the model`, () => {
|
|
||||||
controller.getIsSubordinate = jest.fn();
|
|
||||||
controller.getActiveContract = jest.fn();
|
|
||||||
|
|
||||||
let today = Date.vnNew();
|
|
||||||
let tomorrow = new Date(today.getTime());
|
|
||||||
tomorrow.setDate(tomorrow.getDate() + 1);
|
|
||||||
|
|
||||||
let yesterday = new Date(today.getTime());
|
|
||||||
yesterday.setDate(yesterday.getDate() - 1);
|
|
||||||
|
|
||||||
controller.worker = {id: 1107};
|
|
||||||
|
|
||||||
expect(controller.getIsSubordinate).toHaveBeenCalledWith();
|
|
||||||
expect(controller.getActiveContract).toHaveBeenCalledWith();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('getIsSubordinate()', () => {
|
|
||||||
it(`should return whether the worker is a subordinate`, () => {
|
|
||||||
$httpBackend.expect('GET', `Workers/1106/isSubordinate`).respond(true);
|
|
||||||
controller.getIsSubordinate();
|
|
||||||
$httpBackend.flush();
|
|
||||||
|
|
||||||
expect(controller.isSubordinate).toBe(true);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('getActiveContract()', () => {
|
|
||||||
it(`should return the current contract and then set the businessId property`, () => {
|
|
||||||
jest.spyOn(controller, 'refresh').mockReturnValue(Promise.resolve());
|
|
||||||
|
|
||||||
$httpBackend.expect('GET', `Workers/1106/activeContract`).respond({businessFk: 1106});
|
|
||||||
controller.getActiveContract();
|
|
||||||
$httpBackend.flush();
|
|
||||||
|
|
||||||
expect(controller.businessId).toEqual(1106);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('getContractHolidays()', () => {
|
|
||||||
it(`should return the worker holidays amount and then set the contractHolidays property`, () => {
|
|
||||||
const today = Date.vnNew();
|
|
||||||
const year = today.getFullYear();
|
|
||||||
|
|
||||||
const serializedParams = $httpParamSerializer({year});
|
|
||||||
$httpBackend.expect('GET', `Workers/1106/holidays?${serializedParams}`).respond({totalHolidays: 28});
|
|
||||||
controller.getContractHolidays();
|
|
||||||
$httpBackend.flush();
|
|
||||||
|
|
||||||
expect(controller.contractHolidays).toEqual({totalHolidays: 28});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('formatDay()', () => {
|
|
||||||
it(`should set the day element style`, () => {
|
|
||||||
const today = Date.vnNew();
|
|
||||||
|
|
||||||
controller.events[today.getTime()] = {
|
|
||||||
name: 'Holiday',
|
|
||||||
color: '#000'
|
|
||||||
};
|
|
||||||
|
|
||||||
const dayElement = angular.element('<div><section></section></div>')[0];
|
|
||||||
const dayNumber = dayElement.firstElementChild;
|
|
||||||
|
|
||||||
controller.formatDay(today, dayElement);
|
|
||||||
|
|
||||||
expect(dayNumber.title).toEqual('Holiday');
|
|
||||||
expect(dayNumber.style.backgroundColor).toEqual('rgb(0, 0, 0)');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('pick()', () => {
|
|
||||||
it(`should set the absenceType property to null if they match with the current one`, () => {
|
|
||||||
const absenceType = {id: 1, name: 'Holiday'};
|
|
||||||
controller.absenceType = absenceType;
|
|
||||||
controller.pick(absenceType);
|
|
||||||
|
|
||||||
expect(controller.absenceType).toBeNull();
|
|
||||||
});
|
|
||||||
|
|
||||||
it(`should set the absenceType property`, () => {
|
|
||||||
const absenceType = {id: 1, name: 'Holiday'};
|
|
||||||
const expectedAbsence = {id: 2, name: 'Leave of absence'};
|
|
||||||
controller.absenceType = absenceType;
|
|
||||||
controller.pick(expectedAbsence);
|
|
||||||
|
|
||||||
expect(controller.absenceType).toEqual(expectedAbsence);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('onSelection()', () => {
|
|
||||||
it(`should show an snackbar message if no absence type is selected`, () => {
|
|
||||||
jest.spyOn(controller.vnApp, 'showMessage').mockReturnThis();
|
|
||||||
|
|
||||||
const $event = {};
|
|
||||||
const $days = [];
|
|
||||||
controller.absenceType = null;
|
|
||||||
controller.onSelection($event, $days);
|
|
||||||
|
|
||||||
expect(controller.vnApp.showMessage).toHaveBeenCalledWith('Choose an absence type from the right menu');
|
|
||||||
});
|
|
||||||
|
|
||||||
it(`should call to the create() method`, () => {
|
|
||||||
jest.spyOn(controller, 'create').mockReturnThis();
|
|
||||||
|
|
||||||
const selectedDay = Date.vnNew();
|
|
||||||
const $event = {
|
|
||||||
target: {
|
|
||||||
closest: () => {
|
|
||||||
return {$ctrl: {}};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const $days = [selectedDay];
|
|
||||||
controller.absenceType = {id: 1};
|
|
||||||
controller.onSelection($event, $days);
|
|
||||||
|
|
||||||
expect(controller.create).toHaveBeenCalledWith(jasmine.any(Object), selectedDay);
|
|
||||||
});
|
|
||||||
|
|
||||||
it(`should call to the delete() method`, () => {
|
|
||||||
jest.spyOn(controller, 'delete').mockReturnThis();
|
|
||||||
|
|
||||||
const selectedDay = Date.vnNew();
|
|
||||||
const expectedEvent = {
|
|
||||||
dated: selectedDay,
|
|
||||||
type: 'holiday',
|
|
||||||
absenceId: 1
|
|
||||||
};
|
|
||||||
const $event = {
|
|
||||||
target: {
|
|
||||||
closest: () => {
|
|
||||||
return {$ctrl: {}};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const $days = [selectedDay];
|
|
||||||
controller.events[selectedDay.getTime()] = expectedEvent;
|
|
||||||
controller.absenceType = {id: 1, code: 'holiday'};
|
|
||||||
controller.onSelection($event, $days);
|
|
||||||
|
|
||||||
expect(controller.delete).toHaveBeenCalledWith(jasmine.any(Object), selectedDay, expectedEvent);
|
|
||||||
});
|
|
||||||
|
|
||||||
it(`should call to the edit() method`, () => {
|
|
||||||
jest.spyOn(controller, 'edit').mockReturnThis();
|
|
||||||
|
|
||||||
const selectedDay = Date.vnNew();
|
|
||||||
const expectedEvent = {
|
|
||||||
dated: selectedDay,
|
|
||||||
type: 'leaveOfAbsence',
|
|
||||||
absenceId: 1
|
|
||||||
};
|
|
||||||
const $event = {
|
|
||||||
target: {
|
|
||||||
closest: () => {
|
|
||||||
return {$ctrl: {}};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const $days = [selectedDay];
|
|
||||||
controller.events[selectedDay.getTime()] = expectedEvent;
|
|
||||||
controller.absenceType = {id: 1, code: 'holiday'};
|
|
||||||
controller.onSelection($event, $days);
|
|
||||||
|
|
||||||
expect(controller.edit).toHaveBeenCalledWith(jasmine.any(Object), expectedEvent);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('create()', () => {
|
|
||||||
it(`should make a HTTP POST query and then call to the repaintCanceller() method`, () => {
|
|
||||||
jest.spyOn(controller, 'repaintCanceller').mockReturnThis();
|
|
||||||
|
|
||||||
const dated = Date.vnNew();
|
|
||||||
const calendarElement = {};
|
|
||||||
const expectedResponse = {id: 10};
|
|
||||||
|
|
||||||
$httpBackend.expect('POST', `Workers/1106/createAbsence`).respond(200, expectedResponse);
|
|
||||||
controller.create(calendarElement, dated);
|
|
||||||
$httpBackend.flush();
|
|
||||||
|
|
||||||
const createdEvent = controller.events[dated.getTime()];
|
|
||||||
const absenceType = controller.absenceType;
|
|
||||||
|
|
||||||
expect(createdEvent.absenceId).toEqual(expectedResponse.id);
|
|
||||||
expect(createdEvent.color).toEqual(absenceType.rgb);
|
|
||||||
expect(controller.repaintCanceller).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('edit()', () => {
|
|
||||||
it(`should make a HTTP PATCH query and then call to the repaintCanceller() method`, () => {
|
|
||||||
jest.spyOn(controller, 'repaintCanceller').mockReturnThis();
|
|
||||||
|
|
||||||
const event = {absenceId: 10};
|
|
||||||
const calendarElement = {};
|
|
||||||
const newAbsenceType = {
|
|
||||||
id: 2,
|
|
||||||
name: 'Leave of absence',
|
|
||||||
code: 'leaveOfAbsence',
|
|
||||||
rgb: 'purple'
|
|
||||||
};
|
|
||||||
controller.absenceType = newAbsenceType;
|
|
||||||
|
|
||||||
const expectedParams = {absenceId: 10, absenceTypeId: 2};
|
|
||||||
$httpBackend.expect('PATCH', `Workers/1106/updateAbsence`, expectedParams).respond(200);
|
|
||||||
controller.edit(calendarElement, event);
|
|
||||||
$httpBackend.flush();
|
|
||||||
|
|
||||||
expect(event.name).toEqual(newAbsenceType.name);
|
|
||||||
expect(event.color).toEqual(newAbsenceType.rgb);
|
|
||||||
expect(event.type).toEqual(newAbsenceType.code);
|
|
||||||
expect(controller.repaintCanceller).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('delete()', () => {
|
|
||||||
it(`should make a HTTP DELETE query and then call to the repaintCanceller() method`, () => {
|
|
||||||
jest.spyOn(controller, 'repaintCanceller').mockReturnThis();
|
|
||||||
|
|
||||||
const expectedParams = {absenceId: 10};
|
|
||||||
const calendarElement = {};
|
|
||||||
const selectedDay = Date.vnNew();
|
|
||||||
const expectedEvent = {
|
|
||||||
dated: selectedDay,
|
|
||||||
type: 'leaveOfAbsence',
|
|
||||||
absenceId: 10
|
|
||||||
};
|
|
||||||
|
|
||||||
controller.events[selectedDay.getTime()] = expectedEvent;
|
|
||||||
|
|
||||||
const serializedParams = $httpParamSerializer(expectedParams);
|
|
||||||
$httpBackend.expect('DELETE', `Workers/1106/deleteAbsence?${serializedParams}`).respond(200);
|
|
||||||
controller.delete(calendarElement, selectedDay, expectedEvent);
|
|
||||||
$httpBackend.flush();
|
|
||||||
|
|
||||||
const event = controller.events[selectedDay.getTime()];
|
|
||||||
|
|
||||||
expect(event).toBeUndefined();
|
|
||||||
expect(controller.repaintCanceller).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('repaintCanceller()', () => {
|
|
||||||
it(`should cancell the callback execution timer`, () => {
|
|
||||||
jest.spyOn(window, 'clearTimeout');
|
|
||||||
jest.spyOn(window, 'setTimeout');
|
|
||||||
|
|
||||||
const timeoutId = 90;
|
|
||||||
controller.canceller = timeoutId;
|
|
||||||
|
|
||||||
controller.repaintCanceller(() => {
|
|
||||||
return 'My callback';
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(window.clearTimeout).toHaveBeenCalledWith(timeoutId);
|
|
||||||
expect(window.setTimeout).toHaveBeenCalledWith(jasmine.any(Function), 500);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('refresh()', () => {
|
|
||||||
it(`should make a HTTP GET query and then call to the onData() method`, () => {
|
|
||||||
jest.spyOn(controller, 'onData').mockReturnThis();
|
|
||||||
|
|
||||||
const expecteResponse = [{id: 1}];
|
|
||||||
const expectedParams = {workerFk: controller.worker.id, year: year};
|
|
||||||
const serializedParams = $httpParamSerializer(expectedParams);
|
|
||||||
$httpBackend.expect('GET', `Calendars/absences?${serializedParams}`).respond(200, expecteResponse);
|
|
||||||
controller.refresh();
|
|
||||||
$httpBackend.flush();
|
|
||||||
|
|
||||||
expect(controller.onData).toHaveBeenCalledWith(expecteResponse);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,15 +0,0 @@
|
||||||
Calendar: Calendario
|
|
||||||
Contract: Contrato
|
|
||||||
Festive: Festivo
|
|
||||||
Used: Utilizados
|
|
||||||
Spent: Utilizadas
|
|
||||||
Year: Año
|
|
||||||
of: de
|
|
||||||
days: días
|
|
||||||
hours: horas
|
|
||||||
Choose an absence type from the right menu: Elige un tipo de ausencia desde el menú de la derecha
|
|
||||||
To start adding absences, click an absence type from the right menu and then on the day you want to add an absence: Para empezar a añadir ausencias, haz clic en un tipo de ausencia desde el menu de la derecha y después en el día que quieres añadir la ausencia
|
|
||||||
You can just add absences within the current year: Solo puedes añadir ausencias dentro del año actual
|
|
||||||
Current day: Día actual
|
|
||||||
Paid holidays: Vacaciones pagadas
|
|
||||||
Autonomous worker: Trabajador autónomo
|
|
|
@ -1,65 +0,0 @@
|
||||||
@import "variables";
|
|
||||||
|
|
||||||
vn-worker-calendar {
|
|
||||||
.calendars {
|
|
||||||
position: relative;
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
box-sizing: border-box;
|
|
||||||
padding: $spacing-md;
|
|
||||||
|
|
||||||
& > vn-calendar {
|
|
||||||
border: $border-thin;
|
|
||||||
margin: $spacing-md;
|
|
||||||
padding: $spacing-xs;
|
|
||||||
max-width: 288px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
vn-chip.selectable {
|
|
||||||
cursor: pointer
|
|
||||||
}
|
|
||||||
|
|
||||||
vn-chip.selectable:hover {
|
|
||||||
opacity: 0.8
|
|
||||||
}
|
|
||||||
|
|
||||||
vn-chip vn-avatar {
|
|
||||||
text-align: center;
|
|
||||||
color: white
|
|
||||||
}
|
|
||||||
|
|
||||||
vn-icon[icon="info"] {
|
|
||||||
position: absolute;
|
|
||||||
top: 16px;
|
|
||||||
right: 16px
|
|
||||||
}
|
|
||||||
|
|
||||||
vn-side-menu div > .input {
|
|
||||||
border-bottom: $border-thin;
|
|
||||||
}
|
|
||||||
|
|
||||||
.festive,
|
|
||||||
vn-avatar.today {
|
|
||||||
color: $color-font;
|
|
||||||
width: 24px;
|
|
||||||
min-width: 24px;
|
|
||||||
height: 24px
|
|
||||||
}
|
|
||||||
|
|
||||||
.festive {
|
|
||||||
border: 2px solid $color-alert
|
|
||||||
}
|
|
||||||
|
|
||||||
vn-avatar.today {
|
|
||||||
border: 2px solid $color-font-link
|
|
||||||
}
|
|
||||||
|
|
||||||
.check {
|
|
||||||
margin-top: 0.5px;
|
|
||||||
margin-left: -3px;
|
|
||||||
font-size: 125%;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,198 +0,0 @@
|
||||||
<vn-watcher
|
|
||||||
vn-id="watcher"
|
|
||||||
url="Workers/new"
|
|
||||||
data="$ctrl.worker"
|
|
||||||
insert-mode="true"
|
|
||||||
form="form">
|
|
||||||
</vn-watcher>
|
|
||||||
<form name="form" vn-http-submit="$ctrl.onSubmit()" class="vn-w-md">
|
|
||||||
<vn-card class="vn-pa-lg">
|
|
||||||
<vn-horizontal>
|
|
||||||
<vn-textfield
|
|
||||||
vn-one
|
|
||||||
label="Firstname"
|
|
||||||
ng-model="$ctrl.worker.firstName"
|
|
||||||
rule
|
|
||||||
on-change="$ctrl.generateCodeUser()"
|
|
||||||
vn-focus>
|
|
||||||
</vn-textfield>
|
|
||||||
<vn-textfield
|
|
||||||
vn-one
|
|
||||||
label="Lastname"
|
|
||||||
on-change="$ctrl.generateCodeUser()"
|
|
||||||
ng-model="$ctrl.worker.lastNames"
|
|
||||||
rule>
|
|
||||||
</vn-textfield>
|
|
||||||
<vn-date-picker
|
|
||||||
vn-one
|
|
||||||
label="Birth"
|
|
||||||
ng-model="$ctrl.worker.birth">
|
|
||||||
</vn-date-picker>
|
|
||||||
</vn-horizontal>
|
|
||||||
<vn-horizontal>
|
|
||||||
<vn-textfield
|
|
||||||
vn-one
|
|
||||||
label="Fi"
|
|
||||||
ng-model="$ctrl.worker.fi"
|
|
||||||
rule>
|
|
||||||
</vn-textfield>
|
|
||||||
<vn-textfield
|
|
||||||
vn-one
|
|
||||||
label="Worker code"
|
|
||||||
ng-model="$ctrl.worker.code"
|
|
||||||
maxLength="3"
|
|
||||||
on-change="$ctrl.worker.code = $ctrl.worker.code.toUpperCase()"
|
|
||||||
rule>
|
|
||||||
</vn-textfield>
|
|
||||||
<vn-textfield
|
|
||||||
vn-one
|
|
||||||
label="Phone"
|
|
||||||
ng-model="$ctrl.worker.phone"
|
|
||||||
rule>
|
|
||||||
</vn-textfield>
|
|
||||||
</vn-horizontal>
|
|
||||||
<vn-horizontal>
|
|
||||||
<vn-datalist
|
|
||||||
label="Postcode"
|
|
||||||
vn-one
|
|
||||||
ng-model="$ctrl.worker.postcode"
|
|
||||||
selection="$ctrl.postcode"
|
|
||||||
url="Postcodes/location"
|
|
||||||
fields="['code','townFk']"
|
|
||||||
order="code, townFk"
|
|
||||||
value-field="code"
|
|
||||||
show-field="code"
|
|
||||||
rule>
|
|
||||||
<tpl-item>
|
|
||||||
{{code}} - {{town.name}} ({{town.province.name}},
|
|
||||||
{{town.province.country.name}})
|
|
||||||
</tpl-item>
|
|
||||||
<append>
|
|
||||||
<vn-icon-button
|
|
||||||
icon="add_circle"
|
|
||||||
vn-tooltip="New postcode"
|
|
||||||
ng-click="postcode.open()"
|
|
||||||
vn-acl="deliveryAssistant"
|
|
||||||
vn-acl-action="remove">
|
|
||||||
</vn-icon-button>
|
|
||||||
</append>
|
|
||||||
</vn-datalist>
|
|
||||||
<vn-autocomplete
|
|
||||||
vn-id="province"
|
|
||||||
label="Province"
|
|
||||||
ng-model="$ctrl.worker.provinceFk"
|
|
||||||
selection="$ctrl.province"
|
|
||||||
url="Provinces/location"
|
|
||||||
fields="['id', 'name', 'countryFk']"
|
|
||||||
rule>
|
|
||||||
<tpl-item>{{name}} ({{country.name}})</tpl-item>
|
|
||||||
</vn-autocomplete>
|
|
||||||
</vn-horizontal>
|
|
||||||
<vn-horizontal>
|
|
||||||
<vn-datalist
|
|
||||||
vn-id="town"
|
|
||||||
label="City"
|
|
||||||
ng-model="$ctrl.worker.city"
|
|
||||||
selection="$ctrl.town"
|
|
||||||
url="Towns/location"
|
|
||||||
fields="['id', 'name', 'provinceFk']"
|
|
||||||
value-field="name">
|
|
||||||
<tpl-item>
|
|
||||||
{{name}}, {{province.name}}
|
|
||||||
({{province.country.name}})
|
|
||||||
</tpl-item>
|
|
||||||
</vn-datalist>
|
|
||||||
<vn-textfield
|
|
||||||
vn-two
|
|
||||||
label="Street"
|
|
||||||
ng-model="$ctrl.worker.street"
|
|
||||||
rule>
|
|
||||||
</vn-textfield>
|
|
||||||
</vn-horizontal>
|
|
||||||
<vn-horizontal>
|
|
||||||
<vn-textfield
|
|
||||||
label="Web user"
|
|
||||||
ng-model="$ctrl.worker.name"
|
|
||||||
rule>
|
|
||||||
</vn-textfield>
|
|
||||||
<vn-textfield
|
|
||||||
label="Personal email"
|
|
||||||
ng-model="$ctrl.worker.email"
|
|
||||||
rule>
|
|
||||||
</vn-textfield>
|
|
||||||
</vn-horizontal>
|
|
||||||
<vn-horizontal>
|
|
||||||
<vn-autocomplete
|
|
||||||
vn-one
|
|
||||||
vn-id="company"
|
|
||||||
ng-model="$ctrl.worker.companyFk"
|
|
||||||
url="Companies"
|
|
||||||
show-field="code"
|
|
||||||
value-field="id"
|
|
||||||
label="Company">
|
|
||||||
</vn-autocomplete>
|
|
||||||
<vn-worker-autocomplete
|
|
||||||
vn-one
|
|
||||||
ng-model="$ctrl.worker.bossFk"
|
|
||||||
show-field="nickname"
|
|
||||||
label="Boss">
|
|
||||||
</vn-worker-autocomplete>
|
|
||||||
</vn-horizontal>
|
|
||||||
<vn-horizontal>
|
|
||||||
<vn-autocomplete
|
|
||||||
vn-one
|
|
||||||
label="Pay method"
|
|
||||||
url="Paymethods"
|
|
||||||
ng-model="$ctrl.worker.payMethodFk"
|
|
||||||
initial-data="$ctrl.workerConfig.payMethodFk">
|
|
||||||
</vn-autocomplete>
|
|
||||||
<vn-textfield
|
|
||||||
vn-one
|
|
||||||
label="IBAN"
|
|
||||||
ng-model="$ctrl.worker.iban"
|
|
||||||
on-change="$ctrl.autofillBic()"
|
|
||||||
rule>
|
|
||||||
</vn-textfield>
|
|
||||||
<vn-autocomplete
|
|
||||||
vn-one
|
|
||||||
label="Swift / BIC"
|
|
||||||
url="BankEntities"
|
|
||||||
ng-model="$ctrl.worker.bankEntityFk"
|
|
||||||
fields="['name']"
|
|
||||||
initial-data="$ctrl.worker.bankEntityFk"
|
|
||||||
on-change="$ctrl.autofillBic()"
|
|
||||||
search-function="{or: [{bic: {like: $search +'%'}}, {name: {like: '%'+ $search +'%'}}]}"
|
|
||||||
value-field="id"
|
|
||||||
show-field="bic"
|
|
||||||
vn-acl="salesAssistant, hr"
|
|
||||||
disabled="$ctrl.ibanCountry == 'ES'">
|
|
||||||
<tpl-item>{{bic}} {{name}}</tpl-item>
|
|
||||||
<append>
|
|
||||||
<vn-icon-button
|
|
||||||
vn-auto
|
|
||||||
icon="add_circle"
|
|
||||||
vn-click-stop="bankEntity.show({countryFk: $ctrl.worker.countryFk})"
|
|
||||||
vn-tooltip="New bank entity"
|
|
||||||
vn-acl="salesAssistant, hr">
|
|
||||||
</vn-icon-button>
|
|
||||||
</append>
|
|
||||||
</vn-autocomplete>
|
|
||||||
</vn-horizontal>
|
|
||||||
</vn-card>
|
|
||||||
<vn-button-bar>
|
|
||||||
<vn-submit
|
|
||||||
disabled="!watcher.dataChanged()"
|
|
||||||
label="Create">
|
|
||||||
</vn-submit>
|
|
||||||
<vn-button
|
|
||||||
class="cancel"
|
|
||||||
label="Cancel"
|
|
||||||
ui-sref="worker.index">
|
|
||||||
</vn-button>
|
|
||||||
</vn-button-bar>
|
|
||||||
</form>
|
|
||||||
<!-- New postcode dialog -->
|
|
||||||
<vn-geo-postcode
|
|
||||||
vn-id="postcode"
|
|
||||||
on-response="$ctrl.onResponse($response)">
|
|
||||||
</vn-geo-postcode>
|
|
|
@ -1,141 +0,0 @@
|
||||||
import ngModule from '../module';
|
|
||||||
import Section from 'salix/components/section';
|
|
||||||
|
|
||||||
export default class Controller extends Section {
|
|
||||||
constructor($element, $) {
|
|
||||||
super($element, $);
|
|
||||||
this.worker = {companyFk: this.vnConfig.user.companyFk};
|
|
||||||
this.$http.get(`WorkerConfigs/findOne`, {field: ['payMethodFk']}).then(res => {
|
|
||||||
if (res.data) this.worker.payMethodFk = res.data.payMethodFk;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
onSubmit() {
|
|
||||||
if (!this.worker.iban && !this.worker.bankEntityFk) {
|
|
||||||
delete this.worker.iban;
|
|
||||||
delete this.worker.bankEntityFk;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.$.watcher.submit().then(json => {
|
|
||||||
this.$state.go('worker.card.basicData', {id: json.data.id});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
get ibanCountry() {
|
|
||||||
if (!this.worker || !this.worker.iban) return false;
|
|
||||||
|
|
||||||
let countryCode = this.worker.iban.substr(0, 2);
|
|
||||||
|
|
||||||
return countryCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
autofillBic() {
|
|
||||||
if (!this.worker || !this.worker.iban) return;
|
|
||||||
|
|
||||||
let bankEntityId = parseInt(this.worker.iban.substr(4, 4));
|
|
||||||
let filter = {where: {id: bankEntityId}};
|
|
||||||
|
|
||||||
this.$http.get(`BankEntities`, {filter}).then(response => {
|
|
||||||
const hasData = response.data && response.data[0];
|
|
||||||
|
|
||||||
if (hasData)
|
|
||||||
this.worker.bankEntityFk = response.data[0].id;
|
|
||||||
else if (!hasData)
|
|
||||||
this.worker.bankEntityFk = null;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
generateCodeUser() {
|
|
||||||
if (!this.worker.firstName || !this.worker.lastNames) return;
|
|
||||||
|
|
||||||
const totalName = this.worker.firstName.concat(' ' + this.worker.lastNames).toLowerCase();
|
|
||||||
const totalNameArray = totalName.split(' ');
|
|
||||||
let newCode = '';
|
|
||||||
|
|
||||||
for (let part of totalNameArray)
|
|
||||||
newCode += part.charAt(0);
|
|
||||||
|
|
||||||
this.worker.code = newCode.toUpperCase().slice(0, 3);
|
|
||||||
this.worker.name = totalNameArray[0] + newCode.slice(1);
|
|
||||||
|
|
||||||
if (!this.worker.companyFk)
|
|
||||||
this.worker.companyFk = this.vnConfig.user.companyFk;
|
|
||||||
}
|
|
||||||
|
|
||||||
get province() {
|
|
||||||
return this._province;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Province auto complete
|
|
||||||
set province(selection) {
|
|
||||||
this._province = selection;
|
|
||||||
|
|
||||||
if (!selection) return;
|
|
||||||
|
|
||||||
const country = selection.country;
|
|
||||||
|
|
||||||
if (!this.worker.countryFk)
|
|
||||||
this.worker.countryFk = country.id;
|
|
||||||
}
|
|
||||||
|
|
||||||
get town() {
|
|
||||||
return this._town;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Town auto complete
|
|
||||||
set town(selection) {
|
|
||||||
this._town = selection;
|
|
||||||
|
|
||||||
if (!selection) return;
|
|
||||||
|
|
||||||
const province = selection.province;
|
|
||||||
const country = province.country;
|
|
||||||
const postcodes = selection.postcodes;
|
|
||||||
|
|
||||||
if (!this.worker.provinceFk)
|
|
||||||
this.worker.provinceFk = province.id;
|
|
||||||
|
|
||||||
if (!this.worker.countryFk)
|
|
||||||
this.worker.countryFk = country.id;
|
|
||||||
|
|
||||||
if (postcodes.length === 1)
|
|
||||||
this.worker.postcode = postcodes[0].code;
|
|
||||||
}
|
|
||||||
|
|
||||||
get postcode() {
|
|
||||||
return this._postcode;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Postcode auto complete
|
|
||||||
set postcode(selection) {
|
|
||||||
this._postcode = selection;
|
|
||||||
|
|
||||||
if (!selection) return;
|
|
||||||
|
|
||||||
const town = selection.town;
|
|
||||||
const province = town.province;
|
|
||||||
const country = province.country;
|
|
||||||
|
|
||||||
if (!this.worker.city)
|
|
||||||
this.worker.city = town.name;
|
|
||||||
|
|
||||||
if (!this.worker.provinceFk)
|
|
||||||
this.worker.provinceFk = province.id;
|
|
||||||
|
|
||||||
if (!this.worker.countryFk)
|
|
||||||
this.worker.countryFk = country.id;
|
|
||||||
}
|
|
||||||
|
|
||||||
onResponse(response) {
|
|
||||||
this.worker.postcode = response.code;
|
|
||||||
this.worker.city = response.city;
|
|
||||||
this.worker.provinceFk = response.provinceFk;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Controller.$inject = ['$element', '$scope'];
|
|
||||||
|
|
||||||
ngModule.vnComponent('vnWorkerCreate', {
|
|
||||||
template: require('./index.html'),
|
|
||||||
controller: Controller
|
|
||||||
});
|
|
|
@ -1,133 +0,0 @@
|
||||||
import './index';
|
|
||||||
|
|
||||||
describe('Worker', () => {
|
|
||||||
describe('Component vnWorkerCreate', () => {
|
|
||||||
let $scope;
|
|
||||||
let $state;
|
|
||||||
let controller;
|
|
||||||
|
|
||||||
beforeEach(ngModule('worker'));
|
|
||||||
|
|
||||||
beforeEach(inject(($componentController, $rootScope, _$state_) => {
|
|
||||||
$scope = $rootScope.$new();
|
|
||||||
$state = _$state_;
|
|
||||||
$scope.watcher = {
|
|
||||||
submit: () => {
|
|
||||||
return {
|
|
||||||
then: callback => {
|
|
||||||
callback({data: {id: '1234'}});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const $element = angular.element('<vn-worker-create></vn-worker-create>');
|
|
||||||
controller = $componentController('vnWorkerCreate', {$element, $scope});
|
|
||||||
controller.worker = {};
|
|
||||||
controller.vnConfig = {user: {companyFk: 1}};
|
|
||||||
}));
|
|
||||||
|
|
||||||
describe('onSubmit()', () => {
|
|
||||||
it(`should call submit() on the watcher then expect a callback`, () => {
|
|
||||||
jest.spyOn($state, 'go');
|
|
||||||
controller.onSubmit();
|
|
||||||
|
|
||||||
expect(controller.$state.go).toHaveBeenCalledWith('worker.card.basicData', {id: '1234'});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('province() setter', () => {
|
|
||||||
it(`should set countryFk property`, () => {
|
|
||||||
controller.worker.countryFk = null;
|
|
||||||
controller.province = {
|
|
||||||
id: 1,
|
|
||||||
name: 'New york',
|
|
||||||
country: {
|
|
||||||
id: 2,
|
|
||||||
name: 'USA'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
expect(controller.worker.countryFk).toEqual(2);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('town() setter', () => {
|
|
||||||
it(`should set provinceFk property`, () => {
|
|
||||||
controller.town = {
|
|
||||||
provinceFk: 1,
|
|
||||||
code: 46001,
|
|
||||||
province: {
|
|
||||||
id: 1,
|
|
||||||
name: 'New york',
|
|
||||||
country: {
|
|
||||||
id: 2,
|
|
||||||
name: 'USA'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
postcodes: []
|
|
||||||
};
|
|
||||||
|
|
||||||
expect(controller.worker.provinceFk).toEqual(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
it(`should set provinceFk property and fill the postalCode if there's just one`, () => {
|
|
||||||
controller.town = {
|
|
||||||
provinceFk: 1,
|
|
||||||
code: 46001,
|
|
||||||
province: {
|
|
||||||
id: 1,
|
|
||||||
name: 'New york',
|
|
||||||
country: {
|
|
||||||
id: 2,
|
|
||||||
name: 'USA'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
postcodes: [{code: '46001'}]
|
|
||||||
};
|
|
||||||
|
|
||||||
expect(controller.worker.provinceFk).toEqual(1);
|
|
||||||
expect(controller.worker.postcode).toEqual('46001');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('postcode() setter', () => {
|
|
||||||
it(`should set the town, provinceFk and contryFk properties`, () => {
|
|
||||||
controller.postcode = {
|
|
||||||
townFk: 1,
|
|
||||||
code: 46001,
|
|
||||||
town: {
|
|
||||||
id: 1,
|
|
||||||
name: 'New York',
|
|
||||||
province: {
|
|
||||||
id: 1,
|
|
||||||
name: 'New york',
|
|
||||||
country: {
|
|
||||||
id: 2,
|
|
||||||
name: 'USA'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
expect(controller.worker.city).toEqual('New York');
|
|
||||||
expect(controller.worker.provinceFk).toEqual(1);
|
|
||||||
expect(controller.worker.countryFk).toEqual(2);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('generateCodeUser()', () => {
|
|
||||||
it(`should generate worker code, name and company `, () => {
|
|
||||||
controller.worker = {
|
|
||||||
firstName: 'default',
|
|
||||||
lastNames: 'generate worker'
|
|
||||||
};
|
|
||||||
|
|
||||||
controller.generateCodeUser();
|
|
||||||
|
|
||||||
expect(controller.worker.code).toEqual('DGW');
|
|
||||||
expect(controller.worker.name).toEqual('defaultgw');
|
|
||||||
expect(controller.worker.companyFk).toEqual(controller.vnConfig.user.companyFk);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,13 +0,0 @@
|
||||||
Firstname: Nombre
|
|
||||||
Lastname: Apellidos
|
|
||||||
Fi: DNI/NIF/NIE
|
|
||||||
Birth: Fecha de nacimiento
|
|
||||||
Worker code: Código de trabajador
|
|
||||||
Province: Provincia
|
|
||||||
City: Población
|
|
||||||
ProfileType: Tipo de perfil
|
|
||||||
Street: Dirección
|
|
||||||
Postcode: Código postal
|
|
||||||
Web user: Usuario Web
|
|
||||||
Access permission: Permiso de acceso
|
|
||||||
Pay method: Método de pago
|
|
|
@ -1,94 +0,0 @@
|
||||||
<mg-ajax path="dms/upload" options="vnPost"></mg-ajax>
|
|
||||||
<vn-watcher
|
|
||||||
vn-id="watcher"
|
|
||||||
data="$ctrl.dms">
|
|
||||||
</vn-watcher>
|
|
||||||
<vn-crud-model
|
|
||||||
auto-load="true"
|
|
||||||
url="Warehouses"
|
|
||||||
data="warehouses">
|
|
||||||
</vn-crud-model>
|
|
||||||
<form
|
|
||||||
name="form"
|
|
||||||
ng-submit="$ctrl.onSubmit()"
|
|
||||||
class="vn-ma-md"
|
|
||||||
enctype="multipart/form-data">
|
|
||||||
<div class="vn-w-md">
|
|
||||||
<vn-card class="vn-pa-lg">
|
|
||||||
<vn-horizontal>
|
|
||||||
<vn-textfield
|
|
||||||
vn-one
|
|
||||||
vn-focus
|
|
||||||
label="Reference"
|
|
||||||
ng-model="$ctrl.dms.reference"
|
|
||||||
rule>
|
|
||||||
</vn-textfield>
|
|
||||||
<vn-autocomplete vn-one
|
|
||||||
label="Company"
|
|
||||||
ng-model="$ctrl.dms.companyId"
|
|
||||||
url="Companies"
|
|
||||||
show-field="code"
|
|
||||||
value-field="id">
|
|
||||||
</vn-autocomplete>
|
|
||||||
</vn-horizontal>
|
|
||||||
<vn-horizontal>
|
|
||||||
<vn-autocomplete vn-one
|
|
||||||
label="Warehouse"
|
|
||||||
ng-model="$ctrl.dms.warehouseId"
|
|
||||||
data="warehouses"
|
|
||||||
show-field="name"
|
|
||||||
value-field="id">
|
|
||||||
</vn-autocomplete>
|
|
||||||
<vn-autocomplete vn-one
|
|
||||||
label="Type"
|
|
||||||
ng-model="$ctrl.dms.dmsTypeId"
|
|
||||||
url="DmsTypes"
|
|
||||||
show-field="name"
|
|
||||||
value-field="id">
|
|
||||||
</vn-autocomplete>
|
|
||||||
</vn-horizontal>
|
|
||||||
<vn-horizontal>
|
|
||||||
<vn-textarea
|
|
||||||
vn-one
|
|
||||||
label="Description"
|
|
||||||
ng-model="$ctrl.dms.description"
|
|
||||||
rule>
|
|
||||||
</vn-textarea>
|
|
||||||
</vn-horizontal>
|
|
||||||
<vn-horizontal>
|
|
||||||
<vn-input-file
|
|
||||||
vn-one
|
|
||||||
label="File"
|
|
||||||
ng-model="$ctrl.dms.files"
|
|
||||||
on-change="$ctrl.onFileChange($files)"
|
|
||||||
accept="{{$ctrl.allowedContentTypes}}"
|
|
||||||
required="true"
|
|
||||||
multiple="true">
|
|
||||||
<append>
|
|
||||||
<vn-icon vn-none
|
|
||||||
color-marginal
|
|
||||||
title="{{$ctrl.contentTypesInfo}}"
|
|
||||||
icon="info">
|
|
||||||
</vn-icon>
|
|
||||||
</append>
|
|
||||||
</vn-input-file>
|
|
||||||
</vn-horizontal>
|
|
||||||
<vn-vertical>
|
|
||||||
<vn-check
|
|
||||||
label="Generate identifier for original file"
|
|
||||||
ng-model="$ctrl.dms.hasFile">
|
|
||||||
</vn-check>
|
|
||||||
</vn-vertical>
|
|
||||||
</vn-card>
|
|
||||||
<vn-button-bar>
|
|
||||||
<vn-submit
|
|
||||||
label="Upload">
|
|
||||||
</vn-submit>
|
|
||||||
<vn-button
|
|
||||||
class="cancel"
|
|
||||||
label="Cancel"
|
|
||||||
ui-sref="worker.card.dms.index"></vn-button>
|
|
||||||
</vn-button>
|
|
||||||
</vn-button-bar>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue