Merge branch 'test' of https://gitea.verdnatura.es/verdnatura/salix
gitea/salix/pipeline/head This commit looks good
Details
gitea/salix/pipeline/head This commit looks good
Details
This commit is contained in:
commit
ca30aaa18a
|
@ -5,5 +5,6 @@
|
|||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll.eslint": true
|
||||
},
|
||||
"search.useIgnoreFiles": false
|
||||
"search.useIgnoreFiles": false,
|
||||
"editor.defaultFormatter": "dbaeumer.vscode-eslint"
|
||||
}
|
||||
|
|
16
CHANGELOG.md
16
CHANGELOG.md
|
@ -5,14 +5,24 @@ All notable changes to this project will be documented in this file.
|
|||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [2312.01] - 2023-04-06
|
||||
|
||||
### Added
|
||||
- (Monitor tickets) Muestra un icono al lado de la zona, si el ticket es frágil y se envía por agencia
|
||||
|
||||
### Changed
|
||||
- (Monitor tickets) Cuando se filtra por 'Pendiente' ya no muestra los estados de 'Previa'
|
||||
- (Envíos -> Extra comunitarios) Se agrupan las entradas del mismo travel. Añadidos campos Referencia y Importe.
|
||||
- (Envíos -> Índice) Cambiado el buscador superior por uno lateral
|
||||
|
||||
### Fixed
|
||||
-
|
||||
|
||||
## [2310.01] - 2023-03-23
|
||||
|
||||
### Added
|
||||
- (Trabajadores -> Control de horario) Ahora se puede confirmar/no confirmar el registro horario de cada semana desde esta sección
|
||||
|
||||
### Changed
|
||||
-
|
||||
|
||||
### Fixed
|
||||
- (Clientes -> Listado extendido) Resuelto error al filtrar por clientes inactivos desde la columna "Activo"
|
||||
- (General) Al pasar el ratón por encima del icono de "Borrar" en un campo, se hacía más grande afectando a la interfaz
|
||||
|
|
|
@ -30,16 +30,23 @@ module.exports = Self => {
|
|||
const recipient = to.replace('@', '');
|
||||
|
||||
if (sender.name != recipient) {
|
||||
await models.Chat.create({
|
||||
const chat = await models.Chat.create({
|
||||
senderFk: sender.id,
|
||||
recipient: to,
|
||||
dated: Date.vnNew(),
|
||||
checkUserStatus: 0,
|
||||
message: message,
|
||||
status: 0,
|
||||
status: 'sending',
|
||||
attempts: 0
|
||||
});
|
||||
|
||||
try {
|
||||
await Self.sendMessage(chat.senderFk, chat.recipient, chat.message);
|
||||
await Self.updateChat(chat, 'sent');
|
||||
} catch (error) {
|
||||
await Self.updateChat(chat, 'error', error);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -24,18 +24,13 @@ module.exports = Self => {
|
|||
}
|
||||
});
|
||||
|
||||
Self.sendCheckingPresence = async(ctx, recipientId, message, options) => {
|
||||
Self.sendCheckingPresence = async(ctx, recipientId, message) => {
|
||||
if (!recipientId) return false;
|
||||
|
||||
const myOptions = {};
|
||||
|
||||
if (typeof options == 'object')
|
||||
Object.assign(myOptions, options);
|
||||
|
||||
const models = Self.app.models;
|
||||
const userId = ctx.req.accessToken.userId;
|
||||
const sender = await models.Account.findById(userId);
|
||||
const recipient = await models.Account.findById(recipientId, null, myOptions);
|
||||
const sender = await models.Account.findById(userId, {fields: ['id']});
|
||||
const recipient = await models.Account.findById(recipientId, null);
|
||||
|
||||
// Prevent sending messages to yourself
|
||||
if (recipientId == userId) return false;
|
||||
|
@ -46,16 +41,23 @@ module.exports = Self => {
|
|||
if (process.env.NODE_ENV == 'test')
|
||||
message = `[Test:Environment to user ${userId}] ` + message;
|
||||
|
||||
await models.Chat.create({
|
||||
const chat = await models.Chat.create({
|
||||
senderFk: sender.id,
|
||||
recipient: `@${recipient.name}`,
|
||||
dated: Date.vnNew(),
|
||||
checkUserStatus: 1,
|
||||
message: message,
|
||||
status: 0,
|
||||
status: 'sending',
|
||||
attempts: 0
|
||||
});
|
||||
|
||||
try {
|
||||
await Self.sendCheckingUserStatus(chat);
|
||||
await Self.updateChat(chat, 'sent');
|
||||
} catch (error) {
|
||||
await Self.updateChat(chat, 'error', error);
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
};
|
||||
|
|
|
@ -3,7 +3,6 @@ module.exports = Self => {
|
|||
Self.remoteMethodCtx('sendQueued', {
|
||||
description: 'Send a RocketChat message',
|
||||
accessType: 'WRITE',
|
||||
accepts: [],
|
||||
returns: {
|
||||
type: 'object',
|
||||
root: true
|
||||
|
@ -16,14 +15,17 @@ module.exports = Self => {
|
|||
|
||||
Self.sendQueued = async() => {
|
||||
const models = Self.app.models;
|
||||
const maxAttempts = 3;
|
||||
const sentStatus = 1;
|
||||
const errorStatus = 2;
|
||||
|
||||
const chats = await models.Chat.find({
|
||||
where: {
|
||||
status: {neq: sentStatus},
|
||||
attempts: {lt: maxAttempts}
|
||||
status: {
|
||||
nin: [
|
||||
'sent',
|
||||
'sending'
|
||||
]
|
||||
|
||||
},
|
||||
attempts: {lt: 3}
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -31,16 +33,16 @@ module.exports = Self => {
|
|||
if (chat.checkUserStatus) {
|
||||
try {
|
||||
await Self.sendCheckingUserStatus(chat);
|
||||
await updateChat(chat, sentStatus);
|
||||
await Self.updateChat(chat, 'sent');
|
||||
} catch (error) {
|
||||
await updateChat(chat, errorStatus, error);
|
||||
await Self.updateChat(chat, 'error', error);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
await Self.sendMessage(chat.senderFk, chat.recipient, chat.message);
|
||||
await updateChat(chat, sentStatus);
|
||||
await Self.updateChat(chat, 'sent');
|
||||
} catch (error) {
|
||||
await updateChat(chat, errorStatus, error);
|
||||
await Self.updateChat(chat, 'error', error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -128,15 +130,17 @@ module.exports = Self => {
|
|||
* @param {object} chat - The chat
|
||||
* @param {string} status - The new status
|
||||
* @param {string} error - The error
|
||||
* @param {object} options - Query options
|
||||
* @return {Promise} - The request promise
|
||||
*/
|
||||
async function updateChat(chat, status, error) {
|
||||
*/
|
||||
|
||||
Self.updateChat = async(chat, status, error) => {
|
||||
return chat.updateAttributes({
|
||||
status: status,
|
||||
attempts: ++chat.attempts,
|
||||
error: error
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the current user status on Rocketchat
|
||||
|
|
|
@ -10,7 +10,7 @@ describe('Chat sendCheckingPresence()', () => {
|
|||
|
||||
const chat = {
|
||||
checkUserStatus: 1,
|
||||
status: 0,
|
||||
status: 'pending',
|
||||
attempts: 0
|
||||
};
|
||||
|
||||
|
@ -27,7 +27,7 @@ describe('Chat sendCheckingPresence()', () => {
|
|||
|
||||
const chat = {
|
||||
checkUserStatus: 0,
|
||||
status: 0,
|
||||
status: 'pending',
|
||||
attempts: 0
|
||||
};
|
||||
|
||||
|
|
|
@ -1,6 +1,21 @@
|
|||
const models = require('vn-loopback/server/server').models;
|
||||
const LoopBackContext = require('loopback-context');
|
||||
|
||||
describe('setSaleQuantity()', () => {
|
||||
beforeAll(async() => {
|
||||
const activeCtx = {
|
||||
accessToken: {userId: 9},
|
||||
http: {
|
||||
req: {
|
||||
headers: {origin: 'http://localhost'}
|
||||
}
|
||||
}
|
||||
};
|
||||
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
|
||||
active: activeCtx
|
||||
});
|
||||
});
|
||||
|
||||
it('should change quantity sale', async() => {
|
||||
const tx = await models.Ticket.beginTransaction({});
|
||||
|
||||
|
|
|
@ -1,215 +0,0 @@
|
|||
const md5 = require('md5');
|
||||
const fs = require('fs-extra');
|
||||
|
||||
module.exports = Self => {
|
||||
Self.remoteMethodCtx('saveSign', {
|
||||
description: 'Save sign',
|
||||
accessType: 'WRITE',
|
||||
accepts:
|
||||
[
|
||||
{
|
||||
arg: 'signContent',
|
||||
type: 'string',
|
||||
required: true,
|
||||
description: 'The sign content'
|
||||
}, {
|
||||
arg: 'tickets',
|
||||
type: ['number'],
|
||||
required: true,
|
||||
description: 'The tickets'
|
||||
}, {
|
||||
arg: 'signedTime',
|
||||
type: 'date',
|
||||
description: 'The signed time'
|
||||
}, {
|
||||
arg: 'addressFk',
|
||||
type: 'number',
|
||||
required: true,
|
||||
description: 'The address fk'
|
||||
}
|
||||
],
|
||||
returns: {
|
||||
type: 'Object',
|
||||
root: true
|
||||
},
|
||||
http: {
|
||||
path: `/saveSign`,
|
||||
verb: 'POST'
|
||||
}
|
||||
});
|
||||
|
||||
async function createGestDoc(ticketId, userFk) {
|
||||
const models = Self.app.models;
|
||||
if (!await gestDocExists(ticketId)) {
|
||||
const result = await models.Ticket.findOne({
|
||||
where: {
|
||||
id: ticketId
|
||||
},
|
||||
include: [
|
||||
{
|
||||
relation: 'warehouse',
|
||||
scope: {
|
||||
fields: ['id']
|
||||
}
|
||||
}, {
|
||||
relation: 'client',
|
||||
scope: {
|
||||
fields: ['name']
|
||||
}
|
||||
}, {
|
||||
relation: 'route',
|
||||
scope: {
|
||||
fields: ['id']
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
const warehouseFk = result.warehouseFk;
|
||||
const companyFk = result.companyFk;
|
||||
const client = result.client.name;
|
||||
const route = result.route.id;
|
||||
|
||||
const resultDmsType = await models.DmsType.findOne({
|
||||
where: {
|
||||
code: 'Ticket'
|
||||
}
|
||||
});
|
||||
|
||||
const resultDms = await models.Dms.create({
|
||||
dmsTypeFk: resultDmsType.id,
|
||||
reference: ticketId,
|
||||
description: `Ticket ${ticketId} Cliente ${client} Ruta ${route}`,
|
||||
companyFk: companyFk,
|
||||
warehouseFk: warehouseFk,
|
||||
workerFk: userFk
|
||||
});
|
||||
|
||||
return resultDms.insertId;
|
||||
}
|
||||
}
|
||||
|
||||
async function gestDocExists(ticket) {
|
||||
const models = Self.app.models;
|
||||
const result = await models.TicketDms.findOne({
|
||||
where: {
|
||||
ticketFk: ticket
|
||||
},
|
||||
fields: ['dmsFk']
|
||||
});
|
||||
|
||||
if (result == null)
|
||||
return false;
|
||||
|
||||
const isSigned = await models.Ticket.findOne({
|
||||
where: {
|
||||
id: ticket
|
||||
},
|
||||
fields: ['isSigned']
|
||||
});
|
||||
|
||||
if (isSigned)
|
||||
return true;
|
||||
else
|
||||
await models.Dms.destroyById(ticket);
|
||||
}
|
||||
|
||||
async function dmsRecover(ticket, signContent) {
|
||||
const models = Self.app.models;
|
||||
await models.DmsRecover.create({
|
||||
ticketFk: ticket,
|
||||
sign: signContent
|
||||
});
|
||||
}
|
||||
|
||||
async function ticketGestdoc(ticket, dmsFk) {
|
||||
const models = Self.app.models;
|
||||
models.TicketDms.replaceOrCreate({
|
||||
ticketFk: ticket,
|
||||
dmsFk: dmsFk
|
||||
});
|
||||
|
||||
const queryVnTicketSetState = `CALL vn.ticket_setState(?, ?)`;
|
||||
|
||||
await Self.rawSql(queryVnTicketSetState, [ticket, 'DELIVERED']);
|
||||
}
|
||||
|
||||
async function updateGestdoc(file, ticket) {
|
||||
const models = Self.app.models;
|
||||
models.Dms.updateOne({
|
||||
where: {
|
||||
id: ticket
|
||||
},
|
||||
file: file,
|
||||
contentType: 'image/png'
|
||||
});
|
||||
}
|
||||
|
||||
Self.saveSign = async(ctx, signContent, tickets, signedTime) => {
|
||||
const models = Self.app.models;
|
||||
let tx = await Self.beginTransaction({});
|
||||
try {
|
||||
const userId = ctx.req.accessToken.userId;
|
||||
|
||||
const dmsDir = `storage/dms`;
|
||||
|
||||
let image = null;
|
||||
|
||||
for (let i = 0; i < tickets.length; i++) {
|
||||
const alertLevel = await models.TicketState.findOne({
|
||||
where: {
|
||||
ticketFk: tickets[i]
|
||||
},
|
||||
fields: ['alertLevel']
|
||||
});
|
||||
|
||||
signedTime ? signedTime != undefined : signedTime = Date.vnNew();
|
||||
|
||||
if (alertLevel >= 2) {
|
||||
let dir;
|
||||
let id = null;
|
||||
let fileName = null;
|
||||
|
||||
if (!await gestDocExists(tickets[i])) {
|
||||
id = await createGestDoc(tickets[i], userId);
|
||||
|
||||
const hashDir = md5(id).substring(0, 3);
|
||||
dir = `${dmsDir}/${hashDir}`;
|
||||
|
||||
if (!fs.existsSync(dir))
|
||||
fs.mkdirSync(dir);
|
||||
|
||||
fileName = `${id}.png`;
|
||||
image = `${dir}/${fileName}`;
|
||||
} else
|
||||
|
||||
if (image != null) {
|
||||
if (!fs.existsSync(dir))
|
||||
dmsRecover(tickets[i], signContent);
|
||||
else {
|
||||
fs.writeFile(image, signContent, 'base64', async function(err) {
|
||||
if (err) {
|
||||
await tx.rollback();
|
||||
return err.message;
|
||||
}
|
||||
});
|
||||
}
|
||||
} else
|
||||
dmsRecover(tickets[i], signContent);
|
||||
|
||||
if (id != null && fileName.length > 0) {
|
||||
ticketGestdoc(tickets[i], id);
|
||||
updateGestdoc(id, fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (tx) await tx.commit();
|
||||
|
||||
return 'OK';
|
||||
} catch (err) {
|
||||
await tx.rollback();
|
||||
throw err.message;
|
||||
}
|
||||
};
|
||||
};
|
|
@ -9,17 +9,29 @@
|
|||
"properties": {
|
||||
"id": {
|
||||
"id": true,
|
||||
"type": "number",
|
||||
"forceId": false
|
||||
"type": "number"
|
||||
},
|
||||
"date": {
|
||||
"created": {
|
||||
"type": "date"
|
||||
},
|
||||
"m3":{
|
||||
"longitude":{
|
||||
"type": "number"
|
||||
},
|
||||
"warehouseFk":{
|
||||
"latitude":{
|
||||
"type": "number"
|
||||
},
|
||||
"dated":{
|
||||
"type": "date"
|
||||
},
|
||||
"ticketFk":{
|
||||
"type": "number"
|
||||
}
|
||||
}
|
||||
},
|
||||
"relations": {
|
||||
"ticket": {
|
||||
"type": "belongsTo",
|
||||
"model": "Ticket",
|
||||
"foreignKey": "ticketFk"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@ module.exports = Self => {
|
|||
require('../methods/dms/removeFile')(Self);
|
||||
require('../methods/dms/updateFile')(Self);
|
||||
require('../methods/dms/deleteTrashFiles')(Self);
|
||||
require('../methods/dms/saveSign')(Self);
|
||||
|
||||
Self.checkRole = async function(ctx, id) {
|
||||
const models = Self.app.models;
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
DROP TABLE `vn`.`dmsRecover`;
|
||||
|
||||
ALTER TABLE `vn`.`delivery` DROP FOREIGN KEY delivery_FK;
|
||||
ALTER TABLE `vn`.`delivery` DROP COLUMN addressFk;
|
||||
ALTER TABLE `vn`.`delivery` ADD ticketFk INT NOT NULL;
|
||||
ALTER TABLE `vn`.`delivery` ADD CONSTRAINT delivery_ticketFk_FK FOREIGN KEY (`ticketFk`) REFERENCES `vn`.`ticket`(`id`);
|
||||
|
||||
DELETE FROM `salix`.`ACL` WHERE `property` = 'saveSign';
|
||||
INSERT INTO `salix`.`ACL` (`model`,`property`,`accessType`,`permission`,`principalId`)
|
||||
VALUES
|
||||
('Ticket','saveSign','WRITE','ALLOW','employee');
|
||||
|
||||
DROP PROCEDURE IF EXISTS vn.route_getTickets;
|
||||
|
||||
DELIMITER $$
|
||||
$$
|
||||
CREATE DEFINER=`root`@`localhost` PROCEDURE `vn`.`route_getTickets`(vRouteFk INT)
|
||||
BEGIN
|
||||
/**
|
||||
* Pasado un RouteFk devuelve la información
|
||||
* de sus tickets.
|
||||
*
|
||||
* @param vRouteFk
|
||||
*
|
||||
* @select Información de los tickets
|
||||
*/
|
||||
|
||||
SELECT
|
||||
t.id Id,
|
||||
t.clientFk Client,
|
||||
a.id Address,
|
||||
t.packages Packages,
|
||||
a.street AddressName,
|
||||
a.postalCode PostalCode,
|
||||
a.city City,
|
||||
sub2.itemPackingTypeFk PackingType,
|
||||
c.phone ClientPhone,
|
||||
c.mobile ClientMobile,
|
||||
a.phone AddressPhone,
|
||||
a.mobile AddressMobile,
|
||||
d.longitude Longitude,
|
||||
d.latitude Latitude,
|
||||
wm.mediaValue SalePersonPhone,
|
||||
tob.Note Note,
|
||||
t.isSigned Signed
|
||||
FROM ticket t
|
||||
JOIN client c ON t.clientFk = c.id
|
||||
JOIN address a ON t.addressFk = a.id
|
||||
LEFT JOIN delivery d ON t.id = d.ticketFk
|
||||
LEFT JOIN workerMedia wm ON wm.workerFk = c.salesPersonFk
|
||||
LEFT JOIN
|
||||
(SELECT tob.description Note, t.id
|
||||
FROM ticketObservation tob
|
||||
JOIN ticket t ON tob.ticketFk = t.id
|
||||
JOIN observationType ot ON ot.id = tob.observationTypeFk
|
||||
WHERE t.routeFk = vRouteFk
|
||||
AND ot.code = 'delivery'
|
||||
)tob ON tob.id = t.id
|
||||
LEFT JOIN
|
||||
(SELECT sub.ticketFk,
|
||||
CONCAT('(', GROUP_CONCAT(DISTINCT sub.itemPackingTypeFk ORDER BY sub.items DESC SEPARATOR ','), ') ') itemPackingTypeFk
|
||||
FROM (SELECT s.ticketFk , i.itemPackingTypeFk, COUNT(*) items
|
||||
FROM ticket t
|
||||
JOIN sale s ON s.ticketFk = t.id
|
||||
JOIN item i ON i.id = s.itemFk
|
||||
WHERE t.routeFk = vRouteFk
|
||||
GROUP BY t.id,i.itemPackingTypeFk)sub
|
||||
GROUP BY sub.ticketFk
|
||||
) sub2 ON sub2.ticketFk = t.id
|
||||
WHERE t.routeFk = vRouteFk
|
||||
GROUP BY t.id
|
||||
ORDER BY t.priority;
|
||||
END$$
|
||||
DELIMITER ;
|
|
@ -0,0 +1,3 @@
|
|||
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
|
||||
VALUES ('Operator', '*', 'READ', 'ALLOW', 'ROLE', 'employee'),
|
||||
('Operator', '*', 'WRITE', 'ALLOW', 'ROLE', 'employee');
|
|
@ -0,0 +1,16 @@
|
|||
ALTER TABLE `vn`.`chat` ADD statusNew enum('pending','sent','error','sending') DEFAULT 'pending' NOT NULL;
|
||||
|
||||
UPDATE `vn`.`chat`
|
||||
SET statusNew = 'pending'
|
||||
WHERE status = 0;
|
||||
|
||||
UPDATE `vn`.`chat`
|
||||
SET statusNew = 'sent'
|
||||
WHERE status = 1;
|
||||
|
||||
UPDATE `vn`.`chat`
|
||||
SET statusNew = 'error'
|
||||
WHERE status = 2;
|
||||
|
||||
ALTER TABLE `vn`.`chat` CHANGE status status__ tinyint(1) DEFAULT NULL NULL;
|
||||
ALTER TABLE `vn`.`chat` CHANGE statusNew status enum('pending','sent','error','sending') CHARACTER SET utf8mb3 COLLATE utf8mb3_unicode_ci DEFAULT 'pending' NOT NULL;
|
|
@ -0,0 +1,4 @@
|
|||
ALTER TABLE `vn`.`invoiceInConfig` ADD daysAgo INT UNSIGNED DEFAULT 45 COMMENT 'Días en el pasado para mostrar facturas en invoiceIn series en salix';
|
||||
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
|
||||
VALUES
|
||||
('InvoiceIn', 'getSerial', 'READ', 'ALLOW', 'ROLE', 'administrative');
|
|
@ -0,0 +1,14 @@
|
|||
ALTER TABLE `vn`.`itemType` ADD isFragile tinyint(1) NULL;
|
||||
ALTER TABLE `vn`.`itemType` MODIFY COLUMN isFragile tinyint(1) DEFAULT 0 NOT NULL;
|
||||
|
||||
UPDATE `vn`.`itemType`
|
||||
SET isFragile = 1
|
||||
WHERE code IN ('ZKA', 'ZKE');
|
||||
|
||||
UPDATE `vn`.`itemType`
|
||||
SET isFragile = 1
|
||||
WHERE id IN (SELECT it.id
|
||||
FROM `vn`.`itemCategory` ic
|
||||
JOIN `vn`.`itemType` it ON it.categoryFk = ic.id
|
||||
WHERE ic.code = 'plant');
|
||||
|
|
@ -0,0 +1,159 @@
|
|||
ALTER TABLE `vn`.`operator` ADD sectorFk int(11) NULL;
|
||||
ALTER TABLE `vn`.`operator` ADD labelerFk tinyint(3) unsigned NULL;
|
||||
ALTER TABLE `vn`.`operator` ADD CONSTRAINT operator_FK_5 FOREIGN KEY (labelerFk) REFERENCES `vn`.`printer`(id) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
UPDATE `vn`.`operator` o
|
||||
JOIN (SELECT id, sectorFk, labelerFk
|
||||
FROM `vn`.`worker`) sub ON sub.id = o.workerFk
|
||||
SET o.sectorFk = sub.sectorFk,
|
||||
o.labelerFk = sub.labelerFk;
|
||||
|
||||
DELIMITER $$
|
||||
CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`collection_printSticker`(
|
||||
vSelf INT,
|
||||
vLabelCount INT
|
||||
)
|
||||
BEGIN
|
||||
/**
|
||||
* Prints a yellow label from a collection or a ticket
|
||||
*
|
||||
* @param vSelf collection or ticket
|
||||
* @param vLabelCount number of times the collection has been printed
|
||||
*/
|
||||
DECLARE vPrintArgs JSON DEFAULT JSON_OBJECT('collectionOrTicketFk', vSelf);
|
||||
|
||||
IF vLabelCount IS NULL THEN
|
||||
INSERT INTO ticketTrolley
|
||||
SELECT ticketFk, 1
|
||||
FROM ticketCollection
|
||||
WHERE collectionFk = vSelf
|
||||
ON DUPLICATE KEY UPDATE labelCount = labelCount + 1;
|
||||
ELSE
|
||||
SET vPrintArgs = JSON_MERGE_PATCH(vPrintArgs, JSON_OBJECT('labelCount', vLabelCount));
|
||||
END IF;
|
||||
|
||||
CALL report_print(
|
||||
'LabelCollection',
|
||||
(SELECT o.labelerFk FROM operator o WHERE o.workerFk = account.myUser_getId()),
|
||||
account.myUser_getId(),
|
||||
vPrintArgs,
|
||||
'high'
|
||||
);
|
||||
END$$
|
||||
DELIMITER ;
|
||||
|
||||
DELIMITER $$
|
||||
CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`expeditionPallet_printLabel`(vSelf INT)
|
||||
BEGIN
|
||||
/**
|
||||
* Calls the report_print procedure and passes it
|
||||
* the necessary parameters for printing.
|
||||
*
|
||||
* @param vSelf expeditioPallet id.
|
||||
*/
|
||||
DECLARE vPrinterFk INT;
|
||||
DECLARE vUserFk INT DEFAULT account.myUser_getId();
|
||||
|
||||
SELECT o.labelerFk INTO vPrinterFk
|
||||
FROM operator o
|
||||
WHERE o.workerFk = vUserFk;
|
||||
|
||||
CALL vn.report_print(
|
||||
'LabelPalletExpedition',
|
||||
vPrinterFk,
|
||||
account.myUser_getId(),
|
||||
JSON_OBJECT('palletFk', vSelf, 'userFk', vUserFk),
|
||||
'high'
|
||||
);
|
||||
|
||||
UPDATE vn.expeditionPallet
|
||||
SET isPrint = TRUE
|
||||
WHERE id = vSelf;
|
||||
END$$
|
||||
DELIMITER ;
|
||||
|
||||
DELIMITER $$
|
||||
CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`itemShelving_getAlternatives`(vShelvingFk VARCHAR(10))
|
||||
BEGIN
|
||||
/**
|
||||
* Devuelve un listado de posibles ubicaciones alternativas a ubicar los item de la matricula
|
||||
* del carro que se le ha pasado.
|
||||
*
|
||||
* @param vShelvingFk matricula del carro
|
||||
*/
|
||||
SELECT is2.id,is2.shelvingFk , p.code, is2.itemFk , is2.visible, p.pickingOrder
|
||||
FROM itemShelving is2
|
||||
JOIN shelving sh ON sh.code = is2.shelvingFk
|
||||
JOIN parking p ON p.id = sh.parkingFk
|
||||
JOIN sector s ON s.id = p.sectorFk
|
||||
LEFT JOIN operator o ON o.sectorFk = s.id
|
||||
LEFT JOIN worker w ON w.sectorFk = s.id AND w.id = account.myUser_getId()
|
||||
JOIN warehouse wh ON wh.id = s.warehouseFk
|
||||
JOIN itemShelving is3 ON is3.itemFk = is2.itemFk AND is3.shelvingFk = vShelvingFk COLLATE utf8_unicode_ci
|
||||
WHERE is2.shelvingFk <> vShelvingFk COLLATE utf8_unicode_ci
|
||||
GROUP BY is2.id
|
||||
ORDER BY p.pickingOrder DESC;
|
||||
END$$
|
||||
DELIMITER ;
|
||||
|
||||
DELIMITER $$
|
||||
CREATE OR REPLACE DEFINER=`root`@`localhost` TRIGGER `vn`.`operator_beforeInsert`
|
||||
BEFORE INSERT ON `operator`
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
CALL vn.printer_checkSector(NEW.labelerFk, NEW.sectorFk);
|
||||
END$$
|
||||
DELIMITER ;
|
||||
|
||||
DELIMITER $$
|
||||
CREATE OR REPLACE DEFINER=`root`@`localhost` TRIGGER `vn`.`operator_beforeUpdate`
|
||||
BEFORE UPDATE ON `operator`
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
IF NOT (NEW.labelerFk <=> OLD.labelerFk AND NEW.sectorFk <=> OLD.sectorFk) THEN
|
||||
CALL vn.printer_checkSector(NEW.labelerFk, NEW.sectorFk);
|
||||
END IF;
|
||||
END$$
|
||||
DELIMITER ;
|
||||
|
||||
DELIMITER $$
|
||||
CREATE OR REPLACE DEFINER=`root`@`localhost` TRIGGER `vn`.`worker_beforeUpdate`
|
||||
BEFORE UPDATE ON `worker`
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
IF NOT (NEW.labelerFk <=> OLD.labelerFk AND NEW.sectorFk <=> OLD.sectorFk) THEN
|
||||
CALL vn.printer_checkSector(NEW.labelerFk, NEW.sectorFk);
|
||||
|
||||
INSERT IGNORE INTO vn.operator (workerFk)
|
||||
VALUES (NEW.id);
|
||||
|
||||
UPDATE operator
|
||||
SET labelerFk = NEW.labelerFk,
|
||||
sectorFk = NEW.sectorFk
|
||||
WHERE workerFk = NEW.id;
|
||||
END IF;
|
||||
END$$
|
||||
DELIMITER ;
|
||||
|
||||
CREATE OR REPLACE DEFINER=`root`@`localhost`
|
||||
SQL SECURITY DEFINER
|
||||
VIEW `vn`.`operatorWorkerCode`
|
||||
AS SELECT `o`.`workerFk` AS `workerFk`,
|
||||
concat(`w`.`firstName`, ' ', `w`.`lastName`) AS `fullName`,
|
||||
`w`.`code` AS `code`,
|
||||
`o`.`numberOfWagons` AS `numberOfWagons`
|
||||
FROM (
|
||||
(
|
||||
`vn`.`worker` `w`
|
||||
JOIN `vn`.`operator` `o` ON(`o`.`workerFk` = `w`.`id`)
|
||||
)
|
||||
JOIN `vn`.`sector` `s` ON(`o`.`sectorFk` = `s`.`id`)
|
||||
)
|
||||
WHERE `o`.`sectorFk` IS NOT NULL
|
||||
AND `s`.`code` IN (
|
||||
'H2',
|
||||
'H2',
|
||||
'PEQUES_H',
|
||||
'ALTILLO COMP',
|
||||
'ALTILLO ARTI'
|
||||
)
|
|
@ -0,0 +1,3 @@
|
|||
DROP TRIGGER `vn`.`supplierAccount_afterInsert`;
|
||||
DROP TRIGGER `vn`.`supplierAccount_afterUpdate`;
|
||||
DROP TRIGGER `vn`.`supplierAccount_afterDelete`;
|
|
@ -0,0 +1,47 @@
|
|||
DROP PROCEDURE IF EXISTS `vn`.`ticket_getWarnings`;
|
||||
|
||||
DELIMITER $$
|
||||
$$
|
||||
CREATE PROCEDURE `vn`.`ticket_getWarnings`()
|
||||
BEGIN
|
||||
/**
|
||||
* Calcula las adventencias para un conjunto de tickets.
|
||||
* Agrupados por ticket
|
||||
*
|
||||
* @table tmp.sale_getWarnings(ticketFk) Identificadores de los tickets a calcular
|
||||
* @return tmp.ticket_warnings
|
||||
*/
|
||||
DROP TEMPORARY TABLE IF EXISTS tmp.sale_warnings;
|
||||
CREATE TEMPORARY TABLE tmp.sale_warnings (
|
||||
ticketFk INT(11),
|
||||
saleFk INT(11),
|
||||
isFragile INTEGER(1) DEFAULT 0,
|
||||
PRIMARY KEY (ticketFk, saleFk)
|
||||
) ENGINE = MEMORY;
|
||||
|
||||
-- Frágil
|
||||
INSERT INTO tmp.sale_warnings(ticketFk, saleFk, isFragile)
|
||||
SELECT tt.ticketFk, s.id, TRUE
|
||||
FROM tmp.sale_getWarnings tt
|
||||
LEFT JOIN sale s ON s.ticketFk = tt.ticketFk
|
||||
LEFT JOIN item i ON i.id = s.itemFk
|
||||
LEFT JOIN itemType it ON it.id = i.typeFk
|
||||
LEFT JOIN agencyMode am ON am.id = tt.agencyModeFk
|
||||
LEFT JOIN deliveryMethod dm ON dm.id = am.deliveryMethodFk
|
||||
WHERE dm.code IN ('AGENCY')
|
||||
AND it.isFragile;
|
||||
|
||||
DROP TEMPORARY TABLE IF EXISTS tmp.ticket_warnings;
|
||||
CREATE TEMPORARY TABLE tmp.ticket_warnings
|
||||
(PRIMARY KEY (ticketFk))
|
||||
ENGINE = MEMORY
|
||||
SELECT
|
||||
sw.ticketFk,
|
||||
MAX(sw.isFragile) AS isFragile
|
||||
FROM tmp.sale_warnings sw
|
||||
GROUP BY sw.ticketFk;
|
||||
|
||||
DROP TEMPORARY TABLE
|
||||
tmp.sale_warnings;
|
||||
END$$
|
||||
DELIMITER ;
|
|
@ -0,0 +1,72 @@
|
|||
CREATE TABLE `vn`.`wagonType` (
|
||||
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`name` varchar(30) NOT NULL UNIQUE,
|
||||
`divisible` tinyint(1) NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb3;
|
||||
|
||||
CREATE TABLE `vn`.`wagonTypeColor` (
|
||||
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`name` varchar(30) NOT NULL UNIQUE,
|
||||
`rgb` varchar(30) NOT NULL UNIQUE,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb3;
|
||||
|
||||
CREATE TABLE `vn`.`wagonTypeTray` (
|
||||
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`typeFk` int(11) unsigned,
|
||||
`height` int(11) unsigned NOT NULL,
|
||||
`colorFk` int(11) unsigned,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY (`typeFk`,`height`),
|
||||
CONSTRAINT `wagonTypeTray_type` FOREIGN KEY (`typeFk`) REFERENCES `wagonType` (`id`) ON UPDATE CASCADE,
|
||||
CONSTRAINT `wagonTypeTray_color` FOREIGN KEY (`colorFk`) REFERENCES `wagonTypeColor` (`id`) ON UPDATE CASCADE
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb3;
|
||||
|
||||
CREATE TABLE `vn`.`wagonConfig` (
|
||||
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`width` int(11) unsigned DEFAULT 1350,
|
||||
`height` int(11) unsigned DEFAULT 1900,
|
||||
`maxWagonHeight` int(11) unsigned DEFAULT 200,
|
||||
`minHeightBetweenTrays` int(11) unsigned DEFAULT 50,
|
||||
`maxTrays` int(11) unsigned DEFAULT 6,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb3;
|
||||
|
||||
CREATE TABLE `vn`.`collectionWagon` (
|
||||
`collectionFk` int(11) NOT NULL,
|
||||
`wagonFk` int(11) NOT NULL,
|
||||
`position` int(11) unsigned,
|
||||
PRIMARY KEY (`collectionFk`,`position`),
|
||||
UNIQUE KEY `collectionWagon_unique` (`collectionFk`,`wagonFk`),
|
||||
CONSTRAINT `collectionWagon_collection` FOREIGN KEY (`collectionFk`) REFERENCES `collection` (`id`) ON UPDATE CASCADE,
|
||||
CONSTRAINT `collectionWagon_wagon` FOREIGN KEY (`wagonFk`) REFERENCES `wagon` (`id`) ON UPDATE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
|
||||
|
||||
CREATE TABLE `vn`.`collectionWagonTicket` (
|
||||
`ticketFk` int(11) NOT NULL,
|
||||
`wagonFk` int(11) NOT NULL,
|
||||
`trayFk` int(11) unsigned NOT NULL,
|
||||
`side` SET('L', 'R') NULL,
|
||||
PRIMARY KEY (`ticketFk`),
|
||||
CONSTRAINT `collectionWagonTicket_ticket` FOREIGN KEY (`ticketFk`) REFERENCES `ticket` (`id`) ON UPDATE CASCADE,
|
||||
CONSTRAINT `collectionWagonTicket_wagon` FOREIGN KEY (`wagonFk`) REFERENCES `wagon` (`id`) ON UPDATE CASCADE,
|
||||
CONSTRAINT `collectionWagonTicket_tray` FOREIGN KEY (`trayFk`) REFERENCES `wagonTypeTray` (`id`) ON UPDATE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
|
||||
|
||||
ALTER TABLE `vn`.`wagon` ADD `typeFk` int(11) unsigned NOT NULL;
|
||||
ALTER TABLE `vn`.`wagon` ADD `label` int(11) unsigned NOT NULL;
|
||||
ALTER TABLE `vn`.`wagon` ADD CONSTRAINT `wagon_type` FOREIGN KEY (`typeFk`) REFERENCES `wagonType` (`id`) ON UPDATE CASCADE;
|
||||
|
||||
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
|
||||
VALUES
|
||||
('WagonType', '*', '*', 'ALLOW', 'ROLE', 'productionAssi'),
|
||||
('WagonTypeColor', '*', '*', 'ALLOW', 'ROLE', 'productionAssi'),
|
||||
('WagonTypeTray', '*', '*', 'ALLOW', 'ROLE', 'productionAssi'),
|
||||
('WagonConfig', '*', '*', 'ALLOW', 'ROLE', 'productionAssi'),
|
||||
('CollectionWagon', '*', '*', 'ALLOW', 'ROLE', 'productionAssi'),
|
||||
('CollectionWagonTicket', '*', '*', 'ALLOW', 'ROLE', 'productionAssi'),
|
||||
('Wagon', '*', '*', 'ALLOW', 'ROLE', 'productionAssi'),
|
||||
('WagonType', 'createWagonType', '*', 'ALLOW', 'ROLE', 'productionAssi'),
|
||||
('WagonType', 'deleteWagonType', '*', 'ALLOW', 'ROLE', 'productionAssi'),
|
||||
('WagonType', 'editWagonType', '*', 'ALLOW', 'ROLE', 'productionAssi');
|
|
@ -173,6 +173,10 @@ INSERT INTO `vn`.`sector`(`id`, `description`, `warehouseFk`, `isPreviousPrepare
|
|||
(1, 'First sector', 1, 1, 'FIRST'),
|
||||
(2, 'Second sector', 2, 0, 'SECOND');
|
||||
|
||||
INSERT INTO `vn`.`operator` (`workerFk`, `numberOfWagons`, `trainFk`, `itemPackingTypeFk`, `warehouseFk`, `sectorFk`, `labelerFk`)
|
||||
VALUES ('1106', '1', '1', 'H', '1', '1', '1'),
|
||||
('1107', '1', '1', 'V', '1', '2', '1');
|
||||
|
||||
INSERT INTO `vn`.`printer` (`id`, `name`, `path`, `isLabeler`, `sectorFk`, `ipAddress`)
|
||||
VALUES
|
||||
(1, 'printer1', 'path1', 0, 1 , NULL),
|
||||
|
@ -295,7 +299,8 @@ INSERT INTO `vn`.`payMethod`(`id`,`code`, `name`, `graceDays`, `outstandingDebt
|
|||
INSERT INTO `vn`.`payDem`(`id`, `payDem`)
|
||||
VALUES
|
||||
(1, 10),
|
||||
(2, 20);
|
||||
(2, 20),
|
||||
(7, 0);
|
||||
|
||||
INSERT INTO `vn`.`autonomy`(`id`, `name`, `countryFk`)
|
||||
VALUES
|
||||
|
@ -496,7 +501,8 @@ INSERT INTO `vn`.`observationType`(`id`,`description`, `code`)
|
|||
(3, 'Delivery', 'delivery'),
|
||||
(4, 'SalesPerson', 'salesPerson'),
|
||||
(5, 'Administrative', 'administrative'),
|
||||
(6, 'Weight', 'weight');
|
||||
(6, 'Weight', 'weight'),
|
||||
(7, 'InvoiceOut', 'invoiceOut');
|
||||
|
||||
INSERT INTO `vn`.`addressObservation`(`id`,`addressFk`,`observationTypeFk`,`description`)
|
||||
VALUES
|
||||
|
@ -733,7 +739,9 @@ INSERT INTO `vn`.`ticketObservation`(`id`, `ticketFk`, `observationTypeFk`, `des
|
|||
(9, 23, 5, 'care with the dog'),
|
||||
(10, 23, 4, 'Reclama ticket: 8'),
|
||||
(11, 24, 4, 'Reclama ticket: 7'),
|
||||
(12, 11, 3, 'Delivery after 10am');
|
||||
(12, 11, 3, 'Delivery after 10am'),
|
||||
(13, 1, 7, 'observation of ticket one'),
|
||||
(14, 2, 7, 'observation of ticket two');
|
||||
|
||||
-- FIX for state hours on local, inter_afterInsert
|
||||
-- UPDATE vncontrol.inter SET odbc_date = DATE_ADD(util.VN_CURDATE(), INTERVAL -10 SECOND);
|
||||
|
@ -833,14 +841,14 @@ INSERT INTO `vn`.`temperature`(`code`, `name`, `description`)
|
|||
('warm', 'Warm', 'Warm'),
|
||||
('cool', 'Cool', 'Cool');
|
||||
|
||||
INSERT INTO `vn`.`itemType`(`id`, `code`, `name`, `categoryFk`, `life`, `workerFk`, `isPackaging`, `temperatureFk`)
|
||||
INSERT INTO `vn`.`itemType`(`id`, `code`, `name`, `categoryFk`, `life`, `workerFk`, `isPackaging`, `temperatureFk`, `isFragile`)
|
||||
VALUES
|
||||
(1, 'CRI', 'Crisantemo', 2, 31, 35, 0, 'cool'),
|
||||
(2, 'ITG', 'Anthurium', 1, 31, 35, 0, 'cool'),
|
||||
(3, 'WPN', 'Paniculata', 2, 31, 35, 0, 'cool'),
|
||||
(4, 'PRT', 'Delivery ports', 3, NULL, 35, 1, 'warm'),
|
||||
(5, 'CON', 'Container', 3, NULL, 35, 1, 'warm'),
|
||||
(6, 'ALS', 'Alstroemeria', 1, 31, 16, 0, 'warm');
|
||||
(1, 'CRI', 'Crisantemo', 2, 31, 35, 0, 'cool', 0),
|
||||
(2, 'ITG', 'Anthurium', 1, 31, 35, 0, 'cool', 1),
|
||||
(3, 'WPN', 'Paniculata', 2, 31, 35, 0, 'cool', 0),
|
||||
(4, 'PRT', 'Delivery ports', 3, NULL, 35, 1, 'warm', 0),
|
||||
(5, 'CON', 'Container', 3, NULL, 35, 1, 'warm', 0),
|
||||
(6, 'ALS', 'Alstroemeria', 1, 31, 16, 0, 'warm', 1);
|
||||
|
||||
INSERT INTO `vn`.`ink`(`id`, `name`, `picture`, `showOrder`, `hex`)
|
||||
VALUES
|
||||
|
@ -2482,9 +2490,9 @@ REPLACE INTO `vn`.`invoiceIn`(`id`, `serialNumber`,`serial`, `supplierFk`, `issu
|
|||
(9, 1009, 'R', 2, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 1242, 1, 442, 1),
|
||||
(10, 1010, 'R', 2, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 1243, 1, 442, 1);
|
||||
|
||||
INSERT INTO `vn`.`invoiceInConfig` (`id`, `retentionRate`, `retentionName`, `sageWithholdingFk`)
|
||||
INSERT INTO `vn`.`invoiceInConfig` (`id`, `retentionRate`, `retentionName`, `sageWithholdingFk`, `daysAgo`)
|
||||
VALUES
|
||||
(1, -2, '2% retention', 2);
|
||||
(1, -2, '2% retention', 2, 45);
|
||||
|
||||
INSERT INTO `vn`.`invoiceInDueDay`(`invoiceInFk`, `dueDated`, `bankFk`, `amount`)
|
||||
VALUES
|
||||
|
@ -2626,8 +2634,8 @@ INSERT INTO `vn`.`supplierAgencyTerm` (`agencyFk`, `supplierFk`, `minimumPackage
|
|||
|
||||
INSERT INTO `vn`.`chat` (`senderFk`, `recipient`, `dated`, `checkUserStatus`, `message`, `status`, `attempts`)
|
||||
VALUES
|
||||
(1101, '@PetterParker', util.VN_CURDATE(), 1, 'First test message', 0, 0),
|
||||
(1101, '@PetterParker', util.VN_CURDATE(), 0, 'Second test message', 0, 0);
|
||||
(1101, '@PetterParker', util.VN_CURDATE(), 1, 'First test message', 0, 'sent'),
|
||||
(1101, '@PetterParker', util.VN_CURDATE(), 0, 'Second test message', 0, 'pending');
|
||||
|
||||
|
||||
INSERT INTO `vn`.`mobileAppVersionControl` (`appName`, `version`, `isVersionCritical`)
|
||||
|
@ -2832,4 +2840,27 @@ INSERT INTO `vn`.`workerTimeControlMail` (`id`, `workerFk`, `year`, `week`, `sta
|
|||
(3, 9, 2000, 51, 'CONFIRMED', util.VN_NOW(), 1, NULL),
|
||||
(4, 9, 2001, 1, 'SENDED', util.VN_NOW(), 1, NULL);
|
||||
|
||||
INSERT INTO `vn`.`wagonConfig` (`id`, `width`, `height`, `maxWagonHeight`, `minHeightBetweenTrays`, `maxTrays`)
|
||||
VALUES
|
||||
(1, 1350, 1900, 200, 50, 6);
|
||||
|
||||
INSERT INTO `vn`.`wagonTypeColor` (`id`, `name`, `rgb`)
|
||||
VALUES
|
||||
(1, 'white', '#ffffff'),
|
||||
(2, 'red', '#ff0000'),
|
||||
(3, 'green', '#00ff00'),
|
||||
(4, 'blue', '#0000ff');
|
||||
|
||||
INSERT INTO `vn`.`wagonType` (`id`, `name`, `divisible`)
|
||||
VALUES
|
||||
(1, 'Wagon Type #1', 1);
|
||||
|
||||
INSERT INTO `vn`.`wagonTypeTray` (`id`, `typeFk`, `height`, `colorFk`)
|
||||
VALUES
|
||||
(1, 1, 100, 1),
|
||||
(2, 1, 50, 2),
|
||||
(3, 1, 0, 3);
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -524,7 +524,6 @@ export default {
|
|||
},
|
||||
itemLog: {
|
||||
anyLineCreated: 'vn-item-log > vn-log vn-tbody > vn-tr',
|
||||
fifthLineCreatedProperty: 'vn-item-log > vn-log vn-tbody > vn-tr:nth-child(5) table tr:nth-child(4) td.after',
|
||||
},
|
||||
ticketSummary: {
|
||||
header: 'vn-ticket-summary > vn-card > h5',
|
||||
|
@ -1040,7 +1039,6 @@ export default {
|
|||
boss: 'vn-worker-create vn-autocomplete[ng-model="$ctrl.worker.bossFk"]',
|
||||
role: 'vn-worker-create vn-autocomplete[ng-model="$ctrl.worker.roleFk"]',
|
||||
iban: 'vn-worker-create vn-textfield[ng-model="$ctrl.worker.iban"]',
|
||||
switft: 'vn-worker-create vn-autocomplete[ng-model="$ctrl.worker.bankEntityFk"]',
|
||||
createButton: 'vn-worker-create vn-submit[label="Create"]',
|
||||
},
|
||||
workerPda: {
|
||||
|
@ -1129,6 +1127,15 @@ export default {
|
|||
saveButton: 'vn-invoice-in-tax vn-submit',
|
||||
|
||||
},
|
||||
invoiceInIndex: {
|
||||
topbarSearchParams: 'vn-searchbar div.search-params > span',
|
||||
},
|
||||
invoiceInSerial: {
|
||||
daysAgo: 'vn-invoice-in-serial-search-panel vn-input-number[ng-model="$ctrl.filter.daysAgo"]',
|
||||
serial: 'vn-invoice-in-serial-search-panel vn-textfield[ng-model="$ctrl.filter.serial"]',
|
||||
chip: 'vn-chip > vn-icon',
|
||||
goToIndex: 'vn-invoice-in-serial vn-icon-button[icon="icon-invoice-in"]',
|
||||
},
|
||||
travelIndex: {
|
||||
anySearchResult: 'vn-travel-index vn-tbody > a',
|
||||
firstSearchResult: 'vn-travel-index vn-tbody > a:nth-child(1)',
|
||||
|
@ -1140,7 +1147,16 @@ export default {
|
|||
landingDate: 'vn-travel-create vn-date-picker[ng-model="$ctrl.travel.landed"]',
|
||||
warehouseOut: 'vn-travel-create vn-autocomplete[ng-model="$ctrl.travel.warehouseOutFk"]',
|
||||
warehouseIn: 'vn-travel-create vn-autocomplete[ng-model="$ctrl.travel.warehouseInFk"]',
|
||||
save: 'vn-travel-create vn-submit > button'
|
||||
save: 'vn-travel-create vn-submit > button',
|
||||
generalSearchFilter: 'vn-travel-search-panel vn-textfield[ng-model="$ctrl.search"]',
|
||||
agencyFilter: 'vn-travel-search-panel vn-autocomplete[ng-model="$ctrl.filter.agencyModeFk"]',
|
||||
warehouseOutFilter: 'vn-travel-search-panel vn-autocomplete[ng-model="$ctrl.filter.warehouseOutFk"]',
|
||||
warehouseInFilter: 'vn-travel-search-panel vn-autocomplete[ng-model="$ctrl.filter.warehouseInFk"]',
|
||||
scopeDaysFilter: 'vn-travel-search-panel vn-input-number[ng-model="$ctrl.filter.scopeDays"]',
|
||||
continentFilter: 'vn-travel-search-panel vn-autocomplete[ng-model="$ctrl.filter.continent"]',
|
||||
totalEntriesFilter: 'vn-travel-search-panel vn-input-number[ng-model="$ctrl.totalEntries"]',
|
||||
chip: 'vn-travel-search-panel vn-chip > vn-icon',
|
||||
|
||||
},
|
||||
travelExtraCommunity: {
|
||||
anySearchResult: 'vn-travel-extra-community > vn-card div > tbody > tr[ng-attr-id="{{::travel.id}}"]',
|
||||
|
|
|
@ -27,7 +27,7 @@ describe('Worker time control path', () => {
|
|||
date.setMonth(date.getMonth() + 1);
|
||||
let month = date.toLocaleString('default', {month: 'long'});
|
||||
|
||||
await page.click(selectors.workerTimeControl.nextMonthButton);
|
||||
await page.waitToClick(selectors.workerTimeControl.nextMonthButton);
|
||||
let result = await page.getProperty(selectors.workerTimeControl.monthName, 'innerText');
|
||||
|
||||
expect(result).toContain(month);
|
||||
|
@ -36,7 +36,7 @@ describe('Worker time control path', () => {
|
|||
date.setDate(1);
|
||||
month = date.toLocaleString('default', {month: 'long'});
|
||||
|
||||
await page.click(selectors.workerTimeControl.previousMonthButton);
|
||||
await page.waitToClick(selectors.workerTimeControl.previousMonthButton);
|
||||
result = await page.getProperty(selectors.workerTimeControl.monthName, 'innerText');
|
||||
|
||||
expect(result).toContain(month);
|
||||
|
@ -49,7 +49,7 @@ describe('Worker time control path', () => {
|
|||
|
||||
await page.loginAndModule('salesBoss', 'worker');
|
||||
await page.goto(`http://localhost:5000/#!/worker/${hankPymId}/time-control?timestamp=${timestamp}`);
|
||||
await page.click(selectors.workerTimeControl.secondWeekDay);
|
||||
await page.waitToClick(selectors.workerTimeControl.secondWeekDay);
|
||||
|
||||
result = await page.getProperty(selectors.workerTimeControl.monthName, 'innerText');
|
||||
|
||||
|
|
|
@ -26,7 +26,6 @@ describe('Worker create path', () => {
|
|||
await page.write(selectors.workerCreate.street, 'S/ Doomstadt');
|
||||
await page.write(selectors.workerCreate.email, 'doctorDoom@marvel.com');
|
||||
await page.write(selectors.workerCreate.iban, 'ES9121000418450200051332');
|
||||
await page.autocompleteSearch(selectors.workerCreate.switft, 'BBKKESMMMMM');
|
||||
|
||||
// should check for autocompleted worker code and worker user name
|
||||
const workerCode = await page
|
||||
|
|
|
@ -48,14 +48,14 @@ describe('Item log path', () => {
|
|||
await page.accessToSection('item.card.log');
|
||||
});
|
||||
|
||||
it(`should confirm the log is showing 5 entries`, async() => {
|
||||
it(`should confirm the log is showing 4 entries`, async() => {
|
||||
await page.waitForSelector(selectors.itemLog.anyLineCreated);
|
||||
const anyLineCreatedCount = await page.countElement(selectors.itemLog.anyLineCreated);
|
||||
|
||||
expect(anyLineCreatedCount).toEqual(5);
|
||||
expect(anyLineCreatedCount).toEqual(4);
|
||||
});
|
||||
|
||||
it(`should confirm the log is showing the intrastat for the created item`, async() => {
|
||||
xit(`should confirm the log is showing the intrastat for the created item`, async() => {
|
||||
const fifthLineCreatedProperty = await page
|
||||
.waitToGetProperty(selectors.itemLog.fifthLineCreatedProperty, 'innerText');
|
||||
|
||||
|
|
|
@ -197,6 +197,7 @@ describe('Ticket Edit sale path', () => {
|
|||
});
|
||||
|
||||
it('should check in the history that logs has been added', async() => {
|
||||
pending('https://redmine.verdnatura.es/issues/5455');
|
||||
await page.reload({waitUntil: ['networkidle0', 'domcontentloaded']});
|
||||
await page.waitToClick(selectors.ticketSales.firstSaleHistoryButton);
|
||||
await page.waitForSelector(selectors.ticketSales.firstSaleHistory);
|
||||
|
|
|
@ -9,7 +9,7 @@ describe('Ticket Create notes path', () => {
|
|||
browser = await getBrowser();
|
||||
page = browser.page;
|
||||
await page.loginAndModule('employee', 'ticket');
|
||||
await page.accessToSearchResult('1');
|
||||
await page.accessToSearchResult('5');
|
||||
await page.accessToSection('ticket.card.observation');
|
||||
});
|
||||
|
||||
|
|
|
@ -54,7 +54,7 @@ describe('Ticket Future path', () => {
|
|||
it('should search with the origin IPT', async() => {
|
||||
await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton);
|
||||
|
||||
await page.autocompleteSearch(selectors.ticketFuture.ipt, 'Horizontal');
|
||||
await page.autocompleteSearch(selectors.ticketFuture.ipt, 'H');
|
||||
await page.waitToClick(selectors.ticketFuture.submit);
|
||||
|
||||
expect(httpRequest).toContain('ipt=H');
|
||||
|
@ -65,7 +65,7 @@ describe('Ticket Future path', () => {
|
|||
|
||||
await page.clearInput(selectors.ticketFuture.ipt);
|
||||
|
||||
await page.autocompleteSearch(selectors.ticketFuture.futureIpt, 'Horizontal');
|
||||
await page.autocompleteSearch(selectors.ticketFuture.futureIpt, 'H');
|
||||
await page.waitToClick(selectors.ticketFuture.submit);
|
||||
|
||||
expect(httpRequest).toContain('futureIpt=H');
|
||||
|
@ -108,7 +108,7 @@ describe('Ticket Future path', () => {
|
|||
|
||||
it('should search in smart-table with an IPT Destination', async() => {
|
||||
await page.waitToClick(selectors.ticketFuture.tableButtonSearch);
|
||||
await page.autocompleteSearch(selectors.ticketFuture.tableFutureIpt, 'Horizontal');
|
||||
await page.autocompleteSearch(selectors.ticketFuture.tableFutureIpt, 'H');
|
||||
|
||||
expect(httpRequest).toContain('futureIpt');
|
||||
await page.waitToClick(selectors.ticketFuture.tableButtonSearch);
|
||||
|
|
|
@ -54,7 +54,7 @@ describe('Ticket Advance path', () => {
|
|||
|
||||
it('should search with the origin IPT', async() => {
|
||||
await page.waitToClick(selectors.ticketAdvance.openAdvancedSearchButton);
|
||||
await page.autocompleteSearch(selectors.ticketAdvance.futureIpt, 'Horizontal');
|
||||
await page.autocompleteSearch(selectors.ticketAdvance.futureIpt, 'H');
|
||||
await page.waitToClick(selectors.ticketAdvance.submit);
|
||||
|
||||
expect(httpRequest).toContain('futureIpt=H');
|
||||
|
@ -66,7 +66,7 @@ describe('Ticket Advance path', () => {
|
|||
|
||||
it('should search with the destination IPT', async() => {
|
||||
await page.waitToClick(selectors.ticketAdvance.openAdvancedSearchButton);
|
||||
await page.autocompleteSearch(selectors.ticketAdvance.ipt, 'Horizontal');
|
||||
await page.autocompleteSearch(selectors.ticketAdvance.ipt, 'H');
|
||||
await page.waitToClick(selectors.ticketAdvance.submit);
|
||||
|
||||
expect(httpRequest).toContain('ipt=H');
|
||||
|
@ -78,7 +78,7 @@ describe('Ticket Advance path', () => {
|
|||
|
||||
it('should search in smart-table with an IPT Origin', async() => {
|
||||
await page.waitToClick(selectors.ticketAdvance.tableButtonSearch);
|
||||
await page.autocompleteSearch(selectors.ticketAdvance.tableFutureIpt, 'Vertical');
|
||||
await page.autocompleteSearch(selectors.ticketAdvance.tableFutureIpt, 'V');
|
||||
|
||||
expect(httpRequest).toContain('futureIpt');
|
||||
|
||||
|
@ -89,7 +89,7 @@ describe('Ticket Advance path', () => {
|
|||
|
||||
it('should search in smart-table with an IPT Destination', async() => {
|
||||
await page.waitToClick(selectors.ticketAdvance.tableButtonSearch);
|
||||
await page.autocompleteSearch(selectors.ticketAdvance.tableIpt, 'Vertical');
|
||||
await page.autocompleteSearch(selectors.ticketAdvance.tableIpt, 'V');
|
||||
|
||||
expect(httpRequest).toContain('ipt');
|
||||
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
import selectors from '../../helpers/selectors.js';
|
||||
import getBrowser from '../../helpers/puppeteer';
|
||||
|
||||
describe('InvoiceIn serial path', () => {
|
||||
let browser;
|
||||
let page;
|
||||
let httpRequest;
|
||||
|
||||
beforeAll(async() => {
|
||||
browser = await getBrowser();
|
||||
page = browser.page;
|
||||
await page.loginAndModule('administrative', 'invoiceIn');
|
||||
await page.accessToSection('invoiceIn.serial');
|
||||
page.on('request', req => {
|
||||
if (req.url().includes(`InvoiceIns/getSerial`))
|
||||
httpRequest = req.url();
|
||||
});
|
||||
});
|
||||
|
||||
afterAll(async() => {
|
||||
await browser.close();
|
||||
});
|
||||
|
||||
it('should check that passes the correct params to back', async() => {
|
||||
await page.overwrite(selectors.invoiceInSerial.daysAgo, '30');
|
||||
await page.keyboard.press('Enter');
|
||||
|
||||
expect(httpRequest).toContain('daysAgo=30');
|
||||
|
||||
await page.overwrite(selectors.invoiceInSerial.serial, 'R');
|
||||
await page.keyboard.press('Enter');
|
||||
|
||||
expect(httpRequest).toContain('serial=R');
|
||||
await page.click(selectors.invoiceInSerial.chip);
|
||||
});
|
||||
|
||||
it('should go to index and check if the search-panel has the correct params', async() => {
|
||||
await page.click(selectors.invoiceInSerial.goToIndex);
|
||||
const params = await page.$$(selectors.invoiceInIndex.topbarSearchParams);
|
||||
const serial = await params[0].getProperty('title');
|
||||
const isBooked = await params[1].getProperty('title');
|
||||
const from = await params[2].getProperty('title');
|
||||
|
||||
expect(await serial.jsonValue()).toContain('serial');
|
||||
expect(await isBooked.jsonValue()).toContain('not isBooked');
|
||||
expect(await from.jsonValue()).toContain('from');
|
||||
});
|
||||
});
|
|
@ -9,7 +9,8 @@ describe('Travel basic data path', () => {
|
|||
browser = await getBrowser();
|
||||
page = browser.page;
|
||||
await page.loginAndModule('buyer', 'travel');
|
||||
await page.accessToSearchResult('3');
|
||||
await page.write(selectors.travelIndex.generalSearchFilter, '3');
|
||||
await page.keyboard.press('Enter');
|
||||
await page.accessToSection('travel.card.basicData');
|
||||
});
|
||||
|
||||
|
@ -89,11 +90,13 @@ describe('Travel basic data path', () => {
|
|||
});
|
||||
|
||||
it('should navigate to the travel logs', async() => {
|
||||
pending('https://redmine.verdnatura.es/issues/5455');
|
||||
await page.accessToSection('travel.card.log');
|
||||
await page.waitForState('travel.card.log');
|
||||
});
|
||||
|
||||
it('should check the 1st log contains details from the changes made', async() => {
|
||||
pending('https://redmine.verdnatura.es/issues/5455');
|
||||
const result = await page.waitToGetProperty(selectors.travelLog.firstLogFirstTD, 'innerText');
|
||||
|
||||
expect(result).toContain('new reference!');
|
||||
|
|
|
@ -9,7 +9,8 @@ describe('Travel descriptor path', () => {
|
|||
browser = await getBrowser();
|
||||
page = browser.page;
|
||||
await page.loginAndModule('buyer', 'travel');
|
||||
await page.accessToSearchResult('1');
|
||||
await page.write(selectors.travelIndex.generalSearchFilter, '1');
|
||||
await page.keyboard.press('Enter');
|
||||
await page.waitForState('travel.card.summary');
|
||||
});
|
||||
|
||||
|
@ -81,7 +82,8 @@ describe('Travel descriptor path', () => {
|
|||
await page.waitToClick('.cancel');
|
||||
await page.waitToClick(selectors.globalItems.homeButton);
|
||||
await page.selectModule('travel');
|
||||
await page.accessToSearchResult('3');
|
||||
await page.write(selectors.travelIndex.generalSearchFilter, '3');
|
||||
await page.keyboard.press('Enter');
|
||||
await page.waitForState('travel.card.summary');
|
||||
const state = await page.getState();
|
||||
|
||||
|
|
|
@ -10,7 +10,8 @@ describe('Travel thermograph path', () => {
|
|||
browser = await getBrowser();
|
||||
page = browser.page;
|
||||
await page.loginAndModule('buyer', 'travel');
|
||||
await page.accessToSearchResult('3');
|
||||
await page.write(selectors.travelIndex.generalSearchFilter, '3');
|
||||
await page.keyboard.press('Enter');
|
||||
await page.accessToSection('travel.card.thermograph.index');
|
||||
});
|
||||
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
import selectors from '../../helpers/selectors.js';
|
||||
import getBrowser from '../../helpers/puppeteer';
|
||||
|
||||
describe('Travel search panel path', () => {
|
||||
let browser;
|
||||
let page;
|
||||
let httpRequest;
|
||||
|
||||
beforeAll(async() => {
|
||||
browser = await getBrowser();
|
||||
page = browser.page;
|
||||
await page.loginAndModule('buyer', 'travel');
|
||||
page.on('request', req => {
|
||||
if (req.url().includes(`Travels/filter`))
|
||||
httpRequest = req.url();
|
||||
});
|
||||
});
|
||||
|
||||
afterAll(async() => {
|
||||
await browser.close();
|
||||
});
|
||||
|
||||
it('should filter using all the fields', async() => {
|
||||
await page.click(selectors.travelIndex.chip);
|
||||
await page.write(selectors.travelIndex.generalSearchFilter, 'travel');
|
||||
await page.keyboard.press('Enter');
|
||||
|
||||
expect(httpRequest).toContain('search=travel');
|
||||
|
||||
await page.click(selectors.travelIndex.chip);
|
||||
await page.autocompleteSearch(selectors.travelIndex.agencyFilter, 'Entanglement');
|
||||
|
||||
expect(httpRequest).toContain('agencyModeFk');
|
||||
|
||||
await page.click(selectors.travelIndex.chip);
|
||||
await page.autocompleteSearch(selectors.travelIndex.warehouseOutFilter, 'Warehouse One');
|
||||
|
||||
expect(httpRequest).toContain('warehouseOutFk');
|
||||
|
||||
await page.click(selectors.travelIndex.chip);
|
||||
await page.autocompleteSearch(selectors.travelIndex.warehouseInFilter, 'Warehouse Two');
|
||||
|
||||
expect(httpRequest).toContain('warehouseInFk');
|
||||
|
||||
await page.click(selectors.travelIndex.chip);
|
||||
await page.overwrite(selectors.travelIndex.scopeDaysFilter, '15');
|
||||
await page.keyboard.press('Enter');
|
||||
|
||||
expect(httpRequest).toContain('scopeDays=15');
|
||||
|
||||
await page.click(selectors.travelIndex.chip);
|
||||
await page.autocompleteSearch(selectors.travelIndex.continentFilter, 'Asia');
|
||||
|
||||
expect(httpRequest).toContain('continent');
|
||||
|
||||
await page.click(selectors.travelIndex.chip);
|
||||
await page.write(selectors.travelIndex.totalEntriesFilter, '1');
|
||||
await page.keyboard.press('Enter');
|
||||
|
||||
expect(httpRequest).toContain('totalEntries=1');
|
||||
});
|
||||
});
|
|
@ -114,12 +114,14 @@ export default class Calendar extends FormInput {
|
|||
let day = date.getDate();
|
||||
let wday = date.getDay();
|
||||
let month = date.getMonth();
|
||||
let year = date.getFullYear();
|
||||
|
||||
const currentDay = Date.vnNew().getDate();
|
||||
const currentMonth = Date.vnNew().getMonth();
|
||||
const currentYear = Date.vnNew().getFullYear();
|
||||
|
||||
let classes = {
|
||||
today: day === currentDay && month === currentMonth,
|
||||
today: day === currentDay && month === currentMonth && year === currentYear,
|
||||
weekend: wday === 6 || wday === 0,
|
||||
previous: month < this.month,
|
||||
current: month == this.month,
|
||||
|
|
|
@ -26,7 +26,7 @@ Value should have at most %s characters: El valor debe tener un máximo de %s ca
|
|||
Enter a new search: Introduce una nueva búsqueda
|
||||
No results: Sin resultados
|
||||
Ups! It seems there was an error: ¡Vaya! Parece que ha habido un error
|
||||
General search: Busqueda general
|
||||
General search: Búsqueda general
|
||||
January: Enero
|
||||
February: Febrero
|
||||
March: Marzo
|
||||
|
@ -42,9 +42,9 @@ December: Diciembre
|
|||
Monday: Lunes
|
||||
Tuesday: Martes
|
||||
Wednesday: Miércoles
|
||||
Thursday: Jueves
|
||||
Friday: Viernes
|
||||
Saturday: Sábado
|
||||
Thursday: Jueves
|
||||
Friday: Viernes
|
||||
Saturday: Sábado
|
||||
Sunday: Domingo
|
||||
Has delivery: Hay reparto
|
||||
Loading: Cargando
|
||||
|
@ -63,4 +63,4 @@ Loading...: Cargando...
|
|||
No results found: Sin resultados
|
||||
No data: Sin datos
|
||||
Undo changes: Deshacer cambios
|
||||
Load more results: Cargar más resultados
|
||||
Load more results: Cargar más resultados
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
$font-size: 11pt;
|
||||
$menu-width: 256px;
|
||||
$right-menu-width: 318px;
|
||||
$topbar-height: 56px;
|
||||
$mobile-width: 800px;
|
||||
$float-spacing: 20px;
|
||||
|
|
|
@ -88,13 +88,13 @@ vn-layout {
|
|||
}
|
||||
&.right-menu {
|
||||
& > vn-topbar > .end {
|
||||
width: 80px + $menu-width;
|
||||
width: 80px + $right-menu-width;
|
||||
}
|
||||
& > .main-view {
|
||||
padding-right: $menu-width;
|
||||
padding-right: $right-menu-width;
|
||||
}
|
||||
[fixed-bottom-right] {
|
||||
right: $menu-width;
|
||||
right: $right-menu-width;
|
||||
}
|
||||
}
|
||||
& > .main-view {
|
||||
|
|
|
@ -270,5 +270,6 @@
|
|||
"Warehouse inventory not set": "El almacén inventario no está establecido",
|
||||
"This locker has already been assigned": "Esta taquilla ya ha sido asignada",
|
||||
"Tickets with associated refunds": "No se pueden borrar tickets con abonos asociados. Este ticket está asociado al abono Nº {{id}}",
|
||||
"Not exist this branch": "La rama no existe"
|
||||
"Not exist this branch": "La rama no existe",
|
||||
"This ticket cannot be signed because it has not been boxed": "Este ticket no puede firmarse porque no ha sido encajado"
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
const models = require('vn-loopback/server/server').models;
|
||||
const LoopBackContext = require('loopback-context');
|
||||
|
||||
describe('claim regularizeClaim()', () => {
|
||||
const userId = 18;
|
||||
|
@ -39,6 +40,20 @@ describe('claim regularizeClaim()', () => {
|
|||
return await models.ClaimEnd.create(claimEnds, options);
|
||||
}
|
||||
|
||||
beforeAll(async() => {
|
||||
const activeCtx = {
|
||||
accessToken: {userId: 9},
|
||||
http: {
|
||||
req: {
|
||||
headers: {origin: 'http://localhost'}
|
||||
}
|
||||
}
|
||||
};
|
||||
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
|
||||
active: activeCtx
|
||||
});
|
||||
});
|
||||
|
||||
it('should send a chat message with value "Trash" and then change claim state to resolved', async() => {
|
||||
const tx = await models.Claim.beginTransaction({});
|
||||
|
||||
|
|
|
@ -82,6 +82,11 @@
|
|||
"type": "hasMany",
|
||||
"model": "ClaimDms",
|
||||
"foreignKey": "claimFk"
|
||||
},
|
||||
"lines": {
|
||||
"type": "hasMany",
|
||||
"model": "ClaimBeginning",
|
||||
"foreignKey": "claimFk"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,8 @@ describe('claim', () => {
|
|||
controller = $componentController('vnClaimDetail', {$element, $scope});
|
||||
controller.claim = {
|
||||
ticketFk: 1,
|
||||
id: 2}
|
||||
id: 2,
|
||||
claimStateFk: 2}
|
||||
;
|
||||
controller.salesToClaim = [{saleFk: 1}, {saleFk: 2}];
|
||||
controller.salesClaimed = [{id: 1, sale: {}}];
|
||||
|
|
|
@ -1,49 +0,0 @@
|
|||
|
||||
const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
|
||||
|
||||
module.exports = Self => {
|
||||
Self.remoteMethod('getTransactions', {
|
||||
description: 'Returns last entries',
|
||||
accessType: 'READ',
|
||||
accepts: [{
|
||||
arg: 'filter',
|
||||
type: 'object',
|
||||
description: 'Filter defining where, order, offset, and limit - must be a JSON-encoded string',
|
||||
http: {source: 'query'}
|
||||
}],
|
||||
returns: {
|
||||
type: ['object'],
|
||||
root: true
|
||||
},
|
||||
http: {
|
||||
path: `/getTransactions`,
|
||||
verb: 'GET'
|
||||
}
|
||||
});
|
||||
|
||||
Self.getTransactions = async(filter, options) => {
|
||||
const myOptions = {};
|
||||
|
||||
if (typeof options == 'object')
|
||||
Object.assign(myOptions, options);
|
||||
|
||||
const conn = Self.dataSource.connector;
|
||||
const stmt = new ParameterizedSQL(`
|
||||
SELECT
|
||||
t.id,
|
||||
t.clientFk,
|
||||
t.created,
|
||||
t.amount / 100 amount,
|
||||
t.receiptFk IS NOT NULL AS isConfirmed,
|
||||
tt.message responseMessage,
|
||||
te.message errorMessage
|
||||
FROM hedera.tpvTransaction t
|
||||
JOIN hedera.tpvMerchant m ON m.id = t.merchantFk
|
||||
LEFT JOIN hedera.tpvResponse tt ON tt.id = t.response
|
||||
LEFT JOIN hedera.tpvError te ON te.code = errorCode`);
|
||||
|
||||
stmt.merge(conn.makeSuffix(filter, 't'));
|
||||
|
||||
return Self.rawStmt(stmt, myOptions);
|
||||
};
|
||||
};
|
|
@ -1,21 +0,0 @@
|
|||
const models = require('vn-loopback/server/server').models;
|
||||
|
||||
describe('Client getTransations', () => {
|
||||
it('should call getTransations() method to receive a list of Web Payments from Bruce Wayne', async() => {
|
||||
const tx = await models.Client.beginTransaction({});
|
||||
|
||||
try {
|
||||
const options = {transaction: tx};
|
||||
|
||||
const filter = {where: {clientFk: 1101}};
|
||||
const result = await models.Client.getTransactions(filter, options);
|
||||
|
||||
expect(result[1].id).toBeTruthy();
|
||||
|
||||
await tx.rollback();
|
||||
} catch (e) {
|
||||
await tx.rollback();
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
});
|
|
@ -0,0 +1,66 @@
|
|||
const models = require('vn-loopback/server/server').models;
|
||||
|
||||
describe('Client transactions', () => {
|
||||
it('should call transactions() method to receive a list of Web Payments from Bruce Wayne', async() => {
|
||||
const tx = await models.Client.beginTransaction({});
|
||||
|
||||
try {
|
||||
const options = {transaction: tx};
|
||||
|
||||
const ctx = {};
|
||||
const filter = {where: {clientFk: 1101}};
|
||||
const result = await models.Client.transactions(ctx, filter, options);
|
||||
|
||||
expect(result[1].id).toBeTruthy();
|
||||
|
||||
await tx.rollback();
|
||||
} catch (e) {
|
||||
await tx.rollback();
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
|
||||
it('should call transactions() method filtering by orderFk', async() => {
|
||||
const tx = await models.Client.beginTransaction({});
|
||||
|
||||
try {
|
||||
const options = {transaction: tx};
|
||||
|
||||
const ctx = {args: {orderFk: 6}};
|
||||
const filter = {};
|
||||
const result = await models.Client.transactions(ctx, filter, options);
|
||||
|
||||
const firstRow = result[0];
|
||||
|
||||
expect(result.length).toEqual(1);
|
||||
expect(firstRow.id).toEqual(6);
|
||||
|
||||
await tx.rollback();
|
||||
} catch (e) {
|
||||
await tx.rollback();
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
|
||||
it('should call transactions() method filtering by amount', async() => {
|
||||
const tx = await models.Client.beginTransaction({});
|
||||
|
||||
try {
|
||||
const options = {transaction: tx};
|
||||
|
||||
const ctx = {args: {amount: 40}};
|
||||
const filter = {};
|
||||
const result = await models.Client.transactions(ctx, filter, options);
|
||||
|
||||
const randomIndex = Math.floor(Math.random() * result.length);
|
||||
const transaction = result[randomIndex];
|
||||
|
||||
expect(transaction.amount).toEqual(40);
|
||||
|
||||
await tx.rollback();
|
||||
} catch (e) {
|
||||
await tx.rollback();
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
});
|
|
@ -0,0 +1,84 @@
|
|||
|
||||
const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
|
||||
const buildFilter = require('vn-loopback/util/filter').buildFilter;
|
||||
const mergeFilters = require('vn-loopback/util/filter').mergeFilters;
|
||||
|
||||
module.exports = Self => {
|
||||
Self.remoteMethodCtx('transactions', {
|
||||
description: 'Returns customer transactions',
|
||||
accessType: 'READ',
|
||||
accepts: [
|
||||
{
|
||||
arg: 'filter',
|
||||
type: 'object',
|
||||
description: 'Filter defining where, order, offset, and limit - must be a JSON-encoded string',
|
||||
http: {source: 'query'}
|
||||
},
|
||||
{
|
||||
arg: 'orderFk',
|
||||
type: 'number',
|
||||
http: {source: 'query'}
|
||||
},
|
||||
{
|
||||
arg: 'clientFk',
|
||||
type: 'number',
|
||||
http: {source: 'query'}
|
||||
},
|
||||
{
|
||||
arg: 'amount',
|
||||
type: 'number',
|
||||
http: {source: 'query'}
|
||||
}
|
||||
],
|
||||
returns: {
|
||||
type: ['object'],
|
||||
root: true
|
||||
},
|
||||
http: {
|
||||
path: `/transactions`,
|
||||
verb: 'GET'
|
||||
}
|
||||
});
|
||||
|
||||
Self.transactions = async(ctx, filter, options) => {
|
||||
const args = ctx.args;
|
||||
const myOptions = {};
|
||||
|
||||
if (typeof options == 'object')
|
||||
Object.assign(myOptions, options);
|
||||
|
||||
const where = buildFilter(args, (param, value) => {
|
||||
switch (param) {
|
||||
case 'orderFk':
|
||||
return {'t.id': value};
|
||||
case 'clientFk':
|
||||
return {'t.clientFk': value};
|
||||
case 'amount':
|
||||
return {'t.amount': (value * 100)};
|
||||
}
|
||||
});
|
||||
|
||||
filter = mergeFilters(filter, {where});
|
||||
|
||||
const conn = Self.dataSource.connector;
|
||||
const stmt = new ParameterizedSQL(`
|
||||
SELECT
|
||||
t.id,
|
||||
t.clientFk,
|
||||
c.name AS customerName,
|
||||
t.created,
|
||||
t.amount / 100 amount,
|
||||
t.receiptFk IS NOT NULL AS isConfirmed,
|
||||
tt.message responseMessage,
|
||||
te.message errorMessage
|
||||
FROM hedera.tpvTransaction t
|
||||
JOIN client c ON c.id = t.clientFk
|
||||
JOIN hedera.tpvMerchant m ON m.id = t.merchantFk
|
||||
LEFT JOIN hedera.tpvResponse tt ON tt.id = t.response
|
||||
LEFT JOIN hedera.tpvError te ON te.code = errorCode`);
|
||||
|
||||
stmt.merge(conn.makeSuffix(filter, 't'));
|
||||
|
||||
return Self.rawStmt(stmt, myOptions);
|
||||
};
|
||||
};
|
|
@ -13,7 +13,7 @@ module.exports = Self => {
|
|||
require('../methods/client/getCard')(Self);
|
||||
require('../methods/client/getDebt')(Self);
|
||||
require('../methods/client/getMana')(Self);
|
||||
require('../methods/client/getTransactions')(Self);
|
||||
require('../methods/client/transactions')(Self);
|
||||
require('../methods/client/hasCustomerRole')(Self);
|
||||
require('../methods/client/isValidClient')(Self);
|
||||
require('../methods/client/lastActiveTickets')(Self);
|
||||
|
|
|
@ -1,55 +1,39 @@
|
|||
<vn-crud-model
|
||||
vn-id="model"
|
||||
url="clients/getTransactions"
|
||||
link="{clientFk: $ctrl.$params.id}"
|
||||
limit="20"
|
||||
data="transactions"
|
||||
order="created DESC"
|
||||
auto-load="true">
|
||||
<vn-crud-model vn-id="model" url="clients/transactions" link="{clientFk: $ctrl.$params.id}" limit="20"
|
||||
data="transactions" order="created DESC" auto-load="true">
|
||||
</vn-crud-model>
|
||||
<vn-data-viewer
|
||||
model="model"
|
||||
class="vn-w-md">
|
||||
<vn-data-viewer model="model" class="vn-w-md">
|
||||
<vn-card>
|
||||
<vn-table model="model">
|
||||
<vn-thead>
|
||||
<vn-tr>
|
||||
<vn-th shrink>State</vn-th>
|
||||
<vn-th field="id" number>Id</vn-th>
|
||||
<vn-th field="created" expand>Date</vn-th>
|
||||
<vn-th field="amount" number>Amount</vn-th>
|
||||
<vn-th shrink></vn-th>
|
||||
</vn-tr>
|
||||
</vn-thead>
|
||||
<vn-tbody>
|
||||
<vn-tr ng-repeat="transaction in transactions">
|
||||
<vn-td shrink>
|
||||
<vn-icon
|
||||
vn-tooltip="{{::$ctrl.getFormattedMessage(transaction)}}"
|
||||
ng-show="::((transaction.errorMessage || transaction.responseMessage) && !transaction.isConfirmed)"
|
||||
icon="clear">
|
||||
</vn-icon>
|
||||
<vn-icon
|
||||
vn-tooltip="Confirmed"
|
||||
ng-show="::(transaction.isConfirmed)"
|
||||
icon="check">
|
||||
</vn-icon>
|
||||
</vn-td>
|
||||
<vn-td number>{{::transaction.id}}</vn-td>
|
||||
<vn-td>{{::transaction.created | date:'dd/MM/yyyy HH:mm'}}</vn-td>
|
||||
<vn-td number>{{::transaction.amount | currency: 'EUR':2}}</vn-td>
|
||||
<vn-td shrink>
|
||||
<vn-icon-button
|
||||
icon="done_all"
|
||||
vn-acl="administrative"
|
||||
vn-acl-action="remove"
|
||||
translate-attr="{title: 'Confirm transaction'}"
|
||||
ng-show="::!transaction.isConfirmed"
|
||||
ng-click="$ctrl.confirm(transaction)">
|
||||
</vn-icon-button>
|
||||
</vn-td>
|
||||
</vn-tr>
|
||||
</vn-tbody>
|
||||
</vn-table>
|
||||
<vn-table model="model">
|
||||
<vn-thead>
|
||||
<vn-tr>
|
||||
<vn-th shrink>State</vn-th>
|
||||
<vn-th field="id" number>Id</vn-th>
|
||||
<vn-th field="created" expand>Date</vn-th>
|
||||
<vn-th field="amount" number>Amount</vn-th>
|
||||
<vn-th shrink></vn-th>
|
||||
</vn-tr>
|
||||
</vn-thead>
|
||||
<vn-tbody>
|
||||
<vn-tr ng-repeat="transaction in transactions">
|
||||
<vn-td shrink>
|
||||
<vn-icon vn-tooltip="{{::$ctrl.getFormattedMessage(transaction)}}"
|
||||
ng-show="::((transaction.errorMessage || transaction.responseMessage) && !transaction.isConfirmed)"
|
||||
icon="clear">
|
||||
</vn-icon>
|
||||
<vn-icon vn-tooltip="Confirmed" ng-show="::(transaction.isConfirmed)" icon="check">
|
||||
</vn-icon>
|
||||
</vn-td>
|
||||
<vn-td number>{{::transaction.id}}</vn-td>
|
||||
<vn-td>{{::transaction.created | date:'dd/MM/yyyy HH:mm'}}</vn-td>
|
||||
<vn-td number>{{::transaction.amount | currency: 'EUR':2}}</vn-td>
|
||||
<vn-td shrink>
|
||||
<vn-icon-button icon="done_all" vn-acl="administrative" vn-acl-action="remove"
|
||||
translate-attr="{title: 'Confirm transaction'}" ng-show="::!transaction.isConfirmed"
|
||||
ng-click="$ctrl.confirm(transaction)">
|
||||
</vn-icon-button>
|
||||
</vn-td>
|
||||
</vn-tr>
|
||||
</vn-tbody>
|
||||
</vn-table>
|
||||
</vn-card>
|
||||
</vn-data-viewer>
|
|
@ -1,6 +1,22 @@
|
|||
const models = require('vn-loopback/server/server').models;
|
||||
const LoopBackContext = require('loopback-context');
|
||||
|
||||
describe('Buy editLatestsBuys()', () => {
|
||||
beforeAll(async() => {
|
||||
const activeCtx = {
|
||||
accessToken: {userId: 9},
|
||||
http: {
|
||||
req: {
|
||||
headers: {origin: 'http://localhost'}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
|
||||
active: activeCtx
|
||||
});
|
||||
});
|
||||
|
||||
it('should change the value of a given column for the selected buys', async() => {
|
||||
const tx = await models.Buy.beginTransaction({});
|
||||
const options = {transaction: tx};
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
|
||||
const buildFilter = require('vn-loopback/util/filter').buildFilter;
|
||||
const mergeFilters = require('vn-loopback/util/filter').mergeFilters;
|
||||
|
||||
module.exports = Self => {
|
||||
Self.remoteMethodCtx('getSerial', {
|
||||
description: 'Return invoiceIn serial',
|
||||
accessType: 'READ',
|
||||
accepts: [{
|
||||
arg: 'filter',
|
||||
type: 'object'
|
||||
}, {
|
||||
arg: 'daysAgo',
|
||||
type: 'number',
|
||||
required: true
|
||||
}, {
|
||||
arg: 'serial',
|
||||
type: 'string'
|
||||
}],
|
||||
returns: {
|
||||
type: 'object',
|
||||
root: true
|
||||
},
|
||||
http: {
|
||||
path: '/getSerial',
|
||||
verb: 'GET'
|
||||
}
|
||||
});
|
||||
|
||||
Self.getSerial = async(ctx, options) => {
|
||||
const conn = Self.dataSource.connector;
|
||||
const args = ctx.args;
|
||||
const myOptions = {};
|
||||
|
||||
if (typeof options == 'object')
|
||||
Object.assign(myOptions, options);
|
||||
|
||||
const issued = Date.vnNew();
|
||||
const where = buildFilter(args, (param, value) => {
|
||||
switch (param) {
|
||||
case 'daysAgo':
|
||||
issued.setDate(issued.getDate() - value);
|
||||
return {'i.issued': {gte: issued}};
|
||||
case 'serial':
|
||||
return {'i.serial': {like: `%${value}%`}};
|
||||
}
|
||||
});
|
||||
|
||||
filter = mergeFilters(args.filter, {where});
|
||||
|
||||
const stmt = new ParameterizedSQL(
|
||||
`SELECT i.serial, SUM(IF(i.isBooked, 0,1)) pending, COUNT(*) total
|
||||
FROM vn.invoiceIn i`
|
||||
);
|
||||
|
||||
stmt.merge(conn.makeWhere(filter.where));
|
||||
stmt.merge(`GROUP BY i.serial`);
|
||||
stmt.merge(conn.makeOrderBy(filter.order));
|
||||
stmt.merge(conn.makeLimit(filter));
|
||||
|
||||
const result = await conn.executeStmt(stmt, myOptions);
|
||||
|
||||
return result;
|
||||
};
|
||||
};
|
|
@ -0,0 +1,24 @@
|
|||
const models = require('vn-loopback/server/server').models;
|
||||
|
||||
describe('invoiceIn getSerial()', () => {
|
||||
it('should check that returns without serial param', async() => {
|
||||
const ctx = {args: {daysAgo: 45}};
|
||||
const result = await models.InvoiceIn.getSerial(ctx);
|
||||
|
||||
expect(result.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it('should check that returns with serial param', async() => {
|
||||
const ctx = {args: {daysAgo: 45, serial: 'R'}};
|
||||
const result = await models.InvoiceIn.getSerial(ctx);
|
||||
|
||||
expect(result.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it('should check that returns with non exist serial param', async() => {
|
||||
const ctx = {args: {daysAgo: 45, serial: 'Mock serial'}};
|
||||
const result = await models.InvoiceIn.getSerial(ctx);
|
||||
|
||||
expect(result.length).toEqual(0);
|
||||
});
|
||||
});
|
|
@ -17,6 +17,9 @@
|
|||
},
|
||||
"retentionName": {
|
||||
"type": "string"
|
||||
},
|
||||
"daysAgo": {
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
"relations": {
|
||||
|
|
|
@ -6,4 +6,5 @@ module.exports = Self => {
|
|||
require('../methods/invoice-in/getTotals')(Self);
|
||||
require('../methods/invoice-in/invoiceInPdf')(Self);
|
||||
require('../methods/invoice-in/invoiceInEmail')(Self);
|
||||
require('../methods/invoice-in/getSerial')(Self);
|
||||
};
|
||||
|
|
|
@ -13,3 +13,5 @@ import './dueDay';
|
|||
import './intrastat';
|
||||
import './create';
|
||||
import './log';
|
||||
import './serial';
|
||||
import './serial-search-panel';
|
||||
|
|
|
@ -7,6 +7,7 @@ Foreign value: Divisa
|
|||
InvoiceIn: Facturas recibidas
|
||||
InvoiceIn cloned: Factura clonada
|
||||
InvoiceIn deleted: Factura eliminada
|
||||
InvoiceIn Serial: Facturas por series
|
||||
Invoice list: Listado de facturas recibidas
|
||||
InvoiceIn booked: Factura contabilizada
|
||||
Net: Neto
|
||||
|
@ -22,3 +23,4 @@ Total stems: Total tallos
|
|||
Show agricultural receipt as PDF: Ver recibo agrícola como PDF
|
||||
Send agricultural receipt as PDF: Enviar recibo agrícola como PDF
|
||||
New InvoiceIn: Nueva Factura
|
||||
Days ago: Últimos días
|
||||
|
|
|
@ -12,6 +12,10 @@
|
|||
{
|
||||
"state": "invoiceIn.index",
|
||||
"icon": "icon-invoice-in"
|
||||
},
|
||||
{
|
||||
"state": "invoiceIn.serial",
|
||||
"icon": "icon-invoice-in"
|
||||
}
|
||||
],
|
||||
"card": [
|
||||
|
@ -54,6 +58,15 @@
|
|||
"administrative"
|
||||
]
|
||||
},
|
||||
{
|
||||
"url": "/serial",
|
||||
"state": "invoiceIn.serial",
|
||||
"component": "vn-invoice-in-serial",
|
||||
"description": "InvoiceIn Serial",
|
||||
"acl": [
|
||||
"administrative"
|
||||
]
|
||||
},
|
||||
{
|
||||
"url": "/:id",
|
||||
"state": "invoiceIn.card",
|
||||
|
@ -133,4 +146,4 @@
|
|||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
<vn-side-menu side="right">
|
||||
<vn-horizontal class="input">
|
||||
<vn-input-number
|
||||
label="Days ago"
|
||||
ng-model="$ctrl.filter.daysAgo"
|
||||
vn-focus
|
||||
ng-keydown="$ctrl.onKeyPress($event)"
|
||||
min="0">
|
||||
</vn-input-number>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal class="input">
|
||||
<vn-textfield
|
||||
label="Serial"
|
||||
ng-model="$ctrl.filter.serial"
|
||||
ng-keydown="$ctrl.onKeyPress($event)">
|
||||
</vn-textfield>
|
||||
</vn-horizontal>
|
||||
<div class="chips">
|
||||
<vn-chip
|
||||
ng-if="$ctrl.filter.serial"
|
||||
removable="true"
|
||||
on-remove="$ctrl.removeItemFilter('serial')"
|
||||
class="colored">
|
||||
<span>{{$ctrl.$t('Serial')}}: {{$ctrl.filter.serial}}</span>
|
||||
</vn-chip>
|
||||
</div>
|
||||
</vn-side-menu>
|
|
@ -0,0 +1,44 @@
|
|||
import ngModule from '../module';
|
||||
import SearchPanel from 'core/components/searchbar/search-panel';
|
||||
import './style.scss';
|
||||
|
||||
class Controller extends SearchPanel {
|
||||
constructor($element, $) {
|
||||
super($element, $);
|
||||
this.filter = {};
|
||||
const filter = {
|
||||
fields: ['daysAgo']
|
||||
};
|
||||
this.$http.get('InvoiceInConfigs', {filter}).then(res => {
|
||||
if (res.data) {
|
||||
this.invoiceInConfig = res.data[0];
|
||||
this.addFilters();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
removeItemFilter(param) {
|
||||
this.filter[param] = null;
|
||||
this.addFilters();
|
||||
}
|
||||
|
||||
onKeyPress($event) {
|
||||
if ($event.key === 'Enter')
|
||||
this.addFilters();
|
||||
}
|
||||
|
||||
addFilters() {
|
||||
if (!this.filter.daysAgo)
|
||||
this.filter.daysAgo = this.invoiceInConfig.daysAgo;
|
||||
|
||||
return this.model.addFilter({}, this.filter);
|
||||
}
|
||||
}
|
||||
|
||||
ngModule.component('vnInvoiceInSerialSearchPanel', {
|
||||
template: require('./index.html'),
|
||||
controller: Controller,
|
||||
bindings: {
|
||||
model: '<'
|
||||
}
|
||||
});
|
|
@ -0,0 +1,43 @@
|
|||
import './index.js';
|
||||
|
||||
describe('InvoiceIn', () => {
|
||||
describe('Component serial-search-panel', () => {
|
||||
let controller;
|
||||
let $scope;
|
||||
|
||||
beforeEach(ngModule('invoiceIn'));
|
||||
|
||||
beforeEach(inject(($componentController, $rootScope) => {
|
||||
$scope = $rootScope.$new();
|
||||
const $element = angular.element('<vn-invoice-in-serial-search-panel></vn-invoice-in-serial-search-panel>');
|
||||
controller = $componentController('vnInvoiceInSerialSearchPanel', {$element, $scope});
|
||||
controller.model = {
|
||||
addFilter: jest.fn(),
|
||||
};
|
||||
controller.invoiceInConfig = {
|
||||
daysAgo: 45,
|
||||
};
|
||||
}));
|
||||
|
||||
describe('addFilters()', () => {
|
||||
it('should add default daysAgo if it is not already set', () => {
|
||||
controller.filter = {
|
||||
serial: 'R',
|
||||
};
|
||||
controller.addFilters();
|
||||
|
||||
expect(controller.filter.daysAgo).toEqual(controller.invoiceInConfig.daysAgo);
|
||||
});
|
||||
|
||||
it('should not add default daysAgo if it is already set', () => {
|
||||
controller.filter = {
|
||||
daysAgo: 1,
|
||||
serial: 'R',
|
||||
};
|
||||
controller.addFilters();
|
||||
|
||||
expect(controller.filter.daysAgo).toEqual(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,24 @@
|
|||
@import "variables";
|
||||
|
||||
vn-invoice-in-serial-search-panel vn-side-menu div {
|
||||
& > .input {
|
||||
padding-left: $spacing-md;
|
||||
padding-right: $spacing-md;
|
||||
border-color: $color-spacer;
|
||||
border-bottom: $border-thin;
|
||||
}
|
||||
& > .horizontal {
|
||||
grid-auto-flow: column;
|
||||
grid-column-gap: $spacing-sm;
|
||||
align-items: center;
|
||||
}
|
||||
& > .chips {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
padding: $spacing-md;
|
||||
overflow: hidden;
|
||||
max-width: 100%;
|
||||
border-color: $color-spacer;
|
||||
border-top: $border-thin;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
<vn-crud-model
|
||||
vn-id="model"
|
||||
url="InvoiceIns/getSerial"
|
||||
limit="20">
|
||||
</vn-crud-model>
|
||||
<vn-portal slot="topbar">
|
||||
</vn-portal>
|
||||
<vn-invoice-in-serial-search-panel
|
||||
model="model">
|
||||
</vn-invoice-in-serial-search-panel>
|
||||
<vn-data-viewer
|
||||
model="model"
|
||||
class="vn-w-lg">
|
||||
<vn-card>
|
||||
<vn-table model="model">
|
||||
<vn-thead>
|
||||
<vn-tr>
|
||||
<vn-th field="serial">Serial</vn-th>
|
||||
<vn-th field="pending">Pending</vn-th>
|
||||
<vn-th field="total">Total</vn-th>
|
||||
<vn-th></vn-th>
|
||||
</vn-tr>
|
||||
</vn-thead>
|
||||
<vn-tbody>
|
||||
<vn-tr ng-repeat="invoiceIn in model.data">
|
||||
<vn-td>{{::invoiceIn.serial}}</vn-td>
|
||||
<vn-td>{{::invoiceIn.pending}}</vn-td>
|
||||
<vn-td>{{::invoiceIn.total}}</vn-td>
|
||||
<vn-td shrink>
|
||||
<vn-icon-button
|
||||
vn-click-stop="$ctrl.goToIndex(model.userParams.daysAgo, invoiceIn.serial)"
|
||||
vn-tooltip="Go to InvoiceIn"
|
||||
icon="icon-invoice-in">
|
||||
</vn-icon-button>
|
||||
</vn-td>
|
||||
</vn-tr>
|
||||
</vn-tbody>
|
||||
</vn-table>
|
||||
</vn-card>
|
||||
</vn-data-viewer>
|
|
@ -0,0 +1,22 @@
|
|||
import ngModule from '../module';
|
||||
import Section from 'salix/components/section';
|
||||
|
||||
export default class Controller extends Section {
|
||||
constructor($element, $) {
|
||||
super($element, $);
|
||||
}
|
||||
|
||||
goToIndex(daysAgo, serial) {
|
||||
const issued = Date.vnNew();
|
||||
issued.setDate(issued.getDate() - daysAgo);
|
||||
this.$state.go('invoiceIn.index',
|
||||
{q: `{"serial": "${serial}", "isBooked": false, "from": ${issued.getTime()}}`});
|
||||
}
|
||||
}
|
||||
|
||||
Controller.$inject = ['$element', '$scope'];
|
||||
|
||||
ngModule.vnComponent('vnInvoiceInSerial', {
|
||||
template: require('./index.html'),
|
||||
controller: Controller
|
||||
});
|
|
@ -0,0 +1,3 @@
|
|||
Serial: Serie
|
||||
Pending: Pendientes
|
||||
Go to InvoiceIn: Ir al listado de facturas recibidas
|
|
@ -1,4 +1,5 @@
|
|||
const models = require('vn-loopback/server/server').models;
|
||||
const LoopBackContext = require('loopback-context');
|
||||
|
||||
describe('upsertFixedPrice()', () => {
|
||||
const now = Date.vnNew();
|
||||
|
@ -7,6 +8,17 @@ describe('upsertFixedPrice()', () => {
|
|||
|
||||
beforeAll(async() => {
|
||||
originalFixedPrice = await models.FixedPrice.findById(fixedPriceId);
|
||||
const activeCtx = {
|
||||
accessToken: {userId: 9},
|
||||
http: {
|
||||
req: {
|
||||
headers: {origin: 'http://localhost'}
|
||||
}
|
||||
}
|
||||
};
|
||||
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
|
||||
active: activeCtx
|
||||
});
|
||||
});
|
||||
|
||||
it(`should toggle the hasMinPrice boolean if there's a minPrice and update the rest of the data`, async() => {
|
||||
|
|
|
@ -1,7 +1,21 @@
|
|||
const models = require('vn-loopback/server/server').models;
|
||||
const LoopBackContext = require('loopback-context');
|
||||
|
||||
describe('item clone()', () => {
|
||||
let nextItemId;
|
||||
beforeAll(async() => {
|
||||
const activeCtx = {
|
||||
accessToken: {userId: 9},
|
||||
http: {
|
||||
req: {
|
||||
headers: {origin: 'http://localhost'}
|
||||
}
|
||||
}
|
||||
};
|
||||
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
|
||||
active: activeCtx
|
||||
});
|
||||
});
|
||||
|
||||
beforeEach(async() => {
|
||||
let query = `SELECT i1.id + 1 as id FROM vn.item i1
|
||||
|
|
|
@ -1,6 +1,21 @@
|
|||
const models = require('vn-loopback/server/server').models;
|
||||
const LoopBackContext = require('loopback-context');
|
||||
|
||||
describe('item new()', () => {
|
||||
beforeAll(async() => {
|
||||
const activeCtx = {
|
||||
accessToken: {userId: 9},
|
||||
http: {
|
||||
req: {
|
||||
headers: {origin: 'http://localhost'}
|
||||
}
|
||||
}
|
||||
};
|
||||
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
|
||||
active: activeCtx
|
||||
});
|
||||
});
|
||||
|
||||
it('should create a new item, adding the name as a tag', async() => {
|
||||
const tx = await models.Item.beginTransaction({});
|
||||
const options = {transaction: tx};
|
||||
|
|
|
@ -1,6 +1,21 @@
|
|||
const models = require('vn-loopback/server/server').models;
|
||||
const LoopBackContext = require('loopback-context');
|
||||
|
||||
describe('regularize()', () => {
|
||||
beforeAll(async() => {
|
||||
const activeCtx = {
|
||||
accessToken: {userId: 18},
|
||||
http: {
|
||||
req: {
|
||||
headers: {origin: 'http://localhost'}
|
||||
}
|
||||
}
|
||||
};
|
||||
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
|
||||
active: activeCtx
|
||||
});
|
||||
});
|
||||
|
||||
it('should create a new ticket and add a line', async() => {
|
||||
const tx = await models.Item.beginTransaction({});
|
||||
const options = {transaction: tx};
|
||||
|
|
|
@ -86,11 +86,11 @@
|
|||
class="expendable">
|
||||
<span
|
||||
vn-tooltip="
|
||||
{{::$ctrl.$t('Cost')}}: {{::entry.buyingValue | currency: 'EUR':2 | dashIfEmpty}}<br>
|
||||
{{::$ctrl.$t('Package')}}: {{::entry.packageValue | currency: 'EUR':2 | dashIfEmpty}}<br>
|
||||
{{::$ctrl.$t('Freight')}}: {{::entry.freightValue | currency: 'EUR':2 | dashIfEmpty}}<br>
|
||||
{{::$ctrl.$t('Comission')}}: {{::entry.comissionValue | currency: 'EUR':2 | dashIfEmpty}}">
|
||||
{{::entry.cost | currency: 'EUR':2 | dashIfEmpty}}
|
||||
{{::$ctrl.$t('Cost')}}: {{::entry.buyingValue | currency: 'EUR':3 | dashIfEmpty}}<br>
|
||||
{{::$ctrl.$t('Package')}}: {{::entry.packageValue | currency: 'EUR':3 | dashIfEmpty}}<br>
|
||||
{{::$ctrl.$t('Freight')}}: {{::entry.freightValue | currency: 'EUR':3 | dashIfEmpty}}<br>
|
||||
{{::$ctrl.$t('Comission')}}: {{::entry.comissionValue | currency: 'EUR':3 | dashIfEmpty}}">
|
||||
{{::entry.cost | currency: 'EUR':3 | dashIfEmpty}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td number>{{::entry.weight | dashIfEmpty}}</vn-td>
|
||||
|
|
|
@ -40,11 +40,11 @@ Create: Crear
|
|||
Client card: Ficha del cliente
|
||||
Shipped: F. envío
|
||||
stems: Tallos
|
||||
Weight/Piece: Peso/tallo
|
||||
Weight/Piece: Peso (gramos)/tallo
|
||||
Search items by id, name or barcode: Buscar articulos por identificador, nombre o codigo de barras
|
||||
SalesPerson: Comercial
|
||||
Concept: Concepto
|
||||
Units/Box: Unidades/Caja
|
||||
Units/Box: Unidades/caja
|
||||
|
||||
# Sections
|
||||
Items: Artículos
|
||||
|
|
|
@ -295,11 +295,26 @@ module.exports = Self => {
|
|||
risk = t.debt + t.credit, totalProblems = totalProblems + 1
|
||||
`);
|
||||
|
||||
stmts.push('DROP TEMPORARY TABLE IF EXISTS tmp.sale_getWarnings');
|
||||
|
||||
stmt = new ParameterizedSQL(`
|
||||
SELECT t.*, tp.*,
|
||||
((tp.risk) + cc.riskTolerance < 0) AS hasHighRisk
|
||||
CREATE TEMPORARY TABLE tmp.sale_getWarnings
|
||||
(INDEX (ticketFk, agencyModeFk))
|
||||
ENGINE = MEMORY
|
||||
SELECT f.id ticketFk, f.agencyModeFk
|
||||
FROM tmp.filter f`);
|
||||
stmts.push(stmt);
|
||||
|
||||
stmts.push('CALL ticket_getWarnings()');
|
||||
|
||||
stmt = new ParameterizedSQL(`
|
||||
SELECT t.*,
|
||||
tp.*,
|
||||
((tp.risk) + cc.riskTolerance < 0) AS hasHighRisk,
|
||||
tw.*
|
||||
FROM tmp.tickets t
|
||||
LEFT JOIN tmp.ticket_problems tp ON tp.ticketFk = t.id
|
||||
LEFT JOIN tmp.ticket_warnings tw ON tw.ticketFk = t.id
|
||||
JOIN clientConfig cc`);
|
||||
|
||||
const hasProblems = args.problems;
|
||||
|
@ -352,20 +367,37 @@ module.exports = Self => {
|
|||
return {'t.alertLevel': value};
|
||||
case 'pending':
|
||||
if (value) {
|
||||
return {and: [
|
||||
{'t.alertLevel': 0},
|
||||
{'t.alertLevelCode': {nin: [
|
||||
'OK',
|
||||
'BOARDING',
|
||||
'PRINTED',
|
||||
'PRINTED_AUTO',
|
||||
'PICKER_DESIGNED'
|
||||
]}}
|
||||
]};
|
||||
return {'t.alertLevelCode': {inq: [
|
||||
'FIXING',
|
||||
'FREE',
|
||||
'NOT_READY',
|
||||
'BLOCKED',
|
||||
'EXPANDABLE',
|
||||
'CHAINED',
|
||||
'WAITING_FOR_PAYMENT'
|
||||
]}};
|
||||
} else {
|
||||
return {and: [
|
||||
{'t.alertLevel': {gt: 0}}
|
||||
]};
|
||||
return {'t.alertLevelCode': {inq: [
|
||||
'ON_PREPARATION',
|
||||
'ON_CHECKING',
|
||||
'CHECKED',
|
||||
'PACKING',
|
||||
'PACKED',
|
||||
'INVOICED',
|
||||
'ON_DELIVERY',
|
||||
'PREPARED',
|
||||
'WAITING_FOR_PICKUP',
|
||||
'DELIVERED',
|
||||
'PRINTED_BACK',
|
||||
'LAST_CALL',
|
||||
'PREVIOUS_PREPARATION',
|
||||
'ASSISTED_PREPARATION',
|
||||
'BOARD',
|
||||
'PRINTED STOWAWAY',
|
||||
'OK STOWAWAY',
|
||||
'HALF_PACKED',
|
||||
'COOLER_PREPARATION'
|
||||
]}};
|
||||
}
|
||||
case 'agencyModeFk':
|
||||
case 'warehouseFk':
|
||||
|
@ -387,6 +419,8 @@ module.exports = Self => {
|
|||
tmp.filter,
|
||||
tmp.ticket_problems,
|
||||
tmp.sale_getProblems,
|
||||
tmp.sale_getWarnings,
|
||||
tmp.ticket_warnings,
|
||||
tmp.risk`);
|
||||
|
||||
const sql = ParameterizedSQL.join(stmts, ';');
|
||||
|
|
|
@ -12,4 +12,5 @@ Theoretical: Teórica
|
|||
Practical: Práctica
|
||||
Preparation: Preparación
|
||||
Auto-refresh: Auto-refresco
|
||||
Toggle auto-refresh every 2 minutes: Conmuta el refresco automático cada 2 minutos
|
||||
Toggle auto-refresh every 2 minutes: Conmuta el refresco automático cada 2 minutos
|
||||
Is fragile: Es frágil
|
||||
|
|
|
@ -19,13 +19,13 @@
|
|||
<vn-horizontal class="header">
|
||||
<vn-one translate>
|
||||
Tickets monitor
|
||||
</vn-one>
|
||||
</vn-one>
|
||||
</vn-horizontal>
|
||||
<vn-card>
|
||||
<smart-table
|
||||
model="model"
|
||||
view-config-id="ticketsMonitor"
|
||||
options="$ctrl.smartTableOptions"
|
||||
<smart-table
|
||||
model="model"
|
||||
view-config-id="ticketsMonitor"
|
||||
options="$ctrl.smartTableOptions"
|
||||
expr-builder="$ctrl.exprBuilder(param, value)">
|
||||
<slot-actions>
|
||||
<vn-check
|
||||
|
@ -68,6 +68,7 @@
|
|||
<th field="stateFk">
|
||||
<span translate>State</span>
|
||||
</th>
|
||||
<th field="isFragile"></th>
|
||||
<th field="zoneFk">
|
||||
<span translate>Zone</span>
|
||||
</th>
|
||||
|
@ -80,7 +81,7 @@
|
|||
<tbody>
|
||||
<tr ng-repeat="ticket in model.data track by ticket.id"
|
||||
vn-anchor="{
|
||||
state: 'ticket.card.summary',
|
||||
state: 'ticket.card.summary',
|
||||
params: {id: ticket.id},
|
||||
target: '_blank'
|
||||
}">
|
||||
|
@ -169,12 +170,20 @@
|
|||
class="link">
|
||||
{{ticket.refFk}}
|
||||
</span>
|
||||
<span
|
||||
<span
|
||||
ng-show="!ticket.refFk"
|
||||
class="chip {{ticket.classColor}}">
|
||||
{{ticket.state}}
|
||||
</span>
|
||||
</td>
|
||||
<td number>
|
||||
<vn-icon
|
||||
ng-show="ticket.isFragile"
|
||||
translate-attr="{title: 'Is fragile'}"
|
||||
class="bright"
|
||||
icon="local_bar">
|
||||
</vn-icon>
|
||||
</td>
|
||||
<td name="zone">
|
||||
<span
|
||||
title="{{ticket.zoneName}}"
|
||||
|
@ -191,8 +200,8 @@
|
|||
<td actions>
|
||||
<vn-icon-button
|
||||
vn-anchor="{
|
||||
state: 'ticket.card.sale',
|
||||
params: {id: ticket.id},
|
||||
state: 'ticket.card.sale',
|
||||
params: {id: ticket.id},
|
||||
target: '_blank'
|
||||
}"
|
||||
vn-tooltip="Go to lines"
|
||||
|
@ -213,7 +222,7 @@
|
|||
<vn-ticket-descriptor-popover
|
||||
vn-id="ticketDescriptor">
|
||||
</vn-ticket-descriptor-popover>
|
||||
<vn-worker-descriptor-popover
|
||||
<vn-worker-descriptor-popover
|
||||
vn-id="workerDescriptor">
|
||||
</vn-worker-descriptor-popover>
|
||||
<vn-client-descriptor-popover
|
||||
|
@ -236,22 +245,22 @@
|
|||
ng-click="contextmenu.filterBySelection()">
|
||||
Filter by selection
|
||||
</vn-item>
|
||||
<vn-item translate
|
||||
ng-if="contextmenu.isFilterAllowed()"
|
||||
<vn-item translate
|
||||
ng-if="contextmenu.isFilterAllowed()"
|
||||
ng-click="contextmenu.excludeSelection()">
|
||||
Exclude selection
|
||||
</vn-item>
|
||||
<vn-item translate
|
||||
ng-if="contextmenu.isFilterAllowed()"
|
||||
<vn-item translate
|
||||
ng-if="contextmenu.isFilterAllowed()"
|
||||
ng-click="contextmenu.removeFilter()">
|
||||
Remove filter
|
||||
</vn-item>
|
||||
<vn-item translate
|
||||
<vn-item translate
|
||||
ng-click="contextmenu.removeAllFilters()">
|
||||
Remove all filters
|
||||
</vn-item>
|
||||
<vn-item translate
|
||||
ng-if="contextmenu.isActionAllowed()"
|
||||
<vn-item translate
|
||||
ng-if="contextmenu.isActionAllowed()"
|
||||
ng-click="contextmenu.copyValue()">
|
||||
Copy value
|
||||
</vn-item>
|
||||
|
|
|
@ -1,6 +1,22 @@
|
|||
const app = require('vn-loopback/server/server');
|
||||
const LoopBackContext = require('loopback-context');
|
||||
|
||||
describe('route clone()', () => {
|
||||
beforeAll(async() => {
|
||||
const activeCtx = {
|
||||
accessToken: {userId: 9},
|
||||
http: {
|
||||
req: {
|
||||
headers: {origin: 'http://localhost'}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
|
||||
active: activeCtx
|
||||
});
|
||||
});
|
||||
|
||||
const createdDate = Date.vnNew();
|
||||
it('should throw an error if the amount of ids pased to the clone function do no match the database', async() => {
|
||||
const ids = [996, 997, 998, 999];
|
||||
|
|
|
@ -1,6 +1,20 @@
|
|||
const models = require('vn-loopback/server/server').models;
|
||||
const LoopBackContext = require('loopback-context');
|
||||
|
||||
describe('route updateWorkCenter()', () => {
|
||||
beforeAll(async() => {
|
||||
const activeCtx = {
|
||||
accessToken: {userId: 9},
|
||||
http: {
|
||||
req: {
|
||||
headers: {origin: 'http://localhost'}
|
||||
}
|
||||
}
|
||||
};
|
||||
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
|
||||
active: activeCtx
|
||||
});
|
||||
});
|
||||
const routeId = 1;
|
||||
|
||||
it('should set the commission work center if the worker has workCenter', async() => {
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
module.exports = Self => {
|
||||
Self.remoteMethod('newSupplier', {
|
||||
Self.remoteMethodCtx('newSupplier', {
|
||||
description: 'Creates a new supplier and returns it',
|
||||
accessType: 'WRITE',
|
||||
accepts: [{
|
||||
arg: 'params',
|
||||
type: 'object',
|
||||
http: {source: 'body'}
|
||||
arg: 'name',
|
||||
type: 'string'
|
||||
}],
|
||||
returns: {
|
||||
type: 'string',
|
||||
|
@ -17,29 +16,18 @@ module.exports = Self => {
|
|||
}
|
||||
});
|
||||
|
||||
Self.newSupplier = async params => {
|
||||
Self.newSupplier = async(ctx, options) => {
|
||||
const models = Self.app.models;
|
||||
const args = ctx.args;
|
||||
const myOptions = {};
|
||||
|
||||
if (typeof(params) == 'string')
|
||||
params = JSON.parse(params);
|
||||
if (typeof options == 'object')
|
||||
Object.assign(myOptions, options);
|
||||
|
||||
params.nickname = params.name;
|
||||
delete args.ctx;
|
||||
const data = {...args, ...{nickname: args.name}};
|
||||
const supplier = await models.Supplier.create(data, myOptions);
|
||||
|
||||
if (!myOptions.transaction) {
|
||||
tx = await Self.beginTransaction({});
|
||||
myOptions.transaction = tx;
|
||||
}
|
||||
|
||||
try {
|
||||
const supplier = await models.Supplier.create(params, myOptions);
|
||||
|
||||
if (tx) await tx.commit();
|
||||
|
||||
return supplier;
|
||||
} catch (e) {
|
||||
if (tx) await tx.rollback();
|
||||
throw e;
|
||||
}
|
||||
return supplier;
|
||||
};
|
||||
};
|
||||
|
|
|
@ -1,31 +1,39 @@
|
|||
const app = require('vn-loopback/server/server');
|
||||
const models = require('vn-loopback/server/server').models;
|
||||
const LoopBackContext = require('loopback-context');
|
||||
|
||||
describe('Supplier newSupplier()', () => {
|
||||
const newSupp = {
|
||||
name: 'TestSupplier-1'
|
||||
};
|
||||
const administrativeId = 5;
|
||||
const activeCtx = {
|
||||
accessToken: {userId: administrativeId},
|
||||
http: {
|
||||
req: {
|
||||
headers: {origin: 'http://localhost'}
|
||||
}
|
||||
}
|
||||
};
|
||||
const ctx = {req: activeCtx};
|
||||
|
||||
it('should create a new supplier containing only the name', async() => {
|
||||
pending('https://redmine.verdnatura.es/issues/5203');
|
||||
const activeCtx = {
|
||||
accessToken: {userId: administrativeId},
|
||||
};
|
||||
beforeEach(() => {
|
||||
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
|
||||
active: activeCtx
|
||||
});
|
||||
});
|
||||
|
||||
let result = await app.models.Supplier.newSupplier(JSON.stringify(newSupp));
|
||||
it('should create a new supplier containing only the name', async() => {
|
||||
const tx = await models.Supplier.beginTransaction({});
|
||||
|
||||
expect(result.name).toEqual('TestSupplier-1');
|
||||
expect(result.id).toEqual(443);
|
||||
try {
|
||||
const options = {transaction: tx};
|
||||
ctx.args = {
|
||||
name: 'newSupplier'
|
||||
};
|
||||
|
||||
const createdSupplier = await app.models.Supplier.findById(result.id);
|
||||
const result = await models.Supplier.newSupplier(ctx, options);
|
||||
|
||||
expect(createdSupplier.id).toEqual(result.id);
|
||||
expect(createdSupplier.name).toEqual(result.name);
|
||||
expect(createdSupplier.payDemFk).toEqual(7);
|
||||
expect(createdSupplier.nickname).toEqual(result.name);
|
||||
expect(result.name).toEqual('newSupplier');
|
||||
} catch (e) {
|
||||
await tx.rollback();
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
<vn-watcher
|
||||
vn-id="watcher"
|
||||
url="suppliers/newSupplier"
|
||||
url="Suppliers/newSupplier"
|
||||
data="$ctrl.supplier"
|
||||
params="$ctrl.supplier"
|
||||
insert-mode="true"
|
||||
form="form">
|
||||
</vn-watcher>
|
||||
|
@ -9,8 +10,8 @@
|
|||
<vn-card class="vn-pa-lg">
|
||||
<vn-horizontal>
|
||||
<vn-textfield
|
||||
label="Supplier name"
|
||||
ng-model="$ctrl.supplier.name"
|
||||
label="Supplier name"
|
||||
ng-model="$ctrl.supplier.name"
|
||||
vn-focus>
|
||||
</vn-textfield>
|
||||
</vn-horizontal>
|
||||
|
|
|
@ -1,7 +1,21 @@
|
|||
const models = require('vn-loopback/server/server').models;
|
||||
const LoopBackContext = require('loopback-context');
|
||||
|
||||
describe('sale canEdit()', () => {
|
||||
const employeeId = 1;
|
||||
beforeAll(async() => {
|
||||
const activeCtx = {
|
||||
accessToken: {userId: 9},
|
||||
http: {
|
||||
req: {
|
||||
headers: {origin: 'http://localhost'}
|
||||
}
|
||||
}
|
||||
};
|
||||
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
|
||||
active: activeCtx
|
||||
});
|
||||
});
|
||||
|
||||
describe('sale editTracked', () => {
|
||||
it('should return true if the role is production regardless of the saleTrackings', async() => {
|
||||
|
|
|
@ -1,6 +1,21 @@
|
|||
const models = require('vn-loopback/server/server').models;
|
||||
const LoopBackContext = require('loopback-context');
|
||||
|
||||
describe('sale deleteSales()', () => {
|
||||
beforeAll(async() => {
|
||||
const activeCtx = {
|
||||
accessToken: {userId: 9},
|
||||
http: {
|
||||
req: {
|
||||
headers: {origin: 'http://localhost'}
|
||||
}
|
||||
}
|
||||
};
|
||||
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
|
||||
active: activeCtx
|
||||
});
|
||||
});
|
||||
|
||||
it('should throw an error if the ticket of the given sales is not editable', async() => {
|
||||
const tx = await models.Sale.beginTransaction({});
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
const models = require('vn-loopback/server/server').models;
|
||||
const LoopBackContext = require('loopback-context');
|
||||
|
||||
describe('sale reserve()', () => {
|
||||
const ctx = {
|
||||
|
@ -9,6 +10,20 @@ describe('sale reserve()', () => {
|
|||
}
|
||||
};
|
||||
|
||||
beforeAll(async() => {
|
||||
const activeCtx = {
|
||||
accessToken: {userId: 9},
|
||||
http: {
|
||||
req: {
|
||||
headers: {origin: 'http://localhost'}
|
||||
}
|
||||
}
|
||||
};
|
||||
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
|
||||
active: activeCtx
|
||||
});
|
||||
});
|
||||
|
||||
it('should throw an error if the ticket can not be modified', async() => {
|
||||
const tx = await models.Sale.beginTransaction({});
|
||||
|
||||
|
|
|
@ -1,6 +1,21 @@
|
|||
const models = require('vn-loopback/server/server').models;
|
||||
const LoopBackContext = require('loopback-context');
|
||||
|
||||
describe('sale updateConcept()', () => {
|
||||
beforeAll(async() => {
|
||||
const activeCtx = {
|
||||
accessToken: {userId: 9},
|
||||
http: {
|
||||
req: {
|
||||
headers: {origin: 'http://localhost'}
|
||||
}
|
||||
}
|
||||
};
|
||||
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
|
||||
active: activeCtx
|
||||
});
|
||||
});
|
||||
|
||||
const ctx = {req: {accessToken: {userId: 9}}};
|
||||
const saleId = 25;
|
||||
|
||||
|
|
|
@ -1,6 +1,21 @@
|
|||
const models = require('vn-loopback/server/server').models;
|
||||
const LoopBackContext = require('loopback-context');
|
||||
|
||||
describe('sale updatePrice()', () => {
|
||||
beforeAll(async() => {
|
||||
const activeCtx = {
|
||||
accessToken: {userId: 18},
|
||||
http: {
|
||||
req: {
|
||||
headers: {origin: 'http://localhost'}
|
||||
}
|
||||
}
|
||||
};
|
||||
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
|
||||
active: activeCtx
|
||||
});
|
||||
});
|
||||
|
||||
const ctx = {
|
||||
req: {
|
||||
accessToken: {userId: 18},
|
||||
|
|
|
@ -1,6 +1,21 @@
|
|||
const models = require('vn-loopback/server/server').models;
|
||||
const LoopBackContext = require('loopback-context');
|
||||
|
||||
describe('sale updateQuantity()', () => {
|
||||
beforeAll(async() => {
|
||||
const activeCtx = {
|
||||
accessToken: {userId: 9},
|
||||
http: {
|
||||
req: {
|
||||
headers: {origin: 'http://localhost'}
|
||||
}
|
||||
}
|
||||
};
|
||||
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
|
||||
active: activeCtx
|
||||
});
|
||||
});
|
||||
|
||||
const ctx = {
|
||||
req: {
|
||||
accessToken: {userId: 9},
|
||||
|
|
|
@ -0,0 +1,132 @@
|
|||
const UserError = require('vn-loopback/util/user-error');
|
||||
|
||||
module.exports = Self => {
|
||||
Self.remoteMethodCtx('saveSign', {
|
||||
description: 'Save sign',
|
||||
accessType: 'WRITE',
|
||||
accepts:
|
||||
[
|
||||
{
|
||||
arg: 'tickets',
|
||||
type: ['number'],
|
||||
required: true,
|
||||
description: 'The tickets'
|
||||
},
|
||||
{
|
||||
arg: 'location',
|
||||
type: 'object',
|
||||
description: 'The employee location the moment the sign is saved'
|
||||
},
|
||||
{
|
||||
arg: 'signedTime',
|
||||
type: 'date',
|
||||
description: 'The signed time'
|
||||
}
|
||||
],
|
||||
http: {
|
||||
path: `/saveSign`,
|
||||
verb: 'POST'
|
||||
}
|
||||
});
|
||||
|
||||
Self.saveSign = async(ctx, options) => {
|
||||
const args = Object.assign({}, ctx.args);
|
||||
const models = Self.app.models;
|
||||
const myOptions = {};
|
||||
let tx;
|
||||
|
||||
if (typeof options == 'object')
|
||||
Object.assign(myOptions, options);
|
||||
|
||||
if (!myOptions.transaction) {
|
||||
tx = await Self.beginTransaction({});
|
||||
myOptions.transaction = tx;
|
||||
}
|
||||
|
||||
async function setLocation(ticketId) {
|
||||
await models.Delivery.create({
|
||||
ticketFk: ticketId,
|
||||
longitude: args.location.Longitude,
|
||||
latitude: args.location.Latitude,
|
||||
dated: args.signedTime || new Date()
|
||||
}, myOptions);
|
||||
}
|
||||
|
||||
async function gestDocExists(ticketId) {
|
||||
const ticketDms = await models.TicketDms.findOne({
|
||||
where: {ticketFk: ticketId},
|
||||
fields: ['dmsFk']
|
||||
}, myOptions);
|
||||
|
||||
if (!ticketDms) return false;
|
||||
|
||||
const ticket = await models.Ticket.findById(ticketId, {fields: ['isSigned']}, myOptions);
|
||||
if (ticket.isSigned == true)
|
||||
return true;
|
||||
else
|
||||
await models.Dms.destroyAll({where: {reference: ticketId}}, myOptions);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
async function createGestDoc(id) {
|
||||
const ticket = await models.Ticket.findById(id,
|
||||
{include: [
|
||||
{
|
||||
relation: 'warehouse',
|
||||
scope: {
|
||||
fields: ['id']
|
||||
}
|
||||
}, {
|
||||
relation: 'client',
|
||||
scope: {
|
||||
fields: ['name']
|
||||
}
|
||||
}, {
|
||||
relation: 'route',
|
||||
scope: {
|
||||
fields: ['id']
|
||||
}
|
||||
}
|
||||
]
|
||||
}, myOptions);
|
||||
const dmsType = await models.DmsType.findOne({where: {code: 'Ticket'}, fields: ['id']}, myOptions);
|
||||
const ctxUploadFile = Object.assign({}, ctx);
|
||||
ctxUploadFile.args = {
|
||||
warehouseId: ticket.warehouseFk,
|
||||
companyId: ticket.companyFk,
|
||||
dmsTypeId: dmsType.id,
|
||||
reference: id,
|
||||
description: `Ticket ${id} Cliente ${ticket.client().name} Ruta ${ticket.route().id}`,
|
||||
hasFile: true
|
||||
};
|
||||
await models.Ticket.uploadFile(ctxUploadFile, id, myOptions);
|
||||
}
|
||||
|
||||
try {
|
||||
for (let i = 0; i < args.tickets.length; i++) {
|
||||
const ticketState = await models.TicketState.findOne(
|
||||
{where: {ticketFk: args.tickets[i]},
|
||||
fields: ['alertLevel']
|
||||
}, myOptions);
|
||||
|
||||
const packedAlertLevel = await models.AlertLevel.findOne({where: {code: 'PACKED'},
|
||||
fields: ['id']
|
||||
}, myOptions);
|
||||
|
||||
if (ticketState.alertLevel < packedAlertLevel.id)
|
||||
throw new UserError('This ticket cannot be signed because it has not been boxed');
|
||||
else if (!await gestDocExists(args.tickets[i])) {
|
||||
if (args.location) setLocation(args.tickets[i]);
|
||||
await createGestDoc(args.tickets[i]);
|
||||
await Self.rawSql(`CALL vn.ticket_setState(?, ?)`, [args.tickets[i], 'DELIVERED'], myOptions);
|
||||
}
|
||||
}
|
||||
|
||||
if (tx) await tx.commit();
|
||||
} catch (e) {
|
||||
if (tx) await tx.rollback();
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
};
|
|
@ -1,7 +1,21 @@
|
|||
const models = require('vn-loopback/server/server').models;
|
||||
const LoopBackContext = require('loopback-context');
|
||||
|
||||
describe('ticket addSale()', () => {
|
||||
const ticketId = 13;
|
||||
beforeAll(async() => {
|
||||
const activeCtx = {
|
||||
accessToken: {userId: 9},
|
||||
http: {
|
||||
req: {
|
||||
headers: {origin: 'http://localhost'}
|
||||
}
|
||||
}
|
||||
};
|
||||
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
|
||||
active: activeCtx
|
||||
});
|
||||
});
|
||||
|
||||
it('should create a new sale for the ticket with id 13', async() => {
|
||||
const tx = await models.Ticket.beginTransaction({});
|
||||
|
|
|
@ -10,11 +10,15 @@ describe('ticket merge()', () => {
|
|||
workerFk: 1
|
||||
};
|
||||
|
||||
const activeCtx = {
|
||||
accessToken: {userId: 9},
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
beforeAll(async() => {
|
||||
const activeCtx = {
|
||||
accessToken: {userId: 9},
|
||||
http: {
|
||||
req: {
|
||||
headers: {origin: 'http://localhost'}
|
||||
}
|
||||
}
|
||||
};
|
||||
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
|
||||
active: activeCtx
|
||||
});
|
||||
|
@ -35,16 +39,16 @@ describe('ticket merge()', () => {
|
|||
|
||||
try {
|
||||
const options = {transaction: tx};
|
||||
const chatNotificationBeforeMerge = await models.Chat.find();
|
||||
const chatNotificationBeforeMerge = await models.Chat.find(null, options);
|
||||
|
||||
await models.Ticket.merge(ctx, [tickets], options);
|
||||
|
||||
const createdTicketLog = await models.TicketLog.find({where: {originFk: tickets.originId}}, options);
|
||||
const createdTicketLog = await models.TicketLog.find({where: {originFk: tickets.destinationId}}, options);
|
||||
const deletedTicket = await models.Ticket.findOne({where: {id: tickets.originId}}, options);
|
||||
const salesTicketFuture = await models.Sale.find({where: {ticketFk: tickets.destinationId}}, options);
|
||||
const chatNotificationAfterMerge = await models.Chat.find();
|
||||
const chatNotificationAfterMerge = await models.Chat.find(null, options);
|
||||
|
||||
expect(createdTicketLog.length).toEqual(2);
|
||||
expect(createdTicketLog.length).toEqual(1);
|
||||
expect(deletedTicket.isDeleted).toEqual(true);
|
||||
expect(salesTicketFuture.length).toEqual(2);
|
||||
expect(chatNotificationBeforeMerge.length).toEqual(chatNotificationAfterMerge.length - 2);
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
const models = require('vn-loopback/server/server').models;
|
||||
|
||||
describe('Ticket saveSign()', () => {
|
||||
const FormData = require('form-data');
|
||||
const data = new FormData();
|
||||
let ctx = {req: {
|
||||
accessToken: {userId: 9},
|
||||
headers: {
|
||||
...data.getHeaders()
|
||||
}
|
||||
|
||||
}};
|
||||
|
||||
it(`should throw error if the ticket's alert level is lower than 2`, async() => {
|
||||
const tx = await models.TicketDms.beginTransaction({});
|
||||
const ticketWithOkState = 12;
|
||||
let error;
|
||||
try {
|
||||
const options = {transaction: tx};
|
||||
ctx.args = {tickets: [ticketWithOkState]};
|
||||
|
||||
await models.Ticket.saveSign(ctx, options);
|
||||
|
||||
await tx.rollback();
|
||||
} catch (e) {
|
||||
error = e;
|
||||
await tx.rollback();
|
||||
}
|
||||
|
||||
expect(error).toBeDefined();
|
||||
});
|
||||
});
|
|
@ -1,6 +1,20 @@
|
|||
const models = require('vn-loopback/server/server').models;
|
||||
const LoopBackContext = require('loopback-context');
|
||||
|
||||
describe('sale updateDiscount()', () => {
|
||||
beforeAll(async() => {
|
||||
const activeCtx = {
|
||||
accessToken: {userId: 9},
|
||||
http: {
|
||||
req: {
|
||||
headers: {origin: 'http://localhost'}
|
||||
}
|
||||
}
|
||||
};
|
||||
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
|
||||
active: activeCtx
|
||||
});
|
||||
});
|
||||
const originalSaleId = 8;
|
||||
|
||||
it('should throw an error if no sales were selected', async() => {
|
||||
|
|
|
@ -39,4 +39,5 @@ module.exports = function(Self) {
|
|||
require('../methods/ticket/isRoleAdvanced')(Self);
|
||||
require('../methods/ticket/collectionLabel')(Self);
|
||||
require('../methods/ticket/expeditionPalletLabel')(Self);
|
||||
require('../methods/ticket/saveSign')(Self);
|
||||
};
|
||||
|
|
|
@ -45,6 +45,9 @@
|
|||
"isDeleted": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"isSigned": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"priority": {
|
||||
"type": "number"
|
||||
},
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
Status log: Hitorial de estados
|
||||
Status log: Historial de estados
|
||||
Expedition removed: Expedición eliminada
|
||||
Move: Mover
|
||||
New ticket without route: Nuevo ticket sin ruta
|
||||
|
|
|
@ -28,8 +28,9 @@
|
|||
</vn-button-menu>
|
||||
<vn-button icon="keyboard_arrow_down"
|
||||
label="More"
|
||||
ng-click="moreOptions.show($event)"
|
||||
ng-show="$ctrl.hasSelectedSales()">
|
||||
disabled="!$ctrl.hasSelectedSales()"
|
||||
vn-tooltip="Select lines to see the options"
|
||||
ng-click="moreOptions.show($event)">
|
||||
</vn-button>
|
||||
<vn-button
|
||||
disabled="!$ctrl.hasSelectedSales() || !$ctrl.isEditable"
|
||||
|
|
|
@ -40,3 +40,4 @@ Refund: Abono
|
|||
Promotion mana: Maná promoción
|
||||
Claim mana: Maná reclamación
|
||||
History: Historial
|
||||
Select lines to see the options: Seleccione lineas para ver las opciones
|
||||
|
|
|
@ -130,6 +130,7 @@ module.exports = Self => {
|
|||
SUM(b.stickers) AS stickers,
|
||||
s.id AS cargoSupplierFk,
|
||||
s.nickname AS cargoSupplierNickname,
|
||||
s.name AS supplierName,
|
||||
CAST(SUM(b.weight * b.stickers) as DECIMAL(10,0)) as loadedKg,
|
||||
CAST(SUM(vc.aerealVolumetricDensity * b.stickers * IF(pkg.volume, pkg.volume, pkg.width * pkg.depth * pkg.height) / 1000000) as DECIMAL(10,0)) as volumeKg
|
||||
FROM travel t
|
||||
|
@ -167,6 +168,7 @@ module.exports = Self => {
|
|||
SUM(b.stickers) AS stickers,
|
||||
e.evaNotes,
|
||||
e.notes,
|
||||
e.invoiceAmount,
|
||||
CAST(SUM(b.weight * b.stickers) AS DECIMAL(10,0)) as loadedkg,
|
||||
CAST(SUM(vc.aerealVolumetricDensity * b.stickers * IF(pkg.volume, pkg.volume, pkg.width * pkg.depth * pkg.height) / 1000000) AS DECIMAL(10,0)) as volumeKg
|
||||
FROM tmp.travel tr
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
url="Travels/extraCommunityFilter"
|
||||
user-params="::$ctrl.defaultFilter"
|
||||
data="travels"
|
||||
order="shipped ASC, landed ASC, travelFk, loadPriority, agencyModeFk, evaNotes"
|
||||
order="landed ASC, shipped ASC, travelFk, loadPriority, agencyModeFk, supplierName, evaNotes"
|
||||
limit="20"
|
||||
auto-load="true">
|
||||
</vn-crud-model>
|
||||
|
@ -48,6 +48,9 @@
|
|||
<th field="agencyModeFk">
|
||||
<span translate>Agency</span>
|
||||
</th>
|
||||
<th field="invoiceAmount">
|
||||
<span translate>Amount</span>
|
||||
</th>
|
||||
<th field="ref">
|
||||
<span translate>Reference</span>
|
||||
</th>
|
||||
|
@ -107,6 +110,7 @@
|
|||
{{::travel.cargoSupplierNickname}}
|
||||
</span>
|
||||
</td>
|
||||
<td></td>
|
||||
<td>{{::travel.agencyModeName}}</td>
|
||||
<td vn-click-stop>
|
||||
<vn-td-editable name="reference" expand>
|
||||
|
@ -157,22 +161,15 @@
|
|||
{{::entry.supplierName}}
|
||||
</span>
|
||||
</td>
|
||||
<td number>{{::entry.invoiceAmount | currency: 'EUR': 2}}</td>
|
||||
<td></td>
|
||||
<td class="td-editable">{{::entry.ref}}</td>
|
||||
<td class="td-editable">{{::entry.invoiceNumber}}</td>
|
||||
<td number>{{::entry.stickers}}</td>
|
||||
<td number></td>
|
||||
<td number>{{::entry.loadedkg}}</td>
|
||||
<td number>{{::entry.volumeKg}}</td>
|
||||
<td>
|
||||
<span ng-if="::entry.notes" vn-tooltip="{{::entry.notes}}">
|
||||
{{::entry.notes}}
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<span ng-if="::entry.evaNotes" vn-tooltip="{{::entry.evaNotes}}">
|
||||
{{::entry.evaNotes}}
|
||||
</span>
|
||||
</td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
|
|
|
@ -6,6 +6,6 @@ Phy. KG: KG físico
|
|||
Vol. KG: KG Vol.
|
||||
Search by travel id or reference: Buscar por id de travel o referencia
|
||||
Search by extra community travel: Buscar por envío extra comunitario
|
||||
Continent Out: Continente salida
|
||||
Continent Out: Cont. salida
|
||||
W. Shipped: F. envío
|
||||
W. Landed: F. llegada
|
||||
W. Landed: F. llegada
|
||||
|
|
|
@ -2,6 +2,15 @@
|
|||
<vn-auto-search
|
||||
model="model">
|
||||
</vn-auto-search>
|
||||
<vn-travel-search-panel
|
||||
model="model">
|
||||
</vn-travel-search-panel>
|
||||
<vn-crud-model
|
||||
vn-id="model"
|
||||
url="Travels/filter"
|
||||
limit="20"
|
||||
order="shipped DESC, landed DESC">
|
||||
</vn-crud-model>
|
||||
<vn-data-viewer
|
||||
model="model"
|
||||
class="vn-mb-xl vn-w-xl">
|
||||
|
@ -9,23 +18,22 @@
|
|||
<vn-table model="model">
|
||||
<vn-thead>
|
||||
<vn-tr>
|
||||
<vn-th field="id" number filter-enabled="false">Id</vn-th>
|
||||
<vn-th field="ref">Reference</vn-th>
|
||||
<vn-th field="agencyModeFk">Agency</vn-th>
|
||||
<vn-th field="warehouseOutFk">Warehouse Out</vn-th>
|
||||
<vn-th field="shipped" center shrink-date>Shipped</vn-th>
|
||||
<vn-th field="isDelivered" center>Delivered</vn-th>
|
||||
<vn-th shrink></vn-th>
|
||||
<vn-th field="warehouseInFk">Warehouse In</vn-th>
|
||||
<vn-th field="landed" center shrink-date>Landed</vn-th>
|
||||
<vn-th field="isReceived" center>Received</vn-th>
|
||||
<vn-th shrink></vn-th>
|
||||
<vn-th shrink field="totalEntries">Total entries</vn-th>
|
||||
<vn-th shrink></vn-th>
|
||||
</vn-tr>
|
||||
</vn-thead>
|
||||
<vn-tbody>
|
||||
<a ng-repeat="travel in model.data"
|
||||
<a ng-repeat="travel in model.data"
|
||||
class="clickable vn-tr search-result"
|
||||
ui-sref="travel.card.summary({id: {{::travel.id}}})">
|
||||
<vn-td number>{{::travel.id}}</vn-td>
|
||||
<vn-td>{{::travel.ref}}</vn-td>
|
||||
<vn-td>{{::travel.agencyModeName}}</vn-td>
|
||||
<vn-td>{{::travel.warehouseOutName}}</vn-td>
|
||||
|
@ -34,14 +42,27 @@
|
|||
{{::travel.shipped | date:'dd/MM/yyyy'}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td center><vn-check ng-model="travel.isDelivered" disabled="true"></vn-check></vn-td>
|
||||
<vn-td shrink>
|
||||
<vn-icon
|
||||
icon="flight_takeoff"
|
||||
translate-attr="{title: 'Delivered'}"
|
||||
ng-class="{active: travel.isDelivered}">
|
||||
</vn-icon>
|
||||
</vn-td>
|
||||
<vn-td expand>{{::travel.warehouseInName}}</vn-td>
|
||||
<vn-td center shrink-date>
|
||||
<span class="chip {{$ctrl.compareDate(travel.landed)}}">
|
||||
{{::travel.landed | date:'dd/MM/yyyy'}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td center><vn-check ng-model="travel.isReceived" disabled="true"></vn-check></vn-td>
|
||||
<vn-td shrink>
|
||||
<vn-icon
|
||||
icon="flight_land"
|
||||
translate-attr="{title: 'Received'}"
|
||||
ng-class="{active: travel.isReceived}">
|
||||
</vn-icon>
|
||||
</vn-td>
|
||||
<vn-td shrink>{{::travel.totalEntries}}</vn-td>
|
||||
<vn-td shrink>
|
||||
<vn-horizontal class="buttons">
|
||||
<vn-icon-button
|
||||
|
@ -49,7 +70,7 @@
|
|||
vn-tooltip="Clone"
|
||||
icon="icon-clone">
|
||||
</vn-icon-button>
|
||||
<vn-icon-button
|
||||
<vn-icon-button
|
||||
vn-anchor="::{state: 'entry.create', params: {travelFk: travel.id}}"
|
||||
vn-tooltip="Add entry"
|
||||
icon="icon-ticket">
|
||||
|
@ -78,38 +99,9 @@
|
|||
fixed-bottom-right>
|
||||
<vn-float-button icon="add"></vn-float-button>
|
||||
</a>
|
||||
<vn-confirm
|
||||
<vn-confirm
|
||||
vn-id="clone"
|
||||
on-accept="$ctrl.onCloneAccept($data)"
|
||||
question="Do you want to clone this travel?"
|
||||
message="All it's properties will be copied">
|
||||
</vn-confirm>
|
||||
<vn-contextmenu vn-id="contextmenu" targets="['vn-data-viewer']" model="model"
|
||||
expr-builder="$ctrl.exprBuilder(param, value)">
|
||||
<slot-menu>
|
||||
<vn-item translate
|
||||
ng-if="contextmenu.isFilterAllowed()"
|
||||
ng-click="contextmenu.filterBySelection()">
|
||||
Filter by selection
|
||||
</vn-item>
|
||||
<vn-item translate
|
||||
ng-if="contextmenu.isFilterAllowed()"
|
||||
ng-click="contextmenu.excludeSelection()">
|
||||
Exclude selection
|
||||
</vn-item>
|
||||
<vn-item translate
|
||||
ng-if="contextmenu.isFilterAllowed()"
|
||||
ng-click="contextmenu.removeFilter()">
|
||||
Remove filter
|
||||
</vn-item>
|
||||
<vn-item translate
|
||||
ng-click="contextmenu.removeAllFilters()" >
|
||||
Remove all filters
|
||||
</vn-item>
|
||||
<vn-item translate
|
||||
ng-if="contextmenu.isActionAllowed()"
|
||||
ng-click="contextmenu.copyValue()">
|
||||
Copy value
|
||||
</vn-item>
|
||||
</slot-menu>
|
||||
</vn-contextmenu>
|
|
@ -1,5 +1,6 @@
|
|||
import ngModule from '../module';
|
||||
import Section from 'salix/components/section';
|
||||
import './style.scss';
|
||||
|
||||
export default class Controller extends Section {
|
||||
preview(travel) {
|
||||
|
@ -30,37 +31,6 @@ export default class Controller extends Section {
|
|||
if (timeDifference == 0) return 'warning';
|
||||
if (timeDifference < 0) return 'success';
|
||||
}
|
||||
|
||||
exprBuilder(param, value) {
|
||||
switch (param) {
|
||||
case 'search':
|
||||
return /^\d+$/.test(value)
|
||||
? {'t.id': value}
|
||||
: {'t.ref': {like: `%${value}%`}};
|
||||
case 'ref':
|
||||
return {'t.ref': {like: `%${value}%`}};
|
||||
case 'shipped':
|
||||
return {'t.shipped': {between: this.dateRange(value)}};
|
||||
case 'landed':
|
||||
return {'t.landed': {between: this.dateRange(value)}};
|
||||
case 'id':
|
||||
case 'agencyModeFk':
|
||||
case 'warehouseOutFk':
|
||||
case 'warehouseInFk':
|
||||
case 'totalEntries':
|
||||
param = `t.${param}`;
|
||||
return {[param]: 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];
|
||||
}
|
||||
}
|
||||
|
||||
ngModule.vnComponent('vnTravelIndex', {
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
@import "variables";
|
||||
|
||||
vn-travel-index {
|
||||
vn-icon {
|
||||
color: $color-font-secondary
|
||||
}
|
||||
|
||||
vn-icon.active {
|
||||
color: $color-success
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
#Ordenar alfabeticamente
|
||||
Reference: Referencia
|
||||
Warehouse Out: Almacén salida
|
||||
Warehouse In: Almacén llegada
|
||||
Warehouse Out: Alm salida
|
||||
Warehouse In: Alm llegada
|
||||
Shipped from: Salida desde
|
||||
Shipped to: Salida hasta
|
||||
Landed from: Llegada desde
|
||||
|
@ -10,12 +10,12 @@ Shipped: F. salida
|
|||
Landed: F. llegada
|
||||
Delivered: Enviado
|
||||
Received: Recibido
|
||||
Travel id: Id envío
|
||||
Search travels by id: Buscar envíos por identificador
|
||||
Travel id: Id
|
||||
Search travels by id: Buscar envíos por identificador o referencia
|
||||
New travel: Nuevo envío
|
||||
travel: envío
|
||||
|
||||
# Sections
|
||||
Travels: Envíos
|
||||
Log: Historial
|
||||
Thermographs: Termógrafos
|
||||
Thermographs: Termógrafos
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue