feat: refs #6900 drop section #2863
|
@ -1,28 +0,0 @@
|
|||
import selectors from '../../helpers/selectors.js';
|
||||
import getBrowser from '../../helpers/puppeteer';
|
||||
|
||||
describe('InvoiceIn summary path', () => {
|
||||
let browser;
|
||||
let page;
|
||||
|
||||
beforeAll(async() => {
|
||||
browser = await getBrowser();
|
||||
page = browser.page;
|
||||
await page.loginAndModule('administrative', 'invoiceIn');
|
||||
await page.accessToSearchResult('1');
|
||||
});
|
||||
|
||||
afterAll(async() => {
|
||||
await browser.close();
|
||||
});
|
||||
|
||||
it('should reach the summary section', async() => {
|
||||
await page.waitForState('invoiceIn.card.summary');
|
||||
});
|
||||
|
||||
it('should contain some basic data from the invoice', async() => {
|
||||
const result = await page.waitToGetProperty(selectors.invoiceInSummary.supplierRef, 'innerText');
|
||||
|
||||
expect(result).toEqual('1234');
|
||||
});
|
||||
});
|
|
@ -1,52 +0,0 @@
|
|||
import selectors from '../../helpers/selectors.js';
|
||||
import getBrowser from '../../helpers/puppeteer';
|
||||
|
||||
describe('InvoiceIn descriptor path', () => {
|
||||
let browser;
|
||||
let page;
|
||||
|
||||
beforeAll(async() => {
|
||||
browser = await getBrowser();
|
||||
page = browser.page;
|
||||
await page.loginAndModule('administrative', 'invoiceIn');
|
||||
await page.accessToSearchResult('10');
|
||||
await page.accessToSection('invoiceIn.card.basicData');
|
||||
});
|
||||
|
||||
afterAll(async() => {
|
||||
await browser.close();
|
||||
});
|
||||
|
||||
it('should clone the invoiceIn using the descriptor more menu', async() => {
|
||||
await page.waitToClick(selectors.invoiceInDescriptor.moreMenu);
|
||||
await page.waitToClick(selectors.invoiceInDescriptor.moreMenuCloneInvoiceIn);
|
||||
await page.waitToClick(selectors.invoiceInDescriptor.acceptButton);
|
||||
const message = await page.waitForSnackbar();
|
||||
|
||||
expect(message.text).toContain('InvoiceIn cloned');
|
||||
});
|
||||
|
||||
it('should have been redirected to the created invoiceIn summary', async() => {
|
||||
await page.waitForState('invoiceIn.card.summary');
|
||||
});
|
||||
|
||||
it('should delete the cloned invoiceIn using the descriptor more menu', async() => {
|
||||
await page.waitToClick(selectors.invoiceInDescriptor.moreMenu);
|
||||
await page.waitToClick(selectors.invoiceInDescriptor.moreMenuDeleteInvoiceIn);
|
||||
await page.waitToClick(selectors.invoiceInDescriptor.acceptButton);
|
||||
const message = await page.waitForSnackbar();
|
||||
|
||||
expect(message.text).toContain('InvoiceIn deleted');
|
||||
});
|
||||
|
||||
it('should have been relocated to the invoiceOut index', async() => {
|
||||
await page.waitForState('invoiceIn.index');
|
||||
});
|
||||
|
||||
it(`should search for the deleted invouceOut to find no results`, async() => {
|
||||
await page.doSearch('10');
|
||||
const nResults = await page.countElement(selectors.invoiceOutIndex.searchResult);
|
||||
|
||||
expect(nResults).toEqual(0);
|
||||
});
|
||||
});
|
|
@ -1,196 +0,0 @@
|
|||
import selectors from '../../helpers/selectors.js';
|
||||
import getBrowser from '../../helpers/puppeteer';
|
||||
|
||||
describe('InvoiceIn basic data path', () => {
|
||||
let browser;
|
||||
let page;
|
||||
let newDms;
|
||||
|
||||
beforeAll(async() => {
|
||||
browser = await getBrowser();
|
||||
page = browser.page;
|
||||
await page.loginAndModule('administrative', 'invoiceIn');
|
||||
await page.accessToSearchResult('1');
|
||||
await page.accessToSection('invoiceIn.card.basicData');
|
||||
});
|
||||
|
||||
afterAll(async() => {
|
||||
await browser.close();
|
||||
});
|
||||
|
||||
it(`should edit the invoiceIn basic data`, async() => {
|
||||
const now = Date.vnNew();
|
||||
await page.pickDate(selectors.invoiceInBasicData.issued, now);
|
||||
await page.pickDate(selectors.invoiceInBasicData.operated, now);
|
||||
await page.autocompleteSearch(selectors.invoiceInBasicData.supplier, 'Verdnatura');
|
||||
await page.clearInput(selectors.invoiceInBasicData.supplierRef);
|
||||
await page.write(selectors.invoiceInBasicData.supplierRef, '9999');
|
||||
await page.clearInput(selectors.invoiceInBasicData.dms);
|
||||
await page.write(selectors.invoiceInBasicData.dms, '2');
|
||||
await page.pickDate(selectors.invoiceInBasicData.bookEntried, now);
|
||||
await page.pickDate(selectors.invoiceInBasicData.booked, now);
|
||||
await page.autocompleteSearch(selectors.invoiceInBasicData.currency, 'USD');
|
||||
await page.autocompleteSearch(selectors.invoiceInBasicData.company, 'ORN');
|
||||
await page.waitToClick(selectors.invoiceInBasicData.save);
|
||||
const message = await page.waitForSnackbar();
|
||||
|
||||
expect(message.text).toContain('Data saved!');
|
||||
});
|
||||
|
||||
it(`should confirm the invoiceIn supplier was edited`, async() => {
|
||||
await page.reloadSection('invoiceIn.card.basicData');
|
||||
const result = await page.waitToGetProperty(selectors.invoiceInBasicData.supplier, 'value');
|
||||
|
||||
expect(result).toContain('Verdnatura');
|
||||
});
|
||||
|
||||
it(`should confirm the invoiceIn supplierRef was edited`, async() => {
|
||||
const result = await page
|
||||
.waitToGetProperty(selectors.invoiceInBasicData.supplierRef, 'value');
|
||||
|
||||
expect(result).toEqual('9999');
|
||||
});
|
||||
|
||||
it(`should confirm the invoiceIn currency was edited`, async() => {
|
||||
const result = await page
|
||||
.waitToGetProperty(selectors.invoiceInBasicData.currency, 'value');
|
||||
|
||||
expect(result).toEqual('USD');
|
||||
});
|
||||
|
||||
it(`should confirm the invoiceIn company was edited`, async() => {
|
||||
const result = await page
|
||||
.waitToGetProperty(selectors.invoiceInBasicData.company, 'value');
|
||||
|
||||
expect(result).toEqual('ORN');
|
||||
});
|
||||
|
||||
it(`should confirm the invoiceIn dms was edited`, async() => {
|
||||
const result = await page
|
||||
.waitToGetProperty(selectors.invoiceInBasicData.dms, 'value');
|
||||
|
||||
expect(result).toEqual('2');
|
||||
});
|
||||
|
||||
it(`should create a new invoiceIn dms and save the changes`, async() => {
|
||||
await page.clearInput(selectors.invoiceInBasicData.dms);
|
||||
await page.waitToClick(selectors.invoiceInBasicData.create);
|
||||
|
||||
await page.clearInput(selectors.invoiceInBasicData.reference);
|
||||
await page.write(selectors.invoiceInBasicData.reference, 'New Dms');
|
||||
|
||||
await page.waitToClick(selectors.invoiceInBasicData.confirm);
|
||||
let message = await page.waitForSnackbar();
|
||||
|
||||
await page.clearInput(selectors.invoiceInBasicData.companyId);
|
||||
await page.autocompleteSearch(selectors.invoiceInBasicData.companyId, 'VNL');
|
||||
|
||||
await page.waitToClick(selectors.invoiceInBasicData.confirm);
|
||||
message = await page.waitForSnackbar();
|
||||
|
||||
await page.clearInput(selectors.invoiceInBasicData.warehouseId);
|
||||
await page.autocompleteSearch(selectors.invoiceInBasicData.warehouseId, 'Warehouse One');
|
||||
|
||||
await page.waitToClick(selectors.invoiceInBasicData.confirm);
|
||||
message = await page.waitForSnackbar();
|
||||
|
||||
await page.clearInput(selectors.invoiceInBasicData.dmsTypeId);
|
||||
await page.autocompleteSearch(selectors.invoiceInBasicData.dmsTypeId, 'Ticket');
|
||||
|
||||
await page.waitToClick(selectors.invoiceInBasicData.confirm);
|
||||
message = await page.waitForSnackbar();
|
||||
|
||||
await page.waitToClick(selectors.invoiceInBasicData.description);
|
||||
await page.write(selectors.invoiceInBasicData.description, 'Dms without edition.');
|
||||
|
||||
await page.waitToClick(selectors.invoiceInBasicData.confirm);
|
||||
message = await page.waitForSnackbar();
|
||||
|
||||
expect(message.text).toContain('The files can\'t be empty');
|
||||
|
||||
let currentDir = process.cwd();
|
||||
let filePath = `${currentDir}/e2e/assets/thermograph.jpeg`;
|
||||
|
||||
const [fileChooser] = await Promise.all([
|
||||
page.waitForFileChooser(),
|
||||
page.waitToClick(selectors.invoiceInBasicData.inputFile)
|
||||
]);
|
||||
await fileChooser.accept([filePath]);
|
||||
|
||||
await page.waitToClick(selectors.invoiceInBasicData.confirm);
|
||||
message = await page.waitForSnackbar();
|
||||
|
||||
expect(message.text).toContain('Data saved!');
|
||||
|
||||
newDms = await page
|
||||
.waitToGetProperty(selectors.invoiceInBasicData.dms, 'value');
|
||||
});
|
||||
|
||||
it(`should confirm the invoiceIn was edited with the new dms`, async() => {
|
||||
await page.reloadSection('invoiceIn.card.basicData');
|
||||
const result = await page
|
||||
.waitToGetProperty(selectors.invoiceInBasicData.dms, 'value');
|
||||
|
||||
expect(result).toEqual(newDms);
|
||||
});
|
||||
|
||||
it(`should edit the invoiceIn`, async() => {
|
||||
await page.waitToClick(selectors.invoiceInBasicData.edit);
|
||||
|
||||
await page.clearInput(selectors.invoiceInBasicData.reference);
|
||||
await page.write(selectors.invoiceInBasicData.reference, 'Dms Edited');
|
||||
await page.clearInput(selectors.invoiceInBasicData.companyId);
|
||||
await page.autocompleteSearch(selectors.invoiceInBasicData.companyId, 'CCs');
|
||||
await page.clearInput(selectors.invoiceInBasicData.warehouseId);
|
||||
await page.autocompleteSearch(selectors.invoiceInBasicData.warehouseId, 'Algemesi');
|
||||
await page.clearInput(selectors.invoiceInBasicData.dmsTypeId);
|
||||
await page.autocompleteSearch(selectors.invoiceInBasicData.dmsTypeId, 'Basura');
|
||||
await page.waitToClick(selectors.invoiceInBasicData.description);
|
||||
await page.write(selectors.invoiceInBasicData.description, ' Nevermind, now is edited.');
|
||||
|
||||
await page.waitToClick(selectors.invoiceInBasicData.confirm);
|
||||
let message = await page.waitForSnackbar();
|
||||
|
||||
expect(message.text).toContain('Data saved!');
|
||||
});
|
||||
|
||||
it(`should confirm the new dms has been edited`, async() => {
|
||||
await page.reloadSection('invoiceIn.card.basicData');
|
||||
await page.waitToClick(selectors.invoiceInBasicData.edit);
|
||||
|
||||
const reference = await page
|
||||
.waitToGetProperty(selectors.invoiceInBasicData.reference, 'value');
|
||||
const companyId = await page
|
||||
.waitToGetProperty(selectors.invoiceInBasicData.companyId, 'value');
|
||||
const warehouseId = await page
|
||||
.waitToGetProperty(selectors.invoiceInBasicData.warehouseId, 'value');
|
||||
const dmsTypeId = await page
|
||||
.waitToGetProperty(selectors.invoiceInBasicData.dmsTypeId, 'value');
|
||||
const description = await page
|
||||
.waitToGetProperty(selectors.invoiceInBasicData.description, 'value');
|
||||
|
||||
expect(reference).toEqual('Dms Edited');
|
||||
expect(companyId).toEqual('CCs');
|
||||
expect(warehouseId).toEqual('Algemesi');
|
||||
expect(dmsTypeId).toEqual('Basura');
|
||||
expect(description).toEqual('Dms without edition. Nevermind, now is edited.');
|
||||
|
||||
await page.waitToClick(selectors.invoiceInBasicData.confirm);
|
||||
});
|
||||
|
||||
it(`should disable edit and download if dms doesn't exists, and set back the original dms`, async() => {
|
||||
await page.clearInput(selectors.invoiceInBasicData.dms);
|
||||
await page.write(selectors.invoiceInBasicData.dms, '9999');
|
||||
|
||||
await page.waitForSelector(`${selectors.invoiceInBasicData.download}.disabled`);
|
||||
await page.waitForSelector(`${selectors.invoiceInBasicData.edit}.disabled`);
|
||||
|
||||
await page.clearInput(selectors.invoiceInBasicData.dms);
|
||||
await page.write(selectors.invoiceInBasicData.dms, '1');
|
||||
|
||||
await page.waitToClick(selectors.invoiceInBasicData.save);
|
||||
const message = await page.waitForSnackbar();
|
||||
|
||||
expect(message.text).toContain('Data saved!');
|
||||
});
|
||||
});
|
|
@ -1,59 +0,0 @@
|
|||
import selectors from '../../helpers/selectors.js';
|
||||
import getBrowser from '../../helpers/puppeteer';
|
||||
|
||||
describe('InvoiceIn tax path', () => {
|
||||
let browser;
|
||||
let page;
|
||||
|
||||
beforeAll(async() => {
|
||||
browser = await getBrowser();
|
||||
page = browser.page;
|
||||
await page.loginAndModule('developer', 'invoiceIn');
|
||||
await page.accessToSearchResult('2');
|
||||
await page.accessToSection('invoiceIn.card.tax');
|
||||
});
|
||||
|
||||
afterAll(async() => {
|
||||
await browser.close();
|
||||
});
|
||||
|
||||
it('should add a new tax and check it', async() => {
|
||||
await page.waitToClick(selectors.invoiceInTax.addTaxButton);
|
||||
await page.autocompleteSearch(selectors.invoiceInTax.thirdExpense, '6210000567');
|
||||
await page.write(selectors.invoiceInTax.thirdTaxableBase, '100');
|
||||
await page.autocompleteSearch(selectors.invoiceInTax.thirdTaxType, 'H.P. IVA');
|
||||
await page.autocompleteSearch(selectors.invoiceInTax.thirdTransactionType, 'Operaciones exentas');
|
||||
await page.waitToClick(selectors.invoiceInTax.saveButton);
|
||||
const message = await page.waitForSnackbar();
|
||||
|
||||
await page.waitToClick(selectors.invoiceInDescriptor.summaryIcon);
|
||||
await page.waitForState('invoiceIn.card.summary');
|
||||
const total = await page.waitToGetProperty(selectors.invoiceInSummary.totalTaxableBase, 'innerText');
|
||||
|
||||
await page.accessToSection('invoiceIn.card.tax');
|
||||
|
||||
const thirdExpense = await page.waitToGetProperty(selectors.invoiceInTax.thirdExpense, 'value');
|
||||
const thirdTaxableBase = await page.waitToGetProperty(selectors.invoiceInTax.thirdTaxableBase, 'value');
|
||||
const thirdTaxType = await page.waitToGetProperty(selectors.invoiceInTax.thirdTaxType, 'value');
|
||||
const thirdTransactionType = await page.waitToGetProperty(selectors.invoiceInTax.thirdTransactionType, 'value');
|
||||
const thirdRate = await page.waitToGetProperty(selectors.invoiceInTax.thirdRate, 'value');
|
||||
|
||||
expect(message.text).toContain('Data saved!');
|
||||
|
||||
expect(total).toEqual('Taxable base €1,323.16');
|
||||
|
||||
expect(thirdExpense).toEqual('6210000567');
|
||||
expect(thirdTaxableBase).toEqual('100');
|
||||
expect(thirdTaxType).toEqual('H.P. IVA 4% CEE');
|
||||
expect(thirdTransactionType).toEqual('Operaciones exentas');
|
||||
expect(thirdRate).toEqual('€4.00');
|
||||
});
|
||||
|
||||
it('should delete the added line', async() => {
|
||||
await page.waitToClick(selectors.invoiceInTax.thirdDeleteButton);
|
||||
await page.waitToClick(selectors.invoiceInTax.saveButton);
|
||||
const message = await page.waitForSnackbar();
|
||||
|
||||
expect(message.text).toContain('Data saved!');
|
||||
});
|
||||
});
|
|
@ -1,48 +0,0 @@
|
|||
import selectors from '../../helpers/selectors.js';
|
||||
import getBrowser from '../../helpers/puppeteer';
|
||||
|
||||
describe('InvoiceIn serial path', () => {
|
||||
let browser;
|
||||
let page;
|
||||
let httpRequest;
|
||||
|
||||
beforeAll(async() => {
|
||||
browser = await getBrowser();
|
||||
page = browser.page;
|
||||
await page.loginAndModule('administrative', 'invoiceIn');
|
||||
await page.accessToSection('invoiceIn.serial');
|
||||
page.on('request', req => {
|
||||
if (req.url().includes(`InvoiceIns/getSerial`))
|
||||
httpRequest = req.url();
|
||||
});
|
||||
});
|
||||
|
||||
afterAll(async() => {
|
||||
await browser.close();
|
||||
});
|
||||
|
||||
it('should check that passes the correct params to back', async() => {
|
||||
await page.overwrite(selectors.invoiceInSerial.daysAgo, '30');
|
||||
await page.keyboard.press('Enter');
|
||||
|
||||
expect(httpRequest).toContain('daysAgo=30');
|
||||
|
||||
await page.overwrite(selectors.invoiceInSerial.serial, 'R');
|
||||
await page.keyboard.press('Enter');
|
||||
|
||||
expect(httpRequest).toContain('serial=R');
|
||||
await page.click(selectors.invoiceInSerial.chip);
|
||||
});
|
||||
|
||||
it('should go to index and check if the search-panel has the correct params', async() => {
|
||||
await page.waitToClick(selectors.invoiceInSerial.goToIndex);
|
||||
const params = await page.$$(selectors.invoiceInIndex.topbarSearchParams);
|
||||
const serial = await params[0].getProperty('title');
|
||||
const isBooked = await params[1].getProperty('title');
|
||||
const from = await params[2].getProperty('title');
|
||||
|
||||
expect(await serial.jsonValue()).toContain('serial');
|
||||
expect(await isBooked.jsonValue()).toContain('not isBooked');
|
||||
expect(await from.jsonValue()).toContain('from');
|
||||
});
|
||||
});
|
|
@ -1,315 +0,0 @@
|
|||
<mg-ajax path="InvoiceIns/{{patch.params.id}}/updateInvoiceIn" options="vnPatch"></mg-ajax>
|
||||
<vn-watcher
|
||||
vn-id="watcher"
|
||||
data="$ctrl.invoiceIn"
|
||||
form="form"
|
||||
save="patch">
|
||||
</vn-watcher>
|
||||
<vn-crud-model
|
||||
auto-load="true"
|
||||
url="Companies"
|
||||
data="companies"
|
||||
order="code">
|
||||
</vn-crud-model>
|
||||
<vn-crud-model
|
||||
auto-load="true"
|
||||
url="Warehouses"
|
||||
data="warehouses"
|
||||
order="name">
|
||||
</vn-crud-model>
|
||||
<vn-crud-model
|
||||
auto-load="true"
|
||||
url="DmsTypes"
|
||||
data="dmsTypes"
|
||||
order="name">
|
||||
</vn-crud-model>
|
||||
<form name="form" ng-submit="watcher.submit()" class="vn-w-md">
|
||||
<vn-card class="vn-pa-lg">
|
||||
<vn-horizontal>
|
||||
<vn-autocomplete
|
||||
vn-one
|
||||
ng-model="$ctrl.invoiceIn.supplierFk"
|
||||
url="Suppliers"
|
||||
show-field="nickname"
|
||||
search-function="{or: [{id: $search}, {nickname: {like: '%'+ $search +'%'}}]}"
|
||||
value-field="id"
|
||||
order="nickname"
|
||||
label="Supplier"
|
||||
required="true"
|
||||
rule>
|
||||
<tpl-item>
|
||||
{{::id}} - {{::nickname}}
|
||||
</tpl-item>
|
||||
</vn-autocomplete>
|
||||
<vn-textfield
|
||||
label="Supplier ref"
|
||||
ng-model="$ctrl.invoiceIn.supplierRef"
|
||||
rule>
|
||||
</vn-textfield>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-date-picker
|
||||
vn-one
|
||||
label="Expedition date"
|
||||
ng-model="$ctrl.invoiceIn.issued"
|
||||
vn-focus
|
||||
rule>
|
||||
</vn-date-picker>
|
||||
<vn-date-picker
|
||||
vn-one
|
||||
label="Operation date"
|
||||
ng-model="$ctrl.invoiceIn.operated"
|
||||
rule>
|
||||
</vn-date-picker>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-datalist vn-one
|
||||
label="Undeductible VAT"
|
||||
ng-model="$ctrl.invoiceIn.deductibleExpenseFk"
|
||||
value-field="id"
|
||||
order="name"
|
||||
url="Expenses"
|
||||
fields="['id','name']"
|
||||
rule>
|
||||
<tpl-item>
|
||||
{{id}} - {{name}}
|
||||
</tpl-item>
|
||||
</vn-datalist>
|
||||
<vn-textfield
|
||||
label="Document"
|
||||
ng-model="$ctrl.invoiceIn.dmsFk"
|
||||
ng-change="$ctrl.checkFileExists($ctrl.invoiceIn.dmsFk)"
|
||||
rule>
|
||||
<prepend>
|
||||
<vn-icon-button
|
||||
disabled="$ctrl.editDownloadDisabled"
|
||||
ng-if="$ctrl.invoiceIn.dmsFk"
|
||||
title="{{'Download file' | translate}}"
|
||||
icon="cloud_download"
|
||||
ng-click="$ctrl.downloadFile($ctrl.invoiceIn.dmsFk)">
|
||||
</vn-icon-button>
|
||||
</prepend>
|
||||
<append>
|
||||
<vn-icon-button
|
||||
disabled="$ctrl.editDownloadDisabled"
|
||||
ng-if="$ctrl.invoiceIn.dmsFk"
|
||||
ng-click="$ctrl.openEditDialog($ctrl.invoiceIn.dmsFk)"
|
||||
icon="edit"
|
||||
title="{{'Edit document' | translate}}">
|
||||
</vn-icon-button>
|
||||
<vn-icon-button
|
||||
ng-if="!$ctrl.invoiceIn.dmsFk"
|
||||
ng-click="$ctrl.openCreateDialog()"
|
||||
icon="add_circle"
|
||||
title="{{'Create document' | translate}}">
|
||||
</vn-icon-button>
|
||||
</append>
|
||||
</vn-textfield>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-date-picker
|
||||
vn-one
|
||||
label="Entry date"
|
||||
ng-model="$ctrl.invoiceIn.bookEntried"
|
||||
rule>
|
||||
</vn-date-picker>
|
||||
<vn-date-picker
|
||||
vn-one
|
||||
label="Accounted date"
|
||||
ng-model="$ctrl.invoiceIn.booked"
|
||||
rule>
|
||||
</vn-date-picker>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-autocomplete
|
||||
vn-one
|
||||
label="Currency"
|
||||
ng-model="$ctrl.invoiceIn.currencyFk"
|
||||
url="Currencies"
|
||||
show-field="code"
|
||||
value-field="id"
|
||||
rule>
|
||||
</vn-autocomplete>
|
||||
<vn-autocomplete
|
||||
url="Companies"
|
||||
label="Company"
|
||||
show-field="code"
|
||||
value-field="id"
|
||||
ng-model="$ctrl.invoiceIn.companyFk"
|
||||
rule>
|
||||
</vn-autocomplete>
|
||||
</vn-horizontal>
|
||||
</vn-card>
|
||||
<vn-button-bar>
|
||||
<vn-submit
|
||||
disabled="!watcher.dataChanged()"
|
||||
label="Save">
|
||||
</vn-submit>
|
||||
<vn-button
|
||||
class="cancel"
|
||||
label="Undo changes"
|
||||
disabled="!watcher.dataChanged()"
|
||||
ng-click="watcher.loadOriginalData()">
|
||||
</vn-button>
|
||||
</vn-button-bar>
|
||||
</form>
|
||||
<!-- Create edit dms dialog -->
|
||||
<vn-dialog
|
||||
vn-id="dmsEditDialog"
|
||||
message="Edit document"
|
||||
on-accept="$ctrl.onEdit()">
|
||||
<tpl-body>
|
||||
<vn-horizontal>
|
||||
<vn-textfield
|
||||
vn-one
|
||||
vn-focus
|
||||
label="Reference"
|
||||
ng-model="$ctrl.dms.reference"
|
||||
rule>
|
||||
</vn-textfield>
|
||||
<vn-autocomplete vn-one required="true"
|
||||
label="Company"
|
||||
ng-model="$ctrl.dms.companyId"
|
||||
url="Companies"
|
||||
show-field="code"
|
||||
value-field="id">
|
||||
</vn-autocomplete>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-autocomplete vn-one required="true"
|
||||
label="Warehouse"
|
||||
ng-model="$ctrl.dms.warehouseId"
|
||||
url="Warehouses"
|
||||
show-field="name"
|
||||
value-field="id">
|
||||
</vn-autocomplete>
|
||||
<vn-autocomplete vn-one required="true"
|
||||
label="Type"
|
||||
ng-model="$ctrl.dms.dmsTypeId"
|
||||
url="DmsTypes"
|
||||
show-field="name"
|
||||
value-field="id">
|
||||
</vn-autocomplete>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-textarea
|
||||
vn-one
|
||||
required="true"
|
||||
label="Description"
|
||||
ng-model="$ctrl.dms.description"
|
||||
rule>
|
||||
</vn-textarea>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-input-file
|
||||
vn-one
|
||||
label="File"
|
||||
ng-model="$ctrl.dms.files"
|
||||
on-change="$ctrl.onFileChange($files)"
|
||||
accept="{{$ctrl.allowedContentTypes}}"
|
||||
required="false"
|
||||
multiple="true">
|
||||
<append>
|
||||
<vn-icon vn-none
|
||||
color-marginal
|
||||
title="{{$ctrl.contentTypesInfo}}"
|
||||
icon="info">
|
||||
</vn-icon>
|
||||
</append>
|
||||
</vn-input-file>
|
||||
</vn-horizontal>
|
||||
<vn-vertical>
|
||||
<vn-check disabled="true"
|
||||
label="Generate identifier for original file"
|
||||
ng-model="$ctrl.dms.hasFile">
|
||||
</vn-check>
|
||||
</vn-vertical>
|
||||
</tpl-body>
|
||||
<tpl-buttons>
|
||||
<input type="button" response="cancel" translate-attr="{value: 'Cancel'}"/>
|
||||
<button response="accept" translate>Save</button>
|
||||
</tpl-buttons>
|
||||
</vn-dialog>
|
||||
<!-- Create new dms dialog -->
|
||||
<vn-dialog
|
||||
vn-id="dmsCreateDialog"
|
||||
message="Create document"
|
||||
on-accept="$ctrl.onCreate()">
|
||||
<tpl-body>
|
||||
<vn-horizontal>
|
||||
<vn-textfield
|
||||
vn-one
|
||||
vn-focus
|
||||
label="Reference"
|
||||
ng-model="$ctrl.dms.reference"
|
||||
rule>
|
||||
</vn-textfield>
|
||||
<vn-autocomplete
|
||||
vn-one
|
||||
label="Company"
|
||||
ng-model="$ctrl.dms.companyId"
|
||||
data="companies"
|
||||
show-field="code"
|
||||
value-field="id"
|
||||
required="true">
|
||||
</vn-autocomplete>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-autocomplete
|
||||
vn-one
|
||||
label="Warehouse"
|
||||
ng-model="$ctrl.dms.warehouseId"
|
||||
data="warehouses"
|
||||
show-field="name"
|
||||
value-field="id"
|
||||
required="true">
|
||||
</vn-autocomplete>
|
||||
<vn-autocomplete
|
||||
vn-one
|
||||
label="Type"
|
||||
ng-model="$ctrl.dms.dmsTypeId"
|
||||
data="dmsTypes"
|
||||
show-field="name"
|
||||
value-field="id"
|
||||
required="true">
|
||||
</vn-autocomplete>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-textarea
|
||||
vn-one
|
||||
label="Description"
|
||||
ng-model="$ctrl.dms.description"
|
||||
required="true"
|
||||
rule>
|
||||
</vn-textarea>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-input-file
|
||||
vn-one
|
||||
label="File"
|
||||
ng-model="$ctrl.dms.files"
|
||||
on-change="$ctrl.onFileChange($files)"
|
||||
accept="{{$ctrl.allowedContentTypes}}"
|
||||
required="true"
|
||||
multiple="true">
|
||||
<append>
|
||||
<vn-icon vn-none
|
||||
color-marginal
|
||||
title="{{$ctrl.contentTypesInfo}}"
|
||||
icon="info">
|
||||
</vn-icon>
|
||||
</append>
|
||||
</vn-input-file>
|
||||
</vn-horizontal>
|
||||
<vn-vertical>
|
||||
<vn-check
|
||||
label="Generate identifier for original file"
|
||||
ng-model="$ctrl.dms.hasFile">
|
||||
</vn-check>
|
||||
</vn-vertical>
|
||||
</tpl-body>
|
||||
<tpl-buttons>
|
||||
<input type="button" response="cancel" translate-attr="{value: 'Cancel'}"/>
|
||||
<button response="accept" translate>Create</button>
|
||||
</tpl-buttons>
|
||||
</vn-dialog>
|
|
@ -1,187 +0,0 @@
|
|||
import ngModule from '../module';
|
||||
import Section from 'salix/components/section';
|
||||
import UserError from 'core/lib/user-error';
|
||||
|
||||
class Controller extends Section {
|
||||
constructor($element, $, vnFile) {
|
||||
super($element, $, vnFile);
|
||||
this.dms = {
|
||||
files: [],
|
||||
hasFile: false,
|
||||
hasFileAttached: false
|
||||
};
|
||||
this.vnFile = vnFile;
|
||||
this.getAllowedContentTypes();
|
||||
this._editDownloadDisabled = false;
|
||||
}
|
||||
|
||||
get contentTypesInfo() {
|
||||
return this.$t('ContentTypesInfo', {
|
||||
allowedContentTypes: this.allowedContentTypes
|
||||
});
|
||||
}
|
||||
|
||||
get editDownloadDisabled() {
|
||||
return this._editDownloadDisabled;
|
||||
}
|
||||
|
||||
async checkFileExists(dmsId) {
|
||||
if (!dmsId) return;
|
||||
let filter = {
|
||||
fields: ['id']
|
||||
};
|
||||
await this.$http.get(`Dms/${dmsId}`, {filter})
|
||||
.then(() => this._editDownloadDisabled = false)
|
||||
.catch(() => this._editDownloadDisabled = true);
|
||||
}
|
||||
|
||||
async getFile(dmsId) {
|
||||
const path = `Dms/${dmsId}`;
|
||||
await this.$http.get(path).then(res => {
|
||||
const dms = res.data && res.data;
|
||||
this.dms = {
|
||||
dmsId: dms.id,
|
||||
reference: dms.reference,
|
||||
warehouseId: dms.warehouseFk,
|
||||
companyId: dms.companyFk,
|
||||
dmsTypeId: dms.dmsTypeFk,
|
||||
description: dms.description,
|
||||
hasFile: dms.hasFile,
|
||||
hasFileAttached: false,
|
||||
files: []
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
getAllowedContentTypes() {
|
||||
this.$http.get('DmsContainers/allowedContentTypes').then(res => {
|
||||
if (res.data.length > 0) {
|
||||
const contentTypes = res.data.join(', ');
|
||||
this.allowedContentTypes = contentTypes;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
openEditDialog(dmsId) {
|
||||
this.getFile(dmsId).then(() => this.$.dmsEditDialog.show());
|
||||
}
|
||||
|
||||
openCreateDialog() {
|
||||
const params = {filter: {
|
||||
where: {code: 'invoiceIn'}
|
||||
}};
|
||||
this.$http.get('DmsTypes/findOne', {params}).then(res => {
|
||||
this.dms = {
|
||||
reference: this.invoiceIn.supplierRef,
|
||||
warehouseId: this.vnConfig.warehouseFk,
|
||||
companyId: this.vnConfig.companyFk,
|
||||
dmsTypeId: res.data.id,
|
||||
description: this.invoiceIn.supplier.name,
|
||||
hasFile: true,
|
||||
hasFileAttached: true,
|
||||
files: null
|
||||
};
|
||||
this.$.dmsCreateDialog.show();
|
||||
});
|
||||
}
|
||||
|
||||
downloadFile(dmsId) {
|
||||
this.vnFile.download(`api/dms/${dmsId}/downloadFile`);
|
||||
}
|
||||
|
||||
onFileChange(files) {
|
||||
let hasFileAttached = false;
|
||||
if (files.length > 0)
|
||||
hasFileAttached = true;
|
||||
|
||||
this.$.$applyAsync(() => {
|
||||
this.dms.hasFileAttached = hasFileAttached;
|
||||
});
|
||||
}
|
||||
|
||||
onEdit() {
|
||||
if (!this.dms.companyId)
|
||||
throw new UserError(`The company can't be empty`);
|
||||
if (!this.dms.warehouseId)
|
||||
throw new UserError(`The warehouse can't be empty`);
|
||||
if (!this.dms.dmsTypeId)
|
||||
throw new UserError(`The DMS Type can't be empty`);
|
||||
if (!this.dms.description)
|
||||
throw new UserError(`The description can't be empty`);
|
||||
|
||||
const query = `dms/${this.dms.dmsId}/updateFile`;
|
||||
const options = {
|
||||
method: 'POST',
|
||||
url: query,
|
||||
params: this.dms,
|
||||
headers: {
|
||||
'Content-Type': undefined
|
||||
},
|
||||
transformRequest: files => {
|
||||
const formData = new FormData();
|
||||
|
||||
for (let i = 0; i < files.length; i++)
|
||||
formData.append(files[i].name, files[i]);
|
||||
|
||||
return formData;
|
||||
},
|
||||
data: this.dms.files
|
||||
};
|
||||
|
||||
this.$http(options).then(res => {
|
||||
if (res) {
|
||||
this.vnApp.showSuccess(this.$t('Data saved!'));
|
||||
if (res.data.length > 0) this.invoiceIn.dmsFk = res.data[0].id;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
onCreate() {
|
||||
if (!this.dms.companyId)
|
||||
throw new UserError(`The company can't be empty`);
|
||||
if (!this.dms.warehouseId)
|
||||
throw new UserError(`The warehouse can't be empty`);
|
||||
if (!this.dms.dmsTypeId)
|
||||
throw new UserError(`The DMS Type can't be empty`);
|
||||
if (!this.dms.description)
|
||||
throw new UserError(`The description can't be empty`);
|
||||
if (!this.dms.files)
|
||||
throw new UserError(`The files can't be empty`);
|
||||
|
||||
const query = `Dms/uploadFile`;
|
||||
const options = {
|
||||
method: 'POST',
|
||||
url: query,
|
||||
params: this.dms,
|
||||
headers: {
|
||||
'Content-Type': undefined
|
||||
},
|
||||
transformRequest: files => {
|
||||
const formData = new FormData();
|
||||
|
||||
for (let i = 0; i < files.length; i++)
|
||||
formData.append(files[i].name, files[i]);
|
||||
|
||||
return formData;
|
||||
},
|
||||
data: this.dms.files
|
||||
};
|
||||
|
||||
this.$http(options).then(res => {
|
||||
if (res) {
|
||||
this.vnApp.showSuccess(this.$t('Data saved!'));
|
||||
if (res.data.length > 0) this.invoiceIn.dmsFk = res.data[0].id;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Controller.$inject = ['$element', '$scope', 'vnFile'];
|
||||
|
||||
ngModule.vnComponent('vnInvoiceInBasicData', {
|
||||
template: require('./index.html'),
|
||||
controller: Controller,
|
||||
bindings: {
|
||||
invoiceIn: '<'
|
||||
}
|
||||
});
|
|
@ -1,102 +0,0 @@
|
|||
import './index.js';
|
||||
import watcher from 'core/mocks/watcher';
|
||||
|
||||
describe('InvoiceIn', () => {
|
||||
describe('Component vnInvoiceInBasicData', () => {
|
||||
let controller;
|
||||
let $scope;
|
||||
let $httpBackend;
|
||||
let $httpParamSerializer;
|
||||
|
||||
beforeEach(ngModule('invoiceIn'));
|
||||
|
||||
beforeEach(inject(($componentController, $rootScope, _$httpBackend_, _$httpParamSerializer_) => {
|
||||
$scope = $rootScope.$new();
|
||||
$httpBackend = _$httpBackend_;
|
||||
$httpParamSerializer = _$httpParamSerializer_;
|
||||
const $element = angular.element('<vn-invoice-in-basic-data></vn-invoice-in-basic-data>');
|
||||
controller = $componentController('vnInvoiceInBasicData', {$element, $scope});
|
||||
controller.$.watcher = watcher;
|
||||
$httpBackend.expect('GET', `DmsContainers/allowedContentTypes`).respond({});
|
||||
}));
|
||||
|
||||
describe('onFileChange()', () => {
|
||||
it('should set dms hasFileAttached property to true if has any files', () => {
|
||||
const files = [{id: 1, name: 'MyFile'}];
|
||||
controller.onFileChange(files);
|
||||
|
||||
$scope.$apply();
|
||||
|
||||
expect(controller.dms.hasFileAttached).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('checkFileExists()', () => {
|
||||
it(`should return false if a file exists`, () => {
|
||||
const fileIdExists = 1;
|
||||
controller.checkFileExists(fileIdExists);
|
||||
|
||||
expect(controller.editDownloadDisabled).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('onEdit()', () => {
|
||||
it(`should perform a POST query to edit the dms properties`, () => {
|
||||
jest.spyOn(controller.vnApp, 'showSuccess');
|
||||
|
||||
const dms = {
|
||||
dmsId: 1,
|
||||
reference: 'Ref1',
|
||||
warehouseId: 1,
|
||||
companyId: 442,
|
||||
dmsTypeId: 20,
|
||||
description: 'This is a description',
|
||||
files: []
|
||||
};
|
||||
|
||||
controller.dms = dms;
|
||||
const serializedParams = $httpParamSerializer(controller.dms);
|
||||
const query = `dms/${controller.dms.dmsId}/updateFile?${serializedParams}`;
|
||||
|
||||
$httpBackend.expectPOST(query).respond({});
|
||||
controller.onEdit();
|
||||
$httpBackend.flush();
|
||||
|
||||
expect(controller.vnApp.showSuccess).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('onCreate()', () => {
|
||||
it(`should perform a POST query to create a new dms`, () => {
|
||||
jest.spyOn(controller.vnApp, 'showSuccess');
|
||||
|
||||
const dms = {
|
||||
reference: 'Ref1',
|
||||
warehouseId: 1,
|
||||
companyId: 442,
|
||||
dmsTypeId: 20,
|
||||
description: 'This is a description',
|
||||
files: [{
|
||||
lastModified: 1668673957761,
|
||||
lastModifiedDate: Date.vnNew(),
|
||||
name: 'file-example.png',
|
||||
size: 19653,
|
||||
type: 'image/png',
|
||||
webkitRelativePath: ''
|
||||
}]
|
||||
};
|
||||
|
||||
controller.dms = dms;
|
||||
const serializedParams = $httpParamSerializer(controller.dms);
|
||||
const query = `Dms/uploadFile?${serializedParams}`;
|
||||
|
||||
$httpBackend.expectPOST(query).respond({});
|
||||
controller.onCreate();
|
||||
$httpBackend.flush();
|
||||
|
||||
expect(controller.vnApp.showSuccess).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -1 +0,0 @@
|
|||
ContentTypesInfo: Allowed file types {{allowedContentTypes}}
|
|
@ -1,15 +0,0 @@
|
|||
Upload file: Subir fichero
|
||||
Edit file: Editar fichero
|
||||
Upload: Subir
|
||||
Document: Documento
|
||||
ContentTypesInfo: "Tipos de archivo permitidos: {{allowedContentTypes}}"
|
||||
Generate identifier for original file: Generar identificador para archivo original
|
||||
File management: Gestión documental
|
||||
Hard copy: Copia
|
||||
This file will be deleted: Este fichero va a ser borrado
|
||||
Are you sure?: Estas seguro?
|
||||
File deleted: Fichero eliminado
|
||||
Remove file: Eliminar fichero
|
||||
Download file: Descargar fichero
|
||||
Edit document: Editar documento
|
||||
Create document: Crear documento
|
|
@ -1,55 +0,0 @@
|
|||
<vn-watcher
|
||||
vn-id="watcher"
|
||||
url="InvoiceIns"
|
||||
data="$ctrl.invoiceIn"
|
||||
insert-mode="true"
|
||||
form="form">
|
||||
</vn-watcher>
|
||||
<form name="form" vn-http-submit="$ctrl.onSubmit()" class="vn-w-md">
|
||||
<div class="vn-w-md">
|
||||
<vn-card class="vn-pa-lg">
|
||||
<vn-autocomplete
|
||||
vn-focus
|
||||
vn-id="supplier"
|
||||
url="Suppliers"
|
||||
label="Supplier"
|
||||
search-function="{or: [{id: $search}, {name: {like: '%'+ $search +'%'}}, {nif: {like: '%'+ $search +'%'}}]}"
|
||||
fields="['nif']"
|
||||
show-field="name"
|
||||
value-field="id"
|
||||
ng-model="$ctrl.invoiceIn.supplierFk"
|
||||
order="id"
|
||||
vn-focus>
|
||||
<tpl-item>{{id}}: {{nif}}: {{name}}</tpl-item>
|
||||
</vn-autocomplete>
|
||||
<vn-textfield
|
||||
vn-one
|
||||
label="supplierRef"
|
||||
ng-model="$ctrl.invoiceIn.supplierRef">
|
||||
</vn-textfield>
|
||||
<vn-date-picker
|
||||
label="Issued"
|
||||
ng-model="$ctrl.invoiceIn.issued">
|
||||
</vn-date-picker>
|
||||
<vn-autocomplete
|
||||
vn-one
|
||||
label="Company"
|
||||
ng-model="$ctrl.companyFk"
|
||||
url="companies"
|
||||
show-field="code"
|
||||
value-field="id">
|
||||
</vn-autocomplete>
|
||||
</vn-card>
|
||||
<vn-button-bar>
|
||||
<vn-submit
|
||||
disabled="!watcher.dataChanged()"
|
||||
label="Create">
|
||||
</vn-submit>
|
||||
<vn-button
|
||||
class="cancel"
|
||||
label="Cancel"
|
||||
ui-sref="InvoiceIn.index">
|
||||
</vn-button>
|
||||
</vn-button-bar>
|
||||
</div>
|
||||
</form>
|
|
@ -1,30 +0,0 @@
|
|||
import ngModule from '../module';
|
||||
import Section from 'salix/components/section';
|
||||
|
||||
class Controller extends Section {
|
||||
$onInit() {
|
||||
this.invoiceIn = {};
|
||||
if (this.$params && this.$params.supplierFk)
|
||||
this.invoiceIn.supplierFk = this.$params.supplierFk;
|
||||
this.invoiceIn.issued = Date.vnNew();
|
||||
}
|
||||
|
||||
get companyFk() {
|
||||
return this.invoiceIn.companyFk || this.vnConfig.companyFk;
|
||||
}
|
||||
|
||||
set companyFk(value) {
|
||||
this.invoiceIn.companyFk = value;
|
||||
}
|
||||
|
||||
onSubmit() {
|
||||
this.$.watcher.submit().then(
|
||||
res => this.$state.go('invoiceIn.card.basicData', {id: res.data.id})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ngModule.vnComponent('vnInvoiceInCreate', {
|
||||
template: require('./index.html'),
|
||||
controller: Controller
|
||||
});
|
|
@ -1 +0,0 @@
|
|||
a:a
|
|
@ -1,71 +0,0 @@
|
|||
<vn-crud-model
|
||||
vn-id="model"
|
||||
url="InvoiceInDueDays"
|
||||
data="InvoiceInDueDaysData"
|
||||
link="{invoiceInFk: $ctrl.$params.id}"
|
||||
auto-load="true">
|
||||
</vn-crud-model>
|
||||
<vn-watcher
|
||||
vn-id="watcher"
|
||||
data="InvoiceInDueDaysData"
|
||||
form="form">
|
||||
</vn-watcher>
|
||||
<form name="form" ng-submit="$ctrl.onSubmit()">
|
||||
<vn-card class="vn-pa-lg">
|
||||
<vn-horizontal ng-repeat="invoiceInDueDay in InvoiceInDueDaysData">
|
||||
<vn-date-picker
|
||||
vn-one
|
||||
label="Date"
|
||||
ng-model="invoiceInDueDay.dueDated"
|
||||
vn-focus
|
||||
rule>
|
||||
</vn-date-picker>
|
||||
<vn-autocomplete vn-three
|
||||
label="Bank"
|
||||
ng-model="invoiceInDueDay.bankFk"
|
||||
url="Accountings"
|
||||
show-field="bank"
|
||||
select-fields="['id','bank']"
|
||||
order="id"
|
||||
search-function="$ctrl.bankSearchFunc($search)"
|
||||
rule>
|
||||
<tpl-item>{{id}}: {{bank}}</tpl-item>
|
||||
</vn-autocomplete>
|
||||
<vn-input-number vn-one
|
||||
label="Amount"
|
||||
ng-model="invoiceInDueDay.amount"
|
||||
step="0.01"
|
||||
rule
|
||||
vn-focus>
|
||||
</vn-input-number>
|
||||
<vn-input-number
|
||||
disabled="$ctrl.invoiceIn.currency.code == 'EUR'"
|
||||
label="Foreign value"
|
||||
ng-model="invoiceInDueDay.foreignValue"
|
||||
rule>
|
||||
</vn-input-number>
|
||||
<vn-none>
|
||||
<vn-icon-button
|
||||
vn-tooltip="Remove due day"
|
||||
icon="delete"
|
||||
ng-click="model.remove($index)"
|
||||
tabindex="-1">
|
||||
</vn-icon-button>
|
||||
</vn-none>
|
||||
</vn-horizontal>
|
||||
<vn-one>
|
||||
<vn-icon-button
|
||||
vn-bind="+"
|
||||
vn-tooltip="Add due day"
|
||||
icon="add_circle"
|
||||
ng-click="$ctrl.add()">
|
||||
</vn-icon-button>
|
||||
</vn-one>
|
||||
</vn-card>
|
||||
<vn-button-bar>
|
||||
<vn-submit
|
||||
disabled="!watcher.dataChanged()"
|
||||
label="Save">
|
||||
</vn-submit>
|
||||
</vn-button-bar>
|
||||
</form>
|
|
@ -1,37 +0,0 @@
|
|||
import ngModule from '../module';
|
||||
import Section from 'salix/components/section';
|
||||
|
||||
class Controller extends Section {
|
||||
add() {
|
||||
this.$.model.insert({
|
||||
dueDated: Date.vnNew(),
|
||||
bankFk: this.vnConfig.local.bankFk
|
||||
});
|
||||
}
|
||||
|
||||
onSubmit() {
|
||||
this.$.watcher.check();
|
||||
this.$.model.save().then(() => {
|
||||
this.$.watcher.notifySaved();
|
||||
this.$.watcher.updateOriginalData();
|
||||
this.card.reload();
|
||||
});
|
||||
}
|
||||
|
||||
bankSearchFunc($search) {
|
||||
return /^\d+$/.test($search)
|
||||
? {id: $search}
|
||||
: {bank: {like: '%' + $search + '%'}};
|
||||
}
|
||||
}
|
||||
|
||||
ngModule.vnComponent('vnInvoiceInDueDay', {
|
||||
template: require('./index.html'),
|
||||
controller: Controller,
|
||||
require: {
|
||||
card: '^vnInvoiceInCard'
|
||||
},
|
||||
bindings: {
|
||||
invoiceIn: '<'
|
||||
}
|
||||
});
|
|
@ -1,44 +0,0 @@
|
|||
import './index.js';
|
||||
import watcher from 'core/mocks/watcher';
|
||||
import crudModel from 'core/mocks/crud-model';
|
||||
|
||||
describe('InvoiceIn', () => {
|
||||
describe('Component due day', () => {
|
||||
let controller;
|
||||
let $scope;
|
||||
let vnApp;
|
||||
|
||||
beforeEach(ngModule('invoiceIn'));
|
||||
|
||||
beforeEach(inject(($componentController, $rootScope, _vnApp_) => {
|
||||
vnApp = _vnApp_;
|
||||
jest.spyOn(vnApp, 'showError');
|
||||
$scope = $rootScope.$new();
|
||||
$scope.model = crudModel;
|
||||
$scope.watcher = watcher;
|
||||
|
||||
const $element = angular.element('<vn-invoice-in-due-day></vn-invoice-in-due-day>');
|
||||
controller = $componentController('vnInvoiceInDueDay', {$element, $scope});
|
||||
controller.invoiceIn = {id: 1};
|
||||
}));
|
||||
|
||||
describe('onSubmit()', () => {
|
||||
it('should make HTTP POST request to save due day values', () => {
|
||||
controller.card = {reload: () => {}};
|
||||
jest.spyOn($scope.watcher, 'check');
|
||||
jest.spyOn($scope.watcher, 'notifySaved');
|
||||
jest.spyOn($scope.watcher, 'updateOriginalData');
|
||||
jest.spyOn(controller.card, 'reload');
|
||||
jest.spyOn($scope.model, 'save');
|
||||
|
||||
controller.onSubmit();
|
||||
|
||||
expect($scope.model.save).toHaveBeenCalledWith();
|
||||
expect($scope.watcher.updateOriginalData).toHaveBeenCalledWith();
|
||||
expect($scope.watcher.check).toHaveBeenCalledWith();
|
||||
expect($scope.watcher.notifySaved).toHaveBeenCalledWith();
|
||||
expect(controller.card.reload).toHaveBeenCalledWith();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,17 +1,7 @@
|
|||
export * from './module';
|
||||
|
||||
import './main';
|
||||
import './index/';
|
||||
import './search-panel';
|
||||
import './card';
|
||||
import './descriptor';
|
||||
import './descriptor-popover';
|
||||
import './summary';
|
||||
import './basic-data';
|
||||
import './tax';
|
||||
import './dueDay';
|
||||
import './intrastat';
|
||||
import './create';
|
||||
import './log';
|
||||
import './serial';
|
||||
import './serial-search-panel';
|
||||
|
|
|
@ -1,82 +0,0 @@
|
|||
<vn-auto-search
|
||||
model="model">
|
||||
</vn-auto-search>
|
||||
<vn-data-viewer
|
||||
model="model"
|
||||
class="vn-w-lg">
|
||||
<vn-card>
|
||||
<vn-table model="model">
|
||||
<vn-thead>
|
||||
<vn-tr>
|
||||
<vn-th field="id">ID</vn-th>
|
||||
<vn-th field="supplierFk">Supplier</vn-th>
|
||||
<vn-th field="supplierRef">Supplier ref.</vn-th>
|
||||
<vn-th field="serialNumber">Serial number</vn-th>
|
||||
<vn-th field="serial">Serial</vn-th>
|
||||
<vn-th field="dmsFk">File</vn-th>
|
||||
<vn-th field="issued" expand>Issued</vn-th>
|
||||
<vn-th field="isBooked" center>Is booked</vn-th>
|
||||
<vn-th field="awbCode" vn-tooltip="Air Waybill">AWB</vn-th>
|
||||
<vn-th field="amount" filter-enabled="false">Amount</vn-th>
|
||||
<vn-th></vn-th>
|
||||
</vn-tr>
|
||||
</vn-thead>
|
||||
<vn-tbody>
|
||||
<a
|
||||
ng-repeat="invoiceIn in model.data"
|
||||
class="clickable vn-tr search-result"
|
||||
ui-sref="invoiceIn.card.summary({id: {{::invoiceIn.id}}})">
|
||||
<vn-td>{{::invoiceIn.id}}</vn-td>
|
||||
<vn-td expand>
|
||||
<span
|
||||
class="link"
|
||||
vn-click-stop="supplierDescriptor.show($event, invoiceIn.supplierFk)">
|
||||
{{::invoiceIn.supplierName}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td>{{::invoiceIn.supplierRef | dashIfEmpty}}</vn-td>
|
||||
<vn-td>{{::invoiceIn.serialNumber}}</vn-td>
|
||||
<vn-td>{{::invoiceIn.serial}}</vn-td>
|
||||
<vn-td>
|
||||
<span title="{{'Download file' | translate}}" class="link"
|
||||
ng-click="$ctrl.downloadFile(invoiceIn.dmsFk)">
|
||||
{{::invoiceIn.file}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td expand>{{::invoiceIn.issued | date:'dd/MM/yyyy' | dashIfEmpty}}</vn-td>
|
||||
<vn-td center>
|
||||
<vn-check disabled="true"
|
||||
ng-model="invoiceIn.isBooked">
|
||||
</vn-check>
|
||||
</vn-td>
|
||||
<vn-td>{{::invoiceIn.awbCode}}</vn-td>
|
||||
<vn-td>{{::invoiceIn.amount | currency:'EUR'}}</vn-td>
|
||||
<vn-td shrink>
|
||||
<vn-icon-button
|
||||
vn-click-stop="$ctrl.preview(invoiceIn)"
|
||||
vn-tooltip="Preview"
|
||||
icon="preview">
|
||||
</vn-icon-button>
|
||||
</vn-td>
|
||||
<vn-td shrink>
|
||||
<!-- <vn-icon-button
|
||||
ng-show="invoiceIn.dmsFk"
|
||||
vn-click-stop="$ctrl.openPdf(invoiceIn.dmsFk)"
|
||||
icon="cloud_download"
|
||||
title="Download PDF"
|
||||
vn-tooltip="Download PDF">
|
||||
</vn-icon-button> -->
|
||||
</vn-td>
|
||||
</a>
|
||||
</vn-tbody>
|
||||
</vn-table>
|
||||
</vn-card>
|
||||
</vn-data-viewer>
|
||||
<vn-supplier-descriptor-popover
|
||||
vn-id="supplierDescriptor">
|
||||
</vn-supplier-descriptor-popover>
|
||||
<vn-popup vn-id="summary">
|
||||
<vn-invoice-in-summary
|
||||
invoice-in="$ctrl.selectedInvoiceIn">
|
||||
</vn-invoice-in-summary>
|
||||
</vn-popup>
|
|
@ -1,58 +0,0 @@
|
|||
import ngModule from '../module';
|
||||
import Section from 'salix/components/section';
|
||||
|
||||
export default class Controller extends Section {
|
||||
constructor($element, $, vnFile) {
|
||||
super($element, $, vnFile);
|
||||
this.vnFile = vnFile;
|
||||
}
|
||||
|
||||
exprBuilder(param, value) {
|
||||
switch (param) {
|
||||
case 'issued':
|
||||
return {'ii.issued': {
|
||||
between: this.dateRange(value)}
|
||||
};
|
||||
case 'id':
|
||||
case 'supplierFk':
|
||||
case 'supplierRef':
|
||||
case 'serialNumber':
|
||||
case 'serial':
|
||||
case 'created':
|
||||
case 'isBooked':
|
||||
return {[`ii.${param}`]: value};
|
||||
case 'account':
|
||||
case 'fi':
|
||||
return {[`s.${param}`]: value};
|
||||
case 'awbCode':
|
||||
return {'awb.code': value};
|
||||
default:
|
||||
return {[param]: value};
|
||||
}
|
||||
}
|
||||
|
||||
dateRange(value) {
|
||||
const minHour = new Date(value);
|
||||
minHour.setHours(0, 0, 0, 0);
|
||||
const maxHour = new Date(value);
|
||||
maxHour.setHours(23, 59, 59, 59);
|
||||
|
||||
return [minHour, maxHour];
|
||||
}
|
||||
|
||||
preview(invoiceIn) {
|
||||
this.selectedInvoiceIn = invoiceIn;
|
||||
this.$.summary.show();
|
||||
}
|
||||
|
||||
downloadFile(dmsId) {
|
||||
this.vnFile.download(`api/dms/${dmsId}/downloadFile`);
|
||||
}
|
||||
}
|
||||
|
||||
Controller.$inject = ['$element', '$scope', 'vnFile'];
|
||||
|
||||
ngModule.vnComponent('vnInvoiceInIndex', {
|
||||
template: require('./index.html'),
|
||||
controller: Controller
|
||||
});
|
|
@ -1,6 +0,0 @@
|
|||
Created: Fecha creación
|
||||
Issued: Fecha emisión
|
||||
Supplier ref.: Ref. proveedor
|
||||
Serial number: Num. serie
|
||||
Serial: Serie
|
||||
Is booked: Conciliada
|
|
@ -1,100 +0,0 @@
|
|||
<vn-crud-model
|
||||
vn-id="model"
|
||||
url="InvoiceInIntrastats"
|
||||
data="$ctrl.invoceInIntrastat"
|
||||
link="{invoiceInFk: $ctrl.$params.id}"
|
||||
auto-load="true"
|
||||
on-data-change="$ctrl.calculateTotals()">
|
||||
</vn-crud-model>
|
||||
<vn-crud-model
|
||||
auto-load="true"
|
||||
url="Countries"
|
||||
data="countries"
|
||||
order="name">
|
||||
</vn-crud-model>
|
||||
<vn-crud-model
|
||||
auto-load="true"
|
||||
url="Intrastats"
|
||||
data="intrastats"
|
||||
order="id">
|
||||
</vn-crud-model>
|
||||
<vn-watcher
|
||||
vn-id="watcher"
|
||||
data="$ctrl.invoceInIntrastat"
|
||||
form="form">
|
||||
</vn-watcher>
|
||||
<vn-card
|
||||
class="vn-mb-md vn-pa-lg vn-w-lg"
|
||||
style="text-align: right"
|
||||
ng-if="$ctrl.invoceInIntrastat.length > 0">
|
||||
<vn-label-value label="Total amount"
|
||||
value="{{$ctrl.amountTotal | currency: 'EUR':2}}">
|
||||
</vn-label-value>
|
||||
<vn-label-value label="Total net"
|
||||
value="{{$ctrl.netTotal}}">
|
||||
</vn-label-value>
|
||||
<vn-label-value label="Total stems"
|
||||
value="{{$ctrl.stemsTotal}}">
|
||||
</vn-label-value>
|
||||
</vn-card>
|
||||
<form name="form" ng-submit="$ctrl.onSubmit()">
|
||||
<vn-card class="vn-pa-lg">
|
||||
<vn-horizontal ng-repeat="intrastat in $ctrl.invoceInIntrastat">
|
||||
<vn-autocomplete vn-three
|
||||
label="Code"
|
||||
data="intrastats"
|
||||
ng-model="intrastat.intrastatFk"
|
||||
show-field="description"
|
||||
rule
|
||||
vn-focus>
|
||||
<tpl-item>{{id}}: {{description}}</tpl-item>
|
||||
</vn-autocomplete>
|
||||
<vn-input-number
|
||||
label="Amount"
|
||||
ng-model="intrastat.amount"
|
||||
step="0.01"
|
||||
rule>
|
||||
</vn-input-number>
|
||||
<vn-input-number
|
||||
label="Net"
|
||||
ng-model="intrastat.net"
|
||||
step="0.01"
|
||||
rule>
|
||||
</vn-input-number>
|
||||
<vn-input-number
|
||||
label="Stems"
|
||||
ng-model="intrastat.stems"
|
||||
rule>
|
||||
</vn-input-number>
|
||||
<vn-autocomplete
|
||||
label="Country"
|
||||
data="countries"
|
||||
ng-model="intrastat.countryFk"
|
||||
show-field="code"
|
||||
rule>
|
||||
</vn-autocomplete>
|
||||
<vn-none>
|
||||
<vn-icon-button
|
||||
vn-tooltip="Remove due day"
|
||||
icon="delete"
|
||||
ng-click="$ctrl.deleteIntrastat($index)"
|
||||
tabindex="-1">
|
||||
</vn-icon-button>
|
||||
</vn-none>
|
||||
</vn-horizontal>
|
||||
<vn-one>
|
||||
<vn-icon-button
|
||||
vn-bind="+"
|
||||
vn-tooltip="Add due day"
|
||||
icon="add_circle"
|
||||
ng-click="$ctrl.add()">
|
||||
</vn-icon-button>
|
||||
</vn-one>
|
||||
</vn-card>
|
||||
<vn-button-bar>
|
||||
<vn-submit
|
||||
disabled="!watcher.dataChanged()"
|
||||
label="Save">
|
||||
</vn-submit>
|
||||
</vn-button-bar>
|
||||
</form>
|
|
@ -1,60 +0,0 @@
|
|||
import ngModule from '../module';
|
||||
import Section from 'salix/components/section';
|
||||
|
||||
class Controller extends Section {
|
||||
set invoceInIntrastat(value) {
|
||||
this._invoceInIntrastat = value;
|
||||
|
||||
if (value) this.calculateTotals();
|
||||
}
|
||||
|
||||
get invoceInIntrastat() {
|
||||
return this._invoceInIntrastat;
|
||||
}
|
||||
|
||||
calculateTotals() {
|
||||
this.amountTotal = 0.0;
|
||||
this.netTotal = 0.0;
|
||||
this.stemsTotal = 0.0;
|
||||
if (!this.invoceInIntrastat) return;
|
||||
|
||||
this.invoceInIntrastat.forEach(intrastat => {
|
||||
this.amountTotal += intrastat.amount;
|
||||
this.netTotal += intrastat.net;
|
||||
this.stemsTotal += intrastat.stems;
|
||||
});
|
||||
}
|
||||
|
||||
add() {
|
||||
this.$.model.insert({});
|
||||
}
|
||||
|
||||
deleteIntrastat($index) {
|
||||
this.$.model.remove($index);
|
||||
this.$.model.save().then(() => {
|
||||
this.vnApp.showSuccess(this.$t('Data saved!'));
|
||||
this.calculateTotals();
|
||||
});
|
||||
}
|
||||
|
||||
onSubmit() {
|
||||
this.$.watcher.check();
|
||||
this.$.model.save().then(() => {
|
||||
this.$.watcher.notifySaved();
|
||||
this.$.watcher.updateOriginalData();
|
||||
this.calculateTotals();
|
||||
this.card.reload();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
ngModule.vnComponent('vnInvoiceInIntrastat', {
|
||||
template: require('./index.html'),
|
||||
controller: Controller,
|
||||
require: {
|
||||
card: '^vnInvoiceInCard'
|
||||
},
|
||||
bindings: {
|
||||
invoiceIn: '<'
|
||||
}
|
||||
});
|
|
@ -1,85 +0,0 @@
|
|||
import './index.js';
|
||||
import watcher from 'core/mocks/watcher';
|
||||
import crudModel from 'core/mocks/crud-model';
|
||||
|
||||
describe('InvoiceIn', () => {
|
||||
describe('Component intrastat', () => {
|
||||
let controller;
|
||||
let $scope;
|
||||
let vnApp;
|
||||
|
||||
beforeEach(ngModule('invoiceIn'));
|
||||
|
||||
beforeEach(inject(($componentController, $rootScope, _vnApp_) => {
|
||||
vnApp = _vnApp_;
|
||||
jest.spyOn(vnApp, 'showError');
|
||||
$scope = $rootScope.$new();
|
||||
$scope.model = crudModel;
|
||||
$scope.watcher = watcher;
|
||||
|
||||
const $element = angular.element('<vn-invoice-in-intrastat></vn-invoice-in-intrastat>');
|
||||
controller = $componentController('vnInvoiceInIntrastat', {$element, $scope});
|
||||
controller.invoiceIn = {id: 1};
|
||||
}));
|
||||
|
||||
describe('calculateTotals()', () => {
|
||||
it('should set amountTotal, netTotal and stemsTotal to 0 if salesClaimed has no data', () => {
|
||||
controller.invoceInIntrastat = [];
|
||||
controller.calculateTotals();
|
||||
|
||||
expect(controller.amountTotal).toEqual(0);
|
||||
expect(controller.netTotal).toEqual(0);
|
||||
expect(controller.stemsTotal).toEqual(0);
|
||||
});
|
||||
|
||||
it('should set amountTotal, netTotal and stemsTotal', () => {
|
||||
controller.invoceInIntrastat = [
|
||||
{
|
||||
id: 1,
|
||||
invoiceInFk: 1,
|
||||
net: 30.5,
|
||||
intrastatFk: 5080000,
|
||||
amount: 10,
|
||||
stems: 162,
|
||||
countryFk: 5,
|
||||
statisticalValue: 0
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
invoiceInFk: 1,
|
||||
net: 10,
|
||||
intrastatFk: 6021010,
|
||||
amount: 20,
|
||||
stems: 205,
|
||||
countryFk: 5,
|
||||
statisticalValue: 0
|
||||
}
|
||||
];
|
||||
controller.calculateTotals();
|
||||
|
||||
expect(controller.amountTotal).toEqual(30);
|
||||
expect(controller.netTotal).toEqual(40.5);
|
||||
expect(controller.stemsTotal).toEqual(367);
|
||||
});
|
||||
});
|
||||
|
||||
describe('onSubmit()', () => {
|
||||
it('should make HTTP POST request to save intrastat values', () => {
|
||||
controller.card = {reload: () => {}};
|
||||
jest.spyOn($scope.watcher, 'check');
|
||||
jest.spyOn($scope.watcher, 'notifySaved');
|
||||
jest.spyOn($scope.watcher, 'updateOriginalData');
|
||||
jest.spyOn(controller.card, 'reload');
|
||||
jest.spyOn($scope.model, 'save');
|
||||
|
||||
controller.onSubmit();
|
||||
|
||||
expect($scope.model.save).toHaveBeenCalledWith();
|
||||
expect($scope.watcher.updateOriginalData).toHaveBeenCalledWith();
|
||||
expect($scope.watcher.check).toHaveBeenCalledWith();
|
||||
expect($scope.watcher.notifySaved).toHaveBeenCalledWith();
|
||||
expect(controller.card.reload).toHaveBeenCalledWith();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1 +0,0 @@
|
|||
<vn-log url="InvoiceInLogs" origin-id="$ctrl.$params.id"></vn-log>
|
|
@ -1,7 +0,0 @@
|
|||
import ngModule from '../module';
|
||||
import Section from 'salix/components/section';
|
||||
|
||||
ngModule.vnComponent('vnInvoiceInLog', {
|
||||
template: require('./index.html'),
|
||||
controller: Section,
|
||||
});
|
|
@ -1,18 +0,0 @@
|
|||
<vn-crud-model
|
||||
vn-id="model"
|
||||
url="InvoiceIns/filter"
|
||||
limit="20"
|
||||
order="isBooked, issued DESC">
|
||||
</vn-crud-model>
|
||||
<vn-portal slot="topbar">
|
||||
<vn-searchbar
|
||||
vn-focus
|
||||
panel="vn-invoice-in-search-panel"
|
||||
info="Search invoices in by reference"
|
||||
model="model">
|
||||
</vn-searchbar>
|
||||
</vn-portal>
|
||||
<vn-portal slot="menu">
|
||||
<vn-left-menu></vn-left-menu>
|
||||
</vn-portal>
|
||||
<ui-view></ui-view>
|
|
@ -1,7 +1,16 @@
|
|||
import ngModule from '../module';
|
||||
import ModuleMain from 'salix/components/module-main';
|
||||
|
||||
export default class InvoiceIn extends ModuleMain {}
|
||||
export default class InvoiceIn extends ModuleMain {
|
||||
constructor($element, $) {
|
||||
super($element, $);
|
||||
}
|
||||
|
||||
async $onInit() {
|
||||
this.$state.go('home');
|
||||
window.location.href = await this.vnApp.getUrl(`invoice-in/`);
|
||||
}
|
||||
}
|
||||
|
||||
ngModule.vnComponent('vnInvoiceIn', {
|
||||
controller: InvoiceIn,
|
||||
|
|
|
@ -1,97 +0,0 @@
|
|||
<div class="search-panel">
|
||||
<form ng-submit="$ctrl.onSearch()">
|
||||
<vn-horizontal>
|
||||
<vn-textfield
|
||||
vn-one
|
||||
label="General search"
|
||||
ng-model="filter.search"
|
||||
info="Search invoices in by id or supplier fiscal name"
|
||||
vn-focus>
|
||||
</vn-textfield>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-textfield
|
||||
vn-one
|
||||
label="Supplier ref."
|
||||
ng-model="filter.supplierRef">
|
||||
</vn-textfield>
|
||||
<vn-textfield
|
||||
vn-one
|
||||
label="Supplier fiscal id"
|
||||
ng-model="filter.fi">
|
||||
</vn-textfield>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-autocomplete
|
||||
vn-one ng-model="filter.supplierFk"
|
||||
url="Suppliers"
|
||||
show-field="nickname"
|
||||
search-function="{or: [{id: $search}, {nickname: {like: '%'+ $search +'%'}}]}"
|
||||
value-field="id"
|
||||
order="nickname"
|
||||
label="Supplier">
|
||||
<tpl-item>
|
||||
{{::id}} - {{::nickname}}
|
||||
</tpl-item>
|
||||
</vn-autocomplete>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-textfield
|
||||
vn-one
|
||||
label="Account"
|
||||
ng-model="filter.account">
|
||||
</vn-textfield>
|
||||
<vn-input-number
|
||||
vn-one
|
||||
label="Amount"
|
||||
ng-model="filter.amount"
|
||||
step="0.01">
|
||||
</vn-input-number>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-date-picker
|
||||
vn-one
|
||||
label="From"
|
||||
ng-model="filter.from">
|
||||
</vn-date-picker>
|
||||
<vn-date-picker
|
||||
vn-one
|
||||
label="To"
|
||||
ng-model="filter.to">
|
||||
</vn-date-picker>
|
||||
<vn-date-picker
|
||||
vn-one
|
||||
label="Issued"
|
||||
ng-model="filter.issued">
|
||||
</vn-date-picker>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-textfield
|
||||
vn-one
|
||||
label="Serial number"
|
||||
ng-model="filter.serialNumber">
|
||||
</vn-textfield>
|
||||
<vn-textfield
|
||||
vn-one
|
||||
label="Serial"
|
||||
ng-model="filter.serial">
|
||||
</vn-textfield>
|
||||
<vn-textfield
|
||||
vn-one
|
||||
label="AWB"
|
||||
ng-model="filter.awbCode">
|
||||
</vn-textfield>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-check
|
||||
vn-one
|
||||
triple-state="true"
|
||||
label="Is booked"
|
||||
ng-model="filter.isBooked">
|
||||
</vn-check>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal class="vn-mt-lg">
|
||||
<vn-submit label="Search"></vn-submit>
|
||||
</vn-horizontal>
|
||||
</form>
|
||||
</div>
|
|
@ -1,7 +0,0 @@
|
|||
import ngModule from '../module';
|
||||
import SearchPanel from 'core/components/searchbar/search-panel';
|
||||
|
||||
ngModule.vnComponent('vnInvoiceInSearchPanel', {
|
||||
template: require('./index.html'),
|
||||
controller: SearchPanel
|
||||
});
|
|
@ -1,2 +0,0 @@
|
|||
Supplier fiscal id: CIF proveedor
|
||||
Search invoices in by id or supplier fiscal name: Buscar facturas recibidas por id o por nombre fiscal del proveedor
|
|
@ -1,27 +0,0 @@
|
|||
<vn-side-menu side="right">
|
||||
<vn-horizontal class="input">
|
||||
<vn-input-number
|
||||
label="Days ago"
|
||||
ng-model="$ctrl.filter.daysAgo"
|
||||
vn-focus
|
||||
ng-keydown="$ctrl.onKeyPress($event)"
|
||||
min="0">
|
||||
</vn-input-number>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal class="input">
|
||||
<vn-textfield
|
||||
label="Serial"
|
||||
ng-model="$ctrl.filter.serial"
|
||||
ng-keydown="$ctrl.onKeyPress($event)">
|
||||
</vn-textfield>
|
||||
</vn-horizontal>
|
||||
<div class="chips">
|
||||
<vn-chip
|
||||
ng-if="$ctrl.filter.serial"
|
||||
removable="true"
|
||||
on-remove="$ctrl.removeItemFilter('serial')"
|
||||
class="colored">
|
||||
<span>{{$ctrl.$t('Serial')}}: {{$ctrl.filter.serial}}</span>
|
||||
</vn-chip>
|
||||
</div>
|
||||
</vn-side-menu>
|
|
@ -1,44 +0,0 @@
|
|||
import ngModule from '../module';
|
||||
import SearchPanel from 'core/components/searchbar/search-panel';
|
||||
import './style.scss';
|
||||
|
||||
class Controller extends SearchPanel {
|
||||
constructor($element, $) {
|
||||
super($element, $);
|
||||
this.filter = {};
|
||||
const filter = {
|
||||
fields: ['daysAgo']
|
||||
};
|
||||
this.$http.get('InvoiceInConfigs', {filter}).then(res => {
|
||||
if (res.data) {
|
||||
this.invoiceInConfig = res.data[0];
|
||||
this.addFilters();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
removeItemFilter(param) {
|
||||
this.filter[param] = null;
|
||||
this.addFilters();
|
||||
}
|
||||
|
||||
onKeyPress($event) {
|
||||
if ($event.key === 'Enter')
|
||||
this.addFilters();
|
||||
}
|
||||
|
||||
addFilters() {
|
||||
if (!this.filter.daysAgo)
|
||||
this.filter.daysAgo = this.invoiceInConfig.daysAgo;
|
||||
|
||||
return this.model.addFilter({}, this.filter);
|
||||
}
|
||||
}
|
||||
|
||||
ngModule.component('vnInvoiceInSerialSearchPanel', {
|
||||
template: require('./index.html'),
|
||||
controller: Controller,
|
||||
bindings: {
|
||||
model: '<'
|
||||
}
|
||||
});
|
|
@ -1,43 +0,0 @@
|
|||
import './index.js';
|
||||
|
||||
describe('InvoiceIn', () => {
|
||||
describe('Component serial-search-panel', () => {
|
||||
let controller;
|
||||
let $scope;
|
||||
|
||||
beforeEach(ngModule('invoiceIn'));
|
||||
|
||||
beforeEach(inject(($componentController, $rootScope) => {
|
||||
$scope = $rootScope.$new();
|
||||
const $element = angular.element('<vn-invoice-in-serial-search-panel></vn-invoice-in-serial-search-panel>');
|
||||
controller = $componentController('vnInvoiceInSerialSearchPanel', {$element, $scope});
|
||||
controller.model = {
|
||||
addFilter: jest.fn(),
|
||||
};
|
||||
controller.invoiceInConfig = {
|
||||
daysAgo: 45,
|
||||
};
|
||||
}));
|
||||
|
||||
describe('addFilters()', () => {
|
||||
it('should add default daysAgo if it is not already set', () => {
|
||||
controller.filter = {
|
||||
serial: 'R',
|
||||
};
|
||||
controller.addFilters();
|
||||
|
||||
expect(controller.filter.daysAgo).toEqual(controller.invoiceInConfig.daysAgo);
|
||||
});
|
||||
|
||||
it('should not add default daysAgo if it is already set', () => {
|
||||
controller.filter = {
|
||||
daysAgo: 1,
|
||||
serial: 'R',
|
||||
};
|
||||
controller.addFilters();
|
||||
|
||||
expect(controller.filter.daysAgo).toEqual(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,24 +0,0 @@
|
|||
@import "variables";
|
||||
|
||||
vn-invoice-in-serial-search-panel vn-side-menu div {
|
||||
& > .input {
|
||||
padding-left: $spacing-md;
|
||||
padding-right: $spacing-md;
|
||||
border-color: $color-spacer;
|
||||
border-bottom: $border-thin;
|
||||
}
|
||||
& > .horizontal {
|
||||
grid-auto-flow: column;
|
||||
grid-column-gap: $spacing-sm;
|
||||
align-items: center;
|
||||
}
|
||||
& > .chips {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
padding: $spacing-md;
|
||||
overflow: hidden;
|
||||
max-width: 100%;
|
||||
border-color: $color-spacer;
|
||||
border-top: $border-thin;
|
||||
}
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
<vn-crud-model
|
||||
vn-id="model"
|
||||
url="InvoiceIns/getSerial"
|
||||
limit="20">
|
||||
</vn-crud-model>
|
||||
<vn-portal slot="topbar">
|
||||
</vn-portal>
|
||||
<vn-invoice-in-serial-search-panel
|
||||
model="model">
|
||||
</vn-invoice-in-serial-search-panel>
|
||||
<vn-data-viewer
|
||||
model="model"
|
||||
class="vn-w-lg">
|
||||
<vn-card>
|
||||
<vn-table model="model">
|
||||
<vn-thead>
|
||||
<vn-tr>
|
||||
<vn-th field="serial">Serial</vn-th>
|
||||
<vn-th field="pending">Pending</vn-th>
|
||||
<vn-th field="total">Total</vn-th>
|
||||
<vn-th></vn-th>
|
||||
</vn-tr>
|
||||
</vn-thead>
|
||||
<vn-tbody>
|
||||
<vn-tr ng-repeat="invoiceIn in model.data">
|
||||
<vn-td>{{::invoiceIn.serial}}</vn-td>
|
||||
<vn-td>{{::invoiceIn.pending}}</vn-td>
|
||||
<vn-td>{{::invoiceIn.total}}</vn-td>
|
||||
<vn-td shrink>
|
||||
<vn-icon-button
|
||||
vn-click-stop="$ctrl.goToIndex(model.userParams.daysAgo, invoiceIn.serial)"
|
||||
vn-tooltip="Go to InvoiceIn"
|
||||
icon="icon-invoice-in">
|
||||
</vn-icon-button>
|
||||
</vn-td>
|
||||
</vn-tr>
|
||||
</vn-tbody>
|
||||
</vn-table>
|
||||
</vn-card>
|
||||
</vn-data-viewer>
|
|
@ -1,22 +0,0 @@
|
|||
import ngModule from '../module';
|
||||
import Section from 'salix/components/section';
|
||||
|
||||
export default class Controller extends Section {
|
||||
constructor($element, $) {
|
||||
super($element, $);
|
||||
}
|
||||
|
||||
goToIndex(daysAgo, serial) {
|
||||
const issued = Date.vnNew();
|
||||
issued.setDate(issued.getDate() - daysAgo);
|
||||
this.$state.go('invoiceIn.index',
|
||||
{q: `{"serial": "${serial}", "isBooked": false, "from": ${issued.getTime()}}`});
|
||||
}
|
||||
}
|
||||
|
||||
Controller.$inject = ['$element', '$scope'];
|
||||
|
||||
ngModule.vnComponent('vnInvoiceInSerial', {
|
||||
template: require('./index.html'),
|
||||
controller: Controller
|
||||
});
|
|
@ -1,3 +0,0 @@
|
|||
Serial: Serie
|
||||
Pending: Pendientes
|
||||
Go to InvoiceIn: Ir al listado de facturas recibidas
|
|
@ -1,149 +0,0 @@
|
|||
<vn-crud-model
|
||||
vn-id="model"
|
||||
url="InvoiceInTaxes"
|
||||
fields="[
|
||||
'id',
|
||||
'invoiceInFk',
|
||||
'taxableBase',
|
||||
'expenseFk',
|
||||
'foreignValue',
|
||||
'taxTypeSageFk',
|
||||
'transactionTypeSageFk']"
|
||||
link="{invoiceInFk: $ctrl.$params.id}"
|
||||
data="$ctrl.taxes"
|
||||
auto-load="true">
|
||||
</vn-crud-model>
|
||||
<vn-crud-model
|
||||
url="Expenses"
|
||||
data="expenses"
|
||||
auto-load="true">
|
||||
</vn-crud-model>
|
||||
<vn-watcher
|
||||
vn-id="watcher"
|
||||
data="$ctrl.taxes"
|
||||
form="form">
|
||||
</vn-watcher>
|
||||
<form name="form" ng-submit="$ctrl.onSubmit()">
|
||||
<vn-card class="vn-pa-lg">
|
||||
<vn-horizontal ng-repeat="invoiceInTax in $ctrl.taxes">
|
||||
<vn-autocomplete vn-three vn-id="expense" vn-focus
|
||||
label="Expense"
|
||||
ng-model="invoiceInTax.expenseFk"
|
||||
data="expenses"
|
||||
show-field="id"
|
||||
rule>
|
||||
<tpl-item>{{id}}: {{name}}</tpl-item>
|
||||
<append>
|
||||
<vn-icon-button
|
||||
vn-tooltip="Create expense"
|
||||
icon="add_circle"
|
||||
vn-click-stop="createExpense.show()">
|
||||
</vn-icon-button>
|
||||
</append>
|
||||
</vn-autocomplete>
|
||||
<vn-input-number vn-one
|
||||
disabled="$ctrl.invoiceIn.currency.code != 'EUR'"
|
||||
step="0.01"
|
||||
label="Taxable base"
|
||||
ng-model="invoiceInTax.taxableBase"
|
||||
rule>
|
||||
</vn-input-number>
|
||||
<vn-autocomplete vn-three
|
||||
label="Sage tax"
|
||||
ng-model="invoiceInTax.taxTypeSageFk"
|
||||
url="SageTaxTypes"
|
||||
show-field="vat"
|
||||
fields="['id', 'vat', 'rate']"
|
||||
search-function="{or: [{id: $search}, {vat: {like: '%'+ $search +'%'}}]}"
|
||||
selection="taxRateSelection"
|
||||
rule>
|
||||
<tpl-item>
|
||||
<div>{{::vat}}</div>
|
||||
<div class="text-secondary text-caption">#{{::id}}</div>
|
||||
</tpl-item>
|
||||
</vn-autocomplete>
|
||||
<vn-autocomplete vn-three
|
||||
label="Sage transaction"
|
||||
ng-model="invoiceInTax.transactionTypeSageFk"
|
||||
url="SageTransactionTypes"
|
||||
show-field="transaction"
|
||||
search-function="{or: [{id: $search}, {transaction: {like: '%'+ $search +'%'}}]}"
|
||||
rule>
|
||||
<tpl-item>
|
||||
<div>{{::transaction}}</div>
|
||||
<div class="text-secondary text-caption">#{{::id}}</div>
|
||||
</tpl-item>
|
||||
</vn-autocomplete>
|
||||
<vn-textfield
|
||||
disabled="true"
|
||||
label="Rate"
|
||||
field="$ctrl.taxRate(invoiceInTax, taxRateSelection) | currency:'EUR':2">
|
||||
</vn-textfield>
|
||||
<vn-input-number
|
||||
disabled="$ctrl.invoiceIn.currency.code == 'EUR'"
|
||||
label="Foreign value"
|
||||
ng-model="invoiceInTax.foreignValue"
|
||||
rule>
|
||||
</vn-input-number>
|
||||
<vn-none>
|
||||
<vn-icon-button
|
||||
vn-tooltip="Remove tax"
|
||||
icon="delete"
|
||||
ng-click="model.remove($index)"
|
||||
tabindex="-1">
|
||||
</vn-icon-button>
|
||||
</vn-none>
|
||||
</vn-horizontal>
|
||||
<vn-one>
|
||||
<vn-icon-button
|
||||
vn-bind="+"
|
||||
vn-tooltip="Add tax"
|
||||
icon="add_circle"
|
||||
ng-click="$ctrl.add()">
|
||||
</vn-icon-button>
|
||||
</vn-one>
|
||||
</vn-card>
|
||||
<vn-button-bar>
|
||||
<vn-submit
|
||||
disabled="!watcher.dataChanged()"
|
||||
label="Save">
|
||||
</vn-submit>
|
||||
</vn-button-bar>
|
||||
</form>
|
||||
|
||||
<!-- Dialog of create expense-->
|
||||
<vn-dialog
|
||||
vn-id="createExpense"
|
||||
on-accept="$ctrl.onResponse()">
|
||||
<tpl-body>
|
||||
<section>
|
||||
<h5 class="vn-py-sm">{{$ctrl.$t('New expense')}}</h5>
|
||||
<vn-horizontal>
|
||||
<vn-textfield vn-one
|
||||
vn-id="code"
|
||||
label="Code"
|
||||
ng-model="$ctrl.expense.code"
|
||||
required="true"
|
||||
vn-focus>
|
||||
</vn-textfield>
|
||||
<vn-check
|
||||
vn-one
|
||||
label="It's a withholding"
|
||||
ng-model="$ctrl.expense.isWithheld">
|
||||
</vn-check>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-textfield vn-one
|
||||
vn-id="description"
|
||||
label="Description"
|
||||
ng-model="$ctrl.expense.description"
|
||||
required="true">
|
||||
</vn-textfield>
|
||||
</vn-horizontal>
|
||||
</section>
|
||||
</tpl-body>
|
||||
<tpl-buttons>
|
||||
<input type="button" response="cancel" translate-attr="{value: 'Cancel'}"/>
|
||||
<button response="accept" translate>Save</button>
|
||||
</tpl-buttons>
|
||||
</vn-dialog>
|
|
@ -1,66 +0,0 @@
|
|||
import ngModule from '../module';
|
||||
import Section from 'salix/components/section';
|
||||
import UserError from 'core/lib/user-error';
|
||||
|
||||
class Controller extends Section {
|
||||
constructor($element, $, vnWeekDays) {
|
||||
super($element, $);
|
||||
this.expense = {};
|
||||
}
|
||||
taxRate(invoiceInTax, taxRateSelection) {
|
||||
const taxTypeSage = taxRateSelection && taxRateSelection.rate;
|
||||
const taxableBase = invoiceInTax && invoiceInTax.taxableBase;
|
||||
|
||||
if (taxTypeSage && taxableBase)
|
||||
return (taxTypeSage / 100) * taxableBase;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
add() {
|
||||
this.$.model.insert({
|
||||
invoiceIn: this.$params.id
|
||||
});
|
||||
}
|
||||
|
||||
onSubmit() {
|
||||
this.$.watcher.check();
|
||||
this.$.model.save().then(() => {
|
||||
this.$.watcher.notifySaved();
|
||||
this.$.watcher.updateOriginalData();
|
||||
this.card.reload();
|
||||
});
|
||||
}
|
||||
|
||||
onResponse() {
|
||||
try {
|
||||
if (!this.expense.code)
|
||||
throw new Error(`The code can't be empty`);
|
||||
if (!this.expense.description)
|
||||
throw new UserError(`The description can't be empty`);
|
||||
|
||||
const data = [{
|
||||
id: this.expense.code,
|
||||
isWithheld: this.expense.isWithheld,
|
||||
name: this.expense.description
|
||||
}];
|
||||
|
||||
this.$http.post(`Expenses`, data) .then(() => {
|
||||
this.vnApp.showSuccess(this.$t('Expense saved!'));
|
||||
});
|
||||
} catch (e) {
|
||||
this.vnApp.showError(this.$t(e.message));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ngModule.vnComponent('vnInvoiceInTax', {
|
||||
template: require('./index.html'),
|
||||
controller: Controller,
|
||||
require: {
|
||||
card: '^vnInvoiceInCard'
|
||||
},
|
||||
bindings: {
|
||||
invoiceIn: '<'
|
||||
}
|
||||
});
|
|
@ -1,113 +0,0 @@
|
|||
import './index.js';
|
||||
import watcher from 'core/mocks/watcher';
|
||||
import crudModel from 'core/mocks/crud-model';
|
||||
|
||||
describe('InvoiceIn', () => {
|
||||
describe('Component tax', () => {
|
||||
let controller;
|
||||
let $scope;
|
||||
let vnApp;
|
||||
let $httpBackend;
|
||||
|
||||
beforeEach(ngModule('invoiceIn'));
|
||||
|
||||
beforeEach(inject(($componentController, $rootScope, _vnApp_, _$httpBackend_) => {
|
||||
$httpBackend = _$httpBackend_;
|
||||
vnApp = _vnApp_;
|
||||
jest.spyOn(vnApp, 'showError');
|
||||
$scope = $rootScope.$new();
|
||||
$scope.model = crudModel;
|
||||
$scope.watcher = watcher;
|
||||
|
||||
const $element = angular.element('<vn-invoice-in-tax></vn-invoice-in-tax>');
|
||||
controller = $componentController('vnInvoiceInTax', {$element, $scope});
|
||||
controller.$.model = crudModel;
|
||||
controller.invoiceIn = {id: 1};
|
||||
}));
|
||||
|
||||
describe('taxRate()', () => {
|
||||
it('should set tax rate with the Sage tax type value', () => {
|
||||
const taxRateSelection = {
|
||||
rate: 21
|
||||
};
|
||||
const invoiceInTax = {
|
||||
taxableBase: 200
|
||||
};
|
||||
|
||||
const taxRate = controller.taxRate(invoiceInTax, taxRateSelection);
|
||||
|
||||
expect(taxRate).toEqual(42);
|
||||
});
|
||||
});
|
||||
|
||||
describe('onSubmit()', () => {
|
||||
it('should make HTTP POST request to save tax values', () => {
|
||||
controller.card = {reload: () => {}};
|
||||
jest.spyOn($scope.watcher, 'check');
|
||||
jest.spyOn($scope.watcher, 'notifySaved');
|
||||
jest.spyOn($scope.watcher, 'updateOriginalData');
|
||||
jest.spyOn(controller.card, 'reload');
|
||||
jest.spyOn($scope.model, 'save');
|
||||
|
||||
controller.onSubmit();
|
||||
|
||||
expect($scope.model.save).toHaveBeenCalledWith();
|
||||
expect($scope.watcher.updateOriginalData).toHaveBeenCalledWith();
|
||||
expect($scope.watcher.check).toHaveBeenCalledWith();
|
||||
expect($scope.watcher.notifySaved).toHaveBeenCalledWith();
|
||||
expect(controller.card.reload).toHaveBeenCalledWith();
|
||||
});
|
||||
});
|
||||
|
||||
describe('onResponse()', () => {
|
||||
it('should return success message', () => {
|
||||
controller.expense = {
|
||||
code: 7050000005,
|
||||
isWithheld: 0,
|
||||
description: 'Test'
|
||||
};
|
||||
|
||||
const data = [{
|
||||
id: controller.expense.code,
|
||||
isWithheld: controller.expense.isWithheld,
|
||||
name: controller.expense.description
|
||||
}];
|
||||
|
||||
jest.spyOn(controller.vnApp, 'showSuccess');
|
||||
$httpBackend.expect('POST', `Expenses`, data).respond();
|
||||
|
||||
controller.onResponse();
|
||||
$httpBackend.flush();
|
||||
|
||||
expect(controller.vnApp.showSuccess).toHaveBeenCalledWith('Expense saved!');
|
||||
});
|
||||
|
||||
it('should return an error if code is empty', () => {
|
||||
controller.expense = {
|
||||
code: null,
|
||||
isWithheld: 0,
|
||||
description: 'Test'
|
||||
};
|
||||
|
||||
jest.spyOn(controller.vnApp, 'showError');
|
||||
controller.onResponse();
|
||||
|
||||
expect(controller.vnApp.showError).toHaveBeenCalledWith(`The code can't be empty`);
|
||||
});
|
||||
|
||||
it('should return an error if description is empty', () => {
|
||||
controller.expense = {
|
||||
code: 7050000005,
|
||||
isWithheld: 0,
|
||||
description: null
|
||||
};
|
||||
|
||||
jest.spyOn(controller.vnApp, 'showError');
|
||||
controller.onResponse();
|
||||
|
||||
expect(controller.vnApp.showError).toHaveBeenCalledWith(`The description can't be empty`);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
Create expense: Crear gasto
|
||||
New expense: Nuevo gasto
|
||||
It's a withholding: Es una retención
|
||||
The fields can't be empty: Los campos no pueden estar vacíos
|
||||
The code can't be empty: El código no puede estar vacío
|
||||
The description can't be empty: La descripción no puede estar vacía
|
||||
Expense saved!: Gasto guardado!
|
Loading…
Reference in New Issue