diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6787410bb..93269cdb7 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed
- [Reclamaciones](Descriptor) Cambiado el campo Agencia por Zona
+- [Tickets](Líneas preparadas) Actualizada sección para que sea más visual
### Fixed
- [General] Al utilizar el traductor de Google se descuadraban los iconos
diff --git a/back/methods/osticket/closeTicket.js b/back/methods/osticket/closeTicket.js
index 33fe5958b..178b09601 100644
--- a/back/methods/osticket/closeTicket.js
+++ b/back/methods/osticket/closeTicket.js
@@ -25,36 +25,36 @@ module.exports = Self => {
return false;
const con = mysql.createConnection({
- host: `${config.hostDb}`,
- user: `${config.userDb}`,
- password: `${config.passwordDb}`,
- port: `${config.portDb}`
+ host: config.hostDb,
+ user: config.userDb,
+ password: config.passwordDb,
+ port: config.portDb
});
const sql = `SELECT ot.ticket_id, ot.number
FROM osticket.ost_ticket ot
- JOIN osticket.ost_ticket_status ots ON ots.id = ot.status_id
+ JOIN osticket.ost_ticket_status ots ON ots.id = ot.status_id
JOIN osticket.ost_thread ot2 ON ot2.object_id = ot.ticket_id AND ot2.object_type = 'T'
JOIN (
SELECT ote.thread_id, MAX(ote.created) created, MAX(ote.updated) updated
FROM osticket.ost_thread_entry ote
- WHERE ote.staff_id != 0 AND ote.type = 'R'
+ WHERE ote.staff_id AND ote.type = 'R'
GROUP BY ote.thread_id
- ) sub ON sub.thread_id = ot2.id
- WHERE ot.isanswered = 1
- AND ots.state = '${config.oldStatus}'
- AND IF(sub.updated > sub.created, sub.updated, sub.created) < DATE_SUB(CURDATE(), INTERVAL ${config.day} DAY)`;
+ ) sub ON sub.thread_id = ot2.id
+ WHERE ot.isanswered
+ AND ots.state = ?
+ AND IF(sub.updated > sub.created, sub.updated, sub.created) < DATE_SUB(CURDATE(), INTERVAL ? DAY)`;
- let ticketsId = [];
+ const ticketsId = [];
con.connect(err => {
if (err) throw err;
- con.query(sql, (err, results) => {
- if (err) throw err;
- for (const result of results)
- ticketsId.push(result.ticket_id);
- });
+ con.query(sql, [config.oldStatus, config.day],
+ (err, results) => {
+ if (err) throw err;
+ for (const result of results)
+ ticketsId.push(result.ticket_id);
+ });
});
-
await getRequestToken();
async function getRequestToken() {
@@ -94,6 +94,44 @@ module.exports = Self => {
await close(token, secondCookie);
}
+ async function close(token, secondCookie) {
+ for (const ticketId of ticketsId) {
+ try {
+ const lock = await getLockCode(token, secondCookie, ticketId);
+ if (!lock.code) {
+ let error = `Can't get lock code`;
+ if (lock.msg) error += `: ${lock.msg}`;
+ throw new Error(error);
+ }
+ let form = new FormData();
+ form.append('__CSRFToken__', token);
+ form.append('id', ticketId);
+ form.append('a', config.responseType);
+ form.append('lockCode', lock.code);
+ form.append('from_email_id', config.fromEmailId);
+ form.append('reply-to', config.replyTo);
+ form.append('cannedResp', 0);
+ form.append('response', config.comment);
+ form.append('signature', 'none');
+ form.append('reply_status_id', config.newStatusId);
+
+ const ostUri = `${config.host}/tickets.php?id=${ticketId}`;
+ const params = {
+ method: 'POST',
+ body: form,
+ headers: {
+ 'Cookie': secondCookie
+ }
+ };
+ await fetch(ostUri, params);
+ } catch (e) {
+ const err = new Error(`${ticketId} Ticket close failed: ${e.message}`);
+ err.stack += e.stack;
+ console.error(err);
+ }
+ }
+ }
+
async function getLockCode(token, secondCookie, ticketId) {
const ostUri = `${config.host}/ajax.php/lock/ticket/${ticketId}`;
const params = {
@@ -107,34 +145,7 @@ module.exports = Self => {
const body = await response.text();
const json = JSON.parse(body);
- return json.code;
- }
-
- async function close(token, secondCookie) {
- for (const ticketId of ticketsId) {
- const lockCode = await getLockCode(token, secondCookie, ticketId);
- let form = new FormData();
- form.append('__CSRFToken__', token);
- form.append('id', ticketId);
- form.append('a', config.responseType);
- form.append('lockCode', lockCode);
- form.append('from_email_id', config.fromEmailId);
- form.append('reply-to', config.replyTo);
- form.append('cannedResp', 0);
- form.append('response', config.comment);
- form.append('signature', 'none');
- form.append('reply_status_id', config.newStatusId);
-
- const ostUri = `${config.host}/tickets.php?id=${ticketId}`;
- const params = {
- method: 'POST',
- body: form,
- headers: {
- 'Cookie': secondCookie
- }
- };
- return fetch(ostUri, params);
- }
+ return json;
}
};
};
diff --git a/db/changes/224903/00-insert_notification_invoiceE.sql b/db/changes/224903/00-insert_notification_invoiceE.sql
deleted file mode 100644
index 1d416c196..000000000
--- a/db/changes/224903/00-insert_notification_invoiceE.sql
+++ /dev/null
@@ -1 +0,0 @@
-insert into `util`.`notification` (`id`, `name`,`description`) values (2, 'invoiceElectronic', 'A electronic invoice has been generated');
\ No newline at end of file
diff --git a/db/changes/225001/.gitkeep b/db/changes/225001/.gitkeep
deleted file mode 100644
index e69de29bb..000000000
diff --git a/db/changes/225201/00-invoiceOut_new.sql b/db/changes/225201/00-invoiceOut_new.sql
new file mode 100644
index 000000000..10a42d40d
--- /dev/null
+++ b/db/changes/225201/00-invoiceOut_new.sql
@@ -0,0 +1,225 @@
+DROP PROCEDURE IF EXISTS `vn`.`invoiceOut_new`;
+DELIMITER $$
+CREATE DEFINER=`root`@`localhost` PROCEDURE `vn`.`invoiceOut_new`(
+ vSerial VARCHAR(255),
+ vInvoiceDate DATETIME,
+ vTaxArea VARCHAR(25),
+ OUT vNewInvoiceId INT)
+BEGIN
+/**
+ * Creación de facturas emitidas.
+ * requiere previamente tabla ticketToInvoice(id).
+ *
+ * @param vSerial serie a la cual se hace la factura
+ * @param vInvoiceDate fecha de la factura
+ * @param vTaxArea tipo de iva en relacion a la empresa y al cliente
+ * @param vNewInvoiceId id de la factura que se acaba de generar
+ * @return vNewInvoiceId
+ */
+ DECLARE vSpainCountryCode INT DEFAULT 1;
+ DECLARE vIsAnySaleToInvoice BOOL;
+ DECLARE vIsAnyServiceToInvoice BOOL;
+ DECLARE vNewRef VARCHAR(255);
+ DECLARE vWorker INT DEFAULT account.myUser_getId();
+ DECLARE vCompany INT;
+ DECLARE vSupplier INT;
+ DECLARE vClient INT;
+ DECLARE vCplusStandardInvoiceTypeFk INT DEFAULT 1;
+ DECLARE vCplusCorrectingInvoiceTypeFk INT DEFAULT 6;
+ DECLARE vCplusSimplifiedInvoiceTypeFk INT DEFAULT 2;
+ DECLARE vCorrectingSerial VARCHAR(1) DEFAULT 'R';
+ DECLARE vSimplifiedSerial VARCHAR(1) DEFAULT 'S';
+ DECLARE vNewInvoiceInId INT;
+ DECLARE vIsInterCompany BOOL;
+
+ SET vInvoiceDate = IFNULL(vInvoiceDate,CURDATE());
+
+ SELECT t.clientFk, t.companyFk
+ INTO vClient, vCompany
+ FROM ticketToInvoice tt
+ JOIN ticket t ON t.id = tt.id
+ LIMIT 1;
+
+ -- Eliminem de ticketToInvoice els tickets que no han de ser facturats
+ DELETE ti.*
+ FROM ticketToInvoice ti
+ JOIN ticket t ON t.id = ti.id
+ JOIN sale s ON s.ticketFk = t.id
+ JOIN item i ON i.id = s.itemFk
+ JOIN supplier su ON su.id = t.companyFk
+ JOIN client c ON c.id = t.clientFk
+ LEFT JOIN itemTaxCountry itc ON itc.itemFk = i.id AND itc.countryFk = su.countryFk
+ WHERE YEAR(t.shipped) < 2001
+ OR c.isTaxDataChecked = FALSE
+ OR t.isDeleted
+ OR c.hasToInvoice = FALSE
+ OR itc.id IS NULL;
+
+ SELECT SUM(s.quantity * s.price * (100 - s.discount)/100), ts.id
+ INTO vIsAnySaleToInvoice, vIsAnyServiceToInvoice
+ FROM ticketToInvoice t
+ LEFT JOIN sale s ON s.ticketFk = t.id
+ LEFT JOIN ticketService ts ON ts.ticketFk = t.id;
+
+ IF (vIsAnySaleToInvoice OR vIsAnyServiceToInvoice)
+ AND (vCorrectingSerial = vSerial OR NOT hasAnyNegativeBase())
+ THEN
+
+ -- el trigger añade el siguiente Id_Factura correspondiente a la vSerial
+ INSERT INTO invoiceOut
+ (
+ ref,
+ serial,
+ issued,
+ clientFk,
+ dued,
+ companyFk,
+ cplusInvoiceType477Fk
+ )
+ SELECT
+ 1,
+ vSerial,
+ vInvoiceDate,
+ vClient,
+ getDueDate(vInvoiceDate, dueDay),
+ vCompany,
+ IF(vSerial = vCorrectingSerial,
+ vCplusCorrectingInvoiceTypeFk,
+ IF(vSerial = vSimplifiedSerial,
+ vCplusSimplifiedInvoiceTypeFk,
+ vCplusStandardInvoiceTypeFk))
+ FROM client
+ WHERE id = vClient;
+
+
+ SET vNewInvoiceId = LAST_INSERT_ID();
+
+ SELECT `ref`
+ INTO vNewRef
+ FROM invoiceOut
+ WHERE id = vNewInvoiceId;
+
+ UPDATE ticket t
+ JOIN ticketToInvoice ti ON ti.id = t.id
+ SET t.refFk = vNewRef;
+
+ DROP TEMPORARY TABLE IF EXISTS tmp.updateInter;
+ CREATE TEMPORARY TABLE tmp.updateInter ENGINE = MEMORY
+ SELECT s.id,ti.id ticket_id,vWorker Id_Trabajador
+ FROM ticketToInvoice ti
+ LEFT JOIN ticketState ts ON ti.id = ts.ticket
+ JOIN state s
+ WHERE IFNULL(ts.alertLevel,0) < 3 and s.`code` = getAlert3State(ti.id);
+
+ INSERT INTO vncontrol.inter(state_id,Id_Ticket,Id_Trabajador)
+ SELECT * FROM tmp.updateInter;
+
+ INSERT INTO ticketLog (action, userFk, originFk, description)
+ SELECT 'UPDATE', account.myUser_getId(), ti.id, CONCAT('Crea factura ', vNewRef)
+ FROM ticketToInvoice ti;
+
+ CALL invoiceExpenceMake(vNewInvoiceId);
+ CALL invoiceTaxMake(vNewInvoiceId,vTaxArea);
+
+ UPDATE invoiceOut io
+ JOIN (
+ SELECT SUM(amount) AS total
+ FROM invoiceOutExpence
+ WHERE invoiceOutFk = vNewInvoiceId
+ ) base
+ JOIN (
+ SELECT SUM(vat) AS total
+ FROM invoiceOutTax
+ WHERE invoiceOutFk = vNewInvoiceId
+ ) vat
+ SET io.amount = base.total + vat.total
+ WHERE io.id = vNewInvoiceId;
+
+ DROP TEMPORARY TABLE tmp.updateInter;
+
+ SELECT ios.isCEE INTO vIsInterCompany
+ FROM vn.ticket t
+ JOIN vn.invoiceOut io ON io.`ref` = t.refFk
+ JOIN vn.invoiceOutSerial ios ON ios.code = io.serial
+ WHERE t.refFk = vNewRef
+ LIMIT 1;
+
+ IF (vIsInterCompany) THEN
+
+ SELECT vCompany INTO vSupplier;
+ SELECT id INTO vCompany FROM company WHERE clientFk = vClient;
+
+ INSERT INTO invoiceIn(supplierFk, supplierRef, issued, companyFk)
+ SELECT vSupplier, vNewRef, vInvoiceDate, vCompany;
+
+ SET vNewInvoiceInId = LAST_INSERT_ID();
+
+ DROP TEMPORARY TABLE IF EXISTS tmp.ticket;
+ CREATE TEMPORARY TABLE tmp.ticket
+ (KEY (ticketFk))
+ ENGINE = MEMORY
+ SELECT id ticketFk
+ FROM ticketToInvoice;
+
+ CALL `ticket_getTax`('NATIONAL');
+
+ SET @vTaxableBaseServices := 0.00;
+ SET @vTaxCodeGeneral := NULL;
+
+ INSERT INTO vn.invoiceInTax(invoiceInFk, taxableBase, expenceFk, taxTypeSageFk, transactionTypeSageFk)
+ SELECT vNewInvoiceInId, @vTaxableBaseServices, sub.expenceFk, sub.taxTypeSageFk , sub.transactionTypeSageFk
+ FROM (
+ SELECT @vTaxableBaseServices := SUM(tst.taxableBase) taxableBase, i.expenceFk, i.taxTypeSageFk , i.transactionTypeSageFk, @vTaxCodeGeneral := i.taxClassCodeFk
+ FROM tmp.ticketServiceTax tst
+ JOIN vn.invoiceOutTaxConfig i ON i.taxClassCodeFk = tst.code
+ WHERE i.isService
+ HAVING taxableBase
+ ) sub;
+
+ INSERT INTO vn.invoiceInTax(invoiceInFk, taxableBase, expenceFk, taxTypeSageFk, transactionTypeSageFk)
+ SELECT vNewInvoiceInId, SUM(tt.taxableBase) - IF(tt.code = @vTaxCodeGeneral, @vTaxableBaseServices, 0) taxableBase, i.expenceFk, i.taxTypeSageFk , i.transactionTypeSageFk
+ FROM tmp.ticketTax tt
+ JOIN vn.invoiceOutTaxConfig i ON i.taxClassCodeFk = tt.code
+ WHERE !i.isService
+ GROUP BY tt.pgcFk
+ HAVING taxableBase
+ ORDER BY tt.priority;
+
+ CALL invoiceInDueDay_calculate(vNewInvoiceInId);
+
+ INSERT INTO invoiceInIntrastat (
+ invoiceInFk,
+ intrastatFk,
+ amount,
+ stems,
+ countryFk,
+ net)
+ SELECT
+ vNewInvoiceInId invoiceInFk,
+ i.intrastatFk,
+ CAST(SUM((s.quantity * s.price * (100 - s.discount) / 100 )) AS DECIMAL(10,2)) subtotal,
+ CAST(SUM(IFNULL(i.stems, 1) * s.quantity) AS DECIMAL(10,2)) stems,
+ su.countryFk,
+ CAST(SUM(IFNULL(i.stems, 1)
+ * s.quantity
+ * IF(ic.grams, ic.grams, i.weightByPiece) / 1000) AS DECIMAL(10,2)) netKg
+ FROM sale s
+ JOIN ticket t ON s.ticketFk = t.id
+ JOIN supplier su ON su.id = t.companyFk
+ JOIN item i ON i.id = s.itemFk
+ JOIN vn.itemCost ic ON ic.itemFk = i.id AND ic.warehouseFk = t.warehouseFk
+ JOIN intrastat ir ON ir.id = i.intrastatFk
+ WHERE t.refFk = vNewRef;
+
+ DROP TEMPORARY TABLE tmp.ticket;
+ DROP TEMPORARY TABLE tmp.ticketAmount;
+ DROP TEMPORARY TABLE tmp.ticketTax;
+ DROP TEMPORARY TABLE tmp.ticketServiceTax;
+
+ END IF;
+
+ END IF;
+
+ DROP TEMPORARY TABLE `ticketToInvoice`;
+END$$
+DELIMITER ;
diff --git a/db/changes/225201/01-modules.sql b/db/changes/225201/01-modules.sql
index 82861a5e2..243d2d016 100644
--- a/db/changes/225201/01-modules.sql
+++ b/db/changes/225201/01-modules.sql
@@ -43,7 +43,7 @@ SET t.code = 'claim'
WHERE t.code LIKE 'Claims' ESCAPE '#';
UPDATE salix.module t
-SET t.code = 'user'
+SET t.code = 'account'
WHERE t.code LIKE 'Users' ESCAPE '#';
UPDATE salix.module t
diff --git a/db/changes/225202/00-mdbApp.sql b/db/changes/225202/00-mdbApp.sql
new file mode 100644
index 000000000..50c595d71
--- /dev/null
+++ b/db/changes/225202/00-mdbApp.sql
@@ -0,0 +1,28 @@
+ALTER TABLE `vn`.`mdbApp` DROP PRIMARY KEY;
+ALTER TABLE `vn`.`mdbApp` ADD CONSTRAINT mdbApp_PK PRIMARY KEY (app,baselineBranchFk);
+
+INSERT INTO `vn`.`mdbApp` (app,baselineBranchFk)
+ VALUES ('com','master');
+INSERT INTO `vn`.`mdbApp` (app,baselineBranchFk)
+ VALUES ('enc','master');
+INSERT INTO `vn`.`mdbApp` (app,baselineBranchFk)
+ VALUES ('ent','master');
+INSERT INTO `vn`.`mdbApp` (app,baselineBranchFk)
+ VALUES ('eti','master');
+INSERT INTO `vn`.`mdbApp` (app,baselineBranchFk)
+ VALUES ('lab','master');
+INSERT INTO `vn`.`mdbApp` (app,baselineBranchFk)
+ VALUES ('tpv','master');
+INSERT INTO `vn`.`mdbApp` (app,baselineBranchFk)
+ VALUES ('com','dev');
+INSERT INTO `vn`.`mdbApp` (app,baselineBranchFk)
+ VALUES ('enc','dev');
+INSERT INTO `vn`.`mdbApp` (app,baselineBranchFk)
+ VALUES ('ent','dev');
+INSERT INTO `vn`.`mdbApp` (app,baselineBranchFk)
+ VALUES ('eti','dev');
+INSERT INTO `vn`.`mdbApp` (app,baselineBranchFk)
+ VALUES ('lab','dev');
+INSERT INTO `vn`.`mdbApp` (app,baselineBranchFk)
+ VALUES ('tpv','dev');
+
diff --git a/db/changes/230201/00-ACL_ItemShelvingSale.sql b/db/changes/230201/00-ACL_ItemShelvingSale.sql
new file mode 100644
index 000000000..38b65f89a
--- /dev/null
+++ b/db/changes/230201/00-ACL_ItemShelvingSale.sql
@@ -0,0 +1,2 @@
+INSERT INTO `salix`.`ACL` (`model`,`property`,`accessType`,`permission`,`principalId`)
+ VALUES ('ItemShelvingSale','*','*','ALLOW','employee');
diff --git a/db/changes/230201/00-autoincrement_VnReport_VnPrinter.sql b/db/changes/230201/00-autoincrement_VnReport_VnPrinter.sql
new file mode 100644
index 000000000..a28bf6e90
--- /dev/null
+++ b/db/changes/230201/00-autoincrement_VnReport_VnPrinter.sql
@@ -0,0 +1,4 @@
+SET FOREIGN_KEY_CHECKS = 0;
+ALTER TABLE `vn`.`report` MODIFY COLUMN id tinyint(3) unsigned NOT NULL AUTO_INCREMENT;
+ALTER TABLE `vn`.`printer` MODIFY COLUMN id tinyint(3) unsigned NOT NULL AUTO_INCREMENT;
+SET FOREIGN_KEY_CHECKS = 1;
diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql
index 1ea4fa114..c10649ff3 100644
--- a/db/dump/fixtures.sql
+++ b/db/dump/fixtures.sql
@@ -1143,10 +1143,10 @@ INSERT INTO `vn`.`itemShelving` (`itemFk`, `shelvingFk`, `visible`, `grouping`,
INSERT INTO `vn`.`itemShelvingSale` (`itemShelvingFk`, `saleFk`, `quantity`, `created`, `userFk`)
VALUES
- ('1', '1', '1', '', '1106'),
- ('2', '2', '5', '', '1106'),
- ('1', '7', '1', '', '1106'),
- ('2', '8', '5', '', '1106');
+ ('1', '1', '1', util.VN_CURDATE(), '1106'),
+ ('2', '2', '5', util.VN_CURDATE(), '1106'),
+ ('1', '7', '1', util.VN_CURDATE(), '1106'),
+ ('2', '8', '5', util.VN_CURDATE(), '1106');
INSERT INTO `vncontrol`.`accion`(`accion_id`, `accion`)
VALUES
@@ -1779,7 +1779,7 @@ INSERT INTO `vn`.`claimDestination`(`id`, `description`, `addressFk`)
INSERT INTO `vn`.`claimDevelopment`(`id`, `claimFk`, `claimResponsibleFk`, `workerFk`, `claimReasonFk`, `claimResultFk`, `claimRedeliveryFk`, `claimDestinationFk`)
VALUES
(1, 1, 1, 21, 1, 1, 2, 5),
- (2, 1, 1, 21, 7, 2, 2, 5),
+ (2, 1, 2, 21, 7, 2, 2, 5),
(3, 2, 7, 21, 9, 3, 2, 5),
(4, 3, 7, 21, 15, 8, 2, 5),
(5, 4, 7, 21, 7, 8, 2, 5);
@@ -2692,6 +2692,7 @@ INSERT INTO `util`.`notificationConfig`
INSERT INTO `util`.`notification` (`id`, `name`, `description`)
VALUES
(1, 'print-email', 'notification fixture one'),
+ (2, 'invoice-electronic', 'A electronic invoice has been generated'),
(4, 'supplier-pay-method-update', 'A supplier pay method has been updated');
INSERT INTO `util`.`notificationAcl` (`notificationFk`, `roleFk`)
diff --git a/e2e/paths/01-salix/03_smartTable_searchBar_integrations.spec.js b/e2e/paths/01-salix/03_smartTable_searchBar_integrations.spec.js
index 4fc280209..ad558ace2 100644
--- a/e2e/paths/01-salix/03_smartTable_searchBar_integrations.spec.js
+++ b/e2e/paths/01-salix/03_smartTable_searchBar_integrations.spec.js
@@ -15,7 +15,7 @@ describe('SmartTable SearchBar integration', () => {
await browser.close();
});
- describe('as filters', () => {
+ describe('as filters in smart-table section', () => {
it('should search by type in searchBar', async() => {
await page.waitToClick(selectors.itemsIndex.openAdvancedSearchButton);
await page.autocompleteSearch(selectors.itemsIndex.advancedSearchItemType, 'Anthurium');
@@ -47,6 +47,34 @@ describe('SmartTable SearchBar integration', () => {
});
});
+ describe('as filters in section without smart-table', () => {
+ it('go to zone section', async() => {
+ await page.loginAndModule('salesPerson', 'zone');
+ await page.waitToClick(selectors.globalItems.searchButton);
+ });
+
+ it('should search in searchBar first time', async() => {
+ await page.doSearch('A');
+ const count = await page.countElement(selectors.zoneIndex.searchResult);
+
+ expect(count).toEqual(7);
+ });
+
+ it('should search in searchBar second time', async() => {
+ await page.doSearch('A');
+ const count = await page.countElement(selectors.zoneIndex.searchResult);
+
+ expect(count).toEqual(7);
+ });
+
+ it('should search in searchBar third time', async() => {
+ await page.doSearch('A');
+ const count = await page.countElement(selectors.zoneIndex.searchResult);
+
+ expect(count).toEqual(7);
+ });
+ });
+
describe('as orders', () => {
it('should order by first id', async() => {
await page.loginAndModule('developer', 'item');
diff --git a/e2e/paths/03-worker/01_summary.spec.js b/e2e/paths/03-worker/01_summary.spec.js
index 4ea87481a..4e5b0cfa9 100644
--- a/e2e/paths/03-worker/01_summary.spec.js
+++ b/e2e/paths/03-worker/01_summary.spec.js
@@ -2,68 +2,32 @@ import selectors from '../../helpers/selectors.js';
import getBrowser from '../../helpers/puppeteer';
describe('Worker summary path', () => {
+ const workerId = 3;
let browser;
let page;
beforeAll(async() => {
browser = await getBrowser();
page = browser.page;
await page.loginAndModule('employee', 'worker');
+ const httpDataResponse = page.waitForResponse(response => {
+ return response.status() === 200 && response.url().includes(`Workers/${workerId}`);
+ });
await page.accessToSearchResult('agencyNick');
+ await httpDataResponse;
});
afterAll(async() => {
await browser.close();
});
- it('should reach the employee summary section', async() => {
- await page.waitForState('worker.card.summary');
- });
-
- it('should check the summary contains the name and userName on the header', async() => {
- const result = await page.waitToGetProperty(selectors.workerSummary.header, 'innerText');
-
- expect(result).toEqual('agency agency');
- });
-
- it('should check the summary contains the basic data id', async() => {
- const result = await page.waitToGetProperty(selectors.workerSummary.id, 'innerText');
-
- expect(result).toEqual('3');
- });
-
- it('should check the summary contains the basic data email', async() => {
- const result = await page.waitToGetProperty(selectors.workerSummary.email, 'innerText');
-
- expect(result).toEqual('agency@verdnatura.es');
- });
-
- it('should check the summary contains the basic data department', async() => {
- const result = await page.waitToGetProperty(selectors.workerSummary.department, 'innerText');
-
- expect(result).toEqual('CAMARA');
- });
-
- it('should check the summary contains the user data id', async() => {
- const result = await page.waitToGetProperty(selectors.workerSummary.userId, 'innerText');
-
- expect(result).toEqual('3');
- });
-
- it('should check the summary contains the user data name', async() => {
- const result = await page.waitToGetProperty(selectors.workerSummary.userName, 'innerText');
-
- expect(result).toEqual('agency');
- });
-
- it('should check the summary contains the user data role', async() => {
- const result = await page.waitToGetProperty(selectors.workerSummary.role, 'innerText');
-
- expect(result).toEqual('agency');
- });
-
- it('should check the summary contains the user data extension', async() => {
- const result = await page.waitToGetProperty(selectors.workerSummary.extension, 'innerText');
-
- expect(result).toEqual('1101');
+ it('should reach the employee summary section and check all properties', async() => {
+ expect(await page.getProperty(selectors.workerSummary.header, 'innerText')).toEqual('agency agency');
+ expect(await page.getProperty(selectors.workerSummary.id, 'innerText')).toEqual('3');
+ expect(await page.getProperty(selectors.workerSummary.email, 'innerText')).toEqual('agency@verdnatura.es');
+ expect(await page.getProperty(selectors.workerSummary.department, 'innerText')).toEqual('CAMARA');
+ expect(await page.getProperty(selectors.workerSummary.userId, 'innerText')).toEqual('3');
+ expect(await page.getProperty(selectors.workerSummary.userName, 'innerText')).toEqual('agency');
+ expect(await page.getProperty(selectors.workerSummary.role, 'innerText')).toEqual('agency');
+ expect(await page.getProperty(selectors.workerSummary.extension, 'innerText')).toEqual('1101');
});
});
diff --git a/e2e/paths/03-worker/02_basicData.spec.js b/e2e/paths/03-worker/02_basicData.spec.js
index c367c8706..66a597dd1 100644
--- a/e2e/paths/03-worker/02_basicData.spec.js
+++ b/e2e/paths/03-worker/02_basicData.spec.js
@@ -2,13 +2,18 @@ import selectors from '../../helpers/selectors.js';
import getBrowser from '../../helpers/puppeteer';
describe('Worker basic data path', () => {
+ const workerId = 1106;
let browser;
let page;
beforeAll(async() => {
browser = await getBrowser();
page = browser.page;
await page.loginAndModule('hr', 'worker');
+ const httpDataResponse = page.waitForResponse(response => {
+ return response.status() === 200 && response.url().includes(`Workers/${workerId}`);
+ });
await page.accessToSearchResult('David Charles Haller');
+ await httpDataResponse;
await page.accessToSection('worker.card.basicData');
});
@@ -16,35 +21,20 @@ describe('Worker basic data path', () => {
await browser.close();
});
- it('should edit the form', async() => {
- await page.clearInput(selectors.workerBasicData.name);
- await page.write(selectors.workerBasicData.name, 'David C.');
- await page.clearInput(selectors.workerBasicData.surname);
- await page.write(selectors.workerBasicData.surname, 'H.');
- await page.clearInput(selectors.workerBasicData.phone);
- await page.write(selectors.workerBasicData.phone, '444332211');
- await page.waitToClick(selectors.workerBasicData.saveButton);
+ it('should edit the form and then reload the section and check the data was edited', async() => {
+ await page.overwrite(selectors.workerBasicData.name, 'David C.');
+ await page.overwrite(selectors.workerBasicData.surname, 'H.');
+ await page.overwrite(selectors.workerBasicData.phone, '444332211');
+ await page.click(selectors.workerBasicData.saveButton);
+
const message = await page.waitForSnackbar();
expect(message.text).toContain('Data saved!');
- });
- it('should reload the section then check the name was edited', async() => {
await page.reloadSection('worker.card.basicData');
- const result = await page.waitToGetProperty(selectors.workerBasicData.name, 'value');
- expect(result).toEqual('David C.');
- });
-
- it('should the surname was edited', async() => {
- const result = await page.waitToGetProperty(selectors.workerBasicData.surname, 'value');
-
- expect(result).toEqual('H.');
- });
-
- it('should the phone was edited', async() => {
- const result = await page.waitToGetProperty(selectors.workerBasicData.phone, 'value');
-
- expect(result).toEqual('444332211');
+ expect(await page.waitToGetProperty(selectors.workerBasicData.name, 'value')).toEqual('David C.');
+ expect(await page.waitToGetProperty(selectors.workerBasicData.surname, 'value')).toEqual('H.');
+ expect(await page.waitToGetProperty(selectors.workerBasicData.phone, 'value')).toEqual('444332211');
});
});
diff --git a/e2e/paths/03-worker/03_pbx.spec.js b/e2e/paths/03-worker/03_pbx.spec.js
index f5d2711d1..0e8003c47 100644
--- a/e2e/paths/03-worker/03_pbx.spec.js
+++ b/e2e/paths/03-worker/03_pbx.spec.js
@@ -16,19 +16,16 @@ describe('Worker pbx path', () => {
await browser.close();
});
- it('should receive an error when the extension exceeds 4 characters', async() => {
+ it('should receive an error when the extension exceeds 4 characters and then sucessfully save the changes', async() => {
await page.write(selectors.workerPbx.extension, '55555');
- await page.waitToClick(selectors.workerPbx.saveButton);
- const message = await page.waitForSnackbar();
+ await page.click(selectors.workerPbx.saveButton);
+ let message = await page.waitForSnackbar();
expect(message.text).toContain('Extension format is invalid');
- });
- it('should sucessfully save the changes', async() => {
- await page.clearInput(selectors.workerPbx.extension);
- await page.write(selectors.workerPbx.extension, '4444');
- await page.waitToClick(selectors.workerPbx.saveButton);
- const message = await page.waitForSnackbar();
+ await page.overwrite(selectors.workerPbx.extension, '4444');
+ await page.click(selectors.workerPbx.saveButton);
+ message = await page.waitForSnackbar();
expect(message.text).toContain('Data saved! User must access web');
});
diff --git a/e2e/paths/03-worker/04_time_control.spec.js b/e2e/paths/03-worker/04_time_control.spec.js
index 4236ae0e4..bba7ced89 100644
--- a/e2e/paths/03-worker/04_time_control.spec.js
+++ b/e2e/paths/03-worker/04_time_control.spec.js
@@ -21,38 +21,34 @@ describe('Worker time control path', () => {
const fourPm = '16:00';
const hankPymId = 1107;
- it('should go to the next month', async() => {
- const date = new Date();
+ it('should go to the next month, go to current month and go 1 month in the past', async() => {
+ let date = new Date();
date.setMonth(date.getMonth() + 1);
- const month = date.toLocaleString('default', {month: 'long'});
+ let month = date.toLocaleString('default', {month: 'long'});
- await page.waitToClick(selectors.workerTimeControl.nextMonthButton);
- const result = await page.waitToGetProperty(selectors.workerTimeControl.monthName, 'innerText');
+ await page.click(selectors.workerTimeControl.nextMonthButton);
+ let result = await page.getProperty(selectors.workerTimeControl.monthName, 'innerText');
expect(result).toContain(month);
- });
- it('should go to current month', async() => {
- const date = new Date();
- const month = date.toLocaleString('default', {month: 'long'});
+ date = new Date();
+ month = date.toLocaleString('default', {month: 'long'});
- await page.waitToClick(selectors.workerTimeControl.previousMonthButton);
- const result = await page.waitToGetProperty(selectors.workerTimeControl.monthName, 'innerText');
+ await page.click(selectors.workerTimeControl.previousMonthButton);
+ result = await page.getProperty(selectors.workerTimeControl.monthName, 'innerText');
expect(result).toContain(month);
- });
- it('should go 1 month in the past', async() => {
- const date = new Date();
+ date = new Date();
date.setMonth(date.getMonth() - 1);
const timestamp = Math.round(date.getTime() / 1000);
- const month = date.toLocaleString('default', {month: 'long'});
+ month = date.toLocaleString('default', {month: 'long'});
await page.loginAndModule('salesBoss', 'worker');
await page.goto(`http://localhost:5000/#!/worker/${hankPymId}/time-control?timestamp=${timestamp}`);
- await page.waitToClick(selectors.workerTimeControl.secondWeekDay);
+ await page.click(selectors.workerTimeControl.secondWeekDay);
- const result = await page.waitToGetProperty(selectors.workerTimeControl.monthName, 'innerText');
+ result = await page.getProperty(selectors.workerTimeControl.monthName, 'innerText');
expect(result).toContain(month);
});
@@ -115,7 +111,9 @@ describe('Worker time control path', () => {
});
it('should change week of month', async() => {
- await page.waitToClick(selectors.workerTimeControl.thrirdWeekDay);
- await page.waitForTextInElement(selectors.workerTimeControl.mondayWorkedHours, '00:00 h.');
+ await page.click(selectors.workerTimeControl.thrirdWeekDay);
+ const result = await page.getProperty(selectors.workerTimeControl.mondayWorkedHours, 'innerText');
+
+ expect(result).toEqual('00:00 h.');
});
});
diff --git a/e2e/paths/03-worker/05_calendar.spec.js b/e2e/paths/03-worker/05_calendar.spec.js
index e97b7fe7c..c310baf5a 100644
--- a/e2e/paths/03-worker/05_calendar.spec.js
+++ b/e2e/paths/03-worker/05_calendar.spec.js
@@ -1,16 +1,25 @@
+/* eslint-disable max-len */
import selectors from '../../helpers/selectors.js';
import getBrowser from '../../helpers/puppeteer';
describe('Worker calendar path', () => {
- let reasonableTimeBetweenClicks = 400;
+ const reasonableTimeBetweenClicks = 300;
+ const date = new Date();
+ const lastYear = (date.getFullYear() - 1).toString();
+
let browser;
let page;
+
+ async function accessAs(user) {
+ await page.loginAndModule(user, 'worker');
+ await page.accessToSearchResult('Charles Xavier');
+ await page.accessToSection('worker.card.calendar');
+ }
+
beforeAll(async() => {
browser = await getBrowser();
page = browser.page;
- await page.loginAndModule('hr', 'worker');
- await page.accessToSearchResult('Charles Xavier');
- await page.accessToSection('worker.card.calendar');
+ accessAs('hr');
});
afterAll(async() => {
@@ -21,48 +30,40 @@ describe('Worker calendar path', () => {
it('should set two days as holidays on the calendar and check the total holidays increased by 1.5', async() => {
await page.waitToClick(selectors.workerCalendar.holidays);
await page.waitForTimeout(reasonableTimeBetweenClicks);
- await page.waitToClick(selectors.workerCalendar.penultimateMondayOfJanuary);
+ await page.click(selectors.workerCalendar.penultimateMondayOfJanuary);
await page.waitForTimeout(reasonableTimeBetweenClicks);
- await page.waitToClick(selectors.workerCalendar.absence);
+ await page.click(selectors.workerCalendar.absence);
await page.waitForTimeout(reasonableTimeBetweenClicks);
- await page.waitToClick(selectors.workerCalendar.lastMondayOfMarch);
+ await page.click(selectors.workerCalendar.lastMondayOfMarch);
await page.waitForTimeout(reasonableTimeBetweenClicks);
- await page.waitToClick(selectors.workerCalendar.halfHoliday);
+ await page.click(selectors.workerCalendar.halfHoliday);
await page.waitForTimeout(reasonableTimeBetweenClicks);
- await page.waitToClick(selectors.workerCalendar.fistMondayOfMay);
+ await page.click(selectors.workerCalendar.fistMondayOfMay);
await page.waitForTimeout(reasonableTimeBetweenClicks);
- await page.waitToClick(selectors.workerCalendar.furlough);
+ await page.click(selectors.workerCalendar.furlough);
await page.waitForTimeout(reasonableTimeBetweenClicks);
- await page.waitToClick(selectors.workerCalendar.secondTuesdayOfMay);
+ await page.click(selectors.workerCalendar.secondTuesdayOfMay);
await page.waitForTimeout(reasonableTimeBetweenClicks);
- await page.waitToClick(selectors.workerCalendar.secondWednesdayOfMay);
+ await page.click(selectors.workerCalendar.secondWednesdayOfMay);
await page.waitForTimeout(reasonableTimeBetweenClicks);
- await page.waitToClick(selectors.workerCalendar.secondThursdayOfMay);
+ await page.click(selectors.workerCalendar.secondThursdayOfMay);
await page.waitForTimeout(reasonableTimeBetweenClicks);
- await page.waitToClick(selectors.workerCalendar.halfFurlough);
- await page.waitForTimeout(reasonableTimeBetweenClicks);
- await page.waitToClick(selectors.workerCalendar.secondFridayOfJun);
+ await page.click(selectors.workerCalendar.halfFurlough);
await page.waitForTimeout(reasonableTimeBetweenClicks);
+ await page.click(selectors.workerCalendar.secondFridayOfJun);
- const result = await page.waitToGetProperty(selectors.workerCalendar.totalHolidaysUsed, 'innerText');
-
- expect(result).toContain(' 1.5 ');
+ expect(await page.getProperty(selectors.workerCalendar.totalHolidaysUsed, 'innerText')).toContain(' 1.5 ');
});
});
describe(`as salesBoss`, () => {
- it(`should log in and get to Charles Xavier's calendar`, async() => {
- await page.loginAndModule('salesBoss', 'worker');
- await page.accessToSearchResult('Charles Xavier');
- await page.accessToSection('worker.card.calendar');
- });
+ it(`should log in, get to Charles Xavier's calendar, undo what was done here, and check the total holidays used are back to what it was`, async() => {
+ accessAs('salesBoss');
- it('should undo what was done here', async() => {
- await page.waitForTimeout(reasonableTimeBetweenClicks);
await page.waitToClick(selectors.workerCalendar.holidays);
await page.waitForTimeout(reasonableTimeBetweenClicks);
await page.waitToClick(selectors.workerCalendar.penultimateMondayOfJanuary);
@@ -90,45 +91,24 @@ describe('Worker calendar path', () => {
await page.waitToClick(selectors.workerCalendar.halfFurlough);
await page.waitForTimeout(reasonableTimeBetweenClicks);
await page.waitToClick(selectors.workerCalendar.secondFridayOfJun);
- });
- it('should check the total holidays used are back to what it was', async() => {
- const result = await page.waitToGetProperty(selectors.workerCalendar.totalHolidaysUsed, 'innerText');
-
- expect(result).toContain(' 0 ');
+ expect(await page.getProperty(selectors.workerCalendar.totalHolidaysUsed, 'innerText')).toContain(' 0 ');
});
});
describe(`as Charles Xavier`, () => {
- it(`should log in and get to his calendar`, async() => {
- await page.loginAndModule('CharlesXavier', 'worker');
- await page.accessToSearchResult('Charles Xavier');
- await page.accessToSection('worker.card.calendar');
- });
-
- it('should make a futile attempt to add holidays', async() => {
- await page.waitForTimeout(reasonableTimeBetweenClicks);
+ it('should log in and get to his calendar, make a futile attempt to add holidays, check the total holidays used are now the initial ones and use the year selector to go to the previous year', async() => {
+ accessAs('CharlesXavier');
await page.waitToClick(selectors.workerCalendar.holidays);
await page.waitForTimeout(reasonableTimeBetweenClicks);
- await page.waitToClick(selectors.workerCalendar.penultimateMondayOfJanuary);
- });
- it('should check the total holidays used are now the initial ones', async() => {
- const result = await page.waitToGetProperty(selectors.workerCalendar.totalHolidaysUsed, 'innerText');
+ await page.click(selectors.workerCalendar.penultimateMondayOfJanuary);
- expect(result).toContain(' 0 ');
- });
-
- it('should use the year selector to go to the previous year', async() => {
- const date = new Date();
- const lastYear = (date.getFullYear() - 1).toString();
+ expect(await page.getProperty(selectors.workerCalendar.totalHolidaysUsed, 'innerText')).toContain(' 0 ');
await page.autocompleteSearch(selectors.workerCalendar.year, lastYear);
- await page.waitForTimeout(reasonableTimeBetweenClicks);
- const result = await page.waitToGetProperty(selectors.workerCalendar.totalHolidaysUsed, 'innerText');
-
- expect(result).toContain(' 0 ');
+ expect(await page.getProperty(selectors.workerCalendar.totalHolidaysUsed, 'innerText')).toContain(' 0 ');
});
});
});
diff --git a/front/core/components/searchbar/searchbar.js b/front/core/components/searchbar/searchbar.js
index f2855d711..aefa89b5b 100644
--- a/front/core/components/searchbar/searchbar.js
+++ b/front/core/components/searchbar/searchbar.js
@@ -308,7 +308,7 @@ export default class Searchbar extends Component {
this.tableQ = null;
- const hasParams = this.$params.q && Object.keys(JSON.parse(this.$params.q)).length;
+ const hasParams = this.$params.q && JSON.parse(this.$params.q).tableQ;
if (hasParams) {
const stateFilter = JSON.parse(this.$params.q);
for (let param in stateFilter) {
@@ -325,8 +325,8 @@ export default class Searchbar extends Component {
for (let param in stateFilter.tableQ)
params[param] = stateFilter.tableQ[param];
- Object.assign(stateFilter, params);
- return this.model.applyParams(params)
+ const newParams = Object.assign(stateFilter, params);
+ return this.model.applyParams(newParams)
.then(() => this.model.data);
}
diff --git a/front/core/components/searchbar/searchbar.spec.js b/front/core/components/searchbar/searchbar.spec.js
index ed8fd9d07..9998e7a7c 100644
--- a/front/core/components/searchbar/searchbar.spec.js
+++ b/front/core/components/searchbar/searchbar.spec.js
@@ -174,14 +174,12 @@ describe('Component vnSearchbar', () => {
jest.spyOn(controller, 'doSearch');
controller.model = {
refresh: jest.fn(),
+ applyFilter: jest.fn().mockReturnValue(Promise.resolve()),
userParams: {
id: 1
}
};
- controller.model.applyParams = jest.fn().mockReturnValue(Promise.resolve());
- jest.spyOn(controller.model, 'applyParams');
-
controller.filter = filter;
controller.removeParam(0);
diff --git a/front/core/components/table/style.scss b/front/core/components/table/style.scss
index d0a29a3ba..557268661 100644
--- a/front/core/components/table/style.scss
+++ b/front/core/components/table/style.scss
@@ -29,7 +29,7 @@ vn-table {
& > tbody {
display: table-row-group;
}
- & > vn-tfoot,
+ & > vn-tfoot,
& > .vn-tfoot,
& > tfoot {
border-top: $border;
@@ -42,7 +42,7 @@ vn-table {
height: 48px;
}
vn-thead, .vn-thead,
- vn-tbody, .vn-tbody,
+ vn-tbody, .vn-tbody,
vn-tfoot, .vn-tfoot,
thead, tbody, tfoot {
& > * {
@@ -153,6 +153,18 @@ vn-table {
background-color: $color-font-bg-dark;
color: $color-font-bg;
}
+ &.dark-notice {
+ background-color: $color-notice;
+ color: $color-font-bg;
+ }
+ &.yellow {
+ background-color: $color-yellow;
+ color: $color-font-bg;
+ }
+ &.pink {
+ background-color: $color-pink;
+ color: $color-font-bg;
+ }
}
vn-icon-menu {
display: inline-block;
@@ -194,7 +206,7 @@ vn-table.scrollable > .vn-table,
}
vn-thead th,
- vn-thead vn-th,
+ vn-thead vn-th,
thead vn-th,
thead th {
border-bottom: $border;
@@ -217,4 +229,4 @@ vn-table.scrollable.lg,
.tableWrapper {
overflow-x: auto;
-}
\ No newline at end of file
+}
diff --git a/front/core/styles/variables.scss b/front/core/styles/variables.scss
index c79a8590f..bcc9fab66 100644
--- a/front/core/styles/variables.scss
+++ b/front/core/styles/variables.scss
@@ -101,6 +101,8 @@ $color-marginal: #222;
$color-success: #a3d131;
$color-notice: #32b1ce;
$color-alert: #fa3939;
+$color-pink: #ff99cc;
+$color-yellow: #ffff00;
$color-button: $color-secondary;
$color-spacer: rgba(255, 255, 255, .3);
diff --git a/front/salix/components/sendSms/locale/es.yml b/front/salix/components/sendSms/locale/es.yml
index 64c3fcca6..94ab8e588 100644
--- a/front/salix/components/sendSms/locale/es.yml
+++ b/front/salix/components/sendSms/locale/es.yml
@@ -1,7 +1,7 @@
Send SMS: Enviar SMS
Destination: Destinatario
Message: Mensaje
-SMS sent!: ¡SMS enviado!
+SMS sent: ¡SMS enviado!
Characters remaining: Carácteres restantes
The destination can't be empty: El destinatario no puede estar vacio
The message can't be empty: El mensaje no puede estar vacio
diff --git a/modules/claim/back/methods/claim/filter.js b/modules/claim/back/methods/claim/filter.js
index e86830200..d653229e5 100644
--- a/modules/claim/back/methods/claim/filter.js
+++ b/modules/claim/back/methods/claim/filter.js
@@ -23,7 +23,7 @@ module.exports = Self => {
{
arg: 'search',
type: 'string',
- description: `If it's and integer searchs by id, otherwise it searchs by client name`,
+ description: `If it's a number searchs by id, otherwise it searchs by client name`,
http: {source: 'query'}
},
{
@@ -34,31 +34,31 @@ module.exports = Self => {
},
{
arg: 'id',
- type: 'integer',
+ type: 'number',
description: 'The claim id',
http: {source: 'query'}
},
{
arg: 'clientFk',
- type: 'integer',
+ type: 'number',
description: 'The client id',
http: {source: 'query'}
},
{
arg: 'claimStateFk',
- type: 'integer',
+ type: 'number',
description: 'The claim state id',
http: {source: 'query'}
},
{
arg: 'salesPersonFk',
- type: 'integer',
+ type: 'number',
description: 'The salesPerson id',
http: {source: 'query'}
},
{
arg: 'attenderFk',
- type: 'integer',
+ type: 'number',
description: 'The attender worker id',
http: {source: 'query'}
},
@@ -67,6 +67,18 @@ module.exports = Self => {
type: 'date',
description: 'The to date filter',
http: {source: 'query'}
+ },
+ {
+ arg: 'itemFk',
+ type: 'number',
+ description: 'The item id',
+ http: {source: 'query'}
+ },
+ {
+ arg: 'claimResponsibleFk',
+ type: 'number',
+ description: 'The claimResponsible id',
+ http: {source: 'query'}
}
],
returns: {
@@ -80,33 +92,58 @@ module.exports = Self => {
});
Self.filter = async(ctx, filter, options) => {
+ const models = Self.app.models;
const conn = Self.dataSource.connector;
+ const args = ctx.args;
const myOptions = {};
let to;
if (typeof options == 'object')
Object.assign(myOptions, options);
- const where = buildFilter(ctx.args, (param, value) => {
+ let claimIdsByItemFk = [];
+ let claimIdsByClaimResponsibleFk = [];
+
+ if (args.itemFk) {
+ query = `SELECT cb.claimFk
+ FROM claimBeginning cb
+ LEFT JOIN sale s ON s.id = cb.saleFk
+ WHERE s.itemFk = ?`;
+ const claims = await Self.rawSql(query, [args.itemFk], myOptions);
+ claimIdsByItemFk = claims.map(claim => claim.claimFk);
+ }
+
+ if (args.claimResponsibleFk) {
+ const claims = await models.ClaimDevelopment.find({
+ fields: ['claimFk'],
+ where: {claimResponsibleFk: args.claimResponsibleFk}
+ }, myOptions);
+ claimIdsByClaimResponsibleFk = claims.map(claim => claim.claimFk);
+ }
+
+ const where = buildFilter(args, (param, value) => {
switch (param) {
case 'search':
return /^\d+$/.test(value)
? {'cl.id': value}
: {
or: [
- {'cl.clientName': {like: `%${value}%`}}
+ {'c.name': {like: `%${value}%`}}
]
};
case 'clientName':
- return {'cl.clientName': {like: `%${value}%`}};
+ return {'c.name': {like: `%${value}%`}};
case 'clientFk':
- return {'cl.clientFk': value};
case 'id':
case 'claimStateFk':
case 'priority':
return {[`cl.${param}`]: value};
+ case 'itemFk':
+ return {'cl.id': {inq: claimIdsByItemFk}};
+ case 'claimResponsibleFk':
+ return {'cl.id': {inq: claimIdsByClaimResponsibleFk}};
case 'salesPersonFk':
- return {'cl.salesPersonFk': value};
+ return {'c.salesPersonFk': value};
case 'attenderFk':
return {'cl.workerFk': value};
case 'created':
@@ -118,29 +155,23 @@ module.exports = Self => {
}
});
- filter = mergeFilters(ctx.args.filter, {where});
+ filter = mergeFilters(args.filter, {where});
const stmts = [];
const stmt = new ParameterizedSQL(
- `SELECT *
- FROM (
- SELECT
- cl.id,
- cl.clientFk,
- c.name AS clientName,
- cl.workerFk,
- u.name AS workerName,
- cs.description,
- cl.created,
- cs.priority,
- 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
- LEFT JOIN account.user u ON u.id = w.userFk
- LEFT JOIN claimState cs ON cs.id = cl.claimStateFk ) cl`
+ `SELECT
+ cl.id,
+ cl.clientFk,
+ c.name AS clientName,
+ cl.workerFk,
+ u.name AS workerName,
+ cs.description,
+ cl.created
+ FROM claim cl
+ LEFT JOIN client c ON c.id = cl.clientFk
+ LEFT JOIN account.user u ON u.id = cl.workerFk
+ LEFT JOIN claimState cs ON cs.id = cl.claimStateFk`
);
stmt.merge(conn.makeSuffix(filter));
diff --git a/modules/claim/back/methods/claim/specs/filter.spec.js b/modules/claim/back/methods/claim/specs/filter.spec.js
index b26afe8c4..49e258505 100644
--- a/modules/claim/back/methods/claim/specs/filter.spec.js
+++ b/modules/claim/back/methods/claim/specs/filter.spec.js
@@ -57,4 +57,44 @@ describe('claim filter()', () => {
throw e;
}
});
+
+ it('should return 3 results filtering by item id', async() => {
+ const tx = await app.models.Claim.beginTransaction({});
+
+ try {
+ const options = {transaction: tx};
+
+ const result = await app.models.Claim.filter({args: {filter: {}, itemFk: 2}}, null, options);
+
+ expect(result.length).toEqual(3);
+ expect(result[0].id).toEqual(1);
+ expect(result[1].id).toEqual(2);
+ expect(result[2].id).toEqual(4);
+
+ await tx.rollback();
+ } catch (e) {
+ await tx.rollback();
+ throw e;
+ }
+ });
+
+ it('should return 3 results filtering by claimResponsible id', async() => {
+ const tx = await app.models.Claim.beginTransaction({});
+
+ try {
+ const options = {transaction: tx};
+
+ const result = await app.models.Claim.filter({args: {filter: {}, claimResponsibleFk: 7}}, null, options);
+
+ expect(result.length).toEqual(3);
+ expect(result[0].id).toEqual(2);
+ expect(result[1].id).toEqual(3);
+ expect(result[2].id).toEqual(4);
+
+ await tx.rollback();
+ } catch (e) {
+ await tx.rollback();
+ throw e;
+ }
+ });
});
diff --git a/modules/claim/front/search-panel/index.html b/modules/claim/front/search-panel/index.html
index eec8cd727..151a06c8e 100644
--- a/modules/claim/front/search-panel/index.html
+++ b/modules/claim/front/search-panel/index.html
@@ -58,8 +58,28 @@
ng-model="filter.created">
+
{{ $t('clientMail') }} {{email}}
+{{ $t('ticketId') }} {{ticketId}} + + diff --git a/print/templates/email/invoice-electronic/invoice-electronic.js b/print/templates/email/invoice-electronic/invoice-electronic.js new file mode 100644 index 000000000..2e1e739ac --- /dev/null +++ b/print/templates/email/invoice-electronic/invoice-electronic.js @@ -0,0 +1,21 @@ +module.exports = { + name: 'invoice-electronic', + props: { + name: { + type: [String], + required: true + }, + email: { + type: [String], + required: true + }, + ticketId: { + type: [Number], + required: true + }, + url: { + type: [String], + required: true + } + }, +}; diff --git a/print/templates/email/invoice-electronic/locale/en.yml b/print/templates/email/invoice-electronic/locale/en.yml new file mode 100644 index 000000000..5523a2fa3 --- /dev/null +++ b/print/templates/email/invoice-electronic/locale/en.yml @@ -0,0 +1,4 @@ +subject: A electronic invoice has been created +title: A new electronic invoice has been created for the client +clientMail: The client's email is +ticketId: The invoice's ticket is \ No newline at end of file diff --git a/print/templates/email/invoice-electronic/locale/es.yml b/print/templates/email/invoice-electronic/locale/es.yml new file mode 100644 index 000000000..2cbcfbb36 --- /dev/null +++ b/print/templates/email/invoice-electronic/locale/es.yml @@ -0,0 +1,4 @@ +subject: Se ha creado una factura electrónica +title: Se ha creado una nueva factura electrónica para el cliente +clientMail: El correo del cliente es +ticketId: El ticket de la factura es \ No newline at end of file diff --git a/print/templates/reports/invoice/invoice.js b/print/templates/reports/invoice/invoice.js index 48848c079..f7011ad81 100755 --- a/print/templates/reports/invoice/invoice.js +++ b/print/templates/reports/invoice/invoice.js @@ -82,7 +82,7 @@ module.exports = { return this.rawSqlFromDef(`taxes`, [reference]); }, fetchIntrastat(reference) { - return this.rawSqlFromDef(`intrastat`, [reference, reference, reference, reference, reference]); + return this.rawSqlFromDef(`intrastat`, [reference, reference, reference]); }, fetchRectified(reference) { return this.rawSqlFromDef(`rectified`, [reference]); diff --git a/print/templates/reports/invoice/sql/intrastat.sql b/print/templates/reports/invoice/sql/intrastat.sql index 7f5fbdf39..f986a9564 100644 --- a/print/templates/reports/invoice/sql/intrastat.sql +++ b/print/templates/reports/invoice/sql/intrastat.sql @@ -1,39 +1,26 @@ SELECT * FROM invoiceOut io JOIN invoiceOutSerial ios ON io.serial = ios.code - JOIN - (SELECT - t.refFk, - ir.id code, - ir.description description, - CAST(SUM(IFNULL(i.stems, 1) * s.quantity) AS DECIMAL(10,2)) stems, - CAST(SUM(CAST(IFNULL(i.stems, 1) * s.quantity * IF(ic.grams, ic.grams, i.density * ic.cm3delivery / 1000) / 1000 AS DECIMAL(10,2)) * - IF(sub.weight, sub.weight / vn.invoiceOut_getWeight(?), 1)) AS DECIMAL(10,2)) netKg, - CAST(SUM((s.quantity * s.price * (100 - s.discount) / 100 )) AS DECIMAL(10,2)) subtotal - FROM vn.ticket t - JOIN vn.sale s ON s.ticketFk = t.id - JOIN vn.item i ON i.id = s.itemFk - JOIN vn.itemCost ic ON ic.itemFk = i.id AND ic.warehouseFk = t.warehouseFk - JOIN vn.intrastat ir ON ir.id = i.intrastatFk - LEFT JOIN ( - SELECT t2.weight - FROM vn.ticket t2 - WHERE refFk = ? AND weight - LIMIT 1 - ) sub ON TRUE - WHERE t.refFk = ? - AND i.intrastatFk - GROUP BY i.intrastatFk - UNION ALL - SELECT - NULL AS refFk, - NULL AS code, - NULL AS description, - 0 AS stems, - 0 AS netKg, - IF(CAST(SUM((ts.quantity * ts.price)) AS DECIMAL(10,2)), CAST(SUM((ts.quantity * ts.price)) AS DECIMAL(10,2)), 0) AS subtotal - FROM vn.ticketService ts - JOIN vn.ticket t ON ts.ticketFk = t.id - WHERE t.refFk = ?) sub - WHERE io.`ref` = ? AND ios.isCEE - ORDER BY sub.code; + JOIN( + SELECT ir.id code, + ir.description, + iii.stems, + iii.net netKg, + iii.amount subtotal + FROM vn.invoiceInIntrastat iii + LEFT JOIN vn.invoiceIn ii ON ii.id = iii.invoiceInFk + LEFT JOIN vn.invoiceOut io ON io.ref = ii.supplierRef + LEFT JOIN vn.intrastat ir ON ir.id = iii.intrastatFk + WHERE io.`ref` = ? + UNION ALL + SELECT NULL code, + 'Servicios' description, + 0 stems, + 0 netKg, + IF(CAST(SUM((ts.quantity * ts.price)) AS DECIMAL(10,2)), CAST(SUM((ts.quantity * ts.price)) AS DECIMAL(10,2)), 0) subtotal + FROM vn.ticketService ts + JOIN vn.ticket t ON ts.ticketFk = t.id + WHERE t.refFk = ? + ) sub + WHERE io.ref = ? AND ios.isCEE + ORDER BY sub.code;