2
0
mirror of https://github.com/frappe/books.git synced 2024-12-22 19:09:01 +00:00

incr: convert simple models to .ts Doc subclass

This commit is contained in:
18alantom 2022-04-11 15:11:49 +05:30
parent 309c5c7474
commit cb54100db4
76 changed files with 309 additions and 1057 deletions

View File

@ -29,8 +29,12 @@ import { setName } from './naming';
import {
DefaultMap,
DependsOnMap,
FiltersMap,
FormulaMap,
ListsMap,
ListViewSettings,
RequiredMap,
TreeViewSettings,
ValidationMap,
} from './types';
import { validateSelect } from './validationFunction';
@ -697,4 +701,9 @@ export default class Doc extends Observable<DocValue | Doc[]> {
validations: ValidationMap = {};
required: RequiredMap = {};
dependsOn: DependsOnMap = {};
static lists: ListsMap = {};
static filters: FiltersMap = {};
static listSettings: ListViewSettings = {};
static treeSettings?: TreeViewSettings;
}

View File

@ -1,4 +1,6 @@
import { DocValue } from 'frappe/core/types';
import { FieldType } from 'schemas/types';
import { QueryFilter } from 'utils/db/types';
import Doc from './doc';
/**
@ -13,7 +15,7 @@ import Doc from './doc';
* - `Validation`: Async function that throw an error if the value is invalid.
* - `Required`: Regular function used to decide if a value is mandatory (there are !notnul in the db).
*/
export type Formula = () => Promise<DocValue>;
export type Formula = () => Promise<DocValue | undefined>;
export type Default = () => DocValue;
export type Validation = (value: DocValue) => Promise<void>;
export type Required = () => boolean;
@ -23,11 +25,38 @@ export type DefaultMap = Record<string, Default | undefined>;
export type ValidationMap = Record<string, Validation | undefined>;
export type RequiredMap = Record<string, Required | undefined>;
export type DependsOnMap = Record<string, string[]>
export type DependsOnMap = Record<string, string[]>;
/**
* Should add this for hidden too
*/
export type ModelMap = Record< string, typeof Doc | undefined>
export type DocMap = Record<string, Doc | undefined>;
export type ModelMap = Record<string, typeof Doc | undefined>;
export type DocMap = Record<string, Doc | undefined>;
// Static Config properties
export type FilterFunction = (doc: Doc) => QueryFilter;
export type FiltersMap = Record<string, FilterFunction>;
export type ListFunction = () => string[];
export type ListsMap = Record<string, ListFunction>;
export interface ColumnConfig {
label: string;
fieldtype: FieldType;
size?: string;
render?: (doc: Doc) => { template: string };
getValue?: (doc: Doc) => string;
}
export type ListViewColumn = string | ColumnConfig;
export interface ListViewSettings {
formRoute?: (name: string) => string;
columns?: ListViewColumn[];
}
export interface TreeViewSettings {
parentField: string;
getRootLabel: () => Promise<string>;
}

View File

@ -0,0 +1,50 @@
import frappe from 'frappe';
import Doc from 'frappe/model/doc';
import {
FiltersMap,
ListViewSettings,
TreeViewSettings,
} from 'frappe/model/types';
import { QueryFilter } from 'utils/db/types';
export default class Account extends Doc {
async beforeInsert() {
if (this.accountType || !this.parentAccount) {
return;
}
const account = await frappe.db.get(
'Account',
this.parentAccount as string
);
this.accountType = account.accountType as string;
}
static listSettings: ListViewSettings = {
columns: ['name', 'parentAccount', 'rootType'],
};
static treeSettings: TreeViewSettings = {
parentField: 'parentAccount',
async getRootLabel(): Promise<string> {
const accountingSettings = await frappe.doc.getSingle(
'AccountingSettings'
);
return accountingSettings.companyName as string;
},
};
static filters: FiltersMap = {
parentAccount: (doc: Doc) => {
const filter: QueryFilter = {
isGroup: true,
};
if (doc.rootType) {
filter.rootType = doc.rootType as string;
}
return filter;
},
};
}

View File

@ -0,0 +1,8 @@
import Doc from 'frappe/model/doc';
import { ListViewSettings } from 'frappe/model/types';
export class AccountingLedgerEntry extends Doc {
static listSettings: ListViewSettings = {
columns: ['account', 'party', 'debit', 'credit', 'balance'],
};
}

View File

@ -0,0 +1,20 @@
import Doc from 'frappe/model/doc';
import { FiltersMap, ListsMap } from 'frappe/model/types';
import countryInfo from '../../../fixtures/countryInfo.json';
export class AccountingSettings extends Doc {
static filters: FiltersMap = {
writeOffAccount: () => ({
isGroup: false,
rootType: 'Expense',
}),
roundOffAccount: () => ({
isGroup: false,
rootType: 'Expense',
}),
};
static lists: ListsMap = {
country: () => Object.keys(countryInfo),
};
}

View File

@ -0,0 +1,35 @@
import frappe from 'frappe';
import Doc from 'frappe/model/doc';
import { FiltersMap, FormulaMap } from 'frappe/model/types';
import Money from 'pesa/dist/types/src/money';
export class JournalEntryAccount extends Doc {
getAutoDebitCredit(type: 'debit' | 'credit') {
const otherType = type === 'debit' ? 'credit' : 'debit';
const otherTypeValue = this.get(otherType) as Money;
if (!otherTypeValue.isZero()) {
return frappe.pesa(0);
}
const totalType = this.parentdoc!.getSum('accounts', type, false) as Money;
const totalOtherType = this.parentdoc!.getSum(
'accounts',
otherType,
false
) as Money;
if (totalType.lt(totalOtherType)) {
return totalOtherType.sub(totalType);
}
}
formulas: FormulaMap = {
debit: async () => this.getAutoDebitCredit('debit'),
credit: async () => this.getAutoDebitCredit('credit'),
};
static filters: FiltersMap = {
account: () => ({ isGroup: false }),
};
}

View File

@ -0,0 +1,28 @@
import frappe from 'frappe';
import Doc from 'frappe/model/doc';
import { FiltersMap, FormulaMap } from 'frappe/model/types';
import Money from 'pesa/dist/types/src/money';
export class PaymentFor extends Doc {
formulas: FormulaMap = {
amount: async () => {
const outstandingAmount = this.parentdoc!.getFrom(
this.referenceType as string,
this.referenceName as string,
'outstandingAmount'
) as Money;
if (outstandingAmount) {
return outstandingAmount;
}
return frappe.pesa(0);
},
};
static filters: FiltersMap = {
referenceName: () => ({
outstandingAmount: ['>', 0],
}),
};
}

View File

@ -0,0 +1,95 @@
import frappe from 'frappe';
import Doc from 'frappe/model/doc';
import { FormulaMap, ListsMap } from 'frappe/model/types';
import { DateTime } from 'luxon';
import countryInfo from '../../../fixtures/countryInfo.json';
export function getCOAList() {
return [
{ name: frappe.t`Standard Chart of Accounts`, countryCode: '' },
{ countryCode: 'ae', name: 'U.A.E - Chart of Accounts' },
{
countryCode: 'ca',
name: 'Canada - Plan comptable pour les provinces francophones',
},
{ countryCode: 'gt', name: 'Guatemala - Cuentas' },
{ countryCode: 'hu', name: 'Hungary - Chart of Accounts' },
{ countryCode: 'id', name: 'Indonesia - Chart of Accounts' },
{ countryCode: 'in', name: 'India - Chart of Accounts' },
{ countryCode: 'mx', name: 'Mexico - Plan de Cuentas' },
{ countryCode: 'ni', name: 'Nicaragua - Catalogo de Cuentas' },
{ countryCode: 'nl', name: 'Netherlands - Grootboekschema' },
{ countryCode: 'sg', name: 'Singapore - Chart of Accounts' },
];
}
export class SetupWizard extends Doc {
formulas: FormulaMap = {
fiscalYearStart: async () => {
if (!this.country) return;
const today = DateTime.local();
// @ts-ignore
const fyStart = countryInfo[this.country].fiscal_year_start as
| string
| undefined;
if (fyStart) {
return DateTime.fromFormat(fyStart, 'MM-dd')
.plus({ year: [1, 2, 3].includes(today.month) ? -1 : 0 })
.toISODate();
}
},
fiscalYearEnd: async () => {
if (!this.country) {
return;
}
const today = DateTime.local();
// @ts-ignore
const fyEnd = countryInfo[this.country].fiscal_year_end as
| string
| undefined;
if (fyEnd) {
return DateTime.fromFormat(fyEnd, 'MM-dd')
.plus({ year: [1, 2, 3].includes(today.month) ? 0 : 1 })
.toISODate();
}
},
currency: async () => {
if (!this.country) {
return;
}
// @ts-ignore
return countryInfo[this.country].currency;
},
chartOfAccounts: async () => {
const country = this.get('country') as string | undefined;
if (country === undefined) {
return;
}
// @ts-ignore
const code = (countryInfo[country] as undefined | { code: string })?.code;
if (code === undefined) {
return;
}
const coaList = getCOAList();
const coa = coaList.find(({ countryCode }) => countryCode === code);
if (coa === undefined) {
return coaList[0].name;
}
return coa.name;
},
};
static lists: ListsMap = {
country: () => Object.keys(countryInfo),
chartOfAccounts: () => getCOAList().map(({ name }) => name),
};
}

View File

@ -0,0 +1,13 @@
import Doc from 'frappe/model/doc';
import { FormulaMap } from 'frappe/model/types';
import Money from 'pesa/dist/types/src/money';
export class TaxSummary extends Doc {
formulas: FormulaMap = {
baseAmount: async () => {
const amount = this.amount as Money;
const exchangeRate = (this.parentdoc?.exchangeRate ?? 1) as number;
return amount.mul(exchangeRate);
},
};
}

View File

@ -1,95 +0,0 @@
import frappe, { t } from 'frappe';
import Account from './AccountDocument';
export default {
name: 'Account',
label: t`Account`,
doctype: 'DocType',
documentClass: Account,
isSingle: 0,
isTree: 1,
keywordFields: ['name', 'rootType', 'accountType'],
fields: [
{
fieldname: 'name',
label: t`Account Name`,
fieldtype: 'Data',
required: 1,
},
{
fieldname: 'rootType',
label: t`Root Type`,
fieldtype: 'Select',
placeholder: t`Root Type`,
options: ['Asset', 'Liability', 'Equity', 'Income', 'Expense'],
required: 1,
},
{
fieldname: 'parentAccount',
label: t`Parent Account`,
fieldtype: 'Link',
target: 'Account',
getFilters: (query, doc) => {
const filter = {
isGroup: 1,
};
doc.rootType ? (filter.rootType = doc.rootType) : '';
return filter;
},
},
{
fieldname: 'accountType',
label: t`Account Type`,
placeholder: t`Account Type`,
fieldtype: 'Select',
options: [
'Accumulated Depreciation',
'Bank',
'Cash',
'Chargeable',
'Cost of Goods Sold',
'Depreciation',
'Equity',
'Expense Account',
'Expenses Included In Valuation',
'Fixed Asset',
'Income Account',
'Payable',
'Receivable',
'Round Off',
'Stock',
'Stock Adjustment',
'Stock Received But Not Billed',
'Tax',
'Temporary',
],
},
{
fieldname: 'balance',
label: t`Balance`,
fieldtype: 'Currency',
readOnly: 1,
},
{
fieldname: 'isGroup',
label: t`Is Group`,
fieldtype: 'Check',
},
],
quickEditFields: [
'name',
'rootType',
'parentAccount',
'accountType',
'isGroup',
],
treeSettings: {
parentField: 'parentAccount',
async getRootLabel() {
let accountingSettings = await frappe.getSingle('AccountingSettings');
return accountingSettings.companyName;
},
},
};

View File

@ -1,11 +0,0 @@
import frappe from 'frappe';
import Document from 'frappe/model/document';
export default class Account extends Document {
async validate() {
if (!this.accountType && this.parentAccount) {
const account = frappe.db.get('Account', this.parentAccount);
this.accountType = account.accountType;
}
}
}

View File

@ -1,7 +0,0 @@
import { t } from 'frappe';
export default {
doctype: 'Account',
title: t`Account`,
columns: ['name', 'parentAccount', 'rootType'],
};

View File

@ -1,85 +0,0 @@
import { t } from 'frappe';
export default {
name: 'AccountingLedgerEntry',
label: t`Ledger Entry`,
naming: 'autoincrement',
doctype: 'DocType',
isSingle: 0,
isChild: 0,
keywordFields: ['account', 'party', 'referenceName'],
fields: [
{
fieldname: 'date',
label: t`Date`,
fieldtype: 'Date',
},
{
fieldname: 'account',
label: t`Account`,
fieldtype: 'Link',
target: 'Account',
required: 1,
},
{
fieldname: 'description',
label: t`Description`,
fieldtype: 'Text',
},
{
fieldname: 'party',
label: t`Party`,
fieldtype: 'Link',
target: 'Party',
},
{
fieldname: 'debit',
label: t`Debit`,
fieldtype: 'Currency',
},
{
fieldname: 'credit',
label: t`Credit`,
fieldtype: 'Currency',
},
{
fieldname: 'againstAccount',
label: t`Against Account`,
fieldtype: 'Text',
},
{
fieldname: 'referenceType',
label: t`Ref. Type`,
fieldtype: 'Data',
},
{
fieldname: 'referenceName',
label: t`Ref. Name`,
fieldtype: 'DynamicLink',
references: 'referenceType',
},
{
fieldname: 'balance',
label: t`Balance`,
fieldtype: 'Currency',
},
{
fieldname: 'reverted',
label: t`Reverted`,
fieldtype: 'Check',
default: 0,
},
],
quickEditFields: [
'date',
'account',
'description',
'party',
'debit',
'credit',
'againstAccount',
'referenceType',
'referenceName',
'balance',
],
};

View File

@ -1,7 +0,0 @@
import { t } from 'frappe';
export default {
doctype: 'AccountingLedgerEntry',
title: t`Accounting Ledger Entries`,
columns: ['account', 'party', 'debit', 'credit', 'balance'],
};

View File

@ -1,129 +0,0 @@
import { t } from 'frappe';
import countryInfo from '~/fixtures/countryInfo.json';
const countryList = Object.keys(countryInfo).sort();
export default {
name: 'AccountingSettings',
label: t`Accounting Settings`,
naming: 'name', // {random|autoincrement}
isSingle: 1,
isChild: 0,
isSubmittable: 0,
settings: null,
keywordFields: [],
fields: [
{
label: t`Company Name`,
fieldname: 'companyName',
fieldtype: 'Data',
required: 1,
},
{
label: t`Write Off Account`,
fieldname: 'writeOffAccount',
fieldtype: 'Link',
target: 'Account',
default: 'Write Off',
getFilters() {
return {
isGroup: 0,
rootType: 'Expense',
};
},
},
{
label: t`Round Off Account`,
fieldname: 'roundOffAccount',
fieldtype: 'Link',
target: 'Account',
default: 'Rounded Off',
getFilters() {
return {
isGroup: 0,
rootType: 'Expense',
};
},
},
{
fieldname: 'country',
label: t`Country`,
fieldtype: 'AutoComplete',
placeholder: t`Select Country`,
readOnly: 1,
required: 1,
getList: () => countryList,
},
{
fieldname: 'currency',
label: t`Currency`,
fieldtype: 'Data',
readOnly: 1,
required: 0,
},
{
fieldname: 'fullname',
label: t`Name`,
fieldtype: 'Data',
required: 1,
},
{
fieldname: 'email',
label: t`Email`,
fieldtype: 'Data',
required: 1,
validate: {
type: 'email',
},
},
{
fieldname: 'bankName',
label: t`Bank Name`,
fieldtype: 'Data',
required: 1,
},
{
fieldname: 'fiscalYearStart',
label: t`Fiscal Year Start Date`,
fieldtype: 'Date',
required: 1,
},
{
fieldname: 'fiscalYearEnd',
label: t`Fiscal Year End Date`,
fieldtype: 'Date',
required: 1,
},
{
fieldname: 'setupComplete',
label: t`Setup Complete`,
fieldtype: 'Check',
default: 0,
},
{
fieldname: 'gstin',
label: t`GSTIN`,
fieldtype: 'Data',
placeholder: t`27AAAAA0000A1Z5`,
},
],
quickEditFields: [
'fullname',
'email',
'companyName',
'country',
'currency',
'fiscalYearStart',
'fiscalYearEnd',
'gstin',
],
};

View File

@ -1,18 +0,0 @@
import { t } from 'frappe';
export default {
name: 'Color',
doctype: 'DocType',
fields: [
{
fieldname: 'name',
fieldtype: 'Data',
label: t`Color`,
},
{
fieldname: 'hexvalue',
fieldtype: 'Data',
label: t`Hex Value`,
},
],
};

View File

@ -1,27 +0,0 @@
import { t } from 'frappe';
export default {
name: 'CompanySettings',
label: t`Company Settings`,
naming: 'autoincrement',
isSingle: true,
isChild: false,
keywordFields: ['companyName'],
fields: [
{
fieldname: 'companyName',
label: t`Company Name`,
fieldtype: 'Data',
disabled: false,
required: true,
},
{
fieldname: 'companyAddress',
label: t`Company Address`,
fieldtype: 'Link',
disabled: false,
required: true,
target: 'Address',
},
],
};

View File

@ -1,78 +0,0 @@
import { t } from 'frappe';
export default {
name: 'Contact',
doctype: 'DocType',
isSingle: 0,
naming: 'autoincrement',
pageSettings: {
hideTitle: true,
},
titleField: 'fullName',
keywordFields: ['fullName'],
fields: [
{
fieldname: 'fullName',
label: t`Full Name`,
fieldtype: 'Data',
required: 1,
},
{
fieldname: 'emailAddress',
label: t`Email Address`,
fieldtype: 'Data',
},
{
fieldname: 'userId',
label: t`User ID`,
fieldtype: 'Link',
target: 'User',
hidden: 1,
},
{
fieldname: 'status',
label: t`Status`,
fieldtype: 'Select',
options: ['Passive', 'Open', 'Replied'],
},
{
fieldname: 'gender',
label: t`Gender`,
fieldtype: 'Select',
options: ['Male', 'Female', 'Gender'],
},
{
fieldname: 'mobileNumber',
label: t`Mobile Number`,
fieldtype: 'Data',
},
{
fieldname: 'phone',
label: t`Phone`,
fieldtype: 'Data',
},
],
events: {
validate: (doc) => {},
},
listSettings: {
getFields(list) {
return ['fullName'];
},
getRowHTML(list, data) {
return `<div class="col-11">${list.getNameHTML(data)}</div>`;
},
},
layout: [
// section 1
{
columns: [
{ fields: ['fullName', 'emailAddress', 'userId', 'status'] },
{ fields: ['postalCode', 'gender', 'phone', 'mobileNumber'] },
],
},
],
};

View File

@ -1,38 +0,0 @@
import { t } from 'frappe';
export default {
name: 'Currency',
label: t`Currency`,
doctype: 'DocType',
isSingle: 0,
keywordFields: ['name', 'symbol'],
quickEditFields: ['name', 'symbol'],
fields: [
{
fieldname: 'name',
label: t`Currency Name`,
fieldtype: 'Data',
required: 1,
},
{
fieldname: 'fraction',
label: t`Fraction`,
fieldtype: 'Data',
},
{
fieldname: 'fractionUnits',
label: t`Fraction Units`,
fieldtype: 'Int',
},
{
label: t`Smallest Currency Fraction Value`,
fieldname: 'smallestValue',
fieldtype: 'Currency',
},
{
label: t`Symbol`,
fieldname: 'symbol',
fieldtype: 'Data',
},
],
};

View File

@ -1,67 +0,0 @@
import { t } from 'frappe';
export default {
name: 'GetStarted',
isSingle: 1,
fields: [
{
fieldname: 'onboardingComplete',
label: t`Onboarding Complete`,
fieldtype: 'Check',
},
{
fieldname: 'companySetup',
label: t`Company Setup`,
fieldtype: 'Check',
},
{
fieldname: 'systemSetup',
label: t`System Setup`,
fieldtype: 'Check',
},
{
fieldname: 'invoiceSetup',
label: t`Invoice Setup`,
fieldtype: 'Check',
},
{
fieldname: 'itemCreated',
label: t`Item Created`,
fieldtype: 'Check',
},
{
fieldname: 'customerCreated',
label: t`Customer Created`,
fieldtype: 'Check',
},
{
fieldname: 'supplierCreated',
label: t`Supplier Created`,
fieldtype: 'Check',
},
{
fieldname: 'invoiceCreated',
label: t`Invoice Created`,
fieldtype: 'Check',
},
{
fieldname: 'billCreated',
label: t`Bill Created`,
fieldtype: 'Check',
},
{
fieldname: 'chartOfAccountsReviewed',
label: t`Chart Of Accounts Reviewed`,
fieldtype: 'Check',
},
{
fieldname: 'openingBalanceChecked',
label: t`Opening Balances`,
fieldtype: 'Check',
},
{
fieldname: 'taxesAdded',
label: t`Add Taxes`,
fieldtype: 'Check',
},
],
};

View File

@ -1,45 +0,0 @@
import { t } from 'frappe';
export default {
name: 'JournalEntryAccount',
isChild: 1,
fields: [
{
fieldname: 'account',
label: t`Account`,
placeholder: t`Account`,
fieldtype: 'Link',
target: 'Account',
required: 1,
groupBy: 'rootType',
getFilters: () => ({ isGroup: 0 }),
},
{
fieldname: 'debit',
label: t`Debit`,
fieldtype: 'Currency',
formula: autoDebitCredit('debit'),
},
{
fieldname: 'credit',
label: t`Credit`,
fieldtype: 'Currency',
formula: autoDebitCredit('credit'),
},
],
tableFields: ['account', 'debit', 'credit'],
};
function autoDebitCredit(type) {
let otherType = type === 'debit' ? 'credit' : 'debit';
return (row, doc) => {
if (!row[otherType].isZero()) return frappe.pesa(0);
let totalType = doc.getSum('accounts', type, false);
let totalOtherType = doc.getSum('accounts', otherType, false);
if (totalType.lt(totalOtherType)) {
return totalOtherType.sub(totalType);
}
};
}

View File

@ -1,10 +0,0 @@
import { t } from 'frappe';
export default {
name: 'JournalEntrySettings',
label: t`Journal Entry Setting`,
doctype: 'DocType',
isSingle: 1,
isChild: 0,
keywordFields: [],
fields: [],
};

View File

@ -1,54 +0,0 @@
import frappe, { t } from 'frappe';
const referenceTypeMap = {
SalesInvoice: t`Invoice`,
PurchaseInvoice: t`Bill`,
};
export default {
name: 'PaymentFor',
label: t`Payment For`,
isSingle: 0,
isChild: 1,
keywordFields: [],
tableFields: ['referenceType', 'referenceName', 'amount'],
fields: [
{
fieldname: 'referenceType',
label: t`Reference Type`,
placeholder: t`Type`,
fieldtype: 'Select',
options: Object.keys(referenceTypeMap),
map: referenceTypeMap,
required: 1,
},
{
fieldname: 'referenceName',
label: t`Reference Name`,
fieldtype: 'DynamicLink',
references: 'referenceType',
placeholder: t`Name`,
getFilters() {
return {
outstandingAmount: ['>', 0],
};
},
required: 1,
},
{
fieldname: 'amount',
label: t`Allocated Amount`,
fieldtype: 'Currency',
formula: (row, doc) => {
return (
doc.getFrom(
row.referenceType,
row.referenceName,
'outstandingAmount'
) || frappe.pesa(0)
);
},
required: 1,
},
],
};

View File

@ -1,10 +0,0 @@
import { t } from 'frappe';
export default {
name: 'PaymentSettings',
label: t`Payment Settings`,
isSingle: 1,
isChild: 0,
keywordFields: [],
fields: [],
};

View File

@ -1,105 +0,0 @@
import theme from '@/theme';
import { t } from 'frappe';
export default {
name: 'PrintSettings',
label: t`Print Settings`,
isSingle: 1,
fields: [
{
fieldname: 'logo',
label: t`Logo`,
fieldtype: 'AttachImage',
},
{
fieldname: 'companyName',
label: t`Company Name`,
fieldtype: 'Data',
},
{
fieldname: 'email',
label: t`Email`,
fieldtype: 'Data',
placeholder: t`john@doe.com`,
validate: {
type: 'email',
},
},
{
fieldname: 'displayLogo',
label: t`Display Logo in Invoice`,
fieldtype: 'Check',
},
{
fieldname: 'phone',
label: t`Phone`,
fieldtype: 'Data',
placeholder: t`9888900000`,
validate: {
type: 'phone',
},
},
{
fieldname: 'address',
label: t`Address`,
fieldtype: 'Link',
target: 'Address',
placeholder: t`Click to create`,
inline: true,
},
{
fieldname: 'template',
label: t`Template`,
placeholder: t`Template`,
fieldtype: 'Select',
options: ['Basic', 'Minimal', 'Business'],
default: 'Basic',
},
{
fieldname: 'color',
label: t`Color`,
placeholder: t`Select Color`,
fieldtype: 'Color',
colors: [
'red',
'orange',
'yellow',
'green',
'teal',
'blue',
'indigo',
'purple',
'pink',
]
.map((color) => {
let label = color[0].toUpperCase() + color.slice(1);
return {
label,
value: theme.colors[color]['500'],
};
})
.concat({
label: t`Black`,
value: theme.colors['black'],
}),
},
{
fieldname: 'font',
label: t`Font`,
placeholder: t`Font`,
fieldtype: 'Select',
options: ['Inter', 'Times New Roman', 'Arial', 'Courier'],
default: 'Inter',
},
],
quickEditFields: [
'logo',
'displayLogo',
'template',
'color',
'font',
'email',
'phone',
'address',
],
};

View File

@ -1,10 +0,0 @@
import { t } from 'frappe';
export default {
name: 'PurchaseInvoiceSettings',
label: t`Bills Settings`,
doctype: 'DocType',
isSingle: 1,
isChild: 0,
keywordFields: [],
fields: [],
};

View File

@ -1,37 +0,0 @@
import { t } from 'frappe';
export default {
name: 'SalesInvoiceSettings',
label: t`SalesInvoice Settings`,
doctype: 'DocType',
isSingle: 1,
isChild: 0,
keywordFields: [],
fields: [
{
fieldname: 'template',
label: t`Template`,
placeholder: t`Template`,
fieldtype: 'Select',
options: ['Basic I', 'Basic II', 'Modern'],
required: 1,
default: 'Basic I',
},
{
fieldname: 'font',
label: t`Font`,
placeholder: t`Font`,
fieldtype: 'Select',
options: ['Montserrat', 'Open Sans', 'Oxygen', 'Merriweather'],
required: 1,
default: 'Montserrat',
},
{
fieldname: 'themeColor',
label: t`Theme Color`,
fieldtype: 'Data',
required: 1,
default: '#000000',
hidden: 1,
},
],
};

View File

@ -1,150 +0,0 @@
import { t } from 'frappe';
import { DateTime } from 'luxon';
import countryList from '~/fixtures/countryInfo.json';
import { getCOAList } from '../../../src/utils';
export default {
name: 'SetupWizard',
label: t`Setup Wizard`,
naming: 'name',
isSingle: 1,
isChild: 0,
isSubmittable: 0,
settings: null,
keywordFields: [],
fields: [
{
fieldname: 'companyLogo',
label: t`Company Logo`,
fieldtype: 'AttachImage',
},
{
fieldname: 'country',
label: t`Country`,
fieldtype: 'AutoComplete',
placeholder: t`Select Country`,
required: 1,
getList: () => Object.keys(countryList).sort(),
},
{
fieldname: 'fullname',
label: t`Your Name`,
fieldtype: 'Data',
placeholder: t`John Doe`,
required: 1,
},
{
fieldname: 'email',
label: t`Email`,
fieldtype: 'Data',
placeholder: t`john@doe.com`,
required: 1,
validate: {
type: 'email',
},
},
{
fieldname: 'companyName',
label: t`Company Name`,
placeholder: t`Company Name`,
fieldtype: 'Data',
required: 1,
},
{
fieldname: 'bankName',
label: t`Bank Name`,
fieldtype: 'Data',
placeholder: t`Prime Bank`,
required: 1,
},
{
fieldname: 'fiscalYearStart',
label: t`Fiscal Year Start Date`,
placeholder: t`Fiscal Year Start Date`,
fieldtype: 'Date',
formulaDependsOn: ['country'],
formula: (doc) => {
if (!doc.country) return;
let today = DateTime.local();
let fyStart = countryList[doc.country].fiscal_year_start;
if (fyStart) {
return DateTime.fromFormat(fyStart, 'MM-dd')
.plus({ year: [1, 2, 3].includes(today.month) ? -1 : 0 })
.toISODate();
}
},
required: 1,
},
{
fieldname: 'fiscalYearEnd',
label: t`Fiscal Year End Date`,
placeholder: t`Fiscal Year End Date`,
fieldtype: 'Date',
formulaDependsOn: ['country'],
formula: (doc) => {
if (!doc.country) return;
let today = DateTime.local();
let fyEnd = countryList[doc.country].fiscal_year_end;
if (fyEnd) {
return DateTime.fromFormat(fyEnd, 'MM-dd')
.plus({ year: [1, 2, 3].includes(today.month) ? 0 : 1 })
.toISODate();
}
},
required: 1,
},
{
fieldname: 'currency',
label: t`Currency`,
fieldtype: 'Data',
placeholder: t`Currency`,
formulaDependsOn: ['country'],
formula: (doc) => {
if (!doc.country) return;
return countryList[doc.country].currency;
},
required: 1,
},
{
fieldname: 'completed',
label: t`Completed`,
fieldtype: 'Check',
readonly: 1,
},
{
fieldname: 'chartOfAccounts',
label: t`Chart of Accounts`,
fieldtype: 'AutoComplete',
placeholder: t`Select CoA`,
formulaDependsOn: ['country'],
formula: async (doc) => {
if (!doc.country) return;
const { code } = countryList[doc.country];
const coaList = getCOAList();
const coa = coaList.find(({ countryCode }) => countryCode === code);
if (coa === undefined) {
return coaList[0].name;
}
return coa.name;
},
getList: () => getCOAList().map(({ name }) => name),
},
],
quickEditFields: [
'fullname',
'bankName',
'country',
'currency',
'chartOfAccounts',
'fiscalYearStart',
'fiscalYearEnd',
],
};

View File

@ -1,26 +0,0 @@
import { t } from 'frappe';
export default {
name: 'TaxDetail',
label: t`Tax Detail`,
doctype: 'DocType',
isSingle: 0,
isChild: 1,
keywordFields: [],
fields: [
{
fieldname: 'account',
label: t`Tax Account`,
fieldtype: 'Link',
target: 'Account',
required: 1,
},
{
fieldname: 'rate',
label: t`Rate`,
fieldtype: 'Float',
required: 1,
placeholder: t`0%`,
},
],
tableFields: ['account', 'rate'],
};

View File

@ -1,34 +0,0 @@
import { t } from 'frappe';
export default {
name: 'TaxSummary',
doctype: 'DocType',
isChild: 1,
fields: [
{
fieldname: 'account',
label: t`Tax Account`,
fieldtype: 'Link',
target: 'Account',
required: 1,
},
{
fieldname: 'rate',
label: t`Rate`,
fieldtype: 'Float',
required: 1,
},
{
fieldname: 'amount',
label: t`Amount`,
fieldtype: 'Currency',
required: 1,
},
{
fieldname: 'baseAmount',
label: t`Amount (Company Currency)`,
fieldtype: 'Currency',
formula: (row, doc) => row.amount.mul(doc.exchangeRate),
readOnly: 1,
},
],
};

View File

@ -6,7 +6,7 @@
* match on both ends.
*/
import { SchemaMap } from "schemas/types";
import { SchemaMap } from 'schemas/types';
type UnknownMap = Record<string, unknown>;
export abstract class DatabaseBase {
@ -62,24 +62,32 @@ export interface GetAllOptions {
order?: 'asc' | 'desc';
}
export type QueryFilter = Record<string, string | string[]>;
export type QueryFilter = Record<
string,
boolean | string | (string | number)[]
>;
/**
* DatabaseDemuxBase is an abstract class that ensures that the function signatures
* match between the DatabaseManager and the DatabaseDemux.
*
*
* This allows testing the frontend code while directly plugging in the DatabaseManager
* and bypassing all the API and IPC calls.
*/
export abstract class DatabaseDemuxBase {
abstract getSchemaMap(): Promise<SchemaMap> | SchemaMap
abstract getSchemaMap(): Promise<SchemaMap> | SchemaMap;
abstract createNewDatabase(dbPath: string, countryCode?: string): Promise<void>
abstract createNewDatabase(
dbPath: string,
countryCode?: string
): Promise<void>;
abstract connectToDatabase(dbPath: string, countryCode?: string): Promise<void>
abstract connectToDatabase(
dbPath: string,
countryCode?: string
): Promise<void>;
abstract call(method: DatabaseMethod, ...args: unknown[]): Promise<unknown>
abstract callBespoke(method: string, ...args: unknown[]): Promise<unknown>
abstract call(method: DatabaseMethod, ...args: unknown[]): Promise<unknown>;
abstract callBespoke(method: string, ...args: unknown[]): Promise<unknown>;
}