diff --git a/db/changes/10190-PostErte/00-ACL.sql b/db/changes/10190-PostErte/00-ACL.sql
index 2a2673fcc..8ef44224a 100644
--- a/db/changes/10190-PostErte/00-ACL.sql
+++ b/db/changes/10190-PostErte/00-ACL.sql
@@ -1,4 +1,5 @@
UPDATE `salix`.`ACL` SET `accessType`='WRITE' WHERE `id`='213';
+UPDATE `salix`.`ACL` SET `property` = 'deleteSales' WHERE (`id` = '80');
INSERT IGNORE INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES ('CustomsAgent', '*', '*', 'ALLOW', 'ROLE', 'employee');
diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql
index 95de30b06..e146ff893 100644
--- a/db/dump/fixtures.sql
+++ b/db/dump/fixtures.sql
@@ -1664,11 +1664,13 @@ INSERT INTO `vn`.`workCenterHoliday` (`workCenterFk`, `days`, `year`)
('1', '24.5', YEAR(DATE_ADD(CURDATE(), INTERVAL -1 YEAR))),
('5', '23', YEAR(DATE_ADD(CURDATE(), INTERVAL -1 YEAR)));
-INSERT INTO `postgresql`.`calendar_state` (`calendar_state_id`, `type`, `rgb`, `code`)
+INSERT INTO `postgresql`.`calendar_state` (`calendar_state_id`, `type`, `rgb`, `code`, `holidayEntitlementRate`)
VALUES
- (1, 'Holidays', '#FF4444', 'holiday'),
- (2, 'Leave of absence', '#C71585', 'absence'),
- (6, 'Half holiday', '#E65F00', 'halfHoliday');
+ (1, 'Holidays', '#FF4444', 'holiday', 0),
+ (2, 'Leave of absence', '#C71585', 'absence', 0),
+ (6, 'Half holiday', '#E65F00', 'halfHoliday', 0),
+ (20, 'Furlough', '#97B92F', 'furlough', 1),
+ (21, 'Furlough half day', '#778899', 'halfFurlough', 0.5);
INSERT INTO `postgresql`.`calendar_employee` (`business_id`, `calendar_state_id`, `date`)
VALUES
diff --git a/e2e/helpers/extensions.js b/e2e/helpers/extensions.js
index 636819860..a3c52748d 100644
--- a/e2e/helpers/extensions.js
+++ b/e2e/helpers/extensions.js
@@ -558,7 +558,7 @@ let actions = {
}, selector);
},
- closePopup: async function(selector) {
+ closePopup: async function() {
await Promise.all([
this.keyboard.press('Escape'),
this.waitFor('.vn-popup', {hidden: true}),
diff --git a/e2e/helpers/selectors.js b/e2e/helpers/selectors.js
index c9286ef43..f9a84ac65 100644
--- a/e2e/helpers/selectors.js
+++ b/e2e/helpers/selectors.js
@@ -401,8 +401,9 @@ export default {
createButton: `button[type=submit]`
},
ticketDescriptor: {
- idLabelValue: 'vn-ticket-descriptor vn-label-value[label="Id"]',
+ id: 'vn-descriptor-content div.top > div',
stateLabelValue: 'vn-ticket-descriptor vn-label-value[label="State"]',
+ isDeletedIcon: 'vn-ticket-descriptor vn-icon[icon="icon-deletedTicket"]',
goBackToModuleIndexButton: 'vn-ticket-descriptor a[ui-sref="ticket.index"]',
moreMenu: 'vn-ticket-descriptor vn-icon-button[icon=more_vert]',
moreMenuAddStowaway: '.vn-menu [name="addStowaway"]',
@@ -445,20 +446,23 @@ export default {
savePackagesButton: `button[type=submit]`
},
ticketSales: {
+ setOk: 'vn-ticket-sale vn-tool-bar > vn-button[label="Ok"] > button',
saleButton: 'vn-left-menu a[ui-sref="ticket.card.sale"]',
saleLine: 'vn-table div > vn-tbody > vn-tr',
saleDescriptorPopover: '.vn-popover.shown vn-item-descriptor',
- saleDescriptorPopoverSummaryButton: '.vn-popover.shown vn-item-descriptor a[ui-sref="item.card.summary({id: $ctrl.item.id})"]',
+ saleDescriptorPopoverSummaryButton: '.vn-popover.shown vn-item-descriptor a[ui-sref="item.card.summary({id: $ctrl.descriptor.id})"]',
descriptorItemDiaryButton: '.vn-popover vn-item-descriptor vn-quick-link[icon="icon-transaction"] > a',
newItemFromCatalogButton: 'vn-ticket-sale vn-float-button[icon="add"]',
newItemButton: 'vn-ticket-sale vn-card vn-icon-button[icon="add_circle"]',
- moreMenu: 'vn-ticket-sale vn-tool-bar > vn-button-menu[vn-id="more-button"] > div > button',
- moreMenuCreateClaim: '.vn-drop-down.shown li[name="Add claim"]',
- moreMenuReserve: '.vn-drop-down.shown li[name="Mark as reserved"]',
- moreMenuUnmarkReseved: '.vn-drop-down.shown li[name="Unmark as reserved"]',
- moreMenuUpdateDiscount: '.vn-drop-down.shown li[name="Update discount"]',
+ moreMenu: 'vn-ticket-sale vn-button[label="More"]',
+ moreMenuCreateClaim: 'vn-item[name="claim"]',
+ moreMenuReserve: 'vn-item[name="reserve"]',
+ moreMenuUnmarkReseved: 'vn-item[name="unreserve"]',
+ moreMenuUpdateDiscount: 'vn-item[name="discount"]',
+ moreMenuUpdateDiscountInput: 'vn-input-number[ng-model="$ctrl.edit.discount"] input',
transferQuantityInput: '.vn-popover.shown vn-table > div > vn-tbody > vn-tr > vn-td-editable > span > text',
transferQuantityCell: '.vn-popover.shown vn-table > div > vn-tbody > vn-tr > vn-td-editable',
+ firstSaleId: 'vn-ticket-sale vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(4) > span',
firstSaleClaimIcon: 'vn-ticket-sale vn-table vn-tbody > vn-tr:nth-child(1) vn-icon[icon="icon-claims"]',
firstSaleDescriptorImage: '.vn-popover.shown vn-item-descriptor img',
firstSaleText: 'vn-table div > vn-tbody > vn-tr:nth-child(1)',
@@ -468,9 +472,9 @@ export default {
firstSaleQuantityCell: 'vn-ticket-sale vn-tr:nth-child(1) > vn-td-editable:nth-child(5)',
firstSaleIdAutocomplete: 'vn-ticket-sale vn-table vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(4) > vn-autocomplete',
firstSalePrice: 'vn-ticket-sale vn-table vn-tr:nth-child(1) > vn-td:nth-child(7) > span',
- firstSalePriceInput: '.vn-popover.shown [ng-model="$ctrl.editedPrice"]',
+ firstSalePriceInput: '.vn-popover.shown input[ng-model="$ctrl.field"]',
firstSaleDiscount: 'vn-ticket-sale vn-table vn-tr:nth-child(1) > vn-td:nth-child(8) > span',
- firstSaleDiscountInput: '.vn-popover.shown [ng-model="$ctrl.newDiscount"]',
+ firstSaleDiscountInput: '.vn-popover.shown [ng-model="$ctrl.field"]',
firstSaleImport: 'vn-ticket-sale:nth-child(1) vn-td:nth-child(9)',
firstSaleReservedIcon: 'vn-ticket-sale vn-tr:nth-child(1) > vn-td:nth-child(2) > vn-icon:nth-child(3)',
firstSaleColour: 'vn-ticket-sale vn-tr:nth-child(1) vn-fetched-tags section',
@@ -486,20 +490,22 @@ export default {
secondSaleIdInput: 'vn-ticket-sale vn-table vn-tbody > vn-tr:nth-child(2) > vn-td:nth-child(4) > vn-autocomplete',
secondSaleIdAutocomplete: 'vn-ticket-sale vn-table vn-tbody > vn-tr:nth-child(2) > vn-td:nth-child(4) > vn-autocomplete',
secondSaleQuantity: 'vn-ticket-sale vn-table vn-tr:nth-child(2) vn-input-number',
+ secondSaleQuantityCell: 'vn-ticket-sale > div > vn-card > vn-table > div > vn-tbody > vn-tr:nth-child(2) > vn-td-editable:nth-child(5)',
secondSaleConceptCell: 'vn-ticket-sale vn-tbody > :nth-child(2) > :nth-child(6)',
secondSaleConceptInput: 'vn-ticket-sale vn-tbody > :nth-child(2) > vn-td-editable.ng-isolate-scope.selected vn-textfield',
- totalImport: 'vn-ticket-sale > vn-vertical > vn-card > vn-vertical > vn-horizontal > vn-one > p:nth-child(3) > strong',
+ totalImport: 'vn-ticket-sale vn-one.taxes > p:nth-child(3) > strong',
selectAllSalesCheckbox: 'vn-ticket-sale vn-thead vn-check',
secondSaleCheckbox: 'vn-ticket-sale vn-tr:nth-child(2) vn-check[ng-model="sale.checked"]',
thirdSaleCheckbox: 'vn-ticket-sale vn-tr:nth-child(3) vn-check[ng-model="sale.checked"]',
deleteSaleButton: 'vn-ticket-sale vn-tool-bar > vn-button[icon="delete"]',
transferSaleButton: 'vn-ticket-sale vn-tool-bar > vn-button[icon="call_split"]',
- moveToTicketInput: '.vn-popover.shown vn-textfield[ng-model="$ctrl.transfer.ticketId"]',
+ moveToTicketInput: 'form vn-input-number[ng-model="$ctrl.transfer.ticketId"] input',
moveToTicketButton: '.vn-popover.shown vn-icon[icon="arrow_forward_ios"]',
moveToNewTicketButton: '.vn-popover.shown vn-button[label="New ticket"]',
acceptDeleteLineButton: '.vn-confirm.shown button[response=accept]',
acceptDeleteTicketButton: '.vn-confirm.shown button[response=accept]',
- stateMenuButton: 'vn-ticket-sale vn-tool-bar > vn-button-menu[label="State"]'
+ stateMenuButton: 'vn-ticket-sale vn-tool-bar > vn-button-menu[label="State"]',
+ stateMenuFixOption: ''
},
ticketTracking: {
trackingButton: 'vn-left-menu a[ui-sref="ticket.card.tracking.index"]',
diff --git a/e2e/paths/05-ticket/01-sale/01_list_sales.spec.js b/e2e/paths/05-ticket/01-sale/01_list_sales.spec.js
index f97447c06..f883d08dc 100644
--- a/e2e/paths/05-ticket/01-sale/01_list_sales.spec.js
+++ b/e2e/paths/05-ticket/01-sale/01_list_sales.spec.js
@@ -72,7 +72,8 @@ describe('Ticket List sale path', () => {
}, {}, selectors.ticketSales.secondSaleIdAutocomplete, searchValue);
await page.keyboard.press('Enter');
- await page.write(selectors.ticketSales.secondSaleQuantity, '1');
+ await page.waitToClick(selectors.ticketSales.secondSaleQuantityCell);
+ await page.type(selectors.ticketSales.secondSaleQuantity, '1');
await page.keyboard.press('Enter');
const message = await page.waitForSnackbar();
diff --git a/e2e/paths/05-ticket/01-sale/02_edit_sale.spec.js b/e2e/paths/05-ticket/01-sale/02_edit_sale.spec.js
index a22b0e022..a7b24e4a3 100644
--- a/e2e/paths/05-ticket/01-sale/02_edit_sale.spec.js
+++ b/e2e/paths/05-ticket/01-sale/02_edit_sale.spec.js
@@ -1,8 +1,7 @@
import selectors from '../../../helpers/selectors.js';
import getBrowser from '../../../helpers/puppeteer';
-// #1632 [e2e] ticket.sale - Transferir líneas
-xdescribe('Ticket Edit sale path', () => {
+describe('Ticket Edit sale path', () => {
let browser;
let page;
@@ -10,7 +9,7 @@ xdescribe('Ticket Edit sale path', () => {
browser = await getBrowser();
page = browser.page;
await page.loginAndModule('salesPerson', 'ticket');
- await page.accessToSearchResult(16);
+ await page.accessToSearchResult('16');
await page.accessToSection('ticket.card.sale');
});
@@ -20,29 +19,50 @@ xdescribe('Ticket Edit sale path', () => {
it(`should click on the first sale claim icon to navigate over there`, async() => {
await page.waitToClick(selectors.ticketSales.firstSaleClaimIcon);
- await page.wait(selectors.claimBasicData.claimState);
- const url = await page.parsedUrl();
-
- expect(url.hash).toEqual('#!/claim/2/basic-data');
+ await page.waitForState('claim.card.basicData');
});
it('should navigate to the tickets index', async() => {
await page.waitToClick(selectors.globalItems.applicationsMenuButton);
await page.wait(selectors.globalItems.applicationsMenuVisible);
await page.waitToClick(selectors.globalItems.ticketsButton);
- await page.wait(selectors.ticketsIndex.topbarSearch);
- const url = await page.parsedUrl();
-
- expect(url.hash).toEqual('#!/ticket/index');
+ await page.waitForState('ticket.index');
});
it(`should search for a ticket and then navigate to it's sales`, async() => {
- await page.accessToSearchResult(16);
+ await page.accessToSearchResult('16');
await page.accessToSection('ticket.card.sale');
- await page.waitForURL('/sale');
- const url = await page.parsedUrl();
+ });
- expect(url.hash).toContain('/sale');
+ it(`should set the ticket as libre`, async() => {
+ await page.waitToClick(selectors.ticketSales.stateMenuButton);
+ await page.write('body > div > div > div.content > div.filter.ng-scope > vn-textfield', 'libre');
+ await page.waitFor(500);
+ await page.keyboard.press('Enter');
+ const message = await page.waitForSnackbar();
+
+ expect(message.type).toBe('success');
+ });
+
+ it(`should check it's state is libre now`, async() => {
+ await page.waitForTextInElement(selectors.ticketDescriptor.stateLabelValue, 'Libre');
+ const result = await page.waitToGetProperty(selectors.ticketDescriptor.stateLabelValue, 'innerText');
+
+ expect(result).toEqual('State Libre');
+ });
+
+ it(`should set the ticket as OK`, async() => {
+ await page.waitToClick(selectors.ticketSales.setOk);
+ const message = await page.waitForSnackbar();
+
+ expect(message.type).toBe('success');
+ });
+
+ it(`should check it's state is OK now`, async() => {
+ await page.waitForTextInElement(selectors.ticketDescriptor.stateLabelValue, 'OK');
+ const result = await page.waitToGetProperty(selectors.ticketDescriptor.stateLabelValue, 'innerText');
+
+ expect(result).toEqual('State OK');
});
it(`should check the zoomed image isn't present`, async() => {
@@ -52,26 +72,20 @@ xdescribe('Ticket Edit sale path', () => {
});
it(`should click on the thumbnail image of the 1st sale and see the zoomed image`, async() => {
- await page.clickIfVisible(selectors.ticketSales.firstSaleThumbnailImage);
+ await page.waitToClick(selectors.ticketSales.firstSaleThumbnailImage);
const result = await page.countElement(selectors.ticketSales.firstSaleZoomedImage);
expect(result).toEqual(1);
});
it(`should click on the zoomed image to close it`, async() => {
- await page.clickIfVisible(selectors.ticketSales.firstSaleZoomedImage);
+ await page.waitToClick(selectors.ticketSales.firstSaleZoomedImage);
const result = await page.countElement(selectors.ticketSales.firstSaleZoomedImage);
expect(result).toEqual(0);
});
- it(`should confirm the item descriptor insnt visible yet`, async() => {
- const visible = await page.isVisible(selectors.ticketSales.saleDescriptorPopover);
-
- expect(visible).toBeFalsy();
- });
-
- it(`should click on the first sale ID making the item descriptor visible`, async() => {
+ it(`should click on the first sale ID making now the item descriptor visible`, async() => {
await page.waitToClick(selectors.ticketSales.firstSaleId);
await page.waitImgLoad(selectors.ticketSales.firstSaleDescriptorImage);
const visible = await page.isVisible(selectors.ticketSales.saleDescriptorPopover);
@@ -80,14 +94,14 @@ xdescribe('Ticket Edit sale path', () => {
});
it(`should click on the descriptor image of the 1st sale and see the zoomed image`, async() => {
- await page.clickIfVisible('vn-item-descriptor img');
+ await page.waitToClick('vn-item-descriptor img');
const result = await page.countElement(selectors.ticketSales.firstSaleZoomedImage);
expect(result).toEqual(1);
});
it(`should now click on the zoomed image to close it`, async() => {
- await page.clickIfVisible(selectors.ticketSales.firstSaleZoomedImage);
+ await page.waitToClick(selectors.ticketSales.firstSaleZoomedImage);
const result = await page.countElement(selectors.ticketSales.firstSaleZoomedImage);
expect(result).toEqual(0);
@@ -95,50 +109,46 @@ xdescribe('Ticket Edit sale path', () => {
it(`should click on the summary icon of the item-descriptor to access to the item summary`, async() => {
await page.waitToClick(selectors.ticketSales.saleDescriptorPopoverSummaryButton);
- await page.waitForURL('/summary');
- const url = await page.parsedUrl();
-
- expect(url.hash).toContain('/summary');
+ await page.waitForState('item.card.summary');
});
it('should return to ticket sales section', async() => {
await page.waitToClick(selectors.globalItems.applicationsMenuButton);
await page.wait(selectors.globalItems.applicationsMenuVisible);
await page.waitToClick(selectors.globalItems.ticketsButton);
- await page.accessToSearchResult(16);
+ await page.accessToSearchResult('16');
await page.accessToSection('ticket.card.sale');
- await page.waitForURL('/sale');
- const url = await page.parsedUrl();
-
- expect(url.hash).toContain('/sale');
});
it('should try to add a higher quantity value and then receive an error', async() => {
- await page.focusElement(selectors.ticketSales.firstSaleQuantityCell);
- await page.write(selectors.ticketSales.firstSaleQuantity, '11\u000d');
+ await page.waitToClick(selectors.ticketSales.firstSaleQuantityCell);
+ await page.type(selectors.ticketSales.firstSaleQuantity, '11\u000d');
const message = await page.waitForSnackbar();
expect(message.text).toBe('The new quantity should be smaller than the old one');
});
it('should remove 1 from the first sale quantity', async() => {
- await page.focusElement(selectors.ticketSales.firstSaleQuantityCell);
- await page.write(selectors.ticketSales.firstSaleQuantity, '9\u000d');
+ await page.waitFor(500);
+ await page.waitToClick(selectors.ticketSales.firstSaleQuantityCell);
+ await page.waitFor(selectors.ticketSales.firstSaleQuantity);
+ await page.type(selectors.ticketSales.firstSaleQuantity, '9\u000d');
const message = await page.waitForSnackbar();
expect(message.type).toBe('success');
});
it('should update the price', async() => {
- await page.waitToClick(`${selectors.ticketSales.firstSalePrice} > span`);
- await page.write(selectors.ticketSales.firstSalePriceInput, '5\u000d');
+ await page.waitToClick(selectors.ticketSales.firstSalePrice);
+ await page.waitFor(selectors.ticketSales.firstSalePriceInput);
+ await page.type(selectors.ticketSales.firstSalePriceInput, '5\u000d');
const message = await page.waitForSnackbar();
expect(message.type).toBe('success');
});
it('should confirm the price have been updated', async() => {
- const result = await page.waitToGetProperty(`${selectors.ticketSales.firstSalePrice} span`, 'innerText');
+ const result = await page.waitToGetProperty(selectors.ticketSales.firstSalePrice, 'innerText');
expect(result).toContain('5.00');
});
@@ -150,16 +160,17 @@ xdescribe('Ticket Edit sale path', () => {
});
it('should update the discount', async() => {
- await page.waitToClick(`${selectors.ticketSales.firstSaleDiscount} > span`);
- await page.write(selectors.ticketSales.firstSaleDiscountInput, '50\u000d');
+ await page.waitToClick(selectors.ticketSales.firstSaleDiscount);
+ await page.waitFor(selectors.ticketSales.firstSaleDiscountInput);
+ await page.type(selectors.ticketSales.firstSaleDiscountInput, '50\u000d');
const message = await page.waitForSnackbar();
expect(message.type).toBe('success');
});
it('should confirm the discount have been updated', async() => {
- await page.waitForTextInElement(`${selectors.ticketSales.firstSaleDiscount} > span`, '50.00%');
- const result = await page.waitToGetProperty(`${selectors.ticketSales.firstSaleDiscount} > span`, 'innerText');
+ await page.waitForTextInElement(selectors.ticketSales.firstSaleDiscount, '50.00%');
+ const result = await page.waitToGetProperty(selectors.ticketSales.firstSaleDiscount, 'innerText');
expect(result).toContain('50.00%');
});
@@ -175,48 +186,31 @@ xdescribe('Ticket Edit sale path', () => {
await page.waitToClick(selectors.ticketSales.thirdSaleCheckbox);
await page.waitToClick(selectors.ticketSales.moreMenu);
await page.waitToClick(selectors.ticketSales.moreMenuCreateClaim);
- await page.wait(selectors.claimBasicData.claimState);
- const url = await page.parsedUrl();
-
- expect(url.hash).toContain('basic-data');
+ await page.waitForState('claim.card.basicData');
});
it('should click on the Claims button of the top bar menu', async() => {
await page.waitToClick(selectors.globalItems.applicationsMenuButton);
await page.wait(selectors.globalItems.applicationsMenuVisible);
await page.waitToClick(selectors.globalItems.claimsButton);
- await page.wait(selectors.claimsIndex.searchClaimInput);
- const url = await page.parsedUrl();
-
- expect(url.hash).toEqual('#!/claim/index');
+ await page.waitForState('claim.index');
});
it('should search for the claim with id 4', async() => {
- await page.write(selectors.claimsIndex.searchClaimInput, 4);
- await page.waitToClick(selectors.claimsIndex.searchButton);
- await page.waitForNumberOfElements(selectors.claimsIndex.searchResult, 1);
- const result = await page.countElement(selectors.claimsIndex.searchResult);
-
- expect(result).toEqual(1);
+ await page.accessToSearchResult('4');
+ await page.waitForState('claim.card.summary');
});
it('should click the Tickets button of the top bar menu', async() => {
await page.waitToClick(selectors.globalItems.applicationsMenuButton);
await page.wait(selectors.globalItems.applicationsMenuVisible);
await page.waitToClick(selectors.globalItems.ticketsButton);
- await page.wait(selectors.ticketsIndex.topbarSearch);
- const url = await page.parsedUrl();
-
- expect(url.hash).toEqual('#!/ticket/index');
+ await page.waitForState('ticket.index');
});
it('should search for a ticket then access to the sales section', async() => {
- await page.accessToSearchResult(16);
+ await page.accessToSearchResult('16');
await page.accessToSection('ticket.card.sale');
- await page.waitForURL('/sale');
- const url = await page.parsedUrl();
-
- expect(url.hash).toContain('/sale');
});
it('should select the third sale and delete it', async() => {
@@ -236,18 +230,15 @@ xdescribe('Ticket Edit sale path', () => {
});
it('should select the second sale and transfer it to a valid ticket', async() => {
- const targetTicketId = 12;
+ const targetTicketId = '12';
await page.waitToClick(selectors.ticketSales.secondSaleCheckbox);
await page.waitToClick(selectors.ticketSales.transferSaleButton);
- await page.focusElement(selectors.ticketSales.transferQuantityCell);
- await page.write(selectors.ticketSales.transferQuantityInput, '10\u000d');
- await page.write(selectors.ticketSales.moveToTicketInput, targetTicketId);
+ await page.waitToClick(selectors.ticketSales.transferQuantityCell);
+ await page.type(selectors.ticketSales.transferQuantityInput, '10\u000d');
+ await page.type(selectors.ticketSales.moveToTicketInput, targetTicketId);
await page.waitToClick(selectors.ticketSales.moveToTicketButton);
- await page.waitForURL(`ticket/${targetTicketId}/sale`);
- const result = await page.parsedUrl();
-
- expect(result.hash).toContain(`ticket/${targetTicketId}/sale`);
+ await page.expectURL(`ticket/${targetTicketId}/sale`);
});
it('should confirm the transfered line is the correct one', async() => {
@@ -265,12 +256,8 @@ xdescribe('Ticket Edit sale path', () => {
it('should go back to the original ticket sales section', async() => {
await page.waitToClick(selectors.ticketDescriptor.goBackToModuleIndexButton);
- await page.accessToSearchResult(16);
+ await page.accessToSearchResult('16');
await page.accessToSection('ticket.card.sale');
- await page.waitForURL('/sale');
- const url = await page.parsedUrl();
-
- expect(url.hash).toContain('/sale');
});
it(`should confirm the original ticket has still three lines`, async() => {
@@ -288,25 +275,18 @@ xdescribe('Ticket Edit sale path', () => {
it('should go back to the receiver ticket sales section', async() => {
await page.waitToClick(selectors.ticketDescriptor.goBackToModuleIndexButton);
- await page.accessToSearchResult(12);
+ await page.accessToSearchResult('12');
await page.accessToSection('ticket.card.sale');
- await page.waitForURL('/sale');
- const url = await page.parsedUrl();
-
- expect(url.hash).toContain('/sale');
});
it('should transfer the sale back to the original ticket', async() => {
- const targetTicketId = 16;
+ const targetTicketId = '16';
await page.waitToClick(selectors.ticketSales.secondSaleCheckbox);
await page.waitToClick(selectors.ticketSales.transferSaleButton);
- await page.write(selectors.ticketSales.moveToTicketInput, targetTicketId);
+ await page.type(selectors.ticketSales.moveToTicketInput, targetTicketId);
await page.waitToClick(selectors.ticketSales.moveToTicketButton);
- await page.waitForURL(`ticket/${targetTicketId}/sale`);
- const result = await page.parsedUrl();
-
- expect(result.hash).toContain(`ticket/${targetTicketId}/sale`);
+ await page.expectURL(`ticket/${targetTicketId}/sale`);
});
it('should confirm the original ticket received the line', async() => {
@@ -321,35 +301,29 @@ xdescribe('Ticket Edit sale path', () => {
await page.waitToClick(selectors.ticketSales.firstSaleCheckbox);
await page.waitToClick(selectors.ticketSales.transferSaleButton);
await page.waitToClick(selectors.ticketSales.moveToNewTicketButton);
- await page.waitToClick(selectors.ticketSales.acceptDeleteTicketButton);
const message = await page.waitForSnackbar();
expect(message.text).toBe(`You can't create a ticket for a inactive client`);
+
+ await page.closePopup();
});
it('should go now to the ticket sales section of an active, not frozen client', async() => {
await page.waitToClick(selectors.ticketDescriptor.goBackToModuleIndexButton);
- await page.accessToSearchResult(13);
+ await page.accessToSearchResult('13');
await page.accessToSection('ticket.card.sale');
- await page.waitForURL('/sale');
- const url = await page.parsedUrl();
-
- expect(url.hash).toContain('/sale');
});
it(`should select all sales, tranfer them to a new ticket and delete the sender ticket as it would've been left empty`, async() => {
- const senderTicketId = 13;
+ const senderTicketId = '13';
await page.waitToClick(selectors.ticketSales.selectAllSalesCheckbox);
await page.waitToClick(selectors.ticketSales.transferSaleButton);
await page.waitToClick(selectors.ticketSales.moveToNewTicketButton);
- await page.waitToClick(selectors.ticketSales.acceptDeleteTicketButton);
- await page.wait((selector, ticketId) => {
- return document.querySelector(selector).innerText.toLowerCase().indexOf(`${ticketId}`) == -1;
- }, selectors.ticketDescriptor.idLabelValue, senderTicketId);
- const url = await page.parsedUrl();
-
- expect(url.hash).toContain('/sale');
+ await page.evaluate((selector, ticketId) => {
+ return document.querySelector(selector).innerText.toLowerCase().indexOf(`#${ticketId}`) == -1;
+ }, selectors.ticketDescriptor.id, senderTicketId);
+ await page.waitForState('ticket.card.sale');
});
it('should confirm the new ticket received the line', async() => {
@@ -368,6 +342,7 @@ xdescribe('Ticket Edit sale path', () => {
await page.waitToClick(selectors.ticketSales.firstSaleCheckbox);
await page.waitToClick(selectors.ticketSales.moreMenu);
await page.waitToClick(selectors.ticketSales.moreMenuReserve);
+ await page.closePopup();
await page.waitForClassNotPresent(selectors.ticketSales.firstSaleReservedIcon, 'ng-hide');
const result = await page.isVisible(selectors.ticketSales.firstSaleReservedIcon);
@@ -384,10 +359,12 @@ xdescribe('Ticket Edit sale path', () => {
});
it('should update all sales discount', async() => {
+ await page.closePopup();
await page.waitToClick(selectors.ticketSales.moreMenu);
await page.waitToClick(selectors.ticketSales.moreMenuUpdateDiscount);
- // .write(selectors.ticketSales.moreMenuUpdateDiscountInput, 100) can't find the selector on app (deleted the selector), menu option was removed?
- await page.write('body', '\u000d');
+ await page.waitForSelector(selectors.ticketSales.moreMenuUpdateDiscountInput);
+ await page.type(selectors.ticketSales.moreMenuUpdateDiscountInput, '100');
+ await page.keyboard.press('Enter');
await page.waitForTextInElement(selectors.ticketSales.totalImport, '0.00');
const result = await page.waitToGetProperty(selectors.ticketSales.totalImport, 'innerText');
@@ -396,75 +373,12 @@ xdescribe('Ticket Edit sale path', () => {
it('should log in as Production role and go to a target ticket summary', async() => {
await page.loginAndModule('production', 'ticket');
- await page.accessToSearchResult(13);
- await page.waitForURL('/summary');
- const url = await page.parsedUrl();
-
- expect(url.hash).toContain('/summary');
+ await page.accessToSearchResult('13');
+ await page.waitForState('ticket.card.summary');
});
- it(`should check it's state is deleted`, async() => {
- const result = await page.waitToGetProperty(selectors.ticketDescriptor.stateLabelValue, 'innerText');
-
- expect(result).toEqual('State Eliminado');
- });
-
- describe('when state is preparation and loged as Production', () => {
- it(`should not be able to edit the sale price`, async() => {
- await page.waitToClick(selectors.ticketDescriptor.goBackToModuleIndexButton);
- await page.accessToSearchResult(8);
- await page.accessToSection('ticket.card.sale');
- await page.waitToClick(selectors.ticketSales.firstSalePrice);
- const result = await page.exists(selectors.ticketSales.firstSalePriceInput);
-
- expect(result).toBeFalsy();
- });
-
- it(`should not be able to edit the sale discount`, async() => {
- await page.waitToClick(selectors.ticketSales.firstSaleDiscount);
- const result = await page.exists(selectors.ticketSales.firstSaleDiscountInput);
-
- expect(result).toBeFalsy();
- });
-
- it(`should not be able to edit the sale state`, async() => {
- await page.waitToClick(selectors.ticketSales.stateMenuButton);
- const result = await page.exists(selectors.ticketSales.stateMenuOptions);
-
- expect(result).toBeFalsy();
- });
-
- it('should log in as salesPerson then go to the sales of a target ticket', async() => {
- await page.loginAndModule('salesPerson', 'ticket');
- await page.accessToSearchResult(8);
- await page.accessToSection('ticket.card.sale');
- await page.waitForURL('/sale');
- const url = await page.parsedUrl();
-
- expect(url.hash).toContain('/sale');
- });
- });
-
- describe('when state is preparation and loged as salesPerson', () => {
- it(`shouldn't be able to edit the sale price`, async() => {
- await page.waitToClick(selectors.ticketSales.firstSalePrice);
- const result = await page.exists(selectors.ticketSales.firstSalePriceInput);
-
- expect(result).toBeFalsy();
- });
-
- it(`should be able to edit the sale discount`, async() => {
- await page.waitToClick(selectors.ticketSales.firstSaleDiscount);
- const result = await page.exists(selectors.ticketSales.firstSaleDiscountInput);
-
- expect(result).toBeFalsy();
- });
-
- it(`should not be able to edit the sale state`, async() => {
- await page.waitToClick(selectors.ticketSales.stateMenuButton);
- const result = await page.exists(selectors.ticketSales.stateMenuOptions);
-
- expect(result).toBeFalsy();
- });
+ it(`should check the ticket is deleted`, async() => {
+ await page.waitForSelector(selectors.ticketDescriptor.isDeletedIcon);
+ await page.waitForClassPresent(selectors.ticketDescriptor.isDeletedIcon, 'bright');
});
});
diff --git a/e2e/paths/05-ticket/05_tracking_state.spec.js b/e2e/paths/05-ticket/05_tracking_state.spec.js
index 34f3c4d44..53f082007 100644
--- a/e2e/paths/05-ticket/05_tracking_state.spec.js
+++ b/e2e/paths/05-ticket/05_tracking_state.spec.js
@@ -48,6 +48,7 @@ describe('Ticket Create new tracking state path', () => {
});
it('should now access to the create state view by clicking the create floating button', async() => {
+ await page.waitFor('.vn-popup', {hidden: true}),
await page.waitToClick(selectors.ticketTracking.createStateButton);
await page.waitForState('ticket.card.tracking.edit');
});
diff --git a/e2e/paths/05-ticket/10_request.spec.js b/e2e/paths/05-ticket/10_request.spec.js
index 334b8ba5e..afab9b9e9 100644
--- a/e2e/paths/05-ticket/10_request.spec.js
+++ b/e2e/paths/05-ticket/10_request.spec.js
@@ -18,6 +18,7 @@ describe('Ticket purchase request path', () => {
});
it('should add a new request', async() => {
+ await page.waitFor('.vn-popup', {hidden: true}),
await page.waitToClick(selectors.ticketRequests.addRequestButton);
await page.write(selectors.ticketRequests.descriptionInput, 'New stuff');
await page.write(selectors.ticketRequests.quantity, '9');
diff --git a/e2e/paths/05-ticket/16_summary.spec.js b/e2e/paths/05-ticket/16_summary.spec.js
index f6808651e..70d7592d7 100644
--- a/e2e/paths/05-ticket/16_summary.spec.js
+++ b/e2e/paths/05-ticket/16_summary.spec.js
@@ -58,7 +58,7 @@ describe('Ticket Summary path', () => {
expect(result).toContain('000002');
});
- it(`should click on the first sale ID making the item descriptor visible`, async() => {
+ it(`should click on the first sale ID to make the item descriptor visible`, async() => {
await page.waitToClick(selectors.ticketSummary.firstSaleItemId);
await page.waitImgLoad(selectors.ticketSummary.firstSaleDescriptorImage);
const visible = await page.isVisible(selectors.ticketSummary.itemDescriptorPopover);
diff --git a/e2e/paths/07-order/03_lines.spec.js b/e2e/paths/07-order/03_lines.spec.js
index c054bbaa3..e74eaae23 100644
--- a/e2e/paths/07-order/03_lines.spec.js
+++ b/e2e/paths/07-order/03_lines.spec.js
@@ -8,7 +8,7 @@ describe('Order lines', () => {
browser = await getBrowser();
page = browser.page;
await page.loginAndModule('employee', 'order');
- await page.accessToSearchResult('16');
+ await page.accessToSearchResult('8');
await page.accessToSection('order.card.line');
});
@@ -20,7 +20,7 @@ describe('Order lines', () => {
const result = await page
.waitToGetProperty(selectors.orderLine.orderSubtotal, 'innerText');
- expect(result).toContain('135.60');
+ expect(result).toContain('112.30');
});
it('should delete the first line in the order', async() => {
@@ -32,11 +32,11 @@ describe('Order lines', () => {
});
it('should confirm the order subtotal has changed', async() => {
- await page.waitForTextInElement(selectors.orderLine.orderSubtotal, '90.10');
+ await page.waitForTextInElement(selectors.orderLine.orderSubtotal, '92.80');
const result = await page
.waitToGetProperty(selectors.orderLine.orderSubtotal, 'innerText');
- expect(result).toContain('90.10');
+ expect(result).toContain('92.80');
});
it('should confirm the whole order and redirect to ticket index filtered by clientFk', async() => {
diff --git a/front/core/components/multi-check/multi-check.js b/front/core/components/multi-check/multi-check.js
index d354c9eef..5c11e955e 100644
--- a/front/core/components/multi-check/multi-check.js
+++ b/front/core/components/multi-check/multi-check.js
@@ -68,6 +68,7 @@ export default class MultiCheck extends FormInput {
this.checkAll = value;
this.toggle();
+ this.emit('change', value);
}
/**
diff --git a/gulpfile.js b/gulpfile.js
index b946b48de..096c44584 100644
--- a/gulpfile.js
+++ b/gulpfile.js
@@ -83,8 +83,6 @@ async function backTestOnce(done) {
port: container.dbConf.port
});
- log('[Debug] dataSources', dataSources.vn);
-
let bootOptions = {dataSources};
let app = require(`./loopback/server/server`);
@@ -92,8 +90,6 @@ async function backTestOnce(done) {
try {
app.boot(bootOptions);
- log('[Debug] back started');
-
await new Promise((resolve, reject) => {
const jasmine = require('gulp-jasmine');
diff --git a/modules/claim/back/methods/claim/createFromSales.js b/modules/claim/back/methods/claim/createFromSales.js
index bf62a526e..989b87c95 100644
--- a/modules/claim/back/methods/claim/createFromSales.js
+++ b/modules/claim/back/methods/claim/createFromSales.js
@@ -4,17 +4,15 @@ module.exports = Self => {
Self.remoteMethodCtx('createFromSales', {
description: 'Create a claim',
accepts: [{
- arg: 'claim',
- type: 'object',
+ arg: 'ticketId',
+ type: 'Number',
required: true,
- description: ' newTicketFk, clientFk, ticketCreated',
- http: {source: 'body'}
+ description: 'The origin ticket id'
}, {
arg: 'sales',
- type: 'object',
+ type: ['Object'],
required: true,
- description: '[sales IDs]',
- http: {source: 'body'}
+ description: 'The claimed sales'
}],
returns: {
type: 'object',
@@ -26,28 +24,27 @@ module.exports = Self => {
}
});
- Self.createFromSales = async(ctx, params) => {
- let models = Self.app.models;
- let userId = ctx.req.accessToken.userId;
- let tx = await Self.beginTransaction({});
+ Self.createFromSales = async(ctx, ticketId, sales) => {
+ const models = Self.app.models;
+ const userId = ctx.req.accessToken.userId;
+ const tx = await Self.beginTransaction({});
try {
let options = {transaction: tx};
- const ticketId = params.claim.ticketFk;
const ticket = await models.Ticket.findById(ticketId, null, options);
if (ticket.isDeleted)
throw new UserError(`You can't create a claim for a removed ticket`);
- const worker = await models.Worker.findOne({
- where: {userFk: userId}
+ const newClaim = await Self.create({
+ ticketFk: ticketId,
+ clientFk: ticket.clientFk,
+ ticketCreated: ticket.shipped,
+ workerFk: userId
}, options);
+ const promises = [];
- params.claim.workerFk = worker.id;
- let newClaim = await Self.create(params.claim, options);
- let promises = [];
-
- for (const sale of params.sales) {
+ for (const sale of sales) {
const newClaimBeginning = models.ClaimBeginning.create({
saleFk: sale.id,
claimFk: newClaim.id,
diff --git a/modules/claim/back/methods/claim/specs/createFromSales.spec.js b/modules/claim/back/methods/claim/specs/createFromSales.spec.js
index 226aeba53..5353e640a 100644
--- a/modules/claim/back/methods/claim/specs/createFromSales.spec.js
+++ b/modules/claim/back/methods/claim/specs/createFromSales.spec.js
@@ -1,7 +1,6 @@
const app = require('vn-loopback/server/server');
-describe('Claim Create', () => {
- let newDate = new Date();
+describe('Claim createFromSales()', () => {
let createdClaimFk;
afterAll(async done => {
@@ -10,28 +9,18 @@ describe('Claim Create', () => {
done();
});
- let newClaim = {
- ticketFk: 2,
- clientFk: 101,
- ticketCreated: newDate
- };
-
- let newSale = [{
+ const ticketId = 2;
+ const newSale = [{
id: 3,
instance: 0,
quantity: 10
}];
-
- let params = {claim: newClaim, sales: newSale};
- let ctx = {req: {accessToken: {userId: 1}}};
+ const ctx = {req: {accessToken: {userId: 1}}};
it('should create a new claim', async() => {
- let claim = await app.models.Claim.createFromSales(ctx, params);
+ let claim = await app.models.Claim.createFromSales(ctx, ticketId, newSale);
- expect(claim.ticketFk).toEqual(newClaim.ticketFk);
- expect(claim.clientFk).toEqual(newClaim.clientFk);
- expect(claim.ticketCreated).toEqual(newClaim.ticketCreated);
- expect(claim.workerFk).toEqual(newClaim.workerFk);
+ expect(claim.ticketFk).toEqual(ticketId);
let claimBeginning = await app.models.ClaimBeginning.findOne({where: {claimFk: claim.id}});
@@ -44,7 +33,7 @@ describe('Claim Create', () => {
it('should not be able to create a claim if exists that sale', async() => {
let error;
- await app.models.Claim.createFromSales(ctx, params)
+ await app.models.Claim.createFromSales(ctx, ticketId, newSale)
.catch(e => {
error = e;
diff --git a/modules/client/back/methods/client/canCreateTicket.js b/modules/client/back/methods/client/canCreateTicket.js
new file mode 100644
index 000000000..a47a5f6f3
--- /dev/null
+++ b/modules/client/back/methods/client/canCreateTicket.js
@@ -0,0 +1,31 @@
+module.exports = Self => {
+ Self.remoteMethod('canCreateTicket', {
+ description: 'Checks if the client is active',
+ accessType: 'READ',
+ accepts: [
+ {
+ arg: 'id',
+ type: 'string',
+ required: true,
+ description: 'The user id',
+ http: {source: 'path'}
+ }],
+ returns: {
+ type: 'boolean',
+ root: true
+ },
+ http: {
+ path: `/:id/canCreateTicket`,
+ verb: 'GET'
+ }
+ });
+
+ Self.canCreateTicket = async id => {
+ const client = await Self.app.models.Client.findById(id);
+ const canCreateTicket = client && client.isActive;
+ if (!canCreateTicket)
+ return false;
+
+ return true;
+ };
+};
diff --git a/modules/client/back/methods/client/isValidClient.js b/modules/client/back/methods/client/isValidClient.js
index 241121927..11f183563 100644
--- a/modules/client/back/methods/client/isValidClient.js
+++ b/modules/client/back/methods/client/isValidClient.js
@@ -44,7 +44,7 @@ module.exports = Self => {
return role.name === 'employee';
});
- if (!roleNames.length || isEmployee > -1 ) return false;
+ if (!roleNames.length || isEmployee > -1) return false;
return true;
};
diff --git a/modules/client/back/methods/client/specs/canCreateTicket.spec.js b/modules/client/back/methods/client/specs/canCreateTicket.spec.js
new file mode 100644
index 000000000..9eb1db334
--- /dev/null
+++ b/modules/client/back/methods/client/specs/canCreateTicket.spec.js
@@ -0,0 +1,17 @@
+const app = require('vn-loopback/server/server');
+
+describe('Client canCreateTicket', () => {
+ it('should receive true if the client is active', async() => {
+ let id = 105;
+ let canCreateTicket = await app.models.Client.canCreateTicket(id);
+
+ expect(canCreateTicket).toBeTruthy();
+ });
+
+ it(`should receive false if the client isn't active`, async() => {
+ let id = 106;
+ let canCreateTicket = await app.models.Client.canCreateTicket(id);
+
+ expect(canCreateTicket).toBe(false);
+ });
+});
diff --git a/modules/client/back/models/client.js b/modules/client/back/models/client.js
index 056b49d01..66ab1fdc7 100644
--- a/modules/client/back/models/client.js
+++ b/modules/client/back/models/client.js
@@ -11,6 +11,7 @@ module.exports = Self => {
require('../methods/client/createWithUser')(Self);
require('../methods/client/listWorkers')(Self);
require('../methods/client/hasCustomerRole')(Self);
+ require('../methods/client/canCreateTicket')(Self);
require('../methods/client/isValidClient')(Self);
require('../methods/client/addressesPropagateRe')(Self);
require('../methods/client/getDebt')(Self);
diff --git a/modules/route/back/methods/route/getTickets.js b/modules/route/back/methods/route/getTickets.js
index a0014a60d..211a2e7bb 100644
--- a/modules/route/back/methods/route/getTickets.js
+++ b/modules/route/back/methods/route/getTickets.js
@@ -29,7 +29,7 @@ module.exports = Self => {
order: 'priority',
include: [
{
- relation: 'state',
+ relation: 'ticketState',
scope: {
fields: ['id', 'stateFk'],
include: [{relation: 'state'}]
diff --git a/modules/ticket/back/methods/sale/deleteSales.js b/modules/ticket/back/methods/sale/deleteSales.js
new file mode 100644
index 000000000..d11223d3b
--- /dev/null
+++ b/modules/ticket/back/methods/sale/deleteSales.js
@@ -0,0 +1,43 @@
+let UserError = require('vn-loopback/util/user-error');
+
+module.exports = Self => {
+ Self.remoteMethodCtx('deleteSales', {
+ description: 'Deletes the selected sales',
+ accessType: 'WRITE',
+ accepts: [{
+ arg: 'sales',
+ type: ['Object'],
+ required: true,
+ description: 'The sales to remove'
+ },
+ {
+ arg: 'ticketId',
+ type: 'Number',
+ required: true,
+ description: 'The ticket id'
+ }],
+ returns: {
+ type: ['Object'],
+ root: true
+ },
+ http: {
+ path: `/deleteSales`,
+ verb: 'POST'
+ }
+ });
+
+ Self.deleteSales = async(ctx, sales, ticketId) => {
+ const models = Self.app.models;
+ const isTicketEditable = await models.Ticket.isEditable(ctx, ticketId);
+ if (!isTicketEditable)
+ throw new UserError(`The sales of this ticket can't be modified`);
+
+ const promises = [];
+ for (let sale of sales) {
+ const deletedSale = models.Sale.destroyById(sale.id);
+ promises.push(deletedSale);
+ }
+
+ return Promise.all(promises);
+ };
+};
diff --git a/modules/ticket/back/methods/sale/removes.js b/modules/ticket/back/methods/sale/removes.js
deleted file mode 100644
index f4385072f..000000000
--- a/modules/ticket/back/methods/sale/removes.js
+++ /dev/null
@@ -1,35 +0,0 @@
-let UserError = require('vn-loopback/util/user-error');
-
-module.exports = Self => {
- Self.remoteMethodCtx('removes', {
- description: 'Change the state of a ticket',
- accessType: 'WRITE',
- accepts: [{
- arg: 'params',
- type: 'object',
- required: true,
- description: '[sales IDs], actualTicketFk',
- http: {source: 'body'}
- }],
- returns: {
- type: 'string',
- root: true
- },
- http: {
- path: `/removes`,
- verb: 'post'
- }
- });
-
- Self.removes = async(ctx, params) => {
- let thisTicketIsEditable = await Self.app.models.Ticket.isEditable(ctx, params.actualTicketFk);
- if (!thisTicketIsEditable)
- throw new UserError(`The sales of this ticket can't be modified`);
-
- let promises = [];
- for (let i = 0; i < params.sales.length; i++)
- promises.push(Self.app.models.Sale.destroyById(params.sales[i].id));
-
- return Promise.all(promises);
- };
-};
diff --git a/modules/ticket/back/methods/sale/reserve.js b/modules/ticket/back/methods/sale/reserve.js
index 7e6a6bb3a..e054e1ec8 100644
--- a/modules/ticket/back/methods/sale/reserve.js
+++ b/modules/ticket/back/methods/sale/reserve.js
@@ -6,28 +6,43 @@ module.exports = Self => {
description: 'Change the state of a ticket',
accessType: 'WRITE',
accepts: [{
- arg: 'params',
- type: 'object',
+ arg: 'ticketId',
+ type: 'Number',
required: true,
- description: '[sales IDs], ticketFk, reserved',
- http: {source: 'body'}
+ description: 'The ticket id'
+ }, {
+ arg: 'sales',
+ type: ['Object'],
+ required: true,
+ description: 'The sale to reserve'
+ },
+ {
+ arg: 'reserved',
+ type: 'Boolean',
+ required: true
}],
returns: {
- type: 'string',
+ type: ['Object'],
root: true
},
http: {
path: `/reserve`,
- verb: 'post'
+ verb: 'POST'
}
});
- Self.reserve = async(ctx, params) => {
- let thisTicketIsEditable = await Self.app.models.Ticket.isEditable(ctx, params.ticketFk);
- if (!thisTicketIsEditable)
+ Self.reserve = async(ctx, ticketId, sales, reserved) => {
+ const models = Self.app.models;
+ const isTicketEditable = await models.Ticket.isEditable(ctx, ticketId);
+ if (!isTicketEditable)
throw new UserError(`The sales of this ticket can't be modified`);
- for (let i = 0; i < params.sales.length; i++)
- await Self.app.models.Sale.update({id: params.sales[i].id}, {reserved: params.reserved});
+ const promises = [];
+ for (let sale of sales) {
+ const reservedSale = models.Sale.update({id: sale.id}, {reserved: reserved});
+ promises.push(reservedSale);
+ }
+
+ return Promise.all(promises);
};
};
diff --git a/modules/ticket/back/methods/sale/specs/removes.spec.js b/modules/ticket/back/methods/sale/specs/deleteSales.js
similarity index 66%
rename from modules/ticket/back/methods/sale/specs/removes.spec.js
rename to modules/ticket/back/methods/sale/specs/deleteSales.js
index a12bc54ee..c23ac6758 100644
--- a/modules/ticket/back/methods/sale/specs/removes.spec.js
+++ b/modules/ticket/back/methods/sale/specs/deleteSales.js
@@ -1,6 +1,6 @@
const app = require('vn-loopback/server/server');
-describe('sale removes()', () => {
+describe('sale deleteSales()', () => {
let sale;
let newsale;
@@ -16,13 +16,11 @@ describe('sale removes()', () => {
let ctx = {req: {accessToken: {userId: 9}}};
let error;
- let params = {
- sales: [{id: 1, instance: 0}, {id: 2, instance: 1}],
- actualTicketFk: 2
- };
+ const sales = [{id: 1, instance: 0}, {id: 2, instance: 1}];
+ const ticketId = 2;
try {
- await app.models.Sale.removes(ctx, params);
+ await app.models.Sale.deleteSales(ctx, sales, ticketId);
} catch (e) {
error = e;
}
@@ -32,12 +30,11 @@ describe('sale removes()', () => {
it('should delete the sales', async() => {
let ctx = {req: {accessToken: {userId: 9}}};
- let params = {
- sales: [{id: newsale.id, instance: 0}],
- actualTicketFk: 16
- };
- let res = await app.models.Sale.removes(ctx, params);
+ const sales = [{id: newsale.id, instance: 0}];
+ const ticketId = 16;
+
+ let res = await app.models.Sale.deleteSales(ctx, sales, ticketId);
expect(res).toEqual([{count: 1}]);
});
diff --git a/modules/ticket/back/methods/sale/specs/reserve.spec.js b/modules/ticket/back/methods/sale/specs/reserve.spec.js
index a86d357a8..5379b1487 100644
--- a/modules/ticket/back/methods/sale/specs/reserve.spec.js
+++ b/modules/ticket/back/methods/sale/specs/reserve.spec.js
@@ -1,6 +1,7 @@
const app = require('vn-loopback/server/server');
describe('sale reserve()', () => {
+ const ctx = {req: {accessToken: {userId: 9}}};
afterAll(async done => {
let ctx = {req: {accessToken: {userId: 9}}};
let params = {
@@ -17,13 +18,12 @@ describe('sale reserve()', () => {
});
it('should throw an error if the ticket can not be modified', async() => {
- let ctx = {req: {accessToken: {userId: 9}}};
let error;
- let params = {ticketFk: 2,
- sales: [{id: 5}],
- reserved: false};
+ const ticketId = 2;
+ const sales = [{id: 5}];
+ const reserved = false;
- await app.models.Sale.reserve(ctx, params)
+ await app.models.Sale.reserve(ctx, ticketId, sales, reserved)
.catch(response => {
expect(response).toEqual(new Error(`The sales of this ticket can't be modified`));
error = response;
@@ -38,18 +38,13 @@ describe('sale reserve()', () => {
expect(originalTicketSales[0].reserved).toEqual(0);
expect(originalTicketSales[1].reserved).toEqual(0);
- let ctx = {req: {accessToken: {userId: 9}}};
- let params = {
- sales: [
- {id: 7},
- {id: 8}],
- ticketFk: 11,
- reserved: true
- };
+ const ticketId = 11;
+ const sales = [{id: 7}, {id: 8}];
+ const reserved = true;
- await app.models.Sale.reserve(ctx, params);
+ await app.models.Sale.reserve(ctx, ticketId, sales, reserved);
- let reservedTicketSales = await app.models.Ticket.getSales(11);
+ const reservedTicketSales = await app.models.Ticket.getSales(ticketId);
expect(reservedTicketSales[0].reserved).toEqual(1);
expect(reservedTicketSales[1].reserved).toEqual(1);
diff --git a/modules/ticket/back/methods/ticket/getPossibleStowaways.js b/modules/ticket/back/methods/ticket/getPossibleStowaways.js
index 3565d64ab..675270840 100644
--- a/modules/ticket/back/methods/ticket/getPossibleStowaways.js
+++ b/modules/ticket/back/methods/ticket/getPossibleStowaways.js
@@ -38,7 +38,6 @@ module.exports = Self => {
let highestDate = new Date(ship.shipped.getTime());
highestDate.setHours(23, 59, 59);
-
let possibleStowaways = await models.Ticket.find({
where: {
id: {neq: ticketFk},
@@ -53,7 +52,7 @@ module.exports = Self => {
include: [
{relation: 'agencyMode'},
{relation: 'warehouse'},
- {relation: 'state',
+ {relation: 'ticketState',
scope: {
fields: ['stateFk'],
include: {
diff --git a/modules/ticket/back/methods/ticket/getSalesPersonMana.js b/modules/ticket/back/methods/ticket/getSalesPersonMana.js
index 8ac1d7a38..42faec61b 100644
--- a/modules/ticket/back/methods/ticket/getSalesPersonMana.js
+++ b/modules/ticket/back/methods/ticket/getSalesPersonMana.js
@@ -1,12 +1,12 @@
module.exports = Self => {
Self.remoteMethod('getSalesPersonMana', {
- description: 'Returns mana of a salesperson of a ticket',
+ description: 'Returns the mana amount of a salesperson for a ticket',
accessType: 'READ',
accepts: [{
arg: 'id',
type: 'number',
required: true,
- description: 'ticket id',
+ description: 'The ticket id',
http: {source: 'path'}
}],
returns: {
@@ -18,8 +18,9 @@ module.exports = Self => {
}
});
- Self.getSalesPersonMana = async ticketFk => {
- let ticket = await Self.app.models.Ticket.findById(ticketFk, {
+ Self.getSalesPersonMana = async ticketId => {
+ const models = Self.app.models;
+ const ticket = await models.Ticket.findById(ticketId, {
include: [{
relation: 'client',
scope: {
@@ -29,10 +30,12 @@ module.exports = Self => {
fields: ['id', 'clientFk']
});
- if (!ticket)
- return 0;
+ if (!ticket) return 0;
- let mana = await Self.app.models.WorkerMana.findOne({where: {workerFk: ticket.client().salesPersonFk}, fields: 'amount'});
+ const mana = await models.WorkerMana.findOne({
+ where: {
+ workerFk: ticket.client().salesPersonFk
+ }, fields: 'amount'});
return mana ? mana.amount : 0;
};
diff --git a/modules/ticket/back/methods/ticket/new.js b/modules/ticket/back/methods/ticket/new.js
index 43fbf62e7..2763f1bd0 100644
--- a/modules/ticket/back/methods/ticket/new.js
+++ b/modules/ticket/back/methods/ticket/new.js
@@ -82,7 +82,8 @@ module.exports = Self => {
agencyMode = await models.AgencyMode.findById(agencyModeId);
if (address.client().type().code === 'normal' && (!agencyMode || agencyMode.code != 'refund')) {
- if (!address.client().isActive)
+ const canCreateTicket = await models.Client.canCreateTicket(clientId);
+ if (!canCreateTicket)
throw new UserError(`You can't create a ticket for a inactive client`);
}
diff --git a/modules/ticket/back/methods/ticket/summary.js b/modules/ticket/back/methods/ticket/summary.js
index 2035b4d31..79a7c24d9 100644
--- a/modules/ticket/back/methods/ticket/summary.js
+++ b/modules/ticket/back/methods/ticket/summary.js
@@ -90,7 +90,7 @@ module.exports = Self => {
}
}
}, {
- relation: 'state',
+ relation: 'ticketState',
scope: {
fields: ['stateFk'],
include: {
diff --git a/modules/ticket/back/methods/ticket/transferSales.js b/modules/ticket/back/methods/ticket/transferSales.js
index c2257bf09..541f19615 100644
--- a/modules/ticket/back/methods/ticket/transferSales.js
+++ b/modules/ticket/back/methods/ticket/transferSales.js
@@ -55,8 +55,14 @@ module.exports = Self => {
where: {ticketFk: id}
}, options);
- if (!ticketId)
+ if (!ticketId) {
+ const ticket = await models.Ticket.findById(id);
+ const canCreateTicket = await models.Client.canCreateTicket(ticket.clientFk);
+ if (!canCreateTicket)
+ throw new UserError(`You can't create a ticket for a inactive client`);
+
ticketId = await cloneTicket(originalTicket, options);
+ }
const map = new Map();
for (const sale of originalSales)
diff --git a/modules/ticket/back/models/sale.js b/modules/ticket/back/models/sale.js
index 4ffde08b3..4885071fd 100644
--- a/modules/ticket/back/models/sale.js
+++ b/modules/ticket/back/models/sale.js
@@ -1,7 +1,7 @@
module.exports = Self => {
require('../methods/sale/getClaimableFromTicket')(Self);
require('../methods/sale/reserve')(Self);
- require('../methods/sale/removes')(Self);
+ require('../methods/sale/deleteSales')(Self);
require('../methods/sale/updatePrice')(Self);
require('../methods/sale/updateQuantity')(Self);
require('../methods/sale/updateConcept')(Self);
diff --git a/modules/ticket/back/models/ticket.json b/modules/ticket/back/models/ticket.json
index 21c34232b..63b69b914 100644
--- a/modules/ticket/back/models/ticket.json
+++ b/modules/ticket/back/models/ticket.json
@@ -110,7 +110,7 @@
"model": "TicketObservation",
"foreignKey": "ticketFk"
},
- "state": {
+ "ticketState": {
"type": "hasOne",
"model": "TicketState",
"foreignKey": "ticketFk"
diff --git a/modules/ticket/front/card/index.js b/modules/ticket/front/card/index.js
index 8dce23aa7..80174b5e2 100644
--- a/modules/ticket/front/card/index.js
+++ b/modules/ticket/front/card/index.js
@@ -45,7 +45,7 @@ class Controller extends ModuleCard {
},
},
}, {
- relation: 'state',
+ relation: 'ticketState',
scope: {
fields: ['stateFk'],
include: {
diff --git a/modules/ticket/front/descriptor/addStowaway.html b/modules/ticket/front/descriptor/addStowaway.html
index f05a6584f..56bb321d9 100644
--- a/modules/ticket/front/descriptor/addStowaway.html
+++ b/modules/ticket/front/descriptor/addStowaway.html
@@ -26,7 +26,7 @@
New price
-{{$ctrl.newPrice | currency: 'EUR':2}}
-New price
-{{$ctrl.newPrice | currency: 'EUR':2}}
++ {{$ctrl.getNewPrice() | currency: 'EUR': 2}} +
New price
++ {{$ctrl.getNewPrice() | currency: 'EUR': 2}} +
+