Merge pull request '1368-ticket_sale_refactor' (#327) from 1368-ticket_sale_refactor into dev
gitea/salix/pipeline/head There was a failure building this commit
Details
gitea/salix/pipeline/head There was a failure building this commit
Details
Reviewed-on: #327 Reviewed-by: Joan Sanchez <joan@verdnatura.es>
This commit is contained in:
commit
1e4d432db8
|
@ -1,4 +1,5 @@
|
||||||
UPDATE `salix`.`ACL` SET `accessType`='WRITE' WHERE `id`='213';
|
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');
|
INSERT IGNORE INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES ('CustomsAgent', '*', '*', 'ALLOW', 'ROLE', 'employee');
|
||||||
|
|
||||||
|
|
|
@ -1664,11 +1664,13 @@ INSERT INTO `vn`.`workCenterHoliday` (`workCenterFk`, `days`, `year`)
|
||||||
('1', '24.5', YEAR(DATE_ADD(CURDATE(), INTERVAL -1 YEAR))),
|
('1', '24.5', YEAR(DATE_ADD(CURDATE(), INTERVAL -1 YEAR))),
|
||||||
('5', '23', 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
|
VALUES
|
||||||
(1, 'Holidays', '#FF4444', 'holiday'),
|
(1, 'Holidays', '#FF4444', 'holiday', 0),
|
||||||
(2, 'Leave of absence', '#C71585', 'absence'),
|
(2, 'Leave of absence', '#C71585', 'absence', 0),
|
||||||
(6, 'Half holiday', '#E65F00', 'halfHoliday');
|
(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`)
|
INSERT INTO `postgresql`.`calendar_employee` (`business_id`, `calendar_state_id`, `date`)
|
||||||
VALUES
|
VALUES
|
||||||
|
|
|
@ -558,7 +558,7 @@ let actions = {
|
||||||
}, selector);
|
}, selector);
|
||||||
},
|
},
|
||||||
|
|
||||||
closePopup: async function(selector) {
|
closePopup: async function() {
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
this.keyboard.press('Escape'),
|
this.keyboard.press('Escape'),
|
||||||
this.waitFor('.vn-popup', {hidden: true}),
|
this.waitFor('.vn-popup', {hidden: true}),
|
||||||
|
|
|
@ -401,8 +401,9 @@ export default {
|
||||||
createButton: `button[type=submit]`
|
createButton: `button[type=submit]`
|
||||||
},
|
},
|
||||||
ticketDescriptor: {
|
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"]',
|
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"]',
|
goBackToModuleIndexButton: 'vn-ticket-descriptor a[ui-sref="ticket.index"]',
|
||||||
moreMenu: 'vn-ticket-descriptor vn-icon-button[icon=more_vert]',
|
moreMenu: 'vn-ticket-descriptor vn-icon-button[icon=more_vert]',
|
||||||
moreMenuAddStowaway: '.vn-menu [name="addStowaway"]',
|
moreMenuAddStowaway: '.vn-menu [name="addStowaway"]',
|
||||||
|
@ -445,20 +446,23 @@ export default {
|
||||||
savePackagesButton: `button[type=submit]`
|
savePackagesButton: `button[type=submit]`
|
||||||
},
|
},
|
||||||
ticketSales: {
|
ticketSales: {
|
||||||
|
setOk: 'vn-ticket-sale vn-tool-bar > vn-button[label="Ok"] > button',
|
||||||
saleButton: 'vn-left-menu a[ui-sref="ticket.card.sale"]',
|
saleButton: 'vn-left-menu a[ui-sref="ticket.card.sale"]',
|
||||||
saleLine: 'vn-table div > vn-tbody > vn-tr',
|
saleLine: 'vn-table div > vn-tbody > vn-tr',
|
||||||
saleDescriptorPopover: '.vn-popover.shown vn-item-descriptor',
|
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',
|
descriptorItemDiaryButton: '.vn-popover vn-item-descriptor vn-quick-link[icon="icon-transaction"] > a',
|
||||||
newItemFromCatalogButton: 'vn-ticket-sale vn-float-button[icon="add"]',
|
newItemFromCatalogButton: 'vn-ticket-sale vn-float-button[icon="add"]',
|
||||||
newItemButton: 'vn-ticket-sale vn-card vn-icon-button[icon="add_circle"]',
|
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',
|
moreMenu: 'vn-ticket-sale vn-button[label="More"]',
|
||||||
moreMenuCreateClaim: '.vn-drop-down.shown li[name="Add claim"]',
|
moreMenuCreateClaim: 'vn-item[name="claim"]',
|
||||||
moreMenuReserve: '.vn-drop-down.shown li[name="Mark as reserved"]',
|
moreMenuReserve: 'vn-item[name="reserve"]',
|
||||||
moreMenuUnmarkReseved: '.vn-drop-down.shown li[name="Unmark as reserved"]',
|
moreMenuUnmarkReseved: 'vn-item[name="unreserve"]',
|
||||||
moreMenuUpdateDiscount: '.vn-drop-down.shown li[name="Update discount"]',
|
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',
|
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',
|
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"]',
|
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',
|
firstSaleDescriptorImage: '.vn-popover.shown vn-item-descriptor img',
|
||||||
firstSaleText: 'vn-table div > vn-tbody > vn-tr:nth-child(1)',
|
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)',
|
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',
|
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',
|
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',
|
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)',
|
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)',
|
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',
|
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',
|
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',
|
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',
|
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)',
|
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',
|
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',
|
selectAllSalesCheckbox: 'vn-ticket-sale vn-thead vn-check',
|
||||||
secondSaleCheckbox: 'vn-ticket-sale vn-tr:nth-child(2) vn-check[ng-model="sale.checked"]',
|
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"]',
|
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"]',
|
deleteSaleButton: 'vn-ticket-sale vn-tool-bar > vn-button[icon="delete"]',
|
||||||
transferSaleButton: 'vn-ticket-sale vn-tool-bar > vn-button[icon="call_split"]',
|
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"]',
|
moveToTicketButton: '.vn-popover.shown vn-icon[icon="arrow_forward_ios"]',
|
||||||
moveToNewTicketButton: '.vn-popover.shown vn-button[label="New ticket"]',
|
moveToNewTicketButton: '.vn-popover.shown vn-button[label="New ticket"]',
|
||||||
acceptDeleteLineButton: '.vn-confirm.shown button[response=accept]',
|
acceptDeleteLineButton: '.vn-confirm.shown button[response=accept]',
|
||||||
acceptDeleteTicketButton: '.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: {
|
ticketTracking: {
|
||||||
trackingButton: 'vn-left-menu a[ui-sref="ticket.card.tracking.index"]',
|
trackingButton: 'vn-left-menu a[ui-sref="ticket.card.tracking.index"]',
|
||||||
|
|
|
@ -72,7 +72,8 @@ describe('Ticket List sale path', () => {
|
||||||
}, {}, selectors.ticketSales.secondSaleIdAutocomplete, searchValue);
|
}, {}, selectors.ticketSales.secondSaleIdAutocomplete, searchValue);
|
||||||
|
|
||||||
await page.keyboard.press('Enter');
|
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');
|
await page.keyboard.press('Enter');
|
||||||
const message = await page.waitForSnackbar();
|
const message = await page.waitForSnackbar();
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
import selectors from '../../../helpers/selectors.js';
|
import selectors from '../../../helpers/selectors.js';
|
||||||
import getBrowser from '../../../helpers/puppeteer';
|
import getBrowser from '../../../helpers/puppeteer';
|
||||||
|
|
||||||
// #1632 [e2e] ticket.sale - Transferir líneas
|
describe('Ticket Edit sale path', () => {
|
||||||
xdescribe('Ticket Edit sale path', () => {
|
|
||||||
let browser;
|
let browser;
|
||||||
let page;
|
let page;
|
||||||
|
|
||||||
|
@ -10,7 +9,7 @@ xdescribe('Ticket Edit sale path', () => {
|
||||||
browser = await getBrowser();
|
browser = await getBrowser();
|
||||||
page = browser.page;
|
page = browser.page;
|
||||||
await page.loginAndModule('salesPerson', 'ticket');
|
await page.loginAndModule('salesPerson', 'ticket');
|
||||||
await page.accessToSearchResult(16);
|
await page.accessToSearchResult('16');
|
||||||
await page.accessToSection('ticket.card.sale');
|
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() => {
|
it(`should click on the first sale claim icon to navigate over there`, async() => {
|
||||||
await page.waitToClick(selectors.ticketSales.firstSaleClaimIcon);
|
await page.waitToClick(selectors.ticketSales.firstSaleClaimIcon);
|
||||||
await page.wait(selectors.claimBasicData.claimState);
|
await page.waitForState('claim.card.basicData');
|
||||||
const url = await page.parsedUrl();
|
|
||||||
|
|
||||||
expect(url.hash).toEqual('#!/claim/2/basic-data');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should navigate to the tickets index', async() => {
|
it('should navigate to the tickets index', async() => {
|
||||||
await page.waitToClick(selectors.globalItems.applicationsMenuButton);
|
await page.waitToClick(selectors.globalItems.applicationsMenuButton);
|
||||||
await page.wait(selectors.globalItems.applicationsMenuVisible);
|
await page.wait(selectors.globalItems.applicationsMenuVisible);
|
||||||
await page.waitToClick(selectors.globalItems.ticketsButton);
|
await page.waitToClick(selectors.globalItems.ticketsButton);
|
||||||
await page.wait(selectors.ticketsIndex.topbarSearch);
|
await page.waitForState('ticket.index');
|
||||||
const url = await page.parsedUrl();
|
|
||||||
|
|
||||||
expect(url.hash).toEqual('#!/ticket/index');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it(`should search for a ticket and then navigate to it's sales`, async() => {
|
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.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() => {
|
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() => {
|
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);
|
const result = await page.countElement(selectors.ticketSales.firstSaleZoomedImage);
|
||||||
|
|
||||||
expect(result).toEqual(1);
|
expect(result).toEqual(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it(`should click on the zoomed image to close it`, async() => {
|
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);
|
const result = await page.countElement(selectors.ticketSales.firstSaleZoomedImage);
|
||||||
|
|
||||||
expect(result).toEqual(0);
|
expect(result).toEqual(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it(`should confirm the item descriptor insnt visible yet`, async() => {
|
it(`should click on the first sale ID making now the item descriptor visible`, 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() => {
|
|
||||||
await page.waitToClick(selectors.ticketSales.firstSaleId);
|
await page.waitToClick(selectors.ticketSales.firstSaleId);
|
||||||
await page.waitImgLoad(selectors.ticketSales.firstSaleDescriptorImage);
|
await page.waitImgLoad(selectors.ticketSales.firstSaleDescriptorImage);
|
||||||
const visible = await page.isVisible(selectors.ticketSales.saleDescriptorPopover);
|
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() => {
|
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);
|
const result = await page.countElement(selectors.ticketSales.firstSaleZoomedImage);
|
||||||
|
|
||||||
expect(result).toEqual(1);
|
expect(result).toEqual(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it(`should now click on the zoomed image to close it`, async() => {
|
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);
|
const result = await page.countElement(selectors.ticketSales.firstSaleZoomedImage);
|
||||||
|
|
||||||
expect(result).toEqual(0);
|
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() => {
|
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.waitToClick(selectors.ticketSales.saleDescriptorPopoverSummaryButton);
|
||||||
await page.waitForURL('/summary');
|
await page.waitForState('item.card.summary');
|
||||||
const url = await page.parsedUrl();
|
|
||||||
|
|
||||||
expect(url.hash).toContain('/summary');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return to ticket sales section', async() => {
|
it('should return to ticket sales section', async() => {
|
||||||
await page.waitToClick(selectors.globalItems.applicationsMenuButton);
|
await page.waitToClick(selectors.globalItems.applicationsMenuButton);
|
||||||
await page.wait(selectors.globalItems.applicationsMenuVisible);
|
await page.wait(selectors.globalItems.applicationsMenuVisible);
|
||||||
await page.waitToClick(selectors.globalItems.ticketsButton);
|
await page.waitToClick(selectors.globalItems.ticketsButton);
|
||||||
await page.accessToSearchResult(16);
|
await page.accessToSearchResult('16');
|
||||||
await page.accessToSection('ticket.card.sale');
|
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() => {
|
it('should try to add a higher quantity value and then receive an error', async() => {
|
||||||
await page.focusElement(selectors.ticketSales.firstSaleQuantityCell);
|
await page.waitToClick(selectors.ticketSales.firstSaleQuantityCell);
|
||||||
await page.write(selectors.ticketSales.firstSaleQuantity, '11\u000d');
|
await page.type(selectors.ticketSales.firstSaleQuantity, '11\u000d');
|
||||||
const message = await page.waitForSnackbar();
|
const message = await page.waitForSnackbar();
|
||||||
|
|
||||||
expect(message.text).toBe('The new quantity should be smaller than the old one');
|
expect(message.text).toBe('The new quantity should be smaller than the old one');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should remove 1 from the first sale quantity', async() => {
|
it('should remove 1 from the first sale quantity', async() => {
|
||||||
await page.focusElement(selectors.ticketSales.firstSaleQuantityCell);
|
await page.waitFor(500);
|
||||||
await page.write(selectors.ticketSales.firstSaleQuantity, '9\u000d');
|
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();
|
const message = await page.waitForSnackbar();
|
||||||
|
|
||||||
expect(message.type).toBe('success');
|
expect(message.type).toBe('success');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should update the price', async() => {
|
it('should update the price', async() => {
|
||||||
await page.waitToClick(`${selectors.ticketSales.firstSalePrice} > span`);
|
await page.waitToClick(selectors.ticketSales.firstSalePrice);
|
||||||
await page.write(selectors.ticketSales.firstSalePriceInput, '5\u000d');
|
await page.waitFor(selectors.ticketSales.firstSalePriceInput);
|
||||||
|
await page.type(selectors.ticketSales.firstSalePriceInput, '5\u000d');
|
||||||
const message = await page.waitForSnackbar();
|
const message = await page.waitForSnackbar();
|
||||||
|
|
||||||
expect(message.type).toBe('success');
|
expect(message.type).toBe('success');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should confirm the price have been updated', async() => {
|
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');
|
expect(result).toContain('5.00');
|
||||||
});
|
});
|
||||||
|
@ -150,16 +160,17 @@ xdescribe('Ticket Edit sale path', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should update the discount', async() => {
|
it('should update the discount', async() => {
|
||||||
await page.waitToClick(`${selectors.ticketSales.firstSaleDiscount} > span`);
|
await page.waitToClick(selectors.ticketSales.firstSaleDiscount);
|
||||||
await page.write(selectors.ticketSales.firstSaleDiscountInput, '50\u000d');
|
await page.waitFor(selectors.ticketSales.firstSaleDiscountInput);
|
||||||
|
await page.type(selectors.ticketSales.firstSaleDiscountInput, '50\u000d');
|
||||||
const message = await page.waitForSnackbar();
|
const message = await page.waitForSnackbar();
|
||||||
|
|
||||||
expect(message.type).toBe('success');
|
expect(message.type).toBe('success');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should confirm the discount have been updated', async() => {
|
it('should confirm the discount have been updated', async() => {
|
||||||
await page.waitForTextInElement(`${selectors.ticketSales.firstSaleDiscount} > span`, '50.00%');
|
await page.waitForTextInElement(selectors.ticketSales.firstSaleDiscount, '50.00%');
|
||||||
const result = await page.waitToGetProperty(`${selectors.ticketSales.firstSaleDiscount} > span`, 'innerText');
|
const result = await page.waitToGetProperty(selectors.ticketSales.firstSaleDiscount, 'innerText');
|
||||||
|
|
||||||
expect(result).toContain('50.00%');
|
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.thirdSaleCheckbox);
|
||||||
await page.waitToClick(selectors.ticketSales.moreMenu);
|
await page.waitToClick(selectors.ticketSales.moreMenu);
|
||||||
await page.waitToClick(selectors.ticketSales.moreMenuCreateClaim);
|
await page.waitToClick(selectors.ticketSales.moreMenuCreateClaim);
|
||||||
await page.wait(selectors.claimBasicData.claimState);
|
await page.waitForState('claim.card.basicData');
|
||||||
const url = await page.parsedUrl();
|
|
||||||
|
|
||||||
expect(url.hash).toContain('basic-data');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should click on the Claims button of the top bar menu', async() => {
|
it('should click on the Claims button of the top bar menu', async() => {
|
||||||
await page.waitToClick(selectors.globalItems.applicationsMenuButton);
|
await page.waitToClick(selectors.globalItems.applicationsMenuButton);
|
||||||
await page.wait(selectors.globalItems.applicationsMenuVisible);
|
await page.wait(selectors.globalItems.applicationsMenuVisible);
|
||||||
await page.waitToClick(selectors.globalItems.claimsButton);
|
await page.waitToClick(selectors.globalItems.claimsButton);
|
||||||
await page.wait(selectors.claimsIndex.searchClaimInput);
|
await page.waitForState('claim.index');
|
||||||
const url = await page.parsedUrl();
|
|
||||||
|
|
||||||
expect(url.hash).toEqual('#!/claim/index');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should search for the claim with id 4', async() => {
|
it('should search for the claim with id 4', async() => {
|
||||||
await page.write(selectors.claimsIndex.searchClaimInput, 4);
|
await page.accessToSearchResult('4');
|
||||||
await page.waitToClick(selectors.claimsIndex.searchButton);
|
await page.waitForState('claim.card.summary');
|
||||||
await page.waitForNumberOfElements(selectors.claimsIndex.searchResult, 1);
|
|
||||||
const result = await page.countElement(selectors.claimsIndex.searchResult);
|
|
||||||
|
|
||||||
expect(result).toEqual(1);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should click the Tickets button of the top bar menu', async() => {
|
it('should click the Tickets button of the top bar menu', async() => {
|
||||||
await page.waitToClick(selectors.globalItems.applicationsMenuButton);
|
await page.waitToClick(selectors.globalItems.applicationsMenuButton);
|
||||||
await page.wait(selectors.globalItems.applicationsMenuVisible);
|
await page.wait(selectors.globalItems.applicationsMenuVisible);
|
||||||
await page.waitToClick(selectors.globalItems.ticketsButton);
|
await page.waitToClick(selectors.globalItems.ticketsButton);
|
||||||
await page.wait(selectors.ticketsIndex.topbarSearch);
|
await page.waitForState('ticket.index');
|
||||||
const url = await page.parsedUrl();
|
|
||||||
|
|
||||||
expect(url.hash).toEqual('#!/ticket/index');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should search for a ticket then access to the sales section', async() => {
|
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.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() => {
|
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() => {
|
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.secondSaleCheckbox);
|
||||||
await page.waitToClick(selectors.ticketSales.transferSaleButton);
|
await page.waitToClick(selectors.ticketSales.transferSaleButton);
|
||||||
await page.focusElement(selectors.ticketSales.transferQuantityCell);
|
await page.waitToClick(selectors.ticketSales.transferQuantityCell);
|
||||||
await page.write(selectors.ticketSales.transferQuantityInput, '10\u000d');
|
await page.type(selectors.ticketSales.transferQuantityInput, '10\u000d');
|
||||||
await page.write(selectors.ticketSales.moveToTicketInput, targetTicketId);
|
await page.type(selectors.ticketSales.moveToTicketInput, targetTicketId);
|
||||||
await page.waitToClick(selectors.ticketSales.moveToTicketButton);
|
await page.waitToClick(selectors.ticketSales.moveToTicketButton);
|
||||||
await page.waitForURL(`ticket/${targetTicketId}/sale`);
|
await page.expectURL(`ticket/${targetTicketId}/sale`);
|
||||||
const result = await page.parsedUrl();
|
|
||||||
|
|
||||||
expect(result.hash).toContain(`ticket/${targetTicketId}/sale`);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should confirm the transfered line is the correct one', async() => {
|
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() => {
|
it('should go back to the original ticket sales section', async() => {
|
||||||
await page.waitToClick(selectors.ticketDescriptor.goBackToModuleIndexButton);
|
await page.waitToClick(selectors.ticketDescriptor.goBackToModuleIndexButton);
|
||||||
await page.accessToSearchResult(16);
|
await page.accessToSearchResult('16');
|
||||||
await page.accessToSection('ticket.card.sale');
|
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() => {
|
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() => {
|
it('should go back to the receiver ticket sales section', async() => {
|
||||||
await page.waitToClick(selectors.ticketDescriptor.goBackToModuleIndexButton);
|
await page.waitToClick(selectors.ticketDescriptor.goBackToModuleIndexButton);
|
||||||
await page.accessToSearchResult(12);
|
await page.accessToSearchResult('12');
|
||||||
await page.accessToSection('ticket.card.sale');
|
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() => {
|
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.secondSaleCheckbox);
|
||||||
await page.waitToClick(selectors.ticketSales.transferSaleButton);
|
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.waitToClick(selectors.ticketSales.moveToTicketButton);
|
||||||
await page.waitForURL(`ticket/${targetTicketId}/sale`);
|
await page.expectURL(`ticket/${targetTicketId}/sale`);
|
||||||
const result = await page.parsedUrl();
|
|
||||||
|
|
||||||
expect(result.hash).toContain(`ticket/${targetTicketId}/sale`);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should confirm the original ticket received the line', async() => {
|
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.firstSaleCheckbox);
|
||||||
await page.waitToClick(selectors.ticketSales.transferSaleButton);
|
await page.waitToClick(selectors.ticketSales.transferSaleButton);
|
||||||
await page.waitToClick(selectors.ticketSales.moveToNewTicketButton);
|
await page.waitToClick(selectors.ticketSales.moveToNewTicketButton);
|
||||||
await page.waitToClick(selectors.ticketSales.acceptDeleteTicketButton);
|
|
||||||
const message = await page.waitForSnackbar();
|
const message = await page.waitForSnackbar();
|
||||||
|
|
||||||
expect(message.text).toBe(`You can't create a ticket for a inactive client`);
|
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() => {
|
it('should go now to the ticket sales section of an active, not frozen client', async() => {
|
||||||
await page.waitToClick(selectors.ticketDescriptor.goBackToModuleIndexButton);
|
await page.waitToClick(selectors.ticketDescriptor.goBackToModuleIndexButton);
|
||||||
await page.accessToSearchResult(13);
|
await page.accessToSearchResult('13');
|
||||||
await page.accessToSection('ticket.card.sale');
|
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() => {
|
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.selectAllSalesCheckbox);
|
||||||
await page.waitToClick(selectors.ticketSales.transferSaleButton);
|
await page.waitToClick(selectors.ticketSales.transferSaleButton);
|
||||||
await page.waitToClick(selectors.ticketSales.moveToNewTicketButton);
|
await page.waitToClick(selectors.ticketSales.moveToNewTicketButton);
|
||||||
await page.waitToClick(selectors.ticketSales.acceptDeleteTicketButton);
|
await page.evaluate((selector, ticketId) => {
|
||||||
await page.wait((selector, ticketId) => {
|
return document.querySelector(selector).innerText.toLowerCase().indexOf(`#${ticketId}`) == -1;
|
||||||
return document.querySelector(selector).innerText.toLowerCase().indexOf(`${ticketId}`) == -1;
|
}, selectors.ticketDescriptor.id, senderTicketId);
|
||||||
}, selectors.ticketDescriptor.idLabelValue, senderTicketId);
|
await page.waitForState('ticket.card.sale');
|
||||||
const url = await page.parsedUrl();
|
|
||||||
|
|
||||||
expect(url.hash).toContain('/sale');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should confirm the new ticket received the line', async() => {
|
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.firstSaleCheckbox);
|
||||||
await page.waitToClick(selectors.ticketSales.moreMenu);
|
await page.waitToClick(selectors.ticketSales.moreMenu);
|
||||||
await page.waitToClick(selectors.ticketSales.moreMenuReserve);
|
await page.waitToClick(selectors.ticketSales.moreMenuReserve);
|
||||||
|
await page.closePopup();
|
||||||
await page.waitForClassNotPresent(selectors.ticketSales.firstSaleReservedIcon, 'ng-hide');
|
await page.waitForClassNotPresent(selectors.ticketSales.firstSaleReservedIcon, 'ng-hide');
|
||||||
const result = await page.isVisible(selectors.ticketSales.firstSaleReservedIcon);
|
const result = await page.isVisible(selectors.ticketSales.firstSaleReservedIcon);
|
||||||
|
|
||||||
|
@ -384,10 +359,12 @@ xdescribe('Ticket Edit sale path', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should update all sales discount', async() => {
|
it('should update all sales discount', async() => {
|
||||||
|
await page.closePopup();
|
||||||
await page.waitToClick(selectors.ticketSales.moreMenu);
|
await page.waitToClick(selectors.ticketSales.moreMenu);
|
||||||
await page.waitToClick(selectors.ticketSales.moreMenuUpdateDiscount);
|
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.waitForSelector(selectors.ticketSales.moreMenuUpdateDiscountInput);
|
||||||
await page.write('body', '\u000d');
|
await page.type(selectors.ticketSales.moreMenuUpdateDiscountInput, '100');
|
||||||
|
await page.keyboard.press('Enter');
|
||||||
await page.waitForTextInElement(selectors.ticketSales.totalImport, '0.00');
|
await page.waitForTextInElement(selectors.ticketSales.totalImport, '0.00');
|
||||||
const result = await page.waitToGetProperty(selectors.ticketSales.totalImport, 'innerText');
|
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() => {
|
it('should log in as Production role and go to a target ticket summary', async() => {
|
||||||
await page.loginAndModule('production', 'ticket');
|
await page.loginAndModule('production', 'ticket');
|
||||||
await page.accessToSearchResult(13);
|
await page.accessToSearchResult('13');
|
||||||
await page.waitForURL('/summary');
|
await page.waitForState('ticket.card.summary');
|
||||||
const url = await page.parsedUrl();
|
|
||||||
|
|
||||||
expect(url.hash).toContain('/summary');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it(`should check it's state is deleted`, async() => {
|
it(`should check the ticket is deleted`, async() => {
|
||||||
const result = await page.waitToGetProperty(selectors.ticketDescriptor.stateLabelValue, 'innerText');
|
await page.waitForSelector(selectors.ticketDescriptor.isDeletedIcon);
|
||||||
|
await page.waitForClassPresent(selectors.ticketDescriptor.isDeletedIcon, 'bright');
|
||||||
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();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -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() => {
|
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.waitToClick(selectors.ticketTracking.createStateButton);
|
||||||
await page.waitForState('ticket.card.tracking.edit');
|
await page.waitForState('ticket.card.tracking.edit');
|
||||||
});
|
});
|
||||||
|
|
|
@ -18,6 +18,7 @@ describe('Ticket purchase request path', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should add a new request', async() => {
|
it('should add a new request', async() => {
|
||||||
|
await page.waitFor('.vn-popup', {hidden: true}),
|
||||||
await page.waitToClick(selectors.ticketRequests.addRequestButton);
|
await page.waitToClick(selectors.ticketRequests.addRequestButton);
|
||||||
await page.write(selectors.ticketRequests.descriptionInput, 'New stuff');
|
await page.write(selectors.ticketRequests.descriptionInput, 'New stuff');
|
||||||
await page.write(selectors.ticketRequests.quantity, '9');
|
await page.write(selectors.ticketRequests.quantity, '9');
|
||||||
|
|
|
@ -58,7 +58,7 @@ describe('Ticket Summary path', () => {
|
||||||
expect(result).toContain('000002');
|
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.waitToClick(selectors.ticketSummary.firstSaleItemId);
|
||||||
await page.waitImgLoad(selectors.ticketSummary.firstSaleDescriptorImage);
|
await page.waitImgLoad(selectors.ticketSummary.firstSaleDescriptorImage);
|
||||||
const visible = await page.isVisible(selectors.ticketSummary.itemDescriptorPopover);
|
const visible = await page.isVisible(selectors.ticketSummary.itemDescriptorPopover);
|
||||||
|
|
|
@ -8,7 +8,7 @@ describe('Order lines', () => {
|
||||||
browser = await getBrowser();
|
browser = await getBrowser();
|
||||||
page = browser.page;
|
page = browser.page;
|
||||||
await page.loginAndModule('employee', 'order');
|
await page.loginAndModule('employee', 'order');
|
||||||
await page.accessToSearchResult('16');
|
await page.accessToSearchResult('8');
|
||||||
await page.accessToSection('order.card.line');
|
await page.accessToSection('order.card.line');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ describe('Order lines', () => {
|
||||||
const result = await page
|
const result = await page
|
||||||
.waitToGetProperty(selectors.orderLine.orderSubtotal, 'innerText');
|
.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() => {
|
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() => {
|
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
|
const result = await page
|
||||||
.waitToGetProperty(selectors.orderLine.orderSubtotal, 'innerText');
|
.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() => {
|
it('should confirm the whole order and redirect to ticket index filtered by clientFk', async() => {
|
||||||
|
|
|
@ -68,6 +68,7 @@ export default class MultiCheck extends FormInput {
|
||||||
this.checkAll = value;
|
this.checkAll = value;
|
||||||
|
|
||||||
this.toggle();
|
this.toggle();
|
||||||
|
this.emit('change', value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -83,8 +83,6 @@ async function backTestOnce(done) {
|
||||||
port: container.dbConf.port
|
port: container.dbConf.port
|
||||||
});
|
});
|
||||||
|
|
||||||
log('[Debug] dataSources', dataSources.vn);
|
|
||||||
|
|
||||||
let bootOptions = {dataSources};
|
let bootOptions = {dataSources};
|
||||||
|
|
||||||
let app = require(`./loopback/server/server`);
|
let app = require(`./loopback/server/server`);
|
||||||
|
@ -92,8 +90,6 @@ async function backTestOnce(done) {
|
||||||
try {
|
try {
|
||||||
app.boot(bootOptions);
|
app.boot(bootOptions);
|
||||||
|
|
||||||
log('[Debug] back started');
|
|
||||||
|
|
||||||
await new Promise((resolve, reject) => {
|
await new Promise((resolve, reject) => {
|
||||||
const jasmine = require('gulp-jasmine');
|
const jasmine = require('gulp-jasmine');
|
||||||
|
|
||||||
|
|
|
@ -4,17 +4,15 @@ module.exports = Self => {
|
||||||
Self.remoteMethodCtx('createFromSales', {
|
Self.remoteMethodCtx('createFromSales', {
|
||||||
description: 'Create a claim',
|
description: 'Create a claim',
|
||||||
accepts: [{
|
accepts: [{
|
||||||
arg: 'claim',
|
arg: 'ticketId',
|
||||||
type: 'object',
|
type: 'Number',
|
||||||
required: true,
|
required: true,
|
||||||
description: ' newTicketFk, clientFk, ticketCreated',
|
description: 'The origin ticket id'
|
||||||
http: {source: 'body'}
|
|
||||||
}, {
|
}, {
|
||||||
arg: 'sales',
|
arg: 'sales',
|
||||||
type: 'object',
|
type: ['Object'],
|
||||||
required: true,
|
required: true,
|
||||||
description: '[sales IDs]',
|
description: 'The claimed sales'
|
||||||
http: {source: 'body'}
|
|
||||||
}],
|
}],
|
||||||
returns: {
|
returns: {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
|
@ -26,28 +24,27 @@ module.exports = Self => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Self.createFromSales = async(ctx, params) => {
|
Self.createFromSales = async(ctx, ticketId, sales) => {
|
||||||
let models = Self.app.models;
|
const models = Self.app.models;
|
||||||
let userId = ctx.req.accessToken.userId;
|
const userId = ctx.req.accessToken.userId;
|
||||||
let tx = await Self.beginTransaction({});
|
const tx = await Self.beginTransaction({});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
let options = {transaction: tx};
|
let options = {transaction: tx};
|
||||||
|
|
||||||
const ticketId = params.claim.ticketFk;
|
|
||||||
const ticket = await models.Ticket.findById(ticketId, null, options);
|
const ticket = await models.Ticket.findById(ticketId, null, options);
|
||||||
if (ticket.isDeleted)
|
if (ticket.isDeleted)
|
||||||
throw new UserError(`You can't create a claim for a removed ticket`);
|
throw new UserError(`You can't create a claim for a removed ticket`);
|
||||||
|
|
||||||
const worker = await models.Worker.findOne({
|
const newClaim = await Self.create({
|
||||||
where: {userFk: userId}
|
ticketFk: ticketId,
|
||||||
|
clientFk: ticket.clientFk,
|
||||||
|
ticketCreated: ticket.shipped,
|
||||||
|
workerFk: userId
|
||||||
}, options);
|
}, options);
|
||||||
|
const promises = [];
|
||||||
|
|
||||||
params.claim.workerFk = worker.id;
|
for (const sale of sales) {
|
||||||
let newClaim = await Self.create(params.claim, options);
|
|
||||||
let promises = [];
|
|
||||||
|
|
||||||
for (const sale of params.sales) {
|
|
||||||
const newClaimBeginning = models.ClaimBeginning.create({
|
const newClaimBeginning = models.ClaimBeginning.create({
|
||||||
saleFk: sale.id,
|
saleFk: sale.id,
|
||||||
claimFk: newClaim.id,
|
claimFk: newClaim.id,
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
const app = require('vn-loopback/server/server');
|
const app = require('vn-loopback/server/server');
|
||||||
|
|
||||||
describe('Claim Create', () => {
|
describe('Claim createFromSales()', () => {
|
||||||
let newDate = new Date();
|
|
||||||
let createdClaimFk;
|
let createdClaimFk;
|
||||||
|
|
||||||
afterAll(async done => {
|
afterAll(async done => {
|
||||||
|
@ -10,28 +9,18 @@ describe('Claim Create', () => {
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
let newClaim = {
|
const ticketId = 2;
|
||||||
ticketFk: 2,
|
const newSale = [{
|
||||||
clientFk: 101,
|
|
||||||
ticketCreated: newDate
|
|
||||||
};
|
|
||||||
|
|
||||||
let newSale = [{
|
|
||||||
id: 3,
|
id: 3,
|
||||||
instance: 0,
|
instance: 0,
|
||||||
quantity: 10
|
quantity: 10
|
||||||
}];
|
}];
|
||||||
|
const ctx = {req: {accessToken: {userId: 1}}};
|
||||||
let params = {claim: newClaim, sales: newSale};
|
|
||||||
let ctx = {req: {accessToken: {userId: 1}}};
|
|
||||||
|
|
||||||
it('should create a new claim', async() => {
|
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.ticketFk).toEqual(ticketId);
|
||||||
expect(claim.clientFk).toEqual(newClaim.clientFk);
|
|
||||||
expect(claim.ticketCreated).toEqual(newClaim.ticketCreated);
|
|
||||||
expect(claim.workerFk).toEqual(newClaim.workerFk);
|
|
||||||
|
|
||||||
let claimBeginning = await app.models.ClaimBeginning.findOne({where: {claimFk: claim.id}});
|
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() => {
|
it('should not be able to create a claim if exists that sale', async() => {
|
||||||
let error;
|
let error;
|
||||||
|
|
||||||
await app.models.Claim.createFromSales(ctx, params)
|
await app.models.Claim.createFromSales(ctx, ticketId, newSale)
|
||||||
|
|
||||||
.catch(e => {
|
.catch(e => {
|
||||||
error = e;
|
error = e;
|
||||||
|
|
|
@ -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;
|
||||||
|
};
|
||||||
|
};
|
|
@ -44,7 +44,7 @@ module.exports = Self => {
|
||||||
return role.name === 'employee';
|
return role.name === 'employee';
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!roleNames.length || isEmployee > -1 ) return false;
|
if (!roleNames.length || isEmployee > -1) return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
|
@ -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);
|
||||||
|
});
|
||||||
|
});
|
|
@ -11,6 +11,7 @@ module.exports = Self => {
|
||||||
require('../methods/client/createWithUser')(Self);
|
require('../methods/client/createWithUser')(Self);
|
||||||
require('../methods/client/listWorkers')(Self);
|
require('../methods/client/listWorkers')(Self);
|
||||||
require('../methods/client/hasCustomerRole')(Self);
|
require('../methods/client/hasCustomerRole')(Self);
|
||||||
|
require('../methods/client/canCreateTicket')(Self);
|
||||||
require('../methods/client/isValidClient')(Self);
|
require('../methods/client/isValidClient')(Self);
|
||||||
require('../methods/client/addressesPropagateRe')(Self);
|
require('../methods/client/addressesPropagateRe')(Self);
|
||||||
require('../methods/client/getDebt')(Self);
|
require('../methods/client/getDebt')(Self);
|
||||||
|
|
|
@ -29,7 +29,7 @@ module.exports = Self => {
|
||||||
order: 'priority',
|
order: 'priority',
|
||||||
include: [
|
include: [
|
||||||
{
|
{
|
||||||
relation: 'state',
|
relation: 'ticketState',
|
||||||
scope: {
|
scope: {
|
||||||
fields: ['id', 'stateFk'],
|
fields: ['id', 'stateFk'],
|
||||||
include: [{relation: 'state'}]
|
include: [{relation: 'state'}]
|
||||||
|
|
|
@ -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);
|
||||||
|
};
|
||||||
|
};
|
|
@ -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);
|
|
||||||
};
|
|
||||||
};
|
|
|
@ -6,28 +6,43 @@ module.exports = Self => {
|
||||||
description: 'Change the state of a ticket',
|
description: 'Change the state of a ticket',
|
||||||
accessType: 'WRITE',
|
accessType: 'WRITE',
|
||||||
accepts: [{
|
accepts: [{
|
||||||
arg: 'params',
|
arg: 'ticketId',
|
||||||
type: 'object',
|
type: 'Number',
|
||||||
required: true,
|
required: true,
|
||||||
description: '[sales IDs], ticketFk, reserved',
|
description: 'The ticket id'
|
||||||
http: {source: 'body'}
|
}, {
|
||||||
|
arg: 'sales',
|
||||||
|
type: ['Object'],
|
||||||
|
required: true,
|
||||||
|
description: 'The sale to reserve'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
arg: 'reserved',
|
||||||
|
type: 'Boolean',
|
||||||
|
required: true
|
||||||
}],
|
}],
|
||||||
returns: {
|
returns: {
|
||||||
type: 'string',
|
type: ['Object'],
|
||||||
root: true
|
root: true
|
||||||
},
|
},
|
||||||
http: {
|
http: {
|
||||||
path: `/reserve`,
|
path: `/reserve`,
|
||||||
verb: 'post'
|
verb: 'POST'
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Self.reserve = async(ctx, params) => {
|
Self.reserve = async(ctx, ticketId, sales, reserved) => {
|
||||||
let thisTicketIsEditable = await Self.app.models.Ticket.isEditable(ctx, params.ticketFk);
|
const models = Self.app.models;
|
||||||
if (!thisTicketIsEditable)
|
const isTicketEditable = await models.Ticket.isEditable(ctx, ticketId);
|
||||||
|
if (!isTicketEditable)
|
||||||
throw new UserError(`The sales of this ticket can't be modified`);
|
throw new UserError(`The sales of this ticket can't be modified`);
|
||||||
|
|
||||||
for (let i = 0; i < params.sales.length; i++)
|
const promises = [];
|
||||||
await Self.app.models.Sale.update({id: params.sales[i].id}, {reserved: params.reserved});
|
for (let sale of sales) {
|
||||||
|
const reservedSale = models.Sale.update({id: sale.id}, {reserved: reserved});
|
||||||
|
promises.push(reservedSale);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.all(promises);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
const app = require('vn-loopback/server/server');
|
const app = require('vn-loopback/server/server');
|
||||||
|
|
||||||
describe('sale removes()', () => {
|
describe('sale deleteSales()', () => {
|
||||||
let sale;
|
let sale;
|
||||||
let newsale;
|
let newsale;
|
||||||
|
|
||||||
|
@ -16,13 +16,11 @@ describe('sale removes()', () => {
|
||||||
let ctx = {req: {accessToken: {userId: 9}}};
|
let ctx = {req: {accessToken: {userId: 9}}};
|
||||||
let error;
|
let error;
|
||||||
|
|
||||||
let params = {
|
const sales = [{id: 1, instance: 0}, {id: 2, instance: 1}];
|
||||||
sales: [{id: 1, instance: 0}, {id: 2, instance: 1}],
|
const ticketId = 2;
|
||||||
actualTicketFk: 2
|
|
||||||
};
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await app.models.Sale.removes(ctx, params);
|
await app.models.Sale.deleteSales(ctx, sales, ticketId);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
error = e;
|
error = e;
|
||||||
}
|
}
|
||||||
|
@ -32,12 +30,11 @@ describe('sale removes()', () => {
|
||||||
|
|
||||||
it('should delete the sales', async() => {
|
it('should delete the sales', async() => {
|
||||||
let ctx = {req: {accessToken: {userId: 9}}};
|
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}]);
|
expect(res).toEqual([{count: 1}]);
|
||||||
});
|
});
|
|
@ -1,6 +1,7 @@
|
||||||
const app = require('vn-loopback/server/server');
|
const app = require('vn-loopback/server/server');
|
||||||
|
|
||||||
describe('sale reserve()', () => {
|
describe('sale reserve()', () => {
|
||||||
|
const ctx = {req: {accessToken: {userId: 9}}};
|
||||||
afterAll(async done => {
|
afterAll(async done => {
|
||||||
let ctx = {req: {accessToken: {userId: 9}}};
|
let ctx = {req: {accessToken: {userId: 9}}};
|
||||||
let params = {
|
let params = {
|
||||||
|
@ -17,13 +18,12 @@ describe('sale reserve()', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should throw an error if the ticket can not be modified', async() => {
|
it('should throw an error if the ticket can not be modified', async() => {
|
||||||
let ctx = {req: {accessToken: {userId: 9}}};
|
|
||||||
let error;
|
let error;
|
||||||
let params = {ticketFk: 2,
|
const ticketId = 2;
|
||||||
sales: [{id: 5}],
|
const sales = [{id: 5}];
|
||||||
reserved: false};
|
const reserved = false;
|
||||||
|
|
||||||
await app.models.Sale.reserve(ctx, params)
|
await app.models.Sale.reserve(ctx, ticketId, sales, reserved)
|
||||||
.catch(response => {
|
.catch(response => {
|
||||||
expect(response).toEqual(new Error(`The sales of this ticket can't be modified`));
|
expect(response).toEqual(new Error(`The sales of this ticket can't be modified`));
|
||||||
error = response;
|
error = response;
|
||||||
|
@ -38,18 +38,13 @@ describe('sale reserve()', () => {
|
||||||
expect(originalTicketSales[0].reserved).toEqual(0);
|
expect(originalTicketSales[0].reserved).toEqual(0);
|
||||||
expect(originalTicketSales[1].reserved).toEqual(0);
|
expect(originalTicketSales[1].reserved).toEqual(0);
|
||||||
|
|
||||||
let ctx = {req: {accessToken: {userId: 9}}};
|
const ticketId = 11;
|
||||||
let params = {
|
const sales = [{id: 7}, {id: 8}];
|
||||||
sales: [
|
const reserved = true;
|
||||||
{id: 7},
|
|
||||||
{id: 8}],
|
|
||||||
ticketFk: 11,
|
|
||||||
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[0].reserved).toEqual(1);
|
||||||
expect(reservedTicketSales[1].reserved).toEqual(1);
|
expect(reservedTicketSales[1].reserved).toEqual(1);
|
||||||
|
|
|
@ -38,7 +38,6 @@ module.exports = Self => {
|
||||||
let highestDate = new Date(ship.shipped.getTime());
|
let highestDate = new Date(ship.shipped.getTime());
|
||||||
highestDate.setHours(23, 59, 59);
|
highestDate.setHours(23, 59, 59);
|
||||||
|
|
||||||
|
|
||||||
let possibleStowaways = await models.Ticket.find({
|
let possibleStowaways = await models.Ticket.find({
|
||||||
where: {
|
where: {
|
||||||
id: {neq: ticketFk},
|
id: {neq: ticketFk},
|
||||||
|
@ -53,7 +52,7 @@ module.exports = Self => {
|
||||||
include: [
|
include: [
|
||||||
{relation: 'agencyMode'},
|
{relation: 'agencyMode'},
|
||||||
{relation: 'warehouse'},
|
{relation: 'warehouse'},
|
||||||
{relation: 'state',
|
{relation: 'ticketState',
|
||||||
scope: {
|
scope: {
|
||||||
fields: ['stateFk'],
|
fields: ['stateFk'],
|
||||||
include: {
|
include: {
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
module.exports = Self => {
|
module.exports = Self => {
|
||||||
Self.remoteMethod('getSalesPersonMana', {
|
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',
|
accessType: 'READ',
|
||||||
accepts: [{
|
accepts: [{
|
||||||
arg: 'id',
|
arg: 'id',
|
||||||
type: 'number',
|
type: 'number',
|
||||||
required: true,
|
required: true,
|
||||||
description: 'ticket id',
|
description: 'The ticket id',
|
||||||
http: {source: 'path'}
|
http: {source: 'path'}
|
||||||
}],
|
}],
|
||||||
returns: {
|
returns: {
|
||||||
|
@ -18,8 +18,9 @@ module.exports = Self => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Self.getSalesPersonMana = async ticketFk => {
|
Self.getSalesPersonMana = async ticketId => {
|
||||||
let ticket = await Self.app.models.Ticket.findById(ticketFk, {
|
const models = Self.app.models;
|
||||||
|
const ticket = await models.Ticket.findById(ticketId, {
|
||||||
include: [{
|
include: [{
|
||||||
relation: 'client',
|
relation: 'client',
|
||||||
scope: {
|
scope: {
|
||||||
|
@ -29,10 +30,12 @@ module.exports = Self => {
|
||||||
fields: ['id', 'clientFk']
|
fields: ['id', 'clientFk']
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!ticket)
|
if (!ticket) return 0;
|
||||||
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;
|
return mana ? mana.amount : 0;
|
||||||
};
|
};
|
||||||
|
|
|
@ -82,7 +82,8 @@ module.exports = Self => {
|
||||||
agencyMode = await models.AgencyMode.findById(agencyModeId);
|
agencyMode = await models.AgencyMode.findById(agencyModeId);
|
||||||
|
|
||||||
if (address.client().type().code === 'normal' && (!agencyMode || agencyMode.code != 'refund')) {
|
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`);
|
throw new UserError(`You can't create a ticket for a inactive client`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -90,7 +90,7 @@ module.exports = Self => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
relation: 'state',
|
relation: 'ticketState',
|
||||||
scope: {
|
scope: {
|
||||||
fields: ['stateFk'],
|
fields: ['stateFk'],
|
||||||
include: {
|
include: {
|
||||||
|
|
|
@ -55,8 +55,14 @@ module.exports = Self => {
|
||||||
where: {ticketFk: id}
|
where: {ticketFk: id}
|
||||||
}, options);
|
}, 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);
|
ticketId = await cloneTicket(originalTicket, options);
|
||||||
|
}
|
||||||
|
|
||||||
const map = new Map();
|
const map = new Map();
|
||||||
for (const sale of originalSales)
|
for (const sale of originalSales)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
module.exports = Self => {
|
module.exports = Self => {
|
||||||
require('../methods/sale/getClaimableFromTicket')(Self);
|
require('../methods/sale/getClaimableFromTicket')(Self);
|
||||||
require('../methods/sale/reserve')(Self);
|
require('../methods/sale/reserve')(Self);
|
||||||
require('../methods/sale/removes')(Self);
|
require('../methods/sale/deleteSales')(Self);
|
||||||
require('../methods/sale/updatePrice')(Self);
|
require('../methods/sale/updatePrice')(Self);
|
||||||
require('../methods/sale/updateQuantity')(Self);
|
require('../methods/sale/updateQuantity')(Self);
|
||||||
require('../methods/sale/updateConcept')(Self);
|
require('../methods/sale/updateConcept')(Self);
|
||||||
|
|
|
@ -110,7 +110,7 @@
|
||||||
"model": "TicketObservation",
|
"model": "TicketObservation",
|
||||||
"foreignKey": "ticketFk"
|
"foreignKey": "ticketFk"
|
||||||
},
|
},
|
||||||
"state": {
|
"ticketState": {
|
||||||
"type": "hasOne",
|
"type": "hasOne",
|
||||||
"model": "TicketState",
|
"model": "TicketState",
|
||||||
"foreignKey": "ticketFk"
|
"foreignKey": "ticketFk"
|
||||||
|
|
|
@ -45,7 +45,7 @@ class Controller extends ModuleCard {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
relation: 'state',
|
relation: 'ticketState',
|
||||||
scope: {
|
scope: {
|
||||||
fields: ['stateFk'],
|
fields: ['stateFk'],
|
||||||
include: {
|
include: {
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
<vn-td>{{ticket.landed | date: 'dd/MM/yyyy'}}</vn-td>
|
<vn-td>{{ticket.landed | date: 'dd/MM/yyyy'}}</vn-td>
|
||||||
<vn-td>{{ticket.agencyMode.name}}</vn-td>
|
<vn-td>{{ticket.agencyMode.name}}</vn-td>
|
||||||
<vn-td>{{ticket.warehouse.name}}</vn-td>
|
<vn-td>{{ticket.warehouse.name}}</vn-td>
|
||||||
<vn-td>{{ticket.state.state.name}}</vn-td>
|
<vn-td>{{ticket.ticketState.state.name}}</vn-td>
|
||||||
</vn-tr>
|
</vn-tr>
|
||||||
</vn-tbody>
|
</vn-tbody>
|
||||||
</vn-table>
|
</vn-table>
|
||||||
|
|
|
@ -87,7 +87,7 @@
|
||||||
<div class="attributes">
|
<div class="attributes">
|
||||||
<vn-label-value
|
<vn-label-value
|
||||||
label="State"
|
label="State"
|
||||||
value="{{$ctrl.ticket.state.state.name}}">
|
value="{{$ctrl.ticket.ticketState.state.name}}">
|
||||||
</vn-label-value>
|
</vn-label-value>
|
||||||
<vn-label-value
|
<vn-label-value
|
||||||
label="Sales person"
|
label="Sales person"
|
||||||
|
|
|
@ -210,7 +210,7 @@ class Controller extends Descriptor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
relation: 'state',
|
relation: 'ticketState',
|
||||||
scope: {
|
scope: {
|
||||||
fields: ['stateFk'],
|
fields: ['stateFk'],
|
||||||
include: {
|
include: {
|
||||||
|
|
|
@ -18,7 +18,6 @@ import './expedition';
|
||||||
import './volume';
|
import './volume';
|
||||||
import './package/index';
|
import './package/index';
|
||||||
import './sale';
|
import './sale';
|
||||||
import './sale/editDiscount';
|
|
||||||
import './tracking/index';
|
import './tracking/index';
|
||||||
import './tracking/edit';
|
import './tracking/edit';
|
||||||
import './sale-checked';
|
import './sale-checked';
|
||||||
|
|
|
@ -1,16 +0,0 @@
|
||||||
<section class="header vn-pa-md">
|
|
||||||
<h5>MANÁ: {{$ctrl.mana | currency: 'EUR':0}}</h5>
|
|
||||||
</section>
|
|
||||||
<div class="vn-pa-md">
|
|
||||||
<vn-input-number
|
|
||||||
vn-focus
|
|
||||||
label="Discount"
|
|
||||||
ng-model="$ctrl.newDiscount"
|
|
||||||
on-change="$ctrl.updateDiscount()"
|
|
||||||
suffix="%">
|
|
||||||
</vn-input-number>
|
|
||||||
<div class="simulator">
|
|
||||||
<p class="simulatorTitle" translate>New price</p>
|
|
||||||
<p>{{$ctrl.newPrice | currency: 'EUR':2}}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
|
@ -1,86 +0,0 @@
|
||||||
import ngModule from '../module';
|
|
||||||
import Component from 'core/lib/component';
|
|
||||||
|
|
||||||
class Controller extends Component {
|
|
||||||
set edit(value) {
|
|
||||||
this._edit = value;
|
|
||||||
this.clearDiscount();
|
|
||||||
this.setNewDiscount();
|
|
||||||
}
|
|
||||||
|
|
||||||
get edit() {
|
|
||||||
return this._edit;
|
|
||||||
}
|
|
||||||
|
|
||||||
set bulk(value) {
|
|
||||||
this._bulk = value;
|
|
||||||
this.setNewDiscount();
|
|
||||||
}
|
|
||||||
|
|
||||||
get bulk() {
|
|
||||||
return this._bulk;
|
|
||||||
}
|
|
||||||
|
|
||||||
get newDiscount() {
|
|
||||||
return this._newDiscount;
|
|
||||||
}
|
|
||||||
|
|
||||||
set newDiscount(value) {
|
|
||||||
this._newDiscount = value;
|
|
||||||
this.updateNewPrice();
|
|
||||||
}
|
|
||||||
|
|
||||||
updateNewPrice() {
|
|
||||||
if (this.newDiscount && this.edit[0])
|
|
||||||
this.newPrice = (this.edit[0].quantity * this.edit[0].price) - ((this.newDiscount * (this.edit[0].quantity * this.edit[0].price)) / 100);
|
|
||||||
}
|
|
||||||
|
|
||||||
setNewDiscount() {
|
|
||||||
if (!this.newDiscount && this.edit[0])
|
|
||||||
this.newDiscount = this.edit[0].discount;
|
|
||||||
}
|
|
||||||
|
|
||||||
updateDiscount() {
|
|
||||||
let salesIds = [];
|
|
||||||
let modified = false;
|
|
||||||
|
|
||||||
if (this.newDiscount == null) return;
|
|
||||||
|
|
||||||
for (let i = 0; i < this.edit.length; i++) {
|
|
||||||
if (this.newDiscount != this.edit[0].discount || this.bulk || !this.newDiscount) {
|
|
||||||
salesIds.push(this.edit[i].id);
|
|
||||||
modified = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (modified) {
|
|
||||||
const params = {salesIds: salesIds, newDiscount: this.newDiscount};
|
|
||||||
const query = `Tickets/${this.$params.id}/updateDiscount`;
|
|
||||||
this.$http.post(query, params).then(() => {
|
|
||||||
this.vnApp.showSuccess(this.$translate.instant('Data saved!'));
|
|
||||||
this.clearDiscount();
|
|
||||||
modified = false;
|
|
||||||
}).catch(e => {
|
|
||||||
this.vnApp.showError(e.message);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.onHide();
|
|
||||||
} else
|
|
||||||
this.vnApp.showError(this.$translate.instant('There are no changes to save'));
|
|
||||||
}
|
|
||||||
|
|
||||||
clearDiscount() {
|
|
||||||
this.newDiscount = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ngModule.component('vnTicketSaleEditDiscount', {
|
|
||||||
template: require('./editDiscount.html'),
|
|
||||||
controller: Controller,
|
|
||||||
bindings: {
|
|
||||||
edit: '<?',
|
|
||||||
mana: '<?',
|
|
||||||
bulk: '<?',
|
|
||||||
onHide: '&'
|
|
||||||
}
|
|
||||||
});
|
|
|
@ -12,53 +12,48 @@
|
||||||
<vn-horizontal class="header">
|
<vn-horizontal class="header">
|
||||||
<vn-tool-bar class="vn-mb-md">
|
<vn-tool-bar class="vn-mb-md">
|
||||||
<vn-button
|
<vn-button
|
||||||
disabled="!$ctrl.isEditable"
|
disabled="!$ctrl.isEditable || $ctrl.ticketState == 'OK'"
|
||||||
label="Ok"
|
label="Ok"
|
||||||
vn-http-click="$ctrl.onStateOkClick()"
|
vn-http-click="$ctrl.changeState('OK')"
|
||||||
vn-tooltip="Change ticket state to 'Ok'">
|
vn-tooltip="Change ticket state to 'Ok'">
|
||||||
</vn-button>
|
</vn-button>
|
||||||
<vn-button-menu
|
<vn-button-menu
|
||||||
disabled="!$ctrl.isEditable"
|
disabled="!$ctrl.isEditable"
|
||||||
label="State"
|
label="State"
|
||||||
value-field="id"
|
value-field="code"
|
||||||
url="States/editableStates"
|
url="States/editableStates"
|
||||||
on-change="$ctrl.onStateChange(value)">
|
on-change="$ctrl.changeState(value)">
|
||||||
</vn-button-menu>
|
</vn-button-menu>
|
||||||
<vn-button-menu
|
<vn-button icon="keyboard_arrow_down"
|
||||||
ng-show="$ctrl.isChecked"
|
|
||||||
vn-id="more-button"
|
|
||||||
label="More"
|
label="More"
|
||||||
show-filter="false"
|
ng-click="moreOptions.show($event)"
|
||||||
value-field="callback"
|
ng-show="$ctrl.hasSelectedSales()">
|
||||||
translate-fields="['name']"
|
</vn-button>
|
||||||
on-change="$ctrl.onMoreChange(value)"
|
|
||||||
on-open="$ctrl.onMoreOpen()">
|
|
||||||
</vn-button-menu>
|
|
||||||
<vn-button
|
<vn-button
|
||||||
disabled="!$ctrl.isChecked || !$ctrl.isEditable"
|
disabled="!$ctrl.hasSelectedSales() || !$ctrl.isEditable"
|
||||||
ng-click="deleteLines.show()"
|
ng-click="deleteLines.show()"
|
||||||
vn-tooltip="Remove lines"
|
vn-tooltip="Remove lines"
|
||||||
icon="delete">
|
icon="delete">
|
||||||
</vn-button>
|
</vn-button>
|
||||||
<vn-button
|
<vn-button
|
||||||
disabled="!$ctrl.isChecked || !$ctrl.isEditable"
|
disabled="!$ctrl.hasSelectedSales() || !$ctrl.isEditable"
|
||||||
ng-click="$ctrl.showTransferPopover($event)"
|
ng-click="$ctrl.showTransferPopover($event)"
|
||||||
vn-tooltip="Transfer lines"
|
vn-tooltip="Transfer lines"
|
||||||
icon="call_split">
|
icon="call_split">
|
||||||
</vn-button>
|
</vn-button>
|
||||||
</vn-tool-bar>
|
</vn-tool-bar>
|
||||||
<vn-one class="taxes" ng-if="$ctrl.sales.length > 0">
|
<vn-one class="taxes" ng-if="$ctrl.sales.length > 0">
|
||||||
<p><vn-label translate>Subtotal</vn-label> {{$ctrl.subtotal | currency: 'EUR':2}}</p>
|
<p><vn-label translate>Subtotal</vn-label> {{$ctrl.subtotal | currency: 'EUR': 2}}</p>
|
||||||
<p><vn-label translate>VAT</vn-label> {{$ctrl.VAT | currency: 'EUR':2}}</p>
|
<p><vn-label translate>VAT</vn-label> {{$ctrl.VAT | currency: 'EUR': 2}}</p>
|
||||||
<p><vn-label><strong>Total</strong></vn-label> <strong>{{$ctrl.total | currency: 'EUR':2}}</strong></p>
|
<p><vn-label><strong>Total</strong></vn-label> <strong>{{$ctrl.total | currency: 'EUR': 2}}</strong></p>
|
||||||
</vn-one>
|
</vn-one>
|
||||||
</vn-horizontal>
|
</vn-horizontal>
|
||||||
<vn-table model="model">
|
<vn-table model="model">
|
||||||
<vn-thead>
|
<vn-thead>
|
||||||
<vn-tr>
|
<vn-tr>
|
||||||
<vn-th shrink>
|
<vn-th shrink>
|
||||||
<vn-multi-check
|
<vn-multi-check model="model"
|
||||||
model="model">
|
on-change="$ctrl.resetChanges()">
|
||||||
</vn-multi-check>
|
</vn-multi-check>
|
||||||
</vn-th>
|
</vn-th>
|
||||||
<vn-th shrink></vn-th>
|
<vn-th shrink></vn-th>
|
||||||
|
@ -74,20 +69,19 @@
|
||||||
<vn-tbody>
|
<vn-tbody>
|
||||||
<vn-tr ng-repeat="sale in $ctrl.sales">
|
<vn-tr ng-repeat="sale in $ctrl.sales">
|
||||||
<vn-td shrink>
|
<vn-td shrink>
|
||||||
<vn-check
|
<vn-check tabindex="-1"
|
||||||
ng-model="sale.checked">
|
ng-model="sale.checked">
|
||||||
</vn-check>
|
</vn-check>
|
||||||
</vn-td>
|
</vn-td>
|
||||||
<vn-td shrink>
|
<vn-td shrink>
|
||||||
<a ui-sref="claim.card.basicData({id: sale.claim.claimFk})">
|
<a ui-sref="claim.card.basicData({id: sale.claim.claimFk})">
|
||||||
<vn-icon
|
<vn-icon icon="icon-claims"
|
||||||
ng-show="sale.claim.claimFk"
|
ng-show="sale.claim.claimFk"
|
||||||
icon="icon-claims"
|
|
||||||
vn-tooltip="{{::$ctrl.$t('Claim')}}: {{::sale.claim.claimFk}}">
|
vn-tooltip="{{::$ctrl.$t('Claim')}}: {{::sale.claim.claimFk}}">
|
||||||
</vn-icon>
|
</vn-icon>
|
||||||
</a>
|
</a>
|
||||||
<vn-icon
|
<vn-icon
|
||||||
ng-show="sale.visible < 0 || sale.available < 0"
|
ng-show="::(sale.visible < 0 || sale.available < 0)"
|
||||||
color-main
|
color-main
|
||||||
icon="warning"
|
icon="warning"
|
||||||
vn-tooltip="Visible: {{::sale.visible || 0}} <br> {{::$ctrl.$t('Available')}}: {{::sale.available || 0}}">
|
vn-tooltip="Visible: {{::sale.visible || 0}} <br> {{::$ctrl.$t('Available')}}: {{::sale.available || 0}}">
|
||||||
|
@ -103,13 +97,12 @@
|
||||||
zoom-image="{{::$root.imagePath}}/catalog/1600x900/{{sale.image}}"
|
zoom-image="{{::$root.imagePath}}/catalog/1600x900/{{sale.image}}"
|
||||||
on-error-src/>
|
on-error-src/>
|
||||||
</vn-td>
|
</vn-td>
|
||||||
<vn-td vn-focus number>
|
<vn-td number>
|
||||||
<span class="link" ng-if="sale.id"
|
<span class="link" ng-if="sale.id"
|
||||||
ng-click="descriptor.show($event, sale.itemFk, sale.id)">
|
ng-click="descriptor.show($event, sale.itemFk, sale.id)">
|
||||||
{{sale.itemFk}}
|
{{sale.itemFk}}
|
||||||
</span>
|
</span>
|
||||||
<vn-autocomplete
|
<vn-autocomplete ng-if="!sale.id"
|
||||||
ng-if="!sale.id"
|
|
||||||
vn-focus
|
vn-focus
|
||||||
vn-one
|
vn-one
|
||||||
url="Items"
|
url="Items"
|
||||||
|
@ -117,42 +110,35 @@
|
||||||
show-field="name"
|
show-field="name"
|
||||||
value-field="id"
|
value-field="id"
|
||||||
search-function="$ctrl.itemSearchFunc($search)"
|
search-function="$ctrl.itemSearchFunc($search)"
|
||||||
on-change="$ctrl.onChangeQuantity(sale)"
|
on-change="$ctrl.changeQuantity(sale)"
|
||||||
order="id DESC"
|
order="id DESC"
|
||||||
tabindex="1">
|
tabindex="1">
|
||||||
<tpl-item>
|
<tpl-item>
|
||||||
{{id}} - {{name}}
|
{{::id}} - {{::name}}
|
||||||
</tpl-item>
|
</tpl-item>
|
||||||
</vn-autocomplete>
|
</vn-autocomplete>
|
||||||
</vn-td>
|
</vn-td>
|
||||||
<vn-td-editable ng-if="sale.id" disabled="!$ctrl.isEditable" number>
|
<vn-td-editable disabled="!$ctrl.isEditable" number>
|
||||||
<text>{{sale.quantity}}</text>
|
<text>{{sale.quantity}}</text>
|
||||||
<field>
|
<field>
|
||||||
<vn-input-number class="dense"
|
<vn-input-number class="dense"
|
||||||
vn-focus
|
vn-focus
|
||||||
ng-model="sale.quantity"
|
ng-model="sale.quantity"
|
||||||
on-change="$ctrl.onChangeQuantity(sale)">
|
on-change="$ctrl.changeQuantity(sale)">
|
||||||
</vn-input-number>
|
</vn-input-number>
|
||||||
</field>
|
</field>
|
||||||
</vn-td-editable>
|
</vn-td-editable>
|
||||||
<vn-td ng-if="!sale.id" number>
|
|
||||||
<vn-input-number
|
|
||||||
ng-model="sale.quantity"
|
|
||||||
on-change="$ctrl.onChangeQuantity(sale)"
|
|
||||||
tabindex="2">
|
|
||||||
</vn-input-number>
|
|
||||||
</vn-td>
|
|
||||||
<vn-td-editable disabled="!sale.id || !$ctrl.isEditable" expand>
|
<vn-td-editable disabled="!sale.id || !$ctrl.isEditable" expand>
|
||||||
<text>
|
<text>
|
||||||
<vn-fetched-tags
|
<vn-fetched-tags
|
||||||
max-length="6"
|
max-length="6"
|
||||||
item="sale.item"
|
item="::sale.item"
|
||||||
name="sale.concept"
|
name="sale.concept"
|
||||||
sub-name="sale.subName">
|
sub-name="::sale.subName">
|
||||||
</vn-fetched-tags>
|
</vn-fetched-tags>
|
||||||
</text>
|
</text>
|
||||||
<field>
|
<field>
|
||||||
<vn-textfield class="dense"
|
<vn-textfield class="dense" vn-focus
|
||||||
vn-id="concept"
|
vn-id="concept"
|
||||||
ng-model="sale.concept"
|
ng-model="sale.concept"
|
||||||
on-change="$ctrl.updateConcept(sale)">
|
on-change="$ctrl.updateConcept(sale)">
|
||||||
|
@ -161,14 +147,14 @@
|
||||||
</vn-td-editable>
|
</vn-td-editable>
|
||||||
<vn-td number>
|
<vn-td number>
|
||||||
<span ng-class="{'link': $ctrl.isEditable}"
|
<span ng-class="{'link': $ctrl.isEditable}"
|
||||||
title="{{$ctrl.isEditable ? 'Edit price' : ''}}"
|
translate-attr="{title: $ctrl.isEditable ? 'Edit price' : ''}"
|
||||||
ng-click="$ctrl.showEditPricePopover($event, sale)">
|
ng-click="$ctrl.showEditPricePopover($event, sale)">
|
||||||
{{sale.price | currency: 'EUR':2}}
|
{{sale.price | currency: 'EUR':2}}
|
||||||
</span>
|
</span>
|
||||||
</vn-td>
|
</vn-td>
|
||||||
<vn-td number>
|
<vn-td number>
|
||||||
<span ng-class="{'link': !$ctrl.isLocked}"
|
<span ng-class="{'link': !$ctrl.isLocked}"
|
||||||
title="{{!$ctrl.isLocked ? 'Edit discount' : ''}}"
|
translate-attr="{title: !$ctrl.isLocked ? 'Edit discount' : ''}"
|
||||||
ng-click="$ctrl.showEditDiscountPopover($event, sale)"
|
ng-click="$ctrl.showEditDiscountPopover($event, sale)"
|
||||||
ng-if="sale.id">
|
ng-if="sale.id">
|
||||||
{{(sale.discount / 100) | percentage}}
|
{{(sale.discount / 100) | percentage}}
|
||||||
|
@ -196,7 +182,7 @@
|
||||||
ng-show="$ctrl.isEditable"
|
ng-show="$ctrl.isEditable"
|
||||||
ng-click="$ctrl.newOrderFromTicket()"
|
ng-click="$ctrl.newOrderFromTicket()"
|
||||||
icon="add"
|
icon="add"
|
||||||
vn-tooltip="Add item"
|
vn-tooltip="Add item to basket"
|
||||||
vn-bind="+"
|
vn-bind="+"
|
||||||
fixed-bottom-right>
|
fixed-bottom-right>
|
||||||
</vn-float-button>
|
</vn-float-button>
|
||||||
|
@ -206,60 +192,96 @@
|
||||||
ticket-fk="$ctrl.ticket.id">
|
ticket-fk="$ctrl.ticket.id">
|
||||||
</vn-item-descriptor-popover>
|
</vn-item-descriptor-popover>
|
||||||
|
|
||||||
<!-- Edit Price Popover -->
|
<!-- Price Popover -->
|
||||||
<vn-popover
|
<vn-popover
|
||||||
vn-id="edit-price-popover"
|
vn-id="edit-price-popover"
|
||||||
on-open="$ctrl.getManaSalespersonMana()"
|
on-open="$ctrl.getMana()">
|
||||||
on-close="$ctrl.mana = null">
|
<div class="edit-popover">
|
||||||
<div class="edit-price">
|
<vn-spinner class="vn-pa-xs"
|
||||||
<vn-spinner
|
ng-if="$ctrl.edit.mana == null"
|
||||||
ng-if="$ctrl.mana == null"
|
|
||||||
style="padding: 1em;"
|
|
||||||
enable="true">
|
enable="true">
|
||||||
</vn-spinner>
|
</vn-spinner>
|
||||||
<div ng-if="$ctrl.mana != null">
|
<div ng-if="$ctrl.edit.mana != null">
|
||||||
<section class="header vn-pa-md">
|
<section class="header vn-pa-md">
|
||||||
<h5>MANÁ: {{$ctrl.mana | currency: 'EUR':0}}</h5>
|
<h5>MANÁ: {{::$ctrl.edit.mana | currency: 'EUR': 0}}</h5>
|
||||||
</section>
|
</section>
|
||||||
<div class="vn-pa-md">
|
<div class="vn-pa-md">
|
||||||
<vn-input-number
|
<vn-input-number
|
||||||
vn-focus
|
vn-focus
|
||||||
label="Price"
|
label="Price"
|
||||||
ng-model="$ctrl.newPrice"
|
ng-model="$ctrl.edit.price"
|
||||||
step="0.01"
|
step="0.01"
|
||||||
on-change="$ctrl.updatePrice()"
|
on-change="$ctrl.updatePrice()"
|
||||||
suffix="€">
|
suffix="€">
|
||||||
</vn-input-number>
|
</vn-input-number>
|
||||||
<div class="simulator">
|
<div class="simulator">
|
||||||
<p class="simulatorTitle" translate>New price</p>
|
<p class="simulatorTitle" translate>New price</p>
|
||||||
<p>{{$ctrl.newPrice | currency: 'EUR':2}}</p>
|
<p>
|
||||||
|
<strong>{{$ctrl.getNewPrice() | currency: 'EUR': 2}}</strong>
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</vn-popover>
|
</vn-popover>
|
||||||
|
|
||||||
<!-- Edit Popover -->
|
<!-- Discount popover -->
|
||||||
<vn-popover
|
<vn-popover
|
||||||
vn-id="edit-popover"
|
vn-id="editDiscount"
|
||||||
on-open="$ctrl.getManaSalespersonMana()"
|
on-open="$ctrl.getMana()">
|
||||||
on-close="$ctrl.mana = null">
|
<div class="edit-popover">
|
||||||
<div class="edit-price">
|
<vn-spinner class="vn-pa-xs"
|
||||||
<vn-spinner
|
ng-if="$ctrl.edit.mana == null"
|
||||||
ng-if="$ctrl.mana == null"
|
|
||||||
style="padding: 1em;"
|
|
||||||
enable="true">
|
enable="true">
|
||||||
</vn-spinner>
|
</vn-spinner>
|
||||||
<vn-ticket-sale-edit-discount
|
<div ng-if="$ctrl.edit.mana != null">
|
||||||
ng-if="$ctrl.mana != null"
|
<section class="header vn-pa-md">
|
||||||
mana="$ctrl.mana"
|
<h5>Mana: {{::$ctrl.edit.mana | currency: 'EUR':0}}</h5>
|
||||||
bulk="false"
|
</section>
|
||||||
edit="$ctrl.edit"
|
<div class="vn-pa-md">
|
||||||
on-hide="$ctrl.hideEditPopover()">
|
<vn-input-number
|
||||||
</vn-ticket-sale-edit-discount>
|
vn-focus
|
||||||
|
label="Discount"
|
||||||
|
ng-model="$ctrl.edit.discount"
|
||||||
|
on-change="$ctrl.changeDiscount()"
|
||||||
|
suffix="%">
|
||||||
|
</vn-input-number>
|
||||||
|
<div class="simulator">
|
||||||
|
<p class="simulatorTitle" translate>New price</p>
|
||||||
|
<p>
|
||||||
|
<strong>{{$ctrl.getNewPrice() | currency: 'EUR': 2}}</strong>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</vn-popover>
|
</vn-popover>
|
||||||
|
|
||||||
|
<!-- Multiple discount dialog -->
|
||||||
|
<vn-dialog vn-id="editDiscountDialog"
|
||||||
|
on-open="$ctrl.getMana()"
|
||||||
|
message="Edit discount">
|
||||||
|
<tpl-body>
|
||||||
|
<vn-spinner class="vn-pa-xs"
|
||||||
|
ng-if="$ctrl.edit.mana == null"
|
||||||
|
enable="true">
|
||||||
|
</vn-spinner>
|
||||||
|
<div ng-if="$ctrl.edit.mana != null">
|
||||||
|
<div class="vn-pa-md">
|
||||||
|
<vn-input-number vn-focus
|
||||||
|
label="Discount"
|
||||||
|
ng-model="$ctrl.edit.discount"
|
||||||
|
on-change="$ctrl.changeMultipleDiscount()"
|
||||||
|
suffix="%">
|
||||||
|
</vn-input-number>
|
||||||
|
</div>
|
||||||
|
<section class="header vn-pa-md">
|
||||||
|
<span>Mana: <strong>{{::$ctrl.edit.mana | currency: 'EUR': 0}}</strong></span>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</tpl-body>
|
||||||
|
</vn-dialog>
|
||||||
|
|
||||||
<!-- Transfer Popover -->
|
<!-- Transfer Popover -->
|
||||||
<vn-popover vn-id="transfer">
|
<vn-popover vn-id="transfer">
|
||||||
<div class="vn-pa-md transfer">
|
<div class="vn-pa-md transfer">
|
||||||
|
@ -306,10 +328,10 @@
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th number>Id</th>
|
<th number>Id</th>
|
||||||
<th number>Shipped</th>
|
<th number translate>Shipped</th>
|
||||||
<th number>Agency</th>
|
<th number translate>Agency</th>
|
||||||
<th number>Warehouse</th>
|
<th number translate>Warehouse</th>
|
||||||
<th number>Address</th>
|
<th number translate>Address</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
|
@ -352,28 +374,6 @@
|
||||||
</div>
|
</div>
|
||||||
</vn-popover>
|
</vn-popover>
|
||||||
|
|
||||||
<!-- Edit Dialog -->
|
|
||||||
<vn-dialog
|
|
||||||
vn-id="editDialog"
|
|
||||||
class="edit"
|
|
||||||
on-open="$ctrl.getManaSalespersonMana()"
|
|
||||||
on-close="$ctrl.mana = null">
|
|
||||||
<tpl-body>
|
|
||||||
<vn-spinner
|
|
||||||
ng-if="$ctrl.mana == null"
|
|
||||||
style="padding: 1em;"
|
|
||||||
enable="true">
|
|
||||||
</vn-spinner>
|
|
||||||
<vn-ticket-sale-edit-discount
|
|
||||||
ng-if="$ctrl.mana != null"
|
|
||||||
mana="$ctrl.mana"
|
|
||||||
bulk="true"
|
|
||||||
edit="$ctrl.edit"
|
|
||||||
on-hide="$ctrl.hideEditDialog()">
|
|
||||||
</vn-ticket-sale-edit-discount>
|
|
||||||
</tpl-body>
|
|
||||||
</vn-dialog>
|
|
||||||
|
|
||||||
<!-- SMS Dialog -->
|
<!-- SMS Dialog -->
|
||||||
<vn-ticket-sms
|
<vn-ticket-sms
|
||||||
vn-id="sms"
|
vn-id="sms"
|
||||||
|
@ -384,7 +384,7 @@
|
||||||
vn-id="delete-lines"
|
vn-id="delete-lines"
|
||||||
question="You are going to delete lines of the ticket"
|
question="You are going to delete lines of the ticket"
|
||||||
message="Continue anyway?"
|
message="Continue anyway?"
|
||||||
on-response="$ctrl.onRemoveLinesClick($response)">
|
on-response="$ctrl.removeSales()">
|
||||||
</vn-confirm>
|
</vn-confirm>
|
||||||
|
|
||||||
<vn-confirm
|
<vn-confirm
|
||||||
|
@ -393,3 +393,39 @@
|
||||||
message="This ticket is now empty"
|
message="This ticket is now empty"
|
||||||
on-response="$ctrl.transferSales($ctrl.transfer.ticketId, $response)">
|
on-response="$ctrl.transferSales($ctrl.transfer.ticketId, $response)">
|
||||||
</vn-confirm>
|
</vn-confirm>
|
||||||
|
|
||||||
|
<vn-menu vn-id="moreOptions">
|
||||||
|
<vn-item translate
|
||||||
|
name="sms"
|
||||||
|
ng-click="$ctrl.showSMSDialog()">
|
||||||
|
Send shortage SMS
|
||||||
|
</vn-item>
|
||||||
|
<vn-item translate
|
||||||
|
name="calculatePrice"
|
||||||
|
ng-click="$ctrl.calculateSalePrice()"
|
||||||
|
ng-if="$ctrl.isEditable && $ctrl.hasOneSaleSelected()">
|
||||||
|
Recalculate price
|
||||||
|
</vn-item>
|
||||||
|
<vn-item translate
|
||||||
|
name="discount"
|
||||||
|
ng-click="$ctrl.showEditDiscountDialog($event)">
|
||||||
|
Update discount
|
||||||
|
</vn-item>
|
||||||
|
<vn-item translate
|
||||||
|
name="claim"
|
||||||
|
ng-click="$ctrl.createClaim()">
|
||||||
|
Add claim
|
||||||
|
</vn-item>
|
||||||
|
<vn-item translate
|
||||||
|
name="reserve"
|
||||||
|
ng-click="$ctrl.markAsReserved()"
|
||||||
|
ng-if="$ctrl.isEditable">
|
||||||
|
Mark as reserved
|
||||||
|
</vn-item>
|
||||||
|
<vn-item translate
|
||||||
|
name="unreserve"
|
||||||
|
ng-click="$ctrl.unmarkAsReserved()"
|
||||||
|
ng-if="$ctrl.isEditable && $ctrl.hasReserves()">
|
||||||
|
Unmark as reserved
|
||||||
|
</vn-item>
|
||||||
|
</vn-menu>
|
|
@ -5,32 +5,6 @@ import './style.scss';
|
||||||
class Controller extends Section {
|
class Controller extends Section {
|
||||||
constructor($element, $) {
|
constructor($element, $) {
|
||||||
super($element, $);
|
super($element, $);
|
||||||
this.edit = {};
|
|
||||||
this.moreOptions = [
|
|
||||||
{
|
|
||||||
name: 'Send shortage SMS',
|
|
||||||
callback: this.showSMSDialog
|
|
||||||
}, {
|
|
||||||
name: 'Mark as reserved',
|
|
||||||
callback: this.markAsReserved,
|
|
||||||
show: () => this.isEditable
|
|
||||||
}, {
|
|
||||||
name: 'Unmark as reserved',
|
|
||||||
callback: this.unmarkAsReserved,
|
|
||||||
show: () => this.isEditable
|
|
||||||
}, {
|
|
||||||
name: 'Update discount',
|
|
||||||
callback: this.showEditDialog,
|
|
||||||
show: () => this.isEditable
|
|
||||||
}, {
|
|
||||||
name: 'Add claim',
|
|
||||||
callback: this.createClaim
|
|
||||||
}, {
|
|
||||||
name: 'Recalculate price',
|
|
||||||
callback: this.calculateSalePrice,
|
|
||||||
show: () => this.hasOneSaleSelected()
|
|
||||||
},
|
|
||||||
];
|
|
||||||
this._sales = [];
|
this._sales = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,21 +27,17 @@ class Controller extends Section {
|
||||||
this.refreshTotal();
|
this.refreshTotal();
|
||||||
}
|
}
|
||||||
|
|
||||||
get editedPrice() {
|
get ticketState() {
|
||||||
return this._editedPrice;
|
if (!this.ticket) return null;
|
||||||
|
|
||||||
|
return this.ticket.ticketState.state.code;
|
||||||
}
|
}
|
||||||
|
|
||||||
set editedPrice(value) {
|
get total() {
|
||||||
this._editedPrice = value;
|
return this.subtotal + this.VAT;
|
||||||
this.updateNewPrice();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
refreshTotal() {
|
getSubTotal() {
|
||||||
this.loadSubTotal();
|
|
||||||
this.loadVAT();
|
|
||||||
}
|
|
||||||
|
|
||||||
loadSubTotal() {
|
|
||||||
if (!this.$params.id || !this.sales) return;
|
if (!this.$params.id || !this.sales) return;
|
||||||
this.$http.get(`Tickets/${this.$params.id}/subtotal`).then(res => {
|
this.$http.get(`Tickets/${this.$params.id}/subtotal`).then(res => {
|
||||||
this.subtotal = res.data || 0.0;
|
this.subtotal = res.data || 0.0;
|
||||||
|
@ -75,13 +45,21 @@ class Controller extends Section {
|
||||||
}
|
}
|
||||||
|
|
||||||
getSaleTotal(sale) {
|
getSaleTotal(sale) {
|
||||||
if (!sale.quantity || !sale.price)
|
if (sale.quantity == null || sale.price == null)
|
||||||
return;
|
return null;
|
||||||
|
|
||||||
return sale.quantity * sale.price * ((100 - sale.discount) / 100);
|
const price = sale.quantity * sale.price;
|
||||||
|
const discount = (sale.discount * price) / 100;
|
||||||
|
|
||||||
|
return price - discount;
|
||||||
}
|
}
|
||||||
|
|
||||||
loadVAT() {
|
getMana() {
|
||||||
|
this.$http.get(`Tickets/${this.$params.id}/getSalesPersonMana`)
|
||||||
|
.then(res => this.edit.mana = res.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
getVat() {
|
||||||
this.VAT = 0.0;
|
this.VAT = 0.0;
|
||||||
if (!this.$params.id || !this.sales) return;
|
if (!this.$params.id || !this.sales) return;
|
||||||
this.$http.get(`Tickets/${this.$params.id}/getVAT`).then(res => {
|
this.$http.get(`Tickets/${this.$params.id}/getVAT`).then(res => {
|
||||||
|
@ -89,32 +67,9 @@ class Controller extends Section {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
get total() {
|
refreshTotal() {
|
||||||
return this.subtotal + this.VAT;
|
this.getSubTotal();
|
||||||
}
|
this.getVat();
|
||||||
|
|
||||||
onMoreOpen() {
|
|
||||||
let options = this.moreOptions.filter(option => {
|
|
||||||
const hasShowProperty = Object.hasOwnProperty.call(option, 'show');
|
|
||||||
const shouldShow = !hasShowProperty || option.show === true ||
|
|
||||||
typeof option.show === 'function' && option.show();
|
|
||||||
|
|
||||||
return (shouldShow && (option.always || this.isChecked));
|
|
||||||
});
|
|
||||||
this.$.moreButton.data = options;
|
|
||||||
}
|
|
||||||
|
|
||||||
onMoreChange(callback) {
|
|
||||||
callback.call(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
get isChecked() {
|
|
||||||
if (this.sales) {
|
|
||||||
for (let instance of this.sales)
|
|
||||||
if (instance.checked) return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -122,7 +77,7 @@ class Controller extends Section {
|
||||||
*
|
*
|
||||||
* @return {Array} Checked instances
|
* @return {Array} Checked instances
|
||||||
*/
|
*/
|
||||||
checkedLines() {
|
selectedSales() {
|
||||||
if (!this.sales) return;
|
if (!this.sales) return;
|
||||||
|
|
||||||
return this.sales.filter(sale => {
|
return this.sales.filter(sale => {
|
||||||
|
@ -130,6 +85,38 @@ class Controller extends Section {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
selectedValidSales() {
|
||||||
|
if (!this.sales) return;
|
||||||
|
|
||||||
|
const selectedSales = this.selectedSales();
|
||||||
|
return selectedSales.filter(sale => {
|
||||||
|
return sale.id != undefined;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the total of checked instances
|
||||||
|
*
|
||||||
|
* @return {Number} Total checked instances
|
||||||
|
*/
|
||||||
|
selectedSalesCount() {
|
||||||
|
const selectedSales = this.selectedSales();
|
||||||
|
if (selectedSales)
|
||||||
|
return selectedSales.length;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
hasSelectedSales() {
|
||||||
|
return this.selectedSalesCount() > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
hasOneSaleSelected() {
|
||||||
|
if (this.selectedSalesCount() === 1)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns new instances
|
* Returns new instances
|
||||||
*
|
*
|
||||||
|
@ -143,99 +130,53 @@ class Controller extends Section {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
resetChanges() {
|
||||||
* Returns an array of indexes
|
if (this.newInstances().length === 0)
|
||||||
* from checked instances
|
this.$.watcher.updateOriginalData();
|
||||||
*
|
|
||||||
* @return {Array} Indexes of checked instances
|
|
||||||
*/
|
|
||||||
checkedLinesIndex() {
|
|
||||||
if (!this.sales) return;
|
|
||||||
|
|
||||||
let indexes = [];
|
|
||||||
this.sales.forEach((sale, index) => {
|
|
||||||
if (sale.checked) indexes.push(index);
|
|
||||||
});
|
|
||||||
|
|
||||||
return indexes;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
firstCheckedLine() {
|
changeState(value) {
|
||||||
const checkedLines = this.checkedLines();
|
const params = {ticketFk: this.$params.id, code: value};
|
||||||
if (checkedLines)
|
return this.$http.post('TicketTrackings/changeState', params).then(() => {
|
||||||
return checkedLines[0];
|
this.vnApp.showSuccess(this.$t('Data saved!'));
|
||||||
|
this.card.reload();
|
||||||
|
}).finally(() => this.resetChanges());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
removeSales() {
|
||||||
* Returns the total of checked instances
|
const sales = this.selectedValidSales();
|
||||||
*
|
const params = {sales: sales, ticketId: this.ticket.id};
|
||||||
* @return {Number} Total checked instances
|
this.$http.post(`Sales/deleteSales`, params).then(() => {
|
||||||
*/
|
this.removeSelectedSales();
|
||||||
totalCheckedLines() {
|
this.vnApp.showSuccess(this.$t('Data saved!'));
|
||||||
const checkedLines = this.checkedLines();
|
}).finally(() => this.resetChanges());
|
||||||
if (checkedLines)
|
|
||||||
return checkedLines.length;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
removeCheckedLines() {
|
removeSelectedSales() {
|
||||||
const sales = this.checkedLines();
|
const sales = this.selectedSales();
|
||||||
|
|
||||||
sales.forEach(sale => {
|
sales.forEach(sale => {
|
||||||
const index = this.sales.indexOf(sale);
|
const index = this.sales.indexOf(sale);
|
||||||
this.sales.splice(index, 1);
|
this.sales.splice(index, 1);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (this.newInstances().length === 0)
|
|
||||||
this.$.watcher.updateOriginalData();
|
|
||||||
|
|
||||||
this.refreshTotal();
|
this.refreshTotal();
|
||||||
}
|
}
|
||||||
|
|
||||||
onStateOkClick() {
|
createClaim() {
|
||||||
let filter = {where: {code: 'OK'}, fields: ['id']};
|
const sales = this.selectedValidSales();
|
||||||
let json = encodeURIComponent(JSON.stringify(filter));
|
const params = {ticketId: this.ticket.id, sales: sales};
|
||||||
return this.$http.get(`States?filter=${json}`).then(res => {
|
this.resetChanges();
|
||||||
this.onStateChange(res.data[0].id);
|
this.$http.post(`Claims/createFromSales`, params)
|
||||||
});
|
.then(res => this.$state.go('claim.card.basicData', {id: res.data.id}));
|
||||||
}
|
|
||||||
|
|
||||||
onStateChange(value) {
|
|
||||||
let params = {ticketFk: this.$state.params.id, stateFk: value};
|
|
||||||
this.$http.post('TicketTrackings/changeState', params).then(() => {
|
|
||||||
this.card.reload();
|
|
||||||
this.vnApp.showSuccess(this.$translate.instant('Data saved!'));
|
|
||||||
}).finally(() => {
|
|
||||||
if (this.newInstances().length === 0)
|
|
||||||
this.$.watcher.updateOriginalData();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
onRemoveLinesClick(response) {
|
|
||||||
if (response === 'accept') {
|
|
||||||
let sales = this.checkedLines();
|
|
||||||
|
|
||||||
// Remove unsaved instances
|
|
||||||
sales.forEach((sale, index) => {
|
|
||||||
if (!sale.id) sales.splice(index);
|
|
||||||
});
|
|
||||||
|
|
||||||
let params = {sales: sales, actualTicketFk: this.ticket.id};
|
|
||||||
let query = `Sales/removes`;
|
|
||||||
this.$http.post(query, params).then(() => {
|
|
||||||
this.removeCheckedLines();
|
|
||||||
this.vnApp.showSuccess(this.$translate.instant('Data saved!'));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
showTransferPopover(event) {
|
showTransferPopover(event) {
|
||||||
this.setTransferParams();
|
this.setTransferParams();
|
||||||
this.$.transfer.parent = event.target;
|
this.$.transfer.show(event);
|
||||||
this.$.transfer.show();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setTransferParams() {
|
setTransferParams() {
|
||||||
const checkedSales = JSON.stringify(this.checkedLines());
|
const checkedSales = JSON.stringify(this.selectedValidSales());
|
||||||
const sales = JSON.parse(checkedSales);
|
const sales = JSON.parse(checkedSales);
|
||||||
this.transfer = {
|
this.transfer = {
|
||||||
lastActiveTickets: [],
|
lastActiveTickets: [],
|
||||||
|
@ -258,99 +199,123 @@ class Controller extends Section {
|
||||||
this.$.watcher.updateOriginalData();
|
this.$.watcher.updateOriginalData();
|
||||||
|
|
||||||
const query = `tickets/${this.ticket.id}/transferSales`;
|
const query = `tickets/${this.ticket.id}/transferSales`;
|
||||||
this.$http.post(query, params).then(res => {
|
this.$http.post(query, params)
|
||||||
this.goToTicket(res.data.id);
|
.then(res => this.$state.go('ticket.card.sale', {id: res.data.id}));
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
createClaim() {
|
|
||||||
const claim = {
|
|
||||||
ticketFk: this.ticket.id,
|
|
||||||
clientFk: this.ticket.clientFk,
|
|
||||||
ticketCreated: this.ticket.shipped
|
|
||||||
};
|
|
||||||
const sales = this.checkedLines();
|
|
||||||
|
|
||||||
if (this.newInstances().length === 0)
|
|
||||||
this.$.watcher.updateOriginalData();
|
|
||||||
|
|
||||||
this.$http.post(`Claims/createFromSales`, {claim: claim, sales: sales}).then(res => {
|
|
||||||
this.$state.go('claim.card.basicData', {id: res.data.id});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
goToTicket(ticketId) {
|
|
||||||
this.$state.go('ticket.card.sale', {id: ticketId});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Slesperson Mana
|
|
||||||
getManaSalespersonMana() {
|
|
||||||
this.$http.get(`Tickets/${this.$state.params.id}/getSalesPersonMana`).then(res => {
|
|
||||||
this.mana = res.data;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
showEditPricePopover(event, sale) {
|
showEditPricePopover(event, sale) {
|
||||||
if (!this.isEditable) return;
|
if (!this.isEditable) return;
|
||||||
this.sale = sale;
|
|
||||||
this.newPrice = this.sale.price;
|
|
||||||
this.edit = {
|
this.edit = {
|
||||||
ticketFk: this.ticket.id,
|
price: sale.price,
|
||||||
id: sale.id,
|
sale: sale
|
||||||
quantity: sale.quantity
|
|
||||||
};
|
};
|
||||||
this.$.editPricePopover.parent = event.target;
|
this.$.editPricePopover.show(event);
|
||||||
this.$.editPricePopover.show();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
updatePrice() {
|
updatePrice() {
|
||||||
if (this.newPrice && this.newPrice != this.sale.price) {
|
const sale = this.edit.sale;
|
||||||
const query = `Sales/${this.edit.id}/updatePrice`;
|
const newPrice = this.edit.price;
|
||||||
this.$http.post(query, {newPrice: this.newPrice}).then(res => {
|
if (newPrice != null && newPrice != sale.price) {
|
||||||
this.sale.price = res.data.price;
|
const query = `Sales/${sale.id}/updatePrice`;
|
||||||
|
this.$http.post(query, {newPrice}).then(res => {
|
||||||
this.vnApp.showSuccess(this.$translate.instant('Data saved!'));
|
sale.price = res.data.price;
|
||||||
}).finally(() => {
|
this.edit = null;
|
||||||
if (this.newInstances().length === 0)
|
this.refreshTotal();
|
||||||
this.$.watcher.updateOriginalData();
|
this.vnApp.showSuccess(this.$t('Data saved!'));
|
||||||
});
|
}).finally(() => this.resetChanges());
|
||||||
}
|
}
|
||||||
|
|
||||||
this.$.editPricePopover.hide();
|
this.$.editPricePopover.hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
updateNewPrice() {
|
|
||||||
this.newPrice = this.sale.quantity * this.newPrice - ((this.sale.discount * (this.sale.quantity * this.newPrice)) / 100);
|
|
||||||
}
|
|
||||||
|
|
||||||
showEditDiscountPopover(event, sale) {
|
showEditDiscountPopover(event, sale) {
|
||||||
if (this.isLocked) return;
|
if (this.isLocked) return;
|
||||||
|
|
||||||
this.sale = sale;
|
this.edit = {
|
||||||
this.edit = [{
|
discount: sale.discount,
|
||||||
ticketFk: this.ticket.id,
|
sale: sale
|
||||||
id: sale.id,
|
};
|
||||||
quantity: sale.quantity,
|
|
||||||
price: sale.price,
|
this.$.editDiscount.show(event);
|
||||||
discount: sale.discount
|
|
||||||
}];
|
|
||||||
this.$.editPopover.parent = event.target;
|
|
||||||
this.$.editPopover.show();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
showEditDialog() {
|
showEditDiscountDialog(event) {
|
||||||
this.edit = this.checkedLines();
|
if (this.isLocked) return;
|
||||||
this.$.editDialog.show();
|
|
||||||
|
this.edit = {
|
||||||
|
discount: null,
|
||||||
|
sales: this.selectedValidSales()
|
||||||
|
};
|
||||||
|
|
||||||
|
this.$.editDiscountDialog.show(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
hideEditDialog() {
|
changeDiscount() {
|
||||||
this.$.model.refresh();
|
const sale = this.edit.sale;
|
||||||
this.$.editDialog.hide();
|
const newDiscount = this.edit.discount;
|
||||||
|
if (newDiscount != null && newDiscount != sale.discount)
|
||||||
|
this.updateDiscount([sale]);
|
||||||
|
|
||||||
|
this.$.editDiscount.hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
hideEditPopover() {
|
changeMultipleDiscount() {
|
||||||
this.$.model.refresh();
|
const sales = this.edit.sales;
|
||||||
this.$.editPopover.hide();
|
const newDiscount = this.edit.discount;
|
||||||
|
const hasChanges = sales.some(sale => {
|
||||||
|
return sale.discount != newDiscount;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (newDiscount != null && hasChanges)
|
||||||
|
this.updateDiscount(sales);
|
||||||
|
|
||||||
|
this.$.editDiscountDialog.hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
updateDiscount(sales) {
|
||||||
|
const saleIds = sales.map(sale => {
|
||||||
|
return sale.id;
|
||||||
|
});
|
||||||
|
|
||||||
|
const params = {salesIds: saleIds, newDiscount: this.edit.discount};
|
||||||
|
const query = `Tickets/${this.$params.id}/updateDiscount`;
|
||||||
|
this.$http.post(query, params).then(() => {
|
||||||
|
this.vnApp.showSuccess(this.$translate.instant('Data saved!'));
|
||||||
|
|
||||||
|
for (let sale of sales)
|
||||||
|
sale.discount = this.edit.discount;
|
||||||
|
|
||||||
|
this.edit = null;
|
||||||
|
this.refreshTotal();
|
||||||
|
}).finally(() => this.resetChanges());
|
||||||
|
}
|
||||||
|
|
||||||
|
getNewPrice() {
|
||||||
|
if (this.edit) {
|
||||||
|
const sale = this.edit.sale;
|
||||||
|
let newDiscount = sale.discount;
|
||||||
|
let newPrice = this.edit.price || sale.price;
|
||||||
|
|
||||||
|
if (this.edit.discount != null)
|
||||||
|
newDiscount = this.edit.discount;
|
||||||
|
|
||||||
|
if (this.edit.price != null)
|
||||||
|
newPrice = this.edit.price;
|
||||||
|
|
||||||
|
const price = sale.quantity * newPrice;
|
||||||
|
const discount = (newDiscount * price) / 100;
|
||||||
|
|
||||||
|
return price - discount;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
hasReserves() {
|
||||||
|
return this.sales.some(sale => {
|
||||||
|
return sale.reserved == true;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -368,26 +333,13 @@ class Controller extends Section {
|
||||||
}
|
}
|
||||||
|
|
||||||
setReserved(reserved) {
|
setReserved(reserved) {
|
||||||
let selectedSales = this.checkedLines();
|
const selectedSales = this.selectedValidSales();
|
||||||
let params = {sales: selectedSales, ticketFk: this.ticket.id, reserved: reserved};
|
const params = {ticketId: this.ticket.id, sales: selectedSales, reserved: reserved};
|
||||||
|
this.$http.post(`Sales/reserve`, params).then(() => {
|
||||||
let reservedSales = new Map();
|
selectedSales.forEach(sale => {
|
||||||
this.$http.post(`Sales/reserve`, params).then(res => {
|
sale.reserved = reserved;
|
||||||
let isReserved = res.config.data.reserved;
|
|
||||||
|
|
||||||
res.config.data.sales.forEach(sale => {
|
|
||||||
reservedSales.set(sale.id, {reserved: isReserved});
|
|
||||||
});
|
|
||||||
|
|
||||||
this.sales.forEach(sale => {
|
|
||||||
const reservedSale = reservedSales.get(sale.id);
|
|
||||||
if (reservedSale)
|
|
||||||
sale.reserved = reservedSale.reserved;
|
|
||||||
});
|
|
||||||
}).finally(() => {
|
|
||||||
if (this.newInstances().length === 0)
|
|
||||||
this.$.watcher.updateOriginalData();
|
|
||||||
});
|
});
|
||||||
|
}).finally(() => this.resetChanges());
|
||||||
}
|
}
|
||||||
|
|
||||||
newOrderFromTicket() {
|
newOrderFromTicket() {
|
||||||
|
@ -395,7 +347,7 @@ class Controller extends Section {
|
||||||
const path = this.$state.href('order.card.catalog', {id: res.data});
|
const path = this.$state.href('order.card.catalog', {id: res.data});
|
||||||
window.open(path, '_blank');
|
window.open(path, '_blank');
|
||||||
|
|
||||||
this.vnApp.showSuccess(this.$translate.instant('Order created'));
|
this.vnApp.showSuccess(this.$t('Order created'));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -404,7 +356,7 @@ class Controller extends Section {
|
||||||
const client = this.ticket.client;
|
const client = this.ticket.client;
|
||||||
const phone = address.mobile || address.phone ||
|
const phone = address.mobile || address.phone ||
|
||||||
client.mobile || client.phone;
|
client.mobile || client.phone;
|
||||||
const sales = this.checkedLines();
|
const sales = this.selectedValidSales();
|
||||||
const items = sales.map(sale => {
|
const items = sales.map(sale => {
|
||||||
return `${sale.quantity} ${sale.concept}`;
|
return `${sale.quantity} ${sale.concept}`;
|
||||||
});
|
});
|
||||||
|
@ -417,7 +369,7 @@ class Controller extends Section {
|
||||||
this.newSMS = {
|
this.newSMS = {
|
||||||
destinationFk: this.ticket.clientFk,
|
destinationFk: this.ticket.clientFk,
|
||||||
destination: phone,
|
destination: phone,
|
||||||
message: this.$translate.instant('Product not available', params)
|
message: this.$t('Product not available', params)
|
||||||
};
|
};
|
||||||
this.$.sms.open();
|
this.$.sms.open();
|
||||||
}
|
}
|
||||||
|
@ -433,8 +385,8 @@ class Controller extends Section {
|
||||||
* Creates a new sale if it's a new instance
|
* Creates a new sale if it's a new instance
|
||||||
* Updates the sale quantity for existing instance
|
* Updates the sale quantity for existing instance
|
||||||
*/
|
*/
|
||||||
onChangeQuantity(sale) {
|
changeQuantity(sale) {
|
||||||
if (!sale.quantity) return;
|
if (!sale.itemFk || !sale.quantity) return;
|
||||||
|
|
||||||
if (!sale.id)
|
if (!sale.id)
|
||||||
return this.addSale(sale);
|
return this.addSale(sale);
|
||||||
|
@ -443,37 +395,30 @@ class Controller extends Section {
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Updates a sale quantity
|
* Changes a sale quantity
|
||||||
*/
|
*/
|
||||||
updateQuantity(sale) {
|
updateQuantity(sale) {
|
||||||
const data = {quantity: parseInt(sale.quantity)};
|
const data = {quantity: sale.quantity};
|
||||||
const query = `Sales/${sale.id}/updateQuantity`;
|
this.$http.post(`Sales/${sale.id}/updateQuantity`, data).then(() => {
|
||||||
this.$http.post(query, data).then(() => {
|
this.refreshTotal();
|
||||||
this.vnApp.showSuccess(this.$translate.instant('Data saved!'));
|
this.vnApp.showSuccess(this.$t('Data saved!'));
|
||||||
}).catch(e => {
|
}).catch(e => {
|
||||||
this.$.model.refresh();
|
this.$.model.refresh();
|
||||||
throw e;
|
throw e;
|
||||||
}).finally(() => {
|
}).finally(() => this.resetChanges());
|
||||||
if (this.newInstances().length === 0)
|
|
||||||
this.$.watcher.updateOriginalData();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Updates a sale concept
|
* Changes a sale concept
|
||||||
*/
|
*/
|
||||||
updateConcept(sale) {
|
updateConcept(sale) {
|
||||||
const data = {newConcept: sale.concept};
|
const data = {newConcept: sale.concept};
|
||||||
const query = `Sales/${sale.id}/updateConcept`;
|
this.$http.post(`Sales/${sale.id}/updateConcept`, data).then(() => {
|
||||||
this.$http.post(query, data).then(() => {
|
this.vnApp.showSuccess(this.$t('Data saved!'));
|
||||||
this.vnApp.showSuccess(this.$translate.instant('Data saved!'));
|
|
||||||
}).catch(e => {
|
}).catch(e => {
|
||||||
this.$.model.refresh();
|
this.$.model.refresh();
|
||||||
throw e;
|
throw e;
|
||||||
}).finally(() => {
|
}).finally(() => this.resetChanges());
|
||||||
if (this.newInstances().length === 0)
|
|
||||||
this.$.watcher.updateOriginalData();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -489,7 +434,6 @@ class Controller extends Section {
|
||||||
if (!res.data) return;
|
if (!res.data) return;
|
||||||
|
|
||||||
const newSale = res.data;
|
const newSale = res.data;
|
||||||
|
|
||||||
sale.id = newSale.id;
|
sale.id = newSale.id;
|
||||||
sale.image = newSale.item.image;
|
sale.image = newSale.item.image;
|
||||||
sale.subName = newSale.item.subName;
|
sale.subName = newSale.item.subName;
|
||||||
|
@ -499,37 +443,29 @@ class Controller extends Section {
|
||||||
sale.price = newSale.price;
|
sale.price = newSale.price;
|
||||||
sale.item = newSale.item;
|
sale.item = newSale.item;
|
||||||
|
|
||||||
this.vnApp.showSuccess(this.$translate.instant('Data saved!'));
|
this.refreshTotal();
|
||||||
}).finally(() => {
|
this.vnApp.showSuccess(this.$t('Data saved!'));
|
||||||
if (this.newInstances().length === 0)
|
}).finally(() => this.resetChanges());
|
||||||
this.$.watcher.updateOriginalData();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
isTicketEditable() {
|
isTicketEditable() {
|
||||||
this.$http.get(`Tickets/${this.$state.params.id}/isEditable`).then(res => {
|
this.$http.get(`Tickets/${this.$params.id}/isEditable`)
|
||||||
this.isEditable = res.data;
|
.then(res => this.isEditable = res.data);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
isTicketLocked() {
|
isTicketLocked() {
|
||||||
this.$http.get(`Tickets/${this.$state.params.id}/isLocked`).then(res => {
|
this.$http.get(`Tickets/${this.$params.id}/isLocked`)
|
||||||
this.isLocked = res.data;
|
.then(res => this.isLocked = res.data);
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
hasOneSaleSelected() {
|
|
||||||
if (this.totalCheckedLines() === 1)
|
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
calculateSalePrice() {
|
calculateSalePrice() {
|
||||||
const sale = this.checkedLines()[0];
|
const sale = this.selectedValidSales()[0];
|
||||||
|
if (!sale) return;
|
||||||
const query = `Sales/${sale.id}/recalculatePrice`;
|
const query = `Sales/${sale.id}/recalculatePrice`;
|
||||||
this.$http.post(query).then(res => {
|
this.$http.post(query).then(() => {
|
||||||
this.vnApp.showSuccess(this.$translate.instant('Data saved!'));
|
this.vnApp.showSuccess(this.$t('Data saved!'));
|
||||||
this.$.model.refresh();
|
this.$.model.refresh();
|
||||||
|
this.refreshTotal();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,728 @@
|
||||||
|
import './index.js';
|
||||||
|
import watcher from 'core/mocks/watcher';
|
||||||
|
import crudModel from 'core/mocks/crud-model';
|
||||||
|
|
||||||
|
describe('Ticket', () => {
|
||||||
|
describe('Component vnTicketSale', () => {
|
||||||
|
let controller;
|
||||||
|
let $scope;
|
||||||
|
let $state;
|
||||||
|
let $httpBackend;
|
||||||
|
|
||||||
|
beforeEach(ngModule('ticket'));
|
||||||
|
|
||||||
|
beforeEach(angular.mock.inject(($componentController, $rootScope, _$state_, _$httpBackend_) => {
|
||||||
|
const ticket = {
|
||||||
|
id: 1,
|
||||||
|
clientFk: 101,
|
||||||
|
shipped: 1,
|
||||||
|
created: new Date(),
|
||||||
|
client: {salesPersonFk: 1},
|
||||||
|
address: {mobile: 111111111}
|
||||||
|
};
|
||||||
|
const sales = [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
concept: 'Item 1',
|
||||||
|
quantity: 5,
|
||||||
|
price: 23.5,
|
||||||
|
discount: 0,
|
||||||
|
}, {
|
||||||
|
id: 4,
|
||||||
|
concept: 'Item 2',
|
||||||
|
quantity: 20,
|
||||||
|
price: 5.5,
|
||||||
|
discount: 0,
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
$state = _$state_;
|
||||||
|
$scope = $rootScope.$new();
|
||||||
|
$scope.watcher = watcher;
|
||||||
|
$scope.sms = {open: () => {}};
|
||||||
|
$scope.ticket = ticket;
|
||||||
|
$scope.model = crudModel;
|
||||||
|
$httpBackend = _$httpBackend_;
|
||||||
|
Object.defineProperties($state.params, {
|
||||||
|
id: {
|
||||||
|
value: ticket.id,
|
||||||
|
writable: true
|
||||||
|
},
|
||||||
|
go: {
|
||||||
|
value: () => {},
|
||||||
|
writable: false
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const $element = angular.element('<vn-ticket-sale></vn-ticket-sale>');
|
||||||
|
controller = $componentController('vnTicketSale', {$element, $scope});
|
||||||
|
controller.card = {reload: () => {}};
|
||||||
|
controller._ticket = ticket;
|
||||||
|
controller._sales = sales;
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe('ticket() setter', () => {
|
||||||
|
it('should set the ticket data an then call the isTicketEditable() and isTicketLocked() methods', () => {
|
||||||
|
jest.spyOn(controller, 'isTicketEditable').mockReturnThis();
|
||||||
|
jest.spyOn(controller, 'isTicketLocked').mockReturnThis();
|
||||||
|
|
||||||
|
controller.ticket = {id: 1};
|
||||||
|
|
||||||
|
expect(controller.isTicketEditable).toHaveBeenCalledWith();
|
||||||
|
expect(controller.isTicketLocked).toHaveBeenCalledWith();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('sales() setter', () => {
|
||||||
|
it('should set the sales data an then call the refreshTotal() method', () => {
|
||||||
|
jest.spyOn(controller, 'refreshTotal').mockReturnThis();
|
||||||
|
|
||||||
|
controller.sales = [{id: 1}];
|
||||||
|
|
||||||
|
expect(controller.refreshTotal).toHaveBeenCalledWith();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getSubTotal()', () => {
|
||||||
|
it('should make an HTTP GET query and then set the subtotal property', () => {
|
||||||
|
const expectedAmount = 128;
|
||||||
|
|
||||||
|
$httpBackend.expect('GET', 'Tickets/1/subtotal').respond(200, expectedAmount);
|
||||||
|
controller.getSubTotal();
|
||||||
|
$httpBackend.flush();
|
||||||
|
|
||||||
|
expect(controller.subtotal).toEqual(expectedAmount);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getSaleTotal()', () => {
|
||||||
|
it('should return the sale total amount', () => {
|
||||||
|
const sale = {
|
||||||
|
quantity: 10,
|
||||||
|
price: 2,
|
||||||
|
discount: 10
|
||||||
|
};
|
||||||
|
|
||||||
|
const expectedAmount = 18;
|
||||||
|
const result = controller.getSaleTotal(sale);
|
||||||
|
|
||||||
|
expect(result).toEqual(expectedAmount);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getMana()', () => {
|
||||||
|
it('should make an HTTP GET query and return the worker mana', () => {
|
||||||
|
controller.edit = {};
|
||||||
|
const expectedAmount = 250;
|
||||||
|
|
||||||
|
$httpBackend.expect('GET', 'Tickets/1/getSalesPersonMana').respond(200, expectedAmount);
|
||||||
|
controller.getMana();
|
||||||
|
$httpBackend.flush();
|
||||||
|
|
||||||
|
expect(controller.edit.mana).toEqual(expectedAmount);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getVat()', () => {
|
||||||
|
it('should make an HTTP GET query and return the ticket VAT', () => {
|
||||||
|
controller.edit = {};
|
||||||
|
const expectedAmount = 67;
|
||||||
|
|
||||||
|
$httpBackend.expect('GET', 'Tickets/1/getVAT').respond(200, expectedAmount);
|
||||||
|
controller.getVat();
|
||||||
|
$httpBackend.flush();
|
||||||
|
|
||||||
|
expect(controller.VAT).toEqual(expectedAmount);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('selectedSales()', () => {
|
||||||
|
it('should return a list of selected sales', () => {
|
||||||
|
controller.sales[1].checked = true;
|
||||||
|
|
||||||
|
const expectedSaleId = 4;
|
||||||
|
const result = controller.selectedSales();
|
||||||
|
const firstSelectedSale = result[0];
|
||||||
|
|
||||||
|
expect(result.length).toEqual(1);
|
||||||
|
expect(firstSelectedSale.id).toEqual(expectedSaleId);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('selectedValidSales()', () => {
|
||||||
|
it('should return a list of selected sales having a sale id', () => {
|
||||||
|
const newEmptySale = {quantity: 10, checked: true};
|
||||||
|
controller.sales.push(newEmptySale);
|
||||||
|
controller.sales[0].checked = true;
|
||||||
|
|
||||||
|
const expectedSaleId = 1;
|
||||||
|
const result = controller.selectedValidSales();
|
||||||
|
const firstSelectedSale = result[0];
|
||||||
|
|
||||||
|
expect(result.length).toEqual(1);
|
||||||
|
expect(firstSelectedSale.id).toEqual(expectedSaleId);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('selectedSalesCount()', () => {
|
||||||
|
it('should return the number of selected sales', () => {
|
||||||
|
controller.sales[0].checked = true;
|
||||||
|
|
||||||
|
const result = controller.selectedSalesCount();
|
||||||
|
|
||||||
|
expect(result).toEqual(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('hasSelectedSales()', () => {
|
||||||
|
it('should return truthy if atleast one sale is selected', () => {
|
||||||
|
controller.sales[0].checked = true;
|
||||||
|
|
||||||
|
const result = controller.hasSelectedSales();
|
||||||
|
|
||||||
|
expect(result).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('hasOneSaleSelected()', () => {
|
||||||
|
it('should return truthy if just one sale is selected', () => {
|
||||||
|
controller.sales[0].checked = true;
|
||||||
|
|
||||||
|
const result = controller.hasOneSaleSelected();
|
||||||
|
|
||||||
|
expect(result).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return falsy if more than one sale is selected', () => {
|
||||||
|
controller.sales[0].checked = true;
|
||||||
|
controller.sales[1].checked = true;
|
||||||
|
|
||||||
|
const result = controller.hasOneSaleSelected();
|
||||||
|
|
||||||
|
expect(result).toBeFalsy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('newInstances()', () => {
|
||||||
|
it(`should return a list of sales that doesn't have an id`, () => {
|
||||||
|
const newEmptySale = {quantity: 10, checked: true};
|
||||||
|
controller.sales.push(newEmptySale);
|
||||||
|
|
||||||
|
const result = controller.newInstances();
|
||||||
|
const firstNewSale = result[0];
|
||||||
|
|
||||||
|
expect(result.length).toEqual(1);
|
||||||
|
expect(firstNewSale.id).toBeUndefined();
|
||||||
|
expect(firstNewSale.quantity).toEqual(10);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('resetChanges()', () => {
|
||||||
|
it(`should not call the watcher updateOriginalData() method`, () => {
|
||||||
|
jest.spyOn(controller.$.watcher, 'updateOriginalData').mockReturnThis();
|
||||||
|
|
||||||
|
const newEmptySale = {quantity: 10};
|
||||||
|
controller.sales.push(newEmptySale);
|
||||||
|
controller.resetChanges();
|
||||||
|
|
||||||
|
expect(controller.$.watcher.updateOriginalData).not.toHaveBeenCalledWith();
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`should call the watcher updateOriginalData() method`, () => {
|
||||||
|
jest.spyOn(controller.$.watcher, 'updateOriginalData').mockReturnThis();
|
||||||
|
|
||||||
|
controller.resetChanges();
|
||||||
|
|
||||||
|
expect(controller.$.watcher.updateOriginalData).toHaveBeenCalledWith();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('changeState()', () => {
|
||||||
|
it('should make an HTTP post query, then call the showSuccess(), reload() and resetChanges() methods', () => {
|
||||||
|
jest.spyOn(controller.card, 'reload').mockReturnThis();
|
||||||
|
jest.spyOn(controller.vnApp, 'showSuccess').mockReturnThis();
|
||||||
|
jest.spyOn(controller, 'resetChanges').mockReturnThis();
|
||||||
|
|
||||||
|
const expectedParams = {ticketFk: 1, code: 'OK'};
|
||||||
|
$httpBackend.expect('POST', `TicketTrackings/changeState`, expectedParams).respond(200);
|
||||||
|
controller.changeState('OK');
|
||||||
|
$httpBackend.flush();
|
||||||
|
|
||||||
|
expect(controller.card.reload).toHaveBeenCalledWith();
|
||||||
|
expect(controller.vnApp.showSuccess).toHaveBeenCalledWith('Data saved!');
|
||||||
|
expect(controller.resetChanges).toHaveBeenCalledWith();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('removeSales()', () => {
|
||||||
|
it('should make an HTTP post query, then call the showSuccess(), removeSelectedSales() and resetChanges() methods', () => {
|
||||||
|
jest.spyOn(controller.vnApp, 'showSuccess').mockReturnThis();
|
||||||
|
jest.spyOn(controller, 'removeSelectedSales').mockReturnThis();
|
||||||
|
jest.spyOn(controller, 'resetChanges').mockReturnThis();
|
||||||
|
|
||||||
|
const firstSale = controller.sales[0];
|
||||||
|
firstSale.checked = true;
|
||||||
|
const expectedParams = {sales: [firstSale], ticketId: 1};
|
||||||
|
$httpBackend.expect('POST', `Sales/deleteSales`, expectedParams).respond(200);
|
||||||
|
controller.removeSales();
|
||||||
|
$httpBackend.flush();
|
||||||
|
|
||||||
|
expect(controller.removeSelectedSales).toHaveBeenCalledWith();
|
||||||
|
expect(controller.vnApp.showSuccess).toHaveBeenCalledWith('Data saved!');
|
||||||
|
expect(controller.resetChanges).toHaveBeenCalledWith();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('removeSelectedSales()', () => {
|
||||||
|
it('should remove the selected sales from the controller sale property', () => {
|
||||||
|
jest.spyOn(controller, 'refreshTotal').mockReturnThis();
|
||||||
|
jest.spyOn(controller, 'resetChanges').mockReturnThis();
|
||||||
|
|
||||||
|
const firstSale = controller.sales[0];
|
||||||
|
firstSale.checked = true;
|
||||||
|
|
||||||
|
controller.removeSelectedSales();
|
||||||
|
|
||||||
|
const lastSale = controller.sales[0];
|
||||||
|
|
||||||
|
expect(controller.sales.length).toEqual(1);
|
||||||
|
expect(lastSale.id).toEqual(4);
|
||||||
|
expect(controller.refreshTotal).toHaveBeenCalledWith();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('createClaim()', () => {
|
||||||
|
it('should perform a query and call windows open', () => {
|
||||||
|
jest.spyOn(controller, 'resetChanges').mockReturnThis();
|
||||||
|
jest.spyOn(controller.$state, 'go').mockReturnThis();
|
||||||
|
|
||||||
|
const newEmptySale = {quantity: 10};
|
||||||
|
controller.sales.push(newEmptySale);
|
||||||
|
const firstSale = controller.sales[0];
|
||||||
|
firstSale.checked = true;
|
||||||
|
|
||||||
|
const expectedParams = {ticketId: 1, sales: [firstSale]};
|
||||||
|
$httpBackend.expect('POST', `Claims/createFromSales`, expectedParams).respond(200, {id: 1});
|
||||||
|
controller.createClaim();
|
||||||
|
$httpBackend.flush();
|
||||||
|
|
||||||
|
expect(controller.resetChanges).toHaveBeenCalledWith();
|
||||||
|
expect(controller.$state.go).toHaveBeenCalledWith('claim.card.basicData', {id: 1});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('setTransferParams()', () => {
|
||||||
|
it('should define the transfer object on the controller and its default properties', () => {
|
||||||
|
const firstSale = controller.sales[0];
|
||||||
|
firstSale.checked = true;
|
||||||
|
const expectedResponse = [firstSale];
|
||||||
|
|
||||||
|
$httpBackend.expect('GET', `clients/101/lastActiveTickets?ticketId=1`).respond(expectedResponse);
|
||||||
|
controller.setTransferParams();
|
||||||
|
$httpBackend.flush();
|
||||||
|
|
||||||
|
const lastActiveTickets = controller.transfer.lastActiveTickets;
|
||||||
|
|
||||||
|
expect(controller.transfer).toBeDefined();
|
||||||
|
expect(lastActiveTickets).toBeDefined();
|
||||||
|
expect(lastActiveTickets[0].id).toEqual(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('transferSales()', () => {
|
||||||
|
it('should transfer sales to a ticket and then call to the $state go() method', () => {
|
||||||
|
jest.spyOn(controller.$state, 'go').mockReturnThis();
|
||||||
|
|
||||||
|
controller.transfer = {
|
||||||
|
sales: [{id: 1, itemFk: 1}, {id: 2, itemFk: 4}]
|
||||||
|
};
|
||||||
|
|
||||||
|
const ticketIdToTransfer = 13;
|
||||||
|
const expectedResponse = {id: ticketIdToTransfer};
|
||||||
|
const params = {
|
||||||
|
ticketId: 13,
|
||||||
|
sales: controller.transfer.sales
|
||||||
|
};
|
||||||
|
|
||||||
|
$httpBackend.expect('POST', `tickets/1/transferSales`, params).respond(expectedResponse);
|
||||||
|
controller.transferSales(ticketIdToTransfer);
|
||||||
|
$httpBackend.flush();
|
||||||
|
|
||||||
|
expect(controller.$state.go).toHaveBeenCalledWith('ticket.card.sale', {id: ticketIdToTransfer});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('updatePrice()', () => {
|
||||||
|
it('should make an HTTP POST query, update the sale price and then call to the resetChanges() method', () => {
|
||||||
|
jest.spyOn(controller, 'refreshTotal').mockReturnThis();
|
||||||
|
jest.spyOn(controller.vnApp, 'showSuccess').mockReturnThis();
|
||||||
|
jest.spyOn(controller, 'resetChanges').mockReturnThis();
|
||||||
|
|
||||||
|
const selectedSale = controller.sales[0];
|
||||||
|
selectedSale.checked = true;
|
||||||
|
controller.$.editPricePopover = {hide: jest.fn()};
|
||||||
|
controller.edit = {
|
||||||
|
price: 2,
|
||||||
|
sale: selectedSale
|
||||||
|
};
|
||||||
|
const expectedParams = {newPrice: 2};
|
||||||
|
$httpBackend.expect('POST', `Sales/1/updatePrice`, expectedParams).respond(200, {price: 2});
|
||||||
|
controller.updatePrice();
|
||||||
|
$httpBackend.flush();
|
||||||
|
|
||||||
|
expect(selectedSale.price).toEqual(2);
|
||||||
|
expect(controller.refreshTotal).toHaveBeenCalledWith();
|
||||||
|
expect(controller.vnApp.showSuccess).toHaveBeenCalledWith('Data saved!');
|
||||||
|
expect(controller.$.editPricePopover.hide).toHaveBeenCalledWith();
|
||||||
|
expect(controller.resetChanges).toHaveBeenCalledWith();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('changeDiscount()', () => {
|
||||||
|
it('should call to the updateDiscount() method and then to the editDiscount hide() method', () => {
|
||||||
|
jest.spyOn(controller, 'updateDiscount').mockReturnThis();
|
||||||
|
|
||||||
|
const selectedSale = controller.sales[0];
|
||||||
|
selectedSale.checked = true;
|
||||||
|
const expectedSale = selectedSale;
|
||||||
|
controller.$.editDiscount = {hide: jest.fn()};
|
||||||
|
controller.edit = {
|
||||||
|
discount: 10,
|
||||||
|
sale: selectedSale
|
||||||
|
};
|
||||||
|
|
||||||
|
controller.changeDiscount();
|
||||||
|
|
||||||
|
expect(controller.updateDiscount).toHaveBeenCalledWith([expectedSale]);
|
||||||
|
expect(controller.$.editDiscount.hide).toHaveBeenCalledWith();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('changeMultipleDiscount()', () => {
|
||||||
|
it('should call to the updateDiscount() method and then to the editDiscountDialog hide() method', () => {
|
||||||
|
jest.spyOn(controller, 'updateDiscount').mockReturnThis();
|
||||||
|
|
||||||
|
const firstSelectedSale = controller.sales[0];
|
||||||
|
firstSelectedSale.checked = true;
|
||||||
|
|
||||||
|
const secondSelectedSale = controller.sales[1];
|
||||||
|
secondSelectedSale.checked = true;
|
||||||
|
|
||||||
|
const expectedSales = [firstSelectedSale, secondSelectedSale];
|
||||||
|
controller.$.editDiscountDialog = {hide: jest.fn()};
|
||||||
|
controller.edit = {
|
||||||
|
discount: 10,
|
||||||
|
sales: expectedSales
|
||||||
|
};
|
||||||
|
|
||||||
|
controller.changeMultipleDiscount();
|
||||||
|
|
||||||
|
expect(controller.updateDiscount).toHaveBeenCalledWith(expectedSales);
|
||||||
|
expect(controller.$.editDiscountDialog.hide).toHaveBeenCalledWith();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not call to the updateDiscount() method and then to the editDiscountDialog hide() method', () => {
|
||||||
|
jest.spyOn(controller, 'updateDiscount').mockReturnThis();
|
||||||
|
|
||||||
|
const firstSelectedSale = controller.sales[0];
|
||||||
|
firstSelectedSale.checked = true;
|
||||||
|
firstSelectedSale.discount = 10;
|
||||||
|
|
||||||
|
const secondSelectedSale = controller.sales[1];
|
||||||
|
secondSelectedSale.checked = true;
|
||||||
|
secondSelectedSale.discount = 10;
|
||||||
|
|
||||||
|
const expectedSales = [firstSelectedSale, secondSelectedSale];
|
||||||
|
controller.$.editDiscountDialog = {hide: jest.fn()};
|
||||||
|
controller.edit = {
|
||||||
|
discount: 10,
|
||||||
|
sales: expectedSales
|
||||||
|
};
|
||||||
|
|
||||||
|
controller.changeMultipleDiscount();
|
||||||
|
|
||||||
|
expect(controller.updateDiscount).not.toHaveBeenCalledWith(expectedSales);
|
||||||
|
expect(controller.$.editDiscountDialog.hide).toHaveBeenCalledWith();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('updateDiscount()', () => {
|
||||||
|
it('should make an HTTP POST query, update the sales discount and then call to the resetChanges() method', () => {
|
||||||
|
jest.spyOn(controller, 'resetChanges').mockReturnThis();
|
||||||
|
jest.spyOn(controller.vnApp, 'showSuccess').mockReturnThis();
|
||||||
|
jest.spyOn(controller, 'refreshTotal').mockReturnThis();
|
||||||
|
|
||||||
|
const expectedDiscount = 10;
|
||||||
|
const firstSelectedSale = controller.sales[0];
|
||||||
|
firstSelectedSale.checked = true;
|
||||||
|
|
||||||
|
const secondSelectedSale = controller.sales[1];
|
||||||
|
secondSelectedSale.checked = true;
|
||||||
|
|
||||||
|
controller.edit = {
|
||||||
|
discount: expectedDiscount
|
||||||
|
};
|
||||||
|
|
||||||
|
const expectedSales = [firstSelectedSale, secondSelectedSale];
|
||||||
|
const expectedSaleIds = [firstSelectedSale.id, secondSelectedSale.id];
|
||||||
|
const expectedParams = {salesIds: expectedSaleIds, newDiscount: expectedDiscount};
|
||||||
|
$httpBackend.expect('POST', `Tickets/1/updateDiscount`, expectedParams).respond(200, {discount: 10});
|
||||||
|
controller.updateDiscount(expectedSales);
|
||||||
|
$httpBackend.flush();
|
||||||
|
|
||||||
|
expect(firstSelectedSale.discount).toEqual(expectedDiscount);
|
||||||
|
expect(secondSelectedSale.discount).toEqual(expectedDiscount);
|
||||||
|
expect(controller.refreshTotal).toHaveBeenCalledWith();
|
||||||
|
expect(controller.vnApp.showSuccess).toHaveBeenCalledWith('Data saved!');
|
||||||
|
expect(controller.resetChanges).toHaveBeenCalledWith();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getNewPrice()', () => {
|
||||||
|
it('should return the total price simulation from a price change', () => {
|
||||||
|
const selectedSale = controller.sales[0];
|
||||||
|
selectedSale.checked = true;
|
||||||
|
controller.edit = {
|
||||||
|
price: 2,
|
||||||
|
sale: selectedSale
|
||||||
|
};
|
||||||
|
|
||||||
|
const expectedAmount = 10;
|
||||||
|
const result = controller.getNewPrice();
|
||||||
|
|
||||||
|
expect(result).toEqual(expectedAmount);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return the total price simulation from a discount change', () => {
|
||||||
|
const selectedSale = controller.sales[0];
|
||||||
|
selectedSale.checked = true;
|
||||||
|
controller.edit = {
|
||||||
|
discount: 10,
|
||||||
|
sale: selectedSale
|
||||||
|
};
|
||||||
|
|
||||||
|
const expectedAmount = 105.75;
|
||||||
|
const result = controller.getNewPrice();
|
||||||
|
|
||||||
|
expect(result).toEqual(expectedAmount);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('hasReserves()', () => {
|
||||||
|
it('should return true for any sale marked as reserved', () => {
|
||||||
|
const selectedSale = controller.sales[0];
|
||||||
|
selectedSale.reserved = true;
|
||||||
|
|
||||||
|
const result = controller.hasReserves();
|
||||||
|
|
||||||
|
expect(result).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('unmarkAsReserved()', () => {
|
||||||
|
it('should call setReserved with false', () => {
|
||||||
|
jest.spyOn(controller, 'setReserved');
|
||||||
|
|
||||||
|
controller.unmarkAsReserved(false);
|
||||||
|
|
||||||
|
expect(controller.setReserved).toHaveBeenCalledWith(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('markAsReserved()', () => {
|
||||||
|
it('should call setReserved with true', () => {
|
||||||
|
jest.spyOn(controller, 'setReserved');
|
||||||
|
|
||||||
|
controller.markAsReserved(true);
|
||||||
|
|
||||||
|
expect(controller.setReserved).toHaveBeenCalledWith(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('setReserved()', () => {
|
||||||
|
it('should call getCheckedLines, $.index.accept and make a query ', () => {
|
||||||
|
const selectedSale = controller.sales[0];
|
||||||
|
selectedSale.checked = true;
|
||||||
|
const expectedParams = {
|
||||||
|
sales: [selectedSale],
|
||||||
|
ticketId: 1,
|
||||||
|
reserved: false
|
||||||
|
};
|
||||||
|
|
||||||
|
$httpBackend.expectPOST(`Sales/reserve`, expectedParams).respond();
|
||||||
|
controller.unmarkAsReserved(false);
|
||||||
|
$httpBackend.flush();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('newOrderFromTicket()', () => {
|
||||||
|
it('should make an HTTP post query and then open the new order on a new tab', () => {
|
||||||
|
const expectedParams = {ticketFk: 1};
|
||||||
|
const expectedResponse = {id: 123};
|
||||||
|
|
||||||
|
window.open = jasmine.createSpy('open');
|
||||||
|
controller.$state.href = jasmine.createSpy('href')
|
||||||
|
.and.returnValue('/somePath');
|
||||||
|
|
||||||
|
$httpBackend.expect('POST', `Orders/newFromTicket`, expectedParams).respond(expectedResponse);
|
||||||
|
controller.newOrderFromTicket();
|
||||||
|
$httpBackend.flush();
|
||||||
|
|
||||||
|
expect(window.open).toHaveBeenCalledWith('/somePath', '_blank');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('showSMSDialog()', () => {
|
||||||
|
it('should open an SMS dialog with specified data', () => {
|
||||||
|
jest.spyOn(controller.$.sms, 'open');
|
||||||
|
|
||||||
|
const selectedSale = controller.sales[0];
|
||||||
|
selectedSale.checked = true;
|
||||||
|
controller.showSMSDialog();
|
||||||
|
|
||||||
|
expect(controller.$.sms.open).toHaveBeenCalledWith();
|
||||||
|
expect(controller.newSMS.destination).toEqual(111111111);
|
||||||
|
expect(controller.newSMS.message).not.toEqual('');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('changeQuantity()', () => {
|
||||||
|
it('should not call addSale() or updateQuantity() methods', () => {
|
||||||
|
jest.spyOn(controller, 'addSale');
|
||||||
|
jest.spyOn(controller, 'updateQuantity');
|
||||||
|
|
||||||
|
const sale = {itemFk: 4};
|
||||||
|
controller.changeQuantity(sale);
|
||||||
|
|
||||||
|
expect(controller.addSale).not.toHaveBeenCalled();
|
||||||
|
expect(controller.updateQuantity).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call addSale() method', () => {
|
||||||
|
jest.spyOn(controller, 'addSale');
|
||||||
|
|
||||||
|
const sale = {itemFk: 4, quantity: 5};
|
||||||
|
controller.changeQuantity(sale);
|
||||||
|
|
||||||
|
expect(controller.addSale).toHaveBeenCalledWith(sale);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call updateQuantity() method', () => {
|
||||||
|
jest.spyOn(controller, 'addSale');
|
||||||
|
jest.spyOn(controller, 'updateQuantity');
|
||||||
|
|
||||||
|
const sale = {id: 1, itemFk: 4, quantity: 5};
|
||||||
|
controller.changeQuantity(sale);
|
||||||
|
|
||||||
|
expect(controller.addSale).not.toHaveBeenCalled();
|
||||||
|
expect(controller.updateQuantity).toHaveBeenCalledWith(sale);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('updateQuantity()', () => {
|
||||||
|
it('should make a POST query saving sale quantity', () => {
|
||||||
|
jest.spyOn(controller, 'refreshTotal').mockReturnThis();
|
||||||
|
jest.spyOn(controller, 'resetChanges').mockReturnThis();
|
||||||
|
|
||||||
|
const selectedSale = controller.sales[0];
|
||||||
|
selectedSale.checked = true;
|
||||||
|
selectedSale.quantity = 10;
|
||||||
|
|
||||||
|
const expectedParams = {quantity: 10};
|
||||||
|
$httpBackend.expect('POST', `Sales/1/updateQuantity`, expectedParams).respond();
|
||||||
|
controller.updateQuantity(selectedSale);
|
||||||
|
$httpBackend.flush();
|
||||||
|
|
||||||
|
expect(controller.refreshTotal).toHaveBeenCalledWith();
|
||||||
|
expect(controller.resetChanges).toHaveBeenCalledWith();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('updateConcept()', () => {
|
||||||
|
it('should make a POST query saving sale concept', () => {
|
||||||
|
jest.spyOn(controller, 'resetChanges').mockReturnThis();
|
||||||
|
|
||||||
|
const selectedSale = controller.sales[0];
|
||||||
|
selectedSale.checked = true;
|
||||||
|
selectedSale.concept = 'My new weapon';
|
||||||
|
|
||||||
|
const expectedParams = {newConcept: 'My new weapon'};
|
||||||
|
$httpBackend.expect('POST', `Sales/1/updateConcept`, expectedParams).respond();
|
||||||
|
controller.updateConcept(selectedSale);
|
||||||
|
$httpBackend.flush();
|
||||||
|
|
||||||
|
expect(controller.resetChanges).toHaveBeenCalledWith();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('addSale()', () => {
|
||||||
|
it('should make a POST query adding a new sale', () => {
|
||||||
|
jest.spyOn(controller.vnApp, 'showSuccess').mockReturnThis();
|
||||||
|
jest.spyOn(controller, 'refreshTotal').mockReturnThis();
|
||||||
|
jest.spyOn(controller, 'resetChanges').mockReturnThis();
|
||||||
|
|
||||||
|
const newSale = {itemFk: 4, quantity: 10};
|
||||||
|
const expectedParams = {itemId: 4, quantity: 10};
|
||||||
|
const expectedResult = {
|
||||||
|
id: 30,
|
||||||
|
quantity: 10,
|
||||||
|
discount: 0,
|
||||||
|
price: 0,
|
||||||
|
itemFk: 4,
|
||||||
|
item: {
|
||||||
|
subName: 'Item subName',
|
||||||
|
image: '30.png'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
$httpBackend.expect('POST', `tickets/1/addSale`, expectedParams).respond(expectedResult);
|
||||||
|
controller.addSale(newSale);
|
||||||
|
$httpBackend.flush();
|
||||||
|
|
||||||
|
expect(controller.vnApp.showSuccess).toHaveBeenCalledWith('Data saved!');
|
||||||
|
expect(controller.refreshTotal).toHaveBeenCalledWith();
|
||||||
|
expect(controller.resetChanges).toHaveBeenCalledWith();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('isTicketEditable()', () => {
|
||||||
|
it('should make a HTTP GET query and set the isEditable property on the controller', () => {
|
||||||
|
$httpBackend.expect('GET', `Tickets/1/isEditable`).respond(200, true);
|
||||||
|
controller.isTicketEditable();
|
||||||
|
$httpBackend.flush();
|
||||||
|
|
||||||
|
expect(controller.isEditable).toBeDefined();
|
||||||
|
expect(controller.isEditable).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('isTicketLocked()', () => {
|
||||||
|
it('should make a HTTP GET query and set the isLocked property on the controller', () => {
|
||||||
|
$httpBackend.expect('GET', `Tickets/1/isLocked`).respond(200, false);
|
||||||
|
controller.isTicketLocked();
|
||||||
|
$httpBackend.flush();
|
||||||
|
|
||||||
|
expect(controller.isLocked).toBeDefined();
|
||||||
|
expect(controller.isLocked).toBeFalsy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('calculateSalePrice()', () => {
|
||||||
|
it('should make an HTTP post query ', () => {
|
||||||
|
jest.spyOn(controller.vnApp, 'showSuccess').mockReturnThis();
|
||||||
|
jest.spyOn(controller.$.model, 'refresh').mockReturnThis();
|
||||||
|
jest.spyOn(controller, 'refreshTotal').mockReturnThis();
|
||||||
|
|
||||||
|
const selectedSale = controller.sales[0];
|
||||||
|
selectedSale.checked = true;
|
||||||
|
|
||||||
|
$httpBackend.expect('POST', `Sales/1/recalculatePrice`).respond(200);
|
||||||
|
controller.calculateSalePrice();
|
||||||
|
$httpBackend.flush();
|
||||||
|
|
||||||
|
expect(controller.vnApp.showSuccess).toHaveBeenCalledWith('Data saved!');
|
||||||
|
expect(controller.$.model.refresh).toHaveBeenCalledWith();
|
||||||
|
expect(controller.refreshTotal).toHaveBeenCalledWith();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -1,5 +1,6 @@
|
||||||
New price: Nuevo precio
|
New price: Nuevo precio
|
||||||
Add item: Añadir artículo
|
Add item: Añadir artículo
|
||||||
|
Add item to basket: Añadir artículo a la cesta
|
||||||
Add turn: Añadir a turno
|
Add turn: Añadir a turno
|
||||||
Delete ticket: Eliminar ticket
|
Delete ticket: Eliminar ticket
|
||||||
Mark as reserved: Marcar como reservado
|
Mark as reserved: Marcar como reservado
|
||||||
|
|
|
@ -1,87 +0,0 @@
|
||||||
import '../editDiscount.js';
|
|
||||||
|
|
||||||
describe('Ticket', () => {
|
|
||||||
describe('Component vnTicketSaleEditDiscount', () => {
|
|
||||||
let controller;
|
|
||||||
let $httpBackend;
|
|
||||||
let $state;
|
|
||||||
let $scope;
|
|
||||||
|
|
||||||
beforeEach(ngModule('ticket'));
|
|
||||||
|
|
||||||
beforeEach(angular.mock.inject(($componentController, _$state_, _$httpBackend_, $rootScope) => {
|
|
||||||
$httpBackend = _$httpBackend_;
|
|
||||||
$scope = $rootScope.$new();
|
|
||||||
$scope.index = {model: {instances: [{id: 1}, {id: 2}]}, accept: () => {
|
|
||||||
return {
|
|
||||||
then: () => {}
|
|
||||||
};
|
|
||||||
}};
|
|
||||||
$state = _$state_;
|
|
||||||
$state.params.id = 11;
|
|
||||||
const $element = angular.element('<vn-ticket-sale-edit-discount></vn-ticket-sale-edit-discount>');
|
|
||||||
controller = $componentController('vnTicketSaleEditDiscount', {$element, $scope});
|
|
||||||
controller._edit = [{id: 3}];
|
|
||||||
controller.onHide = () => {};
|
|
||||||
}));
|
|
||||||
|
|
||||||
describe('edit() setter', () => {
|
|
||||||
it('should set _edit value and call setNewDiscount', () => {
|
|
||||||
jest.spyOn(controller, 'setNewDiscount');
|
|
||||||
controller.edit = {id: 1};
|
|
||||||
|
|
||||||
expect(controller.edit).toEqual({id: 1});
|
|
||||||
expect(controller.setNewDiscount).toHaveBeenCalledWith();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('bulk() setter', () => {
|
|
||||||
it('should set _bulk value and call setNewDiscount', () => {
|
|
||||||
jest.spyOn(controller, 'setNewDiscount');
|
|
||||||
controller.bulk = true;
|
|
||||||
|
|
||||||
expect(controller.bulk).toEqual(true);
|
|
||||||
expect(controller.setNewDiscount).toHaveBeenCalledWith();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('setNewDiscount()', () => {
|
|
||||||
it('should set NewDiscount to edit[0].discount value if it doesnt exists', () => {
|
|
||||||
controller.edit = [{discount: 1}];
|
|
||||||
controller.setNewDiscount();
|
|
||||||
|
|
||||||
expect(controller.newDiscount).toEqual(1);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('updateDiscount()', () => {
|
|
||||||
it('should make a query if the discount value has been modified or the bulk value is true', () => {
|
|
||||||
controller.bulk = true;
|
|
||||||
controller.newDiscount = 15;
|
|
||||||
|
|
||||||
$httpBackend.expectPOST(`Tickets/11/updateDiscount`).respond();
|
|
||||||
controller.updateDiscount();
|
|
||||||
|
|
||||||
$httpBackend.flush();
|
|
||||||
});
|
|
||||||
|
|
||||||
it(`should throw if there's no changes on discount and it isn't bulk`, () => {
|
|
||||||
controller.bulk = false;
|
|
||||||
controller.newDiscount = 15;
|
|
||||||
controller.edit = [{discount: 15}];
|
|
||||||
jest.spyOn(controller.vnApp, 'showError');
|
|
||||||
controller.updateDiscount();
|
|
||||||
|
|
||||||
expect(controller.vnApp.showError).toHaveBeenCalledWith('There are no changes to save');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('clearDiscount()', () => {
|
|
||||||
it('should set newDiscount to null', () => {
|
|
||||||
controller.clearDiscount();
|
|
||||||
|
|
||||||
expect(controller.newDiscount).toEqual(null);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,409 +0,0 @@
|
||||||
import '../index.js';
|
|
||||||
import watcher from 'core/mocks/watcher';
|
|
||||||
import crudModel from 'core/mocks/crud-model';
|
|
||||||
|
|
||||||
describe('Ticket', () => {
|
|
||||||
describe('Component vnTicketSale', () => {
|
|
||||||
let controller;
|
|
||||||
let $scope;
|
|
||||||
let $state;
|
|
||||||
let $httpBackend;
|
|
||||||
|
|
||||||
const ticket = {
|
|
||||||
id: 1,
|
|
||||||
clientFk: 101,
|
|
||||||
shipped: 1,
|
|
||||||
created: new Date(),
|
|
||||||
client: {salesPersonFk: 1},
|
|
||||||
address: {mobile: 111111111}
|
|
||||||
};
|
|
||||||
const sales = [
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
concept: 'Item 1',
|
|
||||||
quantity: 5,
|
|
||||||
price: 23.5,
|
|
||||||
discount: 0,
|
|
||||||
}, {
|
|
||||||
id: 4,
|
|
||||||
concept: 'Item 2',
|
|
||||||
quantity: 20,
|
|
||||||
price: 5.5,
|
|
||||||
discount: 0,
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
beforeEach(ngModule('ticket'));
|
|
||||||
|
|
||||||
beforeEach(angular.mock.inject(($componentController, $rootScope, _$state_, _$httpBackend_) => {
|
|
||||||
$state = _$state_;
|
|
||||||
$scope = $rootScope.$new();
|
|
||||||
$scope.watcher = watcher;
|
|
||||||
$scope.sms = {open: () => {}};
|
|
||||||
$scope.ticket = ticket;
|
|
||||||
$scope.model = crudModel;
|
|
||||||
$httpBackend = _$httpBackend_;
|
|
||||||
Object.defineProperties($state.params, {
|
|
||||||
id: {
|
|
||||||
value: ticket.id,
|
|
||||||
writable: true
|
|
||||||
},
|
|
||||||
go: {
|
|
||||||
value: () => {},
|
|
||||||
writable: false
|
|
||||||
}
|
|
||||||
});
|
|
||||||
const $element = angular.element('<vn-ticket-sale></vn-ticket-sale>');
|
|
||||||
controller = $componentController('vnTicketSale', {$element, $scope});
|
|
||||||
controller.card = {reload: () => {}};
|
|
||||||
controller.ticket = ticket;
|
|
||||||
controller.sales = sales;
|
|
||||||
}));
|
|
||||||
|
|
||||||
describe('createClaim()', () => {
|
|
||||||
it('should perform a query and call windows open', () => {
|
|
||||||
jest.spyOn(controller.$state, 'go');
|
|
||||||
|
|
||||||
const claim = {id: 1};
|
|
||||||
const sales = [{id: 1}, {id: 2}];
|
|
||||||
|
|
||||||
$httpBackend.whenGET(`Tickets/1/getVAT`).respond(200, 10.5);
|
|
||||||
$httpBackend.whenGET(`Tickets/1/subtotal`).respond(200, 227.5);
|
|
||||||
$httpBackend.whenGET(`Tickets/1/isEditable`).respond();
|
|
||||||
$httpBackend.whenGET(`Tickets/1/isLocked`).respond();
|
|
||||||
$httpBackend.when('POST', `Claims/createFromSales`, {claim: claim, sales: sales}).respond(claim);
|
|
||||||
$httpBackend.expect('POST', `Claims/createFromSales`).respond(claim);
|
|
||||||
controller.createClaim();
|
|
||||||
$httpBackend.flush();
|
|
||||||
|
|
||||||
expect(controller.subtotal).toEqual(227.5);
|
|
||||||
expect(controller.VAT).toEqual(10.5);
|
|
||||||
expect(controller.total).toEqual(238);
|
|
||||||
expect(controller.$state.go).toHaveBeenCalledWith('claim.card.basicData', {id: 1});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('isChecked() getter', () => {
|
|
||||||
it('should set isChecked value to true when one of the instances has the value checked to true', () => {
|
|
||||||
controller.sales[0].checked = true;
|
|
||||||
|
|
||||||
expect(controller.isChecked).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('checkedLines()', () => {
|
|
||||||
it('should make an array of the instances with the property checked true()', () => {
|
|
||||||
let sale = controller.sales[0];
|
|
||||||
sale.checked = true;
|
|
||||||
let expectedResult = [sale];
|
|
||||||
|
|
||||||
$httpBackend.whenGET(`Tickets/1/subtotal`).respond(200, 227.5);
|
|
||||||
$httpBackend.whenGET(`Tickets/1/getVAT`).respond(200, 10.5);
|
|
||||||
$httpBackend.whenGET(`Tickets/1/isEditable`).respond();
|
|
||||||
$httpBackend.whenGET(`Tickets/1/isLocked`).respond();
|
|
||||||
let result = controller.checkedLines();
|
|
||||||
$httpBackend.flush();
|
|
||||||
|
|
||||||
expect(result).toEqual(expectedResult);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('onStateOkClick()', () => {
|
|
||||||
it('should perform a get and then call a function', () => {
|
|
||||||
let filter = {where: {code: 'OK'}, fields: ['id']};
|
|
||||||
filter = encodeURIComponent(JSON.stringify(filter));
|
|
||||||
let res = [{id: 3}];
|
|
||||||
jest.spyOn(controller, 'onStateChange').mockReturnThis();
|
|
||||||
|
|
||||||
$httpBackend.whenGET(`States?filter=${filter}`).respond(res);
|
|
||||||
$httpBackend.expectGET(`Tickets/1/subtotal`).respond(200, 227.5);
|
|
||||||
$httpBackend.expectGET(`Tickets/1/getVAT`).respond(200, 10.5);
|
|
||||||
$httpBackend.whenGET(`Tickets/1/isEditable`).respond();
|
|
||||||
$httpBackend.whenGET(`Tickets/1/isLocked`).respond();
|
|
||||||
controller.onStateOkClick();
|
|
||||||
$httpBackend.flush();
|
|
||||||
|
|
||||||
expect(controller.onStateChange).toHaveBeenCalledWith(3);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('onStateChange()', () => {
|
|
||||||
it('should perform a post and then call a function', () => {
|
|
||||||
$httpBackend.expectPOST(`TicketTrackings/changeState`).respond();
|
|
||||||
$httpBackend.whenGET(`Tickets/1/subtotal`).respond(200, 227.5);
|
|
||||||
$httpBackend.whenGET(`Tickets/1/getVAT`).respond(200, 10.5);
|
|
||||||
$httpBackend.whenGET(`Tickets/1/isEditable`).respond();
|
|
||||||
$httpBackend.whenGET(`Tickets/1/isLocked`).respond();
|
|
||||||
controller.onStateChange(3);
|
|
||||||
$httpBackend.flush();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('onRemoveLinesClick()', () => {
|
|
||||||
it('should call getCheckedLines, call removeInstances, and make a query', () => {
|
|
||||||
controller.sales[0].checked = true;
|
|
||||||
|
|
||||||
$httpBackend.whenPOST(`Sales/removes`).respond();
|
|
||||||
$httpBackend.whenGET(`Tickets/1/subtotal`).respond(200, 227.5);
|
|
||||||
$httpBackend.whenGET(`Tickets/1/getVAT`).respond(200, 10.5);
|
|
||||||
$httpBackend.whenGET(`Tickets/1/isEditable`).respond();
|
|
||||||
$httpBackend.whenGET(`Tickets/1/isLocked`).respond();
|
|
||||||
controller.onRemoveLinesClick('accept');
|
|
||||||
$httpBackend.flush();
|
|
||||||
|
|
||||||
expect(controller.sales.length).toEqual(1);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('unmarkAsReserved()', () => {
|
|
||||||
it('should call setReserved with false', () => {
|
|
||||||
jest.spyOn(controller, 'setReserved');
|
|
||||||
|
|
||||||
controller.unmarkAsReserved(false);
|
|
||||||
|
|
||||||
expect(controller.setReserved).toHaveBeenCalledWith(false);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('markAsReserved()', () => {
|
|
||||||
it('should call setReserved with true', () => {
|
|
||||||
jest.spyOn(controller, 'setReserved');
|
|
||||||
|
|
||||||
controller.markAsReserved(true);
|
|
||||||
|
|
||||||
expect(controller.setReserved).toHaveBeenCalledWith(true);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('setReserved()', () => {
|
|
||||||
it('should call getCheckedLines, $.index.accept and make a query ', () => {
|
|
||||||
const sale = controller.sales[0];
|
|
||||||
sale.checked = true;
|
|
||||||
let expectedRequest = {
|
|
||||||
sales: [sale],
|
|
||||||
ticketFk: ticket.id,
|
|
||||||
reserved: false
|
|
||||||
};
|
|
||||||
|
|
||||||
$httpBackend.expectPOST(`Sales/reserve`, expectedRequest).respond();
|
|
||||||
$httpBackend.whenGET(`Tickets/1/subtotal`).respond(200, 227.5);
|
|
||||||
$httpBackend.whenGET(`Tickets/1/getVAT`).respond(200, 10.5);
|
|
||||||
$httpBackend.whenGET(`Tickets/1/isEditable`).respond();
|
|
||||||
$httpBackend.whenGET(`Tickets/1/isLocked`).respond();
|
|
||||||
controller.unmarkAsReserved(false);
|
|
||||||
$httpBackend.flush();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('showSMSDialog()', () => {
|
|
||||||
it('should open an SMS dialog with specified data', () => {
|
|
||||||
jest.spyOn(controller.$.sms, 'open');
|
|
||||||
|
|
||||||
controller.sales[0].checked = true;
|
|
||||||
controller.showSMSDialog();
|
|
||||||
|
|
||||||
expect(controller.$.sms.open).toHaveBeenCalledWith();
|
|
||||||
expect(controller.newSMS.destination).toEqual(111111111);
|
|
||||||
expect(controller.newSMS.message).not.toEqual('');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('onChangeQuantity()', () => {
|
|
||||||
it('should not call addSale() or updateQuantity() methods', () => {
|
|
||||||
jest.spyOn(controller, 'addSale');
|
|
||||||
jest.spyOn(controller, 'updateQuantity');
|
|
||||||
|
|
||||||
const sale = {itemFk: 4};
|
|
||||||
controller.onChangeQuantity(sale);
|
|
||||||
|
|
||||||
expect(controller.addSale).not.toHaveBeenCalled();
|
|
||||||
expect(controller.updateQuantity).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should call addSale() method', () => {
|
|
||||||
jest.spyOn(controller, 'addSale');
|
|
||||||
|
|
||||||
const sale = {itemFk: 4, quantity: 5};
|
|
||||||
controller.onChangeQuantity(sale);
|
|
||||||
|
|
||||||
expect(controller.addSale).toHaveBeenCalledWith(sale);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should call updateQuantity() method', () => {
|
|
||||||
jest.spyOn(controller, 'updateQuantity');
|
|
||||||
jest.spyOn(controller, 'addSale');
|
|
||||||
|
|
||||||
const sale = {id: 1, itemFk: 4, quantity: 5};
|
|
||||||
controller.onChangeQuantity(sale);
|
|
||||||
|
|
||||||
expect(controller.addSale).not.toHaveBeenCalled();
|
|
||||||
expect(controller.updateQuantity).toHaveBeenCalledWith(sale);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('updateQuantity()', () => {
|
|
||||||
it('should make a POST query saving sale quantity', () => {
|
|
||||||
jest.spyOn(controller.$.watcher, 'updateOriginalData');
|
|
||||||
const data = {quantity: 10};
|
|
||||||
const sale = sales[0];
|
|
||||||
sale.quantity = 10;
|
|
||||||
|
|
||||||
$httpBackend.when('POST', `Sales/4/updateQuantity`, data).respond();
|
|
||||||
$httpBackend.expect('POST', `Sales/4/updateQuantity`, data).respond();
|
|
||||||
$httpBackend.whenGET(`Tickets/1/subtotal`).respond(200, 227.5);
|
|
||||||
$httpBackend.whenGET(`Tickets/1/getVAT`).respond(200, 10.5);
|
|
||||||
$httpBackend.whenGET(`Tickets/1/isEditable`).respond();
|
|
||||||
$httpBackend.whenGET(`Tickets/1/isLocked`).respond();
|
|
||||||
controller.updateQuantity(sale);
|
|
||||||
$httpBackend.flush();
|
|
||||||
|
|
||||||
expect(controller.$.watcher.updateOriginalData).toHaveBeenCalledWith();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('updateConcept()', () => {
|
|
||||||
it('should make a POST query saving sale concept', () => {
|
|
||||||
jest.spyOn(controller.$.watcher, 'updateOriginalData');
|
|
||||||
const data = {newConcept: 'My new weapon'};
|
|
||||||
const sale = sales[0];
|
|
||||||
sale.concept = 'My new weapon';
|
|
||||||
|
|
||||||
$httpBackend.when('POST', `Sales/4/updateConcept`, data).respond();
|
|
||||||
$httpBackend.expect('POST', `Sales/4/updateConcept`, data).respond();
|
|
||||||
$httpBackend.whenGET(`Tickets/1/subtotal`).respond(200, 227.5);
|
|
||||||
$httpBackend.whenGET(`Tickets/1/getVAT`).respond(200, 10.5);
|
|
||||||
$httpBackend.whenGET(`Tickets/1/isEditable`).respond();
|
|
||||||
$httpBackend.whenGET(`Tickets/1/isLocked`).respond();
|
|
||||||
controller.updateConcept(sale);
|
|
||||||
$httpBackend.flush();
|
|
||||||
|
|
||||||
expect(controller.$.watcher.updateOriginalData).toHaveBeenCalledWith();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('addSale()', () => {
|
|
||||||
it('should make a POST query adding a new sale', () => {
|
|
||||||
jest.spyOn(controller.$.watcher, 'updateOriginalData');
|
|
||||||
const newSale = {itemFk: 4, quantity: 10};
|
|
||||||
const params = {itemId: 4, quantity: 10};
|
|
||||||
|
|
||||||
const expectedResult = {
|
|
||||||
id: 30,
|
|
||||||
quantity: 10,
|
|
||||||
discount: 0,
|
|
||||||
price: 0,
|
|
||||||
itemFk: 4,
|
|
||||||
item: {
|
|
||||||
subName: 'Item subName',
|
|
||||||
image: '30.png'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
$httpBackend.when('POST', `tickets/1/addSale`, params).respond(expectedResult);
|
|
||||||
$httpBackend.expect('POST', `tickets/1/addSale`, params).respond(expectedResult);
|
|
||||||
$httpBackend.whenGET(`Tickets/1/subtotal`).respond(200, 227.5);
|
|
||||||
$httpBackend.whenGET(`Tickets/1/getVAT`).respond(200, 10.5);
|
|
||||||
$httpBackend.whenGET(`Tickets/1/isEditable`).respond();
|
|
||||||
$httpBackend.whenGET(`Tickets/1/isLocked`).respond();
|
|
||||||
controller.addSale(newSale);
|
|
||||||
$httpBackend.flush();
|
|
||||||
|
|
||||||
expect(controller.$.watcher.updateOriginalData).toHaveBeenCalledWith();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('transferSales()', () => {
|
|
||||||
it('should transfer sales to a ticket', () => {
|
|
||||||
jest.spyOn(controller, 'goToTicket');
|
|
||||||
controller.transfer = {
|
|
||||||
sales: [{id: 1, itemFk: 1}, {id: 2, itemFk: 4}]
|
|
||||||
};
|
|
||||||
|
|
||||||
const expectedResponse = {id: 13};
|
|
||||||
const params = {
|
|
||||||
ticketId: 13,
|
|
||||||
sales: controller.transfer.sales
|
|
||||||
};
|
|
||||||
|
|
||||||
$httpBackend.when('POST', `tickets/1/transferSales`, params).respond(expectedResponse);
|
|
||||||
$httpBackend.expect('POST', `tickets/1/transferSales`, params).respond(expectedResponse);
|
|
||||||
$httpBackend.whenGET(`Tickets/1/subtotal`).respond(200, 227.5);
|
|
||||||
$httpBackend.whenGET(`Tickets/1/getVAT`).respond(200, 10.5);
|
|
||||||
$httpBackend.whenGET(`Tickets/1/isEditable`).respond();
|
|
||||||
$httpBackend.whenGET(`Tickets/1/isLocked`).respond();
|
|
||||||
controller.transferSales(13);
|
|
||||||
$httpBackend.flush();
|
|
||||||
|
|
||||||
expect(controller.goToTicket).toHaveBeenCalledWith(13);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('setTransferParams()', () => {
|
|
||||||
it('should define the transfer object on the controller and its default properties', () => {
|
|
||||||
let sale = controller.sales[0];
|
|
||||||
sale.checked = true;
|
|
||||||
const expectedResponse = [sale];
|
|
||||||
|
|
||||||
$httpBackend.when('GET', `clients/101/lastActiveTickets?ticketId=1`).respond(expectedResponse);
|
|
||||||
$httpBackend.expect('GET', `clients/101/lastActiveTickets?ticketId=1`).respond(expectedResponse);
|
|
||||||
$httpBackend.whenGET(`Tickets/1/subtotal`).respond(200, 227.5);
|
|
||||||
$httpBackend.whenGET(`Tickets/1/getVAT`).respond(200, 10.5);
|
|
||||||
$httpBackend.whenGET(`Tickets/1/isEditable`).respond();
|
|
||||||
$httpBackend.whenGET(`Tickets/1/isLocked`).respond();
|
|
||||||
controller.setTransferParams();
|
|
||||||
$httpBackend.flush();
|
|
||||||
|
|
||||||
const lastActiveTickets = controller.transfer.lastActiveTickets;
|
|
||||||
|
|
||||||
expect(controller.transfer).toBeDefined();
|
|
||||||
expect(lastActiveTickets).toBeDefined();
|
|
||||||
expect(lastActiveTickets[0].id).toEqual(4);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('newOrderFromTicket()', () => {
|
|
||||||
it('should make an HTTP post query and then open the new order on a new tab', () => {
|
|
||||||
const params = {ticketFk: 1};
|
|
||||||
const expectedResponse = {id: 123};
|
|
||||||
|
|
||||||
window.open = jasmine.createSpy('open');
|
|
||||||
controller.$state.href = jasmine.createSpy('href')
|
|
||||||
.and.returnValue('/somePath');
|
|
||||||
|
|
||||||
$httpBackend.when('POST', `Orders/newFromTicket`, params).respond(expectedResponse);
|
|
||||||
$httpBackend.expect('POST', `Orders/newFromTicket`, params).respond(expectedResponse);
|
|
||||||
$httpBackend.whenGET(`Tickets/1/subtotal`).respond(200, 227.5);
|
|
||||||
$httpBackend.whenGET(`Tickets/1/getVAT`).respond(200, 10.5);
|
|
||||||
$httpBackend.whenGET(`Tickets/1/isEditable`).respond();
|
|
||||||
$httpBackend.whenGET(`Tickets/1/isLocked`).respond();
|
|
||||||
controller.newOrderFromTicket();
|
|
||||||
$httpBackend.flush();
|
|
||||||
|
|
||||||
expect(window.open).toHaveBeenCalledWith('/somePath', '_blank');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('hasOneSaleSelected()', () => {
|
|
||||||
it('should return true if just one sale is selected', () => {
|
|
||||||
controller.sales[0].checked = true;
|
|
||||||
|
|
||||||
expect(controller.hasOneSaleSelected()).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('calculateSalePrice()', () => {
|
|
||||||
it('should make an HTTP post query ', () => {
|
|
||||||
controller.sales[0].checked = true;
|
|
||||||
|
|
||||||
$httpBackend.when('POST', `Sales/4/recalculatePrice`).respond(200);
|
|
||||||
$httpBackend.whenGET(`Tickets/1/subtotal`).respond(200, 227.5);
|
|
||||||
$httpBackend.whenGET(`Tickets/1/getVAT`).respond(200, 10.5);
|
|
||||||
$httpBackend.whenGET(`Tickets/1/isEditable`).respond();
|
|
||||||
$httpBackend.whenGET(`Tickets/1/isLocked`).respond();
|
|
||||||
|
|
||||||
controller.calculateSalePrice();
|
|
||||||
$httpBackend.flush();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -24,7 +24,7 @@ vn-ticket-sale {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
vn-dialog.edit {
|
vn-dialog.edit {
|
||||||
@extend .edit-price;
|
@extend .edit-popover;
|
||||||
|
|
||||||
&>div{
|
&>div{
|
||||||
padding: 0!important;
|
padding: 0!important;
|
||||||
|
@ -81,8 +81,9 @@ vn-ticket-sale {
|
||||||
width: 400px
|
width: 400px
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.edit-price {
|
.vn-popover .edit-popover {
|
||||||
min-width: 200px;
|
min-width: 200px;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
section.header {
|
section.header {
|
||||||
background-color: $color-main;
|
background-color: $color-main;
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
<vn-horizontal>
|
<vn-horizontal>
|
||||||
<vn-one>
|
<vn-one>
|
||||||
<vn-label-value label="State"
|
<vn-label-value label="State"
|
||||||
value="{{$ctrl.summary.state.state.name}}">
|
value="{{$ctrl.summary.ticketState.state.name}}">
|
||||||
</vn-label-value>
|
</vn-label-value>
|
||||||
<vn-label-value label="Salesperson"
|
<vn-label-value label="Salesperson"
|
||||||
value="{{$ctrl.summary.client.salesPerson.user.nickname}}">
|
value="{{$ctrl.summary.client.salesPerson.user.nickname}}">
|
||||||
|
|
|
@ -31,7 +31,7 @@ class Controller extends Section {
|
||||||
|
|
||||||
get isEditable() {
|
get isEditable() {
|
||||||
try {
|
try {
|
||||||
return !this.ticket.state.state.alertLevel;
|
return !this.ticket.ticketState.state.alertLevel;
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -32,7 +32,7 @@ module.exports = Self => {
|
||||||
zoneFk: id
|
zoneFk: id
|
||||||
},
|
},
|
||||||
include: {
|
include: {
|
||||||
relation: 'state',
|
relation: 'ticketState',
|
||||||
scope: {
|
scope: {
|
||||||
fields: ['id', 'alertLevel', 'code']
|
fields: ['id', 'alertLevel', 'code']
|
||||||
}
|
}
|
||||||
|
@ -49,7 +49,7 @@ module.exports = Self => {
|
||||||
ticketList.forEach(ticket => {
|
ticketList.forEach(ticket => {
|
||||||
promises.push(ticket.updateAttributes({zoneFk: null}, options));
|
promises.push(ticket.updateAttributes({zoneFk: null}, options));
|
||||||
|
|
||||||
if (ticket.state().alertLevel == 0 && ticket.shipped >= today) {
|
if (ticket.ticketState().alertLevel == 0 && ticket.shipped >= today) {
|
||||||
promises.push(models.TicketTracking.create({
|
promises.push(models.TicketTracking.create({
|
||||||
ticketFk: ticket.id,
|
ticketFk: ticket.id,
|
||||||
stateFk: fixingState.id,
|
stateFk: fixingState.id,
|
||||||
|
|
Loading…
Reference in New Issue