ticket.basicData Select zone for productionBoss #1604
gitea/salix/dev This commit looks good Details

This commit is contained in:
Joan Sanchez 2019-07-26 11:48:01 +02:00
parent ab2a47d363
commit 64a4e5f43d
33 changed files with 819 additions and 333 deletions

View File

@ -0,0 +1,38 @@
DELIMITER $$
CREATE DEFINER=`root`@`%` PROCEDURE `vn`.`ticket_componentMakeUpdate`(
vTicketFk INT,
vClientFk INT,
vAgencyModeFk INT,
vAddressFk INT,
vZoneFk INT,
vWarehouseFk TINYINT,
vCompanyFk SMALLINT,
vShipped DATETIME,
vLanded DATE,
vIsDeleted BOOLEAN,
vHasToBeUnrouted BOOLEAN,
vOption INT)
BEGIN
CALL vn.ticket_componentPreview (vTicketFk, vLanded, vAddressFk, vZoneFk, vWarehouseFk);
CALL vn.ticket_componentUpdate (
vTicketFk,
vClientFk,
vAgencyModeFk,
vAddressFk,
vZoneFk,
vWarehouseFk,
vCompanyFk,
vShipped,
vLanded,
vIsDeleted,
vHasToBeUnrouted,
vOption
);
DROP TEMPORARY TABLE
tmp.ticketComponent,
tmp.ticketComponentPrice;
END$$
DELIMITER ;

View File

@ -0,0 +1,111 @@
USE `vn`;
DROP procedure IF EXISTS `ticket_componentPreview`;
DELIMITER $$
USE `vn`$$
CREATE DEFINER=`root`@`%` PROCEDURE `ticket_componentPreview`(
vTicketFk INT,
vLanded DATE,
vAddressFk INT,
vZoneFk INT,
vWarehouseFk SMALLINT)
BEGIN
/**
* Calcula los componentes de los articulos de un ticket
*
* @param vTicketFk id del ticket
* @param vLanded nueva fecha de entrega
* @param vAddressFk nuevo consignatario
* @param vZoneFk nueva zona
* @param vWarehouseFk nuevo warehouse
*
* @return tmp.ticketComponent (warehouseFk, itemFk, componentFk, cost)
*/
DECLARE vShipped DATE;
DECLARE vBuyOrderItem INT DEFAULT 100;
DECLARE vHasDataChanged BOOL DEFAULT FALSE;
DECLARE vHasAddressChanged BOOL;
DECLARE vHasZoneChanged BOOL DEFAULT FALSE;
DECLARE vHasWarehouseChanged BOOL DEFAULT FALSE;
DECLARE vAddressTypeRateFk INT DEFAULT NULL;
DECLARE vAgencyModeTypeRateFk INT DEFAULT NULL;
DECLARE vHasChangeAll BOOL DEFAULT FALSE;
SELECT DATE(landed) <> vLanded,
addressFk <> vAddressFk,
zoneFk <> vZoneFk,
warehouseFk <> vWarehouseFk
INTO
vHasDataChanged,
vHasAddressChanged,
vHasZoneChanged,
vHasWarehouseChanged
FROM vn.ticket t
WHERE t.id = vTicketFk;
IF vHasDataChanged OR vHasWarehouseChanged THEN
SET vHasChangeAll = TRUE;
END IF;
IF vHasAddressChanged THEN
SET vAddressTypeRateFk = 5;
END IF;
IF vHasZoneChanged THEN
SET vAgencyModeTypeRateFk = 6;
END IF;
SELECT TIMESTAMPADD(DAY, -travelingDays, vLanded) INTO vShipped
FROM zone
WHERE id = vZoneFk;
CALL buyUltimate(vWarehouseFk, vShipped);
DROP TEMPORARY TABLE IF EXISTS tmp.ticketLot;
CREATE TEMPORARY TABLE tmp.ticketLot ENGINE = MEMORY (
SELECT
vWarehouseFk AS warehouseFk,
NULL AS available,
s.itemFk,
bu.buyFk
FROM sale s
LEFT JOIN tmp.buyUltimate bu ON bu.itemFk = s.itemFk
WHERE s.ticketFk = vTicketFk
AND s.itemFk != vBuyOrderItem
GROUP BY bu.warehouseFk, bu.itemFk);
CALL catalog_componentCalculate(vZoneFk, vAddressFk, vShipped);
REPLACE INTO tmp.ticketComponent (warehouseFk, itemFk, componentFk, cost)
SELECT t.warehouseFk, s.itemFk, sc.componentFk, sc.value
FROM saleComponent sc
JOIN sale s ON s.id = sc.saleFk
JOIN ticket t ON t.id = s.ticketFk
JOIN componentRate cr ON cr.id = sc.componentFk
WHERE s.ticketFk = vTicketFk
AND (cr.isRenewable = FALSE
OR
(NOT vHasChangeAll
AND (NOT (cr.componentTypeRate <=> vAddressTypeRateFk
OR cr.componentTypeRate <=> vAgencyModeTypeRateFk))));
SET @shipped = vShipped;
DROP TEMPORARY TABLE
tmp.buyUltimate,
tmp.ticketLot;
IF vShipped IS NULL THEN
CALL util.throw('NO_ZONE_AVAILABLE');
END IF;
IF vShipped < CURDATE() THEN
CALL util.throw('ERROR_PAST_SHIPMENT');
END IF;
END$$
DELIMITER ;

View File

@ -0,0 +1,52 @@
DROP procedure IF EXISTS `vn`.`ticket_priceDifference`;
DELIMITER $$
CREATE DEFINER=`root`@`%` PROCEDURE `vn`.`ticket_priceDifference`(
vTicketFk INT,
vLanded DATE,
vAddressFk INT,
vZoneFk INT,
vWarehouseFk INT)
BEGIN
/**
* Devuelve las diferencias de precio
* de los movimientos de un ticket.
*
* @param vTicketFk Id del ticket
* @param vLanded Fecha de recepcion
* @param vAddressFk Id del consignatario
* @param vZoneFk Id de la zona
* @param vWarehouseFk Id del almacén
*/
CALL vn.ticket_componentPreview(vTicketFk, vLanded, vAddressFk, vZoneFk, vWarehouseFk);
SELECT s.itemFk,
i.name,
i.size,
i.category,
IFNULL(s.quantity, 0) AS quantity,
IFNULL(s.price, 0) AS price,
ROUND(SUM(tc.cost), 2) AS newPrice,
s.quantity * (s.price - ROUND(SUM(tc.cost), 2)) difference,
s.id AS saleFk
FROM sale s
JOIN item i ON i.id = s.itemFk
JOIN ticket t ON t.id = s.ticketFk
LEFT JOIN tmp.ticketComponent tc ON tc.itemFk = s.itemFk
AND tc.warehouseFk = t.warehouseFk
LEFT JOIN saleComponent sc ON sc.saleFk = s.id
AND sc.componentFk = tc.componentFk
LEFT JOIN componentRate cr ON cr.id = tc.componentFk
WHERE
t.id = vTicketFk
AND IF(sc.componentFk IS NULL
AND cr.classRate IS NOT NULL, FALSE, TRUE)
GROUP BY s.id ORDER BY s.id;
DROP TEMPORARY TABLE
tmp.ticketComponent,
tmp.ticketComponentPrice;
END$$
DELIMITER ;

View File

@ -1448,6 +1448,14 @@ INSERT INTO `vn`.`ticketRequest`(`id`, `description`, `requesterFk`, `atenderFk`
(3, 'Melee weapon heavy shield 1x0.5m', 18, 35, 20, 4, 3.06, 0, NULL, 1, DATE_ADD(CURDATE(), INTERVAL -15 DAY)), (3, 'Melee weapon heavy shield 1x0.5m', 18, 35, 20, 4, 3.06, 0, NULL, 1, DATE_ADD(CURDATE(), INTERVAL -15 DAY)),
(4, 'Melee weapon combat first 15cm', 18, 35, 15, NULL, 1.30, NULL, NULL, 11, CURDATE()); (4, 'Melee weapon combat first 15cm', 18, 35, 15, NULL, 1.30, NULL, NULL, 11, CURDATE());
INSERT INTO `vn`.`ticketServiceType`(`id`, `name`)
VALUES
(1, 'Porte Agencia'),
(2, 'Portes Retorno'),
(3, 'Porte Carry'),
(4, 'Cargo FITOSANITARIO'),
(5, 'Documentos');
INSERT INTO `vn`.`ticketService`(`id`, `description`, `quantity`, `price`, `taxClassFk`, `ticketFk`) INSERT INTO `vn`.`ticketService`(`id`, `description`, `quantity`, `price`, `taxClassFk`, `ticketFk`)
VALUES VALUES
(1, 'Documentos', 1, 2.00, 1, 1), (1, 'Documentos', 1, 2.00, 1, 1),

View File

@ -441,7 +441,8 @@ export default {
basicDataButton: 'vn-left-menu a[ui-sref="ticket.card.basicData.stepOne"]', basicDataButton: 'vn-left-menu a[ui-sref="ticket.card.basicData.stepOne"]',
clientAutocomplete: 'vn-autocomplete[field="$ctrl.clientFk"]', clientAutocomplete: 'vn-autocomplete[field="$ctrl.clientFk"]',
addressAutocomplete: 'vn-autocomplete[field="$ctrl.ticket.addressFk"]', addressAutocomplete: 'vn-autocomplete[field="$ctrl.ticket.addressFk"]',
agencyAutocomplete: 'vn-autocomplete[field="$ctrl.ticket.agencyModeFk"]', agencyAutocomplete: 'vn-autocomplete[field="$ctrl.agencyModeId"]',
zoneAutocomplete: 'vn-autocomplete[field="$ctrl.zoneId"]',
nextStepButton: 'vn-step-control > section > section.buttons > section:nth-child(2) > vn-button', nextStepButton: 'vn-step-control > section > section.buttons > section:nth-child(2) > vn-button',
finalizeButton: 'vn-step-control > section > section.buttons > section:nth-child(2) > vn-submit', finalizeButton: 'vn-step-control > section > section.buttons > section:nth-child(2) > vn-submit',
stepTwoTotalPriceDif: 'vn-ticket-basic-data-step-two > form > vn-card > div > vn-horizontal > table > tfoot > tr > td:nth-child(4)', stepTwoTotalPriceDif: 'vn-ticket-basic-data-step-two > form > vn-card > div > vn-horizontal > table > tfoot > tr > td:nth-child(4)',

View File

@ -14,6 +14,7 @@ describe('Ticket Edit basic data path', () => {
it(`should edit the ticket agency then click next`, async() => { it(`should edit the ticket agency then click next`, async() => {
let url = await nightmare let url = await nightmare
.autocompleteSearch(selectors.ticketBasicData.agencyAutocomplete, 'Silla247Expensive') .autocompleteSearch(selectors.ticketBasicData.agencyAutocomplete, 'Silla247Expensive')
.waitToGetProperty(`${selectors.ticketBasicData.zoneAutocomplete} input`, 'value')
.waitToClick(selectors.ticketBasicData.nextStepButton) .waitToClick(selectors.ticketBasicData.nextStepButton)
.waitForURL('data/step-two') .waitForURL('data/step-two')
.parsedUrl(); .parsedUrl();

View File

@ -92,8 +92,6 @@ export default class Autocomplete extends Input {
set field(value) { set field(value) {
this._field = value; this._field = value;
if (!value) return;
this.refreshSelection(); this.refreshSelection();
this.emit('change', {value}); this.emit('change', {value});
} }

View File

@ -198,7 +198,9 @@ async function backendStatus() {
timer = setInterval(() => { timer = setInterval(() => {
const url = `${e2eConfig.url}/api/Applications/status`; const url = `${e2eConfig.url}/api/Applications/status`;
request.get(url, (err, res) => { request.get(url, (err, res) => {
if (res.body == 'true') { if (err || attempts > 100) // 250ms * 100 => 25s timeout
throw new Error('Could not connect to backend');
else if (res && res.body == 'true') {
clearInterval(timer); clearInterval(timer);
resolve(attempts); resolve(attempts);
} else } else

View File

@ -21,7 +21,6 @@
"Cannot check Equalization Tax in this NIF/CIF": "Cannot check Equalization Tax in this NIF/CIF", "Cannot check Equalization Tax in this NIF/CIF": "Cannot check Equalization Tax in this NIF/CIF",
"You can't create an order for a frozen client": "You can't create an order for a frozen client", "You can't create an order for a frozen client": "You can't create an order for a frozen client",
"This address doesn't exist": "This address doesn't exist", "This address doesn't exist": "This address doesn't exist",
"NO_AGENCY_AVAILABLE": "NO_AGENCY_AVAILABLE",
"Warehouse cannot be blank": "Warehouse cannot be blank", "Warehouse cannot be blank": "Warehouse cannot be blank",
"Agency cannot be blank": "Agency cannot be blank", "Agency cannot be blank": "Agency cannot be blank",
"The IBAN does not have the correct format": "The IBAN does not have the correct format", "The IBAN does not have the correct format": "The IBAN does not have the correct format",

View File

@ -82,7 +82,8 @@
"INFINITE_LOOP": "Existe una dependencia entre dos Jefes", "INFINITE_LOOP": "Existe una dependencia entre dos Jefes",
"The sales of the current ticket can't be modified": "Las lineas de este ticket no pueden ser modificadas", "The sales of the current ticket can't be modified": "Las lineas de este ticket no pueden ser modificadas",
"The sales of the receiver ticket can't be modified": "Las lineas del ticket al que envias no pueden ser modificadas", "The sales of the receiver ticket can't be modified": "Las lineas del ticket al que envias no pueden ser modificadas",
"NO_AGENCY_AVAILABLE": "No hay agencias disponibles", "NO_AGENCY_AVAILABLE": "No hay una zona de reparto disponible con estos parámetros",
"ERROR_PAST_SHIPMENT": "No puedes seleccionar una fecha de envío en pasado",
"The current ticket can't be modified": "El ticket actual no puede ser modificado", "The current ticket can't be modified": "El ticket actual no puede ser modificado",
"The sales of this ticket can't be modified": "Las lineas de este ticket no pueden ser modificadas", "The sales of this ticket can't be modified": "Las lineas de este ticket no pueden ser modificadas",
"Please select at least one sale": "Por favor selecciona al menos una linea", "Please select at least one sale": "Por favor selecciona al menos una linea",
@ -95,5 +96,6 @@
"This item is not available": "Este artículo no está disponible", "This item is not available": "Este artículo no está disponible",
"This postcode already exists": "Este código postal ya existe", "This postcode already exists": "Este código postal ya existe",
"Concept cannot be blank": "El concepto no puede quedar en blanco", "Concept cannot be blank": "El concepto no puede quedar en blanco",
"File doesn't exists": "El archivo no existe" "File doesn't exists": "El archivo no existe",
"You don't have privileges to change the zone": "No tienes permisos para cambiar la zona"
} }

View File

@ -1,14 +1,10 @@
const ParameterizedSQL = require('loopback-connector').ParameterizedSQL; const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
module.exports = Self => { module.exports = Self => {
Self.remoteMethodCtx('getLanded', { Self.remoteMethod('getLanded', {
description: 'Returns the first shipped and landed possible for params', description: 'Returns the first shipped and landed possible for params',
accessType: 'READ', accessType: 'READ',
accepts: [{ accepts: [{
arg: 'params',
type: 'Object',
description: `shipped, addressFk, agencyModeFk, warehouseFk`
}, {
arg: 'shipped', arg: 'shipped',
type: 'date', type: 'date',
required: true required: true
@ -38,15 +34,14 @@ module.exports = Self => {
} }
}); });
Self.getLanded = async(ctx, params) => { Self.getLanded = async(shipped, addressFk, agencyModeFk, warehouseFk) => {
let stmts = []; let stmts = [];
params = params || ctx.args;
stmts.push(new ParameterizedSQL( stmts.push(new ParameterizedSQL(
`CALL vn.zoneGetLanded(?, ?, ?, ?)`, [ `CALL vn.zoneGetLanded(?, ?, ?, ?)`, [
params.shipped, shipped,
params.addressFk, addressFk,
params.agencyModeFk, agencyModeFk,
params.warehouseFk warehouseFk
] ]
)); ));

View File

@ -1,12 +1,8 @@
module.exports = Self => { module.exports = Self => {
Self.remoteMethodCtx('getShipped', { Self.remoteMethod('getShipped', {
description: 'Returns the first shipped possible for params', description: 'Returns the first shipped possible for params',
accessType: 'READ', accessType: 'READ',
accepts: [{ accepts: [{
arg: 'params',
type: 'Object',
description: `landed, addressFk, agencyModeFk, warehouseFk`
}, {
arg: 'landed', arg: 'landed',
type: 'date', type: 'date',
required: true required: true
@ -36,15 +32,14 @@ module.exports = Self => {
} }
}); });
Self.getShipped = async(ctx, params)=> { Self.getShipped = async(landed, addressFk, agencyModeFk, warehouseFk)=> {
params = params || ctx.args;
let query = `CALL vn.zoneGetShipped(?, ?, ?, ?)`; let query = `CALL vn.zoneGetShipped(?, ?, ?, ?)`;
let [response] = await Self.rawSql(query, [ let [[response]] = await Self.rawSql(query, [
params.landed, landed,
params.addressFk, addressFk,
params.agencyModeFk, agencyModeFk,
params.warehouseFk warehouseFk
]); ]);
return (response[0] && response[0].shipped && response[0].shipped.toJSON()) || null; return response;
}; };
}; };

View File

@ -2,13 +2,11 @@ const app = require('vn-loopback/server/server');
describe('agency getLanded()', () => { describe('agency getLanded()', () => {
it('should return a landing date', async() => { it('should return a landing date', async() => {
let data = { const shipped = new Date();
shipped: new Date(), const addressFk = 121;
addressFk: 121, const agencyModeFk = 7;
agencyModeFk: 7, const warehouseFk = 1;
warehouseFk: 1 let result = await app.models.Agency.getLanded(shipped, addressFk, agencyModeFk, warehouseFk);
};
let result = await app.models.Agency.getLanded({}, data);
expect(result.landed).toBeDefined(); expect(result.landed).toBeDefined();
}); });

View File

@ -2,13 +2,12 @@ const app = require('vn-loopback/server/server');
describe('agency getShipped()', () => { describe('agency getShipped()', () => {
it('should return a shipment date', async() => { it('should return a shipment date', async() => {
let data = { const landed = new Date();
landed: new Date(), const addressFk = 121;
addressFk: 121, const agencyModeFk = 7;
agencyModeFk: 7, const warehouseFk = 1;
warehouseFk: 1
}; let result = await app.models.Agency.getShipped(landed, addressFk, agencyModeFk, warehouseFk);
let result = await app.models.Agency.getShipped({}, data);
expect(result).toBeDefined(); expect(result).toBeDefined();
}); });
@ -17,14 +16,13 @@ describe('agency getShipped()', () => {
let newDate = new Date(); let newDate = new Date();
newDate.setMonth(newDate.getMonth() - 1); newDate.setMonth(newDate.getMonth() - 1);
let data = { const landed = newDate;
landed: newDate, const addressFk = 121;
addressFk: 121, const agencyModeFk = 7;
agencyModeFk: 7, const warehouseFk = 1;
warehouseFk: 1
};
let result = await app.models.Agency.getShipped({}, data);
expect(result).toBeNull(); let result = await app.models.Agency.getShipped(landed, addressFk, agencyModeFk, warehouseFk);
expect(result).toBeUndefined();
}); });
}); });

View File

@ -43,7 +43,7 @@ module.exports = Self => {
r.bankFk, r.bankFk,
u.nickname userNickname, u.nickname userNickname,
r.clientFk, r.clientFk,
FALSE pdf, FALSE hasPdf,
FALSE isInvoice FALSE isInvoice
FROM vn.receipt r FROM vn.receipt r
LEFT JOIN vn.worker w ON w.id = r.workerFk LEFT JOIN vn.worker w ON w.id = r.workerFk
@ -64,7 +64,7 @@ module.exports = Self => {
NULL, NULL,
NULL, NULL,
i.clientFk, i.clientFk,
i.pdf, i.hasPdf,
TRUE isInvoice TRUE isInvoice
FROM vn.invoiceOut i FROM vn.invoiceOut i
JOIN vn.company c ON c.id = i.companyFk JOIN vn.company c ON c.id = i.companyFk

View File

@ -83,7 +83,7 @@
</vn-check> </vn-check>
</vn-td> </vn-td>
<vn-td center> <vn-td center>
<a ng-show="balance.pdf" <a ng-show="balance.hasPdf"
target="_blank" target="_blank"
href="api/InvoiceOuts/{{::balance.id}}/download?access_token={{::$ctrl.accessToken}}"> href="api/InvoiceOuts/{{::balance.id}}/download?access_token={{::$ctrl.accessToken}}">
<vn-icon-button <vn-icon-button

View File

@ -83,7 +83,7 @@ module.exports = Self => {
case 'max': case 'max':
return {amount: {lte: value}}; return {amount: {lte: value}};
case 'hasPdf': case 'hasPdf':
return {'i.pdf': value}; return {'i.hasPdf': value};
case 'created': case 'created':
return {'i.created': value}; return {'i.created': value};
case 'amount': case 'amount':
@ -109,7 +109,7 @@ module.exports = Self => {
i.created, i.created,
i.dued, i.dued,
i.clientFk, i.clientFk,
i.pdf AS hasPdf, i.hasPdf,
c.socialName AS clientSocialName, c.socialName AS clientSocialName,
co.code AS companyCode co.code AS companyCode
FROM invoiceOut i FROM invoiceOut i

View File

@ -1,75 +0,0 @@
const UserError = require('vn-loopback/util/user-error');
module.exports = Self => {
Self.remoteMethodCtx('priceDifference', {
description: 'Returns sales with price difference if the ticket is editable',
accessType: 'READ',
accepts: [{
arg: 'ticketFk',
type: 'number',
required: true,
description: 'ticket id',
http: {source: 'path'}
}, {
arg: 'data',
type: 'Object',
required: true,
description: 'landed, addressFk, agencyModeFk',
http: {source: 'body'}
}],
returns: {
type: ['Object'],
root: true
},
http: {
path: `/:ticketFk/priceDifference`,
verb: 'post'
}
});
Self.priceDifference = async(ctx, ticketFk, data) => {
let thisTicketIsEditable = await Self.app.models.Ticket.isEditable(ctx, ticketFk);
if (!thisTicketIsEditable)
throw new UserError(`The sales of this ticket can't be modified`);
let filter = {
where: {
ticketFk: ticketFk
},
order: 'concept ASC',
include: [{
relation: 'item'
}]
};
let salesObj = {};
salesObj.items = await Self.find(filter);
salesObj.totalUnitPrice = 0.00;
salesObj.totalNewPrice = 0.00;
salesObj.totalDifference = 0.00;
let query = `CALL vn.ticketComponentPriceDifference(?, ?, ?, ?, ?)`;
let [differences] = await Self.rawSql(query, [
ticketFk,
data.landed,
data.addressFk,
data.agencyModeFk,
data.warehouseFk
]);
salesObj.items.forEach(sale => {
differences.forEach(difference => {
if (sale.id == difference.saleFk)
sale.component = difference;
});
salesObj.totalUnitPrice += sale.price;
salesObj.totalNewPrice += sale.component.newPrice;
salesObj.totalDifference += sale.component.difference;
salesObj.totalUnitPrice = Math.round(salesObj.totalUnitPrice * 100) / 100;
salesObj.totalNewPrice = Math.round(salesObj.totalNewPrice * 100) / 100;
salesObj.totalDifference = Math.round(salesObj.totalDifference * 100) / 100;
});
return salesObj;
};
};

View File

@ -1,56 +1,116 @@
const UserError = require('vn-loopback/util/user-error');
module.exports = Self => { module.exports = Self => {
Self.remoteMethod('componentUpdate', { Self.remoteMethodCtx('componentUpdate', {
description: 'Save ticket sale components', description: 'Save ticket sale components',
accessType: 'WRITE', accessType: 'WRITE',
accepts: [{ accepts: [{
arg: 'ticketFk', arg: 'id',
type: 'number', type: 'Number',
required: true, required: true,
description: 'ticket id', description: 'The ticket id',
http: {source: 'path'} http: {source: 'path'}
}, { }, {
arg: 'data', arg: 'clientId',
type: 'Object', type: 'Number',
required: true, description: 'The client id',
description: 'landed, addressFk, agencyModeFk, warehouseFk', required: true
http: {source: 'body'}
}, { }, {
arg: 'context', arg: 'agencyModeId',
type: 'object', type: 'Number',
http: function(ctx) { description: 'The agencyMode id',
return ctx; required: true
} }, {
arg: 'addressId',
type: 'Number',
description: 'The address id',
required: true
}, {
arg: 'zoneId',
type: 'Number',
description: 'The zone id',
required: true
}, {
arg: 'warehouseId',
type: 'Number',
description: 'The warehouse id',
required: true
}, {
arg: 'companyId',
type: 'Number',
description: 'The company id',
required: true
}, {
arg: 'shipped',
type: 'Date',
description: 'The shipped date',
required: true
}, {
arg: 'landed',
type: 'Date',
description: 'The landing date',
required: true
}, {
arg: 'isDeleted',
type: 'Boolean',
description: 'Ticket is deleted',
required: true
}, {
arg: 'hasToBeUnrouted',
type: 'Boolean',
description: 'Ticket should be removed from ticket',
required: true
}, {
arg: 'option',
type: 'Number',
description: 'Action id',
required: true
}], }],
returns: { returns: {
type: ['Object'], type: ['Object'],
root: true root: true
}, },
http: { http: {
path: `/:ticketFk/componentUpdate`, path: `/:id/componentUpdate`,
verb: 'post' verb: 'post'
} }
}); });
Self.componentUpdate = async(ticketFk, data, ctx) => { Self.componentUpdate = async(ctx, id, clientId, agencyModeId, addressId, zoneId, warehouseId,
let userId = ctx.req.accessToken.userId; companyId, shipped, landed, isDeleted, hasToBeUnrouted, option) => {
let hasDeliveryRole = await Self.app.models.Account.hasRole(userId, 'delivery'); const userId = ctx.req.accessToken.userId;
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`);
const hasDeliveryRole = await models.Account.hasRole(userId, 'delivery');
if (!hasDeliveryRole) if (!hasDeliveryRole)
data.hasToBeUnrouted = true; hasToBeUnrouted = true;
let query = 'CALL vn.ticketComponentMakeUpdate(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)'; const isProductionBoss = await models.Account.hasRole(userId, 'productionBoss');
if (!isProductionBoss) {
const zone = await models.Agency.getShipped(landed, addressId, agencyModeId, warehouseId);
if (zone.id != zoneId)
throw new UserError(`You don't have privileges to change the zone`);
}
let query = 'CALL vn.ticket_componentMakeUpdate(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)';
let res = await Self.rawSql(query, [ let res = await Self.rawSql(query, [
ticketFk, id,
data.clientFk, clientId,
data.agencyModeFk, agencyModeId,
data.addressFk, addressId,
data.warehouseFk, zoneId,
data.companyFk, warehouseId,
data.shipped, companyId,
data.landed, shipped,
data.isDeleted, landed,
data.hasToBeUnrouted, isDeleted,
data.option hasToBeUnrouted,
option
]); ]);
return res; return res;
}; };

View File

@ -20,7 +20,7 @@ module.exports = Self => {
}); });
Self.isEditable = async(ctx, ticketFk) => { Self.isEditable = async(ctx, ticketFk) => {
const accessToken = ctx.active && ctx.active.accessToken || ctx.req && ctx.req.accessToken; const accessToken = ctx.req.accessToken;
const userId = accessToken.userId; const userId = accessToken.userId;
let state = await Self.app.models.TicketState.findOne({ let state = await Self.app.models.TicketState.findOne({
where: {ticketFk: ticketFk} where: {ticketFk: ticketFk}

View File

@ -61,21 +61,14 @@ module.exports = Self => {
try { try {
if (!params.shipped && params.landed) { if (!params.shipped && params.landed) {
params.shipped = await models.Agency.getShipped(ctx, { const shippedResult = await models.Agency.getShipped(params.landed,
landed: params.landed, address.id, params.agencyModeFk, params.warehouseFk);
addressFk: address.id, params.shipped = shippedResult.shipped;
agencyModeFk: params.agencyModeFk,
warehouseFk: params.warehouseFk
});
} }
if (params.shipped && !params.landed) { if (params.shipped && !params.landed) {
const landedResult = await models.Agency.getLanded(ctx, { const landedResult = await models.Agency.getLanded(params.shipped,
shipped: params.shipped, address.id, params.agencyModeFk, params.warehouseFk);
addressFk: address.id,
agencyModeFk: params.agencyModeFk,
warehouseFk: params.warehouseFk
});
params.landed = landedResult.landed; params.landed = landedResult.landed;
} }

View File

@ -0,0 +1,110 @@
const UserError = require('vn-loopback/util/user-error');
module.exports = Self => {
Self.remoteMethodCtx('priceDifference', {
description: 'Returns sales with price difference if the ticket is editable',
accessType: 'READ',
accepts: [{
arg: 'id',
type: 'Number',
required: true,
description: 'The ticket id',
http: {source: 'path'}
},
{
arg: 'landed',
type: 'Date',
description: 'The landing date',
required: true
},
{
arg: 'addressId',
type: 'Number',
description: 'The address id',
required: true
},
{
arg: 'agencyModeId',
type: 'Number',
description: 'The agencyMode id',
required: true
},
{
arg: 'zoneId',
type: 'Number',
description: 'The zone id',
required: true
},
{
arg: 'warehouseId',
type: 'Number',
description: 'The warehouse id',
required: true
}],
returns: {
type: ['Object'],
root: true
},
http: {
path: `/:id/priceDifference`,
verb: 'POST'
}
});
Self.priceDifference = async(ctx, id, landed, addressId, agencyModeId, zoneId, warehouseId) => {
const models = Self.app.models;
const isEditable = await models.Ticket.isEditable(ctx, id);
const userId = ctx.req.accessToken.userId;
if (!isEditable)
throw new UserError(`The sales of this ticket can't be modified`);
const isProductionBoss = await models.Account.hasRole(userId, 'productionBoss');
if (!isProductionBoss) {
const zone = await models.Agency.getShipped(landed, addressId, agencyModeId, warehouseId);
if (zone.id != zoneId)
throw new UserError(`You don't have privileges to change the zone`);
}
let salesObj = {};
salesObj.items = await models.Sale.find({
where: {
ticketFk: id
},
order: 'concept ASC',
include: [{
relation: 'item'
}]
});
salesObj.totalUnitPrice = 0.00;
salesObj.totalNewPrice = 0.00;
salesObj.totalDifference = 0.00;
const query = `CALL vn.ticket_priceDifference(?, ?, ?, ?, ?)`;
const args = [id, landed, addressId, zoneId, warehouseId];
const [difComponents] = await Self.rawSql(query, args);
const map = new Map();
difComponents.forEach(difComponent => {
map.set(difComponent.saleFk, difComponent);
});
salesObj.items.forEach(sale => {
const difComponent = map.get(sale.id);
if (difComponent)
sale.component = difComponent;
salesObj.totalUnitPrice += sale.price;
salesObj.totalNewPrice += sale.component.newPrice;
salesObj.totalDifference += sale.component.difference;
salesObj.totalUnitPrice = Math.round(salesObj.totalUnitPrice * 100) / 100;
salesObj.totalNewPrice = Math.round(salesObj.totalNewPrice * 100) / 100;
salesObj.totalDifference = Math.round(salesObj.totalDifference * 100) / 100;
});
return salesObj;
};
};

View File

@ -28,22 +28,22 @@ describe('ticket componentUpdate()', () => {
}); });
it('should change the agencyMode to modify the sale components value', async() => { it('should change the agencyMode to modify the sale components value', async() => {
let data = { const clientId = 102;
clientFk: 102, const addressId = 122;
agencyModeFk: 8, const agencyModeId = 8;
addressFk: 122, const warehouseId = 1;
warehouseFk: 1, const zoneId = 5;
companyFk: 442, const shipped = today;
shipped: today, const companyId = 442;
landed: tomorrow, const isDeleted = false;
isDeleted: false, const landed = tomorrow;
hasToBeUnrouted: false, const hasToBeUnrouted = false;
option: 1 const option = 1;
};
let ctx = {req: {accessToken: {userId: 101}}}; let ctx = {req: {accessToken: {userId: 101}}};
await app.models.Ticket.componentUpdate(ticketId, data, ctx); await app.models.Ticket.componentUpdate(ctx, ticketId, clientId, agencyModeId, addressId,
zoneId, warehouseId, companyId, shipped, landed, isDeleted, hasToBeUnrouted, option);
[componentValue] = await app.models.SaleComponent.rawSql(componentOfSaleSeven); [componentValue] = await app.models.SaleComponent.rawSql(componentOfSaleSeven);
let firstvalueAfterChange = componentValue.value; let firstvalueAfterChange = componentValue.value;
@ -56,21 +56,21 @@ describe('ticket componentUpdate()', () => {
}); });
it('should change the agencyMode to go back to the originals sale components value', async() => { it('should change the agencyMode to go back to the originals sale components value', async() => {
let data = { const clientId = 102;
clientFk: 102, const addressId = 122;
agencyModeFk: 7, const agencyModeId = 7;
addressFk: 122, const warehouseId = 1;
warehouseFk: 1, const zoneId = 3;
companyFk: 442, const shipped = today;
shipped: today, const companyId = 442;
landed: tomorrow, const isDeleted = false;
isDeleted: false, const landed = tomorrow;
hasToBeUnrouted: false, const hasToBeUnrouted = false;
option: 1 const option = 1;
};
let ctx = {req: {accessToken: {userId: 101}}}; let ctx = {req: {accessToken: {userId: 101}}};
await app.models.Ticket.componentUpdate(ticketId, data, ctx); await app.models.Ticket.componentUpdate(ctx, ticketId, clientId, agencyModeId, addressId,
zoneId, warehouseId, companyId, shipped, landed, isDeleted, hasToBeUnrouted, option);
[componentValue] = await app.models.SaleComponent.rawSql(componentOfSaleSeven); [componentValue] = await app.models.SaleComponent.rawSql(componentOfSaleSeven);
let firstvalueAfterChange = componentValue.value; let firstvalueAfterChange = componentValue.value;

View File

@ -3,16 +3,19 @@ let UserError = require('vn-loopback/util/user-error');
describe('sale priceDifference()', () => { describe('sale priceDifference()', () => {
it('should return ticket price differences', async() => { it('should return ticket price differences', async() => {
let ctx = {req: {accessToken: {userId: 9}}};
let tomorrow = new Date(); let tomorrow = new Date();
tomorrow.setDate(tomorrow.getDate() + 1); tomorrow.setDate(tomorrow.getDate() + 1);
let data = {
landed: tomorrow, const ticketId = 16;
addressFk: 126, const landed = tomorrow;
agencyModeFk: 7, const addressId = 126;
warehouseFk: 1 const agencyModeId = 7;
}; const zoneId = 3;
let result = await app.models.Sale.priceDifference(ctx, 16, data); const warehouseId = 1;
const httpCtx = {req: {accessToken: {userId: 106}}};
let result = await app.models.Ticket.priceDifference(httpCtx, ticketId, landed,
addressId, agencyModeId, zoneId, warehouseId);
expect(result.totalUnitPrice).toEqual(215.77); expect(result.totalUnitPrice).toEqual(215.77);
expect(result.totalNewPrice).toEqual(215.77); expect(result.totalNewPrice).toEqual(215.77);
@ -20,15 +23,14 @@ describe('sale priceDifference()', () => {
}); });
it('should return an error if the ticket is not editable', async() => { it('should return an error if the ticket is not editable', async() => {
let ctx = {req: {accessToken: {userId: 9}}}; const ticketId = 1;
const landed = new Date();
const addressId = 121;
const zoneId = 3;
const warehouseId = 1;
let error; let error;
let data = { const httpCtx = {req: {accessToken: {userId: 106}}};
landed: new Date(), await app.models.Ticket.priceDifference(httpCtx, ticketId, landed, addressId, zoneId, warehouseId)
addressFk: 121,
agencyModeFk: 1,
warehouseFk: 1
};
await app.models.Sale.priceDifference(ctx, 1, data)
.catch(e => { .catch(e => {
error = e; error = e;
}); });

View File

@ -1,6 +1,5 @@
module.exports = Self => { module.exports = Self => {
require('../methods/sale/getClaimableFromTicket')(Self); require('../methods/sale/getClaimableFromTicket')(Self);
require('../methods/sale/priceDifference')(Self);
require('../methods/sale/moveToTicket')(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);

View File

@ -4,10 +4,12 @@ const LoopBackContext = require('loopback-context');
module.exports = Self => { module.exports = Self => {
Self.observe('before save', async ctx => { Self.observe('before save', async ctx => {
const loopBackContext = LoopBackContext.getCurrentContext(); const loopBackContext = LoopBackContext.getCurrentContext();
const httpCtx = {req: loopBackContext.active};
const models = Self.app.models;
let changes = ctx.currentInstance || ctx.instance; let changes = ctx.currentInstance || ctx.instance;
if (changes) { if (changes) {
let ticketId = changes.ticketFk; let ticketId = changes.ticketFk;
let isEditable = await Self.app.models.Ticket.isEditable(loopBackContext, ticketId); let isEditable = await models.Ticket.isEditable(httpCtx, ticketId);
if (!isEditable) if (!isEditable)
throw new UserError(`The current ticket can't be modified`); throw new UserError(`The current ticket can't be modified`);
} }
@ -15,9 +17,10 @@ module.exports = Self => {
Self.observe('before delete', async ctx => { Self.observe('before delete', async ctx => {
const loopBackContext = LoopBackContext.getCurrentContext(); const loopBackContext = LoopBackContext.getCurrentContext();
const httpCtx = {req: loopBackContext.active};
const models = Self.app.models; const models = Self.app.models;
const service = await models.TicketService.findById(ctx.where.id); const service = await models.TicketService.findById(ctx.where.id);
const isEditable = await Self.app.models.Ticket.isEditable(loopBackContext, service.ticketFk); const isEditable = await models.Ticket.isEditable(httpCtx, service.ticketFk);
if (!isEditable) if (!isEditable)
throw new UserError(`The current ticket can't be modified`); throw new UserError(`The current ticket can't be modified`);

View File

@ -7,6 +7,7 @@ module.exports = Self => {
require('../methods/ticket/getTotal')(Self); require('../methods/ticket/getTotal')(Self);
require('../methods/ticket/getTaxes')(Self); require('../methods/ticket/getTaxes')(Self);
require('../methods/ticket/subtotal')(Self); require('../methods/ticket/subtotal')(Self);
require('../methods/ticket/priceDifference')(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);

View File

@ -1,3 +1,11 @@
<vn-crud-model
url="/api/Zones"
include="{relation: 'warehouse'}"
data="zones"
order="name"
auto-load="true">
</vn-crud-model>
<form name="form"> <form name="form">
<vn-card pad-large> <vn-card pad-large>
<vn-horizontal> <vn-horizontal>
@ -7,8 +15,8 @@
label="Client" label="Client"
show-field="name" show-field="name"
value-field="id" value-field="id"
field="$ctrl.clientFk" field="$ctrl.clientId"
initial-data="$ctrl.clientFk" initial-data="$ctrl.clientId"
order="id"> order="id">
</vn-autocomplete> </vn-autocomplete>
<vn-autocomplete vn-one <vn-autocomplete vn-one
@ -24,12 +32,12 @@
</tpl-item> </tpl-item>
</vn-autocomplete> </vn-autocomplete>
<vn-autocomplete vn-one <vn-autocomplete vn-one
url="/api/AgencyModes/isActive" url="/api/Warehouses"
label="Agency" label="Warehouse"
show-field="name" show-field="name"
value-field="id" value-field="id"
field="$ctrl.ticket.agencyModeFk" field="$ctrl.ticket.warehouseFk"
initial-data="$ctrl.ticket.agencyModeFk"> initial-data="$ctrl.ticket.warehouseFk">
</vn-autocomplete> </vn-autocomplete>
</vn-horizontal> </vn-horizontal>
<vn-horizontal> <vn-horizontal>
@ -53,16 +61,29 @@
</vn-horizontal> </vn-horizontal>
<vn-horizontal> <vn-horizontal>
<vn-autocomplete vn-one <vn-autocomplete vn-one
url="/api/Warehouses" url="/api/AgencyModes/isActive"
label="Warehouse" label="Agency"
show-field="name" show-field="name"
value-field="id" value-field="id"
field="$ctrl.ticket.warehouseFk" field="$ctrl.agencyModeId">
initial-data="$ctrl.ticket.warehouseFk">
</vn-autocomplete> </vn-autocomplete>
<vn-one> <vn-autocomplete vn-one
<vn-check label="Deleted" field="$ctrl.ticket.isDeleted"></vn-check> data="zones"
</vn-one> label="Zone"
show-field="name"
value-field="id"
field="$ctrl.zoneId"
vn-acl="productionBoss">
<tpl-item>
<span>{{::name}} - {{::warehouse.name}} - Max. {{::hour | dateTime: 'HH:mm'}} h.</span>
</tpl-item>
</vn-autocomplete>
</vn-horizontal>
<vn-horizontal>
<vn-check vn-one
label="Deleted"
field="$ctrl.ticket.isDeleted">
</vn-check>
</vn-horizontal> </vn-horizontal>
</vn-card> </vn-card>
</form> </form>

View File

@ -10,7 +10,11 @@ class Controller {
} }
$onInit() { $onInit() {
this.data.registerChild(this); this.basicData.registerChild(this);
}
get ticket() {
return this._ticket;
} }
set ticket(value) { set ticket(value) {
@ -18,27 +22,23 @@ class Controller {
if (!value || !value.id) return; if (!value || !value.id) return;
this.onChangeAddress(value.clientFk); this.onChangeClient(value.clientFk);
} }
get ticket() { get clientId() {
return this._ticket;
}
set clientFk(value) {
this.ticket.clientFk = value;
this.ticket.addressFk = null;
this.onChangeAddress(value);
}
get clientFk() {
if (this.ticket) if (this.ticket)
return this.ticket.clientFk; return this.ticket.clientFk;
return null; return null;
} }
set clientId(value) {
this.ticket.clientFk = value;
this.ticket.addressFk = null;
this.onChangeClient(value);
}
set shipped(value) { set shipped(value) {
this.ticket.shipped = value; this.ticket.shipped = value;
this.onChangeShipped(value); this.onChangeShipped(value);
@ -51,11 +51,6 @@ class Controller {
return null; return null;
} }
set landed(value) {
this.ticket.landed = value;
this.onChangeLanded(value);
}
get landed() { get landed() {
if (this.ticket) if (this.ticket)
return this.ticket.landed; return this.ticket.landed;
@ -63,47 +58,43 @@ class Controller {
return null; return null;
} }
onChangeShipped(value) { set landed(value) {
let params = { this.ticket.landed = value;
shipped: value, this.onChangeLanded(value);
addressFk: this.ticket.addressFk,
agencyModeFk: this.ticket.agencyModeFk,
warehouseFk: this.ticket.warehouseFk
};
let query = `/api/Agencies/getLanded`;
this.$http.get(query, {params}).then(res => {
if (res.data && res.data.landed)
this.ticket.landed = res.data.landed;
else {
return this.vnApp.showError(
this.$translate.instant(`There's no available agency for this shipping date`)
);
}
});
} }
onChangeLanded(value) { get agencyModeId() {
let params = { if (this.ticket)
landed: value, return this.ticket.agencyModeFk;
addressFk: this.ticket.addressFk,
agencyModeFk: this.ticket.agencyModeFk,
warehouseFk: this.ticket.warehouseFk
};
let query = `/api/Agencies/getShipped`; return null;
this.$http.get(query, {params}).then(res => {
if (res.data)
this.ticket.shipped = res.data;
else {
return this.vnApp.showError(
this.$translate.instant(`There's no available agency for this landing date`)
);
}
});
} }
onChangeAddress(value) { set agencyModeId(value) {
this.ticket.agencyModeFk = value;
if (value)
this.onChangeAgencyMode(value);
}
get zoneId() {
if (this.ticket)
return this.ticket.zoneFk;
return null;
}
set zoneId(value) {
this.ticket.zoneFk = value;
if (value)
this.onChangeZone(value);
}
/*
* Autocompletes address on client change
*/
onChangeClient(value) {
let filter = { let filter = {
include: [ include: [
{ {
@ -129,6 +120,96 @@ class Controller {
}); });
} }
/*
* Returns a landing date
*/
getLanded(params) {
let query = `/api/Agencies/getLanded`;
return this.$http.get(query, {params});
}
/*
* Returns a shipment date
*/
getShipped(params) {
let query = `/api/Agencies/getShipped`;
return this.$http.get(query, {params});
}
onChangeShipped(shipped) {
let params = {
shipped: shipped,
addressFk: this.ticket.addressFk,
agencyModeFk: this.ticket.agencyModeFk,
warehouseFk: this.ticket.warehouseFk
};
let query = `/api/Agencies/getLanded`;
this.$http.get(query, {params}).then(res => {
if (res.data && res.data.landed)
this.ticket.landed = res.data.landed;
else {
return this.vnApp.showError(
this.$translate.instant(`No delivery zone available for this shipping date`)
);
}
});
}
onChangeLanded(landed) {
let params = {
landed: landed,
addressFk: this.ticket.addressFk,
agencyModeFk: this.ticket.agencyModeFk,
warehouseFk: this.ticket.warehouseFk
};
let query = `/api/Agencies/getShipped`;
this.$http.get(query, {params}).then(res => {
if (res.data)
this.ticket.shipped = res.data.shipped;
else {
return this.vnApp.showError(
this.$translate.instant(`No delivery zone available for this landing date`)
);
}
});
}
/*
* Gets an agency from an specified zone
*/
onChangeZone(zoneId) {
const query = `/api/Zones/${zoneId}`;
this.$http.get(query).then(res => {
if (res.data)
this.ticket.agencyModeFk = res.data.agencyModeFk;
});
}
/*
* Gets a zone from an agency
*/
onChangeAgencyMode(agencyModeId) {
let params = {
landed: this.ticket.landed,
addressFk: this.ticket.addressFk,
agencyModeFk: agencyModeId,
warehouseFk: this.ticket.warehouseFk
};
this.ticket.zoneFk = null;
let query = `/api/Agencies/getShipped`;
this.$http.get(query, {params}).then(res => {
if (res.data)
this.ticket.zoneFk = res.data.id;
else {
return this.vnApp.showMessage(
this.$translate.instant('No delivery zone available for this parameters')
);
}
});
}
async onStepChange() { async onStepChange() {
if (this.isFormInvalid()) { if (this.isFormInvalid()) {
return this.vnApp.showError( return this.vnApp.showError(
@ -136,35 +217,31 @@ class Controller {
); );
} }
let query = `/ticket/api/sales/${this.ticket.id}/priceDifference`; let query = `/api/tickets/${this.ticket.id}/priceDifference`;
let data = { let params = {
landed: this.ticket.landed, landed: this.ticket.landed,
addressFk: this.ticket.addressFk, addressId: this.ticket.addressFk,
agencyModeFk: this.ticket.agencyModeFk, agencyModeId: this.ticket.agencyModeFk,
warehouseFk: this.ticket.warehouseFk zoneId: this.ticket.zoneFk,
warehouseId: this.ticket.warehouseFk
}; };
return this.$http.post(query, data).then(res => { return this.$http.post(query, params).then(res => {
if (res.data) if (res.data)
this.ticket.sale = res.data; this.ticket.sale = res.data;
return true; return true;
}, err => { }, err => {
if (err.data.error.message === 'NO_AGENCY_AVAILABLE') { this.vnApp.showError(
this.vnApp.showMessage( this.$translate.instant(err.data.error.message)
this.$translate.instant(`There's no available agency for this landing date`) );
);
} else {
this.vnApp.showMessage(
this.$translate.instant(err.data.error.message)
);
}
}); });
} }
isFormInvalid() { isFormInvalid() {
return !this.ticket.clientFk || !this.ticket.addressFk || !this.ticket.agencyModeFk return !this.ticket.clientFk || !this.ticket.addressFk || !this.ticket.agencyModeFk
|| !this.ticket.companyFk || !this.ticket.shipped || !this.ticket.landed; || !this.ticket.companyFk || !this.ticket.shipped || !this.ticket.landed
|| !this.ticket.zoneFk;
} }
} }
@ -177,6 +254,6 @@ ngModule.component('vnTicketBasicDataStepOne', {
ticket: '<' ticket: '<'
}, },
require: { require: {
data: '^vnTicketBasicData' basicData: '^vnTicketBasicData'
} }
}); });

View File

@ -18,21 +18,21 @@ describe('Ticket', () => {
})); }));
describe('ticket() setter', () => { describe('ticket() setter', () => {
it('should set ticket property and call onChangeAddress() method', () => { it('should set ticket property and call onChangeClient() method', () => {
spyOn(controller, 'onChangeAddress'); spyOn(controller, 'onChangeClient');
controller.ticket = {id: 1, clientFk: 101}; controller.ticket = {id: 1, clientFk: 101};
expect(controller.onChangeAddress).toHaveBeenCalledWith(101); expect(controller.onChangeClient).toHaveBeenCalledWith(101);
}); });
}); });
describe('clientFk() setter', () => { describe('clientId() setter', () => {
it('should set clientFk property and call onChangeAddress() method ', () => { it('should set clientId property and call onChangeClient() method ', () => {
spyOn(controller, 'onChangeAddress'); spyOn(controller, 'onChangeClient');
controller.ticket = {id: 1, clientFk: 101}; controller.ticket = {id: 1, clientId: 101};
controller.clientFk = 102; controller.clientId = 102;
expect(controller.onChangeAddress).toHaveBeenCalledWith(102); expect(controller.onChangeClient).toHaveBeenCalledWith(102);
}); });
}); });
@ -58,6 +58,57 @@ describe('Ticket', () => {
}); });
}); });
describe('agencyModeId() setter', () => {
it('should set agencyModeId property and call onChangeAgencyMode() method ', () => {
const agencyModeId = 8;
spyOn(controller, 'onChangeAgencyMode');
controller.ticket = {id: 1};
controller.agencyModeId = 8;
expect(controller.onChangeAgencyMode).toHaveBeenCalledWith(agencyModeId);
});
});
describe('zoneId() setter', () => {
it('should set zoneId property and call onChangeZone() method ', () => {
const zoneId = 5;
spyOn(controller, 'onChangeZone');
controller.ticket = {id: 1};
controller.zoneId = 5;
expect(controller.onChangeZone).toHaveBeenCalledWith(zoneId);
});
});
describe('onChangeClient()', () => {
it('should return a list of addresses from choosed client', async() => {
const clientId = 102;
let filter = {
include: [
{
relation: 'province',
scope: {
fields: ['name']
}
},
{
relation: 'agencyMode',
scope: {
fields: ['name']
}
}
]
};
filter = encodeURIComponent(JSON.stringify(filter));
$httpBackend.when('GET', `/api/Clients/${clientId}/addresses?filter=${filter}`).respond(200);
$httpBackend.expect('GET', `/api/Clients/${clientId}/addresses?filter=${filter}`);
controller.onChangeClient(clientId);
$httpBackend.flush();
});
});
describe('onChangeShipped()', () => { describe('onChangeShipped()', () => {
it('should return an available landing date', async() => { it('should return an available landing date', async() => {
let shipped = new Date(); let shipped = new Date();
@ -111,11 +162,51 @@ describe('Ticket', () => {
}); });
}); });
describe('onChangeZone()', () => {
it('should return an available zone', async() => {
const zoneId = 5;
$httpBackend.when('GET', `/api/Zones/${zoneId}`).respond(200);
$httpBackend.expect('GET', `/api/Zones/${zoneId}`);
controller.onChangeZone(zoneId);
$httpBackend.flush();
});
});
describe('onChangeAgencyMode()', () => {
it('should return an available agency', async() => {
const landed = new Date();
const agencyModeId = 7;
controller._ticket = {
id: 1,
landed: landed,
addressFk: 121,
agencyModeFk: agencyModeId,
warehouseFk: 1
};
let params = {
landed: landed,
addressFk: 121,
agencyModeFk: agencyModeId,
warehouseFk: 1
};
let serializedParams = $httpParamSerializer(params);
$httpBackend.when('GET', `/api/Agencies/getShipped?${serializedParams}`).respond(200);
$httpBackend.expect('GET', `/api/Agencies/getShipped?${serializedParams}`);
controller.onChangeAgencyMode(agencyModeId);
$httpBackend.flush();
});
});
describe('isFormInvalid()', () => { describe('isFormInvalid()', () => {
it('should check if all form fields are valid', () => { it('should check if all form fields are valid', () => {
controller.ticket = { controller.ticket = {
clientFk: 1, clientFk: 1,
addressFk: 121, addressFk: 121,
zoneFk: 3,
agencyModeFk: 1, agencyModeFk: 1,
companyFk: 442, companyFk: 442,
warehouseFk: 1, warehouseFk: 1,
@ -136,6 +227,7 @@ describe('Ticket', () => {
id: 1, id: 1,
clientFk: 1, clientFk: 1,
addressFk: 121, addressFk: 121,
zoneFk: 3,
agencyModeFk: 1, agencyModeFk: 1,
companyFk: 442, companyFk: 442,
warehouseFk: 1, warehouseFk: 1,
@ -145,8 +237,8 @@ describe('Ticket', () => {
let response = {error: new Error('NO_AGENCY_AVAILABLE')}; let response = {error: new Error('NO_AGENCY_AVAILABLE')};
$httpBackend.whenPOST(`/ticket/api/sales/1/priceDifference`).respond(400, response); $httpBackend.whenPOST(`/api/tickets/1/priceDifference`).respond(400, response);
$httpBackend.expectPOST(`/ticket/api/sales/1/priceDifference`); $httpBackend.expectPOST(`/api/tickets/1/priceDifference`);
controller.onStepChange(); controller.onStepChange();
$httpBackend.flush(); $httpBackend.flush();
}); });

View File

@ -1,3 +1,5 @@
There's no available agency for this landing date: No hay ninguna agencia disponible para la fecha de envío seleccionada No delivery zone available for this landing date: No hay una zona de reparto disponible para la fecha de envío seleccionada
No delivery zone available for this shipping date: No hay una zona de reparto disponible para la fecha de preparación seleccionada
No delivery zone available for this parameters: No hay una zona de reparto disponible con estos parámetros
Deleted: Eliminado Deleted: Eliminado
There's no available agency for this shipping date: No hay ninguna agencia disponible para la fecha de preparación seleccionada Zone: Zona

View File

@ -29,13 +29,14 @@ class Controller {
); );
} }
let query = `/ticket/api/tickets/${this.ticket.id}/componentUpdate`; let query = `/api/tickets/${this.ticket.id}/componentUpdate`;
let data = { let params = {
clientFk: this.ticket.clientFk, clientId: this.ticket.clientFk,
agencyModeFk: this.ticket.agencyModeFk, agencyModeId: this.ticket.agencyModeFk,
addressFk: this.ticket.addressFk, addressId: this.ticket.addressFk,
warehouseFk: this.ticket.warehouseFk, zoneId: this.ticket.zoneFk,
companyFk: this.ticket.companyFk, warehouseId: this.ticket.warehouseFk,
companyId: this.ticket.companyFk,
shipped: this.ticket.shipped, shipped: this.ticket.shipped,
landed: this.ticket.landed, landed: this.ticket.landed,
isDeleted: this.ticket.isDeleted, isDeleted: this.ticket.isDeleted,
@ -43,7 +44,7 @@ class Controller {
option: this.ticket.option option: this.ticket.option
}; };
this.$http.post(query, data).then(res => { this.$http.post(query, params).then(res => {
if (res.data) { if (res.data) {
this.$state.go('ticket.card.summary', {id: this.$state.params.id}); this.$state.go('ticket.card.summary', {id: this.$state.params.id});
this.card.reload(); this.card.reload();

View File

@ -36,6 +36,7 @@ describe('ticket', () => {
id: 1, id: 1,
agencyModeFk: 1, agencyModeFk: 1,
addressFk: 121, addressFk: 121,
zoneFk: 3,
warehouseFk: 1, warehouseFk: 1,
shipped: now, shipped: now,
landed: now, landed: now,
@ -43,16 +44,17 @@ describe('ticket', () => {
}; };
let data = { let data = {
agencyModeFk: 1, agencyModeId: 1,
addressFk: 121, addressId: 121,
warehouseFk: 1, zoneId: 3,
warehouseId: 1,
shipped: now, shipped: now,
landed: now, landed: now,
option: 1 option: 1
}; };
$httpBackend.whenPOST(`/ticket/api/tickets/1/componentUpdate`, data).respond('ok'); $httpBackend.whenPOST(`/api/tickets/1/componentUpdate`, data).respond('ok');
$httpBackend.expectPOST(`/ticket/api/tickets/1/componentUpdate`, data); $httpBackend.expectPOST(`/api/tickets/1/componentUpdate`, data);
controller.onSubmit(); controller.onSubmit();
$httpBackend.flush(); $httpBackend.flush();