2
0
mirror of https://github.com/frappe/books.git synced 2024-12-22 10:58:59 +00:00

fix: dynamic link ref

- gl ordering
- report filtering
- dummy dates
- few other things
This commit is contained in:
18alantom 2022-05-13 19:21:26 +05:30
parent 64d1f13e42
commit 3cdba15b81
12 changed files with 106 additions and 38 deletions

View File

@ -40,7 +40,7 @@ export function getRandomDates(count: number, months: number): Date[] {
let endDate = DateTime.now();
if (months !== 0) {
const back = endDate.minus({ months });
endDate = DateTime.local(endDate.year, back.month, back.daysInMonth);
endDate = DateTime.local(back.year, back.month, back.daysInMonth);
}
const dates: Date[] = [];

View File

@ -170,6 +170,17 @@ async function getPayments(fyo: Fyo, invoices: Invoice[]) {
return payments;
}
function getSalesInvoiceDates(years: number, baseCount: number): Date[] {
const dates: Date[] = [];
for (const months of range(0, years * 12)) {
const flow = getFlowConstant(months);
const count = Math.ceil(flow * baseCount * (Math.random() * 0.25 + 0.75));
dates.push(...getRandomDates(count, months));
}
return dates;
}
async function getSalesInvoices(
fyo: Fyo,
years: number,
@ -184,12 +195,7 @@ async function getSalesInvoices(
* Get certain number of entries for each month of the count
* of years.
*/
let dates: Date[] = [];
for (const months of range(0, years * 12)) {
const flow = getFlowConstant(months);
const count = Math.ceil(flow * baseCount * (Math.random() * 0.25 + 0.75));
dates = dates.concat(getRandomDates(count, months));
}
const dates = getSalesInvoiceDates(years, baseCount);
/**
* For each date create a Sales Invoice.

View File

@ -3,7 +3,7 @@ import { Action } from 'fyo/model/types';
import { DateTime } from 'luxon';
import { ModelNameEnum } from 'models/types';
import { Report } from 'reports/Report';
import { ColumnField, ReportData } from 'reports/types';
import { ColumnField, ReportData, ReportRow } from 'reports/types';
import { Field, FieldTypeEnum, RawValue } from 'schemas/types';
import { QueryFilter } from 'utils/db/types';
@ -56,11 +56,13 @@ export class GeneralLedger extends Report {
}
async setReportData(filter?: string) {
let sort = true;
if (filter !== 'grouped' || this._rawData.length === 0) {
await this._setRawData();
sort = false;
}
const map = this._getGroupedMap();
const map = this._getGroupedMap(sort);
this._setIndexOnEntries(map);
const { totalDebit, totalCredit } = this._getTotalsAndSetBalance(map);
const consolidated = this._consolidateEntries(map);
@ -112,12 +114,15 @@ export class GeneralLedger extends Report {
return reportData;
}
_getRowFromEntry(entry: LedgerEntry, columns: ColumnField[]) {
_getRowFromEntry(entry: LedgerEntry, columns: ColumnField[]): ReportRow {
if (entry.name === -3) {
return Array(columns.length).fill({ value: '' });
return columns.map((c) => ({
value: '',
width: c.width ?? 1,
})) as ReportRow;
}
const row = [];
const row: ReportRow = [];
for (const col of columns) {
const align = col.align ?? 'left';
const width = col.width ?? 1;
@ -138,6 +143,8 @@ export class GeneralLedger extends Report {
if (typeof value === 'boolean' && fieldname === 'reverted') {
value = value ? t`Reverted` : '';
} else {
value = String(value);
}
row.push({
@ -231,7 +238,7 @@ export class GeneralLedger extends Report {
return { totalDebit, totalCredit };
}
_getGroupedMap(): GroupedMap {
_getGroupedMap(sort: boolean): GroupedMap {
let groupBy: keyof LedgerEntry = 'referenceName';
if (this.groupBy !== 'none') {
groupBy = this.groupBy;
@ -240,13 +247,15 @@ export class GeneralLedger extends Report {
/**
* Sort rows by ascending or descending
*/
this._rawData.sort((a, b) => {
if (this.ascending) {
return a.name - b.name;
}
if (sort) {
this._rawData.sort((a, b) => {
if (this.ascending) {
return +a.date! - +b.date!;
}
return b.name - a.name;
});
return +b.date! - +a.date!;
});
}
/**
* Map remembers the order of insertion
@ -285,6 +294,8 @@ export class GeneralLedger extends Report {
{
fields,
filters,
orderBy: 'date',
order: this.ascending ? 'asc' : 'desc',
}
)) as RawLedgerEntry[];
@ -309,7 +320,7 @@ export class GeneralLedger extends Report {
const filters: QueryFilter = {};
const stringFilters = ['account', 'party', 'referenceName'];
for (const sf in stringFilters) {
for (const sf of stringFilters) {
const value = this[sf];
if (value === undefined) {
continue;
@ -361,6 +372,7 @@ export class GeneralLedger extends Report {
label: t`Ref Name`,
references: 'referenceType',
placeholder: t`Ref Name`,
emptyMessage: t`Change Ref Type`,
fieldname: 'referenceName',
},
{
@ -489,10 +501,4 @@ 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: Always visible scrollbar
*/
}

View File

@ -42,7 +42,7 @@ export abstract class Report extends Observable<RawValue> {
async set(key: string, value: RawValue) {
const field = this.filters.find((f) => f.fieldname === key);
if (field === undefined || value === undefined) {
if (field === undefined) {
return;
}
@ -51,7 +51,12 @@ export abstract class Report extends Observable<RawValue> {
return;
}
this[key] = value;
if (getIsNullOrUndef(value)) {
delete this[key];
} else {
this[key] = value;
}
this.columns = this.getColumns();
await this.setReportData(key);
}

View File

@ -8,7 +8,7 @@
{
"fieldname": "date",
"label": "Date",
"fieldtype": "Date",
"fieldtype": "Datetime",
"readOnly": true
},
{

View File

@ -42,6 +42,7 @@ export interface OptionField extends BaseField {
| FieldTypeEnum.AutoComplete
| FieldTypeEnum.Color;
options: SelectOption[];
emptyMessage?: string;
allowCustom?: boolean;
}
@ -52,6 +53,7 @@ export interface TargetField extends BaseField {
export interface DynamicLinkField extends BaseField {
fieldtype: FieldTypeEnum.DynamicLink;
emptyMessage?: string;
references: string; // Reference to an option field that links to schema
}

View File

@ -1,8 +1,10 @@
<script>
import { fyo } from 'src/initFyo';
import Link from './Link.vue';
export default {
name: 'DynamicLink',
props: ['target'],
inject: ['report'],
extends: Link,
created() {
const watchKey = `doc.${this.df.references}`;
@ -17,11 +19,25 @@ export default {
},
methods: {
getTargetSchemaName() {
if (!this.doc || !this.df.references) {
const references = this.df.references;
if (!references) {
return null;
}
return this.doc[this.df.references];
let schemaName = this.doc?.[references];
if (!schemaName) {
schemaName = this.report?.[references];
}
if (!schemaName) {
return null;
}
if (!fyo.schemaMap[schemaName]) {
return null;
}
return schemaName;
},
},
};

View File

@ -77,8 +77,11 @@ export default {
.map(({ item }) => item);
}
options = options.concat(this.getCreateNewOption());
if (options.length === 0) {
if (this.doc) {
options = options.concat(this.getCreateNewOption());
}
if (options.length === 0 && !this.df.emptyMessage) {
return [
{
component: markRaw({

View File

@ -172,6 +172,10 @@ export default {
return this.t`Empty`;
}
if (this.df.emptyMessage) {
return this.df.emptyMessage;
}
const { schemaName, fieldname } = this.df;
const emptyMessage = fyo.models[schemaName]?.emptyMessages[fieldname]?.(
this.doc
@ -207,7 +211,7 @@ export default {
let item = this.items[this.highlightedIndex];
await this.selectItem(item);
} else if (this.items.length === 1) {
await this.selectItem(this.items[0])
await this.selectItem(this.items[0]);
}
},
highlightItemUp() {

View File

@ -152,7 +152,6 @@ import fs from 'fs';
import { t } from 'fyo';
import { ConfigKeys } from 'fyo/core/types';
import { addNewFile } from 'fyo/telemetry/helpers';
import { cloneDeep } from 'lodash';
import { DateTime } from 'luxon';
import Button from 'src/components/Button.vue';
import LanguageSelector from 'src/components/Controls/LanguageSelector.vue';
@ -237,8 +236,7 @@ export default {
this.creatingDemo = false;
},
setFiles() {
const files = cloneDeep(fyo.config.get('files', []));
this.files = files.filter(({ dbPath }) => fs.existsSync(dbPath));
this.files = setAndGetCleanedConfigFiles();
for (const file of this.files) {
const stats = fs.statSync(file.dbPath);
@ -299,4 +297,24 @@ export default {
FeatherIcon,
},
};
function setAndGetCleanedConfigFiles() {
const files = fyo.config
.get('files', [])
.filter(({ dbPath }) => fs.existsSync(dbPath));
const deduper = [];
const deduped = files.filter(({ companyName, dbPath }) => {
const key = `${companyName}-${dbPath}`;
if (deduper.includes(key)) {
return false;
}
deduper.push(key);
return true;
});
fyo.config.set(ConfigKeys.Files, deduped);
return deduped;
}
</script>

View File

@ -37,6 +37,7 @@
</div>
</template>
<script>
import { computed } from '@vue/reactivity';
import { reports } from 'reports';
import FormControl from 'src/components/Controls/FormControl.vue';
import PageHeader from 'src/components/PageHeader.vue';
@ -54,6 +55,11 @@ export default defineComponent({
report: null,
};
},
provide() {
return {
report: computed(() => this.report),
};
},
components: { PageHeader, FormControl, ListReport },
async mounted() {
await this.setReportData();

View File

@ -24,7 +24,9 @@ export function getValueMapFromList<T, K extends keyof T, V extends keyof T>(
}
export function getRandomString(): string {
return Math.random().toString(36).slice(2, 8);
const randomNumber = Math.random().toString(36).slice(2, 8);
const currentTime = Date.now().toString(36);
return `${randomNumber}-${currentTime}`;
}
export async function sleep(durationMilliseconds: number = 1000) {