This commit is contained in:
parent
a5486ec694
commit
0918f154e9
|
@ -0,0 +1,6 @@
|
||||||
|
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
|
||||||
|
VALUES
|
||||||
|
('Dms', '*', 'READ', 'ALLOW', 'ROLE', 'employee'),
|
||||||
|
('ClaimDms', 'removeFile', 'WRITE', 'ALLOW', 'ROLE', 'employee'),
|
||||||
|
('ClaimDms', '*', 'READ', 'ALLOW', 'ROLE', 'employee'),
|
||||||
|
('Claim', 'uploadFile', 'WRITE', 'ALLOW', 'ROLE', 'employee');
|
|
@ -1838,7 +1838,7 @@ INSERT INTO `vn`.`dmsType`(`id`, `name`, `path`, `readRoleFk`, `writeRoleFk`, `c
|
||||||
(17, 'cmr', 'cmr', NULL, NULL, 'cmr'),
|
(17, 'cmr', 'cmr', NULL, NULL, 'cmr'),
|
||||||
(18, 'dua', 'dua', NULL, NULL, 'dua'),
|
(18, 'dua', 'dua', NULL, NULL, 'dua'),
|
||||||
(19, 'inmovilizado', 'inmovilizado', NULL, NULL, 'fixedAssets'),
|
(19, 'inmovilizado', 'inmovilizado', NULL, NULL, 'fixedAssets'),
|
||||||
(20, 'Reclamación', 'reclamacion', NULL, NULL, 'claim');
|
(20, 'Reclamación', 'reclamacion', 1, 1, 'claim');
|
||||||
|
|
||||||
INSERT INTO `vn`.`dms`(`id`, `dmsTypeFk`, `file`, `contentType`, `workerFk`, `warehouseFk`, `companyFk`, `hardCopyNumber`, `hasFile`, `reference`, `description`, `created`)
|
INSERT INTO `vn`.`dms`(`id`, `dmsTypeFk`, `file`, `contentType`, `workerFk`, `warehouseFk`, `companyFk`, `hardCopyNumber`, `hasFile`, `reference`, `description`, `created`)
|
||||||
VALUES
|
VALUES
|
||||||
|
|
|
@ -422,7 +422,7 @@ export default {
|
||||||
thirdSaleCheckbox: 'vn-ticket-sale vn-tr:nth-child(3) vn-check[field="sale.checked"] md-checkbox',
|
thirdSaleCheckbox: 'vn-ticket-sale vn-tr:nth-child(3) vn-check[field="sale.checked"] md-checkbox',
|
||||||
deleteSaleButton: 'vn-ticket-sale vn-tool-bar > vn-button[icon="delete"]',
|
deleteSaleButton: 'vn-ticket-sale vn-tool-bar > vn-button[icon="delete"]',
|
||||||
transferSaleButton: 'vn-ticket-sale vn-tool-bar > vn-button[icon="call_split"]',
|
transferSaleButton: 'vn-ticket-sale vn-tool-bar > vn-button[icon="call_split"]',
|
||||||
moveToTicketInput: 'vn-ticket-sale vn-popover.transfer vn-textfield[model="$ctrl.receiverTicketId"] input',
|
moveToTicketInput: 'vn-ticket-sale vn-popover.transfer vn-textfield[model="$ctrl.transfer.ticketId"] input',
|
||||||
moveToTicketInputClearButton: 'vn-popover.shown i[title="Clear"]',
|
moveToTicketInputClearButton: 'vn-popover.shown i[title="Clear"]',
|
||||||
moveToTicketButton: 'vn-ticket-sale vn-popover.transfer vn-icon[icon="arrow_forward_ios"]',
|
moveToTicketButton: 'vn-ticket-sale vn-popover.transfer vn-icon[icon="arrow_forward_ios"]',
|
||||||
moveToNewTicketButton: 'vn-ticket-sale vn-popover.transfer vn-button[label="New ticket"]',
|
moveToNewTicketButton: 'vn-ticket-sale vn-popover.transfer vn-button[label="New ticket"]',
|
||||||
|
|
|
@ -1,35 +1,39 @@
|
||||||
module.exports = Self => {
|
module.exports = Self => {
|
||||||
Self.remoteMethod('threeLastActive', {
|
Self.remoteMethod('lastActiveTickets', {
|
||||||
description: 'Returns the last three tickets of a client that have the alertLevel at 0 and the shiped day is gt today',
|
description: 'Returns the last three tickets of a client that have the alertLevel at 0 and the shiped day is gt today',
|
||||||
accessType: 'READ',
|
accessType: 'READ',
|
||||||
accepts: [{
|
accepts: [{
|
||||||
arg: 'filter',
|
arg: 'id',
|
||||||
type: 'object',
|
type: 'Number',
|
||||||
required: true,
|
required: true,
|
||||||
description: 'client id, ticketFk'
|
description: 'Client id',
|
||||||
|
http: {source: 'path'}
|
||||||
|
}, {
|
||||||
|
arg: 'ticketId',
|
||||||
|
type: 'Number',
|
||||||
|
required: true
|
||||||
}],
|
}],
|
||||||
returns: {
|
returns: {
|
||||||
type: [this.modelName],
|
type: ['Object'],
|
||||||
root: true
|
root: true
|
||||||
},
|
},
|
||||||
http: {
|
http: {
|
||||||
path: `/threeLastActive`,
|
path: `/:id/lastActiveTickets`,
|
||||||
verb: 'GET'
|
verb: 'GET'
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Self.threeLastActive = async params => {
|
Self.lastActiveTickets = async(id, ticketId) => {
|
||||||
let query = `
|
const query = `
|
||||||
SELECT t.id, t.shipped, a.name AS agencyName, w.name AS warehouseName
|
SELECT t.id, t.shipped, a.name AS agencyName, w.name AS warehouseName
|
||||||
FROM vn.ticket t
|
FROM vn.ticket t
|
||||||
JOIN vn.ticketState ts ON t.id = ts.ticketFk
|
JOIN vn.ticketState ts ON t.id = ts.ticketFk
|
||||||
JOIN vn.agencyMode a ON t.agencyModeFk = a.id
|
JOIN vn.agencyMode a ON t.agencyModeFk = a.id
|
||||||
JOIN vn.warehouse w ON t.warehouseFk = w.id
|
JOIN vn.warehouse w ON t.warehouseFk = w.id
|
||||||
WHERE t.shipped >= CURDATE() AND t.clientFk = ?
|
WHERE t.shipped >= CURDATE() AND t.clientFk = ? AND ts.alertLevel = 0 AND t.id <> ?
|
||||||
AND ts.alertLevel = 0 AND t.id <> ?
|
|
||||||
ORDER BY t.shipped
|
ORDER BY t.shipped
|
||||||
LIMIT 5`;
|
LIMIT 3`;
|
||||||
let tickets = await Self.rawSql(query, [params.clientFk, params.ticketFk]);
|
|
||||||
return tickets;
|
return Self.rawSql(query, [id, ticketId]);
|
||||||
};
|
};
|
||||||
};
|
};
|
|
@ -0,0 +1,12 @@
|
||||||
|
const app = require('vn-loopback/server/server');
|
||||||
|
|
||||||
|
describe('client lastActiveTickets()', () => {
|
||||||
|
it('should return the last three active tickets', async() => {
|
||||||
|
const clientId = 109;
|
||||||
|
const ticketId = 19;
|
||||||
|
|
||||||
|
let result = await app.models.Client.lastActiveTickets(clientId, ticketId);
|
||||||
|
|
||||||
|
expect(result.length).toEqual(3);
|
||||||
|
});
|
||||||
|
});
|
|
@ -21,6 +21,7 @@ module.exports = Self => {
|
||||||
require('../methods/client/confirmTransaction')(Self);
|
require('../methods/client/confirmTransaction')(Self);
|
||||||
require('../methods/client/canBeInvoiced')(Self);
|
require('../methods/client/canBeInvoiced')(Self);
|
||||||
require('../methods/client/uploadFile')(Self);
|
require('../methods/client/uploadFile')(Self);
|
||||||
|
require('../methods/client/lastActiveTickets')(Self);
|
||||||
|
|
||||||
// Validations
|
// Validations
|
||||||
|
|
||||||
|
|
|
@ -1,90 +0,0 @@
|
||||||
let UserError = require('vn-loopback/util/user-error');
|
|
||||||
|
|
||||||
module.exports = Self => {
|
|
||||||
Self.remoteMethodCtx('moveToTicket', {
|
|
||||||
description: 'Moves lines to a new or a given ticket',
|
|
||||||
accepts: [{
|
|
||||||
arg: 'params',
|
|
||||||
type: 'object',
|
|
||||||
required: true,
|
|
||||||
description: 'currentTicket, receiverTicket, [sales IDs], removeEmptyTicket',
|
|
||||||
http: {source: 'body'}
|
|
||||||
}],
|
|
||||||
returns: {
|
|
||||||
type: 'string',
|
|
||||||
root: true
|
|
||||||
},
|
|
||||||
http: {
|
|
||||||
path: `/moveToTicket`,
|
|
||||||
verb: 'post'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Self.moveToTicket = async(ctx, params) => {
|
|
||||||
const models = Self.app.models;
|
|
||||||
const userId = ctx.req.accessToken.userId;
|
|
||||||
let currentTicket = await models.Ticket.findById(params.currentTicket.currentTicketId);
|
|
||||||
let newTicketData = {};
|
|
||||||
let receiverTicket = params.receiverTicket;
|
|
||||||
|
|
||||||
let isCurrentTicketEditable = await models.Ticket.isEditable(ctx, params.currentTicket.currentTicketId);
|
|
||||||
if (!isCurrentTicketEditable)
|
|
||||||
throw new UserError(`The sales of the current ticket can't be modified`);
|
|
||||||
|
|
||||||
if (params.receiverTicket.id) {
|
|
||||||
let isReceiverTicketEditable = await models.Ticket.isEditable(ctx, params.receiverTicket.id);
|
|
||||||
if (!isReceiverTicketEditable)
|
|
||||||
throw new UserError(`The sales of the receiver ticket can't be modified`);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!params.receiverTicket.id) {
|
|
||||||
let travelDates = await models.Agency.getFirstShipped(params.currentTicket);
|
|
||||||
|
|
||||||
if (!travelDates)
|
|
||||||
throw new UserError(`Invalid parameters to create a new ticket`);
|
|
||||||
let shipped = new Date(travelDates.shipped);
|
|
||||||
let landed = new Date(travelDates.landed);
|
|
||||||
|
|
||||||
newTicketData = {
|
|
||||||
clientFk: params.currentTicket.clientFk,
|
|
||||||
addressFk: params.currentTicket.addressFk,
|
|
||||||
agencyModeFk: params.currentTicket.agencyModeFk,
|
|
||||||
warehouseFk: params.currentTicket.warehouseFk,
|
|
||||||
shipped: shipped,
|
|
||||||
landed: landed,
|
|
||||||
userId: userId
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
let tx = await Self.beginTransaction({});
|
|
||||||
|
|
||||||
try {
|
|
||||||
let options = {transaction: tx};
|
|
||||||
|
|
||||||
if (!params.receiverTicket.id)
|
|
||||||
receiverTicket = await models.Ticket.new(ctx, newTicketData, options);
|
|
||||||
|
|
||||||
let promises = [];
|
|
||||||
for (let sale of params.sales) {
|
|
||||||
promises.push(
|
|
||||||
models.Sale.update(
|
|
||||||
{id: sale.id},
|
|
||||||
{ticketFk: receiverTicket.id},
|
|
||||||
options
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (params.removeEmptyTicket)
|
|
||||||
promises.push(currentTicket.updateAttributes({isDeleted: true}, options));
|
|
||||||
|
|
||||||
await Promise.all(promises);
|
|
||||||
await tx.commit();
|
|
||||||
|
|
||||||
return receiverTicket;
|
|
||||||
} catch (error) {
|
|
||||||
await tx.rollback();
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
|
@ -1,37 +0,0 @@
|
||||||
module.exports = function(Self) {
|
|
||||||
Self.remoteMethod('checkEmptiness', {
|
|
||||||
description: 'Checks if the ticket has no packages, componenets and purchase requests',
|
|
||||||
accessType: 'READ',
|
|
||||||
accepts: [
|
|
||||||
{
|
|
||||||
arg: 'id',
|
|
||||||
type: 'number',
|
|
||||||
required: true,
|
|
||||||
description: 'Ticket id',
|
|
||||||
http: {source: 'path'}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
returns: {
|
|
||||||
arg: 'data',
|
|
||||||
type: 'boolean',
|
|
||||||
root: true
|
|
||||||
},
|
|
||||||
http: {
|
|
||||||
path: `/:id/checkEmptiness`,
|
|
||||||
verb: 'get'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Self.checkEmptiness = async id => {
|
|
||||||
const packages = await Self.app.models.TicketPackaging.find({where: {ticketFk: id}});
|
|
||||||
const services = await Self.app.models.TicketService.find({where: {ticketFk: id}});
|
|
||||||
const purchaseRequests = await Self.app.models.TicketRequest.find({where: {ticketFk: id}});
|
|
||||||
|
|
||||||
emptyTicket = !packages.length && !services.length && !purchaseRequests.length;
|
|
||||||
|
|
||||||
if (emptyTicket)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
};
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
module.exports = function(Self) {
|
||||||
|
Self.remoteMethod('isEmpty', {
|
||||||
|
description: 'Checks if the ticket has no packages, componenets and purchase requests',
|
||||||
|
accessType: 'READ',
|
||||||
|
accepts: [
|
||||||
|
{
|
||||||
|
arg: 'id',
|
||||||
|
type: 'number',
|
||||||
|
required: true,
|
||||||
|
description: 'Ticket id',
|
||||||
|
http: {source: 'path'}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
returns: {
|
||||||
|
type: 'Boolean',
|
||||||
|
root: true
|
||||||
|
},
|
||||||
|
http: {
|
||||||
|
path: `/:id/isEmpty`,
|
||||||
|
verb: 'GET'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Self.isEmpty = async(id, options) => {
|
||||||
|
const models = Self.app.models;
|
||||||
|
|
||||||
|
if ((typeof options) != 'object')
|
||||||
|
options = {};
|
||||||
|
|
||||||
|
const hasSales = await models.Sale.count({
|
||||||
|
ticketFk: id
|
||||||
|
}, options);
|
||||||
|
|
||||||
|
const hasPackages = await models.TicketPackaging.count({
|
||||||
|
ticketFk: id
|
||||||
|
}, options);
|
||||||
|
|
||||||
|
const hasServices = await models.TicketService.count({
|
||||||
|
ticketFk: id
|
||||||
|
}, options);
|
||||||
|
|
||||||
|
const hasPurchaseRequests = await models.TicketRequest.count({
|
||||||
|
ticketFk: id
|
||||||
|
}, options);
|
||||||
|
|
||||||
|
const isEmpty = !hasSales && !hasPackages &&
|
||||||
|
!hasServices && !hasPurchaseRequests;
|
||||||
|
|
||||||
|
return isEmpty;
|
||||||
|
};
|
||||||
|
};
|
|
@ -1,27 +0,0 @@
|
||||||
const app = require('vn-loopback/server/server');
|
|
||||||
|
|
||||||
describe('ticket checkEmptiness()', () => {
|
|
||||||
it('should return false if the ticket contains any packages', async() => {
|
|
||||||
let result = await app.models.Ticket.checkEmptiness(3);
|
|
||||||
|
|
||||||
expect(result).toBeFalsy();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return false if the ticket contains any services', async() => {
|
|
||||||
let result = await app.models.Ticket.checkEmptiness(8);
|
|
||||||
|
|
||||||
expect(result).toBeFalsy();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return false if the ticket contains any purchase request', async() => {
|
|
||||||
let result = await app.models.Ticket.checkEmptiness(11);
|
|
||||||
|
|
||||||
expect(result).toBeFalsy();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return true if the ticket does not contain any packages, services or purchase request', async() => {
|
|
||||||
let result = await app.models.Ticket.checkEmptiness(4);
|
|
||||||
|
|
||||||
expect(result).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
const app = require('vn-loopback/server/server');
|
||||||
|
|
||||||
|
describe('ticket isEmpty()', () => {
|
||||||
|
it('should return false if the ticket contains any packages', async() => {
|
||||||
|
let result = await app.models.Ticket.isEmpty(3);
|
||||||
|
|
||||||
|
expect(result).toBeFalsy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return false if the ticket contains any services', async() => {
|
||||||
|
let result = await app.models.Ticket.isEmpty(8);
|
||||||
|
|
||||||
|
expect(result).toBeFalsy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return false if the ticket contains any purchase request', async() => {
|
||||||
|
let result = await app.models.Ticket.isEmpty(11);
|
||||||
|
|
||||||
|
expect(result).toBeFalsy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return false if the ticket contains any sale', async() => {
|
||||||
|
let result = await app.models.Ticket.isEmpty(4);
|
||||||
|
|
||||||
|
expect(result).toBeFalsy();
|
||||||
|
});
|
||||||
|
});
|
|
@ -1,10 +0,0 @@
|
||||||
const app = require('vn-loopback/server/server');
|
|
||||||
|
|
||||||
describe('ticket threeLastActive()', () => {
|
|
||||||
it('should return the last three active tickets', async() => {
|
|
||||||
let params = {clientFk: 109, ticketFk: 19};
|
|
||||||
let result = await app.models.Ticket.threeLastActive(params);
|
|
||||||
|
|
||||||
expect(result.length).toEqual(3);
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,6 +1,6 @@
|
||||||
const app = require('vn-loopback/server/server');
|
const app = require('vn-loopback/server/server');
|
||||||
|
|
||||||
describe('sale moveToTicket()', () => {
|
describe('sale transferSales()', () => {
|
||||||
let createdTicketId;
|
let createdTicketId;
|
||||||
|
|
||||||
afterAll(async done => {
|
afterAll(async done => {
|
||||||
|
@ -12,11 +12,13 @@ describe('sale moveToTicket()', () => {
|
||||||
const ctx = {req: {accessToken: {userId: 101}}};
|
const ctx = {req: {accessToken: {userId: 101}}};
|
||||||
let error;
|
let error;
|
||||||
|
|
||||||
const params = {currentTicket: {currentTicketId: 10}};
|
const currentTicketId = 10;
|
||||||
|
const receiverTicketId = undefined;
|
||||||
|
const sales = [];
|
||||||
|
|
||||||
await app.models.Sale.moveToTicket(ctx, params)
|
await app.models.Ticket.transferSales(ctx, currentTicketId, receiverTicketId, sales)
|
||||||
.catch(response => {
|
.catch(response => {
|
||||||
expect(response.message).toEqual(`The sales of the current ticket can't be modified`);
|
expect(response.message).toEqual(`The sales of this ticket can't be modified`);
|
||||||
error = response;
|
error = response;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -27,9 +29,11 @@ describe('sale moveToTicket()', () => {
|
||||||
const ctx = {req: {accessToken: {userId: 101}}};
|
const ctx = {req: {accessToken: {userId: 101}}};
|
||||||
let error;
|
let error;
|
||||||
|
|
||||||
const params = {currentTicket: {currentTicketId: 16}, receiverTicket: {id: 1}};
|
const currentTicketId = 16;
|
||||||
|
const receiverTicketId = 1;
|
||||||
|
const sales = [];
|
||||||
|
|
||||||
await app.models.Sale.moveToTicket(ctx, params)
|
await app.models.Ticket.transferSales(ctx, currentTicketId, receiverTicketId, sales)
|
||||||
.catch(response => {
|
.catch(response => {
|
||||||
expect(response.message).toEqual(`The sales of the receiver ticket can't be modified`);
|
expect(response.message).toEqual(`The sales of the receiver ticket can't be modified`);
|
||||||
error = response;
|
error = response;
|
||||||
|
@ -42,9 +46,11 @@ describe('sale moveToTicket()', () => {
|
||||||
const ctx = {req: {accessToken: {userId: 101}}};
|
const ctx = {req: {accessToken: {userId: 101}}};
|
||||||
let error;
|
let error;
|
||||||
|
|
||||||
const params = {currentTicket: {currentTicketId: 18}, receiverTicket: {id: undefined}};
|
const currentTicketId = 18;
|
||||||
|
const receiverTicketId = undefined;
|
||||||
|
const sales = [];
|
||||||
|
|
||||||
await app.models.Sale.moveToTicket(ctx, params)
|
await app.models.Ticket.transferSales(ctx, currentTicketId, receiverTicketId, sales)
|
||||||
.catch(response => {
|
.catch(response => {
|
||||||
expect(response.message).toEqual(`Invalid parameters to create a new ticket`);
|
expect(response.message).toEqual(`Invalid parameters to create a new ticket`);
|
||||||
error = response;
|
error = response;
|
||||||
|
@ -56,26 +62,19 @@ describe('sale moveToTicket()', () => {
|
||||||
it('should transfer the sales from one ticket to a new one', async() => {
|
it('should transfer the sales from one ticket to a new one', async() => {
|
||||||
const ctx = {req: {accessToken: {userId: 101}}};
|
const ctx = {req: {accessToken: {userId: 101}}};
|
||||||
let currentTicket = await app.models.Ticket.findById(11);
|
let currentTicket = await app.models.Ticket.findById(11);
|
||||||
currentTicket.currentTicketId = currentTicket.id;
|
let currentTicketSales = await app.models.Ticket.getSales(currentTicket.id);
|
||||||
currentTicket.id = undefined;
|
|
||||||
|
|
||||||
let currentTicketSales = await app.models.Ticket.getSales(currentTicket.currentTicketId);
|
|
||||||
|
|
||||||
expect(currentTicketSales.length).toEqual(2);
|
expect(currentTicketSales.length).toEqual(2);
|
||||||
|
|
||||||
let params = {
|
const currentTicketId = currentTicket.id;
|
||||||
currentTicket: currentTicket,
|
const receiverTicketId = undefined;
|
||||||
receiverTicket: {id: undefined},
|
const sales = currentTicketSales;
|
||||||
sales: [
|
|
||||||
{id: currentTicketSales[0].id},
|
|
||||||
{id: currentTicketSales[1].id}
|
|
||||||
]
|
|
||||||
};
|
|
||||||
|
|
||||||
let createdTicket = await app.models.Sale.moveToTicket(ctx, params);
|
let createdTicket = await app.models.Ticket.transferSales(
|
||||||
|
ctx, currentTicketId, receiverTicketId, sales);
|
||||||
createdTicketId = createdTicket.id;
|
createdTicketId = createdTicket.id;
|
||||||
|
|
||||||
currentTicketSales = await app.models.Ticket.getSales(currentTicket.currentTicketId);
|
currentTicketSales = await app.models.Ticket.getSales(currentTicket.id);
|
||||||
receiverTicketSales = await app.models.Ticket.getSales(createdTicket.id);
|
receiverTicketSales = await app.models.Ticket.getSales(createdTicket.id);
|
||||||
|
|
||||||
expect(currentTicketSales.length).toEqual(0);
|
expect(currentTicketSales.length).toEqual(0);
|
||||||
|
@ -84,33 +83,24 @@ describe('sale moveToTicket()', () => {
|
||||||
|
|
||||||
it('should transfer back the sales and set the created ticket as deleted', async() => {
|
it('should transfer back the sales and set the created ticket as deleted', async() => {
|
||||||
const ctx = {req: {accessToken: {userId: 101}}};
|
const ctx = {req: {accessToken: {userId: 101}}};
|
||||||
let receiverTicketId = 11;
|
const currentTicket = await app.models.Ticket.findById(createdTicketId);
|
||||||
let currentTicket = await app.models.Ticket.findById(createdTicketId);
|
const receiverTicketId = 11;
|
||||||
currentTicket.currentTicketId = createdTicketId;
|
|
||||||
currentTicket.id = undefined;
|
|
||||||
|
|
||||||
let createdTicket = await app.models.Ticket.findById(createdTicketId);
|
let createdTicket = await app.models.Ticket.findById(createdTicketId);
|
||||||
let createdTicketSales = await app.models.Ticket.getSales(createdTicketId);
|
let createdTicketSales = await app.models.Ticket.getSales(createdTicketId);
|
||||||
let receiverTicketSales = await app.models.Ticket.getSales(receiverTicketId);
|
let receiverTicketSales = await app.models.Ticket.getSales(receiverTicketId);
|
||||||
|
|
||||||
|
const currentTicketId = currentTicket.id;
|
||||||
|
const sales = createdTicketSales;
|
||||||
|
|
||||||
expect(createdTicket.isDeleted).toBeFalsy();
|
expect(createdTicket.isDeleted).toBeFalsy();
|
||||||
expect(createdTicketSales.length).toEqual(2);
|
expect(createdTicketSales.length).toEqual(2);
|
||||||
expect(receiverTicketSales.length).toEqual(0);
|
expect(receiverTicketSales.length).toEqual(0);
|
||||||
|
|
||||||
let params = {
|
await app.models.Ticket.transferSales(
|
||||||
removeEmptyTicket: true,
|
ctx, currentTicketId, receiverTicketId, sales);
|
||||||
currentTicket: currentTicket,
|
|
||||||
receiverTicket: {id: receiverTicketId},
|
|
||||||
sales: [
|
|
||||||
{id: createdTicketSales[0].id},
|
|
||||||
{id: createdTicketSales[1].id}
|
|
||||||
]
|
|
||||||
};
|
|
||||||
|
|
||||||
await app.models.Sale.moveToTicket(ctx, params);
|
|
||||||
|
|
||||||
createdTicket = await app.models.Ticket.findById(createdTicketId);
|
createdTicket = await app.models.Ticket.findById(createdTicketId);
|
||||||
|
|
||||||
createdTicketSales = await app.models.Ticket.getSales(createdTicketId);
|
createdTicketSales = await app.models.Ticket.getSales(createdTicketId);
|
||||||
receiverTicketSales = await app.models.Ticket.getSales(receiverTicketId);
|
receiverTicketSales = await app.models.Ticket.getSales(receiverTicketId);
|
||||||
|
|
|
@ -0,0 +1,158 @@
|
||||||
|
let UserError = require('vn-loopback/util/user-error');
|
||||||
|
|
||||||
|
module.exports = Self => {
|
||||||
|
Self.remoteMethodCtx('transferSales', {
|
||||||
|
description: 'Transfer sales to a new or a given ticket',
|
||||||
|
accepts: [{
|
||||||
|
arg: 'id',
|
||||||
|
type: 'Number',
|
||||||
|
required: true,
|
||||||
|
description: 'Origin ticket id',
|
||||||
|
http: {source: 'path'}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
arg: 'ticketId',
|
||||||
|
type: 'Number',
|
||||||
|
description: 'Destination ticket id',
|
||||||
|
required: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
arg: 'sales',
|
||||||
|
type: ['Object'],
|
||||||
|
description: 'The sales to transfer',
|
||||||
|
required: true
|
||||||
|
}],
|
||||||
|
returns: {
|
||||||
|
type: 'Object',
|
||||||
|
root: true
|
||||||
|
},
|
||||||
|
http: {
|
||||||
|
path: `/:id/transferSales`,
|
||||||
|
verb: 'POST'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Self.transferSales = async(ctx, id, ticketId, sales) => {
|
||||||
|
const models = Self.app.models;
|
||||||
|
|
||||||
|
const isEditable = await models.Ticket.isEditable(ctx, id);
|
||||||
|
if (!isEditable)
|
||||||
|
throw new UserError(`The sales of this ticket can't be modified`);
|
||||||
|
|
||||||
|
if (ticketId) {
|
||||||
|
const isReceiverEditable = await models.Ticket.isEditable(ctx, ticketId);
|
||||||
|
if (!isReceiverEditable)
|
||||||
|
throw new UserError(`The sales of the receiver ticket can't be modified`);
|
||||||
|
}
|
||||||
|
|
||||||
|
let tx = await Self.beginTransaction({});
|
||||||
|
|
||||||
|
try {
|
||||||
|
const options = {transaction: tx};
|
||||||
|
const originalTicket = await models.Ticket.findById(id, null, options);
|
||||||
|
const originalSales = await models.Sale.find({
|
||||||
|
where: {ticketFk: id}
|
||||||
|
}, options);
|
||||||
|
|
||||||
|
if (!ticketId)
|
||||||
|
ticketId = await cloneTicket(ctx, originalTicket, options);
|
||||||
|
|
||||||
|
const map = new Map();
|
||||||
|
for (const sale of originalSales)
|
||||||
|
map.set(sale.id, sale);
|
||||||
|
|
||||||
|
const promises = [];
|
||||||
|
for (const sale of sales) {
|
||||||
|
const originalSale = map.get(sale.id);
|
||||||
|
|
||||||
|
if (sale.quantity == originalSale.quantity) {
|
||||||
|
const updatedSale = models.Sale.updateAll({
|
||||||
|
id: sale.id
|
||||||
|
}, {ticketFk: ticketId}, options);
|
||||||
|
|
||||||
|
promises.push(updatedSale);
|
||||||
|
} else if (sale.quantity < originalSale.quantity) {
|
||||||
|
const transferedSale = await transferPartialSale(
|
||||||
|
ticketId, originalSale, sale, options);
|
||||||
|
|
||||||
|
promises.push(transferedSale);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const isTicketEmpty = await models.Ticket.isEmpty(id, options);
|
||||||
|
if (isTicketEmpty) {
|
||||||
|
originalTicket.updateAttributes({
|
||||||
|
isDeleted: true
|
||||||
|
}, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
await Promise.all(promises);
|
||||||
|
await tx.commit();
|
||||||
|
|
||||||
|
return {id: ticketId};
|
||||||
|
} catch (error) {
|
||||||
|
await tx.rollback();
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
async function cloneTicket(ctx, ticket, options) {
|
||||||
|
const models = Self.app.models;
|
||||||
|
const userId = ctx.req.accessToken.userId;
|
||||||
|
|
||||||
|
const travelDates = await models.Agency.getFirstShipped({
|
||||||
|
agencyModeFk: ticket.agencyModeFk,
|
||||||
|
addressFk: ticket.addressFk,
|
||||||
|
warehouseFk: ticket.warehouseFk
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!travelDates)
|
||||||
|
throw new UserError(`Invalid parameters to create a new ticket`);
|
||||||
|
|
||||||
|
let shipped = new Date(travelDates.shipped);
|
||||||
|
let landed = new Date(travelDates.landed);
|
||||||
|
|
||||||
|
const newTicket = await models.Ticket.new(ctx, {
|
||||||
|
clientFk: ticket.clientFk,
|
||||||
|
addressFk: ticket.addressFk,
|
||||||
|
agencyModeFk: ticket.agencyModeFk,
|
||||||
|
warehouseFk: ticket.warehouseFk,
|
||||||
|
shipped: shipped,
|
||||||
|
landed: landed,
|
||||||
|
userId: userId
|
||||||
|
}, options);
|
||||||
|
|
||||||
|
return newTicket.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function transferPartialSale(ticketId, originalSale, sale, options) {
|
||||||
|
const models = Self.app.models;
|
||||||
|
// Update original sale
|
||||||
|
const rest = originalSale.quantity - sale.quantity;
|
||||||
|
const updatedSale = models.Sale.updateAll({
|
||||||
|
id: sale.id
|
||||||
|
}, {quantity: rest}, options);
|
||||||
|
|
||||||
|
// Clone sale with new quantity
|
||||||
|
const newSale = originalSale;
|
||||||
|
newSale.id = undefined;
|
||||||
|
newSale.ticketFk = ticketId;
|
||||||
|
newSale.quantity = sale.quantity;
|
||||||
|
|
||||||
|
const createdSale = await models.Sale.create(newSale, options);
|
||||||
|
|
||||||
|
// Clone sale components
|
||||||
|
const saleComponents = await models.SaleComponent.find({
|
||||||
|
where: {saleFk: sale.id}
|
||||||
|
}, options);
|
||||||
|
const newComponents = saleComponents.map(component => {
|
||||||
|
component.saleFk = createdSale.id;
|
||||||
|
|
||||||
|
return component;
|
||||||
|
});
|
||||||
|
const createdComponents = models.SaleComponent
|
||||||
|
.create(newComponents, options);
|
||||||
|
|
||||||
|
return [updatedSale, createdComponents];
|
||||||
|
}
|
||||||
|
};
|
|
@ -1,6 +1,5 @@
|
||||||
module.exports = Self => {
|
module.exports = Self => {
|
||||||
require('../methods/sale/getClaimableFromTicket')(Self);
|
require('../methods/sale/getClaimableFromTicket')(Self);
|
||||||
require('../methods/sale/moveToTicket')(Self);
|
|
||||||
require('../methods/sale/reserve')(Self);
|
require('../methods/sale/reserve')(Self);
|
||||||
require('../methods/sale/removes')(Self);
|
require('../methods/sale/removes')(Self);
|
||||||
require('../methods/sale/updatePrice')(Self);
|
require('../methods/sale/updatePrice')(Self);
|
||||||
|
|
|
@ -11,7 +11,6 @@ module.exports = Self => {
|
||||||
require('../methods/ticket/componentUpdate')(Self);
|
require('../methods/ticket/componentUpdate')(Self);
|
||||||
require('../methods/ticket/new')(Self);
|
require('../methods/ticket/new')(Self);
|
||||||
require('../methods/ticket/isEditable')(Self);
|
require('../methods/ticket/isEditable')(Self);
|
||||||
require('../methods/ticket/threeLastActive')(Self);
|
|
||||||
require('../methods/ticket/delete')(Self);
|
require('../methods/ticket/delete')(Self);
|
||||||
require('../methods/ticket/getVAT')(Self);
|
require('../methods/ticket/getVAT')(Self);
|
||||||
require('../methods/ticket/getSales')(Self);
|
require('../methods/ticket/getSales')(Self);
|
||||||
|
@ -21,10 +20,11 @@ module.exports = Self => {
|
||||||
require('../methods/ticket/canBeInvoiced')(Self);
|
require('../methods/ticket/canBeInvoiced')(Self);
|
||||||
require('../methods/ticket/makeInvoice')(Self);
|
require('../methods/ticket/makeInvoice')(Self);
|
||||||
require('../methods/ticket/updateEditableTicket')(Self);
|
require('../methods/ticket/updateEditableTicket')(Self);
|
||||||
require('../methods/ticket/checkEmptiness')(Self);
|
require('../methods/ticket/isEmpty')(Self);
|
||||||
require('../methods/ticket/updateDiscount')(Self);
|
require('../methods/ticket/updateDiscount')(Self);
|
||||||
require('../methods/ticket/uploadFile')(Self);
|
require('../methods/ticket/uploadFile')(Self);
|
||||||
require('../methods/ticket/addSale')(Self);
|
require('../methods/ticket/addSale')(Self);
|
||||||
|
require('../methods/ticket/transferSales')(Self);
|
||||||
|
|
||||||
Self.observe('before save', async function(ctx) {
|
Self.observe('before save', async function(ctx) {
|
||||||
if (ctx.isNewInstance) return;
|
if (ctx.isNewInstance) return;
|
||||||
|
|
|
@ -115,7 +115,11 @@
|
||||||
field="sale.itemFk"
|
field="sale.itemFk"
|
||||||
show-field="name"
|
show-field="name"
|
||||||
value-field="id"
|
value-field="id"
|
||||||
search-function="{or: [{id: $search}, {name: {like: '%' + $search + '%'}}]}">
|
search-function="{or: [{id: $search}, {name: {like: '%' + $search + '%'}}]}"
|
||||||
|
order="id DESC">
|
||||||
|
<tpl-item>
|
||||||
|
{{id}} - {{name}}
|
||||||
|
</tpl-item>
|
||||||
</vn-autocomplete>
|
</vn-autocomplete>
|
||||||
</field>
|
</field>
|
||||||
</vn-td-editable>
|
</vn-td-editable>
|
||||||
|
@ -258,51 +262,87 @@
|
||||||
<!-- Transfer Popover -->
|
<!-- Transfer Popover -->
|
||||||
<vn-popover class="transfer" vn-id="transfer">
|
<vn-popover class="transfer" vn-id="transfer">
|
||||||
<div pad-medium>
|
<div pad-medium>
|
||||||
<table class="vn-grid">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th number translate>ID</th>
|
|
||||||
<th number translate>F. envio</th>
|
|
||||||
<th number translate>Agencia</th>
|
|
||||||
<th number translate>Almacen</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr ng-if="$ctrl.lastThreeTickets.length === 0" >
|
|
||||||
<td colspan="4" style="text-align: center" translate>No results</td>
|
|
||||||
</tr>
|
|
||||||
<tr
|
|
||||||
class="clickable"
|
|
||||||
ng-repeat="ticket in $ctrl.lastThreeTickets track by ticket.id"
|
|
||||||
ng-click="$ctrl.checkEmptiness(ticket.id)">
|
|
||||||
<td number>{{::ticket.id}}</td>
|
|
||||||
<td number>{{::ticket.shipped | dateTime: 'dd/MM/yyyy HH:mm'}}</td>
|
|
||||||
<td number>{{::ticket.agencyName}}</td>
|
|
||||||
<td number>{{::ticket.warehouseName}}</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<vn-horizontal>
|
<vn-horizontal>
|
||||||
<vn-textfield
|
<vn-one>
|
||||||
label="Move to ticket"
|
<h4 translate>Sales to transfer</h4>
|
||||||
model="$ctrl.receiverTicketId"
|
<vn-table>
|
||||||
type="number">
|
<vn-thead>
|
||||||
</vn-textfield>
|
<vn-tr>
|
||||||
<vn-icon-button
|
<vn-th number shrink>Id</vn-th>
|
||||||
icon="arrow_forward_ios"
|
<vn-th shrink>Item</vn-th>
|
||||||
ng-click="$ctrl.checkEmptiness($ctrl.receiverTicketId)">
|
<vn-th number shrink>Quantity</vn-th>
|
||||||
</vn-icon-button>
|
</vn-tr>
|
||||||
</vn-horizontal>
|
</vn-thead>
|
||||||
<vn-horizontal>
|
<vn-tbody>
|
||||||
<vn-button
|
<vn-tr ng-repeat="sale in $ctrl.transfer.sales">
|
||||||
label="New ticket"
|
<vn-td number shrink>{{::sale.itemFk | zeroFill:6}}</vn-td>
|
||||||
ng-click="$ctrl.checkEmptiness()">
|
<vn-td shrink>
|
||||||
</vn-button>
|
<span title="{{::sale.concept}}">{{::sale.concept}}</span>
|
||||||
<vn-icon
|
</vn-td>
|
||||||
color-secondary
|
<vn-td-editable number>
|
||||||
vn-tooltip="You have to allow pop-ups in your web browser to use this functionality"
|
<text>{{sale.quantity}}</text>
|
||||||
icon="info">
|
<field>
|
||||||
</vn-icon>
|
<vn-input-number vn-focus
|
||||||
|
model="sale.quantity">
|
||||||
|
</vn-input-number>
|
||||||
|
</field>
|
||||||
|
</vn-td-editable>
|
||||||
|
</vn-tr>
|
||||||
|
</vn-tbody>
|
||||||
|
</vn-table>
|
||||||
|
</vn-one>
|
||||||
|
<vn-one>
|
||||||
|
<vn-horizontal>
|
||||||
|
<h4 vn-one translate>Destination ticket</h4>
|
||||||
|
<vn-icon vn-none
|
||||||
|
color-secondary
|
||||||
|
vn-tooltip="You have to allow pop-ups in your web browser to use this functionality"
|
||||||
|
icon="info">
|
||||||
|
</vn-icon>
|
||||||
|
</vn-horizontal>
|
||||||
|
<table class="vn-grid">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th number>ID</th>
|
||||||
|
<th number>F. envio</th>
|
||||||
|
<th number>Agencia</th>
|
||||||
|
<th number>Almacen</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr ng-if="$ctrl.transfer.lastActiveTickets.length === 0" >
|
||||||
|
<td colspan="4" style="text-align: center" translate>No results</td>
|
||||||
|
</tr>
|
||||||
|
<tr
|
||||||
|
class="clickable"
|
||||||
|
ng-repeat="ticket in $ctrl.transfer.lastActiveTickets track by ticket.id"
|
||||||
|
ng-click="$ctrl.transferSales(ticket.id)">
|
||||||
|
<td number>{{::ticket.id}}</td>
|
||||||
|
<td number>{{::ticket.shipped | dateTime: 'dd/MM/yyyy'}}</td>
|
||||||
|
<td number>{{::ticket.agencyName}}</td>
|
||||||
|
<td number>{{::ticket.warehouseName}}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<vn-horizontal pad-medium-v>
|
||||||
|
<vn-textfield vn-one
|
||||||
|
label="Transfer to ticket"
|
||||||
|
model="$ctrl.transfer.ticketId"
|
||||||
|
type="number">
|
||||||
|
</vn-textfield>
|
||||||
|
<vn-icon-button vn-none
|
||||||
|
icon="arrow_forward_ios"
|
||||||
|
ng-click="$ctrl.transferSales($ctrl.transfer.ticketId)">
|
||||||
|
</vn-icon-button>
|
||||||
|
</vn-horizontal>
|
||||||
|
<vn-horizontal pad-medium-v>
|
||||||
|
<vn-button
|
||||||
|
label="New ticket"
|
||||||
|
ng-click="$ctrl.transferSales()">
|
||||||
|
</vn-button>
|
||||||
|
</vn-horizontal>
|
||||||
|
</vn-one>
|
||||||
</vn-horizontal>
|
</vn-horizontal>
|
||||||
</div>
|
</div>
|
||||||
</vn-popover>
|
</vn-popover>
|
||||||
|
@ -321,7 +361,7 @@
|
||||||
vn-id="delete-ticket"
|
vn-id="delete-ticket"
|
||||||
question="Do you want to delete it?"
|
question="Do you want to delete it?"
|
||||||
message="This ticket is now empty"
|
message="This ticket is now empty"
|
||||||
on-response="$ctrl.moveLines(response)">
|
on-response="$ctrl.transferSales($ctrl.transfer.ticketId, response)">
|
||||||
</vn-confirm>
|
</vn-confirm>
|
||||||
<vn-float-button
|
<vn-float-button
|
||||||
ng-show="$ctrl.isEditable"
|
ng-show="$ctrl.isEditable"
|
||||||
|
|
|
@ -99,6 +99,7 @@ class Controller {
|
||||||
this.isEditable = res.data;
|
this.isEditable = res.data;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
get isChecked() {
|
get isChecked() {
|
||||||
if (this.sales) {
|
if (this.sales) {
|
||||||
for (let instance of this.sales)
|
for (let instance of this.sales)
|
||||||
|
@ -113,7 +114,7 @@ class Controller {
|
||||||
*
|
*
|
||||||
* @return {Array} Checked instances
|
* @return {Array} Checked instances
|
||||||
*/
|
*/
|
||||||
getCheckedLines() {
|
checkedLines() {
|
||||||
if (!this.sales) return;
|
if (!this.sales) return;
|
||||||
|
|
||||||
return this.sales.filter(sale => {
|
return this.sales.filter(sale => {
|
||||||
|
@ -121,13 +122,14 @@ class Controller {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an array of indexes
|
* Returns an array of indexes
|
||||||
* from checked instances
|
* from checked instances
|
||||||
*
|
*
|
||||||
* @return {Array} Indexes of checked instances
|
* @return {Array} Indexes of checked instances
|
||||||
*/
|
*/
|
||||||
getCheckedLinesIndex() {
|
checkedLinesIndex() {
|
||||||
if (!this.sales) return;
|
if (!this.sales) return;
|
||||||
|
|
||||||
let indexes = [];
|
let indexes = [];
|
||||||
|
@ -138,8 +140,25 @@ class Controller {
|
||||||
return indexes;
|
return indexes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
firstCheckedLine() {
|
||||||
|
const checkedLines = this.checkedLines();
|
||||||
|
if (checkedLines)
|
||||||
|
return checkedLines[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the total of checked instances
|
||||||
|
*
|
||||||
|
* @return {Number} Total checked instances
|
||||||
|
*/
|
||||||
|
totalCheckedLines() {
|
||||||
|
const checkedLines = this.checkedLines();
|
||||||
|
if (checkedLines)
|
||||||
|
return checkedLines.length;
|
||||||
|
}
|
||||||
|
|
||||||
removeCheckedLines() {
|
removeCheckedLines() {
|
||||||
const sales = this.getCheckedLines();
|
const sales = this.checkedLines();
|
||||||
|
|
||||||
sales.forEach(sale => {
|
sales.forEach(sale => {
|
||||||
const index = this.sales.indexOf(sale);
|
const index = this.sales.indexOf(sale);
|
||||||
|
@ -167,7 +186,7 @@ class Controller {
|
||||||
|
|
||||||
onRemoveLinesClick(response) {
|
onRemoveLinesClick(response) {
|
||||||
if (response === 'ACCEPT') {
|
if (response === 'ACCEPT') {
|
||||||
let sales = this.getCheckedLines();
|
let sales = this.checkedLines();
|
||||||
|
|
||||||
// Remove unsaved instances
|
// Remove unsaved instances
|
||||||
sales.forEach((sale, index) => {
|
sales.forEach((sale, index) => {
|
||||||
|
@ -188,60 +207,36 @@ class Controller {
|
||||||
}
|
}
|
||||||
|
|
||||||
showTransferPopover(event) {
|
showTransferPopover(event) {
|
||||||
let filter = {clientFk: this.ticket.clientFk, ticketFk: this.ticket.id};
|
this.setTransferParams();
|
||||||
let json = encodeURIComponent(JSON.stringify(filter));
|
|
||||||
let query = `/api/Tickets/threeLastActive?filter=${json}`;
|
|
||||||
this.$http.get(query).then(res => {
|
|
||||||
this.lastThreeTickets = res.data;
|
|
||||||
});
|
|
||||||
this.$scope.transfer.parent = event.target;
|
this.$scope.transfer.parent = event.target;
|
||||||
this.$scope.transfer.show();
|
this.$scope.transfer.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setTransferParams() {
|
||||||
|
const checkedSales = JSON.stringify(this.checkedLines());
|
||||||
|
const sales = JSON.parse(checkedSales);
|
||||||
|
this.transfer = {
|
||||||
|
lastActiveTickets: [],
|
||||||
|
sales: sales
|
||||||
|
};
|
||||||
|
|
||||||
checkEmptiness(receiverTicketId) {
|
const params = {ticketId: this.ticket.id};
|
||||||
let sales = this.getCheckedLines();
|
const query = `/api/clients/${this.ticket.clientFk}/lastActiveTickets`;
|
||||||
let areAllSalesSelected = sales.length === this.$scope.model.data.length;
|
this.$http.get(query, {params}).then(res => {
|
||||||
this.receiverTicketId = receiverTicketId;
|
this.transfer.lastActiveTickets = res.data;
|
||||||
|
});
|
||||||
|
|
||||||
if (areAllSalesSelected) {
|
|
||||||
let query = `/api/Tickets/${this.ticket.id}/checkEmptiness`;
|
|
||||||
this.$http.get(query).then(res => {
|
|
||||||
if (res.data)
|
|
||||||
this.$scope.deleteTicket.show();
|
|
||||||
if (!res.data)
|
|
||||||
this.moveLines(false);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!areAllSalesSelected)
|
|
||||||
this.moveLines(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
moveLines(removeEmptyTicket) {
|
transferSales(ticketId) {
|
||||||
let sales = this.getCheckedLines();
|
const params = {
|
||||||
|
ticketId: ticketId,
|
||||||
let currentTicketData = {
|
sales: this.transfer.sales
|
||||||
currentTicketId: this.ticket.id,
|
|
||||||
clientFk: this.ticket.clientFk,
|
|
||||||
addressFk: this.ticket.addressFk,
|
|
||||||
agencyModeFk: this.ticket.agencyModeFk,
|
|
||||||
warehouseFk: this.ticket.warehouseFk
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let params = {
|
const query = `/api/tickets/${this.ticket.id}/transferSales`;
|
||||||
currentTicket: currentTicketData,
|
this.$http.post(query, params).then(res => {
|
||||||
receiverTicket: this.receiverTicketId ? {id: this.receiverTicketId} : currentTicketData,
|
if (res.data)
|
||||||
sales: sales,
|
|
||||||
removeEmptyTicket: removeEmptyTicket
|
|
||||||
};
|
|
||||||
|
|
||||||
this.$http.post(`/api/Sales/moveToTicket`, params).then(res => {
|
|
||||||
if (res.data) {
|
|
||||||
this.receiverTicketId = null;
|
|
||||||
this.goToTicket(res.data.id);
|
this.goToTicket(res.data.id);
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -251,14 +246,14 @@ class Controller {
|
||||||
clientFk: this.ticket.clientFk,
|
clientFk: this.ticket.clientFk,
|
||||||
ticketCreated: this.ticket.shipped
|
ticketCreated: this.ticket.shipped
|
||||||
};
|
};
|
||||||
const sales = this.getCheckedLines();
|
const sales = this.checkedLines();
|
||||||
this.$http.post(`/api/Claims/createFromSales`, {claim: claim, sales: sales}).then(res => {
|
this.$http.post(`/api/Claims/createFromSales`, {claim: claim, sales: sales}).then(res => {
|
||||||
this.$state.go('claim.card.basicData', {id: res.data.id});
|
this.$state.go('claim.card.basicData', {id: res.data.id});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
goToTicket(ticketID) {
|
goToTicket(ticketId) {
|
||||||
this.$state.go('ticket.card.sale', {id: ticketID});
|
this.$state.go('ticket.card.sale', {id: ticketId});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Slesperson Mana
|
// Slesperson Mana
|
||||||
|
@ -336,7 +331,7 @@ class Controller {
|
||||||
}
|
}
|
||||||
|
|
||||||
showEditDialog() {
|
showEditDialog() {
|
||||||
this.edit = this.getCheckedLines();
|
this.edit = this.checkedLines();
|
||||||
this.$scope.editDialog.show();
|
this.$scope.editDialog.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -365,7 +360,7 @@ class Controller {
|
||||||
}
|
}
|
||||||
|
|
||||||
setReserved(reserved) {
|
setReserved(reserved) {
|
||||||
let selectedSales = this.getCheckedLines();
|
let selectedSales = this.checkedLines();
|
||||||
let params = {sales: selectedSales, ticketFk: this.ticket.id, reserved: reserved};
|
let params = {sales: selectedSales, ticketFk: this.ticket.id, reserved: reserved};
|
||||||
|
|
||||||
let reservedSales = new Map();
|
let reservedSales = new Map();
|
||||||
|
@ -393,7 +388,7 @@ class Controller {
|
||||||
|
|
||||||
showSMSDialog() {
|
showSMSDialog() {
|
||||||
const address = this.ticket.address;
|
const address = this.ticket.address;
|
||||||
const sales = this.getCheckedLines();
|
const sales = this.checkedLines();
|
||||||
const items = sales.map(sale => {
|
const items = sales.map(sale => {
|
||||||
return `${sale.quantity} ${sale.concept}`;
|
return `${sale.quantity} ${sale.concept}`;
|
||||||
});
|
});
|
||||||
|
|
|
@ -7,7 +7,7 @@ Unmark as reserved: Desmarcar como reservado
|
||||||
Update discount: Actualizar descuento
|
Update discount: Actualizar descuento
|
||||||
There is no changes to save: No hay cambios que guardar
|
There is no changes to save: No hay cambios que guardar
|
||||||
Edit discount: Editar descuento
|
Edit discount: Editar descuento
|
||||||
Move to ticket: Mover a ticket
|
Transfer to ticket: Transferir a ticket
|
||||||
New ticket: Nuevo ticket
|
New ticket: Nuevo ticket
|
||||||
Edit price: Editar precio
|
Edit price: Editar precio
|
||||||
You are going to delete lines of the ticket: Vas a borrar lineas del ticket
|
You are going to delete lines of the ticket: Vas a borrar lineas del ticket
|
||||||
|
@ -19,7 +19,8 @@ Available: Disponible
|
||||||
In which day you want to add the ticket?: ¿A que dia quieres añadir el ticket?
|
In which day you want to add the ticket?: ¿A que dia quieres añadir el ticket?
|
||||||
Add claim: Crear reclamación
|
Add claim: Crear reclamación
|
||||||
Claim: Reclamación
|
Claim: Reclamación
|
||||||
Transfer lines: Transferir líneas
|
Sales to transfer: Líneas a transferir
|
||||||
|
Destination ticket: Ticket destinatario
|
||||||
Change ticket state to 'Ok': Cambiar estado del ticket a 'Ok'
|
Change ticket state to 'Ok': Cambiar estado del ticket a 'Ok'
|
||||||
Reserved: Reservado
|
Reserved: Reservado
|
||||||
SMSAvailability: >-
|
SMSAvailability: >-
|
||||||
|
|
|
@ -9,7 +9,7 @@ describe('Ticket', () => {
|
||||||
|
|
||||||
let ticket = {
|
let ticket = {
|
||||||
id: 1,
|
id: 1,
|
||||||
clientFk: 1,
|
clientFk: 101,
|
||||||
shipped: 1,
|
shipped: 1,
|
||||||
created: new Date(),
|
created: new Date(),
|
||||||
client: {salesPersonFk: 1},
|
client: {salesPersonFk: 1},
|
||||||
|
@ -92,13 +92,13 @@ describe('Ticket', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('getCheckedLines()', () => {
|
describe('checkedLines()', () => {
|
||||||
it('should make an array of the instances with the property checked true()', () => {
|
it('should make an array of the instances with the property checked true()', () => {
|
||||||
let sale = controller.sales[1];
|
let sale = controller.sales[1];
|
||||||
sale.checked = true;
|
sale.checked = true;
|
||||||
let expectedResult = [sale];
|
let expectedResult = [sale];
|
||||||
|
|
||||||
expect(controller.getCheckedLines()).toEqual(expectedResult);
|
expect(controller.checkedLines()).toEqual(expectedResult);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -235,5 +235,46 @@ describe('Ticket', () => {
|
||||||
$httpBackend.flush();
|
$httpBackend.flush();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('transferSales()', () => {
|
||||||
|
it('should transfer sales to a ticket', () => {
|
||||||
|
spyOn(controller, 'goToTicket');
|
||||||
|
controller.transfer = {
|
||||||
|
sales: [{id: 1, itemFk: 1}, {id: 2, itemFk: 4}]
|
||||||
|
};
|
||||||
|
|
||||||
|
const expectedResponse = {id: 13};
|
||||||
|
const params = {
|
||||||
|
ticketId: 13,
|
||||||
|
sales: controller.transfer.sales
|
||||||
|
};
|
||||||
|
|
||||||
|
$httpBackend.when('POST', `/api/tickets/1/transferSales`, params).respond(expectedResponse);
|
||||||
|
$httpBackend.expect('POST', `/api/tickets/1/transferSales`, params).respond(expectedResponse);
|
||||||
|
controller.transferSales(13);
|
||||||
|
$httpBackend.flush();
|
||||||
|
|
||||||
|
expect(controller.goToTicket).toHaveBeenCalledWith(13);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('setTransferParams()', () => {
|
||||||
|
it('should define the transfer object on the controller and its default properties', () => {
|
||||||
|
let sale = controller.sales[1];
|
||||||
|
sale.checked = true;
|
||||||
|
const expectedResponse = [sale];
|
||||||
|
|
||||||
|
$httpBackend.when('GET', `/api/clients/101/lastActiveTickets?ticketId=1`).respond(expectedResponse);
|
||||||
|
$httpBackend.expect('GET', `/api/clients/101/lastActiveTickets?ticketId=1`).respond(expectedResponse);
|
||||||
|
controller.setTransferParams();
|
||||||
|
$httpBackend.flush();
|
||||||
|
|
||||||
|
const lastActiveTickets = controller.transfer.lastActiveTickets;
|
||||||
|
|
||||||
|
expect(controller.transfer).toBeDefined();
|
||||||
|
expect(lastActiveTickets).toBeDefined();
|
||||||
|
expect(lastActiveTickets[0].id).toEqual(4);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -61,13 +61,30 @@ vn-ticket-sale {
|
||||||
}
|
}
|
||||||
|
|
||||||
vn-popover.transfer{
|
vn-popover.transfer{
|
||||||
vn-table {
|
vn-textfield {
|
||||||
min-width: 650px;
|
margin: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
vn-horizontal {
|
||||||
|
& > vn-one:nth-child(1){
|
||||||
|
border-right: 1px solid $color-bg;
|
||||||
|
padding-right: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > vn-one:nth-child(2){
|
||||||
|
margin-left: 1em
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vn-table, table {
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
vn-icon:nth-child(1) {
|
|
||||||
padding-top: 0.2em;
|
vn-table {
|
||||||
font-size: 1.7em;
|
width: 20em
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
width: 25em
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue