Merge branch 'dev' into 3605-invoiceIn_intrastat3
gitea/salix/pipeline/head This commit looks good Details

This commit is contained in:
Carlos Jimenez Ruiz 2022-04-11 10:29:01 +00:00
commit b087d275dc
56 changed files with 504 additions and 135 deletions

View File

@ -30,8 +30,13 @@ module.exports = Self => {
const sender = await models.Account.findById(accessToken.userId);
const recipient = to.replace('@', '');
if (sender.name != recipient)
return sendMessage(sender, to, message);
if (sender.name != recipient) {
await sendMessage(sender, to, message);
return true;
}
return false;
};
async function sendMessage(sender, channel, message) {

View File

@ -5,7 +5,7 @@ module.exports = Self => {
description: 'Sends a RocketChat message to a connected user or department channel',
accessType: 'WRITE',
accepts: [{
arg: 'recipientId',
arg: 'workerId',
type: 'number',
required: true,
description: 'The recipient user id'

View File

@ -1,2 +1,2 @@
DELETE FROM salix.ACL
DELETE FROM `salix`.`ACL`
WHERE model = 'ClaimEnd' AND property = 'importTicketSales';

View File

@ -1,3 +1,3 @@
INSERT INTO salix.ACL
INSERT INTO `salix`.`ACL`
(model, property, accessType, permission, principalType, principalId)
VALUES('Collection', 'setSaleQuantity', '*', 'ALLOW', 'ROLE', 'employee');

View File

@ -1,3 +1,3 @@
INSERT INTO salix.ACL
INSERT INTO `salix`.`ACL`
(model, property, accessType, permission, principalType, principalId)
VALUES('Docuware', '*', '*', 'ALLOW', 'ROLE', 'employee');

View File

@ -1,3 +1,3 @@
UPDATE salix.defaultViewConfig
UPDATE `salix`.`defaultViewConfig`
SET `columns`='{"intrastat":false,"stemMultiplier":false,"landed":false,"producer":false}'
WHERE tableCode ='itemsIndex';

View File

@ -1,2 +1,2 @@
INSERT INTO salix.ACL (model,property,accessType,principalId)
INSERT INTO `salix`.`ACL` (model,property,accessType,principalId)
VALUES ('AgencyTerm','*','*','administrative');

View File

@ -1,3 +1 @@
UPDATE `account`.`user`
SET `role` = 57
WHERE id IN (2294, 4365, 7294);
UPDATE `account`.`user` SET `role` = 57 WHERE id IN (2294, 4365, 7294);

View File

@ -0,0 +1,149 @@
DROP PROCEDURE IF EXISTS `vn`.`ticket_doRefund`;
DELIMITER $$
$$
CREATE DEFINER=`root`@`localhost` PROCEDURE `vn`.`ticket_doRefund`(IN vOriginTicket INT, OUT vNewTicket INT)
BEGIN
DECLARE vDone BIT DEFAULT 0;
DECLARE vCustomer MEDIUMINT;
DECLARE vWarehouse TINYINT;
DECLARE vCompany MEDIUMINT;
DECLARE vAddress MEDIUMINT;
DECLARE vRefundAgencyMode INT;
DECLARE vItemFk INT;
DECLARE vQuantity DECIMAL (10,2);
DECLARE vConcept VARCHAR(50);
DECLARE vPrice DECIMAL (10,2);
DECLARE vDiscount TINYINT;
DECLARE vSaleNew INT;
DECLARE vSaleMain INT;
DECLARE vZoneFk INT;
DECLARE vRsMainTicket CURSOR FOR
SELECT *
FROM tmp.sale;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET vDone = 1;
SELECT id INTO vRefundAgencyMode
FROM agencyMode WHERE `name` = 'ABONO';
SELECT clientFk, warehouseFk, companyFk, addressFk
INTO vCustomer, vWarehouse, vCompany, vAddress
FROM ticket
WHERE id = vOriginTicket;
SELECT id INTO vZoneFk
FROM zone WHERE agencyModeFk = vRefundAgencyMode
LIMIT 1;
INSERT INTO vn.ticket (
clientFk,
shipped,
addressFk,
agencyModeFk,
nickname,
warehouseFk,
companyFk,
landed,
zoneFk
)
SELECT
vCustomer,
CURDATE(),
vAddress,
vRefundAgencyMode,
a.nickname,
vWarehouse,
vCompany,
CURDATE(),
vZoneFk
FROM address a
WHERE a.id = vAddress;
SET vNewTicket = LAST_INSERT_ID();
SET vDone := 0;
OPEN vRsMainTicket ;
FETCH vRsMainTicket INTO vSaleMain, vItemFk, vQuantity, vConcept, vPrice, vDiscount;
WHILE NOT vDone DO
INSERT INTO vn.sale(ticketFk, itemFk, quantity, concept, price, discount)
VALUES( vNewTicket, vItemFk, vQuantity, vConcept, vPrice, vDiscount );
SET vSaleNew = LAST_INSERT_ID();
INSERT INTO vn.saleComponent(saleFk,componentFk,`value`)
SELECT vSaleNew,componentFk,`value`
FROM vn.saleComponent
WHERE saleFk = vSaleMain;
FETCH vRsMainTicket INTO vSaleMain, vItemFk, vQuantity, vConcept, vPrice, vDiscount;
END WHILE;
CLOSE vRsMainTicket;
INSERT INTO vn.ticketRefund(refundTicketFk, originalTicketFk)
VALUES(vNewTicket, vOriginTicket);
END$$
DELIMITER ;
CREATE TABLE `vn`.`ticketRefund` (
`id` INT auto_increment NULL,
`refundTicketFk` INT NOT NULL,
`originalTicketFk` INT NOT NULL,
CONSTRAINT `ticketRefund_PK` PRIMARY KEY (id)
)
ENGINE=InnoDB
DEFAULT CHARSET=utf8
COLLATE=utf8_unicode_ci;
ALTER TABLE `vn`.`ticketRefund` ADD CONSTRAINT `ticketRefund_FK` FOREIGN KEY (`refundTicketFk`) REFERENCES `vn`.`ticket`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
ALTER TABLE `vn`.`ticketRefund` ADD CONSTRAINT `ticketRefund_FK_1` FOREIGN KEY (`originalTicketFk`) REFERENCES `vn`.`ticket`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
DELIMITER $$
$$
CREATE DEFINER=`root`@`localhost` TRIGGER `vn`.`ticketRefund_beforeInsert`
BEFORE INSERT ON `ticketRefund`
FOR EACH ROW
BEGIN
DECLARE vAlreadyExists BOOLEAN DEFAULT FALSE;
IF NEW.refundTicketFk = NEW.originalTicketFk THEN
CALL util.throw('Original ticket and refund ticket has same id');
END IF;
SELECT COUNT(*) INTO vAlreadyExists
FROM ticketRefund
WHERE refundTicketFk = NEW.originalTicketFk;
IF vAlreadyExists > 0 THEN
CALL util.throw('This ticket is already a refund');
END IF;
END$$
DELIMITER ;
DELIMITER $$
$$
CREATE DEFINER=`root`@`localhost` TRIGGER `vn`.`ticketRefund_beforeUpdate`
BEFORE UPDATE ON `ticketRefund`
FOR EACH ROW
BEGIN
DECLARE vAlreadyExists BOOLEAN DEFAULT FALSE;
IF NEW.refundTicketFk = NEW.originalTicketFk THEN
CALL util.throw('Original ticket and refund ticket has same id');
END IF;
SELECT COUNT(*) INTO vAlreadyExists
FROM ticketRefund
WHERE refundTicketFk = NEW.originalTicketFk;
IF vAlreadyExists > 0 THEN
CALL util.throw('This ticket is already a refund');
END IF;
END$$
DELIMITER ;

View File

@ -0,0 +1,16 @@
DROP TRIGGER `vn`.`travelThermograph_beforeInsert`;
ALTER TABLE `vn`.`travelThermograph` CHANGE `temperature` `temperature__` enum('COOL','WARM','DRY') CHARACTER SET utf8 COLLATE utf8_unicode_ci DEFAULT NULL NULL;
CREATE OR REPLACE
ALGORITHM = UNDEFINED VIEW `vn2008`.`travel_thermograph` AS
select
`tt`.`thermographFk` AS `thermograph_id`,
`tt`.`created` AS `odbc_date`,
`tt`.`warehouseFk` AS `warehouse_id`,
`tt`.`travelFk` AS `travel_id`,
`tt`.`temperatureFk` AS `temperature`,
`tt`.`result` AS `result`,
`tt`.`dmsFk` AS `gestdoc_id`
from
`vn`.`travelThermograph` `tt`;

View File

@ -0,0 +1,73 @@
DROP PROCEDURE IF EXISTS vn.timeControl_getError;
DELIMITER $$
$$
CREATE DEFINER=`root`@`localhost` PROCEDURE `vn`.`timeControl_getError`(vDatedFrom DATETIME, vDatedTo DATETIME)
BEGIN
/*
* @param vDatedFrom
* @param vDatedTo
* @table tmp.`user`(userFk)
* Fichadas incorrectas de las cuales no se puede calcular horas trabajadas
* @return tmp.timeControlError (id)
*/
DECLARE vDayMaxTime INTEGER;
SET @journeyCounter := 0;
SET @lastUserFk := NULL;
SELECT dayMaxTime INTO vDayMaxTime
FROM workerTimeControlConfig LIMIT 1;
DROP TEMPORARY TABLE IF EXISTS tmp.timeControl;
CREATE TEMPORARY TABLE tmp.timeControl
(INDEX(id), INDEX(journeyCounter))
ENGINE = MEMORY
SELECT sub.id,
sub.direction,
sub.timed,
IF(sub.direction = 'in' OR @hasOut OR sub.userFk <> @lastUserFk, @journeyCounter := @journeyCounter + 1, @journeyCounter) journeyCounter,
@lastUserFk := sub.userFk workerFk,
IF(sub.direction = 'out', @hasOut:= TRUE, @hasOut:= FALSE)
FROM (
SELECT DISTINCT wtc.id,
wtc.direction,
wtc.timed,
wtc.userFk
FROM workerTimeControl wtc
JOIN tmp.`user` w ON w.userFk = wtc.userFk
WHERE wtc.timed BETWEEN DATE_SUB(vDatedFrom, INTERVAL 1 DAY) AND DATE_ADD(vDatedTo, INTERVAL 1 DAY)
ORDER BY wtc.userFk, wtc.timed
) sub;
DROP TEMPORARY TABLE IF EXISTS tmp.timeControlAux;
CREATE TEMPORARY TABLE tmp.timeControlAux
(INDEX(id), INDEX(journeyCounter))
ENGINE = MEMORY
SELECT * FROM tmp.timeControl;
DROP TEMPORARY TABLE IF EXISTS tmp.timeControlError;
CREATE TEMPORARY TABLE tmp.timeControlError
(INDEX(id))
ENGINE = MEMORY
SELECT id
FROM tmp.timeControlAux tca
JOIN (SELECT journeyCounter,
UNIX_TIMESTAMP(MAX(timed)) - UNIX_TIMESTAMP(MIN(timed)) timeWork,
SUM(direction = 'in') totalIn,
SUM(direction = 'out') totalOut,
timed
FROM tmp.timeControl
GROUP BY journeyCounter
HAVING COUNT(*) MOD 2 = 1
OR totalIn <> 1
OR totalOut <> 1
OR timeWork >= vDayMaxTime
)sub ON sub.journeyCounter = tca.journeyCounter
WHERE sub.timed BETWEEN vDatedFrom AND vDatedTo;
DROP TEMPORARY TABLE IF EXISTS tmp.timeControl;
DROP TEMPORARY TABLE IF EXISTS tmp.timeControlAux;
END$$
DELIMITER ;

View File

View File

@ -292,10 +292,10 @@ INSERT INTO `vn`.`contactChannel`(`id`, `name`)
INSERT INTO `vn`.`client`(`id`,`name`,`fi`,`socialName`,`contact`,`street`,`city`,`postcode`,`phone`,`mobile`,`isRelevant`,`email`,`iban`,`dueDay`,`accountingAccount`,`isEqualizated`,`provinceFk`,`hasToInvoice`,`credit`,`countryFk`,`isActive`,`gestdocFk`,`quality`,`payMethodFk`,`created`,`isToBeMailed`,`contactChannelFk`,`hasSepaVnl`,`hasCoreVnl`,`hasCoreVnh`,`riskCalculated`,`clientTypeFk`,`mailAddress`,`hasToInvoiceByAddress`,`isTaxDataChecked`,`isFreezed`,`creditInsurance`,`isCreatedAsServed`,`hasInvoiceSimplified`,`salesPersonFk`,`isVies`,`eypbc`, `businessTypeFk`)
VALUES
(1101, 'Bruce Wayne', '84612325V', 'Batman', 'Alfred', '1007 Mountain Drive, Gotham', 'Silla', 46460, 1111111111, 222222222, 1, 'BruceWayne@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1, 'florist'),
(1102, 'Petter Parker', '87945234L', 'Spider man', 'Aunt May', '20 Ingram Street, Queens, USA', 'Silla', 46460, 1111111111, 222222222, 1, 'PetterParker@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1, 'florist'),
(1103, 'Clark Kent', '06815934E', 'Super man', 'lois lane', '344 Clinton Street, Apartament 3-D', 'Silla', 46460, 1111111111, 222222222, 1, 'ClarkKent@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 0, 19, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1, 'florist'),
(1104, 'Tony Stark', '06089160W', 'Iron man', 'Pepper Potts', '10880 Malibu Point, 90265', 'Silla', 46460, 1111111111, 222222222, 1, 'TonyStark@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1, 'florist'),
(1105, 'Max Eisenhardt', '251628698', 'Magneto', 'Rogue', 'Unknown Whereabouts', 'Silla', 46460, 1111111111, 222222222, 1, 'MaxEisenhardt@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 8, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 1, 1, NULL, 0, 0, 18, 0, 1, 'florist'),
(1102, 'Petter Parker', '87945234L', 'Spider man', 'Aunt May', '20 Ingram Street, Queens, USA', 'Silla', 46460, 1111111111, 222222222, 1, 'PetterParker@mydomain.com', NULL, 0, 1234567890, 0, 2, 1, 300, 1, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1, 'florist'),
(1103, 'Clark Kent', '06815934E', 'Super man', 'lois lane', '344 Clinton Street, Apartament 3-D', 'Silla', 46460, 1111111111, 222222222, 1, 'ClarkKent@mydomain.com', NULL, 0, 1234567890, 0, 3, 1, 0, 19, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1, 'florist'),
(1104, 'Tony Stark', '06089160W', 'Iron man', 'Pepper Potts', '10880 Malibu Point, 90265', 'Silla', 46460, 1111111111, 222222222, 1, 'TonyStark@mydomain.com', NULL, 0, 1234567890, 0, 2, 1, 300, 1, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1, 'florist'),
(1105, 'Max Eisenhardt', '251628698', 'Magneto', 'Rogue', 'Unknown Whereabouts', 'Silla', 46460, 1111111111, 222222222, 1, 'MaxEisenhardt@mydomain.com', NULL, 0, 1234567890, 0, 3, 1, 300, 8, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 1, 1, NULL, 0, 0, 18, 0, 1, 'florist'),
(1106, 'DavidCharlesHaller', '53136686Q', 'Legion', 'Charles Xavier', 'City of New York, New York, USA', 'Silla', 46460, 1111111111, 222222222, 1, 'DavidCharlesHaller@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 0, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 1, 0, NULL, 0, 0, 19, 0, 1, 'florist'),
(1107, 'Hank Pym', '09854837G', 'Ant man', 'Hawk', 'Anthill, San Francisco, California', 'Silla', 46460, 1111111111, 222222222, 1, 'HankPym@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 0, 0, NULL, 0, 0, 19, 0, 1, 'florist'),
(1108, 'Charles Xavier', '22641921P', 'Professor X', 'Beast', '3800 Victory Pkwy, Cincinnati, OH 45207, USA', 'Silla', 46460, 1111111111, 222222222, 1, 'CharlesXavier@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 1, 1, NULL, 0, 0, 19, 0, 1, 'florist'),
@ -2484,18 +2484,6 @@ INSERT INTO `bs`.`defaulter` (`clientFk`, `amount`, `created`, `defaulterSinced`
(1107, 500, CURDATE(), CURDATE()),
(1109, 500, CURDATE(), CURDATE());
UPDATE `vn`.`agency`
SET `supplierFk`=1
WHERE `id`=1;
UPDATE `vn`.`agency`
SET `supplierFk`=1
WHERE `id`=2;
UPDATE `vn`.`agency`
SET `supplierFk`=2
WHERE `id`=3;
UPDATE `vn`.`route`
SET `invoiceInFk`=1
WHERE `id`=1;

View File

@ -392,7 +392,6 @@ export default {
name: 'vn-item-basic-data vn-textfield[ng-model="$ctrl.item.name"]',
relevancy: 'vn-item-basic-data vn-input-number[ng-model="$ctrl.item.relevancy"]',
origin: 'vn-autocomplete[ng-model="$ctrl.item.originFk"]',
compression: 'vn-item-basic-data vn-input-number[ng-model="$ctrl.item.compression"]',
generic: 'vn-autocomplete[ng-model="$ctrl.item.genericFk"]',
isFragile: 'vn-check[ng-model="$ctrl.item.isFragile"]',
longName: 'vn-textfield[ng-model="$ctrl.item.longName"]',

View File

@ -28,7 +28,7 @@ describe('Client defaulter path', () => {
const salesPersonName =
await page.waitToGetProperty(selectors.clientDefaulter.firstSalesPersonName, 'innerText');
expect(clientName).toEqual('Batman');
expect(clientName).toEqual('Ororo Munroe');
expect(salesPersonName).toEqual('salesPersonNick');
});

View File

@ -99,8 +99,8 @@ describe('Worker time control path', () => {
expect(result).toEqual(scanTime);
});
// 3736 check proc vn.timeControl_calculate
xit(`should check Hank Pym worked 6:40 hours`, async() => {
it(`should check Hank Pym worked 6:40 hours`, async() => {
await page.waitForTextInElement(selectors.workerTimeControl.mondayWorkedHours, '06:40 h.');
});
});

View File

@ -30,8 +30,6 @@ describe('Item Edit basic data path', () => {
await page.autocompleteSearch(selectors.itemBasicData.origin, 'Spain');
await page.clearInput(selectors.itemBasicData.relevancy);
await page.write(selectors.itemBasicData.relevancy, '1');
await page.clearInput(selectors.itemBasicData.compression);
await page.write(selectors.itemBasicData.compression, '2');
await page.clearInput(selectors.itemBasicData.generic);
await page.autocompleteSearch(selectors.itemBasicData.generic, '16');
await page.waitToClick(selectors.itemBasicData.isActiveCheckbox);
@ -96,13 +94,6 @@ describe('Item Edit basic data path', () => {
expect(result).toEqual('Spain');
});
it(`should confirm the item compression was edited`, async() => {
const result = await page
.waitToGetProperty(selectors.itemBasicData.compression, 'value');
expect(result).toEqual('2');
});
it(`should confirm the item generic was edited`, async() => {
const result = await page
.waitToGetProperty(selectors.itemBasicData.generic, 'value');

View File

@ -223,5 +223,6 @@
"The item is required": "El artículo es requerido",
"The agency is already assigned to another autonomous": "La agencia ya está asignada a otro autónomo",
"date in the future": "Fecha en el futuro",
"reference duplicated": "Referencia duplicada"
"reference duplicated": "Referencia duplicada",
"This ticket is already a refund": "Este ticket ya es un abono"
}

View File

@ -27,7 +27,7 @@ module.exports = Self => {
http: {source: 'query'}
},
{
arg: 'client',
arg: 'clientName',
type: 'string',
description: 'The worker name',
http: {source: 'query'}
@ -94,14 +94,19 @@ module.exports = Self => {
? {'cl.id': value}
: {
or: [
{'cl.socialName': {like: `%${value}%`}}
{'cl.clientName': {like: `%${value}%`}}
]
};
case 'clientName':
return {'cl.clientName': {like: `%${value}%`}};
case 'clientFk':
return {'cl.clientFk': value};
case 'id':
case 'claimStateFk':
case 'priority':
return {[`cl.${param}`]: value};
case 'salesPersonFk':
return {'cl.salesPersonFk': value};
case 'attenderFk':
return {'cl.workerFk': value};
case 'created':
@ -123,13 +128,14 @@ module.exports = Self => {
SELECT
cl.id,
cl.clientFk,
c.socialName,
c.name AS clientName,
cl.workerFk,
u.name AS workerName,
cs.description,
cl.created,
cs.priority,
cl.claimStateFk
cl.claimStateFk,
c.salesPersonFk
FROM claim cl
LEFT JOIN client c ON c.id = cl.clientFk
LEFT JOIN worker w ON w.id = cl.workerFk

View File

@ -25,7 +25,7 @@ describe('claim filter()', () => {
try {
const options = {transaction: tx};
const result = await app.models.Claim.filter({args: {filter: {}, search: 'Iron man'}}, null, options);
const result = await app.models.Claim.filter({args: {filter: {}, search: 'Tony Stark'}}, null, options);
expect(result.length).toEqual(1);
expect(result[0].id).toEqual(4);

View File

@ -10,16 +10,16 @@
<table>
<thead>
<tr>
<th field="id" shrink>
<th field="clientFk" shrink>
<span translate>Id</span>
</th>
<th field="clientFk">
<th field="clientName">
<span translate>Client</span>
</th>
<th field="created" center shrink-date>
<span translate>Created</span>
</th>
<th field="salesPersonFk">
<th field="workerFk">
<span translate>Worker</span>
</th>
<th field="claimStateFk">
@ -40,7 +40,7 @@
<span
vn-click-stop="clientDescriptor.show($event, claim.clientFk)"
class="link">
{{::claim.socialName}}
{{::claim.clientName}}
</span>
</td>
<td center shrink-date>{{::claim.created | date:'dd/MM/yyyy'}}</td>

View File

@ -11,11 +11,11 @@ class Controller extends Section {
},
columns: [
{
field: 'clientFk',
field: 'clientName',
autocomplete: {
url: 'Clients',
showField: 'socialName',
valueField: 'socialName'
showField: 'name',
valueField: 'name'
}
},
{
@ -46,21 +46,12 @@ class Controller extends Section {
exprBuilder(param, value) {
switch (param) {
case 'clientName':
return {'cl.clientName': {like: `%${value}%`}};
case 'clientFk':
return {['cl.socialName']: value};
case 'id':
case 'claimStateFk':
case 'priority':
case 'workerFk':
return {[`cl.${param}`]: value};
case 'salesPersonFk':
case 'attenderFk':
return {'cl.workerFk': value};
case 'created':
value.setHours(0, 0, 0, 0);
to = new Date(value);
to.setHours(23, 59, 59, 999);
return {'cl.created': {between: [value, to]}};
}
}

View File

@ -18,7 +18,7 @@
<vn-textfield
vn-one
label="Client"
ng-model="filter.client">
ng-model="filter.clientName">
</vn-textfield>
</vn-horizontal>
<vn-horizontal>

View File

@ -0,0 +1,64 @@
module.exports = Self => {
Self.remoteMethod('checkDuplicatedData', {
description: 'Checks if a client has same email, mobile or phone than other client and send an email',
accepts: [{
arg: 'id',
type: 'number',
required: true,
description: 'The client id'
}],
returns: {
type: 'object',
root: true
},
http: {
verb: 'GET',
path: '/:id/checkDuplicatedData'
}
});
Self.checkDuplicatedData = async function(id, options) {
const myOptions = {};
if (typeof options == 'object')
Object.assign(myOptions, options);
const client = await Self.app.models.Client.findById(id, myOptions);
const emails = client.email ? client.email.split(',') : null;
const findParams = [];
if (emails.length) {
for (let email of emails)
findParams.push({email: email});
}
if (client.phone)
findParams.push({phone: client.phone});
if (client.mobile)
findParams.push({mobile: client.mobile});
const filterObj = {
where: {
and: [
{or: findParams},
{id: {neq: client.id}}
]
}
};
const clientSameData = await Self.findOne(filterObj, myOptions);
if (clientSameData) {
await Self.app.models.Mail.create({
receiver: 'direccioncomercial@verdnatura.es',
subject: `Cliente con email/teléfono/móvil duplicados`,
body: 'El cliente ' + client.id + ' comparte alguno de estos datos con el cliente ' + clientSameData.id +
'\n- Email: ' + client.email +
'\n- Teléfono: ' + client.phone +
'\n- Móvil: ' + client.mobile
}, myOptions);
}
};
};

View File

@ -0,0 +1,24 @@
const models = require('vn-loopback/server/server').models;
describe('client checkDuplicated()', () => {
it('should send an mail if mobile/phone/email is duplicated', async() => {
const tx = await models.Client.beginTransaction({});
try {
const options = {transaction: tx};
const id = 1110;
const mailModel = models.Mail;
spyOn(mailModel, 'create');
await models.Client.checkDuplicatedData(id, options);
expect(mailModel.create).toHaveBeenCalled();
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
});

View File

@ -1,9 +1,7 @@
const models = require('vn-loopback/server/server').models;
const soap = require('soap');
describe('client sendSms()', () => {
it('should now send a message and log it', async() => {
spyOn(soap, 'createClientAsync').and.returnValue('a so fake client');
const tx = await models.Client.beginTransaction({});
try {

View File

@ -6,6 +6,12 @@ describe('Address updateAddress', () => {
const provinceId = 5;
const incotermsId = 'FAS';
const customAgentOneId = 1;
const employeeId = 1;
const ctx = {
req: {
accessToken: {userId: employeeId}
}
};
it('should throw the non uee member error if no incoterms is defined', async() => {
const tx = await models.Client.beginTransaction({});
@ -14,11 +20,9 @@ describe('Address updateAddress', () => {
try {
const options = {transaction: tx};
const ctx = {
args: {
ctx.args = {
provinceFk: provinceId,
customsAgentFk: customAgentOneId
}
};
await models.Client.updateAddress(ctx, clientId, addressId, options);
@ -40,11 +44,9 @@ describe('Address updateAddress', () => {
try {
const options = {transaction: tx};
const ctx = {
args: {
ctx.args = {
provinceFk: provinceId,
incotermsFk: incotermsId
}
};
await models.Client.updateAddress(ctx, clientId, addressId, options);
@ -66,13 +68,11 @@ describe('Address updateAddress', () => {
const options = {transaction: tx};
const expectedResult = 'My edited address';
const ctx = {
args: {
ctx.args = {
provinceFk: provinceId,
nickname: expectedResult,
incotermsFk: incotermsId,
customsAgentFk: customAgentOneId
}
};
await models.Client.updateAddress(ctx, clientId, addressId, options);
@ -88,6 +88,48 @@ describe('Address updateAddress', () => {
}
});
it('should return an error for a user without enough privileges', async() => {
const tx = await models.Client.beginTransaction({});
try {
const options = {transaction: tx};
ctx.args = {
isLogifloraAllowed: true
};
await models.Client.updateAddress(ctx, clientId, addressId, options);
await tx.rollback();
} catch (e) {
await tx.rollback();
error = e;
}
expect(error.message).toEqual(`You don't have enough privileges`);
});
it('should update isLogifloraAllowed', async() => {
const tx = await models.Client.beginTransaction({});
const salesAssistantId = 21;
try {
const options = {transaction: tx};
ctx.req.accessToken.userId = salesAssistantId;
ctx.args = {
isLogifloraAllowed: true
};
await models.Client.updateAddress(ctx, clientId, addressId, options);
const address = await models.Address.findById(addressId, null, options);
expect(address.isLogifloraAllowed).toEqual(true);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it('should update the address', async() => {
const tx = await models.Client.beginTransaction({});
@ -95,10 +137,8 @@ describe('Address updateAddress', () => {
const options = {transaction: tx};
const expectedResult = 'My second time edited address';
const ctx = {
args: {
ctx.args = {
nickname: expectedResult
}
};
await models.Client.updateAddress(ctx, clientId, addressId, options);

View File

@ -26,10 +26,9 @@ describe('Client updatePortfolio', () => {
throw e;
}
});
// 3742 first have to migrate vn2008.Clientes_cedidos to vn
// task 3817
xit('should keep the same portfolioWeight when a salesperson is unassigned of a client', async() => {
const salesPersonId = 19;
const tx = await models.Client.beginTransaction({});
try {

View File

@ -68,6 +68,10 @@ module.exports = function(Self) {
{
arg: 'isEqualizated',
type: 'boolean'
},
{
arg: 'isLogifloraAllowed',
type: 'boolean'
}
],
returns: {
@ -83,11 +87,16 @@ module.exports = function(Self) {
Self.updateAddress = async(ctx, clientId, addressId, options) => {
const models = Self.app.models;
const args = ctx.args;
const userId = ctx.req.accessToken.userId;
const myOptions = {};
const isSalesAssistant = await models.Account.hasRole(userId, 'salesAssistant', myOptions);
if (typeof options == 'object')
Object.assign(myOptions, options);
if (args.isLogifloraAllowed && !isSalesAssistant)
throw new UserError(`You don't have enough privileges`);
const address = await models.Address.findOne({
where: {
id: addressId,

View File

@ -56,7 +56,7 @@ module.exports = Self => {
FROM (
SELECT
DISTINCT c.id clientFk,
c.socialName clientName,
c.name clientName,
c.salesPersonFk,
u.nickname salesPersonName,
d.amount,
@ -80,6 +80,7 @@ module.exports = Self => {
stmt.merge(conn.makeWhere(filter.where));
stmt.merge(`GROUP BY d.clientFk`);
stmt.merge(conn.makeOrderBy(filter.order));
stmt.merge(conn.makeLimit(filter));
const itemsIndex = stmts.push(stmt) - 1;
const sql = ParameterizedSQL.join(stmts, ';');

View File

@ -47,12 +47,12 @@ describe('defaulter filter()', () => {
try {
const options = {transaction: tx};
const ctx = {req: {accessToken: {userId: authUserId}}, args: {search: 'spider'}};
const ctx = {req: {accessToken: {userId: authUserId}}, args: {search: 'Petter Parker'}};
const result = await models.Defaulter.filter(ctx, null, options);
const firstRow = result[0];
expect(firstRow.clientName).toEqual('Spider man');
expect(firstRow.clientName).toEqual('Petter Parker');
await tx.rollback();
} catch (e) {

View File

@ -50,6 +50,9 @@
},
"isEqualizated": {
"type": "boolean"
},
"isLogifloraAllowed": {
"type": "boolean"
}
},
"validations": [],

View File

@ -30,6 +30,7 @@ module.exports = Self => {
require('../methods/client/consumption')(Self);
require('../methods/client/createReceipt')(Self);
require('../methods/client/updatePortfolio')(Self);
require('../methods/client/checkDuplicated')(Self);
// Validations

View File

@ -39,6 +39,12 @@
ng-model="$ctrl.address.isEqualizated"
vn-acl="administrative, salesAssistant">
</vn-check>
<vn-check
vn-one
label="Is Logiflora allowed"
ng-model="$ctrl.address.isLogifloraAllowed"
vn-acl="salesAssistant">
</vn-check>
</vn-horizontal>
<vn-horizontal>
<vn-textfield

View File

@ -60,6 +60,11 @@
ng-model="address.isEqualizated"
disabled="true">
</vn-check>
<vn-check
vn-one label="Is Logiflora allowed"
ng-model="address.isLogifloraAllowed"
disabled="true">
</vn-check>
</vn-one>
<vn-vertical
vn-one

View File

@ -17,6 +17,7 @@ class Controller extends Section {
'phone',
'mobile',
'isEqualizated',
'isLogifloraAllowed',
'postalCode'
],
order: [

View File

@ -27,3 +27,4 @@ Mobile: Móvil
# Common
Fiscal name: Nombre fiscal
Street: Dirección fiscal
Is Logiflora allowed: Compra directa en Holanda

View File

@ -6,8 +6,11 @@ class Controller extends Dialog {
super($element, $, $transclude);
this.vnReport = vnReport;
const tomorrow = new Date();
tomorrow.setDate(tomorrow.getDate() + 1);
this.receipt = {
payed: new Date()
payed: tomorrow
};
}

View File

@ -12,6 +12,7 @@ export default class Controller extends Section {
return this.$.watcher.submit().then(() => {
const query = `Clients/updatePortfolio`;
this.$http.get(query);
this.$http.get(`Clients/${this.$params.id}/checkDuplicatedData`);
});
}
}

View File

@ -10,9 +10,10 @@ export default class Controller extends Section {
}
onSubmit() {
return this.$.watcher.submit().then(
json => this.$state.go('client.card.basicData', {id: json.data.id})
);
return this.$.watcher.submit().then(json => {
this.$state.go('client.card.basicData', {id: json.data.id});
this.$http.get(`Clients/${this.client.id}/checkDuplicatedData`);
});
}
get province() {

View File

@ -49,7 +49,7 @@
model="model">
</vn-multi-check>
</th>
<th field="clientName">
<th field="clientFk">
<span translate>Client</span>
</th>
<th field="salesPersonFk">

View File

@ -13,11 +13,11 @@ export default class Controller extends Section {
},
columns: [
{
field: 'clientName',
field: 'clientFk',
autocomplete: {
url: 'Clients',
showField: 'socialName',
valueField: 'socialName'
showField: 'name',
valueField: 'id'
}
},
{
@ -114,7 +114,7 @@ export default class Controller extends Section {
switch (param) {
case 'creditInsurance':
case 'amount':
case 'clientName':
case 'clientFk':
case 'workerFk':
case 'salesPersonFk':
return {[`d.${param}`]: value};

View File

@ -104,15 +104,15 @@ describe('client defaulter', () => {
describe('exprBuilder()', () => {
it('should search by sales person', () => {
let expr = controller.exprBuilder('salesPersonFk', '5');
const expr = controller.exprBuilder('salesPersonFk', '5');
expect(expr).toEqual({'d.salesPersonFk': '5'});
});
it('should search by client name', () => {
let expr = controller.exprBuilder('clientName', '1foo');
it('should search by client', () => {
const expr = controller.exprBuilder('clientFk', '5');
expect(expr).toEqual({'d.clientName': '1foo'});
expect(expr).toEqual({'d.clientFk': '5'});
});
});
});

View File

@ -23,6 +23,7 @@ export default class Client extends ModuleMain {
case 'id':
case 'fi':
case 'postcode':
case 'provinceFk':
case 'salesPersonFk':
return {[param]: value};
}

View File

@ -67,7 +67,7 @@
</td>
<td>
<span
vn-click-stop="itemDescriptor.show($event, item.id)"
vn-click-stop="clientDescriptor.show($event, client.id)"
class="link">
{{::client.id}}
</span>
@ -83,7 +83,9 @@
</smart-table>
</vn-card>
<vn-client-descriptor-popover
vn-id="clientDescriptor">
</vn-client-descriptor-popover>
<vn-popover vn-id="filters">
<div class="vn-pa-lg">
<form ng-submit="$ctrl.onSendClientConsumption()">
@ -153,3 +155,6 @@
</vn-item>
</slot-menu>
</vn-contextmenu>
<vn-client-descriptor-popover
vn-id="clientDescriptor">
</vn-client-descriptor-popover>

View File

@ -50,6 +50,15 @@
ng-model="filter.postcode">
</vn-textfield>
</vn-horizontal>
<vn-horizontal>
<vn-autocomplete
ng-model="filter.provinceFk"
url="Provinces"
show-field="name"
value-field="id"
label="Province">
</vn-autocomplete>
</vn-horizontal>
<vn-horizontal>
<vn-textfield
vn-one

View File

@ -112,9 +112,6 @@
"itemPackingTypeFk": {
"type": "string"
},
"compression": {
"type": "number"
},
"hasKgPrice": {
"type": "boolean",
"description": "Price per Kg"

View File

@ -129,14 +129,6 @@
ng-model="$ctrl.item.density"
rule>
</vn-input-number>
<vn-input-number
vn-one
min="0"
step="0.01"
label="Compression"
ng-model="$ctrl.item.compression"
rule>
</vn-input-number>
<vn-autocomplete
vn-one
label="Generic"

View File

@ -40,7 +40,6 @@ Create: Crear
Client card: Ficha del cliente
Shipped: F. envío
stems: Tallos
Compression: Compresión
Density: Densidad
Search items by id, name or barcode: Buscar articulos por identificador, nombre o codigo de barras
SalesPerson: Comercial

View File

@ -94,9 +94,6 @@
<vn-label-value label="Density"
value="{{$ctrl.summary.item.density}}">
</vn-label-value>
<vn-label-value label="Compression"
value="{{$ctrl.summary.item.compression}}">
</vn-label-value>
<vn-label-value label="Expense"
value="{{$ctrl.summary.item.expense.name}}">
</vn-label-value>

View File

@ -1,5 +1,4 @@
const models = require('vn-loopback/server/server').models;
const soap = require('soap');
describe('ticket sendSms()', () => {
it('should send a message and log it', async() => {
@ -8,7 +7,6 @@ describe('ticket sendSms()', () => {
try {
const options = {transaction: tx};
spyOn(soap, 'createClientAsync').and.returnValue('a so fake client');
const ctx = {req: {accessToken: {userId: 9}}};
const id = 11;
const destination = 222222222;

View File

@ -20,9 +20,6 @@
"created": {
"type": "date"
},
"temperature": {
"type": "string"
},
"temperatureFk": {
"type": "string",
"required": true

View File

@ -158,7 +158,7 @@
<vn-tbody>
<vn-tr ng-repeat="thermograph in $ctrl.travelThermographs">
<vn-td>{{thermograph.thermographFk}} </vn-td>
<vn-td>{{thermograph.temperature}}</vn-td>
<vn-td>{{thermograph.temperatureFk}}</vn-td>
<vn-td>{{thermograph.result}}</vn-td>
<vn-td>{{thermograph.warehouse.name}}</vn-td>
<vn-td expand>{{thermograph.created | date: 'dd/MM/yyyy'}}</vn-td>

View File

@ -78,7 +78,7 @@
class="clickable search-result">
<vn-td number>{{::zone.id}}</vn-td>
<vn-td expand>{{::zone.name}}</vn-td>
<vn-td>{{::zone.agencyMode.name}}</vn-td>
<vn-td>{{::zone.agencyModeName}}</vn-td>
<vn-td shrink>{{::zone.hour | date: 'HH:mm'}}</vn-td>
<vn-td number>{{::zone.price | currency: 'EUR':2}}</vn-td>
<vn-td shrink>

View File

@ -104,7 +104,7 @@
"test": "jest --watch",
"back": "nodemon --inspect -w modules ./node_modules/gulp/bin/gulp.js back",
"lint": "eslint ./ --cache --ignore-pattern .gitignore",
"docker": "docker build -t salix-db ./db"
"docker": "docker build --progress=plain -t salix-db ./db"
},
"jest": {
"projects": [