mirror of
https://github.com/frappe/books.git
synced 2024-12-22 10:58:59 +00:00
refactor: Item and Address models to ts Doc subcls
This commit is contained in:
parent
cb54100db4
commit
781c1d70e9
@ -1,49 +1,10 @@
|
||||
import { showMessageDialog } from '@/utils';
|
||||
import frappe, { t } from 'frappe';
|
||||
import { DateTime } from 'luxon';
|
||||
import { stateCodeMap } from '../regional/in';
|
||||
import { exportCsv, saveExportData } from '../reports/commonExporter';
|
||||
import { getSavePath } from '../src/utils';
|
||||
|
||||
// prettier-ignore
|
||||
export const stateCodeMap = {
|
||||
'JAMMU AND KASHMIR': '1',
|
||||
'HIMACHAL PRADESH': '2',
|
||||
'PUNJAB': '3',
|
||||
'CHANDIGARH': '4',
|
||||
'UTTARAKHAND': '5',
|
||||
'HARYANA': '6',
|
||||
'DELHI': '7',
|
||||
'RAJASTHAN': '8',
|
||||
'UTTAR PRADESH': '9',
|
||||
'BIHAR': '10',
|
||||
'SIKKIM': '11',
|
||||
'ARUNACHAL PRADESH': '12',
|
||||
'NAGALAND': '13',
|
||||
'MANIPUR': '14',
|
||||
'MIZORAM': '15',
|
||||
'TRIPURA': '16',
|
||||
'MEGHALAYA': '17',
|
||||
'ASSAM': '18',
|
||||
'WEST BENGAL': '19',
|
||||
'JHARKHAND': '20',
|
||||
'ODISHA': '21',
|
||||
'CHATTISGARH': '22',
|
||||
'MADHYA PRADESH': '23',
|
||||
'GUJARAT': '24',
|
||||
'DADRA AND NAGAR HAVELI AND DAMAN AND DIU': '26',
|
||||
'MAHARASHTRA': '27',
|
||||
'KARNATAKA': '29',
|
||||
'GOA': '30',
|
||||
'LAKSHADWEEP': '31',
|
||||
'KERALA': '32',
|
||||
'TAMIL NADU': '33',
|
||||
'PUDUCHERRY': '34',
|
||||
'ANDAMAN AND NICOBAR ISLANDS': '35',
|
||||
'TELANGANA': '36',
|
||||
'ANDHRA PRADESH': '37',
|
||||
'LADAKH': '38',
|
||||
};
|
||||
|
||||
const GST = {
|
||||
'GST-0': 0,
|
||||
'GST-0.25': 0.25,
|
||||
|
@ -27,8 +27,10 @@ import {
|
||||
} from './helpers';
|
||||
import { setName } from './naming';
|
||||
import {
|
||||
Action,
|
||||
DefaultMap,
|
||||
DependsOnMap,
|
||||
EmptyMessageMap,
|
||||
FiltersMap,
|
||||
FormulaMap,
|
||||
ListsMap,
|
||||
@ -504,7 +506,7 @@ export default class Doc extends Observable<DocValue | Doc[]> {
|
||||
}
|
||||
|
||||
async getValueFromFormula(field: Field, doc: Doc) {
|
||||
let value: Doc[] | DocValue;
|
||||
let value: Doc[] | DocValue | undefined;
|
||||
|
||||
const formula = doc.formulas[field.fieldtype];
|
||||
if (formula === undefined) {
|
||||
@ -704,6 +706,9 @@ export default class Doc extends Observable<DocValue | Doc[]> {
|
||||
|
||||
static lists: ListsMap = {};
|
||||
static filters: FiltersMap = {};
|
||||
static emptyMessages: EmptyMessageMap = {};
|
||||
static listSettings: ListViewSettings = {};
|
||||
static treeSettings?: TreeViewSettings;
|
||||
|
||||
static actions: Action[] = [];
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { DocValue } from 'frappe/core/types';
|
||||
import { FieldType } from 'schemas/types';
|
||||
import { QueryFilter } from 'utils/db/types';
|
||||
import { Router } from 'vue-router';
|
||||
import Doc from './doc';
|
||||
|
||||
/**
|
||||
@ -39,9 +40,18 @@ export type DocMap = Record<string, Doc | undefined>;
|
||||
export type FilterFunction = (doc: Doc) => QueryFilter;
|
||||
export type FiltersMap = Record<string, FilterFunction>;
|
||||
|
||||
export type ListFunction = () => string[];
|
||||
export type EmptyMessageFunction = (doc: Doc) => string;
|
||||
export type EmptyMessageMap = Record<string, EmptyMessageFunction>;
|
||||
|
||||
export type ListFunction = (doc?: Doc) => string[];
|
||||
export type ListsMap = Record<string, ListFunction>;
|
||||
|
||||
export interface Action {
|
||||
label: string;
|
||||
condition: (doc: Doc) => boolean;
|
||||
action: (doc: Doc, router: Router) => Promise<void>;
|
||||
}
|
||||
|
||||
export interface ColumnConfig {
|
||||
label: string;
|
||||
fieldtype: FieldType;
|
||||
|
@ -1,121 +0,0 @@
|
||||
import { t } from 'frappe';
|
||||
import { stateCodeMap } from '../../../accounting/gst';
|
||||
import countryList from '../../../fixtures/countryInfo.json';
|
||||
import { titleCase } from '../../../src/utils';
|
||||
|
||||
function getStates(doc) {
|
||||
switch (doc.country) {
|
||||
case 'India':
|
||||
return Object.keys(stateCodeMap).map(titleCase).sort();
|
||||
default:
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
name: 'Address',
|
||||
doctype: 'DocType',
|
||||
regional: 1,
|
||||
isSingle: 0,
|
||||
keywordFields: [
|
||||
'addressLine1',
|
||||
'addressLine2',
|
||||
'city',
|
||||
'state',
|
||||
'country',
|
||||
'postalCode',
|
||||
],
|
||||
fields: [
|
||||
{
|
||||
fieldname: 'addressLine1',
|
||||
label: t`Address Line 1`,
|
||||
placeholder: t`Address Line 1`,
|
||||
fieldtype: 'Data',
|
||||
required: 1,
|
||||
},
|
||||
{
|
||||
fieldname: 'addressLine2',
|
||||
label: t`Address Line 2`,
|
||||
placeholder: t`Address Line 2`,
|
||||
fieldtype: 'Data',
|
||||
},
|
||||
{
|
||||
fieldname: 'city',
|
||||
label: t`City / Town`,
|
||||
placeholder: t`City / Town`,
|
||||
fieldtype: 'Data',
|
||||
required: 1,
|
||||
},
|
||||
{
|
||||
fieldname: 'state',
|
||||
label: t`State`,
|
||||
placeholder: t`State`,
|
||||
fieldtype: 'AutoComplete',
|
||||
emptyMessage: (doc) => {
|
||||
if (doc.country) {
|
||||
return 'Enter State';
|
||||
}
|
||||
return 'Enter Country to load States';
|
||||
},
|
||||
getList: getStates,
|
||||
},
|
||||
{
|
||||
fieldname: 'country',
|
||||
label: t`Country`,
|
||||
placeholder: t`Country`,
|
||||
fieldtype: 'AutoComplete',
|
||||
getList: () => Object.keys(countryList).sort(),
|
||||
required: 1,
|
||||
},
|
||||
{
|
||||
fieldname: 'postalCode',
|
||||
label: t`Postal Code`,
|
||||
placeholder: t`Postal Code`,
|
||||
fieldtype: 'Data',
|
||||
},
|
||||
{
|
||||
fieldname: 'emailAddress',
|
||||
label: t`Email Address`,
|
||||
placeholder: t`Email Address`,
|
||||
fieldtype: 'Data',
|
||||
},
|
||||
{
|
||||
fieldname: 'phone',
|
||||
label: t`Phone`,
|
||||
placeholder: t`Phone`,
|
||||
fieldtype: 'Data',
|
||||
},
|
||||
{
|
||||
fieldname: 'fax',
|
||||
label: t`Fax`,
|
||||
fieldtype: 'Data',
|
||||
},
|
||||
{
|
||||
fieldname: 'addressDisplay',
|
||||
fieldtype: 'Text',
|
||||
label: t`Address Display`,
|
||||
readOnly: true,
|
||||
formula: (doc) => {
|
||||
return [
|
||||
doc.addressLine1,
|
||||
doc.addressLine2,
|
||||
doc.city,
|
||||
doc.state,
|
||||
doc.country,
|
||||
doc.postalCode,
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join(', ');
|
||||
},
|
||||
},
|
||||
],
|
||||
quickEditFields: [
|
||||
'addressLine1',
|
||||
'addressLine2',
|
||||
'city',
|
||||
'state',
|
||||
'country',
|
||||
'postalCode',
|
||||
],
|
||||
inlineEditDisplayField: 'addressDisplay',
|
||||
};
|
48
models/baseModels/Address/Address.ts
Normal file
48
models/baseModels/Address/Address.ts
Normal file
@ -0,0 +1,48 @@
|
||||
import frappe from 'frappe';
|
||||
import Doc from 'frappe/model/doc';
|
||||
import { EmptyMessageMap, FormulaMap, ListsMap } from 'frappe/model/types';
|
||||
import { stateCodeMap } from 'regional/in';
|
||||
import { titleCase } from 'utils';
|
||||
import countryInfo from '../../../fixtures/countryInfo.json';
|
||||
|
||||
export class Address extends Doc {
|
||||
formulas: FormulaMap = {
|
||||
addressDisplay: async () => {
|
||||
return [
|
||||
this.addressLine1,
|
||||
this.addressLine2,
|
||||
this.city,
|
||||
this.state,
|
||||
this.country,
|
||||
this.postalCode,
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join(', ');
|
||||
},
|
||||
};
|
||||
|
||||
static lists: ListsMap = {
|
||||
state(doc?: Doc) {
|
||||
const country = doc?.country as string | undefined;
|
||||
switch (country) {
|
||||
case 'India':
|
||||
return Object.keys(stateCodeMap).map(titleCase).sort();
|
||||
default:
|
||||
return [] as string[];
|
||||
}
|
||||
},
|
||||
country() {
|
||||
return Object.keys(countryInfo).sort();
|
||||
},
|
||||
};
|
||||
|
||||
static emptyMessages: EmptyMessageMap = {
|
||||
state: (doc: Doc) => {
|
||||
if (doc.country) {
|
||||
return frappe.t`Enter State`;
|
||||
}
|
||||
|
||||
return frappe.t`Enter Country to load States`;
|
||||
},
|
||||
};
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
import { t } from 'frappe';
|
||||
import { cloneDeep } from 'lodash';
|
||||
import { stateCodeMap } from '../../../accounting/gst';
|
||||
import { titleCase } from '../../../src/utils';
|
||||
import AddressOriginal from './Address';
|
||||
|
||||
export default function getAugmentedAddress({ country }) {
|
||||
const Address = cloneDeep(AddressOriginal);
|
||||
if (!country) {
|
||||
return Address;
|
||||
}
|
||||
|
||||
const stateList = Object.keys(stateCodeMap).map(titleCase).sort();
|
||||
if (country === 'India') {
|
||||
Address.fields = [
|
||||
...Address.fields,
|
||||
{
|
||||
fieldname: 'pos',
|
||||
label: t`Place of Supply`,
|
||||
fieldtype: 'AutoComplete',
|
||||
placeholder: t`Place of Supply`,
|
||||
formula: (doc) => (stateList.includes(doc.state) ? doc.state : ''),
|
||||
getList: () => stateList,
|
||||
},
|
||||
];
|
||||
|
||||
Address.quickEditFields = [...Address.quickEditFields, 'pos'];
|
||||
}
|
||||
|
||||
return Address;
|
||||
}
|
@ -1,168 +0,0 @@
|
||||
import frappe, { t } from 'frappe';
|
||||
|
||||
const itemForMap = {
|
||||
purchases: t`Purchases`,
|
||||
sales: t`Sales`,
|
||||
both: t`Both`,
|
||||
};
|
||||
|
||||
export default {
|
||||
name: 'Item',
|
||||
label: t`Item`,
|
||||
doctype: 'DocType',
|
||||
isSingle: 0,
|
||||
regional: 1,
|
||||
keywordFields: ['name', 'description'],
|
||||
fields: [
|
||||
{
|
||||
fieldname: 'name',
|
||||
label: t`Item Name`,
|
||||
fieldtype: 'Data',
|
||||
placeholder: t`Item Name`,
|
||||
required: 1,
|
||||
},
|
||||
{
|
||||
fieldname: 'image',
|
||||
label: t`Image`,
|
||||
fieldtype: 'AttachImage',
|
||||
},
|
||||
{
|
||||
fieldname: 'description',
|
||||
label: t`Description`,
|
||||
placeholder: t`Item Description`,
|
||||
fieldtype: 'Text',
|
||||
},
|
||||
{
|
||||
fieldname: 'unit',
|
||||
label: t`Unit Type`,
|
||||
fieldtype: 'Select',
|
||||
placeholder: t`Unit Type`,
|
||||
default: 'Unit',
|
||||
options: ['Unit', 'Kg', 'Gram', 'Hour', 'Day'],
|
||||
},
|
||||
{
|
||||
fieldname: 'itemType',
|
||||
label: t`Type`,
|
||||
placeholder: t`Type`,
|
||||
fieldtype: 'Select',
|
||||
default: 'Product',
|
||||
options: ['Product', 'Service'],
|
||||
},
|
||||
{
|
||||
fieldname: 'for',
|
||||
label: t`For`,
|
||||
fieldtype: 'Select',
|
||||
options: Object.keys(itemForMap),
|
||||
map: itemForMap,
|
||||
default: 'both',
|
||||
},
|
||||
{
|
||||
fieldname: 'incomeAccount',
|
||||
label: t`Income`,
|
||||
fieldtype: 'Link',
|
||||
target: 'Account',
|
||||
placeholder: t`Income`,
|
||||
required: 1,
|
||||
disableCreation: true,
|
||||
getFilters: () => {
|
||||
return {
|
||||
isGroup: 0,
|
||||
rootType: 'Income',
|
||||
};
|
||||
},
|
||||
formulaDependsOn: ['itemType'],
|
||||
async formula(doc) {
|
||||
let accountName = 'Service';
|
||||
if (doc.itemType === 'Product') {
|
||||
accountName = 'Sales';
|
||||
}
|
||||
|
||||
const accountExists = await frappe.db.exists('Account', accountName);
|
||||
return accountExists ? accountName : '';
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldname: 'expenseAccount',
|
||||
label: t`Expense`,
|
||||
fieldtype: 'Link',
|
||||
target: 'Account',
|
||||
placeholder: t`Expense`,
|
||||
required: 1,
|
||||
disableCreation: true,
|
||||
getFilters: () => {
|
||||
return {
|
||||
isGroup: 0,
|
||||
rootType: 'Expense',
|
||||
};
|
||||
},
|
||||
formulaDependsOn: ['itemType'],
|
||||
async formula() {
|
||||
const cogs = await frappe.db.getAllRaw('Account', {
|
||||
filters: {
|
||||
accountType: 'Cost of Goods Sold',
|
||||
},
|
||||
});
|
||||
if (cogs.length === 0) {
|
||||
return '';
|
||||
} else {
|
||||
return cogs[0].name;
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldname: 'tax',
|
||||
label: t`Tax`,
|
||||
fieldtype: 'Link',
|
||||
target: 'Tax',
|
||||
placeholder: t`Tax`,
|
||||
},
|
||||
{
|
||||
fieldname: 'rate',
|
||||
label: t`Rate`,
|
||||
fieldtype: 'Currency',
|
||||
validate(value) {
|
||||
if (value.isNegative()) {
|
||||
throw new frappe.errors.ValidationError(t`Rate can't be negative.`);
|
||||
}
|
||||
},
|
||||
},
|
||||
],
|
||||
quickEditFields: [
|
||||
'rate',
|
||||
'unit',
|
||||
'itemType',
|
||||
'for',
|
||||
'tax',
|
||||
'description',
|
||||
'incomeAccount',
|
||||
'expenseAccount',
|
||||
],
|
||||
actions: [
|
||||
{
|
||||
label: t`New Invoice`,
|
||||
condition: (doc) => !doc.isNew(),
|
||||
action: async (doc, router) => {
|
||||
const invoice = await frappe.getEmptyDoc('SalesInvoice');
|
||||
invoice.append('items', {
|
||||
item: doc.name,
|
||||
rate: doc.rate,
|
||||
tax: doc.tax,
|
||||
});
|
||||
router.push(`/edit/SalesInvoice/${invoice.name}`);
|
||||
},
|
||||
},
|
||||
{
|
||||
label: t`New Bill`,
|
||||
condition: (doc) => !doc.isNew(),
|
||||
action: async (doc, router) => {
|
||||
const invoice = await frappe.getEmptyDoc('PurchaseInvoice');
|
||||
invoice.append('items', {
|
||||
item: doc.name,
|
||||
rate: doc.rate,
|
||||
tax: doc.tax,
|
||||
});
|
||||
router.push(`/edit/PurchaseInvoice/${invoice.name}`);
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
98
models/baseModels/Item/Item.ts
Normal file
98
models/baseModels/Item/Item.ts
Normal file
@ -0,0 +1,98 @@
|
||||
import frappe from 'frappe';
|
||||
import { DocValue } from 'frappe/core/types';
|
||||
import Doc from 'frappe/model/doc';
|
||||
import {
|
||||
Action,
|
||||
DependsOnMap,
|
||||
FiltersMap,
|
||||
FormulaMap,
|
||||
ListViewSettings,
|
||||
ValidationMap,
|
||||
} from 'frappe/model/types';
|
||||
import Money from 'pesa/dist/types/src/money';
|
||||
|
||||
export class Item extends Doc {
|
||||
formulas: FormulaMap = {
|
||||
incomeAccount: async () => {
|
||||
let accountName = 'Service';
|
||||
if (this.itemType === 'Product') {
|
||||
accountName = 'Sales';
|
||||
}
|
||||
|
||||
const accountExists = await frappe.db.exists('Account', accountName);
|
||||
return accountExists ? accountName : '';
|
||||
},
|
||||
expenseAccount: async () => {
|
||||
const cogs = await frappe.db.getAllRaw('Account', {
|
||||
filters: {
|
||||
accountType: 'Cost of Goods Sold',
|
||||
},
|
||||
});
|
||||
|
||||
if (cogs.length === 0) {
|
||||
return '';
|
||||
} else {
|
||||
return cogs[0].name as string;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
static filters: FiltersMap = {
|
||||
incomeAccount: () => ({
|
||||
isGroup: false,
|
||||
rootType: 'Income',
|
||||
}),
|
||||
expenseAccount: () => ({
|
||||
isGroup: false,
|
||||
rootType: 'Expense',
|
||||
}),
|
||||
};
|
||||
|
||||
dependsOn: DependsOnMap = {
|
||||
incomeAccount: ['itemType'],
|
||||
expenseAccount: ['itemType'],
|
||||
};
|
||||
|
||||
validations: ValidationMap = {
|
||||
rate: async (value: DocValue) => {
|
||||
if ((value as Money).isNegative()) {
|
||||
throw new frappe.errors.ValidationError(
|
||||
frappe.t`Rate can't be negative.`
|
||||
);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
actions: Action[] = [
|
||||
{
|
||||
label: frappe.t`New Invoice`,
|
||||
condition: (doc) => !doc.isNew,
|
||||
action: async (doc, router) => {
|
||||
const invoice = await frappe.doc.getEmptyDoc('SalesInvoice');
|
||||
invoice.append('items', {
|
||||
item: doc.name as string,
|
||||
rate: doc.rate as Money,
|
||||
tax: doc.tax as string,
|
||||
});
|
||||
router.push(`/edit/SalesInvoice/${invoice.name}`);
|
||||
},
|
||||
},
|
||||
{
|
||||
label: frappe.t`New Bill`,
|
||||
condition: (doc) => !doc.isNew,
|
||||
action: async (doc, router) => {
|
||||
const invoice = await frappe.doc.getEmptyDoc('PurchaseInvoice');
|
||||
invoice.append('items', {
|
||||
item: doc.name as string,
|
||||
rate: doc.rate as Money,
|
||||
tax: doc.tax as string,
|
||||
});
|
||||
router.push(`/edit/PurchaseInvoice/${invoice.name}`);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
listSettings: ListViewSettings = {
|
||||
columns: ['name', 'unit', 'tax', 'rate'],
|
||||
};
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
import { t } from 'frappe';
|
||||
|
||||
export default {
|
||||
doctype: 'Item',
|
||||
title: t`Items`,
|
||||
columns: ['name', 'unit', 'tax', 'rate'],
|
||||
};
|
@ -1,29 +0,0 @@
|
||||
import { t } from 'frappe';
|
||||
import { cloneDeep } from 'lodash';
|
||||
import ItemOriginal from './Item';
|
||||
|
||||
export default function getAugmentedItem({ country }) {
|
||||
const Item = cloneDeep(ItemOriginal);
|
||||
if (!country) {
|
||||
return Item;
|
||||
}
|
||||
|
||||
if (country === 'India') {
|
||||
const nameFieldIndex = Item.fields.findIndex((i) => i.fieldname === 'name');
|
||||
|
||||
Item.fields = [
|
||||
...Item.fields.slice(0, nameFieldIndex + 1),
|
||||
{
|
||||
fieldname: 'hsnCode',
|
||||
label: t`HSN/SAC`,
|
||||
fieldtype: 'Int',
|
||||
placeholder: t`HSN/SAC Code`,
|
||||
},
|
||||
...Item.fields.slice(nameFieldIndex + 1, Item.fields.length),
|
||||
];
|
||||
|
||||
Item.quickEditFields.unshift('hsnCode');
|
||||
}
|
||||
|
||||
return Item;
|
||||
}
|
37
models/regionalModels/in/Address.ts
Normal file
37
models/regionalModels/in/Address.ts
Normal file
@ -0,0 +1,37 @@
|
||||
import { FormulaMap, ListsMap } from 'frappe/model/types';
|
||||
import { Address as BaseAddress } from 'models/baseModels/Address/Address';
|
||||
import { stateCodeMap } from 'regional/in';
|
||||
import { titleCase } from 'utils';
|
||||
|
||||
export class Address extends BaseAddress {
|
||||
formulas: FormulaMap = {
|
||||
addressDisplay: async () => {
|
||||
return [
|
||||
this.addressLine1,
|
||||
this.addressLine2,
|
||||
this.city,
|
||||
this.state,
|
||||
this.country,
|
||||
this.postalCode,
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join(', ');
|
||||
},
|
||||
|
||||
pos: async () => {
|
||||
const stateList = Object.keys(stateCodeMap).map(titleCase).sort();
|
||||
const state = this.state as string;
|
||||
if (stateList.includes(state)) {
|
||||
return state;
|
||||
}
|
||||
return '';
|
||||
},
|
||||
};
|
||||
|
||||
static lists: ListsMap = {
|
||||
...BaseAddress.lists,
|
||||
pos: () => {
|
||||
return Object.keys(stateCodeMap).map(titleCase).sort();
|
||||
},
|
||||
};
|
||||
}
|
39
regional/in.ts
Normal file
39
regional/in.ts
Normal file
@ -0,0 +1,39 @@
|
||||
// prettier-ignore
|
||||
export const stateCodeMap = {
|
||||
'JAMMU AND KASHMIR': '1',
|
||||
'HIMACHAL PRADESH': '2',
|
||||
'PUNJAB': '3',
|
||||
'CHANDIGARH': '4',
|
||||
'UTTARAKHAND': '5',
|
||||
'HARYANA': '6',
|
||||
'DELHI': '7',
|
||||
'RAJASTHAN': '8',
|
||||
'UTTAR PRADESH': '9',
|
||||
'BIHAR': '10',
|
||||
'SIKKIM': '11',
|
||||
'ARUNACHAL PRADESH': '12',
|
||||
'NAGALAND': '13',
|
||||
'MANIPUR': '14',
|
||||
'MIZORAM': '15',
|
||||
'TRIPURA': '16',
|
||||
'MEGHALAYA': '17',
|
||||
'ASSAM': '18',
|
||||
'WEST BENGAL': '19',
|
||||
'JHARKHAND': '20',
|
||||
'ODISHA': '21',
|
||||
'CHATTISGARH': '22',
|
||||
'MADHYA PRADESH': '23',
|
||||
'GUJARAT': '24',
|
||||
'DADRA AND NAGAR HAVELI AND DAMAN AND DIU': '26',
|
||||
'MAHARASHTRA': '27',
|
||||
'KARNATAKA': '29',
|
||||
'GOA': '30',
|
||||
'LAKSHADWEEP': '31',
|
||||
'KERALA': '32',
|
||||
'TAMIL NADU': '33',
|
||||
'PUDUCHERRY': '34',
|
||||
'ANDAMAN AND NICOBAR ISLANDS': '35',
|
||||
'TELANGANA': '36',
|
||||
'ANDHRA PRADESH': '37',
|
||||
'LADAKH': '38',
|
||||
};
|
@ -83,5 +83,6 @@
|
||||
"state",
|
||||
"country",
|
||||
"postalCode"
|
||||
]
|
||||
],
|
||||
"inlineEditDisplayField": "addressDisplay"
|
||||
}
|
||||
|
@ -124,6 +124,7 @@ export interface Schema {
|
||||
keywordFields?: string[]; // Used to get fields that are to be used for search.
|
||||
quickEditFields?: string[]; // Used to get fields for the quickEditForm
|
||||
treeSettings?: TreeSettings; // Used to determine root nodes
|
||||
inlineEditDisplayField?:string,// Display field if inline editable
|
||||
naming?: Naming; // Used for assigning name, default is 'random' else 'numberSeries' if present
|
||||
}
|
||||
|
||||
|
13
src/utils.js
13
src/utils.js
@ -423,19 +423,6 @@ export function showToast(props) {
|
||||
replaceAndAppendMount(toast, 'toast-target');
|
||||
}
|
||||
|
||||
export function titleCase(phrase) {
|
||||
return phrase
|
||||
.split(' ')
|
||||
.map((word) => {
|
||||
const wordLower = word.toLowerCase();
|
||||
if (['and', 'an', 'a', 'from', 'by', 'on'].includes(wordLower)) {
|
||||
return wordLower;
|
||||
}
|
||||
return wordLower[0].toUpperCase() + wordLower.slice(1);
|
||||
})
|
||||
.join(' ');
|
||||
}
|
||||
|
||||
export async function getIsSetupComplete() {
|
||||
try {
|
||||
const { setupComplete } = await frappe.getSingle('AccountingSettings');
|
||||
|
@ -18,6 +18,7 @@
|
||||
"@/*": ["src/*"],
|
||||
"schemas/*": ["schemas/*"],
|
||||
"backend/*": ["backend/*"],
|
||||
"regional/*": ["regional/*"],
|
||||
"utils/*": ["utils/*"]
|
||||
},
|
||||
"lib": ["esnext", "dom", "dom.iterable", "scripthost"]
|
||||
|
@ -55,3 +55,16 @@ export function getListFromMap<T>(map: Record<string, T>): T[] {
|
||||
export function getIsNullOrUndef(value: unknown): boolean {
|
||||
return value === null || value === undefined;
|
||||
}
|
||||
|
||||
export function titleCase(phrase: string): string {
|
||||
return phrase
|
||||
.split(' ')
|
||||
.map((word) => {
|
||||
const wordLower = word.toLowerCase();
|
||||
if (['and', 'an', 'a', 'from', 'by', 'on'].includes(wordLower)) {
|
||||
return wordLower;
|
||||
}
|
||||
return wordLower[0].toUpperCase() + wordLower.slice(1);
|
||||
})
|
||||
.join(' ');
|
||||
}
|
||||
|
@ -44,6 +44,7 @@ module.exports = {
|
||||
schemas: path.resolve(__dirname, './schemas'),
|
||||
backend: path.resolve(__dirname, './backend'),
|
||||
utils: path.resolve(__dirname, './utils'),
|
||||
regional: path.resolve(__dirname, './regional'),
|
||||
});
|
||||
|
||||
config.plugins.push(
|
||||
|
Loading…
Reference in New Issue
Block a user