mirror of
https://github.com/frappe/books.git
synced 2025-01-03 07:12:21 +00:00
incr: start rewriting reports
- list type report eg GL almost done
This commit is contained in:
parent
c95473c6b0
commit
cc493e9fb1
@ -22,6 +22,7 @@ interface RawLedgerEntry {
|
||||
}
|
||||
|
||||
interface LedgerEntry {
|
||||
index?: string;
|
||||
name: number;
|
||||
account: string;
|
||||
date: Date | null;
|
||||
@ -49,8 +50,8 @@ export class GeneralLedger extends Report {
|
||||
super(fyo);
|
||||
|
||||
if (!this.toField) {
|
||||
this.toField = DateTime.now().toISODate();
|
||||
this.fromField = DateTime.now().minus({ years: 1 }).toISODate();
|
||||
this.toDate = DateTime.now().toISODate();
|
||||
this.fromDate = DateTime.now().minus({ years: 1 }).toISODate();
|
||||
}
|
||||
}
|
||||
|
||||
@ -60,13 +61,14 @@ export class GeneralLedger extends Report {
|
||||
}
|
||||
|
||||
const map = this._getGroupedMap();
|
||||
this._setIndexOnEntries(map);
|
||||
const { totalDebit, totalCredit } = this._getTotalsAndSetBalance(map);
|
||||
const consolidated = this._consolidateEntries(map);
|
||||
|
||||
/**
|
||||
* Push a blank row if last row isn't blank
|
||||
*/
|
||||
if (consolidated.at(-1)!.name !== -3) {
|
||||
if (consolidated.at(-1)?.name !== -3) {
|
||||
this._pushBlankEntry(consolidated);
|
||||
}
|
||||
|
||||
@ -90,42 +92,52 @@ export class GeneralLedger extends Report {
|
||||
this.reportData = this._convertEntriesToReportData(consolidated);
|
||||
}
|
||||
|
||||
_setIndexOnEntries(map: GroupedMap) {
|
||||
let i = 1;
|
||||
for (const key of map.keys()) {
|
||||
for (const entry of map.get(key)!) {
|
||||
entry.index = String(i);
|
||||
i = i + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_convertEntriesToReportData(entries: LedgerEntry[]): ReportData {
|
||||
const reportData = [];
|
||||
const fieldnames = this.columns.map((f) => f.fieldname);
|
||||
for (const entry of entries) {
|
||||
const row = this._getRowFromEntry(entry, fieldnames);
|
||||
const row = this._getRowFromEntry(entry, this.columns);
|
||||
reportData.push(row);
|
||||
}
|
||||
|
||||
return reportData;
|
||||
}
|
||||
|
||||
_getRowFromEntry(entry: LedgerEntry, fieldnames: string[]) {
|
||||
_getRowFromEntry(entry: LedgerEntry, columns: ColumnField[]) {
|
||||
if (entry.name === -3) {
|
||||
return Array(fieldnames.length).fill({ value: '' });
|
||||
return Array(columns.length).fill({ value: '' });
|
||||
}
|
||||
|
||||
const row = [];
|
||||
for (const n of fieldnames) {
|
||||
let value = entry[n as keyof LedgerEntry];
|
||||
for (const col of columns) {
|
||||
const align = col.align ?? 'left';
|
||||
const width = col.width ?? 1;
|
||||
const fieldname = col.fieldname;
|
||||
|
||||
let value = entry[fieldname as keyof LedgerEntry];
|
||||
if (value === null || value === undefined) {
|
||||
row.push({ value: '' });
|
||||
continue;
|
||||
value = '';
|
||||
}
|
||||
|
||||
let align = 'left';
|
||||
if (value instanceof Date) {
|
||||
value = this.fyo.format(value, FieldTypeEnum.Date);
|
||||
}
|
||||
|
||||
if (typeof value === 'number') {
|
||||
align = 'right';
|
||||
if (typeof value === 'number' && fieldname !== 'index') {
|
||||
value = this.fyo.format(value, FieldTypeEnum.Currency);
|
||||
}
|
||||
|
||||
if (typeof value === 'boolean' && n === 'reverted' && value) {
|
||||
value = t`Reverted`;
|
||||
if (typeof value === 'boolean' && fieldname === 'reverted') {
|
||||
value = value ? t`Reverted` : '';
|
||||
}
|
||||
|
||||
row.push({
|
||||
@ -133,6 +145,7 @@ export class GeneralLedger extends Report {
|
||||
bold: entry.name === -2,
|
||||
value,
|
||||
align,
|
||||
width,
|
||||
});
|
||||
}
|
||||
|
||||
@ -266,7 +279,7 @@ export class GeneralLedger extends Report {
|
||||
'reverts',
|
||||
];
|
||||
|
||||
const filters = this._getQueryFilters();
|
||||
const filters = {} ?? this._getQueryFilters();
|
||||
const entries = (await this.fyo.db.getAllRaw(
|
||||
ModelNameEnum.AccountingLedgerEntry,
|
||||
{
|
||||
@ -338,16 +351,16 @@ export class GeneralLedger extends Report {
|
||||
{ label: t`Journal Entries`, value: 'JournalEntry' },
|
||||
],
|
||||
|
||||
label: t`Reference Type`,
|
||||
label: t`Ref Type`,
|
||||
fieldname: 'referenceType',
|
||||
placeholder: t`Reference Type`,
|
||||
placeholder: t`Ref Type`,
|
||||
default: 'All',
|
||||
},
|
||||
{
|
||||
fieldtype: 'DynamicLink',
|
||||
placeholder: t`Reference Name`,
|
||||
label: t`Ref Name`,
|
||||
references: 'referenceType',
|
||||
label: t`Reference Name`,
|
||||
placeholder: t`Ref Name`,
|
||||
fieldname: 'referenceName',
|
||||
},
|
||||
{
|
||||
@ -377,19 +390,7 @@ export class GeneralLedger extends Report {
|
||||
fieldname: 'toDate',
|
||||
},
|
||||
{
|
||||
fieldtype: 'Check',
|
||||
default: false,
|
||||
label: t`Cancelled`,
|
||||
fieldname: 'reverted',
|
||||
},
|
||||
{
|
||||
fieldtype: 'Check',
|
||||
default: false,
|
||||
label: t`Ascending`,
|
||||
fieldname: 'ascending',
|
||||
},
|
||||
{
|
||||
fieldtype: 'Check',
|
||||
fieldtype: 'Select',
|
||||
default: 'none',
|
||||
label: t`Group By`,
|
||||
fieldname: 'groupBy',
|
||||
@ -400,11 +401,30 @@ export class GeneralLedger extends Report {
|
||||
{ label: t`Reference`, value: 'referenceName' },
|
||||
],
|
||||
},
|
||||
{
|
||||
fieldtype: 'Check',
|
||||
default: false,
|
||||
label: t`Include Cancelled`,
|
||||
fieldname: 'reverted',
|
||||
},
|
||||
{
|
||||
fieldtype: 'Check',
|
||||
default: false,
|
||||
label: t`Ascending Order`,
|
||||
fieldname: 'ascending',
|
||||
},
|
||||
] as Field[];
|
||||
}
|
||||
|
||||
getColumns(): ColumnField[] {
|
||||
let columns = [
|
||||
{
|
||||
label: t`#`,
|
||||
fieldtype: 'Int',
|
||||
fieldname: 'index',
|
||||
align: 'right',
|
||||
width: 0.5,
|
||||
},
|
||||
{
|
||||
label: t`Account`,
|
||||
fieldtype: 'Link',
|
||||
@ -415,41 +435,43 @@ export class GeneralLedger extends Report {
|
||||
label: t`Date`,
|
||||
fieldtype: 'Date',
|
||||
fieldname: 'date',
|
||||
width: 0.75,
|
||||
},
|
||||
{
|
||||
label: t`Debit`,
|
||||
fieldtype: 'Currency',
|
||||
fieldname: 'debit',
|
||||
align: 'right',
|
||||
width: 1.25,
|
||||
},
|
||||
{
|
||||
label: t`Credit`,
|
||||
fieldtype: 'Currency',
|
||||
fieldname: 'credit',
|
||||
align: 'right',
|
||||
width: 1.25,
|
||||
},
|
||||
{
|
||||
label: t`Balance`,
|
||||
fieldtype: 'Currency',
|
||||
fieldname: 'balance',
|
||||
align: 'right',
|
||||
width: 1.25,
|
||||
},
|
||||
{
|
||||
label: t`Reference Type`,
|
||||
fieldtype: 'Data',
|
||||
fieldname: 'referenceType',
|
||||
},
|
||||
{
|
||||
label: t`Reference Name`,
|
||||
fieldtype: 'Data',
|
||||
fieldname: 'referenceName',
|
||||
},
|
||||
{
|
||||
label: t`Party`,
|
||||
fieldtype: 'Link',
|
||||
fieldname: 'party',
|
||||
},
|
||||
{
|
||||
label: t`Ref Name`,
|
||||
fieldtype: 'Data',
|
||||
fieldname: 'referenceName',
|
||||
},
|
||||
{
|
||||
label: t`Ref Type`,
|
||||
fieldtype: 'Data',
|
||||
fieldname: 'referenceType',
|
||||
},
|
||||
{
|
||||
label: t`Reverted`,
|
||||
fieldtype: 'Check',
|
||||
@ -467,4 +489,12 @@ export class GeneralLedger extends Report {
|
||||
getActions(): Action[] {
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Order by date and then the number
|
||||
* TODO: Something is wrong with dummy data, there are entries from 2022 Dec
|
||||
* TODO: Add pagination
|
||||
* TODO: Always visible scrollbar
|
||||
* TODO: Extract out list view report to a different component
|
||||
*/
|
||||
}
|
||||
|
@ -1,2 +1,2 @@
|
||||
import { GeneralLedger } from './GeneralLedger/GeneralLedger';
|
||||
export { GeneralLedger };
|
||||
export const reports = { GeneralLedger };
|
||||
|
@ -7,12 +7,14 @@ export interface ReportCell {
|
||||
bold?: boolean;
|
||||
italics?: boolean;
|
||||
align?: 'left' | 'right' | 'center';
|
||||
width?: number;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export type ReportRow = ReportCell[];
|
||||
export type ReportData = ReportRow[];
|
||||
export interface ColumnField extends BaseField {
|
||||
align?: 'left' | 'right' | 'center';
|
||||
width?: number;
|
||||
}
|
||||
|
||||
|
@ -134,7 +134,7 @@ export default {
|
||||
},
|
||||
async getFilters() {
|
||||
const { schemaName, fieldname } = this.df;
|
||||
const getFilters = fyo.models[schemaName].filters[fieldname];
|
||||
const getFilters = fyo.models[schemaName]?.filters?.[fieldname];
|
||||
|
||||
if (getFilters === undefined) {
|
||||
return {};
|
||||
|
@ -1,6 +1,7 @@
|
||||
<template>
|
||||
<div class="flex flex-col max-w-full">
|
||||
<PageHeader :title="report.title">
|
||||
<div class="flex flex-col w-full h-full">
|
||||
<PageHeader :title="title">
|
||||
<!--
|
||||
<DropdownWithActions
|
||||
v-for="group of actionGroups"
|
||||
:key="group.label"
|
||||
@ -11,428 +12,164 @@
|
||||
{{ group.label }}
|
||||
</DropdownWithActions>
|
||||
<DropdownWithActions :actions="actions" />
|
||||
|
||||
-->
|
||||
</PageHeader>
|
||||
<div class="flex px-8 mt-2 text-base" v-if="report.filterFields">
|
||||
<div
|
||||
class="w-40 ml-2 first:ml-0"
|
||||
:class="
|
||||
df.fieldtype === 'Check' &&
|
||||
'flex justify-between items-center bg-gray-100 px-2 rounded'
|
||||
"
|
||||
v-for="df in report.filterFields"
|
||||
:key="df.fieldname"
|
||||
>
|
||||
<div v-if="df.fieldtype === 'Check'" class="text-sm mr-2">
|
||||
{{ df.label }}
|
||||
</div>
|
||||
<FormControl
|
||||
size="small"
|
||||
input-class="bg-gray-100"
|
||||
:df="df"
|
||||
:value="filters[df.fieldname]"
|
||||
@change="(value) => onFilterChange(df, value)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Filters -->
|
||||
<div v-if="report" class="mx-4 grid grid-cols-5 gap-2">
|
||||
<FormControl
|
||||
v-for="field in report.filters"
|
||||
:show-label="field.fieldtype === 'Check'"
|
||||
:key="field.fieldname + '-filter'"
|
||||
class="bg-gray-100 rounded"
|
||||
:class="field.fieldtype === 'Check' ? 'flex pl-3' : ''"
|
||||
input-class="bg-transparent px-3 py-2 text-base"
|
||||
:df="field"
|
||||
:value="report.get(field.fieldname)"
|
||||
:read-only="loading"
|
||||
@change="async (value) => await report.set(field.fieldname, value)"
|
||||
/>
|
||||
</div>
|
||||
<div class="px-8 mt-4">
|
||||
<div>
|
||||
<div ref="header" class="overflow-hidden">
|
||||
<Row gap="2rem" :grid-template-columns="gridTemplateColumns">
|
||||
<div
|
||||
class="py-4 text-base truncate"
|
||||
:class="[
|
||||
getColumnAlignClass(column),
|
||||
loading ? 'text-gray-100' : 'text-gray-600',
|
||||
]"
|
||||
v-for="column in columns"
|
||||
:key="column.label"
|
||||
>
|
||||
<span :class="{ 'bg-gray-100': loading }">
|
||||
{{ column.label }}
|
||||
</span>
|
||||
</div>
|
||||
</Row>
|
||||
</div>
|
||||
<WithScroll
|
||||
@scroll="onBodyScroll"
|
||||
class="flex-1 overflow-auto"
|
||||
:style="`height: ${height}`"
|
||||
>
|
||||
<Row
|
||||
v-show="row.isShown"
|
||||
v-for="(row, i) in rows.slice(sliceIndex.from, sliceIndex.to)"
|
||||
:key="i"
|
||||
gap="2rem"
|
||||
:grid-template-columns="gridTemplateColumns"
|
||||
>
|
||||
<div
|
||||
class="py-4 text-base overflow-scroll no-scrollbar"
|
||||
:class="getCellClasses(row, column)"
|
||||
v-for="column in columns"
|
||||
:key="column.label"
|
||||
@click="toggleChildren(row, i)"
|
||||
>
|
||||
<div class="inline-flex">
|
||||
<feather-icon
|
||||
v-if="row.isBranch && !row.isLeaf && column === columns[0]"
|
||||
class="flex-shrink-0 w-4 h-4 mr-2"
|
||||
:name="row.expanded ? 'chevron-down' : 'chevron-right'"
|
||||
/>
|
||||
<span class="truncate" :class="{ 'bg-gray-100': loading }">
|
||||
<component
|
||||
:is="cellComponent(row[column.fieldname], column)"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</Row>
|
||||
</WithScroll>
|
||||
|
||||
<!-- Report Outer Container -->
|
||||
<div
|
||||
v-if="report"
|
||||
class="mx-4 mt-4 overflow-x-scroll inline-block overflow-y-hidden"
|
||||
>
|
||||
<div class="inline-block">
|
||||
<!-- Title Row -->
|
||||
<div
|
||||
v-if="usePagination"
|
||||
class="flex w-full justify-center mt-2.5 text-base"
|
||||
class="flex items-center border-b"
|
||||
:style="{ height: `${hconst}px` }"
|
||||
ref="titleRow"
|
||||
>
|
||||
<div class="flex justify-center items-center gap-1 text-gray-800">
|
||||
<feather-icon
|
||||
name="chevron-left"
|
||||
class="text-gray-600 w-4 h-4 cursor-pointer"
|
||||
v-show="pageNo > 1"
|
||||
@click="pageNo -= 1"
|
||||
/>
|
||||
<div class="w-4 h-4" v-show="pageNo <= 1" />
|
||||
<div class="flex gap-1 bg-gray-100 rounded pr-2">
|
||||
<input
|
||||
type="number"
|
||||
class="
|
||||
w-6
|
||||
text-right
|
||||
outline-none
|
||||
bg-transparent
|
||||
focus:text-gray-900
|
||||
"
|
||||
v-model="pageNo"
|
||||
min="1"
|
||||
max="maxPages"
|
||||
/>
|
||||
<p class="text-gray-600">/</p>
|
||||
<p class="w-5">{{ maxPages }}</p>
|
||||
<p
|
||||
v-for="(col, c) in report.columns"
|
||||
:key="c + '-col'"
|
||||
:style="getCellStyle(col, c)"
|
||||
class="
|
||||
text-gray-600 text-base
|
||||
px-3
|
||||
flex-shrink-0
|
||||
overflow-x-scroll
|
||||
whitespace-nowrap
|
||||
"
|
||||
>
|
||||
{{ col.label }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Report Rows Continer -->
|
||||
<div
|
||||
class="overflow-y-scroll"
|
||||
:style="{ height: `${hconst * maxRows + 5}px` }"
|
||||
>
|
||||
<!-- Report Rows -->
|
||||
<div
|
||||
v-for="(row, r) in report.reportData"
|
||||
:key="r + '-row'"
|
||||
class="border-b flex items-center"
|
||||
:style="{ height: `${hconst}px` }"
|
||||
>
|
||||
<!-- Report Cell -->
|
||||
<div
|
||||
v-for="(cell, c) in row"
|
||||
:key="`${c}-${r}-cell`"
|
||||
:style="getCellStyle(cell, c)"
|
||||
class="
|
||||
text-gray-900 text-base
|
||||
px-3
|
||||
flex-shrink-0
|
||||
overflow-x-scroll
|
||||
whitespace-nowrap
|
||||
"
|
||||
>
|
||||
{{ cell.value }}
|
||||
</div>
|
||||
<div class="w-4 h-4" v-show="pageNo >= maxPages" />
|
||||
<feather-icon
|
||||
name="chevron-right"
|
||||
class="text-gray-600 w-4 h-4 cursor-pointer"
|
||||
v-show="pageNo < maxPages"
|
||||
@click="pageNo += 1"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="h-10 mx-4 mb-4 p-2 bg-red-100 text-base border-t">
|
||||
add pagination here
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { getReportData } from 'reports/index';
|
||||
import reportViewConfig from 'reports/view';
|
||||
import Button from 'src/components/Button';
|
||||
import { reports } from 'reports';
|
||||
import FormControl from 'src/components/Controls/FormControl.vue';
|
||||
import DropdownWithActions from 'src/components/DropdownWithActions.vue';
|
||||
import FeatherIcon from 'src/components/FeatherIcon.vue';
|
||||
import PageHeader from 'src/components/PageHeader';
|
||||
import Row from 'src/components/Row';
|
||||
import WithScroll from 'src/components/WithScroll';
|
||||
import PageHeader from 'src/components/PageHeader.vue';
|
||||
import { fyo } from 'src/initFyo';
|
||||
import { h, markRaw, nextTick } from 'vue';
|
||||
import { defineComponent } from 'vue';
|
||||
|
||||
export default {
|
||||
name: 'Report',
|
||||
props: ['reportName', 'defaultFilters'],
|
||||
components: {
|
||||
PageHeader,
|
||||
Button,
|
||||
Row,
|
||||
FormControl,
|
||||
WithScroll,
|
||||
DropdownWithActions,
|
||||
FeatherIcon,
|
||||
},
|
||||
provide() {
|
||||
return {
|
||||
doc: this.filters,
|
||||
};
|
||||
export default defineComponent({
|
||||
props: {
|
||||
reportName: String,
|
||||
},
|
||||
data() {
|
||||
let filters = {};
|
||||
for (let df of reportViewConfig[this.reportName].filterFields) {
|
||||
filters[df.fieldname] = null;
|
||||
}
|
||||
|
||||
return {
|
||||
loading: true,
|
||||
filters,
|
||||
pageNo: 1,
|
||||
pageLen: 25,
|
||||
reportData: {
|
||||
rows: [],
|
||||
columns: [],
|
||||
},
|
||||
wconst: 8,
|
||||
hconst: 48,
|
||||
loading: false,
|
||||
report: null,
|
||||
};
|
||||
},
|
||||
async activated() {
|
||||
this.reportData.columns = this.report.getColumns({ filters: this.filters });
|
||||
await this.setDefaultFilters();
|
||||
await this.fetchReportData();
|
||||
components: { PageHeader, FormControl },
|
||||
async mounted() {
|
||||
await this.setReportData();
|
||||
},
|
||||
methods: {
|
||||
onBodyScroll({ scrollLeft }) {
|
||||
nextTick(() => {
|
||||
this.$refs.header.scrollLeft = scrollLeft;
|
||||
});
|
||||
},
|
||||
async fetchReportData() {
|
||||
let data = await getReportData(this.report.method, this.filters);
|
||||
|
||||
let rows;
|
||||
if (data.rows) {
|
||||
rows = data.rows;
|
||||
} else {
|
||||
rows = data;
|
||||
}
|
||||
|
||||
this.reportData.columns = markRaw(
|
||||
this.report.getColumns({
|
||||
filters: this.filters,
|
||||
data,
|
||||
})
|
||||
);
|
||||
|
||||
if (!rows) {
|
||||
rows = [];
|
||||
}
|
||||
|
||||
this.reportData.rows = markRaw(this.addTreeMeta(rows));
|
||||
this.loading = false;
|
||||
},
|
||||
|
||||
addTreeMeta(rows) {
|
||||
return rows.map((row) => {
|
||||
if ('indent' in row) {
|
||||
row.isBranch = true;
|
||||
row.expanded = true;
|
||||
row.isLeaf = !row.isGroup;
|
||||
}
|
||||
row.isShown = true;
|
||||
return row;
|
||||
});
|
||||
},
|
||||
|
||||
toggleChildren(row, rowIndex) {
|
||||
if (!row.isBranch) return;
|
||||
|
||||
let flag;
|
||||
if (row.expanded) {
|
||||
row.expanded = false;
|
||||
flag = false;
|
||||
} else {
|
||||
row.expanded = true;
|
||||
flag = true;
|
||||
}
|
||||
|
||||
let _rows = this.rows.slice(rowIndex + 1);
|
||||
for (let _row of _rows) {
|
||||
if (row.isBranch && _row.indent > row.indent) {
|
||||
_row.expanded = flag;
|
||||
_row.isShown = flag;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
onFilterChange(df, value) {
|
||||
this.filters[df.fieldname] = value;
|
||||
this.fetchReportData();
|
||||
},
|
||||
|
||||
async resetFilters() {
|
||||
await this.setDefaultFilters();
|
||||
await this.fetchReportData();
|
||||
},
|
||||
|
||||
async setDefaultFilters() {
|
||||
for (let df of this.report.filterFields) {
|
||||
let defaultValue = null;
|
||||
if (df.default) {
|
||||
if (typeof df.default === 'function') {
|
||||
defaultValue = await df.default();
|
||||
} else {
|
||||
defaultValue = df.default;
|
||||
}
|
||||
}
|
||||
this.filters[df.fieldname] = defaultValue;
|
||||
}
|
||||
|
||||
if (this.defaultFilters) {
|
||||
Object.assign(this.filters, this.defaultFilters);
|
||||
}
|
||||
},
|
||||
|
||||
cellComponent(cellValue, column) {
|
||||
if (typeof cellValue === 'object') {
|
||||
// cellValue has a component definition
|
||||
return cellValue;
|
||||
}
|
||||
if (column.component) {
|
||||
// column has a component definition
|
||||
return column.component(cellValue, column);
|
||||
}
|
||||
|
||||
// default cell component
|
||||
let formattedValue =
|
||||
cellValue != null && cellValue !== ''
|
||||
? fyo.format(cellValue, column)
|
||||
: '';
|
||||
return {
|
||||
render() {
|
||||
return h('span', formattedValue);
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
getColumnAlignClass(column) {
|
||||
return {
|
||||
'text-right': ['Int', 'Float', 'Currency'].includes(column.fieldtype),
|
||||
};
|
||||
},
|
||||
|
||||
getCellClasses(row, column) {
|
||||
let padding = ['pl-0', 'pl-6', 'pl-12', 'pl-18', 'pl-20'];
|
||||
let treeCellClasses;
|
||||
if (row.isBranch && column === this.columns[0]) {
|
||||
treeCellClasses = [
|
||||
padding[row.indent],
|
||||
'hover:bg-gray-100 cursor-pointer',
|
||||
];
|
||||
}
|
||||
return [
|
||||
this.getColumnAlignClass(column),
|
||||
treeCellClasses,
|
||||
this.loading ? 'text-gray-100' : 'text-gray-900',
|
||||
];
|
||||
},
|
||||
getReportData() {
|
||||
return { rows: this.rows, columns: this.columns, filters: this.filters };
|
||||
},
|
||||
getCurriedAction(action) {
|
||||
return (...args) => action(this.getReportData, ...args);
|
||||
},
|
||||
async activated() {
|
||||
await this.setReportData();
|
||||
if (fyo.store.isDevelopment) {
|
||||
window.rep = this;
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
usePagination() {
|
||||
return (
|
||||
this.reportName === 'general-ledger' && this.rows.length > this.pageLen
|
||||
);
|
||||
maxRows() {
|
||||
return 18 - Math.ceil(this.report.filters.length / 5);
|
||||
},
|
||||
height() {
|
||||
if (this.usePagination && this.platform === 'Windows') {
|
||||
return 'calc(100vh - 14.5rem)';
|
||||
} else if (this.usePagination) {
|
||||
return 'calc(100vh - 13rem)';
|
||||
}
|
||||
|
||||
return 'calc(100vh - 12rem)';
|
||||
},
|
||||
sliceIndex() {
|
||||
if (!this.usePagination) {
|
||||
return {
|
||||
from: 0,
|
||||
to: this.rows.length,
|
||||
};
|
||||
}
|
||||
return {
|
||||
from: (this.pageNo - 1) * this.pageLen,
|
||||
to: this.pageNo * this.pageLen,
|
||||
};
|
||||
},
|
||||
maxPages() {
|
||||
return Math.ceil(this.rows.length / this.pageLen);
|
||||
},
|
||||
actions() {
|
||||
return [
|
||||
...(this.report.actions
|
||||
?.filter((action) => !action.group)
|
||||
.map((action) =>
|
||||
Object.assign({}, action, {
|
||||
action: this.getCurriedAction(action.action),
|
||||
})
|
||||
) ?? []),
|
||||
{
|
||||
label: this.t`Reset Filters`,
|
||||
action: this.resetFilters,
|
||||
},
|
||||
];
|
||||
},
|
||||
actionGroups() {
|
||||
const groups =
|
||||
this.report.actions
|
||||
?.filter((action) => action.group)
|
||||
.reduce((acc, action) => {
|
||||
acc[action.group] ??= { type: action.type, actions: [] };
|
||||
const actionWithoutGroup = Object.assign({}, action);
|
||||
actionWithoutGroup.action = this.getCurriedAction(action.action);
|
||||
delete actionWithoutGroup.group;
|
||||
acc[action.group].actions.push(actionWithoutGroup);
|
||||
return acc;
|
||||
}, {}) ?? {};
|
||||
|
||||
return Object.keys(groups).map((label) => ({ label, ...groups[label] }));
|
||||
},
|
||||
columns() {
|
||||
return this.loading
|
||||
? this.blankStateData.columns
|
||||
: this.reportData.columns;
|
||||
},
|
||||
rows() {
|
||||
return this.loading ? this.blankStateData.rows : this.reportData.rows;
|
||||
},
|
||||
blankStateData() {
|
||||
let columns = Array.from(new Array(6)).map((v, i) => {
|
||||
return {
|
||||
fieldtype: 'Data',
|
||||
fieldname: `Test ${i + 1}`,
|
||||
label: `Test ${i + 1}`,
|
||||
};
|
||||
});
|
||||
let rows = Array.from(new Array(14)).map(() => {
|
||||
return columns.reduce((obj, col) => {
|
||||
obj[col.fieldname] = 'Test Data ' + col.fieldname;
|
||||
obj.isShown = true;
|
||||
return obj;
|
||||
}, {});
|
||||
});
|
||||
return {
|
||||
columns,
|
||||
rows,
|
||||
};
|
||||
},
|
||||
report() {
|
||||
return reportViewConfig[this.reportName];
|
||||
},
|
||||
columnWidth() {
|
||||
return 'minmax(7rem, 1fr)';
|
||||
},
|
||||
gridTemplateColumns() {
|
||||
return this.columns
|
||||
.map((col) => {
|
||||
let multiplier = col.width;
|
||||
if (!multiplier) {
|
||||
multiplier = 1;
|
||||
}
|
||||
let minWidth = `${7 * multiplier}rem`;
|
||||
let maxWidth = `${9 * multiplier}rem`;
|
||||
|
||||
return `minmax(${minWidth}, ${maxWidth})`;
|
||||
})
|
||||
.join(' ');
|
||||
title() {
|
||||
return reports[this.reportName]?.title ?? t`Report`;
|
||||
},
|
||||
},
|
||||
};
|
||||
methods: {
|
||||
getCellStyle(cell, i) {
|
||||
const styles = {};
|
||||
const width = cell.width ?? 1;
|
||||
const align = cell.align ?? 'left';
|
||||
|
||||
styles['width'] = `${width * this.wconst}rem`;
|
||||
styles['text-align'] = align;
|
||||
|
||||
if (cell.bold) {
|
||||
styles['font-weight'] = 'bold';
|
||||
}
|
||||
|
||||
if (cell.italics) {
|
||||
styles['font-style'] = 'italic';
|
||||
}
|
||||
|
||||
if (i === 0) {
|
||||
styles['padding-left'] = '0px';
|
||||
}
|
||||
|
||||
if (i === this.report.columns.length - 1) {
|
||||
styles['padding-right'] = '0px';
|
||||
}
|
||||
|
||||
return styles;
|
||||
},
|
||||
async setReportData() {
|
||||
const Report = reports[this.reportName];
|
||||
if (this.report === null) {
|
||||
this.report = new Report(fyo);
|
||||
}
|
||||
|
||||
if (!this.report.reportData.length) {
|
||||
await this.report.setReportData();
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { ipcRenderer } from 'electron';
|
||||
import { ConfigKeys } from 'fyo/core/types';
|
||||
import { GeneralLedger } from 'reports';
|
||||
import { IPC_ACTIONS } from 'utils/messages';
|
||||
import { App as VueApp, createApp } from 'vue';
|
||||
import App from './App.vue';
|
||||
@ -106,6 +105,3 @@ function setOnWindow() {
|
||||
window.fyo = fyo;
|
||||
}
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
window.GL = GeneralLedger;
|
||||
|
@ -8,7 +8,7 @@ import JournalEntryForm from 'src/pages/JournalEntryForm.vue';
|
||||
import ListView from 'src/pages/ListView/ListView.vue';
|
||||
import PrintView from 'src/pages/PrintView/PrintView.vue';
|
||||
import QuickEditForm from 'src/pages/QuickEditForm.vue';
|
||||
// import Report from 'src/pages/Report.vue';
|
||||
import Report from 'src/pages/Report.vue';
|
||||
import Settings from 'src/pages/Settings/Settings.vue';
|
||||
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router';
|
||||
import { fyo } from './initFyo';
|
||||
@ -87,14 +87,12 @@ const routes: RouteRecordRaw[] = [
|
||||
component: PrintView,
|
||||
props: true,
|
||||
},
|
||||
/*
|
||||
{
|
||||
path: '/report/:reportName',
|
||||
name: 'Report',
|
||||
component: Report,
|
||||
props: true,
|
||||
},
|
||||
*/
|
||||
{
|
||||
path: '/chart-of-accounts',
|
||||
name: 'Chart Of Accounts',
|
||||
|
@ -132,18 +132,18 @@ function getCompleteSidebar(): SidebarConfig {
|
||||
},
|
||||
],
|
||||
},
|
||||
/*
|
||||
{
|
||||
label: t`Reports`,
|
||||
name: t`reports`,
|
||||
icon: 'reports',
|
||||
route: '/report/general-ledger',
|
||||
route: '/report/GeneralLedger',
|
||||
items: [
|
||||
{
|
||||
label: t`General Ledger`,
|
||||
name: 'general-ledger',
|
||||
route: '/report/general-ledger',
|
||||
route: '/report/GeneralLedger',
|
||||
},
|
||||
/*
|
||||
{
|
||||
label: t`Profit And Loss`,
|
||||
name: 'profit-and-loss',
|
||||
@ -171,9 +171,9 @@ function getCompleteSidebar(): SidebarConfig {
|
||||
route: '/report/gstr-2',
|
||||
hidden: () => fyo.singles.AccountingSettings!.country !== 'India',
|
||||
},
|
||||
*/
|
||||
],
|
||||
},
|
||||
*/
|
||||
{
|
||||
label: t`Setup`,
|
||||
name: t`setup`,
|
||||
|
@ -104,3 +104,22 @@ export function invertMap(map: Record<string, string>): Record<string, string> {
|
||||
|
||||
return inverted;
|
||||
}
|
||||
|
||||
export function time<K, T>(func: (...args: K[]) => T, ...args: K[]): T {
|
||||
const name = func.name;
|
||||
console.time(name);
|
||||
const stuff = func(...args);
|
||||
console.timeEnd(name);
|
||||
return stuff;
|
||||
}
|
||||
|
||||
export async function timeAsync<K, T>(
|
||||
func: (...args: K[]) => Promise<T>,
|
||||
...args: K[]
|
||||
): Promise<T> {
|
||||
const name = func.name;
|
||||
console.time(name);
|
||||
const stuff = await func(...args);
|
||||
console.timeEnd(name);
|
||||
return stuff;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user