Merge branch 'dev' of https://gitea.verdnatura.es/verdnatura/salix into 2056-entry_descriptor
gitea/salix/2056-entry_descriptor This commit looks good Details

This commit is contained in:
Bernat Exposito Domenech 2020-02-21 12:48:37 +01:00
commit 50a8da2064
29 changed files with 396 additions and 159 deletions

View File

@ -1,19 +1,3 @@
ALTER TABLE `vn`.`ticket` ALTER TABLE `vn`.`ticket`
ADD COLUMN `zonePrice` DECIMAL(10,2) NULL DEFAULT NULL AFTER `collectionFk`, ADD COLUMN `zonePrice` DECIMAL(10,2) NULL DEFAULT NULL AFTER `collectionFk`,
ADD COLUMN `zoneBonus` DECIMAL(10,2) NULL DEFAULT NULL AFTER `zonePrice`, ADD COLUMN `zoneBonus` DECIMAL(10,2) NULL DEFAULT NULL AFTER `zonePrice`;
ADD COLUMN `zoneClosure` TIME NULL AFTER `zoneBonus`;
CREATE TABLE `vn`.`zoneCalcTicket` (
`zoneFk` int(11) NOT NULL PRIMARY KEY,
CONSTRAINT `zoneCalcTicketfk_1` FOREIGN KEY (`zoneFk`) REFERENCES `vn`.`zone` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
DROP EVENT IF EXISTS vn.`zone_doCalc`;
CREATE DEFINER=`root`@`%` EVENT vn.`zone_doCalc`
ON SCHEDULE EVERY 15 SECOND STARTS '2020-01-31 11:32:30'
ON COMPLETION PRESERVE ENABLE
DO CALL util.procNoOverlap('vn.zone_doCalc');
DROP TABLE `vn`.`zoneConfig`;
DROP procedure IF EXISTS vn.`zoneClosure_recalc`;

View File

@ -0,0 +1,96 @@
USE `vn`;
DROP procedure IF EXISTS `ticketCreateWithUser`;
DELIMITER $$
USE `vn`$$
CREATE DEFINER=`root`@`%` PROCEDURE `ticketCreateWithUser`(
vClientId INT
,vShipped DATE
,vWarehouseFk INT
,vCompanyFk INT
,vAddressFk INT
,vAgencyModeFk INT
,vRouteFk INT
,vlanded DATE
,vUserId INT
,OUT vNewTicket INT)
BEGIN
DECLARE vZoneFk INT;
DECLARE vPrice DECIMAL(10,2);
DECLARE vBonus DECIMAL(10,2);
IF vClientId IS NULL THEN
CALL util.throw ('CLIENT_NOT_ESPECIFIED');
END IF;
IF NOT vAddressFk OR vAddressFk IS NULL THEN
SELECT id INTO vAddressFk
FROM address
WHERE clientFk = vClientId AND isDefaultAddress;
END IF;
IF vAgencyModeFk IS NOT NULL THEN
CALL vn.zone_getShippedWarehouse(vlanded, vAddressFk, vAgencyModeFk);
SELECT zoneFk, price, bonus INTO vZoneFk, vPrice, vBonus
FROM tmp.zoneGetShipped
WHERE shipped = vShipped AND warehouseFk = vWarehouseFk LIMIT 1;
IF vZoneFk IS NULL OR vZoneFk = 0 THEN
CALL util.throw ('NOT_ZONE_WITH_THIS_PARAMETERS');
END IF;
END IF;
INSERT INTO ticket (
clientFk,
shipped,
addressFk,
agencyModeFk,
nickname,
warehouseFk,
routeFk,
companyFk,
landed,
zoneFk,
zonePrice,
zoneBonus
)
SELECT
vClientId,
vShipped,
a.id,
vAgencyModeFk,
a.nickname,
vWarehouseFk,
IF(vRouteFk,vRouteFk,NULL),
vCompanyFk,
vlanded,
vZoneFk,
vPrice,
vBonus
FROM address a
JOIN agencyMode am ON am.id = a.agencyModeFk
WHERE a.id = vAddressFk;
SET vNewTicket = LAST_INSERT_ID();
INSERT INTO ticketObservation(ticketFk, observationTypeFk, description)
SELECT vNewTicket, ao.observationTypeFk, ao.description
FROM addressObservation ao
JOIN address a ON a.id = ao.addressFk
WHERE a.id = vAddressFk;
INSERT INTO vn.ticketLog
SET originFk = vNewTicket, userFk = vUserId, `action` = 'insert', description = CONCAT('Ha creado el ticket:', ' ', vNewTicket);
IF (SELECT ct.isCreatedAsServed FROM vn.clientType ct JOIN vn.client c ON c.typeFk = ct.code WHERE c.id = vClientId ) <> FALSE THEN
INSERT INTO vncontrol.inter(state_id, Id_Ticket, Id_Trabajador)
SELECT id, vNewTicket, getWorker()
FROM state
WHERE `code` = 'DELIVERED';
END IF;
END$$
DELIMITER ;

View File

@ -0,0 +1,82 @@
USE `vn`;
DROP procedure IF EXISTS `ticket_componentUpdate`;
DELIMITER $$
USE `vn`$$
CREATE DEFINER=`root`@`%` PROCEDURE `ticket_componentUpdate`(
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
DECLARE vPrice DECIMAL(10,2);
DECLARE vBonus DECIMAL(10,2);
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
ROLLBACK;
RESIGNAL;
END;
START TRANSACTION;
IF (SELECT addressFk FROM ticket WHERE id = vTicketFk) <> vAddressFk THEN
UPDATE ticket t
JOIN address a ON a.id = vAddressFk
SET t.nickname = a.nickname
WHERE t.id = vTicketFk;
END IF;
CALL vn.zone_getShippedWarehouse(vlanded, vAddressFk, vAgencyModeFk);
SELECT zoneFk, price, bonus INTO vZoneFk, vPrice, vBonus
FROM tmp.zoneGetShipped
WHERE shipped = vShipped AND warehouseFk = vWarehouseFk LIMIT 1;
UPDATE ticket t
SET
t.clientFk = vClientFk,
t.agencyModeFk = vAgencyModeFk,
t.addressFk = vAddressFk,
t.zoneFk = vZoneFk,
t.zonePrice = vPrice,
t.zoneBonus = vBonus,
t.warehouseFk = vWarehouseFk,
t.companyFk = vCompanyFk,
t.landed = vLanded,
t.shipped = vShipped,
t.isDeleted = vIsDeleted
WHERE
t.id = vTicketFk;
IF vHasToBeUnrouted THEN
UPDATE ticket t SET t.routeFk = NULL
WHERE t.id = vTicketFk;
END IF;
IF vOption <> 8 THEN
DROP TEMPORARY TABLE IF EXISTS tmp.sale;
CREATE TEMPORARY TABLE tmp.sale
(PRIMARY KEY (saleFk))
ENGINE = MEMORY
SELECT id AS saleFk, vWarehouseFk warehouseFk
FROM sale s WHERE s.ticketFk = vTicketFk;
CALL ticketComponentUpdateSale (vOption);
DROP TEMPORARY TABLE tmp.sale;
END IF;
COMMIT;
END$$
DELIMITER ;

View File

@ -1,56 +0,0 @@
USE `vn`;
DROP procedure IF EXISTS `zone_doCalc`;
DELIMITER $$
USE `vn`$$
CREATE DEFINER=`root`@`%` PROCEDURE `zone_doCalc`()
proc: BEGIN
/**
* Updates ticket fields related with zone
*/
DECLARE vDone BOOL;
DECLARE vTicketFk INT;
DECLARE vShipped DATE;
DECLARE vZoneFk INT;
DECLARE cCur CURSOR FOR
SELECT t.id, t.shipped, t.zoneFk
FROM zoneCalcTicket zct
JOIN ticket t ON t.zoneFk = zct.zoneFk
WHERE shipped >= CURDATE();
DECLARE CONTINUE HANDLER FOR NOT FOUND
SET vDone = TRUE;
OPEN cCur;
myLoop: LOOP
SET vDone = FALSE;
FETCH cCur INTO vTicketFk, vShipped, vZoneFk;
IF vDone THEN
LEAVE myLoop;
END IF;
DROP TEMPORARY TABLE IF EXISTS tmp.zone;
CREATE TEMPORARY TABLE tmp.zone
(INDEX (id))
ENGINE = MEMORY
SELECT vZoneFk id;
CALL zone_getOptionsForShipment(vShipped, TRUE);
UPDATE ticket t
LEFT JOIN tmp.zoneOption zo ON TRUE
SET zonePrice = zo.price, zoneBonus = zo.bonus, zoneClosure = zo.`hour`
WHERE t.id = vTicketFk;
END LOOP;
CLOSE cCur;
DELETE FROM zoneCalcTicket;
END$$
DELIMITER ;

View File

@ -0,0 +1,49 @@
USE `vn`;
DROP procedure IF EXISTS `zoneClosure_recalc`;
DELIMITER $$
USE `vn`$$
CREATE DEFINER=`root`@`%` PROCEDURE `zoneClosure_recalc`()
proc: BEGIN
/**
* Recalculates the delivery time (hour) for every zone in days + scope in future
*/
DECLARE vScope INT;
DECLARE vCounter INT DEFAULT 0;
DECLARE vShipped DATE DEFAULT CURDATE();
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
BEGIN
DO RELEASE_LOCK('vn.zoneClosure_recalc');
RESIGNAL;
END;
IF NOT GET_LOCK('vn.zoneClosure_recalc', 0) THEN
LEAVE proc;
END IF;
SELECT scope INTO vScope
FROM zoneConfig;
DROP TEMPORARY TABLE IF EXISTS tmp.zone;
CREATE TEMPORARY TABLE tmp.zone
(INDEX (id))
ENGINE = MEMORY
SELECT id FROM zone;
TRUNCATE TABLE zoneClosure;
WHILE vCounter <= vScope DO
CALL zone_getOptionsForShipment(vShipped, TRUE);
INSERT INTO zoneClosure(zoneFk, dated, `hour`)
SELECT zoneFk, vShipped, `hour` FROM tmp.zoneOption;
SET vCounter = vCounter + 1;
SET vShipped = TIMESTAMPADD(DAY, 1, vShipped);
END WHILE;
DROP TEMPORARY TABLE tmp.zone;
DO RELEASE_LOCK('vn.zoneClosure_recalc');
END$$
DELIMITER ;

View File

@ -7,6 +7,7 @@ CREATE DEFINER=`root`@`%` PROCEDURE `zone_doCalcInitialize`()
proc: BEGIN proc: BEGIN
/** /**
* Initialize ticket * Initialize ticket
* si en 01-07-20 aun esta este proc, kkear
*/ */
DECLARE vDone BOOL; DECLARE vDone BOOL;
DECLARE vTicketFk INT; DECLARE vTicketFk INT;
@ -16,7 +17,7 @@ proc: BEGIN
DECLARE cCur CURSOR FOR DECLARE cCur CURSOR FOR
SELECT t.id, t.landed, t.zoneFk SELECT t.id, t.landed, t.zoneFk
FROM ticket t FROM ticket t
WHERE (zonePrice IS NULL OR zoneBonus IS NULL OR zoneClosure IS NULL) WHERE (zonePrice IS NULL OR zoneBonus IS NULL)
AND landed >= '2019-01-01' AND shipped >= '2019-01-01' AND landed >= '2019-01-01' AND shipped >= '2019-01-01'
GROUP BY landed, zoneFk; GROUP BY landed, zoneFk;
@ -43,12 +44,12 @@ proc: BEGIN
UPDATE ticket t UPDATE ticket t
LEFT JOIN tmp.zoneOption zo ON TRUE LEFT JOIN tmp.zoneOption zo ON TRUE
SET zonePrice = zo.price, zoneBonus = zo.bonus, zoneClosure = zo.`hour` SET zonePrice = zo.price, zoneBonus = zo.bonus
WHERE t.zoneFk = vZoneFk AND landed = vLanded; WHERE t.zoneFk = vZoneFk AND landed = vLanded;
UPDATE ticket t UPDATE ticket t
LEFT JOIN vn.zone z ON z.id = t.zoneFk LEFT JOIN vn.zone z ON z.id = t.zoneFk
SET zonePrice = z.price, zoneBonus = z.bonus, zoneClosure = z.`hour` SET zonePrice = z.price, zoneBonus = z.bonus
WHERE t.zonePrice IS NULL AND z.id = vZoneFk WHERE t.zonePrice IS NULL AND z.id = vZoneFk
AND landed >= '2019-01-01' AND shipped >= '2019-01-01'; AND landed >= '2019-01-01' AND shipped >= '2019-01-01';
@ -56,7 +57,6 @@ proc: BEGIN
CLOSE cCur; CLOSE cCur;
DELETE FROM zoneCalcTicket;
END$$ END$$
DELIMITER ; DELIMITER ;

View File

@ -6,7 +6,7 @@ USE `vn`$$
CREATE DEFINER=`root`@`%` PROCEDURE `zone_getShippedWarehouse`(vLanded DATE, vAddressFk INT, vAgencyModeFk INT) CREATE DEFINER=`root`@`%` PROCEDURE `zone_getShippedWarehouse`(vLanded DATE, vAddressFk INT, vAgencyModeFk INT)
BEGIN BEGIN
/** /**
* Devuelve la ­nima fecha de envío para cada warehouse * Devuelve la ƒÂ­nima fecha de envío para cada warehouse
* *
* @param vLanded La fecha de recepcion * @param vLanded La fecha de recepcion
* @param vAddressFk Id del consignatario * @param vAddressFk Id del consignatario
@ -25,7 +25,9 @@ BEGIN
TIMESTAMPADD(DAY,-zo.travelingDays, vLanded) shipped, TIMESTAMPADD(DAY,-zo.travelingDays, vLanded) shipped,
zo.`hour`, zo.`hour`,
zw.warehouseFk, zw.warehouseFk,
z.agencyModeFk z.agencyModeFk,
zo.price,
zo.bonus
FROM tmp.zoneOption zo FROM tmp.zoneOption zo
JOIN zoneWarehouse zw ON zw.zoneFk = zo.zoneFk JOIN zoneWarehouse zw ON zw.zoneFk = zo.zoneFk
JOIN zone z ON z.id = zo.zoneFk JOIN zone z ON z.id = zo.zoneFk

View File

@ -498,6 +498,8 @@ INSERT INTO `vn`.`zoneWarehouse` (`id`, `zoneFk`, `warehouseFk`)
(11, 11, 5), (11, 11, 5),
(12, 12, 4), (12, 12, 4),
(13, 13, 5); (13, 13, 5);
INSERT INTO `vn`.`zoneConfig` (`scope`) VALUES ('1');
INSERT INTO `vn`.`route`(`id`, `time`, `workerFk`, `created`, `vehicleFk`, `agencyModeFk`, `description`, `m3`, `cost`, `started`, `finished`, `zoneFk`) INSERT INTO `vn`.`route`(`id`, `time`, `workerFk`, `created`, `vehicleFk`, `agencyModeFk`, `description`, `m3`, `cost`, `started`, `finished`, `zoneFk`)
VALUES VALUES
@ -1530,7 +1532,7 @@ INSERT INTO `vn`.`ticketRequest`(`id`, `description`, `requesterFk`, `attenderFk
VALUES VALUES
(1, 'Ranged weapon longbow 2m', 18, 35, 5, 1, 9.10, 1, 1, 1, DATE_ADD(CURDATE(), INTERVAL -15 DAY)), (1, 'Ranged weapon longbow 2m', 18, 35, 5, 1, 9.10, 1, 1, 1, DATE_ADD(CURDATE(), INTERVAL -15 DAY)),
(2, 'Melee weapon combat first 15cm', 18, 35, 10, 2, 1.07, 0, NULL, 1, DATE_ADD(CURDATE(), INTERVAL -15 DAY)), (2, 'Melee weapon combat first 15cm', 18, 35, 10, 2, 1.07, 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)), (3, 'Melee weapon heavy shield 1x0.5m', 18, 35, 20, NULL, 3.06, NULL, NULL, 23, CURDATE()),
(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()),
(5, 'Melee weapon combat first 15cm', 18, 35, 15, 4, 1.30, 0, NULL, 18, CURDATE()); (5, 'Melee weapon combat first 15cm', 18, 35, 15, 4, 1.30, 0, NULL, 18, CURDATE());

View File

@ -179,6 +179,13 @@ let actions = {
await this.click(selector); await this.click(selector);
}, },
writeOnEditableTD: async function(selector, text) {
let builtSelector = await this.selectorFormater(selector);
await this.waitToClick(selector);
await this.type(builtSelector, text);
await this.keyboard.press('Enter');
},
focusElement: async function(selector) { focusElement: async function(selector) {
await this.wait(selector); await this.wait(selector);
return await this.evaluate(selector => { return await this.evaluate(selector => {
@ -284,22 +291,14 @@ let actions = {
}, {}, selector, text); }, {}, selector, text);
}, },
selectorFormater: async function(selector) { selectorFormater: function(selector) {
let builtSelector = `${selector} input`;
if (selector.includes('vn-autocomplete'))
return builtSelector = `${selector} input`;
if (selector.includes('vn-textarea')) if (selector.includes('vn-textarea'))
return builtSelector = `${selector} textarea`; return `${selector} textarea`;
if (selector.includes('vn-textfield'))
return builtSelector = `${selector} input`;
if (selector.includes('vn-input-file')) if (selector.includes('vn-input-file'))
return builtSelector = `${selector} section`; return `${selector} section`;
return builtSelector; return `${selector} input`;
}, },
waitForTextInField: async function(selector, text) { waitForTextInField: async function(selector, text) {

View File

@ -250,6 +250,17 @@ export default {
inactiveIcon: 'vn-item-descriptor vn-icon[icon="icon-unavailable"]', inactiveIcon: 'vn-item-descriptor vn-icon[icon="icon-unavailable"]',
navigateBackToIndex: 'vn-item-descriptor vn-icon[icon="chevron_left"]' navigateBackToIndex: 'vn-item-descriptor vn-icon[icon="chevron_left"]'
}, },
itemRequest: {
firstRequestItemID: 'vn-item-request vn-tbody > vn-tr:nth-child(1) > vn-td-editable:nth-child(7)',
firstRequestQuantity: 'vn-item-request vn-tbody > vn-tr:nth-child(1) > vn-td-editable:nth-child(8)',
firstRequestConcept: 'vn-item-request vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(9)',
secondRequestStatus: 'vn-item-request vn-tbody > vn-tr:nth-child(2) > vn-td:nth-child(10)',
firstRequestStatus: 'vn-item-request vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(10)',
secondRequestDecline: 'vn-item-request vn-tbody > vn-tr:nth-child(1) vn-icon-button[icon="thumb_down"]',
declineReason: 'vn-textarea[ng-model="$ctrl.denyObservation"]',
acceptDeclineReason: 'button[response="accept"]',
},
itemBasicData: { itemBasicData: {
basicDataButton: 'vn-left-menu a[ui-sref="item.card.basicData"]', basicDataButton: 'vn-left-menu a[ui-sref="item.card.basicData"]',
goToItemIndexButton: 'vn-item-descriptor [ui-sref="item.index"]', goToItemIndexButton: 'vn-item-descriptor [ui-sref="item.index"]',

View File

@ -0,0 +1,48 @@
import selectors from '../../helpers/selectors.js';
import getBrowser from '../../helpers/puppeteer';
describe('Item request path', () => {
let browser;
let page;
beforeAll(async() => {
browser = await getBrowser();
page = browser.page;
await page.loginAndModule('buyer', 'item');
await page.accessToSection('item.request');
});
afterAll(async() => {
await browser.close();
});
it('should reach the item request section', async() => {
const result = await page.expectURL('/item/request');
expect(result).toBe(true);
});
it('should fill the id and quantity then check the concept was updated', async() => {
await page.writeOnEditableTD(selectors.itemRequest.firstRequestItemID, '4');
await page.writeOnEditableTD(selectors.itemRequest.firstRequestQuantity, '10');
await page.waitForTextInElement(selectors.itemRequest.firstRequestConcept, 'Melee weapon heavy shield 1x0.5m');
let filledConcept = await page.waitToGetProperty(selectors.itemRequest.firstRequestConcept, 'innerText');
expect(filledConcept).toContain('Melee weapon heavy shield 1x0.5m');
});
it('should the status of the request should now be accepted', async() => {
let status = await page.waitToGetProperty(selectors.itemRequest.firstRequestStatus, 'innerText');
expect(status).toContain('Aceptada');
});
it('should now click on the second declain request icon then type the reason', async() => {
await page.waitToClick(selectors.itemRequest.secondRequestDecline);
await page.write(selectors.itemRequest.declineReason, 'not quite as expected');
await page.waitToClick(selectors.itemRequest.acceptDeclineReason);
await page.waitForContentLoaded();
let status = await page.waitToGetProperty(selectors.itemRequest.firstRequestStatus, 'innerText');
expect(status).toContain('Denegada');
});
});

View File

@ -15,7 +15,7 @@ export function directive($parse) {
const element = $element[0]; const element = $element[0];
$element.on('click', () => { $element.on('click', () => {
const controller = element.$ctrl; const controller = element.$ctrl;
controller.$oldDisabled = field.$ctrl.disabled; controller.$oldDisabled = controller.disabled;
controller.disabled = true; controller.disabled = true;
cb($scope).finally(() => { cb($scope).finally(() => {

View File

@ -11,7 +11,7 @@
"Zone": { "Zone": {
"dataSource": "vn" "dataSource": "vn"
}, },
"ZoneCalcTicket": { "ZoneClosure": {
"dataSource": "vn" "dataSource": "vn"
}, },
"ZoneEvent": { "ZoneEvent": {

View File

@ -1,6 +1,5 @@
const app = require('vn-loopback/server/server'); const app = require('vn-loopback/server/server');
module.exports = Self => { module.exports = Self => {
app.on('started', function() { app.on('started', function() {
let models = ['Zone', 'ZoneEvent', 'ZoneExclusion']; let models = ['Zone', 'ZoneEvent', 'ZoneExclusion'];
@ -14,10 +13,13 @@ module.exports = Self => {
async function doCalc(ctx) { async function doCalc(ctx) {
try { try {
await Self.create({zoneFk: ctx.instance.zoneFk || ctx.instance.id}); await Self.rawSql(`
CREATE EVENT zoneClosure_doRecalc
ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 15 SECOND
DO CALL zoneClosure_recalc;
`);
} catch (err) { } catch (err) {
if (err.code != 'ER_DUP_ENTRY') if (err.code != 'ER_EVENT_ALREADY_EXISTS') throw err;
throw err;
} }
} }
}); });

View File

@ -1,15 +1,23 @@
{ {
"name": "ZoneCalcTicket", "name": "ZoneClosure",
"base": "VnModel", "base": "VnModel",
"options": { "options": {
"mysql": { "mysql": {
"table": "zoneCalcTicket" "table": "zoneClosure"
} }
}, },
"properties": { "properties": {
"zoneFk": { "zoneFk": {
"id": true, "id": true,
"type": "Number" "type": "Number"
},
"dated": {
"type": "Date",
"required": true
},
"hour": {
"type": "date",
"required": true
} }
}, },
"relations": { "relations": {

View File

@ -5,60 +5,60 @@ module.exports = function(Self) {
description: 'Creates client address updating default address', description: 'Creates client address updating default address',
accepts: [{ accepts: [{
arg: 'id', arg: 'id',
type: 'Number', type: 'number',
description: 'The client id', description: 'The client id',
http: {source: 'path'} http: {source: 'path'}
}, },
{ {
arg: 'nickname', arg: 'nickname',
type: 'String', type: 'string',
required: true required: true
}, },
{ {
arg: 'city', arg: 'city',
type: 'String', type: 'string',
required: true required: true
}, },
{ {
arg: 'street', arg: 'street',
type: 'String', type: 'string',
required: true required: true
}, },
{ {
arg: 'phone', arg: 'phone',
type: 'String' type: 'string'
}, },
{ {
arg: 'mobile', arg: 'mobile',
type: 'String' type: 'string'
}, },
{ {
arg: 'postalCode', arg: 'postalCode',
type: 'String' type: 'string'
}, },
{ {
arg: 'provinceId', arg: 'provinceId',
type: 'Number' type: 'number'
}, },
{ {
arg: 'agencyModeId', arg: 'agencyModeId',
type: 'Number' type: 'number'
}, },
{ {
arg: 'incotermsId', arg: 'incotermsId',
type: 'String' type: 'string'
}, },
{ {
arg: 'customsAgentId', arg: 'customsAgentId',
type: 'Number' type: 'number'
}, },
{ {
arg: 'isActive', arg: 'isActive',
type: 'Boolean' type: 'boolean'
}, },
{ {
arg: 'isDefaultAddress', arg: 'isDefaultAddress',
type: 'Boolean' type: 'boolean'
}], }],
returns: { returns: {
root: true, root: true,

View File

@ -10,63 +10,63 @@ module.exports = function(Self) {
}, },
{ {
arg: 'clientId', arg: 'clientId',
type: 'Number', type: 'number',
description: 'The client id', description: 'The client id',
http: {source: 'path'} http: {source: 'path'}
}, },
{ {
arg: 'addressId', arg: 'addressId',
type: 'Number', type: 'number',
description: 'The address id', description: 'The address id',
http: {source: 'path'} http: {source: 'path'}
}, },
{ {
arg: 'nickname', arg: 'nickname',
type: 'String' type: 'string'
}, },
{ {
arg: 'city', arg: 'city',
type: 'String' type: 'string'
}, },
{ {
arg: 'street', arg: 'street',
type: 'String' type: 'string'
}, },
{ {
arg: 'phone', arg: 'phone',
type: 'String' type: 'any'
}, },
{ {
arg: 'mobile', arg: 'mobile',
type: 'String' type: 'any'
}, },
{ {
arg: 'postalCode', arg: 'postalCode',
type: 'String' type: 'any'
}, },
{ {
arg: 'provinceFk', arg: 'provinceFk',
type: 'Number' type: 'any'
}, },
{ {
arg: 'agencyModeFk', arg: 'agencyModeFk',
type: 'Number' type: 'any'
}, },
{ {
arg: 'incotermsFk', arg: 'incotermsFk',
type: 'String' type: 'any'
}, },
{ {
arg: 'customsAgentFk', arg: 'customsAgentFk',
type: 'Number' type: 'any'
}, },
{ {
arg: 'isActive', arg: 'isActive',
type: 'Boolean' type: 'boolean'
}, },
{ {
arg: 'isEqualizated', arg: 'isEqualizated',
type: 'Boolean' type: 'boolean'
}], }],
returns: { returns: {
root: true, root: true,

View File

@ -17,75 +17,75 @@ module.exports = Self => {
}, },
{ {
arg: 'socialName', arg: 'socialName',
type: 'String' type: 'string'
}, },
{ {
arg: 'fi', arg: 'fi',
type: 'String' type: 'string'
}, },
{ {
arg: 'street', arg: 'street',
type: 'String' type: 'string'
}, },
{ {
arg: 'postcode', arg: 'postcode',
type: 'String' type: 'string'
}, },
{ {
arg: 'city', arg: 'city',
type: 'String' type: 'string'
}, },
{ {
arg: 'countryFk', arg: 'countryFk',
type: 'Number' type: 'number'
}, },
{ {
arg: 'provinceFk', arg: 'provinceFk',
type: 'Number' type: 'number'
}, },
{ {
arg: 'hasToInvoiceByAddress', arg: 'hasToInvoiceByAddress',
type: 'Boolean' type: 'boolean'
}, },
{ {
arg: 'hasToInvoice', arg: 'hasToInvoice',
type: 'Boolean' type: 'boolean'
}, },
{ {
arg: 'isActive', arg: 'isActive',
type: 'Boolean' type: 'boolean'
}, },
{ {
arg: 'isFreezed', arg: 'isFreezed',
type: 'Boolean' type: 'boolean'
}, },
{ {
arg: 'isVies', arg: 'isVies',
type: 'Boolean' type: 'boolean'
}, },
{ {
arg: 'isToBeMailed', arg: 'isToBeMailed',
type: 'Boolean' type: 'boolean'
}, },
{ {
arg: 'isEqualizated', arg: 'isEqualizated',
type: 'Boolean' type: 'boolean'
}, },
{ {
arg: 'isTaxDataVerified', arg: 'isTaxDataVerified',
type: 'Boolean' type: 'boolean'
}, },
{ {
arg: 'isTaxDataChecked', arg: 'isTaxDataChecked',
type: 'Boolean' type: 'boolean'
}, },
{ {
arg: 'despiteOfClient', arg: 'despiteOfClient',
type: 'Number' type: 'number'
}], }],
returns: { returns: {
arg: 'res', arg: 'res',
type: 'String', type: 'string',
root: true root: true
}, },
http: { http: {

View File

@ -55,10 +55,11 @@ class Controller extends Component {
} }
showSMSDialog() { showSMSDialog() {
const phone = this.$params.phone || this.client.phone; const client = this.client;
const phone = this.$params.phone || client.mobile || client.phone;
const message = this.$params.message || ''; const message = this.$params.message || '';
this.newSMS = { this.newSMS = {
destinationFk: this.client.id, destinationFk: client.id,
destination: phone, destination: phone,
message: message message: message
}; };

View File

@ -85,7 +85,7 @@
<vn-td> <vn-td>
<vn-icon <vn-icon
ng-if="request.response.length" ng-if="request.response.length"
ranslate-attr="{title: request.response}" translate-attr="{title: request.response}"
icon="insert_drive_file"> icon="insert_drive_file">
</vn-icon> </vn-icon>
<vn-icon-button <vn-icon-button

View File

@ -1,12 +1,12 @@
const app = require('vn-loopback/server/server'); const app = require('vn-loopback/server/server');
describe('ticket-request filter()', () => { describe('ticket-request filter()', () => {
it('should return all ticket requests', async() => { it('should now return all ticket requests', async() => {
let ctx = {req: {accessToken: {userId: 9}}, args: {}}; let ctx = {req: {accessToken: {userId: 9}}, args: {}};
let result = await app.models.TicketRequest.filter(ctx); let result = await app.models.TicketRequest.filter(ctx);
expect(result.length).toEqual(2); expect(result.length).toEqual(3);
}); });
it('should return the ticket request matching a generic search value which is the ticket ID', async() => { it('should return the ticket request matching a generic search value which is the ticket ID', async() => {
@ -42,7 +42,7 @@ describe('ticket-request filter()', () => {
let result = await app.models.TicketRequest.filter(ctx); let result = await app.models.TicketRequest.filter(ctx);
let requestId = result[0].id; let requestId = result[0].id;
expect(requestId).toEqual(4); expect(requestId).toEqual(3);
}); });
it('should return the ticket request matching the isOk triple-state', async() => { it('should return the ticket request matching the isOk triple-state', async() => {
@ -51,7 +51,7 @@ describe('ticket-request filter()', () => {
let result = await app.models.TicketRequest.filter(ctx); let result = await app.models.TicketRequest.filter(ctx);
let requestId = result[0].id; let requestId = result[0].id;
expect(requestId).toEqual(4); expect(requestId).toEqual(3);
}); });
it('should return the ticket request matching the client ID', async() => { it('should return the ticket request matching the client ID', async() => {
@ -69,7 +69,7 @@ describe('ticket-request filter()', () => {
let result = await app.models.TicketRequest.filter(ctx); let result = await app.models.TicketRequest.filter(ctx);
let requestId = result[0].id; let requestId = result[0].id;
expect(requestId).toEqual(4); expect(requestId).toEqual(3);
}); });
it('should return the ticket request matching the salesPerson ID', async() => { it('should return the ticket request matching the salesPerson ID', async() => {
@ -78,6 +78,6 @@ describe('ticket-request filter()', () => {
let result = await app.models.TicketRequest.filter(ctx); let result = await app.models.TicketRequest.filter(ctx);
let requestId = result[0].id; let requestId = result[0].id;
expect(requestId).toEqual(4); expect(requestId).toEqual(3);
}); });
}); });

View File

@ -108,8 +108,10 @@ module.exports = Self => {
await Promise.all(promises); await Promise.all(promises);
query = `call vn.manaSpellersRequery(?)`; if (salesPersonId) {
await Self.rawSql(query, [salesPersonId], options); const query = `call vn.manaSpellersRequery(?)`;
await Self.rawSql(query, [salesPersonId], options);
}
await tx.commit(); await tx.commit();
} catch (error) { } catch (error) {

View File

@ -27,7 +27,9 @@ class Controller extends ModuleCard {
'isFreezed', 'isFreezed',
'isTaxDataChecked', 'isTaxDataChecked',
'credit', 'credit',
'email' 'email',
'phone',
'mobile'
], ],
include: { include: {
relation: 'salesPerson', relation: 'salesPerson',

View File

@ -241,7 +241,9 @@ class Controller extends Component {
showSMSDialog() { showSMSDialog() {
const address = this.ticket.address; const address = this.ticket.address;
const phone = this.$params.phone || address.mobile; const client = this.ticket.client;
const phone = this.$params.phone || address.mobile || address.phone ||
client.mobile || client.phone;
const message = this.$params.message || this.$translate.instant('SMSPayment'); const message = this.$params.message || this.$translate.instant('SMSPayment');
this.newSMS = { this.newSMS = {
destinationFk: this.ticket.clientFk, destinationFk: this.ticket.clientFk,

View File

@ -431,6 +431,9 @@ class Controller {
showSMSDialog() { showSMSDialog() {
const address = this.ticket.address; const address = this.ticket.address;
const client = this.ticket.client;
const phone = address.mobile || address.phone ||
client.mobile || client.phone;
const sales = this.checkedLines(); const sales = this.checkedLines();
const items = sales.map(sale => { const items = sales.map(sale => {
return `${sale.quantity} ${sale.concept}`; return `${sale.quantity} ${sale.concept}`;
@ -443,7 +446,7 @@ class Controller {
}; };
this.newSMS = { this.newSMS = {
destinationFk: this.ticket.clientFk, destinationFk: this.ticket.clientFk,
destination: address.mobile || null, destination: phone,
message: this.$translate.instant('SMSAvailability', params) message: this.$translate.instant('SMSAvailability', params)
}; };
this.$scope.sms.open(); this.$scope.sms.open();