Merge branch 'dev' into zone-deliveryDays-quitar-campo-provincia
gitea/salix/pipeline/head This commit looks good
Details
gitea/salix/pipeline/head This commit looks good
Details
This commit is contained in:
commit
729daf8b34
|
@ -101,6 +101,16 @@ INSERT INTO `vn`.`sector`(`id`, `description`, `warehouseFk`, `isPreviousPrepare
|
||||||
(1, 'First sector', 1, 1, 'FIRST', 999, 999),
|
(1, 'First sector', 1, 1, 'FIRST', 999, 999),
|
||||||
(2, 'Second sector', 2, 0, 'SECOND', 100, 150);
|
(2, 'Second sector', 2, 0, 'SECOND', 100, 150);
|
||||||
|
|
||||||
|
INSERT INTO `vn`.`parking` (`id`, `column`, `row`, `sectorFk`, `code`, `pickingOrder`)
|
||||||
|
VALUES
|
||||||
|
('1', '700', '01', '1', '700-01', '70001'),
|
||||||
|
('2', '700', '02', '2', '700-02', '70002');
|
||||||
|
|
||||||
|
INSERT INTO `vn`.`shelving` (`code`, `parkingFk`, `isPrinted`, `priority`, `parked`, `userFk`)
|
||||||
|
VALUES
|
||||||
|
('GVC', '1', '0', '1', '0', '106'),
|
||||||
|
('HEJ', '2', '0', '1', '0', '106');
|
||||||
|
|
||||||
INSERT INTO `vn`.`warehouseAlias`(`id`, `name`)
|
INSERT INTO `vn`.`warehouseAlias`(`id`, `name`)
|
||||||
VALUES
|
VALUES
|
||||||
(1, 'Main Warehouse');
|
(1, 'Main Warehouse');
|
||||||
|
@ -554,6 +564,10 @@ INSERT INTO `vn`.`ticketObservation`(`id`, `ticketFk`, `observationTypeFk`, `des
|
||||||
(10, 23, 4, 'Reclama ticket: 8'),
|
(10, 23, 4, 'Reclama ticket: 8'),
|
||||||
(11, 24, 4, 'Reclama ticket: 7');
|
(11, 24, 4, 'Reclama ticket: 7');
|
||||||
|
|
||||||
|
-- FIX for state hours on local, inter_afterInsert
|
||||||
|
UPDATE vncontrol.inter SET odbc_date = DATE_ADD(CURDATE(), INTERVAL -10 SECOND);
|
||||||
|
|
||||||
|
|
||||||
INSERT INTO `vn`.`ticketTracking`(`ticketFk`, `stateFk`, `workerFk`, `created`)
|
INSERT INTO `vn`.`ticketTracking`(`ticketFk`, `stateFk`, `workerFk`, `created`)
|
||||||
VALUES
|
VALUES
|
||||||
(1, 16, 5 , DATE_ADD(NOW(), INTERVAL -1 MONTH)),
|
(1, 16, 5 , DATE_ADD(NOW(), INTERVAL -1 MONTH)),
|
||||||
|
@ -928,6 +942,18 @@ INSERT INTO `vn`.`saleComponent`(`saleFk`, `componentFk`, `value`)
|
||||||
(32, 36, -92.324),
|
(32, 36, -92.324),
|
||||||
(32, 39, 0.994);
|
(32, 39, 0.994);
|
||||||
|
|
||||||
|
INSERT INTO `vn`.`itemShelving` (`id`, `itemFk`, `shelvingFk`, `shelve`, `deep`, `quantity`, `visible`, `available`, `grouping`, `packing`, `level`, `userFk`)
|
||||||
|
VALUES
|
||||||
|
('1', '2', 'GVC', 'A', '0', '1', '1', '1', '1', '1', '1', '106'),
|
||||||
|
('2', '4', 'HEJ', 'A', '0', '2', '1', '1', '1', '1', '1', '106');
|
||||||
|
|
||||||
|
INSERT INTO `vn`.`itemShelvingSale` (`itemShelvingFk`, `saleFk`, `quantity`, `created`, `userFk`)
|
||||||
|
VALUES
|
||||||
|
('1', '1', '1', '', '106'),
|
||||||
|
('2', '2', '5', '', '106'),
|
||||||
|
('1', '7', '1', '', '106'),
|
||||||
|
('2', '8', '5', '', '106');
|
||||||
|
|
||||||
INSERT INTO `vncontrol`.`accion`(`accion_id`, `accion`)
|
INSERT INTO `vncontrol`.`accion`(`accion_id`, `accion`)
|
||||||
VALUES
|
VALUES
|
||||||
(3, 'ACTION ONE'),
|
(3, 'ACTION ONE'),
|
||||||
|
|
|
@ -367,6 +367,13 @@ export default {
|
||||||
advancedSearchInvoiceOut: 'vn-ticket-search-panel vn-textfield[ng-model="filter.refFk"]',
|
advancedSearchInvoiceOut: 'vn-ticket-search-panel vn-textfield[ng-model="filter.refFk"]',
|
||||||
newTicketButton: 'vn-ticket-index a',
|
newTicketButton: 'vn-ticket-index a',
|
||||||
searchResult: 'vn-ticket-index vn-card > vn-table > div > vn-tbody > a.vn-tr',
|
searchResult: 'vn-ticket-index vn-card > vn-table > div > vn-tbody > a.vn-tr',
|
||||||
|
secondTicketCheckbox: 'vn-ticket-index vn-tbody > a:nth-child(2) > vn-td:nth-child(1) > vn-check',
|
||||||
|
thirdTicketCheckbox: 'vn-ticket-index vn-tbody > a:nth-child(3) > vn-td:nth-child(1) > vn-check',
|
||||||
|
sixthTicketCheckbox: 'vn-ticket-index vn-tbody > a:nth-child(6) > vn-td:nth-child(1) > vn-check',
|
||||||
|
payoutButton: 'vn-ticket-index vn-button[icon="icon-recovery"]',
|
||||||
|
payoutCompany: '.vn-dialog vn-autocomplete[ng-model="$ctrl.receipt.companyFk"]',
|
||||||
|
payoutBank: '.vn-dialog vn-autocomplete[ng-model="$ctrl.receipt.bankFk"]',
|
||||||
|
submitPayout: '.vn-dialog vn-button[label="Save"]',
|
||||||
searchWeeklyResult: 'vn-ticket-weekly-index vn-table vn-tbody > vn-tr',
|
searchWeeklyResult: 'vn-ticket-weekly-index vn-table vn-tbody > vn-tr',
|
||||||
searchResultDate: 'vn-ticket-summary [label=Landed] span',
|
searchResultDate: 'vn-ticket-summary [label=Landed] span',
|
||||||
topbarSearch: 'vn-searchbar',
|
topbarSearch: 'vn-searchbar',
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
import selectors from '../../helpers/selectors.js';
|
||||||
|
import getBrowser from '../../helpers/puppeteer';
|
||||||
|
|
||||||
|
describe('Ticket index payout path', () => {
|
||||||
|
let browser;
|
||||||
|
let page;
|
||||||
|
|
||||||
|
beforeAll(async() => {
|
||||||
|
browser = await getBrowser();
|
||||||
|
page = browser.page;
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(async() => {
|
||||||
|
await browser.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should navigate to the ticket index', async() => {
|
||||||
|
await page.loginAndModule('administrative', 'ticket');
|
||||||
|
let url = await page.expectURL('#!/ticket/index');
|
||||||
|
|
||||||
|
expect(url).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should check three tickets 2 of a clinet and 1 of another', async() => {
|
||||||
|
await page.keyboard.press('Enter');
|
||||||
|
await page.waitToClick(selectors.ticketsIndex.secondTicketCheckbox);
|
||||||
|
await page.waitToClick(selectors.ticketsIndex.sixthTicketCheckbox);
|
||||||
|
await page.waitToClick(selectors.ticketsIndex.payoutButton);
|
||||||
|
const result = await page.waitForLastSnackbar();
|
||||||
|
|
||||||
|
expect(result).toEqual('You cannot make a payment on account from multiple clients');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should uncheck the sixth ticket result and check the third which is from the same client then open the payout form', async() => {
|
||||||
|
await page.waitToClick(selectors.ticketsIndex.sixthTicketCheckbox);
|
||||||
|
await page.waitToClick(selectors.ticketsIndex.thirdTicketCheckbox);
|
||||||
|
await page.waitToClick(selectors.ticketsIndex.payoutButton);
|
||||||
|
|
||||||
|
await page.waitForSelector(selectors.ticketsIndex.payoutCompany);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should fill the company and bank to perform a payout', async() => {
|
||||||
|
await page.autocompleteSearch(selectors.ticketsIndex.payoutBank, 'cash');
|
||||||
|
await page.waitToClick(selectors.ticketsIndex.submitPayout);
|
||||||
|
const result = await page.waitForLastSnackbar();
|
||||||
|
|
||||||
|
expect(result).toEqual('Data saved!');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should navigate to the client balance section and check a new balance line was entered', async() => {
|
||||||
|
await page.waitToClick(selectors.globalItems.homeButton);
|
||||||
|
await page.selectModule('client');
|
||||||
|
await page.accessToSearchResult('101');
|
||||||
|
await page.accessToSection('client.card.balance.index');
|
||||||
|
await page.waitForSelector('vn-client-balance-index vn-tbody > vn-tr');
|
||||||
|
let result = await page.countElement('vn-client-balance-index vn-tbody > vn-tr');
|
||||||
|
|
||||||
|
expect(result).toEqual(4);
|
||||||
|
});
|
||||||
|
});
|
|
@ -81,7 +81,7 @@ describe('Order edit basic data path', () => {
|
||||||
await page.waitToClick(selectors.orderBasicData.saveButton);
|
await page.waitToClick(selectors.orderBasicData.saveButton);
|
||||||
const result = await page.waitForLastSnackbar();
|
const result = await page.waitForLastSnackbar();
|
||||||
|
|
||||||
expect(result).toEqual('Data saved!');
|
expect(result).toContain('Data saved!');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should now confirm the client have been edited', async() => {
|
it('should now confirm the client have been edited', async() => {
|
||||||
|
|
|
@ -69,8 +69,7 @@ describe('Order catalog', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should search for an item by id', async() => {
|
it('should search for an item by id', async() => {
|
||||||
await page.write(selectors.orderCatalog.itemId, '2');
|
await page.accessToSearchResult('2');
|
||||||
await page.keyboard.press('Enter');
|
|
||||||
await page.waitForNumberOfElements('section.product', 1);
|
await page.waitForNumberOfElements('section.product', 1);
|
||||||
const result = await page.countElement('section.product');
|
const result = await page.countElement('section.product');
|
||||||
|
|
||||||
|
|
|
@ -62,6 +62,7 @@
|
||||||
"MESSAGE_INSURANCE_CHANGE": "I have changed the insurence credit of client [{{clientName}} (#{{clientId}})]({{{url}}}) to *{{credit}} €*",
|
"MESSAGE_INSURANCE_CHANGE": "I have changed the insurence credit of client [{{clientName}} (#{{clientId}})]({{{url}}}) to *{{credit}} €*",
|
||||||
"MESSAGE_CHANGED_PAYMETHOD": "I have changed the pay method for client [{{clientName}} (#{{clientId}})]({{{url}}})",
|
"MESSAGE_CHANGED_PAYMETHOD": "I have changed the pay method for client [{{clientName}} (#{{clientId}})]({{{url}}})",
|
||||||
"Sent units from ticket": "I sent *{{quantity}}* units of [{{concept}} (#{{itemId}})]({{{itemUrl}}}) to *\"{{nickname}}\"* coming from ticket id [#{{ticketId}}]({{{ticketUrl}}})",
|
"Sent units from ticket": "I sent *{{quantity}}* units of [{{concept}} (#{{itemId}})]({{{itemUrl}}}) to *\"{{nickname}}\"* coming from ticket id [#{{ticketId}}]({{{ticketUrl}}})",
|
||||||
|
"This ticket is not an stowaway anymore": "The ticket id [#{{ticketId}}]({{{ticketUrl}}}) is not an stowaway anymore",
|
||||||
"Customs agent is required for a non UEE member": "Customs agent is required for a non UEE member",
|
"Customs agent is required for a non UEE member": "Customs agent is required for a non UEE member",
|
||||||
"Incoterms is required for a non UEE member": "Incoterms is required for a non UEE member",
|
"Incoterms is required for a non UEE member": "Incoterms is required for a non UEE member",
|
||||||
"Client checked as validated despite of duplication": "Client checked as validated despite of duplication from client id {{clientId}}",
|
"Client checked as validated despite of duplication": "Client checked as validated despite of duplication from client id {{clientId}}",
|
||||||
|
|
|
@ -125,6 +125,7 @@
|
||||||
"MESSAGE_INSURANCE_CHANGE": "He cambiado el crédito asegurado del cliente [{{clientName}} (#{{clientId}})]({{{url}}}) a *{{credit}} €*",
|
"MESSAGE_INSURANCE_CHANGE": "He cambiado el crédito asegurado del cliente [{{clientName}} (#{{clientId}})]({{{url}}}) a *{{credit}} €*",
|
||||||
"MESSAGE_CHANGED_PAYMETHOD": "He cambiado la forma de pago del cliente [{{clientName}} (#{{clientId}})]({{{url}}})",
|
"MESSAGE_CHANGED_PAYMETHOD": "He cambiado la forma de pago del cliente [{{clientName}} (#{{clientId}})]({{{url}}})",
|
||||||
"Sent units from ticket": "Envio *{{quantity}}* unidades de [{{concept}} (#{{itemId}})]({{{itemUrl}}}) a *\"{{nickname}}\"* provenientes del ticket id [#{{ticketId}}]({{{ticketUrl}}})",
|
"Sent units from ticket": "Envio *{{quantity}}* unidades de [{{concept}} (#{{itemId}})]({{{itemUrl}}}) a *\"{{nickname}}\"* provenientes del ticket id [#{{ticketId}}]({{{ticketUrl}}})",
|
||||||
|
"This ticket is not an stowaway anymore": "El ticket id [#{{ticketId}}]({{{ticketUrl}}}) ha dejado de ser un polizón",
|
||||||
"Client checked as validated despite of duplication": "Cliente comprobado a pesar de que existe el cliente id {{clientId}}",
|
"Client checked as validated despite of duplication": "Cliente comprobado a pesar de que existe el cliente id {{clientId}}",
|
||||||
"ORDER_ROW_UNAVAILABLE": "No hay disponibilidad de este producto",
|
"ORDER_ROW_UNAVAILABLE": "No hay disponibilidad de este producto",
|
||||||
"Distance must be lesser than 1000": "La distancia debe ser inferior a 1000",
|
"Distance must be lesser than 1000": "La distancia debe ser inferior a 1000",
|
||||||
|
|
|
@ -44,6 +44,9 @@
|
||||||
"ItemTypeTag": {
|
"ItemTypeTag": {
|
||||||
"dataSource": "vn"
|
"dataSource": "vn"
|
||||||
},
|
},
|
||||||
|
"ItemShelving": {
|
||||||
|
"dataSource": "vn"
|
||||||
|
},
|
||||||
"ItemShelvingSale": {
|
"ItemShelvingSale": {
|
||||||
"dataSource": "vn"
|
"dataSource": "vn"
|
||||||
},
|
},
|
||||||
|
|
|
@ -25,6 +25,11 @@
|
||||||
"model": "Sale",
|
"model": "Sale",
|
||||||
"foreignKey": "saleFk"
|
"foreignKey": "saleFk"
|
||||||
},
|
},
|
||||||
|
"itemShelving": {
|
||||||
|
"type": "belongsTo",
|
||||||
|
"model": "ItemShelving",
|
||||||
|
"foreignKey": "itemShelvingFk"
|
||||||
|
},
|
||||||
"user": {
|
"user": {
|
||||||
"type": "belongsTo",
|
"type": "belongsTo",
|
||||||
"model": "Account",
|
"model": "Account",
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
{
|
||||||
|
"name": "ItemShelving",
|
||||||
|
"base": "VnModel",
|
||||||
|
"options": {
|
||||||
|
"mysql": {
|
||||||
|
"table": "itemShelving"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "number",
|
||||||
|
"id": true,
|
||||||
|
"description": "Identifier"
|
||||||
|
},
|
||||||
|
"shelve": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"deep": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"quantity": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"created": {
|
||||||
|
"type": "Date"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"relations": {
|
||||||
|
"item": {
|
||||||
|
"type": "belongsTo",
|
||||||
|
"model": "Item",
|
||||||
|
"foreignKey": "itemFk"
|
||||||
|
},
|
||||||
|
"user": {
|
||||||
|
"type": "belongsTo",
|
||||||
|
"model": "Account",
|
||||||
|
"foreignKey": "userFk"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,6 +11,13 @@
|
||||||
limit="50"
|
limit="50"
|
||||||
data="$ctrl.items">
|
data="$ctrl.items">
|
||||||
</vn-crud-model>
|
</vn-crud-model>
|
||||||
|
<vn-portal slot="topbar">
|
||||||
|
<vn-searchbar
|
||||||
|
auto-state="false"
|
||||||
|
info="Search by item id or name"
|
||||||
|
on-search="$ctrl.onSearch($params)">
|
||||||
|
</vn-searchbar>
|
||||||
|
</vn-portal>
|
||||||
|
|
||||||
<vn-order-catalog-view model="model"
|
<vn-order-catalog-view model="model"
|
||||||
order="$ctrl.order">
|
order="$ctrl.order">
|
||||||
|
@ -77,14 +84,6 @@
|
||||||
</div>
|
</div>
|
||||||
</vn-vertical>
|
</vn-vertical>
|
||||||
<vn-vertical class="input vn-pt-md">
|
<vn-vertical class="input vn-pt-md">
|
||||||
<vn-textfield vn-id="itemId"
|
|
||||||
ng-keyUp="$ctrl.onSearchById($event)"
|
|
||||||
label="Item id">
|
|
||||||
<prepend>
|
|
||||||
<vn-icon icon="icon-item"></vn-icon>
|
|
||||||
</prepend>
|
|
||||||
</vn-textfield>
|
|
||||||
|
|
||||||
<vn-datalist vn-one
|
<vn-datalist vn-one
|
||||||
vn-id="search"
|
vn-id="search"
|
||||||
data="$ctrl.tagValues"
|
data="$ctrl.tagValues"
|
||||||
|
@ -117,10 +116,19 @@
|
||||||
ng-if="$ctrl.itemId"
|
ng-if="$ctrl.itemId"
|
||||||
removable="true"
|
removable="true"
|
||||||
translate-attr="{title: 'Item'}"
|
translate-attr="{title: 'Item'}"
|
||||||
on-remove="$ctrl.itemId = null"
|
on-remove="$ctrl.removeItemId()"
|
||||||
class="colored">
|
class="colored">
|
||||||
<span>Id: {{$ctrl.itemId}}</span>
|
<span>Id: {{$ctrl.itemId}}</span>
|
||||||
</vn-chip>
|
</vn-chip>
|
||||||
|
<vn-chip
|
||||||
|
ng-if="$ctrl.itemName"
|
||||||
|
removable="true"
|
||||||
|
translate-attr="{title: 'Item'}"
|
||||||
|
on-remove="$ctrl.removeItemName()"
|
||||||
|
class="colored">
|
||||||
|
<span translate>Name</span>
|
||||||
|
<span>: {{$ctrl.itemName}}</span>
|
||||||
|
</vn-chip>
|
||||||
<vn-chip
|
<vn-chip
|
||||||
ng-if="category.selection"
|
ng-if="category.selection"
|
||||||
removable="true"
|
removable="true"
|
||||||
|
|
|
@ -48,9 +48,6 @@ class Controller extends Section {
|
||||||
if (!value) return;
|
if (!value) return;
|
||||||
|
|
||||||
this.$.$applyAsync(() => {
|
this.$.$applyAsync(() => {
|
||||||
if (this.$params.itemId)
|
|
||||||
this.itemId = parseInt(this.$params.itemId);
|
|
||||||
|
|
||||||
if (this.$params.categoryId)
|
if (this.$params.categoryId)
|
||||||
this.categoryId = parseInt(this.$params.categoryId);
|
this.categoryId = parseInt(this.$params.categoryId);
|
||||||
|
|
||||||
|
@ -111,17 +108,6 @@ class Controller extends Section {
|
||||||
this.applyFilters();
|
this.applyFilters();
|
||||||
}
|
}
|
||||||
|
|
||||||
get itemId() {
|
|
||||||
return this._itemId;
|
|
||||||
}
|
|
||||||
|
|
||||||
set itemId(value) {
|
|
||||||
this._itemId = value;
|
|
||||||
|
|
||||||
this.updateStateParams();
|
|
||||||
this.applyFilters();
|
|
||||||
}
|
|
||||||
|
|
||||||
get tags() {
|
get tags() {
|
||||||
return this._tags;
|
return this._tags;
|
||||||
}
|
}
|
||||||
|
@ -195,18 +181,6 @@ class Controller extends Section {
|
||||||
this.itemTypes = res.data);
|
this.itemTypes = res.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Search by item id filter
|
|
||||||
* @param {object} event
|
|
||||||
*/
|
|
||||||
onSearchById(event) {
|
|
||||||
const value = this.$.itemId.value;
|
|
||||||
if (event.key === 'Enter' && value) {
|
|
||||||
this.itemId = value;
|
|
||||||
this.$.itemId.value = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Search by tag value
|
* Search by tag value
|
||||||
* @param {object} event
|
* @param {object} event
|
||||||
|
@ -230,9 +204,19 @@ class Controller extends Section {
|
||||||
this.applyFilters();
|
this.applyFilters();
|
||||||
}
|
}
|
||||||
|
|
||||||
applyFilters() {
|
removeItemId() {
|
||||||
|
this.itemId = null;
|
||||||
|
this.applyFilters();
|
||||||
|
}
|
||||||
|
|
||||||
|
removeItemName() {
|
||||||
|
this.itemName = null;
|
||||||
|
this.applyFilters();
|
||||||
|
}
|
||||||
|
|
||||||
|
applyFilters(filter = {}) {
|
||||||
let newParams = {};
|
let newParams = {};
|
||||||
let newFilter = {};
|
let newFilter = Object.assign({}, filter);
|
||||||
const model = this.$.model;
|
const model = this.$.model;
|
||||||
|
|
||||||
if (this.categoryId)
|
if (this.categoryId)
|
||||||
|
@ -241,16 +225,13 @@ class Controller extends Section {
|
||||||
if (this.typeId)
|
if (this.typeId)
|
||||||
newFilter.typeFk = this.typeId;
|
newFilter.typeFk = this.typeId;
|
||||||
|
|
||||||
if (this.itemId)
|
|
||||||
newFilter = {'i.id': this.itemId};
|
|
||||||
|
|
||||||
newParams = {
|
newParams = {
|
||||||
orderFk: this.order.id,
|
orderFk: this.$params.id,
|
||||||
orderBy: this.getOrderBy(),
|
orderBy: this.getOrderBy(),
|
||||||
tags: this.tags,
|
tags: this.tags,
|
||||||
};
|
};
|
||||||
|
|
||||||
model.applyFilter({where: newFilter}, newParams);
|
return model.applyFilter({where: newFilter}, newParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
openPanel(event) {
|
openPanel(event) {
|
||||||
|
@ -282,10 +263,6 @@ class Controller extends Section {
|
||||||
if (this.typeId)
|
if (this.typeId)
|
||||||
params.typeId = this.typeId;
|
params.typeId = this.typeId;
|
||||||
|
|
||||||
params.itemId = undefined;
|
|
||||||
if (this.itemId)
|
|
||||||
params.itemId = this.itemId;
|
|
||||||
|
|
||||||
params.tags = undefined;
|
params.tags = undefined;
|
||||||
if (this.tags.length) {
|
if (this.tags.length) {
|
||||||
const tags = [];
|
const tags = [];
|
||||||
|
@ -344,6 +321,27 @@ class Controller extends Section {
|
||||||
newFilterList = newFilterList.concat(tags);
|
newFilterList = newFilterList.concat(tags);
|
||||||
this.orderFields = newFilterList;
|
this.orderFields = newFilterList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onSearch(params) {
|
||||||
|
if (!params) return;
|
||||||
|
|
||||||
|
this.itemId = null;
|
||||||
|
this.itemName = null;
|
||||||
|
|
||||||
|
if (params.search) {
|
||||||
|
if (/^\d+$/.test(params.search)) {
|
||||||
|
this.itemId = params.search;
|
||||||
|
return this.applyFilters({
|
||||||
|
'i.id': params.search
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.itemName = params.search;
|
||||||
|
return this.applyFilters({
|
||||||
|
'i.name': {like: `%${params.search}%`}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else return this.applyFilters();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ngModule.component('vnOrderCatalog', {
|
ngModule.component('vnOrderCatalog', {
|
||||||
|
|
|
@ -17,12 +17,15 @@ describe('Order', () => {
|
||||||
$scope.search = {};
|
$scope.search = {};
|
||||||
$scope.itemId = {};
|
$scope.itemId = {};
|
||||||
$state = _$state_;
|
$state = _$state_;
|
||||||
$state.params.categoryId = 1;
|
|
||||||
$state.params.typeId = 2;
|
|
||||||
$state.current.name = 'my.current.state';
|
$state.current.name = 'my.current.state';
|
||||||
const $element = angular.element('<vn-order-catalog></vn-order-catalog>');
|
const $element = angular.element('<vn-order-catalog></vn-order-catalog>');
|
||||||
controller = $componentController('vnOrderCatalog', {$element, $scope});
|
controller = $componentController('vnOrderCatalog', {$element, $scope});
|
||||||
controller._order = {id: 4};
|
controller._order = {id: 4};
|
||||||
|
controller.$params = {
|
||||||
|
categoryId: 1,
|
||||||
|
typeId: 2,
|
||||||
|
id: 4
|
||||||
|
};
|
||||||
}));
|
}));
|
||||||
|
|
||||||
describe('order() setter', () => {
|
describe('order() setter', () => {
|
||||||
|
@ -112,18 +115,6 @@ describe('Order', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('itemId() setter', () => {
|
|
||||||
it(`should set itemId property and then call updateStateParams() and applyFilters() methods`, () => {
|
|
||||||
jest.spyOn(controller, 'updateStateParams');
|
|
||||||
jest.spyOn(controller, 'applyFilters');
|
|
||||||
|
|
||||||
controller.itemId = 1;
|
|
||||||
|
|
||||||
expect(controller.updateStateParams).toHaveBeenCalledWith();
|
|
||||||
expect(controller.applyFilters).toHaveBeenCalledWith();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('tags() setter', () => {
|
describe('tags() setter', () => {
|
||||||
it(`should set tags property and then call updateStateParams() and applyFilters() methods`, () => {
|
it(`should set tags property and then call updateStateParams() and applyFilters() methods`, () => {
|
||||||
jest.spyOn(controller, 'updateStateParams');
|
jest.spyOn(controller, 'updateStateParams');
|
||||||
|
@ -158,23 +149,27 @@ describe('Order', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('onSearchById()', () => {
|
describe('onSearch()', () => {
|
||||||
it(`should not filter by id if the event key code doesn't equals to 'Enter'`, () => {
|
it(`should apply a filter by item id an then call the applyFilters method`, () => {
|
||||||
jest.spyOn(controller, 'applyFilters');
|
jest.spyOn(controller, 'applyFilters');
|
||||||
|
|
||||||
controller.$.itemId.value = 1;
|
const itemId = 1;
|
||||||
controller.onSearchById({key: 'Tab'});
|
controller.onSearch({search: itemId});
|
||||||
|
|
||||||
expect(controller.applyFilters).not.toHaveBeenCalledWith();
|
expect(controller.applyFilters).toHaveBeenCalledWith({
|
||||||
|
'i.id': itemId
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it(`should filter by id if the event key code equals to 'Enter' an then call applyFilters()`, () => {
|
it(`should apply a filter by item name an then call the applyFilters method`, () => {
|
||||||
jest.spyOn(controller, 'applyFilters');
|
jest.spyOn(controller, 'applyFilters');
|
||||||
|
|
||||||
controller.$.itemId.value = 1;
|
const itemName = 'Bow';
|
||||||
controller.onSearchById({key: 'Enter'});
|
controller.onSearch({search: itemName});
|
||||||
|
|
||||||
expect(controller.applyFilters).toHaveBeenCalledWith();
|
expect(controller.applyFilters).toHaveBeenCalledWith({
|
||||||
|
'i.name': {like: `%${itemName}%`}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -224,7 +219,6 @@ describe('Order', () => {
|
||||||
|
|
||||||
controller._categoryId = 2;
|
controller._categoryId = 2;
|
||||||
controller._typeId = 4;
|
controller._typeId = 4;
|
||||||
controller._itemId = 1;
|
|
||||||
controller._tags = [
|
controller._tags = [
|
||||||
{tagFk: 11, value: 'Precission', tagSelection: {name: 'Category'}}
|
{tagFk: 11, value: 'Precission', tagSelection: {name: 'Category'}}
|
||||||
];
|
];
|
||||||
|
@ -232,7 +226,7 @@ describe('Order', () => {
|
||||||
value: 'Precission',
|
value: 'Precission',
|
||||||
tagFk: 11, tagSelection: {name: 'Category'}}
|
tagFk: 11, tagSelection: {name: 'Category'}}
|
||||||
]);
|
]);
|
||||||
let result = {categoryId: 2, typeId: 4, itemId: 1, tags: tags};
|
let result = {categoryId: 2, typeId: 4, tags: tags};
|
||||||
controller.updateStateParams();
|
controller.updateStateParams();
|
||||||
|
|
||||||
expect(controller.$state.go).toHaveBeenCalledWith('my.current.state', result);
|
expect(controller.$state.go).toHaveBeenCalledWith('my.current.state', result);
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
Name: Nombre
|
||||||
|
Search by item id or name: Buscar por id de artículo o nombre
|
|
@ -41,7 +41,7 @@
|
||||||
"order": "$ctrl.order"
|
"order": "$ctrl.order"
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
"url": "/catalog?categoryId&typeId&itemId&tags",
|
"url": "/catalog?q&categoryId&typeId&tags",
|
||||||
"state": "order.card.catalog",
|
"state": "order.card.catalog",
|
||||||
"component": "vn-order-catalog",
|
"component": "vn-order-catalog",
|
||||||
"description": "Catalog",
|
"description": "Catalog",
|
||||||
|
|
|
@ -3,6 +3,10 @@ module.exports = Self => {
|
||||||
Self.remoteMethodCtx('editableStates', {
|
Self.remoteMethodCtx('editableStates', {
|
||||||
description: 'Gets the editable states according the user role ',
|
description: 'Gets the editable states according the user role ',
|
||||||
accessType: 'READ',
|
accessType: 'READ',
|
||||||
|
accepts: {
|
||||||
|
arg: 'filter',
|
||||||
|
type: 'object'
|
||||||
|
},
|
||||||
returns: {
|
returns: {
|
||||||
type: ['Object'],
|
type: ['Object'],
|
||||||
root: true
|
root: true
|
||||||
|
@ -13,10 +17,10 @@ module.exports = Self => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Self.editableStates = async ctx => {
|
Self.editableStates = async(ctx, filter) => {
|
||||||
let userId = ctx.req.accessToken.userId;
|
let userId = ctx.req.accessToken.userId;
|
||||||
let models = Self.app.models;
|
let models = Self.app.models;
|
||||||
let statesList = await models.State.find();
|
let statesList = await models.State.find({where: filter.where});
|
||||||
|
|
||||||
let isProduction = await models.Account.hasRole(userId, 'production');
|
let isProduction = await models.Account.hasRole(userId, 'production');
|
||||||
let isSalesPerson = await models.Account.hasRole(userId, 'salesPerson');
|
let isSalesPerson = await models.Account.hasRole(userId, 'salesPerson');
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
const app = require('vn-loopback/server/server');
|
const app = require('vn-loopback/server/server');
|
||||||
|
|
||||||
describe('ticket editableStates()', () => {
|
describe('ticket editableStates()', () => {
|
||||||
|
const filter = {where: {name: {like: '%%'}}};
|
||||||
it('should return the expected state for the given role', async() => {
|
it('should return the expected state for the given role', async() => {
|
||||||
const productionRole = 49;
|
const productionRole = 49;
|
||||||
const ctx = {req: {accessToken: {userId: productionRole}}};
|
const ctx = {req: {accessToken: {userId: productionRole}}};
|
||||||
let result = await app.models.State.editableStates(ctx);
|
|
||||||
|
let result = await app.models.State.editableStates(ctx, filter);
|
||||||
let deliveredState = result.some(state => state.code == 'DELIVERED');
|
let deliveredState = result.some(state => state.code == 'DELIVERED');
|
||||||
|
|
||||||
expect(deliveredState).toBeTruthy();
|
expect(deliveredState).toBeTruthy();
|
||||||
|
@ -13,7 +15,7 @@ describe('ticket editableStates()', () => {
|
||||||
it(`should returns the expected states by a specific role`, async() => {
|
it(`should returns the expected states by a specific role`, async() => {
|
||||||
const productionRole = 18;
|
const productionRole = 18;
|
||||||
const ctx = {req: {accessToken: {userId: productionRole}}};
|
const ctx = {req: {accessToken: {userId: productionRole}}};
|
||||||
let result = await app.models.State.editableStates(ctx);
|
let result = await app.models.State.editableStates(ctx, filter);
|
||||||
let deliveredState = result.some(state => state.code == 'DELIVERED');
|
let deliveredState = result.some(state => state.code == 'DELIVERED');
|
||||||
let pickerDesignedState = result.some(state => state.code == 'PICKER_DESIGNED');
|
let pickerDesignedState = result.some(state => state.code == 'PICKER_DESIGNED');
|
||||||
|
|
||||||
|
@ -24,7 +26,7 @@ describe('ticket editableStates()', () => {
|
||||||
it(`should return again the expected state by a specific role`, async() => {
|
it(`should return again the expected state by a specific role`, async() => {
|
||||||
const employeeRole = 1;
|
const employeeRole = 1;
|
||||||
const ctx = {req: {accessToken: {userId: employeeRole}}};
|
const ctx = {req: {accessToken: {userId: employeeRole}}};
|
||||||
let result = await app.models.State.editableStates(ctx);
|
let result = await app.models.State.editableStates(ctx, filter);
|
||||||
let pickerDesignedState = result.some(state => state.code == 'PICKER_DESIGNED');
|
let pickerDesignedState = result.some(state => state.code == 'PICKER_DESIGNED');
|
||||||
|
|
||||||
expect(pickerDesignedState).toBeFalsy();
|
expect(pickerDesignedState).toBeFalsy();
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
|
|
||||||
module.exports = Self => {
|
module.exports = Self => {
|
||||||
Self.remoteMethod('deleteStowaway', {
|
Self.remoteMethodCtx('deleteStowaway', {
|
||||||
description: 'Deletes an stowaway',
|
description: 'Deletes an stowaway',
|
||||||
accessType: 'WRITE',
|
accessType: 'WRITE',
|
||||||
accepts: [{
|
accepts: [{
|
||||||
|
@ -19,21 +19,66 @@ module.exports = Self => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Self.deleteStowaway = async id => {
|
Self.deleteStowaway = async(ctx, id) => {
|
||||||
|
const models = Self.app.models;
|
||||||
|
const $t = ctx.req.__; // $translate
|
||||||
const ticket = await Self.findById(id, {
|
const ticket = await Self.findById(id, {
|
||||||
include: [{
|
include: [{
|
||||||
relation: 'ship'
|
relation: 'ship'
|
||||||
}, {
|
}, {
|
||||||
relation: 'stowaway'
|
relation: 'stowaway'
|
||||||
|
}, {
|
||||||
|
relation: 'client',
|
||||||
|
scope: {
|
||||||
|
include: {
|
||||||
|
relation: 'salesPerson'
|
||||||
|
}
|
||||||
|
}
|
||||||
}]
|
}]
|
||||||
});
|
});
|
||||||
|
|
||||||
let params;
|
let stowawayFk;
|
||||||
if (ticket.stowaway())
|
let shipFk;
|
||||||
params = [ticket.stowaway().shipFk, ticket.stowaway().id];
|
if (ticket.stowaway()) {
|
||||||
else if (ticket.ship())
|
shipFk = ticket.stowaway().shipFk;
|
||||||
params = [ticket.ship().shipFk, ticket.ship().id];
|
stowawayFk = ticket.stowaway().id;
|
||||||
|
} else if (ticket.ship()) {
|
||||||
|
shipFk = ticket.ship().shipFk;
|
||||||
|
stowawayFk = ticket.ship().id;
|
||||||
|
}
|
||||||
|
|
||||||
return Self.rawSql(`CALL vn.stowaway_unboarding(?, ?)`, params);
|
const stowaway = await models.Stowaway.findOne({
|
||||||
|
where: {
|
||||||
|
id: stowawayFk,
|
||||||
|
shipFk: shipFk
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const result = await stowaway.destroy();
|
||||||
|
|
||||||
|
const state = await models.State.findOne({
|
||||||
|
where: {
|
||||||
|
code: 'BOARDING'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const ticketTracking = await models.TicketTracking.findOne({
|
||||||
|
where: {
|
||||||
|
ticketFk: shipFk,
|
||||||
|
stateFk: state.id
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
await ticketTracking.destroy();
|
||||||
|
|
||||||
|
const salesPerson = ticket.client().salesPerson();
|
||||||
|
if (salesPerson) {
|
||||||
|
const origin = ctx.req.headers.origin;
|
||||||
|
const message = $t('This ticket is not an stowaway anymore', {
|
||||||
|
ticketId: stowawayFk,
|
||||||
|
ticketUrl: `${origin}/#!/ticket/${stowawayFk}/summary`
|
||||||
|
});
|
||||||
|
await models.Chat.sendCheckingPresence(ctx, salesPerson.id, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -23,6 +23,7 @@ module.exports = Self => {
|
||||||
|
|
||||||
Self.setDeleted = async(ctx, id) => {
|
Self.setDeleted = async(ctx, id) => {
|
||||||
const models = Self.app.models;
|
const models = Self.app.models;
|
||||||
|
const userId = ctx.req.accessToken.userId;
|
||||||
const isEditable = await Self.isEditable(ctx, id);
|
const isEditable = await Self.isEditable(ctx, id);
|
||||||
const $t = ctx.req.__; // $translate
|
const $t = ctx.req.__; // $translate
|
||||||
|
|
||||||
|
@ -30,16 +31,30 @@ module.exports = Self => {
|
||||||
throw new UserError(`The sales of this ticket can't be modified`);
|
throw new UserError(`The sales of this ticket can't be modified`);
|
||||||
|
|
||||||
// Check if has sales with shelving
|
// Check if has sales with shelving
|
||||||
|
const isSalesAssistant = await models.Account.hasRole(userId, 'salesAssistant');
|
||||||
const sales = await models.Sale.find({
|
const sales = await models.Sale.find({
|
||||||
include: {relation: 'itemShelving'},
|
include: {relation: 'itemShelvingSale'},
|
||||||
where: {ticketFk: id}
|
where: {ticketFk: id}
|
||||||
});
|
});
|
||||||
const hasItemShelvingSales = sales.some(sale => {
|
const hasItemShelvingSales = sales.some(sale => {
|
||||||
return sale.itemShelving();
|
return sale.itemShelvingSale();
|
||||||
});
|
});
|
||||||
if (hasItemShelvingSales)
|
|
||||||
|
if (hasItemShelvingSales && !isSalesAssistant)
|
||||||
throw new UserError(`You cannot delete a ticket that part of it is being prepared`);
|
throw new UserError(`You cannot delete a ticket that part of it is being prepared`);
|
||||||
|
|
||||||
|
if (hasItemShelvingSales && isSalesAssistant) {
|
||||||
|
const promises = [];
|
||||||
|
for (let sale of sales) {
|
||||||
|
if (sale.itemShelvingSale()) {
|
||||||
|
const itemShelvingSale = sale.itemShelvingSale();
|
||||||
|
const destroyedShelving = models.ItemShelvingSale.destroyById(itemShelvingSale.id);
|
||||||
|
promises.push(destroyedShelving);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await Promise.all(promises);
|
||||||
|
}
|
||||||
|
|
||||||
// Check for existing claim
|
// Check for existing claim
|
||||||
const claimOfATicket = await models.Claim.findOne({where: {ticketFk: id}});
|
const claimOfATicket = await models.Claim.findOne({where: {ticketFk: id}});
|
||||||
if (claimOfATicket)
|
if (claimOfATicket)
|
||||||
|
|
|
@ -3,40 +3,100 @@ const app = require('vn-loopback/server/server');
|
||||||
describe('ticket deleteStowaway()', () => {
|
describe('ticket deleteStowaway()', () => {
|
||||||
const shipId = 16;
|
const shipId = 16;
|
||||||
const stowawayId = 17;
|
const stowawayId = 17;
|
||||||
|
const ctx = {
|
||||||
|
req: {
|
||||||
|
accessToken: {userId: 18},
|
||||||
|
headers: {origin: 'http://localhost'}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
ctx.req.__ = (value, params) => {
|
||||||
|
return params.nickname;
|
||||||
|
};
|
||||||
|
|
||||||
|
afterAll(async() => {
|
||||||
|
await app.models.Stowaway.rawSql(
|
||||||
|
`CALL ticketStateUpdate(?, ?)`, [shipId, 'OK']);
|
||||||
|
await app.models.Stowaway.rawSql(
|
||||||
|
`CALL ticketStateUpdate(?, ?)`, [stowawayId, 'OK']);
|
||||||
|
});
|
||||||
|
|
||||||
it('should create an stowaway', async() => {
|
it('should create an stowaway', async() => {
|
||||||
await app.models.Stowaway.rawSql(`
|
await app.models.Stowaway.rawSql(`
|
||||||
INSERT INTO stowaway (id, shipFk) VALUES (?, ?)
|
INSERT INTO stowaway (id, shipFk) VALUES (?, ?)
|
||||||
`, [stowawayId, shipId]);
|
`, [stowawayId, shipId]);
|
||||||
|
await app.models.Stowaway.rawSql(
|
||||||
|
`CALL ticketStateUpdate(?, ?)`, [shipId, 'BOARDING']);
|
||||||
|
|
||||||
const stowawayExists = await app.models.Stowaway.count({id: stowawayId, shipFk: shipId});
|
const stowawayExists = await app.models.Stowaway.count({id: stowawayId, shipFk: shipId});
|
||||||
|
|
||||||
expect(stowawayExists).toEqual(1);
|
expect(stowawayExists).toEqual(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should confirm that the ship ticket is on "BOARDING" state', async() => {
|
||||||
|
const shipState = await app.models.TicketLastState.findOne({
|
||||||
|
where: {
|
||||||
|
ticketFk: shipId
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(shipState.name).toEqual('Embarcando');
|
||||||
|
});
|
||||||
|
|
||||||
it('should delete the stowaway from the ship ticket', async() => {
|
it('should delete the stowaway from the ship ticket', async() => {
|
||||||
await app.models.Ticket.deleteStowaway(shipId);
|
await app.models.Ticket.deleteStowaway(ctx, shipId);
|
||||||
|
|
||||||
const stowawayExists = await app.models.Stowaway.count({id: stowawayId, shipFk: shipId});
|
const stowawayExists = await app.models.Stowaway.count({id: stowawayId, shipFk: shipId});
|
||||||
|
|
||||||
expect(stowawayExists).toEqual(0);
|
expect(stowawayExists).toEqual(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should confirm that the ship ticket is not on "BOARDING" state anymore', async() => {
|
||||||
|
const shipState = await app.models.TicketLastState.findOne({
|
||||||
|
where: {
|
||||||
|
ticketFk: shipId
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(shipState.name).toEqual('OK');
|
||||||
|
});
|
||||||
|
|
||||||
it('should create again an stowaway', async() => {
|
it('should create again an stowaway', async() => {
|
||||||
await app.models.Stowaway.rawSql(`
|
await app.models.Stowaway.rawSql(`
|
||||||
INSERT INTO stowaway (id, shipFk) VALUES (?, ?)
|
INSERT INTO stowaway (id, shipFk) VALUES (?, ?)
|
||||||
`, [stowawayId, shipId]);
|
`, [shipId, stowawayId]);
|
||||||
|
await app.models.Stowaway.rawSql(
|
||||||
|
`CALL ticketStateUpdate(?, ?)`, [stowawayId, 'BOARDING']);
|
||||||
|
|
||||||
const stowawayExists = await app.models.Stowaway.count({id: stowawayId, shipFk: shipId});
|
const stowawayExists = await app.models.Stowaway.count({id: shipId, shipFk: stowawayId});
|
||||||
|
|
||||||
expect(stowawayExists).toEqual(1);
|
expect(stowawayExists).toEqual(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should delete the stowaway from the stowaway ticket', async() => {
|
it('should confirm that the stowaway ticket is on "BOARDING" state', async() => {
|
||||||
await app.models.Ticket.deleteStowaway(stowawayId);
|
const shipState = await app.models.TicketLastState.findOne({
|
||||||
|
where: {
|
||||||
|
ticketFk: stowawayId
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const stowawayExists = await app.models.Stowaway.count({id: stowawayId, shipFk: shipId});
|
expect(shipState.name).toEqual('Embarcando');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should delete the stowaway from the stowaway ticket', async() => {
|
||||||
|
await app.models.Ticket.deleteStowaway(ctx, stowawayId);
|
||||||
|
|
||||||
|
const stowawayExists = await app.models.Stowaway.count({id: shipId, shipFk: stowawayId});
|
||||||
|
|
||||||
expect(stowawayExists).toEqual(0);
|
expect(stowawayExists).toEqual(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should confirm that the stowaway ticket is not on "BOARDING" state anymore', async() => {
|
||||||
|
const shipState = await app.models.TicketLastState.findOne({
|
||||||
|
where: {
|
||||||
|
ticketFk: stowawayId
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(shipState.name).toEqual('OK');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,29 +1,33 @@
|
||||||
const app = require('vn-loopback/server/server');
|
const app = require('vn-loopback/server/server');
|
||||||
|
const models = app.models;
|
||||||
|
|
||||||
describe('ticket deleted()', () => {
|
describe('ticket deleted()', () => {
|
||||||
let ticket;
|
let ticket;
|
||||||
let ctx;
|
let sale;
|
||||||
|
|
||||||
beforeAll(async done => {
|
beforeAll(async done => {
|
||||||
let originalTicket = await app.models.Ticket.findOne({where: {id: 16}});
|
let originalTicket = await models.Ticket.findOne({where: {id: 16}});
|
||||||
originalTicket.id = null;
|
originalTicket.id = null;
|
||||||
ticket = await app.models.Ticket.create(originalTicket);
|
ticket = await models.Ticket.create(originalTicket);
|
||||||
|
sale = await models.Sale.create({
|
||||||
|
ticketFk: ticket.id,
|
||||||
|
itemFk: 4,
|
||||||
|
concept: 'Melee weapon',
|
||||||
|
quantity: 10
|
||||||
|
});
|
||||||
|
|
||||||
ctx = {
|
await models.ItemShelvingSale.create({
|
||||||
req: {
|
itemShelvingFk: 1,
|
||||||
accessToken: {userId: 106},
|
saleFk: sale.id,
|
||||||
headers: {
|
quantity: 10,
|
||||||
origin: 'http://localhost:5000'
|
userFk: 106
|
||||||
},
|
});
|
||||||
__: () => {}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(async done => {
|
afterAll(async done => {
|
||||||
await app.models.Ticket.destroyById(ticket.id);
|
await models.Ticket.destroyById(ticket.id);
|
||||||
|
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
@ -32,16 +36,62 @@ describe('ticket deleted()', () => {
|
||||||
expect(ticket.isDeleted).toEqual(false);
|
expect(ticket.isDeleted).toEqual(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should set a ticket to deleted', async() => {
|
it('should make sure the ticket sale has an item shelving', async() => {
|
||||||
|
const sales = await models.Sale.find({
|
||||||
|
include: {relation: 'itemShelvingSale'},
|
||||||
|
where: {ticketFk: ticket.id}
|
||||||
|
});
|
||||||
|
const hasItemShelvingSales = sales.some(sale => {
|
||||||
|
return sale.itemShelvingSale();
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(hasItemShelvingSales).toEqual(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set a ticket to deleted and remove all item shelvings', async() => {
|
||||||
|
const salesAssistantId = 21;
|
||||||
|
const ctx = {
|
||||||
|
req: {
|
||||||
|
accessToken: {userId: salesAssistantId},
|
||||||
|
headers: {
|
||||||
|
origin: 'http://localhost:5000'
|
||||||
|
},
|
||||||
|
__: () => {}
|
||||||
|
}
|
||||||
|
};
|
||||||
await app.models.Ticket.setDeleted(ctx, ticket.id);
|
await app.models.Ticket.setDeleted(ctx, ticket.id);
|
||||||
|
|
||||||
let deletedTicket = await app.models.Ticket.findOne({where: {id: ticket.id}, fields: ['isDeleted']});
|
let deletedTicket = await app.models.Ticket.findOne({
|
||||||
|
where: {id: ticket.id},
|
||||||
|
fields: ['isDeleted']
|
||||||
|
});
|
||||||
|
|
||||||
expect(deletedTicket.isDeleted).toEqual(true);
|
expect(deletedTicket.isDeleted).toEqual(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should not have any item shelving', async() => {
|
||||||
|
const sales = await models.Sale.find({
|
||||||
|
include: {relation: 'itemShelvingSale'},
|
||||||
|
where: {ticketFk: ticket.id}
|
||||||
|
});
|
||||||
|
const hasItemShelvingSales = sales.some(sale => {
|
||||||
|
return sale.itemShelvingSale();
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(hasItemShelvingSales).toEqual(false);
|
||||||
|
});
|
||||||
|
|
||||||
it('should throw an error if the given ticket has a claim', async() => {
|
it('should throw an error if the given ticket has a claim', async() => {
|
||||||
let ticketId = 16;
|
const ticketId = 16;
|
||||||
|
const ctx = {
|
||||||
|
req: {
|
||||||
|
accessToken: {userId: 106},
|
||||||
|
headers: {
|
||||||
|
origin: 'http://localhost:5000'
|
||||||
|
},
|
||||||
|
__: () => {}
|
||||||
|
}
|
||||||
|
};
|
||||||
let error;
|
let error;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -56,6 +56,9 @@
|
||||||
"TicketState":{
|
"TicketState":{
|
||||||
"dataSource": "vn"
|
"dataSource": "vn"
|
||||||
},
|
},
|
||||||
|
"TicketLastState":{
|
||||||
|
"dataSource": "vn"
|
||||||
|
},
|
||||||
"TicketService":{
|
"TicketService":{
|
||||||
"dataSource": "vn"
|
"dataSource": "vn"
|
||||||
},
|
},
|
||||||
|
|
|
@ -73,7 +73,7 @@
|
||||||
"model": "SaleTracking",
|
"model": "SaleTracking",
|
||||||
"foreignKey": "saleFk"
|
"foreignKey": "saleFk"
|
||||||
},
|
},
|
||||||
"itemShelving": {
|
"itemShelvingSale": {
|
||||||
"type": "hasOne",
|
"type": "hasOne",
|
||||||
"model": "ItemShelvingSale",
|
"model": "ItemShelvingSale",
|
||||||
"foreignKey": "saleFk"
|
"foreignKey": "saleFk"
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
{
|
||||||
|
"name": "TicketLastState",
|
||||||
|
"base": "VnModel",
|
||||||
|
"options": {
|
||||||
|
"mysql": {
|
||||||
|
"table": "ticketLastState"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"ticketFk": {
|
||||||
|
"id": 1,
|
||||||
|
"type": "Number"
|
||||||
|
},
|
||||||
|
"ticketTrackingFk": {
|
||||||
|
"id": 2,
|
||||||
|
"type": "Number"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"relations": {
|
||||||
|
"ticket": {
|
||||||
|
"type": "belongsTo",
|
||||||
|
"model": "Ticket",
|
||||||
|
"foreignKey": "ticketFk"
|
||||||
|
},
|
||||||
|
"ticketTracking": {
|
||||||
|
"type": "belongsTo",
|
||||||
|
"model": "TicketTracking",
|
||||||
|
"foreignKey": "ticketTrackingFk"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -29,7 +29,7 @@ export default class Controller extends Section {
|
||||||
}
|
}
|
||||||
|
|
||||||
get checked() {
|
get checked() {
|
||||||
const tickets = this.$.tickets || [];
|
const tickets = this.$.model.data || [];
|
||||||
const checkedLines = [];
|
const checkedLines = [];
|
||||||
for (let ticket of tickets) {
|
for (let ticket of tickets) {
|
||||||
if (ticket.checked)
|
if (ticket.checked)
|
||||||
|
|
|
@ -88,7 +88,7 @@ describe('Component vnTicketIndex', () => {
|
||||||
controller.$.balanceCreateDialog = {show: () => {}};
|
controller.$.balanceCreateDialog = {show: () => {}};
|
||||||
jest.spyOn(controller.$.balanceCreateDialog, 'show').mockReturnThis();
|
jest.spyOn(controller.$.balanceCreateDialog, 'show').mockReturnThis();
|
||||||
|
|
||||||
controller.$.tickets = tickets;
|
controller.$.model = {data: tickets};
|
||||||
controller.$.balanceCreateDialog.amountPaid = 0;
|
controller.$.balanceCreateDialog.amountPaid = 0;
|
||||||
controller.openBalanceDialog();
|
controller.openBalanceDialog();
|
||||||
|
|
||||||
|
@ -102,7 +102,7 @@ describe('Component vnTicketIndex', () => {
|
||||||
|
|
||||||
describe('checked()', () => {
|
describe('checked()', () => {
|
||||||
it('should return an array of checked tickets', () => {
|
it('should return an array of checked tickets', () => {
|
||||||
controller.$.tickets = tickets;
|
controller.$.model = {data: tickets};
|
||||||
const result = controller.checked;
|
const result = controller.checked;
|
||||||
const firstRow = result[0];
|
const firstRow = result[0];
|
||||||
const secondRow = result[1];
|
const secondRow = result[1];
|
||||||
|
@ -115,7 +115,7 @@ describe('Component vnTicketIndex', () => {
|
||||||
|
|
||||||
describe('totalChecked()', () => {
|
describe('totalChecked()', () => {
|
||||||
it('should return the total number of checked tickets', () => {
|
it('should return the total number of checked tickets', () => {
|
||||||
controller.$.tickets = tickets;
|
controller.$.model = {data: tickets};
|
||||||
const result = controller.checked;
|
const result = controller.checked;
|
||||||
|
|
||||||
expect(result.length).toEqual(2);
|
expect(result.length).toEqual(2);
|
||||||
|
|
|
@ -45,10 +45,59 @@
|
||||||
</form>
|
</form>
|
||||||
</vn-side-menu>
|
</vn-side-menu>
|
||||||
|
|
||||||
|
<vn-crud-model vn-id="zoneModel"
|
||||||
|
url="Zones"
|
||||||
|
filter="::$ctrl.filter"
|
||||||
|
limit="20"
|
||||||
|
data="zones"
|
||||||
|
auto-load="false">
|
||||||
|
</vn-crud-model>
|
||||||
|
|
||||||
<!-- Zone Popover -->
|
<!-- Zone Popover -->
|
||||||
<vn-popover vn-id="zoneEvents">
|
<vn-popover vn-id="zoneEvents">
|
||||||
<div class="zoneEvents">
|
<div class="zoneEvents">
|
||||||
<div class="header vn-pa-sm" translate>Zones</div>
|
<div class="header vn-pa-sm" translate>Zones</div>
|
||||||
<vn-zone-index vn-id="zoneIndex"></vn-zone-index>
|
<vn-data-viewer
|
||||||
|
model="zoneModel"
|
||||||
|
class="vn-w-md vn-mb-xl">
|
||||||
|
<vn-card>
|
||||||
|
<vn-table model="zoneModel">
|
||||||
|
<vn-thead>
|
||||||
|
<vn-tr>
|
||||||
|
<vn-th field="id" number>Id</vn-th>
|
||||||
|
<vn-th field="name" expand>Name</vn-th>
|
||||||
|
<vn-th field="agencyModeFk">Agency</vn-th>
|
||||||
|
<vn-th field="hour" shrink>Closing</vn-th>
|
||||||
|
<vn-th field="price" number>Price</vn-th>
|
||||||
|
<vn-th shrink></vn-th>
|
||||||
|
</vn-tr>
|
||||||
|
</vn-thead>
|
||||||
|
<vn-tbody>
|
||||||
|
<vn-tr
|
||||||
|
ng-repeat="zone in zoneModel.data"
|
||||||
|
ui-sref="zone.card.summary({id: zone.id})"
|
||||||
|
class="clickable search-result">
|
||||||
|
<vn-td number>{{::zone.id}}</vn-td>
|
||||||
|
<vn-td expand>{{::zone.name}}</vn-td>
|
||||||
|
<vn-td>{{::zone.agencyMode.name}}</vn-td>
|
||||||
|
<vn-td shrink>{{::zone.hour | date: 'HH:mm'}}</vn-td>
|
||||||
|
<vn-td number>{{::zone.price | currency: 'EUR':2}}</vn-td>
|
||||||
|
<vn-td shrink>
|
||||||
|
<vn-horizontal class="buttons">
|
||||||
|
<vn-icon-button
|
||||||
|
ng-click="$ctrl.preview($event, zone)"
|
||||||
|
vn-tooltip="Preview"
|
||||||
|
icon="desktop_windows">
|
||||||
|
</vn-icon-button>
|
||||||
|
</vn-horizontal>
|
||||||
|
</vn-td>
|
||||||
|
</vn-tr>
|
||||||
|
</vn-tbody>
|
||||||
|
</vn-table>
|
||||||
|
</vn-card>
|
||||||
|
</vn-data-viewer>
|
||||||
</div>
|
</div>
|
||||||
</vn-popover>
|
</vn-popover>
|
||||||
|
<vn-popup vn-id="summary">
|
||||||
|
<vn-zone-summary zone="$ctrl.selectedZone"></vn-zone-summary>
|
||||||
|
</vn-popup>
|
|
@ -49,8 +49,7 @@ class Controller extends Section {
|
||||||
zones.push(event.zoneFk);
|
zones.push(event.zoneFk);
|
||||||
|
|
||||||
this.$.zoneEvents.show($event.target);
|
this.$.zoneEvents.show($event.target);
|
||||||
const zoneIndex = this.$.zoneIndex;
|
const zoneModel = this.$.zoneModel;
|
||||||
const zoneModel = zoneIndex.$scope.model;
|
|
||||||
zoneModel.applyFilter({
|
zoneModel.applyFilter({
|
||||||
include: {
|
include: {
|
||||||
relation: 'agencyMode',
|
relation: 'agencyMode',
|
||||||
|
@ -61,6 +60,12 @@ class Controller extends Section {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
preview(event, zone) {
|
||||||
|
this.stopEvent(event);
|
||||||
|
this.selectedZone = zone;
|
||||||
|
this.$.summary.show();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ngModule.component('vnZoneDeliveryDays', {
|
ngModule.component('vnZoneDeliveryDays', {
|
||||||
|
|
|
@ -14,12 +14,8 @@ describe('Zone Component vnZoneDeliveryDays', () => {
|
||||||
$element = angular.element('<vn-zone-delivery-days></vn-zone-delivery-days');
|
$element = angular.element('<vn-zone-delivery-days></vn-zone-delivery-days');
|
||||||
controller = $componentController('vnZoneDeliveryDays', {$element});
|
controller = $componentController('vnZoneDeliveryDays', {$element});
|
||||||
controller.$.zoneEvents = popover;
|
controller.$.zoneEvents = popover;
|
||||||
controller.$.zoneIndex = {
|
|
||||||
$scope: {
|
|
||||||
model: crudModel
|
|
||||||
}
|
|
||||||
};
|
|
||||||
controller.$.params = {};
|
controller.$.params = {};
|
||||||
|
controller.$.zoneModel = crudModel;
|
||||||
}));
|
}));
|
||||||
|
|
||||||
describe('deliveryMethodFk() setter', () => {
|
describe('deliveryMethodFk() setter', () => {
|
||||||
|
@ -80,7 +76,7 @@ describe('Zone Component vnZoneDeliveryDays', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should call the show() method and then call the applyFilter() method with the expected ids', () => {
|
it('should call the show() method and then call the applyFilter() method with the expected ids', () => {
|
||||||
const zoneModel = controller.$.zoneIndex.$scope.model;
|
const zoneModel = controller.$.zoneModel;
|
||||||
jest.spyOn(controller.$.zoneEvents, 'show');
|
jest.spyOn(controller.$.zoneEvents, 'show');
|
||||||
jest.spyOn(zoneModel, 'applyFilter');
|
jest.spyOn(zoneModel, 'applyFilter');
|
||||||
|
|
||||||
|
|
|
@ -19,11 +19,7 @@ vn-zone-delivery-days {
|
||||||
.zoneEvents {
|
.zoneEvents {
|
||||||
width: 700px;
|
width: 700px;
|
||||||
max-height: 450px;
|
max-height: 450px;
|
||||||
|
|
||||||
vn-float-button {
|
|
||||||
display: none
|
|
||||||
}
|
|
||||||
|
|
||||||
vn-data-viewer {
|
vn-data-viewer {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
vn-pagination {
|
vn-pagination {
|
||||||
|
|
Loading…
Reference in New Issue