mirror of
https://github.com/frappe/books.git
synced 2024-12-22 19:09:01 +00:00
incr: type frappe/utils/format
This commit is contained in:
parent
9ec004184c
commit
a8e208a68a
@ -1,5 +1,5 @@
|
||||
import Doc from 'frappe/model/doc';
|
||||
import { DocMap, ModelMap } from 'frappe/model/types';
|
||||
import { DocMap, ModelMap, SinglesMap } from 'frappe/model/types';
|
||||
import { coreModels } from 'frappe/models';
|
||||
import { getRandomString } from 'frappe/utils';
|
||||
import Observable from 'frappe/utils/observable';
|
||||
@ -8,7 +8,7 @@ import { DocValue, DocValueMap } from './types';
|
||||
|
||||
export class DocHandler {
|
||||
frappe: Frappe;
|
||||
singles: DocMap = {};
|
||||
singles: SinglesMap = {};
|
||||
docs: Observable<DocMap> = new Observable();
|
||||
models: ModelMap = {};
|
||||
|
||||
|
@ -15,7 +15,6 @@ import { format } from './utils/format';
|
||||
import { t, T } from './utils/translation';
|
||||
import { ErrorLog } from './utils/types';
|
||||
|
||||
|
||||
export class Frappe {
|
||||
t = t;
|
||||
T = T;
|
||||
@ -36,6 +35,9 @@ export class Frappe {
|
||||
methods?: Record<string, Function>;
|
||||
temp?: Record<string, unknown>;
|
||||
|
||||
currencyFormatter?: Intl.NumberFormat;
|
||||
currencySymbols: Record<string, string | undefined> = {};
|
||||
|
||||
constructor(DatabaseDemux?: DatabaseDemuxConstructor) {
|
||||
/**
|
||||
* `DatabaseManager` can be passed as the `DatabaseDemux` for
|
||||
@ -84,6 +86,7 @@ export class Frappe {
|
||||
await this.#initializeMoneyMaker();
|
||||
|
||||
this.doc.registerModels(models, regionalModels);
|
||||
await this.doc.getSingle('SystemSettings');
|
||||
this._initialized = true;
|
||||
}
|
||||
|
||||
|
@ -28,6 +28,7 @@ import {
|
||||
import { setName } from './naming';
|
||||
import {
|
||||
Action,
|
||||
CurrenciesMap,
|
||||
DefaultMap,
|
||||
DependsOnMap,
|
||||
EmptyMessageMap,
|
||||
@ -705,6 +706,7 @@ export default class Doc extends Observable<DocValue | Doc[]> {
|
||||
required: RequiredMap = {};
|
||||
hidden: HiddenMap = {};
|
||||
dependsOn: DependsOnMap = {};
|
||||
getCurrencies: CurrenciesMap = {};
|
||||
|
||||
static lists: ListsMap = {};
|
||||
static filters: FiltersMap = {};
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { DocValue, DocValueMap } from 'frappe/core/types';
|
||||
import SystemSettings from 'frappe/models/SystemSettings';
|
||||
import { FieldType } from 'schemas/types';
|
||||
import { QueryFilter } from 'utils/db/types';
|
||||
import { Router } from 'vue-router';
|
||||
@ -22,11 +23,13 @@ export type Default = () => DocValue;
|
||||
export type Validation = (value: DocValue) => Promise<void>;
|
||||
export type Required = () => boolean;
|
||||
export type Hidden = () => boolean;
|
||||
export type GetCurrency = () => string;
|
||||
|
||||
export type FormulaMap = Record<string, Formula | undefined>;
|
||||
export type DefaultMap = Record<string, Default | undefined>;
|
||||
export type ValidationMap = Record<string, Validation | undefined>;
|
||||
export type RequiredMap = Record<string, Required | undefined>;
|
||||
export type CurrenciesMap = Record<string, GetCurrency>;
|
||||
export type HiddenMap = Record<string, Hidden>;
|
||||
export type DependsOnMap = Record<string, string[]>;
|
||||
|
||||
@ -37,6 +40,11 @@ export type DependsOnMap = Record<string, string[]>;
|
||||
export type ModelMap = Record<string, typeof Doc | undefined>;
|
||||
export type DocMap = Record<string, Doc | undefined>;
|
||||
|
||||
export interface SinglesMap {
|
||||
SystemSettings?: SystemSettings
|
||||
[key: string]: Doc | undefined
|
||||
}
|
||||
|
||||
// Static Config properties
|
||||
|
||||
export type FilterFunction = (doc: Doc) => QueryFilter;
|
||||
|
@ -1,8 +1,9 @@
|
||||
export const DEFAULT_INTERNAL_PRECISION = 11;
|
||||
export const DEFAULT_DISPLAY_PRECISION = 2;
|
||||
export const DEFAULT_DATE_FORMAT = 'yyyy-MM-dd';
|
||||
export const DEFAULT_LOCALE = 'en-IN';
|
||||
export const DEFAULT_COUNTRY_CODE = 'in';
|
||||
export const DEFAULT_CURRENCY = 'XXX';
|
||||
export const DEFAULT_CURRENCY = 'INR';
|
||||
export const DEFAULT_LANGUAGE = 'English';
|
||||
export const DEFAULT_NUMBER_SERIES = {
|
||||
SalesInvoice: 'SINV-',
|
||||
|
@ -1,113 +0,0 @@
|
||||
import frappe from 'frappe';
|
||||
import { DateTime } from 'luxon';
|
||||
import { DEFAULT_DISPLAY_PRECISION, DEFAULT_LOCALE } from './consts';
|
||||
|
||||
export function format(value, df, doc) {
|
||||
if (!df) {
|
||||
return value;
|
||||
}
|
||||
|
||||
if (typeof df === 'string') {
|
||||
df = { fieldtype: df };
|
||||
}
|
||||
|
||||
if (df.fieldtype === 'Currency') {
|
||||
const currency = getCurrency(df, doc);
|
||||
value = formatCurrency(value, currency);
|
||||
} else if (df.fieldtype === 'Date') {
|
||||
let dateFormat;
|
||||
if (!frappe.SystemSettings) {
|
||||
dateFormat = 'yyyy-MM-dd';
|
||||
} else {
|
||||
dateFormat = frappe.SystemSettings.dateFormat;
|
||||
}
|
||||
|
||||
if (typeof value === 'string') {
|
||||
// ISO String
|
||||
value = DateTime.fromISO(value);
|
||||
} else if (Object.prototype.toString.call(value) === '[object Date]') {
|
||||
// JS Date
|
||||
value = DateTime.fromJSDate(value);
|
||||
}
|
||||
|
||||
value = value.toFormat(dateFormat);
|
||||
if (value === 'Invalid DateTime') {
|
||||
value = '';
|
||||
}
|
||||
} else if (df.fieldtype === 'Check') {
|
||||
typeof parseInt(value) === 'number'
|
||||
? (value = parseInt(value))
|
||||
: (value = Boolean(value));
|
||||
} else {
|
||||
if (value === null || value === undefined) {
|
||||
value = '';
|
||||
} else {
|
||||
value = value + '';
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
function formatCurrency(value, currency) {
|
||||
let valueString;
|
||||
try {
|
||||
valueString = formatNumber(value);
|
||||
} catch (err) {
|
||||
err.message += ` value: '${value}', type: ${typeof value}`;
|
||||
throw err;
|
||||
}
|
||||
|
||||
const currencySymbol = frappe.currencySymbols[currency];
|
||||
if (currencySymbol) {
|
||||
return currencySymbol + ' ' + valueString;
|
||||
}
|
||||
|
||||
return valueString;
|
||||
}
|
||||
|
||||
function formatNumber(value) {
|
||||
const numberFormatter = getNumberFormatter();
|
||||
if (typeof value === 'number') {
|
||||
return numberFormatter.format(value);
|
||||
}
|
||||
|
||||
if (value.round) {
|
||||
return numberFormatter.format(value.round());
|
||||
}
|
||||
|
||||
const formattedNumber = numberFormatter.format(value);
|
||||
if (formattedNumber === 'NaN') {
|
||||
throw Error(
|
||||
`invalid value passed to formatNumber: '${value}' of type ${typeof value}`
|
||||
);
|
||||
}
|
||||
|
||||
return formattedNumber;
|
||||
}
|
||||
|
||||
function getNumberFormatter() {
|
||||
if (frappe.currencyFormatter) {
|
||||
return frappe.currencyFormatter;
|
||||
}
|
||||
|
||||
const locale = frappe.SystemSettings.locale ?? DEFAULT_LOCALE;
|
||||
const display =
|
||||
frappe.SystemSettings.displayPrecision ?? DEFAULT_DISPLAY_PRECISION;
|
||||
|
||||
return (frappe.currencyFormatter = Intl.NumberFormat(locale, {
|
||||
style: 'decimal',
|
||||
minimumFractionDigits: display,
|
||||
}));
|
||||
}
|
||||
|
||||
function getCurrency(df, doc) {
|
||||
if (!(doc && df.getCurrency)) {
|
||||
return df.currency || frappe.AccountingSettings.currency || '';
|
||||
}
|
||||
|
||||
if (doc.meta && doc.meta.isChild) {
|
||||
return df.getCurrency(doc, doc.parentdoc);
|
||||
}
|
||||
|
||||
return df.getCurrency(doc);
|
||||
}
|
150
frappe/utils/format.ts
Normal file
150
frappe/utils/format.ts
Normal file
@ -0,0 +1,150 @@
|
||||
import frappe from 'frappe';
|
||||
import { DocValue } from 'frappe/core/types';
|
||||
import Doc from 'frappe/model/doc';
|
||||
import { DateTime } from 'luxon';
|
||||
import Money from 'pesa/dist/types/src/money';
|
||||
import { Field, FieldType, FieldTypeEnum } from 'schemas/types';
|
||||
import { getIsNullOrUndef } from 'utils';
|
||||
import {
|
||||
DEFAULT_CURRENCY,
|
||||
DEFAULT_DATE_FORMAT,
|
||||
DEFAULT_DISPLAY_PRECISION,
|
||||
DEFAULT_LOCALE,
|
||||
} from './consts';
|
||||
|
||||
export function format(
|
||||
value: DocValue,
|
||||
df?: string | Field,
|
||||
doc?: Doc
|
||||
): string {
|
||||
if (!df) {
|
||||
return String(value);
|
||||
}
|
||||
|
||||
const field: Field = getField(df);
|
||||
|
||||
if (field.fieldtype === FieldTypeEnum.Currency) {
|
||||
return formatCurrency(value, field, doc);
|
||||
}
|
||||
|
||||
if (field.fieldtype === FieldTypeEnum.Date) {
|
||||
return formatDate(value);
|
||||
}
|
||||
|
||||
if (field.fieldtype === FieldTypeEnum.Check) {
|
||||
return Boolean(value).toString();
|
||||
}
|
||||
|
||||
if (getIsNullOrUndef(value)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return String(value);
|
||||
}
|
||||
|
||||
function formatDate(value: DocValue): string {
|
||||
const dateFormat =
|
||||
(frappe.singles.SystemSettings?.dateFormat as string) ??
|
||||
DEFAULT_DATE_FORMAT;
|
||||
|
||||
let dateValue: DateTime;
|
||||
if (typeof value === 'string') {
|
||||
dateValue = DateTime.fromISO(value);
|
||||
} else if (value instanceof Date) {
|
||||
dateValue = DateTime.fromJSDate(value);
|
||||
} else {
|
||||
dateValue = DateTime.fromSeconds(value as number);
|
||||
}
|
||||
|
||||
const formattedDate = dateValue.toFormat(dateFormat);
|
||||
if (value === 'Invalid DateTime') {
|
||||
return '';
|
||||
}
|
||||
|
||||
return formattedDate;
|
||||
}
|
||||
|
||||
function formatCurrency(value: DocValue, field: Field, doc?: Doc): string {
|
||||
const currency = getCurrency(field, doc);
|
||||
|
||||
let valueString;
|
||||
try {
|
||||
valueString = formatNumber(value);
|
||||
} catch (err) {
|
||||
(err as Error).message += ` value: '${value}', type: ${typeof value}`;
|
||||
throw err;
|
||||
}
|
||||
|
||||
const currencySymbol = frappe.currencySymbols[currency];
|
||||
if (currencySymbol !== undefined) {
|
||||
return currencySymbol + ' ' + valueString;
|
||||
}
|
||||
|
||||
return valueString;
|
||||
}
|
||||
|
||||
function formatNumber(value: DocValue): string {
|
||||
const numberFormatter = getNumberFormatter();
|
||||
if (typeof value === 'number') {
|
||||
return numberFormatter.format(value);
|
||||
}
|
||||
|
||||
if ((value as Money).round) {
|
||||
const floatValue = parseFloat((value as Money).round());
|
||||
return numberFormatter.format(floatValue);
|
||||
}
|
||||
|
||||
const floatValue = parseFloat(value as string);
|
||||
const formattedNumber = numberFormatter.format(floatValue);
|
||||
|
||||
if (formattedNumber === 'NaN') {
|
||||
throw Error(
|
||||
`invalid value passed to formatNumber: '${value}' of type ${typeof value}`
|
||||
);
|
||||
}
|
||||
|
||||
return formattedNumber;
|
||||
}
|
||||
|
||||
function getNumberFormatter() {
|
||||
if (frappe.currencyFormatter) {
|
||||
return frappe.currencyFormatter;
|
||||
}
|
||||
|
||||
const locale =
|
||||
(frappe.singles.SystemSettings?.locale as string) ?? DEFAULT_LOCALE;
|
||||
const display =
|
||||
(frappe.singles.SystemSettings?.displayPrecision as number) ??
|
||||
DEFAULT_DISPLAY_PRECISION;
|
||||
|
||||
return (frappe.currencyFormatter = Intl.NumberFormat(locale, {
|
||||
style: 'decimal',
|
||||
minimumFractionDigits: display,
|
||||
}));
|
||||
}
|
||||
|
||||
function getCurrency(field: Field, doc?: Doc): string {
|
||||
if (doc && doc.getCurrencies[field.fieldname]) {
|
||||
return doc.getCurrencies[field.fieldname]();
|
||||
}
|
||||
|
||||
if (doc && doc.parentdoc?.getCurrencies[field.fieldname]) {
|
||||
return doc.parentdoc.getCurrencies[field.fieldname]();
|
||||
}
|
||||
|
||||
return (
|
||||
(frappe.singles.SystemSettings?.currency as string) ?? DEFAULT_CURRENCY
|
||||
);
|
||||
}
|
||||
|
||||
function getField(df: string | Field): Field {
|
||||
if (typeof df === 'string') {
|
||||
return {
|
||||
label: '',
|
||||
fieldname: '',
|
||||
fieldtype: df as FieldType,
|
||||
};
|
||||
}
|
||||
|
||||
return df;
|
||||
}
|
Loading…
Reference in New Issue
Block a user