diff --git a/CHANGELOG.md b/CHANGELOG.md
index d7073dc53..3f241b91f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,8 +9,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
- [General](Inicio) Permite recuperar la contraseña
+- [Artículo](Datos Básicos) Añadido campo Unidades/Caja
### Changed
+- [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/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 fc6f25551..7563a0da9 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);
diff --git a/e2e/helpers/selectors.js b/e2e/helpers/selectors.js
index e1792ea7b..052d8a480 100644
--- a/e2e/helpers/selectors.js
+++ b/e2e/helpers/selectors.js
@@ -463,6 +463,7 @@ export default {
generic: 'vn-autocomplete[ng-model="$ctrl.item.genericFk"]',
isFragile: 'vn-check[ng-model="$ctrl.item.isFragile"]',
longName: 'vn-textfield[ng-model="$ctrl.item.longName"]',
+ packingOut: 'vn-input-number[ng-model="$ctrl.item.packingOut"]',
isActiveCheckbox: 'vn-check[label="Active"]',
priceInKgCheckbox: 'vn-check[label="Price in kg"]',
newIntrastatButton: 'vn-item-basic-data vn-icon-button[vn-tooltip="New intrastat"] > button',
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/e2e/paths/04-item/02_basic_data.spec.js b/e2e/paths/04-item/02_basic_data.spec.js
index a663ea3bb..3cf142816 100644
--- a/e2e/paths/04-item/02_basic_data.spec.js
+++ b/e2e/paths/04-item/02_basic_data.spec.js
@@ -35,6 +35,7 @@ describe('Item Edit basic data path', () => {
await page.waitToClick(selectors.itemBasicData.isActiveCheckbox);
await page.waitToClick(selectors.itemBasicData.priceInKgCheckbox);
await page.waitToClick(selectors.itemBasicData.isFragile);
+ await page.write(selectors.itemBasicData.packingOut, '5');
await page.waitToClick(selectors.itemBasicData.submitBasicDataButton);
const message = await page.waitForSnackbar();
@@ -128,4 +129,11 @@ describe('Item Edit basic data path', () => {
expect(result).toBe('checked');
});
+
+ it(`should confirm the item packingOut was edited`, async() => {
+ const result = await page
+ .waitToGetProperty(selectors.itemBasicData.packingOut, 'value');
+
+ expect(result).toEqual('5');
+ });
});
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/package-lock.json b/front/package-lock.json
index 6922cae53..d0fe4de2d 100644
--- a/front/package-lock.json
+++ b/front/package-lock.json
@@ -1,7 +1,7 @@
{
"name": "salix-front",
"version": "1.0.0",
- "lockfileVersion": 1,
+ "lockfileVersion": 2,
"requires": true,
"packages": {
"": {
@@ -25,8 +25,7 @@
},
"node_modules/@uirouter/angularjs": {
"version": "1.0.30",
- "resolved": "https://registry.npmjs.org/@uirouter/angularjs/-/angularjs-1.0.30.tgz",
- "integrity": "sha512-qkc3RFZc91S5K0gc/QVAXc9LGDPXjR04vDgG/11j8+yyZEuQojXxKxdLhKIepiPzqLmGRVqzBmBc27gtqaEeZg==",
+ "license": "MIT",
"dependencies": {
"@uirouter/core": "6.0.8"
},
@@ -39,17 +38,14 @@
},
"node_modules/@uirouter/core": {
"version": "6.0.8",
- "resolved": "https://registry.npmjs.org/@uirouter/core/-/core-6.0.8.tgz",
- "integrity": "sha512-Gc/BAW47i4L54p8dqYCJJZuv2s3tqlXQ0fvl6Zp2xrblELPVfxmjnc0eurx3XwfQdaqm3T6uls6tQKkof/4QMw==",
+ "license": "MIT",
"engines": {
"node": ">=4.0.0"
}
},
"node_modules/angular": {
"version": "1.8.3",
- "resolved": "https://registry.npmjs.org/angular/-/angular-1.8.3.tgz",
- "integrity": "sha512-5qjkWIQQVsHj4Sb5TcEs4WZWpFeVFHXwxEBHUhrny41D8UrBAd6T/6nPPAsLngJCReIOqi95W3mxdveveutpZw==",
- "deprecated": "For the actively supported Angular, see https://www.npmjs.com/package/@angular/core. AngularJS support has officially ended. For extended AngularJS support options, see https://goo.gle/angularjs-path-forward."
+ "license": "MIT"
},
"node_modules/angular-animate": {
"version": "1.8.2",
@@ -67,8 +63,7 @@
},
"node_modules/angular-translate": {
"version": "2.19.0",
- "resolved": "https://registry.npmjs.org/angular-translate/-/angular-translate-2.19.0.tgz",
- "integrity": "sha512-Z/Fip5uUT2N85dPQ0sMEe1JdF5AehcDe4tg/9mWXNDVU531emHCg53ZND9Oe0dyNiGX5rWcJKmsL1Fujus1vGQ==",
+ "license": "MIT",
"dependencies": {
"angular": "^1.8.0"
},
@@ -78,8 +73,7 @@
},
"node_modules/angular-translate-loader-partial": {
"version": "2.19.0",
- "resolved": "https://registry.npmjs.org/angular-translate-loader-partial/-/angular-translate-loader-partial-2.19.0.tgz",
- "integrity": "sha512-NnMw13LMV4bPQmJK7/pZOZAnPxe0M5OtUHchADs5Gye7V7feonuEnrZ8e1CKhBlv9a7IQyWoqcBa4Lnhg8gk5w==",
+ "license": "MIT",
"dependencies": {
"angular-translate": "~2.19.0"
}
@@ -126,8 +120,7 @@
},
"node_modules/moment": {
"version": "2.29.4",
- "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz",
- "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==",
+ "license": "MIT",
"engines": {
"node": "*"
}
@@ -172,73 +165,51 @@
"dependencies": {
"@uirouter/angularjs": {
"version": "1.0.30",
- "resolved": "https://registry.npmjs.org/@uirouter/angularjs/-/angularjs-1.0.30.tgz",
- "integrity": "sha512-qkc3RFZc91S5K0gc/QVAXc9LGDPXjR04vDgG/11j8+yyZEuQojXxKxdLhKIepiPzqLmGRVqzBmBc27gtqaEeZg==",
"requires": {
"@uirouter/core": "6.0.8"
}
},
"@uirouter/core": {
- "version": "6.0.8",
- "resolved": "https://registry.npmjs.org/@uirouter/core/-/core-6.0.8.tgz",
- "integrity": "sha512-Gc/BAW47i4L54p8dqYCJJZuv2s3tqlXQ0fvl6Zp2xrblELPVfxmjnc0eurx3XwfQdaqm3T6uls6tQKkof/4QMw=="
+ "version": "6.0.8"
},
"angular": {
- "version": "1.8.3",
- "resolved": "https://registry.npmjs.org/angular/-/angular-1.8.3.tgz",
- "integrity": "sha512-5qjkWIQQVsHj4Sb5TcEs4WZWpFeVFHXwxEBHUhrny41D8UrBAd6T/6nPPAsLngJCReIOqi95W3mxdveveutpZw=="
+ "version": "1.8.3"
},
"angular-animate": {
- "version": "1.8.2",
- "resolved": "https://registry.npmjs.org/angular-animate/-/angular-animate-1.8.2.tgz",
- "integrity": "sha512-Jbr9+grNMs9Kj57xuBU3Ju3NOPAjS1+g2UAwwDv7su1lt0/PLDy+9zEwDiu8C8xJceoTbmBNKiWGPJGBdCQLlA=="
+ "version": "1.8.2"
},
"angular-moment": {
"version": "1.3.0",
- "resolved": "https://registry.npmjs.org/angular-moment/-/angular-moment-1.3.0.tgz",
- "integrity": "sha512-KG8rvO9MoaBLwtGnxTeUveSyNtrL+RNgGl1zqWN36+HDCCVGk2DGWOzqKWB6o+eTTbO3Opn4hupWKIElc8XETA==",
"requires": {
"moment": ">=2.8.0 <3.0.0"
}
},
"angular-translate": {
"version": "2.19.0",
- "resolved": "https://registry.npmjs.org/angular-translate/-/angular-translate-2.19.0.tgz",
- "integrity": "sha512-Z/Fip5uUT2N85dPQ0sMEe1JdF5AehcDe4tg/9mWXNDVU531emHCg53ZND9Oe0dyNiGX5rWcJKmsL1Fujus1vGQ==",
"requires": {
"angular": "^1.8.0"
}
},
"angular-translate-loader-partial": {
"version": "2.19.0",
- "resolved": "https://registry.npmjs.org/angular-translate-loader-partial/-/angular-translate-loader-partial-2.19.0.tgz",
- "integrity": "sha512-NnMw13LMV4bPQmJK7/pZOZAnPxe0M5OtUHchADs5Gye7V7feonuEnrZ8e1CKhBlv9a7IQyWoqcBa4Lnhg8gk5w==",
"requires": {
"angular-translate": "~2.19.0"
}
},
"argparse": {
"version": "1.0.10",
- "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
- "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
"requires": {
"sprintf-js": "~1.0.2"
}
},
"croppie": {
- "version": "2.6.5",
- "resolved": "https://registry.npmjs.org/croppie/-/croppie-2.6.5.tgz",
- "integrity": "sha512-IlChnVUGG5T3w2gRZIaQgBtlvyuYnlUWs2YZIXXR3H9KrlO1PtBT3j+ykxvy9eZIWhk+V5SpBmhCQz5UXKrEKQ=="
+ "version": "2.6.5"
},
"esprima": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
- "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="
+ "version": "4.0.1"
},
"js-yaml": {
"version": "3.14.1",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
- "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
"requires": {
"argparse": "^1.0.7",
"esprima": "^4.0.0"
@@ -246,39 +217,27 @@
},
"mg-crud": {
"version": "1.1.2",
- "resolved": "https://registry.npmjs.org/mg-crud/-/mg-crud-1.1.2.tgz",
- "integrity": "sha512-mAR6t0aQHKnT0QHKHpLOi0kNPZfO36iMpIoiLjFHxuio6mIJyuveBJ4VNlNXJRxLh32/FLADEb41/sYo7QUKFw==",
"requires": {
"angular": "^1.6.1"
}
},
"moment": {
- "version": "2.29.4",
- "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz",
- "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w=="
+ "version": "2.29.4"
},
"oclazyload": {
- "version": "0.6.3",
- "resolved": "https://registry.npmjs.org/oclazyload/-/oclazyload-0.6.3.tgz",
- "integrity": "sha512-HpOSYUgjtt6sTB/C6+FWsExR+9HCnXKsUA96RWkDXfv11C8Cc9X2DlR0WIZwFIiG6FQU0pwB5dhoYyut8bFAOQ=="
+ "version": "0.6.3"
},
"require-yaml": {
"version": "0.0.1",
- "resolved": "https://registry.npmjs.org/require-yaml/-/require-yaml-0.0.1.tgz",
- "integrity": "sha512-M6eVEgLPRbeOhgSCnOTtdrOOEQzbXRchg24Xa13c39dMuraFKdI9emUo97Rih0YEFzSICmSKg8w4RQp+rd9pOQ==",
"requires": {
- "js-yaml": "^4.1.0"
+ "js-yaml": ""
},
"dependencies": {
"argparse": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
- "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
+ "version": "2.0.1"
},
"js-yaml": {
"version": "4.1.0",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
- "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
"requires": {
"argparse": "^2.0.1"
}
@@ -286,14 +245,10 @@
}
},
"sprintf-js": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
- "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g=="
+ "version": "1.0.3"
},
"validator": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/validator/-/validator-6.3.0.tgz",
- "integrity": "sha512-BylxTwhqwjQI5MDJF7amCy/L0ejJO+74DvCsLV52Lq3+3bhVcVMKqNqOiNcQJm2G48u9EAcw4xFERAmFbwXM9Q=="
+ "version": "6.3.0"
}
}
}
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">
+
+
+ {{::id}} - {{::name}}
+
+
+
+
-
\ No newline at end of file
+
diff --git a/modules/claim/front/search-panel/index.js b/modules/claim/front/search-panel/index.js
index a7e8fb046..2400b8ede 100644
--- a/modules/claim/front/search-panel/index.js
+++ b/modules/claim/front/search-panel/index.js
@@ -1,7 +1,14 @@
import ngModule from '../module';
import SearchPanel from 'core/components/searchbar/search-panel';
+class Controller extends SearchPanel {
+ itemSearchFunc($search) {
+ return /^\d+$/.test($search)
+ ? {id: $search}
+ : {name: {like: '%' + $search + '%'}};
+ }
+}
ngModule.vnComponent('vnClaimSearchPanel', {
template: require('./index.html'),
- controller: SearchPanel
+ controller: Controller
});
diff --git a/modules/client/front/balance/create/index.js b/modules/client/front/balance/create/index.js
index 935129574..35b2e0b38 100644
--- a/modules/client/front/balance/create/index.js
+++ b/modules/client/front/balance/create/index.js
@@ -4,7 +4,7 @@ import Dialog from 'core/components/dialog';
class Controller extends Dialog {
constructor($element, $, $transclude, vnReport) {
super($element, $, $transclude);
-
+ this.viewReceipt = true;
this.vnReport = vnReport;
this.receipt = {};
}
diff --git a/modules/client/front/balance/create/index.spec.js b/modules/client/front/balance/create/index.spec.js
index fa6b48ea4..2c4ed1940 100644
--- a/modules/client/front/balance/create/index.spec.js
+++ b/modules/client/front/balance/create/index.spec.js
@@ -75,6 +75,7 @@ describe('Client', () => {
jest.spyOn(controller.vnReport, 'show');
controller.$params = {id: 1101};
+ controller.viewReceipt = false;
$httpBackend.expect('POST', `Clients/1101/createReceipt`).respond({id: 1});
controller.responseHandler('accept');
diff --git a/modules/invoiceOut/back/methods/invoiceOut/specs/createPdf.spec.js b/modules/invoiceOut/back/methods/invoiceOut/specs/createPdf.spec.js
index ee3310368..803338ef3 100644
--- a/modules/invoiceOut/back/methods/invoiceOut/specs/createPdf.spec.js
+++ b/modules/invoiceOut/back/methods/invoiceOut/specs/createPdf.spec.js
@@ -11,7 +11,6 @@ describe('InvoiceOut createPdf()', () => {
const ctx = {req: activeCtx};
it('should create a new PDF file and set true the hasPdf property', async() => {
- pending('https://redmine.verdnatura.es/issues/4875');
const invoiceId = 1;
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
active: activeCtx
diff --git a/modules/invoiceOut/back/methods/invoiceOut/specs/downloadZip.spec.js b/modules/invoiceOut/back/methods/invoiceOut/specs/downloadZip.spec.js
index 4d1833635..0f62a6876 100644
--- a/modules/invoiceOut/back/methods/invoiceOut/specs/downloadZip.spec.js
+++ b/modules/invoiceOut/back/methods/invoiceOut/specs/downloadZip.spec.js
@@ -13,7 +13,6 @@ describe('InvoiceOut downloadZip()', () => {
};
it('should return part of link to dowloand the zip', async() => {
- pending('https://redmine.verdnatura.es/issues/4875');
const tx = await models.InvoiceOut.beginTransaction({});
try {
@@ -31,6 +30,8 @@ describe('InvoiceOut downloadZip()', () => {
});
it('should return an error if the size of the files is too large', async() => {
+ pending('https://redmine.verdnatura.es/issues/5035');
+
const tx = await models.InvoiceOut.beginTransaction({});
let error;
diff --git a/modules/invoiceOut/back/methods/invoiceOut/specs/filter.spec.js b/modules/invoiceOut/back/methods/invoiceOut/specs/filter.spec.js
index 7b5886236..e5cf5fda0 100644
--- a/modules/invoiceOut/back/methods/invoiceOut/specs/filter.spec.js
+++ b/modules/invoiceOut/back/methods/invoiceOut/specs/filter.spec.js
@@ -51,7 +51,6 @@ describe('InvoiceOut filter()', () => {
});
it('should return the invoice out matching hasPdf', async() => {
- pending('https://redmine.verdnatura.es/issues/4875');
const tx = await models.InvoiceOut.beginTransaction({});
const options = {transaction: tx};
@@ -67,7 +66,7 @@ describe('InvoiceOut filter()', () => {
const result = await models.InvoiceOut.filter(ctx, {id: invoiceOut.id}, options);
- expect(result.length).toEqual(1);
+ expect(result.length).toBeGreaterThanOrEqual(1);
await tx.rollback();
} catch (e) {
diff --git a/modules/invoiceOut/front/descriptor-menu/index.html b/modules/invoiceOut/front/descriptor-menu/index.html
index 1c0919288..389fcf81b 100644
--- a/modules/invoiceOut/front/descriptor-menu/index.html
+++ b/modules/invoiceOut/front/descriptor-menu/index.html
@@ -17,12 +17,12 @@
target="_blank"
name="showInvoicePdf"
translate>
- Show as PDF
+ as PDF
- Show as CSV
+ as CSV
diff --git a/modules/invoiceOut/front/descriptor-menu/locale/es.yml b/modules/invoiceOut/front/descriptor-menu/locale/es.yml
index 488c1a3f8..df0ba57cf 100644
--- a/modules/invoiceOut/front/descriptor-menu/locale/es.yml
+++ b/modules/invoiceOut/front/descriptor-menu/locale/es.yml
@@ -2,6 +2,8 @@ Show invoice...: Ver factura...
Send invoice...: Enviar factura...
Send PDF invoice: Enviar factura en PDF
Send CSV invoice: Enviar factura en CSV
+as PDF: como PDF
+as CSV: como CSV
Delete Invoice: Eliminar factura
Clone Invoice: Clonar factura
Book invoice: Asentar factura
diff --git a/modules/item/back/methods/item-shelving-sale/filter.js b/modules/item/back/methods/item-shelving-sale/filter.js
new file mode 100644
index 000000000..12029d33d
--- /dev/null
+++ b/modules/item/back/methods/item-shelving-sale/filter.js
@@ -0,0 +1,49 @@
+
+const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
+
+module.exports = Self => {
+ Self.remoteMethod('filter', {
+ description: 'Returns all item shelving sale matching with the filter',
+ accessType: 'READ',
+ accepts: [{
+ arg: 'filter',
+ type: 'object',
+ description: 'Filter defining where and paginated data'
+ }],
+ returns: {
+ type: ['object'],
+ root: true
+ },
+ http: {
+ path: `/filter`,
+ verb: 'GET'
+ }
+ });
+
+ Self.filter = async(filter, options) => {
+ const conn = Self.dataSource.connector;
+ const myOptions = {};
+
+ if (typeof options == 'object')
+ Object.assign(myOptions, options);
+
+ const stmt = new ParameterizedSQL(`
+ SELECT iss.created,
+ iss.saleFk,
+ iss.quantity,
+ iss.userFk,
+ ish.shelvingFk,
+ p.code,
+ u.name
+ FROM itemShelvingSale iss
+ LEFT JOIN itemShelving ish ON iss.itemShelvingFk = ish.id
+ LEFT JOIN shelving s ON ish.shelvingFk = s.code
+ LEFT JOIN parking p ON s.parkingFk = p.id
+ LEFT JOIN account.user u ON u.id = iss.userFk`
+ );
+
+ stmt.merge(conn.makeSuffix(filter));
+
+ return conn.executeStmt(stmt);
+ };
+};
diff --git a/modules/item/back/models/item-shelving-sale.js b/modules/item/back/models/item-shelving-sale.js
new file mode 100644
index 000000000..b89be9f00
--- /dev/null
+++ b/modules/item/back/models/item-shelving-sale.js
@@ -0,0 +1,3 @@
+module.exports = Self => {
+ require('../methods/item-shelving-sale/filter')(Self);
+};
diff --git a/modules/item/back/models/item-shelving.json b/modules/item/back/models/item-shelving.json
index 951a4553a..0890350da 100644
--- a/modules/item/back/models/item-shelving.json
+++ b/modules/item/back/models/item-shelving.json
@@ -12,21 +12,12 @@
"id": true,
"description": "Identifier"
},
- "shelve": {
- "type": "string"
- },
"shelvingFk": {
"type": "string"
},
"itemFk": {
"type": "number"
},
- "deep": {
- "type": "number"
- },
- "quantity": {
- "type": "number"
- },
"created": {
"type": "date"
}
@@ -41,6 +32,11 @@
"type": "belongsTo",
"model": "Account",
"foreignKey": "userFk"
- }
+ },
+ "shelving": {
+ "type": "belongsTo",
+ "model": "Shelving",
+ "foreignKey": "shelvingFk"
+ }
}
}
diff --git a/modules/item/front/basic-data/index.html b/modules/item/front/basic-data/index.html
index 8d1afe4e1..fd21ab240 100644
--- a/modules/item/front/basic-data/index.html
+++ b/modules/item/front/basic-data/index.html
@@ -1,6 +1,6 @@
-
-
@@ -95,7 +95,7 @@
@@ -108,15 +108,15 @@
@@ -124,10 +124,17 @@
+
+
-
@@ -225,12 +232,12 @@
-
\ No newline at end of file
+
diff --git a/modules/item/front/locale/es.yml b/modules/item/front/locale/es.yml
index 88ab031e1..0fc014742 100644
--- a/modules/item/front/locale/es.yml
+++ b/modules/item/front/locale/es.yml
@@ -44,6 +44,7 @@ Weight/Piece: Peso/tallo
Search items by id, name or barcode: Buscar articulos por identificador, nombre o codigo de barras
SalesPerson: Comercial
Concept: Concepto
+Units/Box: Unidades/Caja
# Sections
Items: Artículos
@@ -61,4 +62,4 @@ Item diary: Registro de compra-venta
Last entries: Últimas entradas
Tags: Etiquetas
Waste breakdown: Desglose de mermas
-Waste breakdown by item: Desglose de mermas por artículo
\ No newline at end of file
+Waste breakdown by item: Desglose de mermas por artículo
diff --git a/modules/ticket/back/methods/sale/salePreparingList.js b/modules/ticket/back/methods/sale/salePreparingList.js
new file mode 100644
index 000000000..e6e7d5164
--- /dev/null
+++ b/modules/ticket/back/methods/sale/salePreparingList.js
@@ -0,0 +1,33 @@
+module.exports = Self => {
+ Self.remoteMethodCtx('salePreparingList', {
+ description: 'Returns a list with the lines of a ticket and its different states of preparation',
+ accessType: 'READ',
+ accepts: [{
+ arg: 'id',
+ type: 'number',
+ required: true,
+ description: 'The ticket id',
+ http: {source: 'path'}
+ }],
+ returns: {
+ type: ['object'],
+ root: true
+ },
+ http: {
+ path: `/:id/salePreparingList`,
+ verb: 'GET'
+ }
+ });
+
+ Self.salePreparingList = async(ctx, id, options) => {
+ const myOptions = {};
+
+ if (typeof options == 'object')
+ Object.assign(myOptions, options);
+
+ query = `CALL vn.salePreparingList(?)`;
+ const [sales] = await Self.rawSql(query, [id], myOptions);
+
+ return sales;
+ };
+};
diff --git a/modules/ticket/back/models/sale.js b/modules/ticket/back/models/sale.js
index ae247fc24..bab201fdd 100644
--- a/modules/ticket/back/models/sale.js
+++ b/modules/ticket/back/models/sale.js
@@ -1,5 +1,6 @@
module.exports = Self => {
require('../methods/sale/getClaimableFromTicket')(Self);
+ require('../methods/sale/salePreparingList')(Self);
require('../methods/sale/reserve')(Self);
require('../methods/sale/deleteSales')(Self);
require('../methods/sale/updatePrice')(Self);
diff --git a/modules/ticket/front/sale-tracking/index.html b/modules/ticket/front/sale-tracking/index.html
index fc585650a..851817551 100644
--- a/modules/ticket/front/sale-tracking/index.html
+++ b/modules/ticket/front/sale-tracking/index.html
@@ -1,10 +1,11 @@
@@ -12,31 +13,27 @@
-
+ Is checked
Item
- Description
+ Description
Quantity
- Original
- Worker
- State
- Created
+
-
-
-
-
+
+
+
+
+
+
+
- {{sale.itemFk | zeroFill:6}}
+ {{::sale.itemFk | zeroFill:6}}
@@ -53,16 +50,18 @@
{{::sale.quantity}}
- {{::sale.originalQuantity}}
-
-
- {{::sale.userNickname | dashIfEmpty}}
-
+
+
+
+
+
- {{::sale.state}}
- {{::sale.created | date: 'dd/MM/yyyy HH:mm'}}
@@ -70,8 +69,99 @@
+ warehouse-fk="$ctrl.ticket.warehouseFk"
+ ticket-fk="$ctrl.ticket.id">
-
-
\ No newline at end of file
+
+
+
+
+
+
+
+
+
+ Quantity
+ Original
+ Worker
+ State
+ Created
+
+
+
+
+ {{::sale.quantity}}
+ {{::sale.originalQuantity}}
+
+
+ {{::sale.userNickname | dashIfEmpty}}
+
+
+ {{::sale.state}}
+ {{::sale.created | date: 'dd/MM/yyyy HH:mm'}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Quantity
+ Worker
+ Shelving
+ Parking
+ Created
+
+
+
+
+ {{::itemShelvingSale.quantity}}
+
+
+ {{::itemShelvingSale.name | dashIfEmpty}}
+
+
+ {{::itemShelvingSale.shelvingFk}}
+ {{::itemShelvingSale.code}}
+ {{::itemShelvingSale.created | date: 'dd/MM/yyyy HH:mm'}}
+
+
+
+
+
+
+
+
diff --git a/modules/ticket/front/sale-tracking/index.js b/modules/ticket/front/sale-tracking/index.js
index 394ef4f1e..60e42a461 100644
--- a/modules/ticket/front/sale-tracking/index.js
+++ b/modules/ticket/front/sale-tracking/index.js
@@ -1,12 +1,100 @@
import ngModule from '../module';
import Section from 'salix/components/section';
+import './style.scss';
-class Controller extends Section {}
+class Controller extends Section {
+ constructor($element, $) {
+ super($element, $);
+ this.filter = {
+ include: [
+ {
+ relation: 'item'
+ }, {
+ relation: 'saleTracking',
+ scope: {
+ fields: ['isChecked']
+ }
+ }
+ ]
+ };
+ }
+
+ get sales() {
+ return this._sales;
+ }
+
+ set sales(value) {
+ this._sales = value;
+ if (value) {
+ const query = `Sales/${this.$params.id}/salePreparingList`;
+ this.$http.get(query)
+ .then(res => {
+ this.salePreparingList = res.data;
+ for (const salePreparing of this.salePreparingList) {
+ for (const sale of this.sales) {
+ if (salePreparing.saleFk == sale.id)
+ sale.preparingList = salePreparing;
+ }
+ }
+ });
+ }
+ }
+
+ showItemDescriptor(event, sale) {
+ this.quicklinks = {
+ btnThree: {
+ icon: 'icon-transaction',
+ state: `item.card.diary({
+ id: ${sale.itemFk},
+ warehouseFk: ${this.ticket.warehouseFk},
+ lineFk: ${sale.id}
+ })`,
+ tooltip: 'Item diary'
+ }
+ };
+ this.$.itemDescriptor.show(event.target, sale.itemFk);
+ }
+
+ chipHasSaleGroupDetail(hasSaleGroupDetail) {
+ if (hasSaleGroupDetail) return 'pink';
+ else return 'message';
+ }
+
+ chipIsPreviousSelected(isPreviousSelected) {
+ if (isPreviousSelected) return 'notice';
+ else return 'message';
+ }
+
+ chipIsPrevious(isPrevious) {
+ if (isPrevious) return 'dark-notice';
+ else return 'message';
+ }
+
+ chipIsPrepared(isPrepared) {
+ if (isPrepared) return 'warning';
+ else return 'message';
+ }
+
+ chipIsControled(isControled) {
+ if (isControled) return 'yellow';
+ else return 'message';
+ }
+
+ showSaleTracking(sale) {
+ this.saleId = sale.id;
+ this.$.saleTracking.show();
+ }
+
+ showItemShelvingSale(sale) {
+ this.saleId = sale.id;
+ this.$.itemShelvingSale.show();
+ }
+}
ngModule.vnComponent('vnTicketSaleTracking', {
template: require('./index.html'),
controller: Controller,
bindings: {
- ticket: '<',
- },
+ ticket: '<'
+ }
});
diff --git a/modules/ticket/front/sale-tracking/locale/es.yml b/modules/ticket/front/sale-tracking/locale/es.yml
new file mode 100644
index 000000000..eabc0a04d
--- /dev/null
+++ b/modules/ticket/front/sale-tracking/locale/es.yml
@@ -0,0 +1,6 @@
+ItemShelvings sale: Carros línea
+has saleGroupDetail: tiene detalle grupo lineas
+is previousSelected: es previa seleccionada
+is previous: es previa
+is prepared: esta preparado
+is controled: esta controlado
diff --git a/modules/ticket/front/sale-tracking/style.scss b/modules/ticket/front/sale-tracking/style.scss
new file mode 100644
index 000000000..6d8b3db69
--- /dev/null
+++ b/modules/ticket/front/sale-tracking/style.scss
@@ -0,0 +1,7 @@
+@import "variables";
+
+.chip {
+ display: inline-block;
+ min-width: 15px;
+ min-height: 25px;
+}