Merge branch 'dev' of https://gitea.verdnatura.es/verdnatura/salix into 2742--invoiceIn-create
gitea/salix/pipeline/head This commit looks good
Details
gitea/salix/pipeline/head This commit looks good
Details
This commit is contained in:
commit
8c0171096f
|
@ -12,17 +12,23 @@ module.exports = function(Self) {
|
|||
}
|
||||
});
|
||||
|
||||
Self.getStarredModules = async ctx => {
|
||||
Self.getStarredModules = async(ctx, options) => {
|
||||
const models = Self.app.models;
|
||||
const userId = ctx.req.accessToken.userId;
|
||||
|
||||
let myOptions = {};
|
||||
|
||||
if (typeof options == 'object')
|
||||
Object.assign(myOptions, options);
|
||||
|
||||
const filter = {
|
||||
where: {
|
||||
workerFk: userId
|
||||
},
|
||||
fields: ['moduleFk']
|
||||
fields: ['id', 'workerFk', 'moduleFk', 'position'],
|
||||
order: 'position ASC'
|
||||
};
|
||||
|
||||
const starredModules = await Self.app.models.StarredModule.find(filter);
|
||||
|
||||
return starredModules;
|
||||
return models.StarredModule.find(filter, myOptions);
|
||||
};
|
||||
};
|
||||
|
|
|
@ -0,0 +1,98 @@
|
|||
module.exports = function(Self) {
|
||||
Self.remoteMethodCtx('setPosition', {
|
||||
description: 'sets the position of a given module',
|
||||
accessType: 'WRITE',
|
||||
returns: {
|
||||
type: 'object',
|
||||
root: true
|
||||
},
|
||||
accepts: [
|
||||
{
|
||||
arg: 'moduleName',
|
||||
type: 'string',
|
||||
required: true,
|
||||
description: 'The module name'
|
||||
},
|
||||
{
|
||||
arg: 'direction',
|
||||
type: 'string',
|
||||
required: true,
|
||||
description: 'Whether to move left or right the module position'
|
||||
}
|
||||
],
|
||||
http: {
|
||||
path: `/setPosition`,
|
||||
verb: 'post'
|
||||
}
|
||||
});
|
||||
|
||||
Self.setPosition = async(ctx, moduleName, direction, options) => {
|
||||
const models = Self.app.models;
|
||||
const userId = ctx.req.accessToken.userId;
|
||||
|
||||
let tx;
|
||||
let myOptions = {};
|
||||
|
||||
if (typeof options == 'object')
|
||||
Object.assign(myOptions, options);
|
||||
|
||||
if (!myOptions.transaction) {
|
||||
tx = await Self.beginTransaction({});
|
||||
myOptions.transaction = tx;
|
||||
}
|
||||
|
||||
try {
|
||||
const filter = {
|
||||
where: {
|
||||
workerFk: userId,
|
||||
moduleFk: moduleName
|
||||
},
|
||||
order: 'position DESC'
|
||||
};
|
||||
|
||||
const [movingModule] = await models.StarredModule.find(filter, myOptions);
|
||||
|
||||
let operator;
|
||||
let order;
|
||||
|
||||
switch (direction) {
|
||||
case 'left':
|
||||
operator = {lt: movingModule.position};
|
||||
order = 'position DESC';
|
||||
break;
|
||||
case 'right':
|
||||
operator = {gt: movingModule.position};
|
||||
order = 'position ASC';
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
const pushedModule = await models.StarredModule.findOne({
|
||||
where: {
|
||||
position: operator,
|
||||
workerFk: userId
|
||||
},
|
||||
order: order
|
||||
}, myOptions);
|
||||
|
||||
if (!pushedModule) return;
|
||||
|
||||
const movingPosition = pushedModule.position;
|
||||
const pushingPosition = movingModule.position;
|
||||
|
||||
await movingModule.updateAttribute('position', movingPosition, myOptions);
|
||||
await pushedModule.updateAttribute('position', pushingPosition, myOptions);
|
||||
|
||||
if (tx) await tx.commit();
|
||||
|
||||
return {
|
||||
movingModule: movingModule,
|
||||
pushedModule: pushedModule
|
||||
};
|
||||
} catch (e) {
|
||||
if (tx) await tx.rollback();
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
};
|
|
@ -19,7 +19,7 @@ describe('getStarredModules()', () => {
|
|||
});
|
||||
|
||||
it(`should return the starred modules for a given user`, async() => {
|
||||
const newStarred = await app.models.StarredModule.create({workerFk: 9, moduleFk: 'Clients'});
|
||||
const newStarred = await app.models.StarredModule.create({workerFk: 9, moduleFk: 'Clients', position: 1});
|
||||
const starredModules = await app.models.StarredModule.getStarredModules(ctx);
|
||||
|
||||
expect(starredModules.length).toEqual(1);
|
||||
|
|
|
@ -0,0 +1,223 @@
|
|||
const app = require('vn-loopback/server/server');
|
||||
const LoopBackContext = require('loopback-context');
|
||||
|
||||
describe('setPosition()', () => {
|
||||
const activeCtx = {
|
||||
accessToken: {userId: 9},
|
||||
http: {
|
||||
req: {
|
||||
headers: {origin: 'http://localhost'}
|
||||
}
|
||||
}
|
||||
};
|
||||
const ctx = {
|
||||
req: activeCtx
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
|
||||
active: activeCtx
|
||||
});
|
||||
});
|
||||
|
||||
it('should increase the orders module position by replacing it with clients and vice versa', async() => {
|
||||
const tx = await app.models.StarredModule.beginTransaction({});
|
||||
|
||||
const filter = {
|
||||
where: {
|
||||
workerFk: ctx.req.accessToken.userId,
|
||||
moduleFk: 'Orders'
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
const options = {transaction: tx};
|
||||
await app.models.StarredModule.toggleStarredModule(ctx, 'Orders', options);
|
||||
await app.models.StarredModule.toggleStarredModule(ctx, 'Clients', options);
|
||||
|
||||
let orders = await app.models.StarredModule.findOne(filter, options);
|
||||
|
||||
filter.where.moduleFk = 'Clients';
|
||||
let clients = await app.models.StarredModule.findOne(filter, options);
|
||||
|
||||
expect(orders.position).toEqual(1);
|
||||
expect(clients.position).toEqual(2);
|
||||
|
||||
await app.models.StarredModule.setPosition(ctx, 'Clients', 'left', options);
|
||||
|
||||
filter.where.moduleFk = 'Clients';
|
||||
clients = await app.models.StarredModule.findOne(filter, options);
|
||||
|
||||
filter.where.moduleFk = 'Orders';
|
||||
orders = await app.models.StarredModule.findOne(filter, options);
|
||||
|
||||
expect(clients.position).toEqual(1);
|
||||
expect(orders.position).toEqual(2);
|
||||
|
||||
await tx.rollback();
|
||||
} catch (e) {
|
||||
await tx.rollback();
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
|
||||
it('should decrease the orders module position by replacing it with clients and vice versa', async() => {
|
||||
const tx = await app.models.StarredModule.beginTransaction({});
|
||||
|
||||
const filter = {
|
||||
where: {
|
||||
workerFk: ctx.req.accessToken.userId,
|
||||
moduleFk: 'Orders'
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
const options = {transaction: tx};
|
||||
await app.models.StarredModule.toggleStarredModule(ctx, 'Orders', options);
|
||||
await app.models.StarredModule.toggleStarredModule(ctx, 'Clients', options);
|
||||
|
||||
let orders = await app.models.StarredModule.findOne(filter, options);
|
||||
|
||||
filter.where.moduleFk = 'Clients';
|
||||
let clients = await app.models.StarredModule.findOne(filter, options);
|
||||
|
||||
expect(orders.position).toEqual(1);
|
||||
expect(clients.position).toEqual(2);
|
||||
|
||||
await app.models.StarredModule.setPosition(ctx, 'Orders', 'right', options);
|
||||
|
||||
filter.where.moduleFk = 'Orders';
|
||||
orders = await app.models.StarredModule.findOne(filter, options);
|
||||
|
||||
filter.where.moduleFk = 'Clients';
|
||||
clients = await app.models.StarredModule.findOne(filter, options);
|
||||
|
||||
expect(orders.position).toEqual(2);
|
||||
expect(clients.position).toEqual(1);
|
||||
|
||||
await tx.rollback();
|
||||
} catch (e) {
|
||||
await tx.rollback();
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
|
||||
it('should switch two modules after adding and deleting several modules', async() => {
|
||||
const tx = await app.models.StarredModule.beginTransaction({});
|
||||
|
||||
const filter = {
|
||||
where: {
|
||||
workerFk: ctx.req.accessToken.userId,
|
||||
moduleFk: 'Items'
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
const options = {transaction: tx};
|
||||
|
||||
await app.models.StarredModule.toggleStarredModule(ctx, 'Clients', options);
|
||||
await app.models.StarredModule.toggleStarredModule(ctx, 'Orders', options);
|
||||
await app.models.StarredModule.toggleStarredModule(ctx, 'Clients', options);
|
||||
await app.models.StarredModule.toggleStarredModule(ctx, 'Orders', options);
|
||||
await app.models.StarredModule.toggleStarredModule(ctx, 'Items', options);
|
||||
await app.models.StarredModule.toggleStarredModule(ctx, 'Claims', options);
|
||||
await app.models.StarredModule.toggleStarredModule(ctx, 'Clients', options);
|
||||
await app.models.StarredModule.toggleStarredModule(ctx, 'Orders', options);
|
||||
await app.models.StarredModule.toggleStarredModule(ctx, 'Zones', options);
|
||||
|
||||
const items = await app.models.StarredModule.findOne(filter, options);
|
||||
|
||||
filter.where.moduleFk = 'Claims';
|
||||
const claims = await app.models.StarredModule.findOne(filter, options);
|
||||
|
||||
filter.where.moduleFk = 'Clients';
|
||||
let clients = await app.models.StarredModule.findOne(filter, options);
|
||||
|
||||
filter.where.moduleFk = 'Orders';
|
||||
let orders = await app.models.StarredModule.findOne(filter, options);
|
||||
|
||||
filter.where.moduleFk = 'Zones';
|
||||
const zones = await app.models.StarredModule.findOne(filter, options);
|
||||
|
||||
expect(items.position).toEqual(1);
|
||||
expect(claims.position).toEqual(2);
|
||||
expect(clients.position).toEqual(3);
|
||||
expect(orders.position).toEqual(4);
|
||||
expect(zones.position).toEqual(5);
|
||||
|
||||
await app.models.StarredModule.setPosition(ctx, 'Clients', 'right', options);
|
||||
|
||||
filter.where.moduleFk = 'Orders';
|
||||
orders = await app.models.StarredModule.findOne(filter, options);
|
||||
|
||||
filter.where.moduleFk = 'Clients';
|
||||
clients = await app.models.StarredModule.findOne(filter, options);
|
||||
|
||||
expect(orders.position).toEqual(3);
|
||||
expect(clients.position).toEqual(4);
|
||||
|
||||
await tx.rollback();
|
||||
} catch (e) {
|
||||
await tx.rollback();
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
|
||||
it('should switch two modules after adding and deleting a module between them', async() => {
|
||||
const tx = await app.models.StarredModule.beginTransaction({});
|
||||
|
||||
const filter = {
|
||||
where: {
|
||||
workerFk: ctx.req.accessToken.userId,
|
||||
moduleFk: 'Items'
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
const options = {transaction: tx};
|
||||
|
||||
await app.models.StarredModule.toggleStarredModule(ctx, 'Items', options);
|
||||
await app.models.StarredModule.toggleStarredModule(ctx, 'Clients', options);
|
||||
await app.models.StarredModule.toggleStarredModule(ctx, 'Claims', options);
|
||||
await app.models.StarredModule.toggleStarredModule(ctx, 'Orders', options);
|
||||
await app.models.StarredModule.toggleStarredModule(ctx, 'Zones', options);
|
||||
|
||||
const items = await app.models.StarredModule.findOne(filter, options);
|
||||
|
||||
filter.where.moduleFk = 'Clients';
|
||||
let clients = await app.models.StarredModule.findOne(filter, options);
|
||||
|
||||
filter.where.moduleFk = 'Claims';
|
||||
const claims = await app.models.StarredModule.findOne(filter, options);
|
||||
|
||||
filter.where.moduleFk = 'Orders';
|
||||
let orders = await app.models.StarredModule.findOne(filter, options);
|
||||
|
||||
filter.where.moduleFk = 'Zones';
|
||||
const zones = await app.models.StarredModule.findOne(filter, options);
|
||||
|
||||
expect(items.position).toEqual(1);
|
||||
expect(clients.position).toEqual(2);
|
||||
expect(claims.position).toEqual(3);
|
||||
expect(orders.position).toEqual(4);
|
||||
expect(zones.position).toEqual(5);
|
||||
|
||||
await app.models.StarredModule.toggleStarredModule(ctx, 'Claims', options);
|
||||
await app.models.StarredModule.setPosition(ctx, 'Clients', 'right', options);
|
||||
|
||||
filter.where.moduleFk = 'Clients';
|
||||
clients = await app.models.StarredModule.findOne(filter, options);
|
||||
|
||||
filter.where.moduleFk = 'Orders';
|
||||
orders = await app.models.StarredModule.findOne(filter, options);
|
||||
|
||||
expect(orders.position).toEqual(2);
|
||||
expect(clients.position).toEqual(4);
|
||||
|
||||
await tx.rollback();
|
||||
} catch (e) {
|
||||
await tx.rollback();
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
});
|
|
@ -27,6 +27,7 @@ describe('toggleStarredModule()', () => {
|
|||
expect(starredModules.length).toEqual(1);
|
||||
expect(starredModule.moduleFk).toEqual('Orders');
|
||||
expect(starredModule.workerFk).toEqual(activeCtx.accessToken.userId);
|
||||
expect(starredModule.position).toEqual(starredModules.length);
|
||||
|
||||
await app.models.StarredModule.toggleStarredModule(ctx, 'Orders');
|
||||
starredModules = await app.models.StarredModule.getStarredModules(ctx);
|
||||
|
|
|
@ -18,24 +18,61 @@ module.exports = function(Self) {
|
|||
}
|
||||
});
|
||||
|
||||
Self.toggleStarredModule = async(ctx, moduleName) => {
|
||||
Self.toggleStarredModule = async(ctx, moduleName, options) => {
|
||||
const models = Self.app.models;
|
||||
const userId = ctx.req.accessToken.userId;
|
||||
const filter = {
|
||||
where: {
|
||||
workerFk: userId,
|
||||
moduleFk: moduleName
|
||||
|
||||
let tx;
|
||||
let myOptions = {};
|
||||
|
||||
if (typeof options == 'object')
|
||||
Object.assign(myOptions, options);
|
||||
|
||||
if (!myOptions.transaction) {
|
||||
tx = await Self.beginTransaction({});
|
||||
myOptions.transaction = tx;
|
||||
}
|
||||
|
||||
try {
|
||||
const filter = {
|
||||
where: {
|
||||
workerFk: userId,
|
||||
moduleFk: moduleName
|
||||
}
|
||||
};
|
||||
|
||||
const [starredModule] = await models.StarredModule.find(filter, myOptions);
|
||||
|
||||
delete filter.moduleName;
|
||||
const allStarredModules = await models.StarredModule.getStarredModules(ctx, myOptions);
|
||||
|
||||
let addedModule;
|
||||
|
||||
if (starredModule)
|
||||
await starredModule.destroy(myOptions);
|
||||
else {
|
||||
let highestPosition;
|
||||
if (allStarredModules.length) {
|
||||
allStarredModules.sort((a, b) => {
|
||||
return a.position - b.position;
|
||||
});
|
||||
highestPosition = allStarredModules[allStarredModules.length - 1].position + 1;
|
||||
} else
|
||||
highestPosition = 1;
|
||||
|
||||
addedModule = await models.StarredModule.create({
|
||||
workerFk: userId,
|
||||
moduleFk: moduleName,
|
||||
position: highestPosition
|
||||
}, myOptions);
|
||||
}
|
||||
};
|
||||
|
||||
const [starredModule] = await Self.app.models.StarredModule.find(filter);
|
||||
if (tx) await tx.commit();
|
||||
|
||||
if (starredModule)
|
||||
await starredModule.destroy();
|
||||
else {
|
||||
return Self.app.models.StarredModule.create({
|
||||
workerFk: userId,
|
||||
moduleFk: moduleName
|
||||
});
|
||||
return addedModule;
|
||||
} catch (e) {
|
||||
if (tx) await tx.rollback();
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
module.exports = Self => {
|
||||
require('../methods/starred-module/getStarredModules')(Self);
|
||||
require('../methods/starred-module/toggleStarredModule')(Self);
|
||||
require('../methods/starred-module/setPosition')(Self);
|
||||
};
|
||||
|
|
|
@ -18,6 +18,10 @@
|
|||
"moduleFk": {
|
||||
"type": "string",
|
||||
"required": true
|
||||
},
|
||||
"position": {
|
||||
"type": "number",
|
||||
"required": true
|
||||
}
|
||||
},
|
||||
"relations": {
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
INSERT INTO salix.module (code) VALUES ('Monitors');
|
|
@ -120,7 +120,7 @@ BEGIN
|
|||
GROUP BY tl.ticketFk
|
||||
ON DUPLICATE KEY UPDATE
|
||||
isAvailable = 0;
|
||||
/*
|
||||
|
||||
INSERT INTO tmp.ticketProblems(ticketFk, itemShortage)
|
||||
SELECT ticketFk, problem
|
||||
FROM (
|
||||
|
@ -142,10 +142,10 @@ BEGIN
|
|||
AND NOT i.generic
|
||||
AND CURDATE() = vDate
|
||||
AND t.warehouseFk = vWarehouse
|
||||
GROUP BY tl.ticketFk LIMIT 1) sub
|
||||
GROUP BY tl.ticketFk) sub
|
||||
ON DUPLICATE KEY UPDATE
|
||||
itemShortage = sub.problem;
|
||||
*/
|
||||
|
||||
INSERT INTO tmp.ticketProblems(ticketFk, itemDelay)
|
||||
SELECT ticketFk, problem
|
||||
FROM (
|
||||
|
@ -165,7 +165,7 @@ BEGIN
|
|||
AND NOT i.generic
|
||||
AND CURDATE() = vDate
|
||||
AND t.warehouseFk = vWarehouse
|
||||
GROUP BY tl.ticketFk LIMIT 1) sub
|
||||
GROUP BY tl.ticketFk) sub
|
||||
ON DUPLICATE KEY UPDATE
|
||||
itemDelay = sub.problem;
|
||||
END WHILE;
|
||||
|
@ -182,7 +182,6 @@ BEGIN
|
|||
|
||||
DROP TEMPORARY TABLE
|
||||
tmp.clientGetDebt,
|
||||
tmp.ticketList;
|
||||
|
||||
tmp.ticketList;
|
||||
END;;$$
|
||||
DELIMITER ;
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
ALTER TABLE `vn`.`starredModule`
|
||||
ADD `position` INT NOT NULL AFTER `moduleFk`;
|
||||
|
||||
SET @count:=0;
|
||||
UPDATE `vn`.`starredModule` sm
|
||||
JOIN (
|
||||
SELECT sm.id, IF(@workerFk = sm.workerFk, @count:=@count+1, @count:=1) AS position, @workerFk:=sm.workerFk
|
||||
FROM `vn`.`starredModule` sm ORDER BY workerFk, moduleFk ASC) AS smt ON smt.id = sm.id
|
||||
SET sm.position = smt.position;
|
|
@ -0,0 +1,18 @@
|
|||
CREATE TABLE `vn`.`invoiceInLog` (
|
||||
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`originFk` MEDIUMINT UNSIGNED NOT NULL,
|
||||
`userFk` int(10) unsigned DEFAULT NULL,
|
||||
`action` set('insert','update','delete') COLLATE utf8_unicode_ci NOT NULL,
|
||||
`creationDate` timestamp NULL DEFAULT current_timestamp(),
|
||||
`description` text CHARACTER SET utf8 DEFAULT NULL,
|
||||
`changedModel` varchar(45) COLLATE utf8_unicode_ci DEFAULT NULL,
|
||||
`oldInstance` text COLLATE utf8_unicode_ci DEFAULT NULL,
|
||||
`newInstance` text COLLATE utf8_unicode_ci DEFAULT NULL,
|
||||
`changedModelId` int(11) DEFAULT NULL,
|
||||
`changedModelValue` varchar(45) COLLATE utf8_unicode_ci DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `originFk` (`originFk`),
|
||||
KEY `userFk` (`userFk`),
|
||||
CONSTRAINT `invoiceInLog_ibfk_1` FOREIGN KEY (`originFk`) REFERENCES `vn`.`invoiceIn` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
CONSTRAINT `invoiceInLog_ibfk_2` FOREIGN KEY (`userFk`) REFERENCES `account`.`user` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
|
|
@ -0,0 +1,103 @@
|
|||
DROP PROCEDURE IF EXISTS `vn`.`ticket_componentMakeUpdate`;
|
||||
|
||||
DELIMITER $$
|
||||
$$
|
||||
|
||||
CREATE
|
||||
DEFINER = root@`%` PROCEDURE `vn`.`ticket_componentMakeUpdate`(IN vTicketFk INT, IN vClientFk INT,
|
||||
IN vNickname VARCHAR(50), IN vAgencyModeFk INT,
|
||||
IN vAddressFk INT, IN vZoneFk INT, IN vWarehouseFk TINYINT,
|
||||
IN vCompanyFk SMALLINT, IN vShipped DATETIME,
|
||||
IN vLanded DATE, IN vIsDeleted TINYINT(1),
|
||||
IN vHasToBeUnrouted TINYINT(1), IN vOption INT)
|
||||
BEGIN
|
||||
/**
|
||||
* Modifica en el ticket los campos que se le pasan por parámetro
|
||||
* y cambia sus componentes
|
||||
*
|
||||
* @param vTicketFk Id del ticket a modificar
|
||||
* @param vClientFk nuevo cliente
|
||||
* @param vNickname nuevo alias
|
||||
* @param vAgencyModeFk nueva agencia
|
||||
* @param vAddressFk nuevo consignatario
|
||||
* @param vZoneFk nueva zona
|
||||
* @param vWarehouseFk nuevo almacen
|
||||
* @param vCompanyFk nueva empresa
|
||||
* @param vShipped nueva fecha del envio de mercancia
|
||||
* @param vLanded nueva fecha de recepcion de mercancia
|
||||
* @param vIsDeleted si se borra el ticket
|
||||
* @param vHasToBeUnrouted si se le elimina la ruta al ticket
|
||||
* @param vOption opcion para el case del proc ticketComponentUpdateSale
|
||||
*/
|
||||
DECLARE vPrice DECIMAL(10,2);
|
||||
DECLARE vBonus DECIMAL(10,2);
|
||||
DECLARE EXIT HANDLER FOR SQLEXCEPTION
|
||||
BEGIN
|
||||
ROLLBACK;
|
||||
RESIGNAL;
|
||||
END;
|
||||
|
||||
CALL ticket_componentPreview (vTicketFk, vLanded, vAddressFk, vZoneFk, vWarehouseFk);
|
||||
|
||||
START TRANSACTION;
|
||||
|
||||
IF (SELECT addressFk FROM ticket WHERE id = vTicketFk) <> vAddressFk THEN
|
||||
|
||||
UPDATE ticket t
|
||||
JOIN address a ON a.id = vAddressFk
|
||||
SET t.nickname = a.nickname
|
||||
WHERE t.id = vTicketFk;
|
||||
|
||||
END IF;
|
||||
|
||||
CALL zone_getShippedWarehouse(vlanded, vAddressFk, vAgencyModeFk);
|
||||
|
||||
SELECT zoneFk, price, bonus INTO vZoneFk, vPrice, vBonus
|
||||
FROM tmp.zoneGetShipped
|
||||
WHERE shipped BETWEEN DATE(vShipped) AND util.dayEnd(vShipped) AND warehouseFk = vWarehouseFk LIMIT 1;
|
||||
|
||||
UPDATE ticket t
|
||||
SET
|
||||
t.clientFk = vClientFk,
|
||||
t.nickname = vNickname,
|
||||
t.agencyModeFk = vAgencyModeFk,
|
||||
t.addressFk = vAddressFk,
|
||||
t.zoneFk = vZoneFk,
|
||||
t.zonePrice = vPrice,
|
||||
t.zoneBonus = vBonus,
|
||||
t.warehouseFk = vWarehouseFk,
|
||||
t.companyFk = vCompanyFk,
|
||||
t.landed = vLanded,
|
||||
t.shipped = vShipped,
|
||||
t.isDeleted = vIsDeleted
|
||||
WHERE
|
||||
t.id = vTicketFk;
|
||||
|
||||
IF vHasToBeUnrouted THEN
|
||||
UPDATE ticket t SET t.routeFk = NULL
|
||||
WHERE t.id = vTicketFk;
|
||||
END IF;
|
||||
|
||||
IF vOption <> 8 THEN
|
||||
DROP TEMPORARY TABLE IF EXISTS tmp.sale;
|
||||
CREATE TEMPORARY TABLE tmp.sale
|
||||
(PRIMARY KEY (saleFk))
|
||||
ENGINE = MEMORY
|
||||
SELECT id AS saleFk, vWarehouseFk warehouseFk
|
||||
FROM sale s WHERE s.ticketFk = vTicketFk;
|
||||
|
||||
DROP TEMPORARY TABLE IF EXISTS tmp.ticketComponent;
|
||||
CREATE TEMPORARY TABLE tmp.ticketComponent
|
||||
SELECT * FROM tmp.ticketComponentPreview;
|
||||
|
||||
CALL ticketComponentUpdateSale (vOption);
|
||||
|
||||
DROP TEMPORARY TABLE tmp.sale;
|
||||
DROP TEMPORARY TABLE IF EXISTS tmp.ticketComponent;
|
||||
END IF;
|
||||
COMMIT;
|
||||
|
||||
DROP TEMPORARY TABLE tmp.zoneGetShipped, tmp.ticketComponentPreview;
|
||||
END$$
|
||||
DELIMITER ;
|
||||
|
|
@ -806,19 +806,6 @@ INSERT INTO `vn`.`priceFixed`(`id`, `itemFk`, `rate0`, `rate1`, `rate2`, `rate3`
|
|||
(2, 3, 10, 10, 10, 10, CURDATE(), DATE_ADD(CURDATE(), INTERVAL +1 MONTH), 0, 1, CURDATE()),
|
||||
(3, 5, 8.5, 10, 7.5, 6, CURDATE(), DATE_ADD(CURDATE(), INTERVAL +1 MONTH), 1, 2, CURDATE());
|
||||
|
||||
INSERT INTO `vn`.`expedition`(`id`, `agencyModeFk`, `ticketFk`, `isBox`, `created`, `itemFk`, `counter`, `checked`, `workerFk`)
|
||||
VALUES
|
||||
(1, 1, 1, 71, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 1, 1, 1, 18),
|
||||
(2, 1, 1, 71, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 1, 2, 1, 18),
|
||||
(3, 1, 1, 71, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 2, 3, 1, 18),
|
||||
(4, 1, 1, 71, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 4, 4, 1, 18),
|
||||
(5, 1, 2, 71, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 1, 1, 1, 18),
|
||||
(6, 7, 3, 71, DATE_ADD(CURDATE(), INTERVAL -2 MONTH), 1, 1, 1, 18),
|
||||
(7, 2, 4, 71, DATE_ADD(CURDATE(), INTERVAL -3 MONTH), 1, 1, 1, 18),
|
||||
(8, 3, 5, 71, DATE_ADD(CURDATE(), INTERVAL -4 MONTH), 1, 1, 1, 18),
|
||||
(9, 3, 6, 71, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 1, 1, 1, 18),
|
||||
(10, 7, 7, 71, CURDATE(), 1, 1, 1, 18);
|
||||
|
||||
INSERT INTO `vn`.`expeditionBoxVol`(`boxFk`, `m3`, `ratio`)
|
||||
VALUES
|
||||
(71,0.141,1);
|
||||
|
@ -834,6 +821,19 @@ INSERT INTO `vn`.`packaging`(`id`, `volume`, `width`, `height`, `depth`, `isPack
|
|||
('cc', 1640038.00, 56.00, 220.00, 128.00, 1, CURDATE(), 15, 90.00),
|
||||
('pallet 100', 2745600.00, 100.00, 220.00, 120.00, 1, CURDATE(), 16, 0.00);
|
||||
|
||||
INSERT INTO `vn`.`expedition`(`id`, `agencyModeFk`, `ticketFk`, `isBox`, `created`, `itemFk`, `counter`, `checked`, `workerFk`, `externalId`, `packagingFk`)
|
||||
VALUES
|
||||
(1, 1, 1, 71, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 15, 1, 1, 18, 'UR9000006041', 94),
|
||||
(2, 1, 1, 71, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 16, 2, 1, 18, 'UR9000006041', 94),
|
||||
(3, 1, 1, 71, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), NULL, 3, 1, 18, 'UR9000006041', 94),
|
||||
(4, 1, 1, 71, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), NULL, 4, 1, 18, 'UR9000006041', 94),
|
||||
(5, 1, 2, 71, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), NULL, 1, 1, 18, NULL, 94),
|
||||
(6, 7, 3, 71, DATE_ADD(CURDATE(), INTERVAL -2 MONTH), NULL, 1, 1, 18, NULL, 94),
|
||||
(7, 2, 4, 71, DATE_ADD(CURDATE(), INTERVAL -3 MONTH), NULL, 1, 1, 18, NULL, 94),
|
||||
(8, 3, 5, 71, DATE_ADD(CURDATE(), INTERVAL -4 MONTH), NULL, 1, 1, 18, NULL, 94),
|
||||
(9, 3, 6, 71, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), NULL, 1, 1, 18, NULL, 94),
|
||||
(10, 7, 7, 71, CURDATE(), NULL, 1, 1, 18, NULL, 94);
|
||||
|
||||
INSERT INTO `vn`.`ticketPackaging`(`id`, `ticketFk`, `packagingFk`, `quantity`, `created`, `pvp`)
|
||||
VALUES
|
||||
(1, 1, 2, 2, CURDATE(), NULL),
|
||||
|
@ -2348,4 +2348,25 @@ INSERT INTO `vn`.`zoneAgencyMode`(`id`, `agencyModeFk`, `zoneFk`)
|
|||
(1, 1, 1),
|
||||
(2, 1, 2),
|
||||
(3, 6, 5),
|
||||
(4, 7, 1);
|
||||
(4, 7, 1);
|
||||
|
||||
INSERT INTO `vn`.`expeditionTruck` (`id`, `ETD`, `description`)
|
||||
VALUES
|
||||
(1, CONCAT(YEAR(DATE_ADD(CURDATE(), INTERVAL +3 YEAR))), 'Best truck in fleet');
|
||||
|
||||
INSERT INTO `vn`.`expeditionPallet` (`id`, `truckFk`, `built`, `position`, `isPrint`)
|
||||
VALUES
|
||||
(1, 1, CURDATE(), 1, 1);
|
||||
|
||||
INSERT INTO `vn`.`expeditionScan` (`id`, `expeditionFk`, `scanned`, `palletFk`)
|
||||
VALUES
|
||||
(1, 1, CURDATE(), 1),
|
||||
(2, 2, CURDATE(), 1),
|
||||
(3, 3, CURDATE(), 1),
|
||||
(4, 4, CURDATE(), 1),
|
||||
(5, 5, CURDATE(), 1),
|
||||
(6, 6, CURDATE(), 1),
|
||||
(7, 7, CURDATE(), 1),
|
||||
(8, 8, CURDATE(), 1),
|
||||
(9, 9, CURDATE(), 1),
|
||||
(10, 10, CURDATE(), 1);
|
|
@ -151,6 +151,7 @@ export default {
|
|||
mobile: 'vn-client-basic-data vn-textfield[ng-model="$ctrl.client.mobile"]',
|
||||
salesPerson: 'vn-client-basic-data vn-autocomplete[ng-model="$ctrl.client.salesPersonFk"]',
|
||||
channel: 'vn-client-basic-data vn-autocomplete[ng-model="$ctrl.client.contactChannelFk"]',
|
||||
transferor: 'vn-client-basic-data vn-autocomplete[ng-model="$ctrl.client.transferorFk"]',
|
||||
saveButton: 'vn-client-basic-data button[type=submit]'
|
||||
},
|
||||
clientFiscalData: {
|
||||
|
@ -162,7 +163,6 @@ export default {
|
|||
postcode: 'vn-client-fiscal-data vn-datalist[ng-model="$ctrl.client.postcode"]',
|
||||
sageTax: 'vn-client-fiscal-data vn-autocomplete[ng-model="$ctrl.client.sageTaxTypeFk"]',
|
||||
sageTransaction: 'vn-client-fiscal-data vn-autocomplete[ng-model="$ctrl.client.sageTransactionTypeFk"]',
|
||||
transferor: 'vn-client-fiscal-data vn-autocomplete[ng-model="$ctrl.client.transferorFk"]',
|
||||
city: 'vn-client-fiscal-data vn-datalist[ng-model="$ctrl.client.city"]',
|
||||
province: 'vn-client-fiscal-data vn-autocomplete[ng-model="$ctrl.client.provinceFk"]',
|
||||
country: 'vn-client-fiscal-data vn-autocomplete[ng-model="$ctrl.client.countryFk"]',
|
||||
|
@ -474,7 +474,7 @@ export default {
|
|||
advancedSearchDaysOnward: 'vn-ticket-search-panel vn-input-number[ng-model="filter.scopeDays"]',
|
||||
advancedSearchClient: 'vn-ticket-search-panel vn-textfield[ng-model="filter.clientFk"]',
|
||||
advancedSearchButton: 'vn-ticket-search-panel button[type=submit]',
|
||||
newTicketButton: 'vn-ticket-index a[ui-sref="ticket.create"]',
|
||||
newTicketButton: 'vn-ticket-index vn-button[icon="add"]',
|
||||
searchResult: 'vn-ticket-index vn-card > vn-table > div > vn-tbody > a.vn-tr',
|
||||
firstTicketCheckbox: 'vn-ticket-index vn-tbody > a:nth-child(1) > vn-td:nth-child(1) > vn-check',
|
||||
secondTicketCheckbox: 'vn-ticket-index vn-tbody > a:nth-child(2) > vn-td:nth-child(1) > vn-check',
|
||||
|
@ -572,11 +572,11 @@ export default {
|
|||
firstSaleZoomedImage: 'body > div > div > img',
|
||||
firstSaleQuantity: 'vn-ticket-sale [ng-model="sale.quantity"]',
|
||||
firstSaleQuantityCell: 'vn-ticket-sale vn-tr:nth-child(1) > vn-td-editable:nth-child(6)',
|
||||
firstSalePrice: 'vn-ticket-sale vn-table vn-tr:nth-child(1) > vn-td:nth-child(8) > span',
|
||||
firstSalePrice: 'vn-ticket-sale vn-table vn-tr:nth-child(1) > vn-td:nth-child(9) > span',
|
||||
firstSalePriceInput: '.vn-popover.shown input[ng-model="$ctrl.field"]',
|
||||
firstSaleDiscount: 'vn-ticket-sale vn-table vn-tr:nth-child(1) > vn-td:nth-child(9) > span',
|
||||
firstSaleDiscount: 'vn-ticket-sale vn-table vn-tr:nth-child(1) > vn-td:nth-child(10) > span',
|
||||
firstSaleDiscountInput: '.vn-popover.shown [ng-model="$ctrl.field"]',
|
||||
firstSaleImport: 'vn-ticket-sale:nth-child(1) vn-td:nth-child(10)',
|
||||
firstSaleImport: 'vn-ticket-sale:nth-child(1) vn-td:nth-child(11)',
|
||||
firstSaleReservedIcon: 'vn-ticket-sale vn-tr:nth-child(1) > vn-td:nth-child(2) > vn-icon:nth-child(3)',
|
||||
firstSaleColour: 'vn-ticket-sale vn-tr:nth-child(1) vn-fetched-tags section',
|
||||
firstSaleCheckbox: 'vn-ticket-sale vn-tr:nth-child(1) vn-check[ng-model="sale.checked"]',
|
||||
|
@ -837,7 +837,8 @@ export default {
|
|||
saveButton: 'vn-worker-pbx button[type=submit]'
|
||||
},
|
||||
workerTimeControl: {
|
||||
timeDialog: '.vn-dialog.shown vn-input-time[ng-model="$ctrl.newTime"]',
|
||||
dialogTimeInput: '.vn-dialog.shown vn-input-time[ng-model="$ctrl.newTimeEntry.timed"]',
|
||||
dialogTimeDirection: '.vn-dialog.shown vn-autocomplete[ng-model="$ctrl.newTimeEntry.direction"]',
|
||||
mondayAddTimeButton: 'vn-worker-time-control vn-table > div > vn-tfoot > vn-tr:nth-child(2) > vn-td:nth-child(1) > vn-icon-button',
|
||||
tuesdayAddTimeButton: 'vn-worker-time-control vn-table > div > vn-tfoot > vn-tr:nth-child(2) > vn-td:nth-child(2) > vn-icon-button',
|
||||
wednesdayAddTimeButton: 'vn-worker-time-control vn-table > div > vn-tfoot > vn-tr:nth-child(2) > vn-td:nth-child(3) > vn-icon-button',
|
||||
|
@ -845,35 +846,35 @@ export default {
|
|||
fridayAddTimeButton: 'vn-worker-time-control vn-table > div > vn-tfoot > vn-tr:nth-child(2) > vn-td:nth-child(5) > vn-icon-button',
|
||||
saturdayAddTimeButton: 'vn-worker-time-control vn-table > div > vn-tfoot > vn-tr:nth-child(2) > vn-td:nth-child(6) > vn-icon-button',
|
||||
sundayAddTimeButton: 'vn-worker-time-control vn-table > div > vn-tfoot > vn-tr:nth-child(2) > vn-td:nth-child(7) > vn-icon-button',
|
||||
firstEntryOfMonday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(1) > section:nth-child(1) > vn-chip > div',
|
||||
firstEntryOfTuesday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(2) > section:nth-child(1) > vn-chip > div',
|
||||
firstEntryOfWednesday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(3) > section:nth-child(1) > vn-chip > div',
|
||||
firstEntryOfThursday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(4) > section:nth-child(1) > vn-chip > div',
|
||||
firstEntryOfFriday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(5) > section:nth-child(1) > vn-chip > div',
|
||||
firstEntryOfSaturday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(6) > section:nth-child(1) > vn-chip > div',
|
||||
firstEntryOfSunday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(7) > section:nth-child(1) > vn-chip > div',
|
||||
secondEntryOfMonday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(1) > section:nth-child(2) > vn-chip > div',
|
||||
secondEntryOfTuesday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(2) > section:nth-child(2) > vn-chip > div',
|
||||
secondEntryOfWednesday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(3) > section:nth-child(2) > vn-chip > div',
|
||||
secondEntryOfThursday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(4) > section:nth-child(2) > vn-chip > div',
|
||||
secondEntryOfFriday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(5) > section:nth-child(2) > vn-chip > div',
|
||||
secondEntryOfSaturday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(6) > section:nth-child(2) > vn-chip > div',
|
||||
secondEntryOfSunday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(7) > section:nth-child(2) > vn-chip > div',
|
||||
thirdEntryOfMonday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(1) > section:nth-child(3) > vn-chip > div',
|
||||
firstEntryOfMonday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(1) > section:nth-child(1) > vn-chip > div:nth-child(2)',
|
||||
firstEntryOfTuesday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(2) > section:nth-child(1) > vn-chip > div:nth-child(2)',
|
||||
firstEntryOfWednesday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(3) > section:nth-child(1) > vn-chip > div:nth-child(2)',
|
||||
firstEntryOfThursday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(4) > section:nth-child(1) > vn-chip > div:nth-child(2)',
|
||||
firstEntryOfFriday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(5) > section:nth-child(1) > vn-chip > div:nth-child(2)',
|
||||
firstEntryOfSaturday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(6) > section:nth-child(1) > vn-chip > div:nth-child(2)',
|
||||
firstEntryOfSunday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(7) > section:nth-child(1) > vn-chip > div:nth-child(2)',
|
||||
secondEntryOfMonday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(1) > section:nth-child(2) > vn-chip > div:nth-child(2)',
|
||||
secondEntryOfTuesday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(2) > section:nth-child(2) > vn-chip > div:nth-child(2)',
|
||||
secondEntryOfWednesday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(3) > section:nth-child(2) > vn-chip > div:nth-child(2)',
|
||||
secondEntryOfThursday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(4) > section:nth-child(2) > vn-chip > div:nth-child(2)',
|
||||
secondEntryOfFriday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(5) > section:nth-child(2) > vn-chip > div:nth-child(2)',
|
||||
secondEntryOfSaturday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(6) > section:nth-child(2) > vn-chip > div:nth-child(2)',
|
||||
secondEntryOfSunday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(7) > section:nth-child(2) > vn-chip > div:nth-child(2)',
|
||||
thirdEntryOfMonday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(1) > section:nth-child(3) > vn-chip > div:nth-child(2)',
|
||||
thirdEntryOfMondayDelete: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(1) > section:nth-child(3) > vn-chip > vn-icon[icon="cancel"]',
|
||||
thirdEntryOfTuesday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(2) > section:nth-child(3) > vn-chip > div',
|
||||
thirdEntryOfWednesday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(3) > section:nth-child(3) > vn-chip > div',
|
||||
thirdEntryOfThursday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(4) > section:nth-child(3) > vn-chip > div',
|
||||
thirdEntryOfFriday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(5) > section:nth-child(3) > vn-chip > div',
|
||||
thirdEntryOfSaturday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(6) > section:nth-child(3) > vn-chip > div',
|
||||
thirdEntryOfSunday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(7) > section:nth-child(3) > vn-chip > div',
|
||||
fourthEntryOfMonday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(1) > section:nth-child(4) > vn-chip > div',
|
||||
fourthEntryOfTuesday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(2) > section:nth-child(4) > vn-chip > div',
|
||||
fourthEntryOfWednesday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(3) > section:nth-child(4) > vn-chip > div',
|
||||
fourthEntryOfThursday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(4) > section:nth-child(4) > vn-chip > div',
|
||||
fourthEntryOfFriday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(5) > section:nth-child(4) > vn-chip > div',
|
||||
fourthEntryOfSaturday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(6) > section:nth-child(4) > vn-chip > div',
|
||||
fourthEntryOfSunday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(7) > section:nth-child(4) > vn-chip > div',
|
||||
thirdEntryOfTuesday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(2) > section:nth-child(3) > vn-chip > div:nth-child(2)',
|
||||
thirdEntryOfWednesday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(3) > section:nth-child(3) > vn-chip > div:nth-child(2)',
|
||||
thirdEntryOfThursday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(4) > section:nth-child(3) > vn-chip > div:nth-child(2)',
|
||||
thirdEntryOfFriday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(5) > section:nth-child(3) > vn-chip > div:nth-child(2)',
|
||||
thirdEntryOfSaturday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(6) > section:nth-child(3) > vn-chip > div:nth-child(2)',
|
||||
thirdEntryOfSunday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(7) > section:nth-child(3) > vn-chip > div:nth-child(2)',
|
||||
fourthEntryOfMonday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(1) > section:nth-child(4) > vn-chip > div:nth-child(2)',
|
||||
fourthEntryOfTuesday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(2) > section:nth-child(4) > vn-chip > div:nth-child(2)',
|
||||
fourthEntryOfWednesday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(3) > section:nth-child(4) > vn-chip > div:nth-child(2)',
|
||||
fourthEntryOfThursday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(4) > section:nth-child(4) > vn-chip > div:nth-child(2)',
|
||||
fourthEntryOfFriday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(5) > section:nth-child(4) > vn-chip > div:nth-child(2)',
|
||||
fourthEntryOfSaturday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(6) > section:nth-child(4) > vn-chip > div:nth-child(2)',
|
||||
fourthEntryOfSunday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(7) > section:nth-child(4) > vn-chip > div:nth-child(2)',
|
||||
mondayWorkedHours: 'vn-worker-time-control vn-table > div > vn-tfoot > vn-tr:nth-child(1) > vn-td:nth-child(1)',
|
||||
tuesdayWorkedHours: 'vn-worker-time-control vn-table > div > vn-tfoot > vn-tr:nth-child(1) > vn-td:nth-child(2)',
|
||||
wednesdayWorkedHours: 'vn-worker-time-control vn-table > div > vn-tfoot > vn-tr:nth-child(1) > vn-td:nth-child(3)',
|
||||
|
@ -888,7 +889,7 @@ export default {
|
|||
},
|
||||
workerCalendar: {
|
||||
year: 'vn-worker-calendar vn-autocomplete[ng-model="$ctrl.year"]',
|
||||
totalHolidaysUsed: 'vn-worker-calendar div.totalBox > div',
|
||||
totalHolidaysUsed: 'vn-worker-calendar div.totalBox:first-child > div',
|
||||
penultimateMondayOfJanuary: 'vn-worker-calendar vn-calendar:nth-child(2) section:nth-child(22) > div',
|
||||
lastMondayOfMarch: 'vn-worker-calendar vn-calendar:nth-child(4) section:nth-child(29) > div',
|
||||
fistMondayOfMay: 'vn-worker-calendar vn-calendar:nth-child(6) section:nth-child(8) > div',
|
||||
|
@ -896,11 +897,11 @@ export default {
|
|||
secondTuesdayOfMay: 'vn-worker-calendar vn-calendar:nth-child(6) section:nth-child(16) > div',
|
||||
secondWednesdayOfMay: 'vn-worker-calendar vn-calendar:nth-child(6) section:nth-child(17) > div',
|
||||
secondThursdayOfMay: 'vn-worker-calendar vn-calendar:nth-child(6) section:nth-child(18) > div',
|
||||
holidays: 'vn-worker-calendar > vn-side-menu div:nth-child(3) > vn-chip:nth-child(1)',
|
||||
absence: 'vn-worker-calendar > vn-side-menu div:nth-child(3) > vn-chip:nth-child(2)',
|
||||
halfHoliday: 'vn-worker-calendar > vn-side-menu div:nth-child(3) > vn-chip:nth-child(3)',
|
||||
furlough: 'vn-worker-calendar > vn-side-menu div:nth-child(3) > vn-chip:nth-child(4)',
|
||||
halfFurlough: 'vn-worker-calendar > vn-side-menu div:nth-child(3) > vn-chip:nth-child(5)',
|
||||
holidays: 'vn-worker-calendar > vn-side-menu [name="absenceTypes"] > vn-chip:nth-child(1)',
|
||||
absence: 'vn-worker-calendar > vn-side-menu [name="absenceTypes"] > vn-chip:nth-child(2)',
|
||||
halfHoliday: 'vn-worker-calendar > vn-side-menu [name="absenceTypes"] > vn-chip:nth-child(3)',
|
||||
furlough: 'vn-worker-calendar > vn-side-menu [name="absenceTypes"] > vn-chip:nth-child(4)',
|
||||
halfFurlough: 'vn-worker-calendar > vn-side-menu [name="absenceTypes"] > vn-chip:nth-child(5)',
|
||||
},
|
||||
invoiceOutIndex: {
|
||||
topbarSearch: 'vn-searchbar',
|
||||
|
|
|
@ -34,6 +34,7 @@ describe('Client Edit basicData path', () => {
|
|||
await page.clearInput(selectors.clientBasicData.email);
|
||||
await page.write(selectors.clientBasicData.email, 'PWallace@verdnatura.es');
|
||||
await page.autocompleteSearch(selectors.clientBasicData.channel, 'Rumors on the streets');
|
||||
await page.autocompleteSearch(selectors.clientBasicData.transferor, 'Max Eisenhardt');
|
||||
await page.waitToClick(selectors.clientBasicData.saveButton);
|
||||
const message = await page.waitForSnackbar();
|
||||
|
||||
|
@ -67,6 +68,13 @@ describe('Client Edit basicData path', () => {
|
|||
|
||||
expect(result).toEqual('Rumors on the streets');
|
||||
});
|
||||
|
||||
it('should confirm the previous client have been selected', async() => {
|
||||
const result = await page
|
||||
.waitToGetProperty(selectors.clientBasicData.transferor, 'value');
|
||||
|
||||
expect(result).toEqual('Max Eisenhardt');
|
||||
});
|
||||
});
|
||||
|
||||
describe('as salesAssistant', () => {
|
||||
|
|
|
@ -68,7 +68,6 @@ describe('Client Edit fiscalData path', () => {
|
|||
await page.write(selectors.clientFiscalData.city, 'Valencia');
|
||||
await page.autocompleteSearch(selectors.clientFiscalData.sageTax, 'operaciones no sujetas');
|
||||
await page.autocompleteSearch(selectors.clientFiscalData.sageTransaction, 'regularización de inversiones');
|
||||
await page.autocompleteSearch(selectors.clientFiscalData.transferor, 'Max Eisenhardt');
|
||||
await page.clearInput(selectors.clientFiscalData.postcode);
|
||||
await page.write(selectors.clientFiscalData.postcode, '46000');
|
||||
await page.waitToClick(selectors.clientFiscalData.activeCheckbox);
|
||||
|
@ -202,12 +201,6 @@ describe('Client Edit fiscalData path', () => {
|
|||
expect(result).toEqual('36: Regularización de inversiones');
|
||||
});
|
||||
|
||||
it('should confirm the transferor have been edited', async() => {
|
||||
const result = await page.waitToGetProperty(selectors.clientFiscalData.transferor, 'value');
|
||||
|
||||
expect(result).toEqual('Max Eisenhardt');
|
||||
});
|
||||
|
||||
it('should confirm the city have been autocompleted', async() => {
|
||||
const result = await page.waitToGetProperty(selectors.clientFiscalData.city, 'value');
|
||||
|
||||
|
|
|
@ -22,7 +22,8 @@ describe('Worker time control path', () => {
|
|||
const scanTime = '07:00';
|
||||
|
||||
await page.waitToClick(selectors.workerTimeControl.mondayAddTimeButton);
|
||||
await page.pickTime(selectors.workerTimeControl.timeDialog, scanTime);
|
||||
await page.pickTime(selectors.workerTimeControl.dialogTimeInput, scanTime);
|
||||
await page.autocompleteSearch(selectors.workerTimeControl.dialogTimeDirection, 'in');
|
||||
await page.respondToDialog('accept');
|
||||
const result = await page.waitToGetProperty(selectors.workerTimeControl.firstEntryOfMonday, 'innerText');
|
||||
|
||||
|
@ -33,7 +34,8 @@ describe('Worker time control path', () => {
|
|||
const scanTime = '10:00';
|
||||
|
||||
await page.waitToClick(selectors.workerTimeControl.mondayAddTimeButton);
|
||||
await page.pickTime(selectors.workerTimeControl.timeDialog, scanTime);
|
||||
await page.pickTime(selectors.workerTimeControl.dialogTimeInput, scanTime);
|
||||
await page.autocompleteSearch(selectors.workerTimeControl.dialogTimeDirection, 'intermediate');
|
||||
await page.respondToDialog('accept');
|
||||
const result = await page.waitToGetProperty(selectors.workerTimeControl.secondEntryOfMonday, 'innerText');
|
||||
|
||||
|
@ -44,7 +46,8 @@ describe('Worker time control path', () => {
|
|||
const scanTime = '18:00';
|
||||
|
||||
await page.waitToClick(selectors.workerTimeControl.mondayAddTimeButton);
|
||||
await page.pickTime(selectors.workerTimeControl.timeDialog, scanTime);
|
||||
await page.pickTime(selectors.workerTimeControl.dialogTimeInput, scanTime);
|
||||
await page.autocompleteSearch(selectors.workerTimeControl.dialogTimeDirection, 'intermediate');
|
||||
await page.respondToDialog('accept');
|
||||
const result = await page.waitToGetProperty(selectors.workerTimeControl.thirdEntryOfMonday, 'innerText');
|
||||
|
||||
|
@ -66,7 +69,8 @@ describe('Worker time control path', () => {
|
|||
const scanTime = '14:00';
|
||||
|
||||
await page.waitToClick(selectors.workerTimeControl.mondayAddTimeButton);
|
||||
await page.pickTime(selectors.workerTimeControl.timeDialog, scanTime);
|
||||
await page.pickTime(selectors.workerTimeControl.dialogTimeInput, scanTime);
|
||||
await page.autocompleteSearch(selectors.workerTimeControl.dialogTimeDirection, 'out');
|
||||
await page.respondToDialog('accept');
|
||||
const result = await page.waitToGetProperty(selectors.workerTimeControl.thirdEntryOfMonday, 'innerText');
|
||||
|
||||
|
@ -77,7 +81,8 @@ describe('Worker time control path', () => {
|
|||
const scanTime = '10:20';
|
||||
|
||||
await page.waitToClick(selectors.workerTimeControl.mondayAddTimeButton);
|
||||
await page.pickTime(selectors.workerTimeControl.timeDialog, scanTime);
|
||||
await page.pickTime(selectors.workerTimeControl.dialogTimeInput, scanTime);
|
||||
await page.autocompleteSearch(selectors.workerTimeControl.dialogTimeDirection, 'intermediate');
|
||||
await page.respondToDialog('accept');
|
||||
const result = await page.waitToGetProperty(selectors.workerTimeControl.fourthEntryOfMonday, 'innerText');
|
||||
|
||||
|
@ -103,7 +108,8 @@ describe('Worker time control path', () => {
|
|||
const scanTime = '08:00';
|
||||
|
||||
await page.waitToClick(selectors.workerTimeControl.tuesdayAddTimeButton);
|
||||
await page.pickTime(selectors.workerTimeControl.timeDialog, scanTime);
|
||||
await page.pickTime(selectors.workerTimeControl.dialogTimeInput, scanTime);
|
||||
await page.autocompleteSearch(selectors.workerTimeControl.dialogTimeDirection, 'in');
|
||||
await page.respondToDialog('accept');
|
||||
const result = await page.waitToGetProperty(selectors.workerTimeControl.firstEntryOfTuesday, 'innerText');
|
||||
|
||||
|
@ -114,7 +120,8 @@ describe('Worker time control path', () => {
|
|||
const scanTime = '10:00';
|
||||
|
||||
await page.waitToClick(selectors.workerTimeControl.tuesdayAddTimeButton);
|
||||
await page.pickTime(selectors.workerTimeControl.timeDialog, scanTime);
|
||||
await page.pickTime(selectors.workerTimeControl.dialogTimeInput, scanTime);
|
||||
await page.autocompleteSearch(selectors.workerTimeControl.dialogTimeDirection, 'intermediate');
|
||||
await page.respondToDialog('accept');
|
||||
const result = await page.waitToGetProperty(selectors.workerTimeControl.secondEntryOfTuesday, 'innerText');
|
||||
|
||||
|
@ -125,7 +132,8 @@ describe('Worker time control path', () => {
|
|||
const scanTime = '10:20';
|
||||
|
||||
await page.waitToClick(selectors.workerTimeControl.tuesdayAddTimeButton);
|
||||
await page.pickTime(selectors.workerTimeControl.timeDialog, scanTime);
|
||||
await page.pickTime(selectors.workerTimeControl.dialogTimeInput, scanTime);
|
||||
await page.autocompleteSearch(selectors.workerTimeControl.dialogTimeDirection, 'intermediate');
|
||||
await page.respondToDialog('accept');
|
||||
const result = await page.waitToGetProperty(selectors.workerTimeControl.thirdEntryOfTuesday, 'innerText');
|
||||
|
||||
|
@ -136,7 +144,8 @@ describe('Worker time control path', () => {
|
|||
const scanTime = '16:00';
|
||||
|
||||
await page.waitToClick(selectors.workerTimeControl.tuesdayAddTimeButton);
|
||||
await page.pickTime(selectors.workerTimeControl.timeDialog, scanTime);
|
||||
await page.pickTime(selectors.workerTimeControl.dialogTimeInput, scanTime);
|
||||
await page.autocompleteSearch(selectors.workerTimeControl.dialogTimeDirection, 'out');
|
||||
await page.respondToDialog('accept');
|
||||
const result = await page.waitToGetProperty(selectors.workerTimeControl.fourthEntryOfTuesday, 'innerText');
|
||||
|
||||
|
@ -153,7 +162,8 @@ describe('Worker time control path', () => {
|
|||
const scanTime = '09:00';
|
||||
|
||||
await page.waitToClick(selectors.workerTimeControl.wednesdayAddTimeButton);
|
||||
await page.pickTime(selectors.workerTimeControl.timeDialog, scanTime);
|
||||
await page.pickTime(selectors.workerTimeControl.dialogTimeInput, scanTime);
|
||||
await page.autocompleteSearch(selectors.workerTimeControl.dialogTimeDirection, 'in');
|
||||
await page.respondToDialog('accept');
|
||||
const result = await page.waitToGetProperty(selectors.workerTimeControl.firstEntryOfWednesday, 'innerText');
|
||||
|
||||
|
@ -164,7 +174,8 @@ describe('Worker time control path', () => {
|
|||
const scanTime = '10:00';
|
||||
|
||||
await page.waitToClick(selectors.workerTimeControl.wednesdayAddTimeButton);
|
||||
await page.pickTime(selectors.workerTimeControl.timeDialog, scanTime);
|
||||
await page.pickTime(selectors.workerTimeControl.dialogTimeInput, scanTime);
|
||||
await page.autocompleteSearch(selectors.workerTimeControl.dialogTimeDirection, 'intermediate');
|
||||
await page.respondToDialog('accept');
|
||||
const result = await page.waitToGetProperty(selectors.workerTimeControl.secondEntryOfWednesday, 'innerText');
|
||||
|
||||
|
@ -175,7 +186,8 @@ describe('Worker time control path', () => {
|
|||
const scanTime = '10:20';
|
||||
|
||||
await page.waitToClick(selectors.workerTimeControl.wednesdayAddTimeButton);
|
||||
await page.pickTime(selectors.workerTimeControl.timeDialog, scanTime);
|
||||
await page.pickTime(selectors.workerTimeControl.dialogTimeInput, scanTime);
|
||||
await page.autocompleteSearch(selectors.workerTimeControl.dialogTimeDirection, 'intermediate');
|
||||
await page.respondToDialog('accept');
|
||||
const result = await page.waitToGetProperty(selectors.workerTimeControl.thirdEntryOfWednesday, 'innerText');
|
||||
|
||||
|
@ -186,7 +198,8 @@ describe('Worker time control path', () => {
|
|||
const scanTime = '17:00';
|
||||
|
||||
await page.waitToClick(selectors.workerTimeControl.wednesdayAddTimeButton);
|
||||
await page.pickTime(selectors.workerTimeControl.timeDialog, scanTime);
|
||||
await page.pickTime(selectors.workerTimeControl.dialogTimeInput, scanTime);
|
||||
await page.autocompleteSearch(selectors.workerTimeControl.dialogTimeDirection, 'out');
|
||||
await page.respondToDialog('accept');
|
||||
const result = await page.waitToGetProperty(selectors.workerTimeControl.fourthEntryOfWednesday, 'innerText');
|
||||
|
||||
|
@ -203,7 +216,8 @@ describe('Worker time control path', () => {
|
|||
const scanTime = '09:59';
|
||||
|
||||
await page.waitToClick(selectors.workerTimeControl.thursdayAddTimeButton);
|
||||
await page.pickTime(selectors.workerTimeControl.timeDialog, scanTime);
|
||||
await page.pickTime(selectors.workerTimeControl.dialogTimeInput, scanTime);
|
||||
await page.autocompleteSearch(selectors.workerTimeControl.dialogTimeDirection, 'in');
|
||||
await page.respondToDialog('accept');
|
||||
const result = await page.waitToGetProperty(selectors.workerTimeControl.firstEntryOfThursday, 'innerText');
|
||||
|
||||
|
@ -213,7 +227,8 @@ describe('Worker time control path', () => {
|
|||
it(`should joyfully scan out Hank Pym for break`, async() => {
|
||||
const scanTime = '10:00';
|
||||
await page.waitToClick(selectors.workerTimeControl.thursdayAddTimeButton);
|
||||
await page.pickTime(selectors.workerTimeControl.timeDialog, scanTime);
|
||||
await page.pickTime(selectors.workerTimeControl.dialogTimeInput, scanTime);
|
||||
await page.autocompleteSearch(selectors.workerTimeControl.dialogTimeDirection, 'intermediate');
|
||||
await page.respondToDialog('accept');
|
||||
const result = await page.waitToGetProperty(selectors.workerTimeControl.secondEntryOfThursday, 'innerText');
|
||||
|
||||
|
@ -223,7 +238,8 @@ describe('Worker time control path', () => {
|
|||
it(`should joyfully scan in Hank Pym from the break`, async() => {
|
||||
const scanTime = '10:20';
|
||||
await page.waitToClick(selectors.workerTimeControl.thursdayAddTimeButton);
|
||||
await page.pickTime(selectors.workerTimeControl.timeDialog, scanTime);
|
||||
await page.pickTime(selectors.workerTimeControl.dialogTimeInput, scanTime);
|
||||
await page.autocompleteSearch(selectors.workerTimeControl.dialogTimeDirection, 'intermediate');
|
||||
await page.respondToDialog('accept');
|
||||
const result = await page.waitToGetProperty(selectors.workerTimeControl.thirdEntryOfThursday, 'innerText');
|
||||
|
||||
|
@ -233,7 +249,8 @@ describe('Worker time control path', () => {
|
|||
it(`should joyfully scan out Hank Pym for the day`, async() => {
|
||||
const scanTime = '17:59';
|
||||
await page.waitToClick(selectors.workerTimeControl.thursdayAddTimeButton);
|
||||
await page.pickTime(selectors.workerTimeControl.timeDialog, scanTime);
|
||||
await page.pickTime(selectors.workerTimeControl.dialogTimeInput, scanTime);
|
||||
await page.autocompleteSearch(selectors.workerTimeControl.dialogTimeDirection, 'out');
|
||||
await page.respondToDialog('accept');
|
||||
const result = await page.waitToGetProperty(selectors.workerTimeControl.fourthEntryOfThursday, 'innerText');
|
||||
|
||||
|
@ -249,7 +266,8 @@ describe('Worker time control path', () => {
|
|||
it('should smilingly scan in Hank Pym', async() => {
|
||||
const scanTime = '07:30';
|
||||
await page.waitToClick(selectors.workerTimeControl.fridayAddTimeButton);
|
||||
await page.pickTime(selectors.workerTimeControl.timeDialog, scanTime);
|
||||
await page.pickTime(selectors.workerTimeControl.dialogTimeInput, scanTime);
|
||||
await page.autocompleteSearch(selectors.workerTimeControl.dialogTimeDirection, 'in');
|
||||
await page.respondToDialog('accept');
|
||||
const result = await page.waitToGetProperty(selectors.workerTimeControl.firstEntryOfFriday, 'innerText');
|
||||
|
||||
|
@ -259,7 +277,8 @@ describe('Worker time control path', () => {
|
|||
it(`should smilingly scan out Hank Pym for break`, async() => {
|
||||
const scanTime = '10:00';
|
||||
await page.waitToClick(selectors.workerTimeControl.fridayAddTimeButton);
|
||||
await page.pickTime(selectors.workerTimeControl.timeDialog, scanTime);
|
||||
await page.pickTime(selectors.workerTimeControl.dialogTimeInput, scanTime);
|
||||
await page.autocompleteSearch(selectors.workerTimeControl.dialogTimeDirection, 'intermediate');
|
||||
await page.respondToDialog('accept');
|
||||
const result = await page.waitToGetProperty(selectors.workerTimeControl.secondEntryOfFriday, 'innerText');
|
||||
|
||||
|
@ -269,7 +288,8 @@ describe('Worker time control path', () => {
|
|||
it(`should smilingly scan in Hank Pym from the break`, async() => {
|
||||
const scanTime = '10:20';
|
||||
await page.waitToClick(selectors.workerTimeControl.fridayAddTimeButton);
|
||||
await page.pickTime(selectors.workerTimeControl.timeDialog, scanTime);
|
||||
await page.pickTime(selectors.workerTimeControl.dialogTimeInput, scanTime);
|
||||
await page.autocompleteSearch(selectors.workerTimeControl.dialogTimeDirection, 'intermediate');
|
||||
await page.respondToDialog('accept');
|
||||
const result = await page.waitToGetProperty(selectors.workerTimeControl.thirdEntryOfFriday, 'innerText');
|
||||
|
||||
|
@ -279,7 +299,8 @@ describe('Worker time control path', () => {
|
|||
it(`should smilingly scan out Hank Pym for the day`, async() => {
|
||||
const scanTime = '15:30';
|
||||
await page.waitToClick(selectors.workerTimeControl.fridayAddTimeButton);
|
||||
await page.pickTime(selectors.workerTimeControl.timeDialog, scanTime);
|
||||
await page.pickTime(selectors.workerTimeControl.dialogTimeInput, scanTime);
|
||||
await page.autocompleteSearch(selectors.workerTimeControl.dialogTimeDirection, 'out');
|
||||
await page.respondToDialog('accept');
|
||||
const result = await page.waitToGetProperty(selectors.workerTimeControl.fourthEntryOfFriday, 'innerText');
|
||||
|
||||
|
@ -310,8 +331,10 @@ describe('Worker time control path', () => {
|
|||
|
||||
it('should lovingly scan in Hank Pym', async() => {
|
||||
const scanTime = '06:00';
|
||||
await page.waitForTimeout(1000); // without this timeout the dialog doesn't pop up
|
||||
await page.waitToClick(selectors.workerTimeControl.saturdayAddTimeButton);
|
||||
await page.pickTime(selectors.workerTimeControl.timeDialog, scanTime);
|
||||
await page.pickTime(selectors.workerTimeControl.dialogTimeInput, scanTime);
|
||||
await page.autocompleteSearch(selectors.workerTimeControl.dialogTimeDirection, 'in');
|
||||
await page.respondToDialog('accept');
|
||||
const result = await page.waitToGetProperty(selectors.workerTimeControl.firstEntryOfSaturday, 'innerText');
|
||||
|
||||
|
@ -321,7 +344,8 @@ describe('Worker time control path', () => {
|
|||
it(`should lovingly scan out Hank Pym for the day with no break to leave a bit early`, async() => {
|
||||
const scanTime = '13:40';
|
||||
await page.waitToClick(selectors.workerTimeControl.saturdayAddTimeButton);
|
||||
await page.pickTime(selectors.workerTimeControl.timeDialog, scanTime);
|
||||
await page.pickTime(selectors.workerTimeControl.dialogTimeInput, scanTime);
|
||||
await page.autocompleteSearch(selectors.workerTimeControl.dialogTimeDirection, 'out');
|
||||
await page.respondToDialog('accept');
|
||||
const result = await page.waitToGetProperty(selectors.workerTimeControl.secondEntryOfSaturday, 'innerText');
|
||||
|
||||
|
@ -337,7 +361,8 @@ describe('Worker time control path', () => {
|
|||
it('should gladly scan in Hank Pym', async() => {
|
||||
const scanTime = '05:00';
|
||||
await page.waitToClick(selectors.workerTimeControl.sundayAddTimeButton);
|
||||
await page.pickTime(selectors.workerTimeControl.timeDialog, scanTime);
|
||||
await page.pickTime(selectors.workerTimeControl.dialogTimeInput, scanTime);
|
||||
await page.autocompleteSearch(selectors.workerTimeControl.dialogTimeDirection, 'in');
|
||||
await page.respondToDialog('accept');
|
||||
const result = await page.waitToGetProperty(selectors.workerTimeControl.firstEntryOfSunday, 'innerText');
|
||||
|
||||
|
@ -347,7 +372,8 @@ describe('Worker time control path', () => {
|
|||
it(`should gladly scan out Hank Pym for the day with no break to leave a bit early`, async() => {
|
||||
const scanTime = '12:40';
|
||||
await page.waitToClick(selectors.workerTimeControl.sundayAddTimeButton);
|
||||
await page.pickTime(selectors.workerTimeControl.timeDialog, scanTime);
|
||||
await page.pickTime(selectors.workerTimeControl.dialogTimeInput, scanTime);
|
||||
await page.autocompleteSearch(selectors.workerTimeControl.dialogTimeDirection, 'out');
|
||||
await page.respondToDialog('accept');
|
||||
const result = await page.waitToGetProperty(selectors.workerTimeControl.secondEntryOfSunday, 'innerText');
|
||||
|
||||
|
|
|
@ -26,7 +26,8 @@ describe('Travel create path', () => {
|
|||
it('should fill the reference, agency and ship date then save the form', async() => {
|
||||
await page.write(selectors.travelIndex.reference, 'Testing reference');
|
||||
await page.autocompleteSearch(selectors.travelIndex.agency, 'inhouse pickup');
|
||||
await page.pickDate(selectors.travelIndex.shipDate, date);
|
||||
await page.pickDate(selectors.travelIndex.shipDate, date); // this line autocompletes another 3 fields
|
||||
await page.waitForTimeout(1000);
|
||||
await page.waitToClick(selectors.travelIndex.save);
|
||||
|
||||
const message = await page.waitForSnackbar();
|
||||
|
@ -35,8 +36,6 @@ describe('Travel create path', () => {
|
|||
});
|
||||
|
||||
it('should check the user was redirected to the travel basic data upon creation', async() => {
|
||||
// backup code for further intermitences still on track.
|
||||
// await page.screenshot({path: 'e2e/paths/10-travel/error.jpeg', type: 'jpeg'});
|
||||
await page.waitForState('travel.card.basicData');
|
||||
});
|
||||
|
||||
|
|
|
@ -136,6 +136,7 @@ describe('Travel descriptor path', () => {
|
|||
it('should navigate to the summary and then clone the travel and its entries using the descriptor menu to get redirected to the cloned travel basic data', async() => {
|
||||
await page.waitToClick('vn-icon[icon="preview"]'); // summary icon
|
||||
await page.waitForState('travel.card.summary');
|
||||
await page.waitForTimeout(1000);
|
||||
await page.waitToClick(selectors.travelDescriptor.dotMenu);
|
||||
await page.waitToClick(selectors.travelDescriptor.dotMenuCloneWithEntries);
|
||||
await page.waitToClick(selectors.travelDescriptor.acceptClonation);
|
||||
|
|
|
@ -65,6 +65,7 @@ describe('Account create and basic data path', () => {
|
|||
describe('Descriptor option', () => {
|
||||
describe('Edit role', () => {
|
||||
it('should edit the role using the descriptor menu', async() => {
|
||||
await page.waitForTimeout(1000); // sometimes descriptor fails to load it's functionalities without this timeout
|
||||
await page.waitToClick(selectors.accountDescriptor.menuButton);
|
||||
await page.waitToClick(selectors.accountDescriptor.changeRole);
|
||||
await page.autocompleteSearch(selectors.accountDescriptor.newRole, 'adminBoss');
|
||||
|
|
|
@ -11,7 +11,7 @@ import './style.scss';
|
|||
* @property {String} valueField The data field name that should be used as value
|
||||
* @property {Array} data Static data for the autocomplete
|
||||
* @property {Object} intialData An initial data to avoid the server request used to get the selection
|
||||
* @property {Boolean} multiple Wether to allow multiple selection
|
||||
* @property {Boolean} multiple Whether to allow multiple selection
|
||||
* @property {Object} selection Current object selected
|
||||
*
|
||||
* @event change Thrown when value is changed
|
||||
|
|
|
@ -1,6 +1,12 @@
|
|||
<div
|
||||
ng-transclude="prepend"
|
||||
class="prepend"></div>
|
||||
<div ng-transclude></div>
|
||||
<div
|
||||
ng-transclude="append"
|
||||
class="append"></div>
|
||||
<vn-icon
|
||||
ng-click="$ctrl.onRemove()"
|
||||
ng-click="$ctrl.onRemove($event)"
|
||||
ng-if="$ctrl.removable"
|
||||
icon="cancel"
|
||||
tabindex="0">
|
||||
|
|
|
@ -3,16 +3,19 @@ import Component from '../../lib/component';
|
|||
import './style.scss';
|
||||
|
||||
export default class Chip extends Component {
|
||||
onRemove() {
|
||||
if (!this.disabled) this.emit('remove');
|
||||
onRemove($event) {
|
||||
if (!this.disabled) this.emit('remove', {$event});
|
||||
}
|
||||
}
|
||||
Chip.$inject = ['$element', '$scope', '$transclude'];
|
||||
|
||||
ngModule.vnComponent('vnChip', {
|
||||
template: require('./index.html'),
|
||||
transclude: {
|
||||
prepend: '?prepend',
|
||||
append: '?append'
|
||||
},
|
||||
controller: Chip,
|
||||
transclude: true,
|
||||
bindings: {
|
||||
disabled: '<?',
|
||||
removable: '<?'
|
||||
|
|
|
@ -18,9 +18,14 @@ describe('Component vnChip', () => {
|
|||
it(`should emit remove event`, () => {
|
||||
controller.emit = () => {};
|
||||
jest.spyOn(controller, 'emit');
|
||||
controller.onRemove();
|
||||
|
||||
expect(controller.emit).toHaveBeenCalledWith('remove');
|
||||
const $event = new Event('click');
|
||||
const target = document.createElement('div');
|
||||
target.dispatchEvent($event);
|
||||
|
||||
controller.onRemove($event);
|
||||
|
||||
expect(controller.emit).toHaveBeenCalledWith('remove', {$event});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
@import "variables";
|
||||
@import "effects";
|
||||
|
||||
vn-chip {
|
||||
border-radius: 16px;
|
||||
|
@ -24,25 +25,47 @@ vn-chip {
|
|||
&.transparent {
|
||||
background-color: transparent;
|
||||
}
|
||||
&.colored {
|
||||
&.colored,
|
||||
&.colored.clickable:hover,
|
||||
&.colored.clickable:focus {
|
||||
background-color: $color-main;
|
||||
color: $color-font-bg;
|
||||
}
|
||||
&.notice {
|
||||
background-color: $color-notice-medium
|
||||
|
||||
&.notice,
|
||||
&.notice.clickable:hover,
|
||||
&.notice.clickable:focus {
|
||||
background-color: $color-notice-medium;
|
||||
}
|
||||
&.success {
|
||||
&.success,
|
||||
&.success.clickable:hover,
|
||||
&.success.clickable:focus {
|
||||
background-color: $color-success-medium;
|
||||
}
|
||||
&.warning {
|
||||
&.warning,
|
||||
&.warning.clickable:hover,
|
||||
&.warning.clickable:focus {
|
||||
background-color: $color-main-medium;
|
||||
}
|
||||
&.alert {
|
||||
&.alert,
|
||||
&.alert.clickable:hover,
|
||||
&.alert.clickable:focus {
|
||||
background-color: $color-alert-medium;
|
||||
}
|
||||
&.message {
|
||||
&.message,
|
||||
&.message.clickable:hover,
|
||||
&.message.clickable:focus {
|
||||
color: $color-font-dark;
|
||||
background-color: $color-bg-dark
|
||||
background-color: $color-bg-dark;
|
||||
}
|
||||
&.clickable {
|
||||
@extend %clickable;
|
||||
opacity: 0.8;
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
& > div {
|
||||
|
@ -75,6 +98,20 @@ vn-chip {
|
|||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
& > .prepend {
|
||||
padding: 0 5px;
|
||||
padding-right: 0;
|
||||
|
||||
&:empty {display:none;}
|
||||
}
|
||||
& > .append {
|
||||
padding: 0 5px;
|
||||
padding-left: 0;
|
||||
|
||||
&:empty {display:none;}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
vn-avatar {
|
||||
|
|
|
@ -43,14 +43,14 @@ export default class Contextmenu {
|
|||
get row() {
|
||||
if (!this.target) return null;
|
||||
|
||||
return this.target.closest('vn-tr, .vn-tr');
|
||||
return this.target.closest('[ng-repeat]');
|
||||
}
|
||||
|
||||
get rowIndex() {
|
||||
if (!this.row) return null;
|
||||
|
||||
const table = this.row.closest('vn-table, .vn-table');
|
||||
const tBody = table.querySelector('vn-tbody, .vn-tbody');
|
||||
const rows = tBody.querySelectorAll('vn-tr, .vn-tr');
|
||||
const rows = table.querySelectorAll('[ng-repeat]');
|
||||
|
||||
return Array.from(rows).findIndex(
|
||||
rowItem => rowItem == this.row
|
||||
|
|
|
@ -17,7 +17,7 @@ export default class Popup extends Component {
|
|||
}
|
||||
|
||||
/**
|
||||
* @type {Boolean} Wether to show or hide the popup.
|
||||
* @type {Boolean} Whether to show or hide the popup.
|
||||
*/
|
||||
get shown() {
|
||||
return this._shown;
|
||||
|
|
|
@ -102,7 +102,7 @@ vn-table {
|
|||
& > vn-one {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
font-size: 0.75rem;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
& > vn-one:nth-child(2) h3 {
|
||||
|
@ -229,4 +229,8 @@ vn-table.scrollable.sm,
|
|||
vn-table.scrollable.lg,
|
||||
.vn-table.scrollable.lg {
|
||||
max-height: 700px
|
||||
}
|
||||
|
||||
.tableWrapper {
|
||||
overflow-x: auto;
|
||||
}
|
|
@ -9,18 +9,33 @@
|
|||
<vn-icon icon="push_pin"></vn-icon>
|
||||
</div>
|
||||
<div class="modules">
|
||||
<a
|
||||
ng-repeat="mod in ::$ctrl.modules"
|
||||
<a
|
||||
ng-repeat="mod in $ctrl.modules | orderBy: '+position'"
|
||||
ng-animate-ref="{{mod.position}}"
|
||||
ng-if='mod.starred'
|
||||
ui-sref="{{::mod.route.state}}"
|
||||
translate-attr="{title: mod.name}"
|
||||
class="vn-shadow">
|
||||
<div
|
||||
vn-tooltip="Remove from favorites"
|
||||
class="pin"
|
||||
ng-click="$ctrl.toggleStarredModule(mod, $event)">
|
||||
<vn-icon icon="remove_circle"></vn-icon>
|
||||
</div>
|
||||
<span>
|
||||
<vn-icon
|
||||
vn-tooltip="Move left"
|
||||
class="small-icon"
|
||||
ng-click="$ctrl.moveModule(mod, $event, 'left')"
|
||||
icon="arrow_left">
|
||||
</vn-icon>
|
||||
<vn-icon
|
||||
vn-tooltip="Remove from favorites"
|
||||
class="small-icon"
|
||||
ng-click="$ctrl.toggleStarredModule(mod, $event)"
|
||||
icon="remove_circle">
|
||||
</vn-icon>
|
||||
<vn-icon
|
||||
vn-tooltip="Move right"
|
||||
class="small-icon"
|
||||
ng-click="$ctrl.moveModule(mod, $event, 'right')"
|
||||
icon="arrow_right">
|
||||
</vn-icon>
|
||||
</span>
|
||||
<div>
|
||||
<vn-icon icon="{{::mod.icon || 'photo'}}"></vn-icon>
|
||||
</div>
|
||||
|
@ -41,17 +56,19 @@
|
|||
</div>
|
||||
<div class="modules">
|
||||
<a
|
||||
ng-repeat="mod in ::$ctrl.modules"
|
||||
ng-repeat="mod in $ctrl.modules"
|
||||
ng-if='!mod.starred'
|
||||
ui-sref="{{::mod.route.state}}"
|
||||
translate-attr="{title: mod.name}"
|
||||
class="vn-shadow">
|
||||
<div
|
||||
vn-tooltip="Add to favorites"
|
||||
class="pin"
|
||||
ng-click="$ctrl.toggleStarredModule(mod, $event)">
|
||||
<vn-icon icon="push_pin"></vn-icon>
|
||||
</div>
|
||||
<span>
|
||||
<div
|
||||
vn-tooltip="Add to favorites"
|
||||
class="small-icon"
|
||||
ng-click="$ctrl.toggleStarredModule(mod, $event)">
|
||||
<vn-icon icon="push_pin"></vn-icon>
|
||||
</div>
|
||||
</span>
|
||||
<div>
|
||||
<vn-icon icon="{{::mod.icon || 'photo'}}"></vn-icon>
|
||||
</div>
|
||||
|
|
|
@ -35,6 +35,7 @@ export default class Controller extends Component {
|
|||
for (let starredModule of res.data) {
|
||||
const module = this.modules.find(mod => mod.name === starredModule.moduleFk);
|
||||
module.starred = true;
|
||||
module.position = starredModule.position;
|
||||
}
|
||||
this.countModules();
|
||||
});
|
||||
|
@ -48,9 +49,10 @@ export default class Controller extends Component {
|
|||
const params = {moduleName: module.name};
|
||||
const query = `starredModules/toggleStarredModule`;
|
||||
this.$http.post(query, params).then(res => {
|
||||
if (res.data)
|
||||
if (res.data) {
|
||||
module.starred = true;
|
||||
else
|
||||
module.position = res.data.position;
|
||||
} else
|
||||
module.starred = false;
|
||||
|
||||
this.vnApp.showSuccess(this.$t('Data saved!'));
|
||||
|
@ -74,6 +76,26 @@ export default class Controller extends Component {
|
|||
|
||||
return this.$sce.trustAsHtml(getName(mod));
|
||||
}
|
||||
|
||||
moveModule(module, event, direction) {
|
||||
if (event.defaultPrevented) return;
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
const params = {moduleName: module.name, direction: direction};
|
||||
const query = `starredModules/setPosition`;
|
||||
this.$http.post(query, params).then(res => {
|
||||
if (res.data) {
|
||||
module.position = res.data.movingModule.position;
|
||||
this.modules.forEach(mod => {
|
||||
if (mod.name == res.data.pushedModule.moduleFk)
|
||||
mod.position = res.data.pushedModule.position;
|
||||
});
|
||||
this.vnApp.showSuccess(this.$t('Data saved!'));
|
||||
this.countModules();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
Controller.$inject = ['$element', '$scope', 'vnModules', '$sce'];
|
||||
|
||||
|
|
|
@ -59,7 +59,7 @@ describe('Salix Component vnHome', () => {
|
|||
expect(controller._modules[0].starred).toBe(true);
|
||||
});
|
||||
|
||||
it(`should set the received module as regular if it was starred`, () => {
|
||||
it('should set the received module as regular if it was starred', () => {
|
||||
const event = new Event('target');
|
||||
controller._modules = [{module: 'client', name: 'Clients', starred: true}];
|
||||
|
||||
|
@ -72,4 +72,34 @@ describe('Salix Component vnHome', () => {
|
|||
expect(controller._modules[0].starred).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('moveModule()', () => {
|
||||
it('should perform a query to setPosition and the apply the position to the moved and pushed modules', () => {
|
||||
const starredModules = [
|
||||
{id: 1, moduleFk: 'Clients', workerFk: 9},
|
||||
{id: 2, moduleFk: 'Orders', workerFk: 9}
|
||||
];
|
||||
|
||||
const movedModules = {
|
||||
movingModule: {position: 2, moduleFk: 'Clients'},
|
||||
pushedModule: {position: 1, moduleFk: 'Orders'}
|
||||
};
|
||||
const event = new Event('target');
|
||||
controller._modules = [
|
||||
{module: 'client', name: 'Clients', position: 1},
|
||||
{module: 'orders', name: 'Orders', position: 2}
|
||||
];
|
||||
|
||||
$httpBackend.whenRoute('GET', 'starredModules/getStarredModules').respond(starredModules);
|
||||
$httpBackend.expectPOST('starredModules/setPosition').respond(movedModules);
|
||||
|
||||
expect(controller._modules[0].position).toEqual(1);
|
||||
expect(controller._modules[1].position).toEqual(2);
|
||||
controller.moveModule(controller._modules[0], event, 'right');
|
||||
$httpBackend.flush();
|
||||
|
||||
expect(controller._modules[0].position).toEqual(2);
|
||||
expect(controller._modules[1].position).toEqual(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
Favorites: Favoritos
|
||||
You can set modules as favorites by clicking their icon: Puedes establecer módulos como favoritos haciendo clic en el icono
|
||||
Add to favorites: Añadir a favoritos.
|
||||
Remove from favorites: Quitar de favoritos.
|
||||
Add to favorites: Añadir a favoritos
|
||||
Remove from favorites: Quitar de favoritos
|
||||
Move left: Mover a la izquierda
|
||||
Move right: Mover a la derecha
|
|
@ -52,6 +52,11 @@ vn-home {
|
|||
max-width: 704px;
|
||||
margin: 0 auto;
|
||||
|
||||
& > a:first-child span vn-icon[icon="arrow_left"],
|
||||
& > a:last-child span vn-icon[icon="arrow_right"] {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
& > a {
|
||||
@extend %clickable-light;
|
||||
display: flex;
|
||||
|
@ -66,19 +71,18 @@ vn-home {
|
|||
background-color: $color-button;
|
||||
color: $color-font-dark;
|
||||
|
||||
& .pin {
|
||||
& .small-icon {
|
||||
display: inline-flex;
|
||||
opacity: 0;
|
||||
flex-direction: row;
|
||||
justify-content: left;
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
vn-icon {
|
||||
margin: auto;
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
}
|
||||
&:hover .pin {
|
||||
&:hover .small-icon {
|
||||
flex-direction: row;
|
||||
opacity: 1;
|
||||
|
||||
}
|
||||
|
||||
& > div {
|
||||
|
|
|
@ -97,5 +97,6 @@
|
|||
"Role name must be written in camelCase": "Role name must be written in camelCase",
|
||||
"Client assignment has changed": "I did change the salesperson ~*\"<{{previousWorkerName}}>\"*~ by *\"<{{currentWorkerName}}>\"* from the client [{{clientName}} ({{clientId}})]({{{url}}})",
|
||||
"None": "None",
|
||||
"error densidad = 0": "error densidad = 0"
|
||||
"error densidad = 0": "error densidad = 0",
|
||||
"nickname": "nickname"
|
||||
}
|
|
@ -180,5 +180,6 @@
|
|||
"This genus already exist": "Este genus ya existe",
|
||||
"This specie already exist": "Esta especie ya existe",
|
||||
"Client assignment has changed": "He cambiado el comercial ~*\"<{{previousWorkerName}}>\"*~ por *\"<{{currentWorkerName}}>\"* del cliente [{{clientName}} ({{clientId}})]({{{url}}})",
|
||||
"None": "Ninguno"
|
||||
"None": "Ninguno",
|
||||
"The contract was not active during the selected date": "El contrato no estaba activo durante la fecha seleccionada"
|
||||
}
|
|
@ -93,7 +93,7 @@ module.exports = function(Self) {
|
|||
clientOriginal.accountingAccount
|
||||
],
|
||||
options);
|
||||
} else {
|
||||
} else if (accountingType.isAutoConciliated == true) {
|
||||
const description = `${clientOriginal.id} : ${clientOriginal.socialName} - ${accountingType.receiptDescription}`;
|
||||
const [xdiarioNew] = await Self.rawSql(
|
||||
`SELECT xdiario_new(?, CURDATE(), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ledger;`,
|
||||
|
|
|
@ -16,9 +16,6 @@
|
|||
"type": "number",
|
||||
"required": true
|
||||
},
|
||||
"amountUnpaid": {
|
||||
"type": "number"
|
||||
},
|
||||
"payed": {
|
||||
"type": "date",
|
||||
"required": true
|
||||
|
|
|
@ -69,6 +69,19 @@
|
|||
label="Channel">
|
||||
</vn-autocomplete>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-autocomplete
|
||||
ng-model="$ctrl.client.transferorFk"
|
||||
url="Clients/isActive"
|
||||
search-function="$ctrl.transferorSearchFunction($search)"
|
||||
where="{id: {neq: $ctrl.client.id}}"
|
||||
show-field="name"
|
||||
value-field="id"
|
||||
label="Previous client"
|
||||
info="In case of a company succession, specify the grantor company"
|
||||
rule>
|
||||
</vn-autocomplete>
|
||||
</vn-horizontal>
|
||||
</vn-card>
|
||||
<vn-button-bar>
|
||||
<vn-submit
|
||||
|
|
|
@ -1,9 +1,17 @@
|
|||
import ngModule from '../module';
|
||||
import Section from 'salix/components/section';
|
||||
|
||||
export default class Controller extends Section {
|
||||
transferorSearchFunction($search) {
|
||||
return /^\d+$/.test($search)
|
||||
? {id: $search}
|
||||
: {name: {like: '%' + $search + '%'}};
|
||||
}
|
||||
}
|
||||
|
||||
ngModule.vnComponent('vnClientBasicData', {
|
||||
template: require('./index.html'),
|
||||
controller: Section,
|
||||
controller: Controller,
|
||||
bindings: {
|
||||
client: '<'
|
||||
}
|
||||
|
|
|
@ -51,6 +51,8 @@
|
|||
</vn-data-viewer>
|
||||
<vn-float-button
|
||||
ng-if="$ctrl.canCreateNew()"
|
||||
vn-acl="insurance"
|
||||
vn-acl-action="remove"
|
||||
vn-tooltip="New contract"
|
||||
fixed-bottom-right
|
||||
ui-sref="client.card.creditInsurance.create"
|
||||
|
|
|
@ -30,6 +30,8 @@
|
|||
</div>
|
||||
<a
|
||||
ng-if="!$ctrl.isClosed"
|
||||
vn-acl="insurance"
|
||||
vn-acl-action="remove"
|
||||
ui-sref="client.card.creditInsurance.insurance.create({classificationId: {{$ctrl.$params.classificationId}}})"
|
||||
fixed-bottom-right
|
||||
vn-tooltip="New credit"
|
||||
|
|
|
@ -73,17 +73,6 @@
|
|||
rule>
|
||||
<tpl-item>{{id}}: {{transaction}}</tpl-item>
|
||||
</vn-autocomplete>
|
||||
<vn-autocomplete vn-one
|
||||
ng-model="$ctrl.client.transferorFk"
|
||||
url="Clients/isActive"
|
||||
search-function="$ctrl.transferorSearchFunction($search)"
|
||||
where="{id: {neq: $ctrl.client.id}}"
|
||||
show-field="name"
|
||||
value-field="id"
|
||||
label="Previous client"
|
||||
info="In case of a company succession, specify the grantor company"
|
||||
rule>
|
||||
</vn-autocomplete>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-datalist vn-one
|
||||
|
|
|
@ -173,12 +173,6 @@ export default class Controller extends Section {
|
|||
this.client.provinceFk = response.provinceFk;
|
||||
this.client.countryFk = response.countryFk;
|
||||
}
|
||||
|
||||
transferorSearchFunction($search) {
|
||||
return /^\d+$/.test($search)
|
||||
? {id: $search}
|
||||
: {name: {like: '%' + $search + '%'}};
|
||||
}
|
||||
}
|
||||
|
||||
ngModule.vnComponent('vnClientFiscalData', {
|
||||
|
|
|
@ -240,14 +240,12 @@
|
|||
"url": "/credit-insurance",
|
||||
"abstract": true,
|
||||
"state": "client.card.creditInsurance",
|
||||
"component": "ui-view",
|
||||
"acl": ["insurance"]
|
||||
"component": "ui-view"
|
||||
}, {
|
||||
"url": "/index",
|
||||
"state": "client.card.creditInsurance.index",
|
||||
"component": "vn-client-credit-insurance-index",
|
||||
"description": "Credit contracts",
|
||||
"acl": ["insurance"],
|
||||
"params": {
|
||||
"client": "$ctrl.client"
|
||||
}
|
||||
|
@ -256,6 +254,7 @@
|
|||
"state": "client.card.creditInsurance.create",
|
||||
"component": "vn-client-credit-insurance-create",
|
||||
"description": "New insurance",
|
||||
"acl": ["insurance"],
|
||||
"params": {
|
||||
"client": "$ctrl.client"
|
||||
}
|
||||
|
@ -279,6 +278,7 @@
|
|||
"state": "client.card.creditInsurance.insurance.create",
|
||||
"component": "vn-client-credit-insurance-insurance-create",
|
||||
"description": "New credit",
|
||||
"acl": ["insurance"],
|
||||
"params": {
|
||||
"client": "$ctrl.client"
|
||||
}
|
||||
|
|
|
@ -1,3 +1,13 @@
|
|||
<vn-crud-model
|
||||
vn-id="ticketsModel"
|
||||
auto-load="true"
|
||||
url="Tickets"
|
||||
link="{clientFk: $ctrl.$params.id}"
|
||||
filter="::$ctrl.ticketFilter"
|
||||
limit="5"
|
||||
data="tickets"
|
||||
order="shipped DESC">
|
||||
</vn-crud-model>
|
||||
<vn-card class="summary">
|
||||
<h5>
|
||||
<a ng-if="::$ctrl.summary.id"
|
||||
|
@ -269,14 +279,107 @@
|
|||
ng-class="{alert: $ctrl.summary.defaulters[0].amount}"
|
||||
info="Deviated invoices minus payments">
|
||||
</vn-label-value>
|
||||
<vn-vertical ng-if="$ctrl.summary.recovery.started">
|
||||
<vn-label-value label="Recovery since"
|
||||
value="{{$ctrl.summary.recovery.started | date:'dd/MM/yyyy'}}">
|
||||
<vn-label-value label="Recovery since"
|
||||
ng-if="$ctrl.summary.recovery.started"
|
||||
value="{{$ctrl.summary.recovery.started | date:'dd/MM/yyyy'}}">
|
||||
</vn-label-value>
|
||||
</vn-vertical>
|
||||
</vn-one>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-one>
|
||||
<h4 translate>Latest tickets</h4>
|
||||
<vn-table model="ticketsModel" class="scrollable sm">
|
||||
<vn-thead>
|
||||
<vn-tr>
|
||||
<vn-th field="id" number>Id</vn-th>
|
||||
<vn-th field="nickname" expand>Client</vn-th>
|
||||
<vn-th field="packages" shrink>Packages</vn-th>
|
||||
<vn-th field="shipped" shrink-date>Date</vn-th>
|
||||
<vn-th>State</vn-th>
|
||||
<vn-th shrink>Total</vn-th>
|
||||
<vn-th></vn-th>
|
||||
</vn-tr>
|
||||
</vn-thead>
|
||||
<vn-tbody>
|
||||
<a ng-repeat="ticket in ticketsModel.data"
|
||||
class="clickable vn-tr search-result"
|
||||
ui-sref="ticket.card.summary({id: {{::ticket.id}}})">
|
||||
<vn-td number>{{::ticket.id}}</vn-td>
|
||||
<vn-td expand>
|
||||
<span
|
||||
title="{{::ticket.nickname}}"
|
||||
vn-click-stop="clientDescriptor.show($event, ticket.clientFk)"
|
||||
class="link">
|
||||
{{::ticket.nickname}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td shrink>
|
||||
{{::ticket.packages}}
|
||||
</vn-td>
|
||||
<vn-td shrink-date>
|
||||
<span class="chip {{::$ctrl.chipColor(ticket.shipped)}}">
|
||||
{{::ticket.shipped | date: 'dd/MM/yyyy'}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td>
|
||||
<span
|
||||
ng-show="::ticket.refFk"
|
||||
title="{{::ticket.refFk}}"
|
||||
vn-click-stop="invoiceOutDescriptor.show($event, ticket.invoiceOutId)"
|
||||
class="link">
|
||||
{{::ticket.refFk}}
|
||||
</span>
|
||||
<span
|
||||
ng-show="::!ticket.refFk"
|
||||
class="chip {{::$ctrl.stateColor(ticket)}}">
|
||||
{{::ticket.ticketState.state.name}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td shrink>
|
||||
<span class="chip {{$ctrl.totalPriceColor(ticket)}}">
|
||||
{{::(ticket.totalWithVat ? ticket.totalWithVat : 0) | currency: 'EUR': 2}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td actions>
|
||||
<vn-icon-button
|
||||
vn-anchor="::{
|
||||
state: 'ticket.card.sale',
|
||||
params: {id: ticket.id},
|
||||
target: '_blank'
|
||||
}"
|
||||
vn-tooltip="Go to lines"
|
||||
icon="icon-lines">
|
||||
</vn-icon-button>
|
||||
<vn-icon-button
|
||||
vn-click-stop="$ctrl.preview(ticket)"
|
||||
vn-tooltip="Preview"
|
||||
icon="preview">
|
||||
</vn-icon-button>
|
||||
</vn-td>
|
||||
</a>
|
||||
</vn-tbody>
|
||||
</vn-table>
|
||||
<vn-pagination
|
||||
model="ticketsModel"
|
||||
class="vn-pt-xs"
|
||||
scroll-selector="vn-table[model='ticketsModel']"
|
||||
scroll-offset="100">
|
||||
</vn-pagination>
|
||||
</vn-one>
|
||||
</vn-horizontal>
|
||||
</vn-card>
|
||||
<vn-client-descriptor-popover
|
||||
vn-id="clientDescriptor">
|
||||
</vn-client-descriptor-popover>
|
||||
<vn-worker-descriptor-popover
|
||||
vn-id="workerDescriptor">
|
||||
</vn-worker-descriptor-popover>
|
||||
</vn-worker-descriptor-popover>
|
||||
<vn-invoice-out-descriptor-popover
|
||||
vn-id="invoiceOutDescriptor">
|
||||
</vn-invoice-out-descriptor-popover>
|
||||
<vn-popup vn-id="summary">
|
||||
<vn-ticket-summary
|
||||
ticket="$ctrl.selectedTicket"
|
||||
model="model">
|
||||
</vn-ticket-summary>
|
||||
</vn-popup>
|
|
@ -3,6 +3,21 @@ import Summary from 'salix/components/summary';
|
|||
import './style.scss';
|
||||
|
||||
class Controller extends Summary {
|
||||
constructor($element, $) {
|
||||
super($element, $);
|
||||
|
||||
this.ticketFilter = {
|
||||
include: {
|
||||
relation: 'ticketState',
|
||||
scope: {
|
||||
fields: ['stateFk', 'code', 'alertLevel'],
|
||||
include: {
|
||||
relation: 'state'
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
$onChanges() {
|
||||
if (!this.client)
|
||||
return;
|
||||
|
@ -18,6 +33,7 @@ class Controller extends Summary {
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
get isEmployee() {
|
||||
return this.aclService.hasAny(['employee']);
|
||||
}
|
||||
|
@ -39,6 +55,45 @@ class Controller extends Summary {
|
|||
if (rate)
|
||||
return rate * 100;
|
||||
}
|
||||
|
||||
stateColor(ticket) {
|
||||
const ticketState = ticket.ticketState;
|
||||
|
||||
if (ticketState.code === 'OK')
|
||||
return 'success';
|
||||
else if (ticketState.code === 'FREE')
|
||||
return 'notice';
|
||||
else if (ticketState.alertLevel === 1)
|
||||
return 'warning';
|
||||
else if (ticketState.alertLevel === 0)
|
||||
return 'alert';
|
||||
}
|
||||
|
||||
chipColor(date) {
|
||||
const today = new Date();
|
||||
today.setHours(0, 0, 0, 0);
|
||||
|
||||
const ticketShipped = new Date(date);
|
||||
ticketShipped.setHours(0, 0, 0, 0);
|
||||
|
||||
const difference = today - ticketShipped;
|
||||
|
||||
if (difference == 0)
|
||||
return 'warning';
|
||||
if (difference < 0)
|
||||
return 'success';
|
||||
}
|
||||
|
||||
totalPriceColor(ticket) {
|
||||
const total = parseInt(ticket.totalWithVat);
|
||||
if (total > 0 && total < 50)
|
||||
return 'warning';
|
||||
}
|
||||
|
||||
preview(ticket) {
|
||||
this.selectedTicket = ticket;
|
||||
this.$.summary.show();
|
||||
}
|
||||
}
|
||||
|
||||
ngModule.vnComponent('vnClientSummary', {
|
||||
|
|
|
@ -4,15 +4,15 @@ describe('Client', () => {
|
|||
describe('Component vnClientSummary', () => {
|
||||
let controller;
|
||||
let $httpBackend;
|
||||
let $scope;
|
||||
let $window;
|
||||
|
||||
beforeEach(ngModule('client'));
|
||||
|
||||
beforeEach(inject(($componentController, _$httpBackend_, $rootScope) => {
|
||||
beforeEach(inject(($componentController, _$httpBackend_, _$window_) => {
|
||||
$window = _$window_;
|
||||
$httpBackend = _$httpBackend_;
|
||||
$scope = $rootScope.$new();
|
||||
const $element = angular.element('<vn-client-summary></vn-client-summary>');
|
||||
controller = $componentController('vnClientSummary', {$element, $scope});
|
||||
controller = $componentController('vnClientSummary', {$element});
|
||||
controller.client = {id: 101};
|
||||
}));
|
||||
|
||||
|
@ -48,5 +48,82 @@ describe('Client', () => {
|
|||
expect(result).toEqual(300);
|
||||
});
|
||||
});
|
||||
|
||||
describe('chipColor()', () => {
|
||||
it('should return warning when the date is the present', () => {
|
||||
let today = new Date();
|
||||
let result = controller.chipColor(today);
|
||||
|
||||
expect(result).toEqual('warning');
|
||||
});
|
||||
|
||||
it('should return success when the date is in the future', () => {
|
||||
let futureDate = new Date();
|
||||
futureDate = futureDate.setDate(futureDate.getDate() + 10);
|
||||
let result = controller.chipColor(futureDate);
|
||||
|
||||
expect(result).toEqual('success');
|
||||
});
|
||||
|
||||
it('should return undefined when the date is in the past', () => {
|
||||
let pastDate = new Date();
|
||||
pastDate = pastDate.setDate(pastDate.getDate() - 10);
|
||||
let result = controller.chipColor(pastDate);
|
||||
|
||||
expect(result).toEqual(undefined);
|
||||
});
|
||||
});
|
||||
|
||||
describe('stateColor()', () => {
|
||||
it('should return "success" when the alertLevelCode property is "OK"', () => {
|
||||
const result = controller.stateColor({ticketState: {code: 'OK'}});
|
||||
|
||||
expect(result).toEqual('success');
|
||||
});
|
||||
|
||||
it('should return "notice" when the alertLevelCode property is "FREE"', () => {
|
||||
const result = controller.stateColor({ticketState: {code: 'FREE'}});
|
||||
|
||||
expect(result).toEqual('notice');
|
||||
});
|
||||
|
||||
it('should return "warning" when the alertLevel property is "1', () => {
|
||||
const result = controller.stateColor({ticketState: {code: 'PACKING', alertLevel: 1}});
|
||||
|
||||
expect(result).toEqual('warning');
|
||||
});
|
||||
|
||||
it('should return "alert" when the alertLevel property is "0"', () => {
|
||||
const result = controller.stateColor({ticketState: {code: 'FIXING', alertLevel: 0}});
|
||||
|
||||
expect(result).toEqual('alert');
|
||||
});
|
||||
});
|
||||
|
||||
describe('totalPriceColor()', () => {
|
||||
it('should return "warning" when the ticket amount is less than 50€', () => {
|
||||
const result = controller.totalPriceColor({totalWithVat: '8.50'});
|
||||
|
||||
expect(result).toEqual('warning');
|
||||
});
|
||||
});
|
||||
|
||||
describe('preview()', () => {
|
||||
it('should show the dialog summary', () => {
|
||||
controller.$.summary = {show: () => {}};
|
||||
jest.spyOn(controller.$.summary, 'show');
|
||||
|
||||
const ticket = {id: 1, clientFk: 101};
|
||||
|
||||
const event = new MouseEvent('click', {
|
||||
view: $window,
|
||||
bubbles: true,
|
||||
cancelable: true
|
||||
});
|
||||
controller.preview(event, ticket);
|
||||
|
||||
expect(controller.$.summary.show).toHaveBeenCalledWith();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -19,3 +19,4 @@ Solunion's maximum risk: Riesgo máximo asumido por Solunion
|
|||
Invoices minus payments: Facturas menos recibos
|
||||
Deviated invoices minus payments: Facturas fuera de plazo menos recibos
|
||||
Go to the client: Ir al cliente
|
||||
Latest tickets: Últimos tickets
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
@import "variables";
|
||||
|
||||
vn-client-summary {
|
||||
vn-client-summary .summary {
|
||||
max-width: $width-lg;
|
||||
|
||||
.alert span {
|
||||
color: $color-alert !important
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
<vn-tr ng-repeat="transaction in transactions">
|
||||
<vn-td shrink>
|
||||
<vn-icon
|
||||
vn-tooltip="{{$ctrl.getFormattedMessage(transaction)}}"
|
||||
vn-tooltip="{{::$ctrl.getFormattedMessage(transaction)}}"
|
||||
ng-show="::((transaction.errorMessage || transaction.responseMessage) && !transaction.isConfirmed)"
|
||||
icon="clear">
|
||||
</vn-icon>
|
||||
|
|
|
@ -89,7 +89,7 @@ module.exports = Self => {
|
|||
|
||||
const newBuy = await models.Buy.create(ctx.args, myOptions);
|
||||
|
||||
let filter = {
|
||||
const filter = {
|
||||
fields: [
|
||||
'id',
|
||||
'itemFk',
|
||||
|
@ -136,7 +136,7 @@ module.exports = Self => {
|
|||
}
|
||||
};
|
||||
|
||||
let stmts = [];
|
||||
const stmts = [];
|
||||
let stmt;
|
||||
|
||||
stmts.push('DROP TEMPORARY TABLE IF EXISTS tmp.buyRecalc');
|
||||
|
|
|
@ -32,7 +32,7 @@ module.exports = Self => {
|
|||
}
|
||||
|
||||
try {
|
||||
let promises = [];
|
||||
const promises = [];
|
||||
for (let buy of ctx.args.buys) {
|
||||
const buysToDelete = models.Buy.destroyById(buy.id, myOptions);
|
||||
promises.push(buysToDelete);
|
||||
|
|
|
@ -30,28 +30,33 @@ module.exports = Self => {
|
|||
}
|
||||
});
|
||||
|
||||
Self.editLatestBuys = async(field, newValue, lines) => {
|
||||
Self.editLatestBuys = async(field, newValue, lines, options) => {
|
||||
let tx;
|
||||
let myOptions = {};
|
||||
|
||||
if (typeof options == 'object')
|
||||
Object.assign(myOptions, options);
|
||||
|
||||
if (!myOptions.transaction) {
|
||||
tx = await Self.beginTransaction({});
|
||||
myOptions.transaction = tx;
|
||||
}
|
||||
|
||||
let modelName;
|
||||
let identifier;
|
||||
|
||||
switch (field) {
|
||||
case 'size':
|
||||
case 'density':
|
||||
case 'minPrice':
|
||||
case 'description':
|
||||
case 'packingOut':
|
||||
modelName = 'Item';
|
||||
identifier = 'itemFk';
|
||||
break;
|
||||
case 'quantity':
|
||||
case 'buyingValue':
|
||||
case 'freightValue':
|
||||
case 'packing':
|
||||
case 'grouping':
|
||||
case 'groupingMode':
|
||||
case 'comissionValue':
|
||||
case 'packageValue':
|
||||
case 'price2':
|
||||
case 'price3':
|
||||
case 'weight':
|
||||
modelName = 'Buy';
|
||||
identifier = 'id';
|
||||
|
@ -60,28 +65,27 @@ module.exports = Self => {
|
|||
const models = Self.app.models;
|
||||
const model = models[modelName];
|
||||
|
||||
let tx = await model.beginTransaction({});
|
||||
|
||||
try {
|
||||
let promises = [];
|
||||
let options = {transaction: tx};
|
||||
|
||||
let targets = lines.map(line => {
|
||||
const targets = lines.map(line => {
|
||||
return line[identifier];
|
||||
});
|
||||
|
||||
let value = {};
|
||||
const value = {};
|
||||
value[field] = newValue;
|
||||
|
||||
// intentarlo con updateAll
|
||||
for (let target of targets)
|
||||
promises.push(model.upsertWithWhere({id: target}, value, options));
|
||||
promises.push(model.upsertWithWhere({id: target}, value, myOptions));
|
||||
|
||||
await Promise.all(promises);
|
||||
await tx.commit();
|
||||
} catch (error) {
|
||||
await tx.rollback();
|
||||
throw error;
|
||||
const result = await Promise.all(promises, myOptions);
|
||||
|
||||
if (tx) await tx.commit();
|
||||
|
||||
return result;
|
||||
} catch (e) {
|
||||
if (tx) await tx.rollback();
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
|
|
@ -13,71 +13,85 @@ module.exports = Self => {
|
|||
type: 'object',
|
||||
description: 'Filter defining where, order, offset, and limit - must be a JSON-encoded string',
|
||||
http: {source: 'query'}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
arg: 'search',
|
||||
type: 'string',
|
||||
description: 'Searchs the entry by id',
|
||||
http: {source: 'query'}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
arg: 'id',
|
||||
type: 'integer',
|
||||
description: 'The entry id',
|
||||
http: {source: 'query'}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
arg: 'created',
|
||||
type: 'date',
|
||||
description: 'The created date to filter',
|
||||
http: {source: 'query'}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
arg: 'travelFk',
|
||||
type: 'number',
|
||||
description: 'The travel id to filter',
|
||||
http: {source: 'query'}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
arg: 'companyFk',
|
||||
type: 'number',
|
||||
description: 'The company to filter',
|
||||
http: {source: 'query'}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
arg: 'isBooked',
|
||||
type: 'boolean',
|
||||
description: 'The isBokked filter',
|
||||
http: {source: 'query'}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
arg: 'isConfirmed',
|
||||
type: 'boolean',
|
||||
description: 'The isConfirmed filter',
|
||||
http: {source: 'query'}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
arg: 'isOrdered',
|
||||
type: 'boolean',
|
||||
description: 'The isOrdered filter',
|
||||
http: {source: 'query'}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
arg: 'ref',
|
||||
type: 'string',
|
||||
description: 'The ref filter',
|
||||
http: {source: 'query'}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
arg: 'supplierFk',
|
||||
type: 'number',
|
||||
description: 'The supplier id to filter',
|
||||
http: {source: 'query'}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
arg: 'invoiceInFk',
|
||||
type: 'number',
|
||||
description: 'The invoiceIn id to filter',
|
||||
http: {source: 'query'}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
arg: 'currencyFk',
|
||||
type: 'number',
|
||||
description: 'The currency id to filter',
|
||||
http: {source: 'query'}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
arg: 'from',
|
||||
type: 'date',
|
||||
description: `The from date filter`
|
||||
}, {
|
||||
},
|
||||
{
|
||||
arg: 'to',
|
||||
type: 'date',
|
||||
description: `The to date filter`
|
||||
|
@ -93,9 +107,14 @@ module.exports = Self => {
|
|||
}
|
||||
});
|
||||
|
||||
Self.filter = async(ctx, filter) => {
|
||||
let conn = Self.dataSource.connector;
|
||||
let where = buildFilter(ctx.args, (param, value) => {
|
||||
Self.filter = async(ctx, filter, options) => {
|
||||
let myOptions = {};
|
||||
|
||||
if (typeof options == 'object')
|
||||
Object.assign(myOptions, options);
|
||||
|
||||
const conn = Self.dataSource.connector;
|
||||
const where = buildFilter(ctx.args, (param, value) => {
|
||||
switch (param) {
|
||||
case 'search':
|
||||
return /^\d+$/.test(value)
|
||||
|
@ -128,7 +147,7 @@ module.exports = Self => {
|
|||
});
|
||||
filter = mergeFilters(ctx.args.filter, {where});
|
||||
|
||||
let stmts = [];
|
||||
const stmts = [];
|
||||
let stmt;
|
||||
stmt = new ParameterizedSQL(
|
||||
`SELECT
|
||||
|
@ -163,10 +182,10 @@ module.exports = Self => {
|
|||
);
|
||||
|
||||
stmt.merge(conn.makeSuffix(filter));
|
||||
let itemsIndex = stmts.push(stmt) - 1;
|
||||
const itemsIndex = stmts.push(stmt) - 1;
|
||||
|
||||
let sql = ParameterizedSQL.join(stmts, ';');
|
||||
let result = await conn.executeStmt(sql);
|
||||
const sql = ParameterizedSQL.join(stmts, ';');
|
||||
const result = await conn.executeStmt(sql, myOptions);
|
||||
return itemsIndex === 0 ? result : result[itemsIndex];
|
||||
};
|
||||
};
|
||||
|
|
|
@ -1,14 +1,22 @@
|
|||
const mergeFilters = require('vn-loopback/util/filter').mergeFilters;
|
||||
|
||||
module.exports = Self => {
|
||||
Self.remoteMethod('getBuys', {
|
||||
description: 'Returns buys for one entry',
|
||||
accessType: 'READ',
|
||||
accepts: {
|
||||
accepts: [{
|
||||
arg: 'id',
|
||||
type: 'number',
|
||||
required: true,
|
||||
description: 'The entry id',
|
||||
http: {source: 'path'}
|
||||
},
|
||||
{
|
||||
arg: 'filter',
|
||||
type: 'object',
|
||||
description: 'Filter defining where, order, offset, and limit - must be a JSON-encoded string'
|
||||
}
|
||||
],
|
||||
returns: {
|
||||
type: ['Object'],
|
||||
root: true
|
||||
|
@ -19,8 +27,14 @@ module.exports = Self => {
|
|||
}
|
||||
});
|
||||
|
||||
Self.getBuys = async id => {
|
||||
let filter = {
|
||||
Self.getBuys = async(id, filter, options) => {
|
||||
const models = Self.app.models;
|
||||
let myOptions = {};
|
||||
|
||||
if (typeof options == 'object')
|
||||
Object.assign(myOptions, options);
|
||||
|
||||
let defaultFilter = {
|
||||
where: {entryFk: id},
|
||||
fields: [
|
||||
'id',
|
||||
|
@ -68,7 +82,8 @@ module.exports = Self => {
|
|||
}
|
||||
};
|
||||
|
||||
let buys = await Self.app.models.Buy.find(filter);
|
||||
return buys;
|
||||
defaultFilter = mergeFilters(defaultFilter, filter);
|
||||
|
||||
return models.Buy.find(defaultFilter, myOptions);
|
||||
};
|
||||
};
|
||||
|
|
|
@ -19,8 +19,14 @@ module.exports = Self => {
|
|||
}
|
||||
});
|
||||
|
||||
Self.getEntry = async id => {
|
||||
let filter = {
|
||||
Self.getEntry = async(id, options) => {
|
||||
const models = Self.app.models;
|
||||
let myOptions = {};
|
||||
|
||||
if (typeof options == 'object')
|
||||
Object.assign(myOptions, options);
|
||||
|
||||
const filter = {
|
||||
where: {id: id},
|
||||
include: [
|
||||
{
|
||||
|
@ -70,7 +76,6 @@ module.exports = Self => {
|
|||
],
|
||||
};
|
||||
|
||||
let entry = await Self.app.models.Entry.findOne(filter);
|
||||
return entry;
|
||||
return models.Entry.findOne(filter, myOptions);
|
||||
};
|
||||
};
|
||||
|
|
|
@ -45,8 +45,8 @@ module.exports = Self => {
|
|||
const conn = Self.dataSource.connector;
|
||||
const args = ctx.args;
|
||||
const models = Self.app.models;
|
||||
|
||||
let tx;
|
||||
|
||||
if (!options.transaction) {
|
||||
tx = await Self.beginTransaction({});
|
||||
options.transaction = tx;
|
||||
|
@ -76,7 +76,7 @@ module.exports = Self => {
|
|||
const createdBuys = await models.Buy.create(buys, options);
|
||||
const buyIds = createdBuys.map(buy => buy.id);
|
||||
|
||||
let stmts = [];
|
||||
const stmts = [];
|
||||
let stmt;
|
||||
|
||||
stmts.push('DROP TEMPORARY TABLE IF EXISTS tmp.buyRecalc');
|
||||
|
|
|
@ -24,14 +24,19 @@ module.exports = Self => {
|
|||
}
|
||||
});
|
||||
|
||||
Self.importBuysPreview = async(id, buys) => {
|
||||
Self.importBuysPreview = async(id, buys, options) => {
|
||||
const models = Self.app.models;
|
||||
let myOptions = {};
|
||||
|
||||
if (typeof options == 'object')
|
||||
Object.assign(myOptions, options);
|
||||
|
||||
for (let buy of buys) {
|
||||
const packaging = await models.Packaging.findOne({
|
||||
fields: ['id'],
|
||||
where: {volume: {gte: buy.volume}},
|
||||
order: 'volume ASC'
|
||||
});
|
||||
}, myOptions);
|
||||
buy.packageFk = packaging.id;
|
||||
}
|
||||
|
||||
|
|
|
@ -10,46 +10,59 @@ module.exports = Self => {
|
|||
accepts: [
|
||||
{
|
||||
arg: 'filter',
|
||||
type: 'Object',
|
||||
type: 'object',
|
||||
description: 'Filter defining where, order, offset, and limit - must be a JSON-encoded string',
|
||||
},
|
||||
{
|
||||
arg: 'search',
|
||||
type: 'String',
|
||||
type: 'string',
|
||||
description: `If it's and integer searchs by id, otherwise it searchs by name`,
|
||||
}, {
|
||||
},
|
||||
{
|
||||
arg: 'id',
|
||||
type: 'Integer',
|
||||
type: 'integer',
|
||||
description: 'Item id',
|
||||
}, {
|
||||
},
|
||||
{
|
||||
arg: 'tags',
|
||||
type: ['Object'],
|
||||
type: ['object'],
|
||||
description: 'List of tags to filter with',
|
||||
http: {source: 'query'}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
arg: 'description',
|
||||
type: 'String',
|
||||
type: 'string',
|
||||
description: 'The item description',
|
||||
}, {
|
||||
},
|
||||
{
|
||||
arg: 'salesPersonFk',
|
||||
type: 'Integer',
|
||||
type: 'integer',
|
||||
description: 'The buyer of the item',
|
||||
}, {
|
||||
},
|
||||
{
|
||||
arg: 'active',
|
||||
type: 'Boolean',
|
||||
type: 'boolean',
|
||||
description: 'Whether the item is or not active',
|
||||
}, {
|
||||
},
|
||||
{
|
||||
arg: 'visible',
|
||||
type: 'Boolean',
|
||||
type: 'boolean',
|
||||
description: 'Whether the item is or not visible',
|
||||
}, {
|
||||
},
|
||||
{
|
||||
arg: 'typeFk',
|
||||
type: 'Integer',
|
||||
type: 'integer',
|
||||
description: 'Type id',
|
||||
}, {
|
||||
},
|
||||
{
|
||||
arg: 'categoryFk',
|
||||
type: 'Integer',
|
||||
type: 'integer',
|
||||
description: 'Category id',
|
||||
},
|
||||
{
|
||||
arg: 'packingOut',
|
||||
type: 'integer',
|
||||
description: 'the packingOut',
|
||||
}
|
||||
],
|
||||
returns: {
|
||||
|
@ -62,16 +75,24 @@ module.exports = Self => {
|
|||
}
|
||||
});
|
||||
|
||||
Self.latestBuysFilter = async(ctx, filter) => {
|
||||
let conn = Self.dataSource.connector;
|
||||
let where = buildFilter(ctx.args, (param, value) => {
|
||||
Self.latestBuysFilter = async(ctx, filter, options) => {
|
||||
let myOptions = {};
|
||||
|
||||
if (typeof options == 'object')
|
||||
Object.assign(myOptions, options);
|
||||
|
||||
const conn = Self.dataSource.connector;
|
||||
const where = buildFilter(ctx.args, (param, value) => {
|
||||
switch (param) {
|
||||
case 'search':
|
||||
return /^\d+$/.test(value)
|
||||
? {'i.id': value}
|
||||
: {'i.name': {like: `%${value}%`}};
|
||||
case 'id':
|
||||
return {'i.id': value};
|
||||
case 'packingOut':
|
||||
case 'typeFk':
|
||||
param = `i.${param}`;
|
||||
return {[param]: value};
|
||||
case 'description':
|
||||
return {'i.description': {like: `%${value}%`}};
|
||||
case 'categoryFk':
|
||||
|
@ -80,8 +101,6 @@ module.exports = Self => {
|
|||
return {'it.workerFk': value};
|
||||
case 'code':
|
||||
return {'it.code': value};
|
||||
case 'typeFk':
|
||||
return {'i.typeFk': value};
|
||||
case 'active':
|
||||
return {'i.isActive': value};
|
||||
case 'visible':
|
||||
|
@ -93,7 +112,7 @@ module.exports = Self => {
|
|||
});
|
||||
filter = mergeFilters(ctx.args.filter, {where});
|
||||
|
||||
let stmts = [];
|
||||
const stmts = [];
|
||||
let stmt;
|
||||
|
||||
stmts.push('CALL cache.last_buy_refresh(FALSE)');
|
||||
|
@ -113,6 +132,7 @@ module.exports = Self => {
|
|||
i.description,
|
||||
i.name,
|
||||
i.subName,
|
||||
i.packingOut,
|
||||
i.tag5,
|
||||
i.value5,
|
||||
i.tag6,
|
||||
|
@ -179,10 +199,10 @@ module.exports = Self => {
|
|||
}
|
||||
|
||||
stmt.merge(conn.makeSuffix(filter));
|
||||
let buysIndex = stmts.push(stmt) - 1;
|
||||
const buysIndex = stmts.push(stmt) - 1;
|
||||
|
||||
let sql = ParameterizedSQL.join(stmts, ';');
|
||||
let result = await conn.executeStmt(sql);
|
||||
const sql = ParameterizedSQL.join(stmts, ';');
|
||||
const result = await conn.executeStmt(sql, myOptions);
|
||||
return buysIndex === 0 ? result : result[buysIndex];
|
||||
};
|
||||
};
|
||||
|
|
|
@ -3,29 +3,32 @@ const model = app.models.Buy;
|
|||
|
||||
describe('Buy editLatestsBuys()', () => {
|
||||
it('should change the value of a given column for the selected buys', async() => {
|
||||
let ctx = {
|
||||
args: {
|
||||
search: 'Ranged weapon longbow 2m'
|
||||
}
|
||||
};
|
||||
const tx = await app.models.Entry.beginTransaction({});
|
||||
const options = {transaction: tx};
|
||||
|
||||
let [original] = await model.latestBuysFilter(ctx);
|
||||
try {
|
||||
let ctx = {
|
||||
args: {
|
||||
search: 'Ranged weapon longbow 2m'
|
||||
}
|
||||
};
|
||||
|
||||
const field = 'size';
|
||||
let newValue = 99;
|
||||
const lines = [{itemFk: original.itemFk, id: original.id}];
|
||||
const [original] = await model.latestBuysFilter(ctx, null, options);
|
||||
|
||||
await model.editLatestBuys(field, newValue, lines);
|
||||
const field = 'size';
|
||||
const newValue = 99;
|
||||
const lines = [{itemFk: original.itemFk, id: original.id}];
|
||||
|
||||
let [result] = await model.latestBuysFilter(ctx);
|
||||
await model.editLatestBuys(field, newValue, lines, options);
|
||||
|
||||
expect(result.size).toEqual(99);
|
||||
const [result] = await model.latestBuysFilter(ctx, null, options);
|
||||
|
||||
newValue = original.size;
|
||||
await model.editLatestBuys(field, newValue, lines);
|
||||
expect(result[field]).toEqual(newValue);
|
||||
|
||||
let [restoredFixture] = await model.latestBuysFilter(ctx);
|
||||
|
||||
expect(restoredFixture.size).toEqual(original.size);
|
||||
await tx.rollback();
|
||||
} catch (e) {
|
||||
await tx.rollback();
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
},
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "entry"
|
||||
"table": "entry"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
|
|
|
@ -10,182 +10,185 @@
|
|||
</vn-watcher>
|
||||
<div class="vn-w-xl">
|
||||
<vn-card class="vn-pa-lg">
|
||||
<vn-horizontal class="header">
|
||||
<vn-tool-bar class="vn-mb-md">
|
||||
<vn-button
|
||||
disabled="$ctrl.selectedBuys() == 0"
|
||||
ng-click="deleteBuys.show()"
|
||||
vn-tooltip="Delete buy(s)"
|
||||
icon="delete">
|
||||
</vn-button>
|
||||
</vn-tool-bar>
|
||||
<vn-one class="taxes" ng-if="$ctrl.sales.length > 0">
|
||||
<p><vn-label translate>Subtotal</vn-label> {{$ctrl.ticket.totalWithoutVat | currency: 'EUR':2}}</p>
|
||||
<p><vn-label translate>VAT</vn-label> {{$ctrl.ticket.totalWithVat - $ctrl.ticket.totalWithoutVat | currency: 'EUR':2}}</p>
|
||||
<p><vn-label><strong>Total</strong></vn-label> <strong>{{$ctrl.ticket.totalWithVat | currency: 'EUR':2}}</strong></p>
|
||||
</vn-one>
|
||||
</vn-horizontal>
|
||||
<table class="vn-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th shrink>
|
||||
<vn-multi-check model="model" on-change="$ctrl.resetChanges()">
|
||||
</vn-multi-check>
|
||||
</th>
|
||||
<th translate center>Item</th>
|
||||
<th translate center>Quantity</th>
|
||||
<th translate center>Package</th>
|
||||
<th translate>Stickers</th>
|
||||
<th translate>Weight</th>
|
||||
<th translate>Packing</th>
|
||||
<th translate>Grouping</th>
|
||||
<th translate>Buying value</th>
|
||||
<th translate expand>Grouping price</th>
|
||||
<th translate expand>Packing price</th>
|
||||
<th translate>Import</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody ng-repeat="buy in $ctrl.buys">
|
||||
<tr>
|
||||
<td shrink>
|
||||
<vn-check tabindex="-1" ng-model="buy.checked">
|
||||
</vn-check>
|
||||
</td>
|
||||
<td shrink>
|
||||
<span
|
||||
ng-if="buy.id"
|
||||
ng-click="itemDescriptor.show($event, buy.item.id)"
|
||||
class="link">
|
||||
{{::buy.item.id | zeroFill:6}}
|
||||
</span>
|
||||
<vn-autocomplete ng-if="!buy.id" class="dense"
|
||||
vn-focus
|
||||
url="Items"
|
||||
ng-model="buy.itemFk"
|
||||
show-field="name"
|
||||
value-field="id"
|
||||
search-function="$ctrl.itemSearchFunc($search)"
|
||||
on-change="$ctrl.saveBuy(buy)"
|
||||
order="id DESC"
|
||||
tabindex="1">
|
||||
<tpl-item>
|
||||
{{::id}} - {{::name}}
|
||||
</tpl-item>
|
||||
</vn-autocomplete>
|
||||
</td>
|
||||
<td>
|
||||
<vn-input-number class="dense"
|
||||
title="{{::buy.quantity | dashIfEmpty}}"
|
||||
ng-model="buy.quantity"
|
||||
on-change="$ctrl.saveBuy(buy)">
|
||||
</vn-input-number>
|
||||
</td>
|
||||
<td center>
|
||||
<vn-autocomplete
|
||||
vn-one
|
||||
title="{{::buy.packageFk | dashIfEmpty}}"
|
||||
url="Packagings"
|
||||
show-field="id"
|
||||
value-field="id"
|
||||
where="{isBox: true}"
|
||||
ng-model="buy.packageFk"
|
||||
on-change="$ctrl.saveBuy(buy)">
|
||||
</vn-autocomplete>
|
||||
</td>
|
||||
<td>
|
||||
<vn-input-number class="dense"
|
||||
title="{{::buy.stickers | dashIfEmpty}}"
|
||||
ng-model="buy.stickers"
|
||||
on-change="$ctrl.saveBuy(buy)">
|
||||
</vn-input-number>
|
||||
</td>
|
||||
<td>
|
||||
<vn-input-number class="dense"
|
||||
title="{{::buy.weight | dashIfEmpty}}"
|
||||
ng-model="buy.weight"
|
||||
on-change="$ctrl.saveBuy(buy)">
|
||||
</vn-input-number>
|
||||
</td>
|
||||
<td>
|
||||
<vn-input-number class="dense"
|
||||
title="{{::buy.packing | dashIfEmpty}}"
|
||||
ng-model="buy.packing"
|
||||
on-change="$ctrl.saveBuy(buy)">
|
||||
</vn-input-number>
|
||||
</td>
|
||||
<td>
|
||||
<vn-input-number class="dense"
|
||||
title="{{::buy.grouping | dashIfEmpty}}"
|
||||
ng-model="buy.grouping"
|
||||
on-change="$ctrl.saveBuy(buy)">
|
||||
</vn-input-number>
|
||||
</td>
|
||||
<td>
|
||||
<vn-input-number class="dense"
|
||||
title="{{::buy.buyingValue | dashIfEmpty}}"
|
||||
ng-model="buy.buyingValue"
|
||||
on-change="$ctrl.saveBuy(buy)">
|
||||
</vn-input-number>
|
||||
</td>
|
||||
<td>
|
||||
<vn-input-number class="dense"
|
||||
title="{{::buy.price2 | dashIfEmpty}}"
|
||||
ng-model="buy.price2"
|
||||
on-change="$ctrl.saveBuy(buy)">
|
||||
</vn-input-number>
|
||||
</td>
|
||||
<td>
|
||||
<vn-input-number class="dense"
|
||||
title="{{::buy.price3 | dashIfEmpty}}"
|
||||
ng-model="buy.price3"
|
||||
on-change="$ctrl.saveBuy(buy)">
|
||||
</vn-input-number>
|
||||
</td>
|
||||
<td>
|
||||
<span
|
||||
ng-if="buy.quantity != null && buy.buyingValue != null"
|
||||
title="{{buy.quantity * buy.buyingValue | currency: 'EUR':2}}">
|
||||
{{buy.quantity * buy.buyingValue | currency: 'EUR':2}}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="dark-row">
|
||||
<td shrink>
|
||||
</td>
|
||||
<td shrink>
|
||||
<span translate-attr="{title: 'Item type'}">
|
||||
{{::buy.item.itemType.code}}
|
||||
</span>
|
||||
</td>
|
||||
<td number shrink>
|
||||
<span translate-attr="{title: 'Item size'}">
|
||||
{{::buy.item.size}}
|
||||
</span>
|
||||
</td>
|
||||
<td center>
|
||||
<span translate-attr="{title: 'Minimum price'}">
|
||||
{{::buy.item.minPrice | currency: 'EUR':2}}
|
||||
</span>
|
||||
</td>
|
||||
<td vn-fetched-tags colspan="9">
|
||||
<vn-one title="{{::buy.item.name}}">{{::buy.item.name}}</vn-one>
|
||||
<vn-fetched-tags
|
||||
max-length="6"
|
||||
item="::buy.item"
|
||||
tabindex="-1">
|
||||
</vn-fetched-tags>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div>
|
||||
<vn-icon-button
|
||||
vn-one
|
||||
vn-tooltip="Add buy"
|
||||
vn-bind="+"
|
||||
icon="add_circle"
|
||||
ng-click="model.insert({})">
|
||||
</vn-icon-button>
|
||||
<div class="tableWrapper">
|
||||
<vn-horizontal class="header">
|
||||
<vn-tool-bar class="vn-mb-md">
|
||||
<vn-button
|
||||
disabled="$ctrl.selectedBuys() == 0"
|
||||
ng-click="deleteBuys.show()"
|
||||
vn-tooltip="Delete buy(s)"
|
||||
icon="delete">
|
||||
</vn-button>
|
||||
</vn-tool-bar>
|
||||
<vn-one class="taxes" ng-if="$ctrl.sales.length > 0">
|
||||
<p><vn-label translate>Subtotal</vn-label> {{$ctrl.ticket.totalWithoutVat | currency: 'EUR':2}}</p>
|
||||
<p><vn-label translate>VAT</vn-label> {{$ctrl.ticket.totalWithVat - $ctrl.ticket.totalWithoutVat | currency: 'EUR':2}}</p>
|
||||
<p><vn-label><strong>Total</strong></vn-label> <strong>{{$ctrl.ticket.totalWithVat | currency: 'EUR':2}}</strong></p>
|
||||
</vn-one>
|
||||
</vn-horizontal>
|
||||
<table class="vn-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th shrink>
|
||||
<vn-multi-check model="model" on-change="$ctrl.resetChanges()">
|
||||
</vn-multi-check>
|
||||
</th>
|
||||
<th translate center>Item</th>
|
||||
<th translate center>Quantity</th>
|
||||
<th translate center>Package</th>
|
||||
<th translate>Stickers</th>
|
||||
<th translate>Weight</th>
|
||||
<th translate>Packing</th>
|
||||
<th translate>Grouping</th>
|
||||
<th translate>Buying value</th>
|
||||
<th translate expand>Grouping price</th>
|
||||
<th translate expand>Packing price</th>
|
||||
<th translate>Import</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody ng-repeat="buy in $ctrl.buys">
|
||||
<tr>
|
||||
<td shrink>
|
||||
<vn-check tabindex="-1" ng-model="buy.checked">
|
||||
</vn-check>
|
||||
</td>
|
||||
<td shrink>
|
||||
<span
|
||||
ng-if="buy.id"
|
||||
ng-click="itemDescriptor.show($event, buy.item.id)"
|
||||
class="link">
|
||||
{{::buy.item.id | zeroFill:6}}
|
||||
</span>
|
||||
<vn-autocomplete ng-if="!buy.id" class="dense"
|
||||
vn-focus
|
||||
url="Items"
|
||||
ng-model="buy.itemFk"
|
||||
show-field="name"
|
||||
value-field="id"
|
||||
search-function="$ctrl.itemSearchFunc($search)"
|
||||
on-change="$ctrl.saveBuy(buy)"
|
||||
order="id DESC"
|
||||
tabindex="1">
|
||||
<tpl-item>
|
||||
{{::id}} - {{::name}}
|
||||
</tpl-item>
|
||||
</vn-autocomplete>
|
||||
</td>
|
||||
<td>
|
||||
<vn-input-number class="dense"
|
||||
title="{{::buy.quantity | dashIfEmpty}}"
|
||||
ng-model="buy.quantity"
|
||||
on-change="$ctrl.saveBuy(buy)">
|
||||
</vn-input-number>
|
||||
</td>
|
||||
<td center>
|
||||
<vn-autocomplete
|
||||
vn-one
|
||||
title="{{::buy.packageFk | dashIfEmpty}}"
|
||||
url="Packagings"
|
||||
show-field="id"
|
||||
value-field="id"
|
||||
where="{isBox: true}"
|
||||
ng-model="buy.packageFk"
|
||||
on-change="$ctrl.saveBuy(buy)">
|
||||
</vn-autocomplete>
|
||||
</td>
|
||||
<td>
|
||||
<vn-input-number class="dense"
|
||||
title="{{::buy.stickers | dashIfEmpty}}"
|
||||
ng-model="buy.stickers"
|
||||
on-change="$ctrl.saveBuy(buy)">
|
||||
</vn-input-number>
|
||||
</td>
|
||||
<td>
|
||||
<vn-input-number class="dense"
|
||||
title="{{::buy.weight | dashIfEmpty}}"
|
||||
ng-model="buy.weight"
|
||||
on-change="$ctrl.saveBuy(buy)">
|
||||
</vn-input-number>
|
||||
</td>
|
||||
<td>
|
||||
<vn-input-number class="dense"
|
||||
title="{{::buy.packing | dashIfEmpty}}"
|
||||
ng-model="buy.packing"
|
||||
on-change="$ctrl.saveBuy(buy)">
|
||||
</vn-input-number>
|
||||
</td>
|
||||
<td>
|
||||
<vn-input-number class="dense"
|
||||
title="{{::buy.grouping | dashIfEmpty}}"
|
||||
ng-model="buy.grouping"
|
||||
on-change="$ctrl.saveBuy(buy)">
|
||||
</vn-input-number>
|
||||
</td>
|
||||
<td>
|
||||
<vn-input-number class="dense"
|
||||
title="{{::buy.buyingValue | dashIfEmpty}}"
|
||||
ng-model="buy.buyingValue"
|
||||
on-change="$ctrl.saveBuy(buy)">
|
||||
</vn-input-number>
|
||||
</td>
|
||||
<td>
|
||||
<vn-input-number class="dense"
|
||||
title="{{::buy.price2 | dashIfEmpty}}"
|
||||
ng-model="buy.price2"
|
||||
on-change="$ctrl.saveBuy(buy)">
|
||||
</vn-input-number>
|
||||
</td>
|
||||
<td>
|
||||
<vn-input-number class="dense"
|
||||
title="{{::buy.price3 | dashIfEmpty}}"
|
||||
ng-model="buy.price3"
|
||||
on-change="$ctrl.saveBuy(buy)">
|
||||
</vn-input-number>
|
||||
</td>
|
||||
<td>
|
||||
<span
|
||||
ng-if="buy.quantity != null && buy.buyingValue != null"
|
||||
title="{{buy.quantity * buy.buyingValue | currency: 'EUR':2}}">
|
||||
{{buy.quantity * buy.buyingValue | currency: 'EUR':2}}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="dark-row">
|
||||
<td shrink>
|
||||
</td>
|
||||
<td shrink>
|
||||
<span translate-attr="{title: 'Item type'}">
|
||||
{{::buy.item.itemType.code}}
|
||||
</span>
|
||||
</td>
|
||||
<td number shrink>
|
||||
<span translate-attr="{title: 'Item size'}">
|
||||
{{::buy.item.size}}
|
||||
</span>
|
||||
</td>
|
||||
<td center>
|
||||
<span translate-attr="{title: 'Minimum price'}">
|
||||
{{::buy.item.minPrice | currency: 'EUR':2}}
|
||||
</span>
|
||||
</td>
|
||||
<td vn-fetched-tags colspan="8">
|
||||
<vn-one title="{{::buy.item.name}}">{{::buy.item.name}}</vn-one>
|
||||
<vn-fetched-tags
|
||||
max-length="6"
|
||||
item="::buy.item"
|
||||
tabindex="-1">
|
||||
</vn-fetched-tags>
|
||||
</td>
|
||||
</tr>
|
||||
<tr><td></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div>
|
||||
<vn-icon-button
|
||||
vn-one
|
||||
vn-tooltip="Add buy"
|
||||
vn-bind="+"
|
||||
icon="add_circle"
|
||||
ng-click="model.insert({})">
|
||||
</vn-icon-button>
|
||||
</div>
|
||||
</div>
|
||||
</vn-card>
|
||||
</div>
|
||||
|
|
|
@ -3,19 +3,34 @@
|
|||
|
||||
vn-entry-buy-index vn-card {
|
||||
max-width: $width-xl;
|
||||
|
||||
|
||||
.dark-row {
|
||||
background-color: lighten($color-marginal, 10%);
|
||||
}
|
||||
|
||||
tbody tr:nth-child(1) {
|
||||
border-top: 1px solid $color-marginal;
|
||||
thead tr {
|
||||
border-left: 1px solid white;
|
||||
border-right: 1px solid white;
|
||||
}
|
||||
|
||||
tbody tr:nth-child(1),
|
||||
tbody tr:nth-child(2) {
|
||||
border-left: 1px solid $color-marginal;
|
||||
border-right: 1px solid $color-marginal;
|
||||
}
|
||||
|
||||
tbody tr:nth-child(2) {
|
||||
border-bottom: 1px solid $color-marginal;
|
||||
}
|
||||
|
||||
tbody{
|
||||
border-bottom: 1px solid $color-marginal;
|
||||
}
|
||||
|
||||
tbody:last-child {
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
tbody tr:nth-child(3) {
|
||||
height: inherit
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ Commission: Comisión
|
|||
Landed: F. entrega
|
||||
Reference: Referencia
|
||||
Created: Creado
|
||||
Booked: Facturado
|
||||
Booked: Contabilizada
|
||||
Is inventory: Inventario
|
||||
Notes: Notas
|
||||
Status: Estado
|
||||
|
|
|
@ -57,6 +57,7 @@
|
|||
<vn-th field="ektFk">Ekt</vn-th>
|
||||
<vn-th field="weight">Weight</vn-th>
|
||||
<vn-th field="packageFk" expand>PackageName</vn-th>
|
||||
<vn-th field="packingOut" expand>PackingOut</vn-th>
|
||||
</vn-tr>
|
||||
</vn-thead>
|
||||
<vn-tbody>
|
||||
|
@ -147,6 +148,7 @@
|
|||
<vn-td number>{{::buy.ektFk | dashIfEmpty}}</vn-td>
|
||||
<vn-td number>{{::buy.weight}}</vn-td>
|
||||
<vn-td number>{{::buy.packageFk}}</vn-td>
|
||||
<vn-td number>{{::buy.packingOut}}</vn-td>
|
||||
</a>
|
||||
</vn-tbody>
|
||||
</vn-table>
|
||||
|
|
|
@ -16,20 +16,14 @@ export default class Controller extends Section {
|
|||
if (this._columns) return this._columns;
|
||||
|
||||
this._columns = [
|
||||
{field: 'quantity', displayName: this.$t('Quantity')},
|
||||
{field: 'buyingValue', displayName: this.$t('Buying value')},
|
||||
{field: 'freightValue', displayName: this.$t('Freight value')},
|
||||
{field: 'packing', displayName: this.$t('Packing')},
|
||||
{field: 'grouping', displayName: this.$t('Grouping')},
|
||||
{field: 'comissionValue', displayName: this.$t('Commission value')},
|
||||
{field: 'packageValue', displayName: this.$t('Package value')},
|
||||
{field: 'price2', displayName: this.$t('Grouping price')},
|
||||
{field: 'price3', displayName: this.$t('Packing price')},
|
||||
{field: 'weight', displayName: this.$t('Weight')},
|
||||
{field: 'description', displayName: this.$t('Description')},
|
||||
{field: 'minPrice', displayName: this.$t('Min price')},
|
||||
{field: 'size', displayName: this.$t('Size')},
|
||||
{field: 'density', displayName: this.$t('Density')}
|
||||
{field: 'density', displayName: this.$t('Density')},
|
||||
{field: 'packingOut', displayName: this.$t('PackingOut')}
|
||||
];
|
||||
|
||||
return this._columns;
|
||||
|
@ -59,10 +53,14 @@ export default class Controller extends Section {
|
|||
}
|
||||
|
||||
onEditAccept() {
|
||||
const rowsToEdit = [];
|
||||
for (let row of this.checked)
|
||||
rowsToEdit.push({id: row.id, itemFk: row.itemFk});
|
||||
|
||||
let data = {
|
||||
field: this.editedColumn.field,
|
||||
newValue: this.editedColumn.newValue,
|
||||
lines: this.checked
|
||||
lines: rowsToEdit
|
||||
};
|
||||
|
||||
return this.$http.post('Buys/editLatestBuys', data)
|
||||
|
|
|
@ -13,4 +13,5 @@ Minimun amount: Cantidad mínima de compra
|
|||
Field to edit: Campo a editar
|
||||
PackageName: Cubo
|
||||
Edit: Editar
|
||||
buy(s): compra(s)
|
||||
buy(s): compra(s)
|
||||
PackingOut: Packing envíos
|
|
@ -26,30 +26,35 @@
|
|||
"abstract": true,
|
||||
"component": "vn-entry",
|
||||
"description": "Entries"
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"url": "/index?q",
|
||||
"state": "entry.index",
|
||||
"component": "vn-entry-index",
|
||||
"description": "Entries",
|
||||
"acl": ["buyer", "administrative"]
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"url": "/latest-buys?q",
|
||||
"state": "entry.latestBuys",
|
||||
"component": "vn-entry-latest-buys",
|
||||
"description": "Latest buys",
|
||||
"acl": ["buyer", "administrative"]
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"url": "/create?supplierFk&travelFk&companyFk",
|
||||
"state": "entry.create",
|
||||
"component": "vn-entry-create",
|
||||
"description": "New entry",
|
||||
"acl": ["buyer", "administrative"]
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"url": "/:id",
|
||||
"state": "entry.card",
|
||||
"abstract": true,
|
||||
"component": "vn-entry-card"
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"url": "/summary",
|
||||
"state": "entry.card.summary",
|
||||
"component": "vn-entry-summary",
|
||||
|
@ -58,7 +63,8 @@
|
|||
"entry": "$ctrl.entry"
|
||||
},
|
||||
"acl": ["buyer", "administrative"]
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"url": "/basic-data",
|
||||
"state": "entry.card.basicData",
|
||||
"component": "vn-entry-basic-data",
|
||||
|
@ -67,7 +73,8 @@
|
|||
"entry": "$ctrl.entry"
|
||||
},
|
||||
"acl": ["buyer", "administrative"]
|
||||
},{
|
||||
},
|
||||
{
|
||||
"url": "/observation",
|
||||
"state": "entry.card.observation",
|
||||
"component": "vn-entry-observation",
|
||||
|
@ -76,7 +83,8 @@
|
|||
"entry": "$ctrl.entry"
|
||||
},
|
||||
"acl": ["buyer", "administrative"]
|
||||
},{
|
||||
},
|
||||
{
|
||||
"url" : "/log",
|
||||
"state": "entry.card.log",
|
||||
"component": "vn-entry-log",
|
||||
|
|
|
@ -1,3 +1,10 @@
|
|||
<vn-crud-model
|
||||
vn-id="buysModel"
|
||||
url="Entries/{{$ctrl.$params.id}}/getBuys"
|
||||
limit="5"
|
||||
data="buys"
|
||||
auto-load="true">
|
||||
</vn-crud-model>
|
||||
<vn-card class="summary">
|
||||
<h5>
|
||||
<a ng-if="::$ctrl.entryData.id"
|
||||
|
@ -95,7 +102,7 @@
|
|||
<th translate center expand field="price3">Packing price</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody ng-repeat="line in $ctrl.buys">
|
||||
<tbody ng-repeat="line in buys">
|
||||
<tr>
|
||||
<td center title="{{::line.quantity}}">{{::line.quantity}}</td>
|
||||
<td center title="{{::line.stickers | dashIfEmpty}}">{{::line.stickers | dashIfEmpty}}</td>
|
||||
|
@ -156,6 +163,10 @@
|
|||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<vn-pagination
|
||||
model="buysModel"
|
||||
class="vn-pt-xs">
|
||||
</vn-pagination>
|
||||
</vn-auto>
|
||||
</vn-horizontal>
|
||||
</vn-card>
|
||||
|
|
|
@ -10,10 +10,8 @@ class Controller extends Summary {
|
|||
set entry(value) {
|
||||
this._entry = value;
|
||||
|
||||
if (value && value.id) {
|
||||
if (value && value.id)
|
||||
this.getEntryData();
|
||||
this.getBuys();
|
||||
}
|
||||
}
|
||||
|
||||
getEntryData() {
|
||||
|
@ -21,12 +19,6 @@ class Controller extends Summary {
|
|||
this.entryData = response.data;
|
||||
});
|
||||
}
|
||||
|
||||
getBuys() {
|
||||
return this.$http.get(`Entries/${this.entry.id}/getBuys`).then(response => {
|
||||
this.buys = response.data;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
ngModule.vnComponent('vnEntrySummary', {
|
||||
|
|
|
@ -46,20 +46,4 @@ describe('component vnEntrySummary', () => {
|
|||
expect(controller.entryData).toEqual('I am the entryData');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getBuys()', () => {
|
||||
it('should perform a get asking for the buys of an entry', () => {
|
||||
controller._entry = {id: 999};
|
||||
|
||||
const thatQuery = `Entries/${controller._entry.id}/getEntry`;
|
||||
const query = `Entries/${controller._entry.id}/getBuys`;
|
||||
|
||||
$httpBackend.whenGET(thatQuery).respond('My Entries');
|
||||
$httpBackend.expectGET(query).respond('Some buys');
|
||||
controller.getBuys();
|
||||
$httpBackend.flush();
|
||||
|
||||
expect(controller.buys).toEqual('Some buys');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -109,8 +109,9 @@ module.exports = Self => {
|
|||
return {'ii.created': {gte: value}};
|
||||
case 'to':
|
||||
return {'ii.created': {lte: value}};
|
||||
case 'account':
|
||||
case 'fi':
|
||||
return {'s.nif': value};
|
||||
case 'account':
|
||||
return {[`s.${param}`]: value};
|
||||
case 'supplierRef':
|
||||
case 'supplierFk':
|
||||
|
@ -139,6 +140,7 @@ module.exports = Self => {
|
|||
ii.supplierRef,
|
||||
ii.docFk AS dmsFk,
|
||||
ii.supplierFk,
|
||||
ii.expenceFkDeductible deductibleExpenseFk,
|
||||
s.name AS supplierName,
|
||||
s.account,
|
||||
SUM(iid.amount) AS amount,
|
||||
|
|
|
@ -39,6 +39,18 @@ module.exports = Self => {
|
|||
scope: {
|
||||
fields: ['withholding']
|
||||
}
|
||||
},
|
||||
{
|
||||
relation: 'expenseDeductible',
|
||||
scope: {
|
||||
fields: ['id', 'name', 'taxTypeFk']
|
||||
}
|
||||
},
|
||||
{
|
||||
relation: 'currency',
|
||||
scope: {
|
||||
fields: ['id', 'name']
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
|
|
@ -4,5 +4,8 @@
|
|||
},
|
||||
"InvoiceInDueDay": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"InvoiceInLog": {
|
||||
"dataSource": "vn"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
{
|
||||
"name": "InvoiceInLog",
|
||||
"base": "VnModel",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "invoiceInLog"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"id": {
|
||||
"id": true,
|
||||
"type": "number",
|
||||
"forceId": false
|
||||
},
|
||||
"originFk": {
|
||||
"type": "number",
|
||||
"required": true
|
||||
},
|
||||
"userFk": {
|
||||
"type": "number"
|
||||
},
|
||||
"action": {
|
||||
"type": "string",
|
||||
"required": true
|
||||
},
|
||||
"changedModel": {
|
||||
"type": "string"
|
||||
},
|
||||
"oldInstance": {
|
||||
"type": "object"
|
||||
},
|
||||
"newInstance": {
|
||||
"type": "object"
|
||||
},
|
||||
"creationDate": {
|
||||
"type": "date"
|
||||
},
|
||||
"changedModelId": {
|
||||
"type": "string"
|
||||
},
|
||||
"changedModelValue": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"relations": {
|
||||
"user": {
|
||||
"type": "belongsTo",
|
||||
"model": "Account",
|
||||
"foreignKey": "userFk"
|
||||
}
|
||||
},
|
||||
"scope": {
|
||||
"order": [
|
||||
"creationDate DESC",
|
||||
"id DESC"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -1,6 +1,9 @@
|
|||
{
|
||||
"name": "InvoiceIn",
|
||||
"base": "VnModel",
|
||||
"base": "Loggable",
|
||||
"log": {
|
||||
"model": "InvoiceInLog"
|
||||
},
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "invoiceIn"
|
||||
|
@ -30,9 +33,6 @@
|
|||
"isBooked": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"isVatDeductible": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"booked": {
|
||||
"type": "date"
|
||||
},
|
||||
|
@ -47,6 +47,12 @@
|
|||
"mysql": {
|
||||
"columnName": "docFk"
|
||||
}
|
||||
},
|
||||
"deductibleExpenseFk": {
|
||||
"type": "number",
|
||||
"mysql": {
|
||||
"columnName": "expenceFkDeductible"
|
||||
}
|
||||
}
|
||||
},
|
||||
"relations": {
|
||||
|
@ -60,6 +66,11 @@
|
|||
"model": "SageWithholding",
|
||||
"foreignKey": "withholdingSageFk"
|
||||
},
|
||||
"expenseDeductible": {
|
||||
"type": "belongsTo",
|
||||
"model": "Expense",
|
||||
"foreignKey": "deductibleExpenseFk"
|
||||
},
|
||||
"company": {
|
||||
"type": "belongsTo",
|
||||
"model": "Company",
|
||||
|
|
|
@ -7,21 +7,6 @@
|
|||
</vn-watcher>
|
||||
<form name="form" ng-submit="watcher.submit()" class="vn-w-md">
|
||||
<vn-card class="vn-pa-lg">
|
||||
<vn-horizontal>
|
||||
<vn-date-picker
|
||||
vn-one
|
||||
label="Expedition date"
|
||||
ng-model="$ctrl.invoiceIn.issued"
|
||||
vn-focus
|
||||
rule>
|
||||
</vn-date-picker>
|
||||
<vn-date-picker
|
||||
vn-one
|
||||
label="Operation date"
|
||||
ng-model="$ctrl.invoiceIn.operated"
|
||||
rule>
|
||||
</vn-date-picker>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-autocomplete
|
||||
vn-one
|
||||
|
@ -44,6 +29,35 @@
|
|||
rule>
|
||||
</vn-textfield>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-date-picker
|
||||
vn-one
|
||||
label="Expedition date"
|
||||
ng-model="$ctrl.invoiceIn.issued"
|
||||
vn-focus
|
||||
rule>
|
||||
</vn-date-picker>
|
||||
<vn-date-picker
|
||||
vn-one
|
||||
label="Operation date"
|
||||
ng-model="$ctrl.invoiceIn.operated"
|
||||
rule>
|
||||
</vn-date-picker>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-datalist vn-one
|
||||
label="Undeductible VAT"
|
||||
ng-model="$ctrl.invoiceIn.deductibleExpenseFk"
|
||||
value-field="id"
|
||||
order="name"
|
||||
url="Expenses"
|
||||
fields="['id','name']"
|
||||
rule>
|
||||
<tpl-item>
|
||||
{{id}} - {{name}}
|
||||
</tpl-item>
|
||||
</vn-datalist>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-date-picker
|
||||
vn-one
|
||||
|
|
|
@ -9,3 +9,4 @@ import './descriptor-popover';
|
|||
import './summary';
|
||||
import './basic-data';
|
||||
import './create';
|
||||
import './log';
|
||||
|
|
|
@ -54,19 +54,22 @@
|
|||
</vn-icon-button>
|
||||
</vn-td>
|
||||
<vn-td shrink>
|
||||
<vn-icon-button
|
||||
<!-- <vn-icon-button
|
||||
ng-show="invoiceIn.dmsFk"
|
||||
vn-click-stop="$ctrl.openPdf(invoiceIn.dmsFk)"
|
||||
icon="cloud_download"
|
||||
title="Download PDF"
|
||||
vn-tooltip="Download PDF">
|
||||
</vn-icon-button>
|
||||
</vn-icon-button> -->
|
||||
</vn-td>
|
||||
</a>
|
||||
</vn-tbody>
|
||||
</vn-table>
|
||||
</vn-card>
|
||||
</vn-data-viewer>
|
||||
<vn-supplier-descriptor-popover
|
||||
vn-id="supplierDescriptor">
|
||||
</vn-supplier-descriptor-popover>
|
||||
<vn-popup vn-id="summary">
|
||||
<vn-invoice-in-summary
|
||||
invoice-in="$ctrl.selectedInvoiceIn">
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
<vn-log url="InvoiceInLogs" origin-id="$ctrl.$params.id"></vn-log>
|
|
@ -0,0 +1,7 @@
|
|||
import ngModule from '../module';
|
||||
import Section from 'salix/components/section';
|
||||
|
||||
ngModule.vnComponent('vnInvoiceInLog', {
|
||||
template: require('./index.html'),
|
||||
controller: Section,
|
||||
});
|
|
@ -2,16 +2,26 @@
|
|||
"module": "invoiceIn",
|
||||
"name": "Invoices in",
|
||||
"icon": "icon-invoiceIn",
|
||||
"validations" : true,
|
||||
"dependencies": ["worker", "supplier"],
|
||||
"validations": true,
|
||||
"dependencies": [
|
||||
"worker",
|
||||
"supplier"
|
||||
],
|
||||
"menus": {
|
||||
"main": [
|
||||
{"state": "invoiceIn.index", "icon": "icon-invoiceIn"}
|
||||
{
|
||||
"state": "invoiceIn.index",
|
||||
"icon": "icon-invoiceIn"
|
||||
}
|
||||
],
|
||||
"card": [
|
||||
{
|
||||
"state": "invoiceIn.card.basicData",
|
||||
"icon": "settings"
|
||||
},
|
||||
{
|
||||
"state": "invoiceIn.card.log",
|
||||
"icon": "history"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -28,7 +38,9 @@
|
|||
"state": "invoiceIn.index",
|
||||
"component": "vn-invoice-in-index",
|
||||
"description": "InvoiceIn",
|
||||
"acl": ["administrative"]
|
||||
"acl": [
|
||||
"administrative"
|
||||
]
|
||||
},
|
||||
{
|
||||
"url": "/:id",
|
||||
|
@ -44,7 +56,9 @@
|
|||
"params": {
|
||||
"invoice-in": "$ctrl.invoiceIn"
|
||||
},
|
||||
"acl": ["administrative"]
|
||||
"acl": [
|
||||
"administrative"
|
||||
]
|
||||
},
|
||||
{
|
||||
"url": "/basic-data",
|
||||
|
@ -53,13 +67,28 @@
|
|||
"description": "Basic data",
|
||||
"params": {
|
||||
"invoice-in": "$ctrl.invoiceIn"
|
||||
}
|
||||
},
|
||||
"acl": [
|
||||
"administrative"
|
||||
]
|
||||
},
|
||||
{
|
||||
"url" : "/create?supplierFk",
|
||||
"url": "/create?supplierFk",
|
||||
"state": "invoiceIn.create",
|
||||
"component": "vn-invoice-in-create",
|
||||
"description": "New InvoiceIn"
|
||||
"description": "New InvoiceIn",
|
||||
"acl": [
|
||||
"administrative"
|
||||
]
|
||||
},
|
||||
{
|
||||
"url": "/log",
|
||||
"state": "invoiceIn.card.log",
|
||||
"component": "vn-invoice-in-log",
|
||||
"description": "Log",
|
||||
"acl": [
|
||||
"administrative"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -27,11 +27,12 @@
|
|||
label="Account"
|
||||
ng-model="filter.account">
|
||||
</vn-textfield>
|
||||
<vn-textfield
|
||||
<vn-input-number
|
||||
vn-one
|
||||
label="Amount"
|
||||
ng-model="filter.amount">
|
||||
</vn-textfield>
|
||||
ng-model="filter.amount"
|
||||
step="0.01">
|
||||
</vn-input-number>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-date-picker
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
</vn-label-value>
|
||||
<vn-label-value label="Supplier ref" value="{{$ctrl.summary.supplierRef}}">
|
||||
</vn-label-value>
|
||||
<vn-label-value label="Currency" value="{{$ctrl.summary.currency.name}}">
|
||||
</vn-label-value>
|
||||
<vn-label-value label="Doc number" value="{{$ctrl.summary.serial}}/{{$ctrl.summary.serialNumber}}">
|
||||
</vn-label-value>
|
||||
</vn-one>
|
||||
|
@ -34,11 +36,11 @@
|
|||
<vn-one>
|
||||
<vn-label-value label="Sage withholding" value="{{$ctrl.summary.sageWithholding.withholding}}">
|
||||
</vn-label-value>
|
||||
<vn-label-value label="Undeductible VAT" value="{{$ctrl.summary.expenseDeductible.name}}">
|
||||
</vn-label-value>
|
||||
<vn-label-value label="Company" value="{{$ctrl.summary.company.code}}">
|
||||
</vn-label-value>
|
||||
<vn-vertical>
|
||||
<vn-check label="Deductible" ng-model="$ctrl.summary.isVatDeductible" disabled="true">
|
||||
</vn-check>
|
||||
<vn-check label="Booked" ng-model="$ctrl.summary.isBooked" disabled="true">
|
||||
</vn-check>
|
||||
</vn-vertical>
|
||||
|
|
|
@ -7,4 +7,4 @@ Booked date: Fecha contable
|
|||
Accounted date: Fecha contable
|
||||
Doc number: Numero documento
|
||||
Sage withholding: Retención sage
|
||||
Deductible: Deducible
|
||||
Undeductible VAT: Iva no deducible
|
|
@ -0,0 +1,55 @@
|
|||
const mergeFilters = require('vn-loopback/util/filter').mergeFilters;
|
||||
|
||||
module.exports = Self => {
|
||||
Self.remoteMethod('getTickets', {
|
||||
description: 'Returns tickets for one invoiceOut',
|
||||
accessType: 'READ',
|
||||
accepts: [{
|
||||
arg: 'id',
|
||||
type: 'number',
|
||||
required: true,
|
||||
description: 'The invoiceOut id',
|
||||
http: {source: 'path'}
|
||||
},
|
||||
{
|
||||
arg: 'filter',
|
||||
type: 'object',
|
||||
description: 'Filter defining where, order, offset, and limit - must be a JSON-encoded string'
|
||||
}
|
||||
],
|
||||
returns: {
|
||||
type: ['object'],
|
||||
root: true
|
||||
},
|
||||
http: {
|
||||
path: `/:id/getTickets`,
|
||||
verb: 'GET'
|
||||
}
|
||||
});
|
||||
|
||||
Self.getTickets = async(id, filter, options) => {
|
||||
const models = Self.app.models;
|
||||
let myOptions = {};
|
||||
|
||||
if (typeof options == 'object')
|
||||
Object.assign(myOptions, options);
|
||||
|
||||
const invoiceOut = await models.InvoiceOut.findById(id, {fields: 'ref'}, myOptions);
|
||||
|
||||
let defaultFilter = {
|
||||
where: {refFk: invoiceOut.ref},
|
||||
fields: [
|
||||
'id',
|
||||
'nickname',
|
||||
'shipped',
|
||||
'totalWithVat',
|
||||
'clientFk'
|
||||
]
|
||||
|
||||
};
|
||||
|
||||
defaultFilter = mergeFilters(defaultFilter, filter);
|
||||
|
||||
return models.Ticket.find(defaultFilter, myOptions);
|
||||
};
|
||||
};
|
|
@ -0,0 +1,10 @@
|
|||
const app = require('vn-loopback/server/server');
|
||||
|
||||
describe('entry getTickets()', () => {
|
||||
const invoiceOutId = 4;
|
||||
it('should get the ticket of an invoiceOut', async() => {
|
||||
const result = await app.models.InvoiceOut.getTickets(invoiceOutId);
|
||||
|
||||
expect(result.length).toEqual(1);
|
||||
});
|
||||
});
|
|
@ -7,14 +7,6 @@ describe('invoiceOut summary()', () => {
|
|||
expect(result.invoiceOut.id).toEqual(1);
|
||||
});
|
||||
|
||||
it(`should return a summary object containing data from it's tickets`, async() => {
|
||||
const summary = await app.models.InvoiceOut.summary(1);
|
||||
const tickets = summary.invoiceOut.tickets();
|
||||
|
||||
expect(summary.invoiceOut.ref).toEqual('T1111111');
|
||||
expect(tickets.length).toEqual(2);
|
||||
});
|
||||
|
||||
it(`should return a summary object containing it's supplier country`, async() => {
|
||||
const summary = await app.models.InvoiceOut.summary(1);
|
||||
const supplier = summary.invoiceOut.supplier();
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
|
||||
|
||||
module.exports = Self => {
|
||||
Self.remoteMethod('summary', {
|
||||
description: 'The invoiceOut summary',
|
||||
|
@ -22,7 +20,6 @@ module.exports = Self => {
|
|||
});
|
||||
|
||||
Self.summary = async id => {
|
||||
const conn = Self.dataSource.connector;
|
||||
let summary = {};
|
||||
|
||||
const filter = {
|
||||
|
@ -57,54 +54,20 @@ module.exports = Self => {
|
|||
scope: {
|
||||
fields: ['id', 'socialName']
|
||||
}
|
||||
},
|
||||
{
|
||||
relation: 'tickets'
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
summary.invoiceOut = await Self.app.models.InvoiceOut.findOne(filter);
|
||||
|
||||
let stmts = [];
|
||||
|
||||
stmts.push('DROP TEMPORARY TABLE IF EXISTS tmp.ticket');
|
||||
|
||||
stmt = new ParameterizedSQL(`
|
||||
CREATE TEMPORARY TABLE tmp.ticket
|
||||
(INDEX (ticketFk)) ENGINE = MEMORY
|
||||
SELECT id ticketFk FROM vn.ticket WHERE refFk=?`, [summary.invoiceOut.ref]);
|
||||
stmts.push(stmt);
|
||||
|
||||
stmts.push('CALL ticketGetTotal()');
|
||||
|
||||
let ticketTotalsIndex = stmts.push('SELECT * FROM tmp.ticketTotal') - 1;
|
||||
|
||||
stmt = new ParameterizedSQL(`
|
||||
const invoiceOutTaxes = await Self.rawSql(`
|
||||
SELECT iot.* , pgc.*, IF(pe.equFk IS NULL, taxableBase, 0) AS Base, pgc.rate / 100 as vatPercent
|
||||
FROM vn.invoiceOutTax iot
|
||||
JOIN vn.pgc ON pgc.code = iot.pgcFk
|
||||
LEFT JOIN vn.pgcEqu pe ON pe.equFk = pgc.code
|
||||
WHERE invoiceOutFk = ?`, [summary.invoiceOut.id]);
|
||||
let invoiceOutTaxesIndex = stmts.push(stmt) - 1;
|
||||
|
||||
stmts.push(
|
||||
`DROP TEMPORARY TABLE
|
||||
tmp.ticket,
|
||||
tmp.ticketTotal`);
|
||||
|
||||
let sql = ParameterizedSQL.join(stmts, ';');
|
||||
let result = await conn.executeStmt(sql);
|
||||
|
||||
totalMap = {};
|
||||
for (ticketTotal of result[ticketTotalsIndex])
|
||||
totalMap[ticketTotal.ticketFk] = ticketTotal.total;
|
||||
|
||||
summary.invoiceOut.tickets().forEach(ticket => {
|
||||
ticket.total = totalMap[ticket.id];
|
||||
});
|
||||
|
||||
summary.invoiceOut.taxesBreakdown = result[invoiceOutTaxesIndex];
|
||||
summary.invoiceOut.taxesBreakdown = invoiceOutTaxes;
|
||||
|
||||
return summary;
|
||||
};
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
module.exports = Self => {
|
||||
require('../methods/invoiceOut/filter')(Self);
|
||||
require('../methods/invoiceOut/summary')(Self);
|
||||
require('../methods/invoiceOut/getTickets')(Self);
|
||||
require('../methods/invoiceOut/download')(Self);
|
||||
require('../methods/invoiceOut/delete')(Self);
|
||||
require('../methods/invoiceOut/book')(Self);
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
<vn-td expand>{{::invoiceOut.created | date:'dd/MM/yyyy' | dashIfEmpty}}</vn-td>
|
||||
<vn-td>{{::invoiceOut.companyCode | dashIfEmpty}}</vn-td>
|
||||
<vn-td shrink>{{::invoiceOut.dued | date:'dd/MM/yyyy' | dashIfEmpty}}</vn-td>
|
||||
<vn-td>
|
||||
<vn-td shrink>
|
||||
<vn-icon-button
|
||||
ng-show="invoiceOut.hasPdf"
|
||||
vn-click-stop="$ctrl.openPdf(invoiceOut.id)"
|
||||
|
@ -45,7 +45,7 @@
|
|||
vn-tooltip="Download PDF">
|
||||
</vn-icon-button>
|
||||
</vn-td>
|
||||
<vn-td>
|
||||
<vn-td shrink>
|
||||
<vn-icon-button
|
||||
vn-click-stop="$ctrl.preview(invoiceOut)"
|
||||
vn-tooltip="Preview"
|
||||
|
|
|
@ -1,3 +1,10 @@
|
|||
<vn-crud-model
|
||||
vn-id="ticketsModel"
|
||||
url="InvoiceOuts/{{$ctrl.$params.id}}/getTickets"
|
||||
limit="10"
|
||||
data="tickets"
|
||||
auto-load="true">
|
||||
</vn-crud-model>
|
||||
<vn-card class="summary">
|
||||
<h5>
|
||||
<a ng-if="::$ctrl.summary.invoiceOut.id"
|
||||
|
@ -59,7 +66,7 @@
|
|||
</vn-tr>
|
||||
</vn-thead>
|
||||
<vn-tbody>
|
||||
<vn-tr ng-repeat="ticket in $ctrl.summary.invoiceOut.tickets">
|
||||
<vn-tr ng-repeat="ticket in tickets">
|
||||
<vn-td number>
|
||||
<span
|
||||
ng-click="ticketDescriptor.show($event, ticket.id)"
|
||||
|
@ -75,10 +82,14 @@
|
|||
</span>
|
||||
</vn-td>
|
||||
<vn-td expand>{{ticket.shipped | date: 'dd/MM/yyyy' | dashIfEmpty}}</vn-td>
|
||||
<vn-td number>{{ticket.total | currency: 'EUR': 2}}</vn-td>
|
||||
<vn-td number>{{ticket.totalWithVat | currency: 'EUR': 2}}</vn-td>
|
||||
</vn-tr>
|
||||
</vn-tbody>
|
||||
</vn-table>
|
||||
<vn-pagination
|
||||
model="ticketsModel"
|
||||
class="vn-pt-xs">
|
||||
</vn-pagination>
|
||||
</vn-auto>
|
||||
</vn-horizontal>
|
||||
</vn-card>
|
||||
|
|
|
@ -9,14 +9,17 @@
|
|||
"properties": {
|
||||
"id": {
|
||||
"id": true,
|
||||
"type": "Number",
|
||||
"type": "number",
|
||||
"description": "Identifier"
|
||||
},
|
||||
"name": {
|
||||
"type": "String"
|
||||
},
|
||||
"isWithheld": {
|
||||
"type": "Number"
|
||||
"type": "number"
|
||||
},
|
||||
"taxTypeFk": {
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
"relations": {
|
||||
|
|
|
@ -117,6 +117,9 @@
|
|||
"value10": {
|
||||
"type": "string"
|
||||
},
|
||||
"itemPackingTypeFk": {
|
||||
"type": "string"
|
||||
},
|
||||
"compression": {
|
||||
"type": "number"
|
||||
},
|
||||
|
@ -137,6 +140,9 @@
|
|||
"minPrice": {
|
||||
"type": "number"
|
||||
},
|
||||
"packingOut": {
|
||||
"type": "number"
|
||||
},
|
||||
"hasMinPrice": {
|
||||
"type": "boolean"
|
||||
},
|
||||
|
|
|
@ -304,7 +304,6 @@ module.exports = Self => {
|
|||
stmts.push(
|
||||
`DROP TEMPORARY TABLE
|
||||
tmp.filter,
|
||||
tmp.ticket,
|
||||
tmp.ticket_problems`);
|
||||
|
||||
let sql = ParameterizedSQL.join(stmts, ';');
|
||||
|
|
|
@ -10,6 +10,11 @@
|
|||
Clients on website
|
||||
</vn-one>
|
||||
<vn-none>
|
||||
<vn-icon class="arrow"
|
||||
icon="keyboard_arrow_up"
|
||||
vn-tooltip="Minimize/Maximize"
|
||||
ng-click="$ctrl.main.toggle()">
|
||||
</vn-icon>
|
||||
<vn-icon
|
||||
icon="refresh"
|
||||
vn-tooltip="Refresh"
|
||||
|
@ -17,7 +22,7 @@
|
|||
</vn-icon>
|
||||
</vn-none>
|
||||
</vn-horizontal>
|
||||
<vn-card>
|
||||
<vn-card vn-id="card">
|
||||
<vn-table model="model" class="scrollable sm">
|
||||
<vn-thead>
|
||||
<vn-tr>
|
||||
|
@ -52,12 +57,6 @@
|
|||
</vn-tr>
|
||||
</vn-tbody>
|
||||
</vn-table>
|
||||
<div
|
||||
ng-if="!model.data.length"
|
||||
class="empty-rows vn-pa-sm"
|
||||
translate>
|
||||
No results
|
||||
</div>
|
||||
<vn-pagination
|
||||
model="model"
|
||||
class="vn-pt-xs"
|
||||
|
|
|
@ -26,5 +26,8 @@ export default class Controller extends Section {
|
|||
|
||||
ngModule.vnComponent('vnMonitorSalesClients', {
|
||||
template: require('./index.html'),
|
||||
controller: Controller
|
||||
controller: Controller,
|
||||
require: {
|
||||
main: '^vnMonitorIndex'
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,11 +1,5 @@
|
|||
<vn-horizontal>
|
||||
<vn-three class="vn-mr-sm">
|
||||
<vn-monitor-sales-tickets></vn-monitor-sales-tickets>
|
||||
</vn-three>
|
||||
<vn-one>
|
||||
<vn-vertical>
|
||||
<vn-monitor-sales-clients class="vn-mb-sm"></vn-monitor-sales-clients>
|
||||
<vn-monitor-sales-orders></vn-monitor-sales-orders>
|
||||
</vn-vertical>
|
||||
</vn-one>
|
||||
</vn-horizontal>
|
||||
<vn-monitor-sales-clients class="vn-mb-sm"></vn-monitor-sales-clients>
|
||||
<vn-monitor-sales-orders></vn-monitor-sales-orders>
|
||||
</vn-horizontal>
|
||||
<vn-monitor-sales-tickets></vn-monitor-sales-tickets>
|
|
@ -2,7 +2,22 @@ import ngModule from '../module';
|
|||
import Section from 'salix/components/section';
|
||||
import './style.scss';
|
||||
|
||||
export default class Controller extends Section {
|
||||
toggle() {
|
||||
const monitor = this.element.querySelector('vn-horizontal');
|
||||
const isHidden = monitor.classList.contains('hidden');
|
||||
|
||||
if (!isHidden)
|
||||
monitor.classList.add('hidden');
|
||||
else
|
||||
monitor.classList.remove('hidden');
|
||||
}
|
||||
}
|
||||
|
||||
ngModule.vnComponent('vnMonitorIndex', {
|
||||
template: require('./index.html'),
|
||||
controller: Section
|
||||
controller: Controller,
|
||||
require: {
|
||||
main: '^vnMonitorIndex'
|
||||
}
|
||||
});
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue