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:
parent
64d1f13e42
commit
3cdba15b81
@ -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[] = [];
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
*/
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -8,7 +8,7 @@
|
||||
{
|
||||
"fieldname": "date",
|
||||
"label": "Date",
|
||||
"fieldtype": "Date",
|
||||
"fieldtype": "Datetime",
|
||||
"readOnly": true
|
||||
},
|
||||
{
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
},
|
||||
},
|
||||
};
|
||||
|
@ -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({
|
||||
|
@ -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() {
|
||||
|
@ -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>
|
||||
|
@ -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();
|
||||
|
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user