2
0
mirror of https://github.com/frappe/books.git synced 2025-02-02 12:08:27 +00:00

incr: add keyword fields, start with doc search

This commit is contained in:
18alantom 2022-05-04 21:55:08 +05:30
parent eedb4415ce
commit a0f812e1a8
21 changed files with 190 additions and 51 deletions

View File

@ -243,8 +243,9 @@ export default class DatabaseCore extends DatabaseBase {
} }
const hasCreated = !!schema.fields.find((f) => f.fieldname === 'created'); const hasCreated = !!schema.fields.find((f) => f.fieldname === 'created');
const { const {
fields = ['name', ...(schema.keywordFields ?? [])], fields = ['name'],
filters, filters,
offset, offset,
limit, limit,

View File

@ -143,13 +143,5 @@
"readOnly": true "readOnly": true
} }
], ],
"quickEditFields": [ "quickEditFields": ["name", "rootType", "parentAccount", "accountType", "isGroup", "balance"]
"name",
"rootType",
"parentAccount",
"accountType",
"isGroup",
"balance"
],
"keywordFields": ["name", "rootType", "accountType"]
} }

View File

@ -83,6 +83,5 @@
"balance", "balance",
"reverted", "reverted",
"reverts" "reverts"
], ]
"keywordFields": ["account", "party", "referenceName"]
} }

View File

@ -76,13 +76,5 @@
"country", "country",
"postalCode" "postalCode"
], ],
"keywordFields": [
"addressLine1",
"addressLine2",
"city",
"state",
"country",
"postalCode"
],
"inlineEditDisplayField": "addressDisplay" "inlineEditDisplayField": "addressDisplay"
} }

View File

@ -18,6 +18,5 @@
"required": true, "required": true,
"target": "Address" "target": "Address"
} }
], ]
"keywordFields": ["companyName"]
} }

View File

@ -30,6 +30,5 @@
"fieldtype": "Data" "fieldtype": "Data"
} }
], ],
"keywordFields": ["name", "symbol"],
"quickEditFields": ["name", "symbol"] "quickEditFields": ["name", "symbol"]
} }

View File

@ -135,5 +135,5 @@
"expenseAccount", "expenseAccount",
"hsnCode" "hsnCode"
], ],
"keywordFields": ["name", "description"] "keywordFields": ["name", "itemType", "for"]
} }

View File

@ -90,7 +90,7 @@
"fieldname": "userRemark", "fieldname": "userRemark",
"label": "User Remark", "label": "User Remark",
"fieldtype": "Text", "fieldtype": "Text",
"placeholder": "User Remark" "placeholder": "Add a remark"
}, },
{ {
"fieldname": "numberSeries", "fieldname": "numberSeries",
@ -100,5 +100,6 @@
"required": true, "required": true,
"default": "JV-" "default": "JV-"
} }
] ],
} "keywordFields": ["name", "entryType"]
}

View File

@ -23,5 +23,6 @@
"fieldtype": "Currency" "fieldtype": "Currency"
} }
], ],
"tableFields": ["account", "debit", "credit"] "tableFields": ["account", "debit", "credit"],
} "keywordFields": ["account"]
}

View File

@ -59,6 +59,5 @@
"readOnly": true "readOnly": true
} }
], ],
"quickEditFields": ["referenceType", "start", "padZeros"], "quickEditFields": ["referenceType", "start", "padZeros"]
"keywordFields": []
} }

View File

@ -90,5 +90,5 @@
"role", "role",
"taxId" "taxId"
], ],
"keywordFields": ["name"] "keywordFields": ["name", "email", "role"]
} }

View File

@ -36,5 +36,6 @@
"required": true "required": true
} }
], ],
"tableFields": ["referenceType", "referenceName", "amount"] "tableFields": ["referenceType", "referenceName", "amount"],
"keywordFields": ["referenceName", "referenceType"]
} }

View File

@ -105,5 +105,5 @@
"default": "PINV-" "default": "PINV-"
} }
], ],
"keywordFields": ["name", "party", "numberSeries"] "keywordFields": ["name", "party"]
} }

View File

@ -68,5 +68,6 @@
"placeholder": "HSN/SAC Code" "placeholder": "HSN/SAC Code"
} }
], ],
"tableFields": ["item", "tax", "quantity", "rate", "amount"] "tableFields": ["item", "tax", "quantity", "rate", "amount"],
"keywordFields": ["item", "tax"]
} }

View File

@ -4,7 +4,6 @@
"isSingle": false, "isSingle": false,
"isChild": false, "isChild": false,
"isSubmittable": true, "isSubmittable": true,
"keywordFields": ["name", "party"],
"fields": [ "fields": [
{ {
"label": "Invoice No", "label": "Invoice No",
@ -93,6 +92,7 @@
{ {
"fieldname": "terms", "fieldname": "terms",
"label": "Notes", "label": "Notes",
"placeholder": "Add invoice terms",
"fieldtype": "Text" "fieldtype": "Text"
}, },
{ {
@ -103,5 +103,6 @@
"required": true, "required": true,
"default": "SINV-" "default": "SINV-"
} }
] ],
"keywordFields": ["name", "party"]
} }

View File

@ -69,5 +69,6 @@
"placeholder": "HSN/SAC Code" "placeholder": "HSN/SAC Code"
} }
], ],
"tableFields": ["item", "tax", "quantity", "rate", "amount"] "tableFields": ["item", "tax", "quantity", "rate", "amount"],
"keywordFields": ["item", "tax"]
} }

View File

@ -22,6 +22,5 @@
"fieldtype": "Data", "fieldtype": "Data",
"required": true "required": true
} }
], ]
"keywordFields": [] }
}

View File

@ -90,12 +90,5 @@
"required": true "required": true
} }
], ],
"quickEditFields": [ "quickEditFields": ["locale", "dateFormat", "currency", "displayPrecision", "hideGetStarted"]
"locale",
"dateFormat",
"currency",
"displayPrecision",
"hideGetStarted"
],
"keywordFields": []
} }

View File

@ -48,7 +48,6 @@ export default {
'name', 'name',
schema.titleField, schema.titleField,
this.df.groupBy, this.df.groupBy,
...schema.keywordFields,
]), ]),
].filter(Boolean); ].filter(Boolean);

View File

@ -108,7 +108,7 @@ function getListConfig(schemaName) {
const listConfig = fyo.models[schemaName]?.getListViewSettings?.(fyo); const listConfig = fyo.models[schemaName]?.getListViewSettings?.(fyo);
if (listConfig?.columns === undefined) { if (listConfig?.columns === undefined) {
return { return {
columns: fyo.schemaMap[schemaName].keywordFields ?? ['name'], columns: ['name'],
}; };
} }
return listConfig; return listConfig;

View File

@ -1,7 +1,10 @@
import { t } from 'fyo'; import { t } from 'fyo';
import { DocValueMap } from 'fyo/core/types';
import { ModelNameEnum } from 'models/types'; import { ModelNameEnum } from 'models/types';
import reports from 'reports/view'; import reports from 'reports/view';
import { OptionField } from 'schemas/types';
import { fyo } from 'src/initFyo'; import { fyo } from 'src/initFyo';
import { GetAllOptions } from 'utils/db/types';
import { routeTo } from './ui'; import { routeTo } from './ui';
export const searchGroups = ['Docs', 'List', 'Create', 'Report', 'Page']; export const searchGroups = ['Docs', 'List', 'Create', 'Report', 'Page'];
@ -208,3 +211,161 @@ export function getSearchList() {
getSetupList(), getSetupList(),
].flat(); ].flat();
} }
interface Searchable {
schemaName: string;
fields: string[];
meta: string[];
isChild: boolean;
isSubmittable: boolean;
}
interface Keyword {
values: string[];
meta: Record<string, string | boolean | undefined>;
priority: number;
}
interface Keywords {
searchable: Searchable;
keywords: Keyword[];
}
class Search {
keywords: Record<string, Keywords>;
priorityMap: Record<string, number> = {
[ModelNameEnum.SalesInvoice]: 125,
[ModelNameEnum.PurchaseInvoice]: 100,
[ModelNameEnum.Payment]: 75,
[ModelNameEnum.Item]: 50,
[ModelNameEnum.Party]: 50,
[ModelNameEnum.JournalEntry]: 50,
};
constructor() {
this.keywords = {};
}
getSearchList() {
const keywords = Object.values(this.keywords);
return keywords.map((kw) => kw.keywords).flat();
}
async fetchKeywords() {
const searchables = this.#getSearchables();
for (const searchable of searchables) {
const options: GetAllOptions = {
fields: [searchable.fields, searchable.meta].flat(),
order: 'desc',
};
if (!searchable.isChild) {
options.orderBy = 'modified';
}
const maps = await fyo.db.getAllRaw(searchable.schemaName, options);
this.addToSearchable(maps, searchable);
}
this.#setPriority();
}
#getSearchables(): Searchable[] {
const searchable: Searchable[] = [];
for (const schemaName of Object.keys(fyo.schemaMap)) {
const schema = fyo.schemaMap[schemaName];
if (!schema?.keywordFields?.length) {
continue;
}
const fields = [...schema.keywordFields];
const meta = [];
if (schema.isChild) {
meta.push('parent', 'parentSchemaName');
}
if (schema.isSubmittable) {
meta.push('submitted', 'cancelled');
}
searchable.push({
schemaName,
fields,
meta,
isChild: !!schema.isChild,
isSubmittable: !!schema.isSubmittable,
});
}
return searchable;
}
#setPriority() {
for (const schemaName in this.keywords) {
const kw = this.keywords[schemaName];
const basePriority = this.priorityMap[schemaName] ?? 0;
for (const k of kw.keywords) {
k.priority += basePriority;
if (k.meta.submitted) {
k.priority += 25;
}
if (k.meta.cancelled) {
k.priority -= 200;
}
if (kw.searchable.isChild) {
k.priority -= 150;
}
}
}
}
addToSearchable(maps: DocValueMap[], searchable: Searchable) {
if (!maps.length) {
return;
}
this.keywords[searchable.schemaName] ??= { searchable, keywords: [] };
for (const map of maps) {
const keyword: Keyword = { values: [], meta: {}, priority: 0 };
this.#setKeywords(map, searchable, keyword);
this.#setMeta(map, searchable, keyword);
this.keywords[searchable.schemaName]!.keywords.push(keyword);
}
}
#setKeywords(map: DocValueMap, searchable: Searchable, keyword: Keyword) {
// Set individual field values
for (const fn of searchable.fields) {
let value = map[fn] as string | undefined;
const field = fyo.getField(searchable.schemaName, fn);
const { options } = field as OptionField;
if (options) {
value = options.find((o) => o.value === value)?.label ?? value;
}
keyword.values.push(value ?? '');
}
}
#setMeta(map: DocValueMap, searchable: Searchable, keyword: Keyword) {
// Set the meta map
for (const fn of searchable.meta) {
const meta = map[fn];
if (typeof meta === 'number') {
keyword.meta[fn] = Boolean(meta);
} else if (typeof meta === 'string') {
keyword.meta[fn] = meta;
}
}
keyword.meta.schemaName = searchable.schemaName;
}
}
//@ts-ignore
window.sc = new Search();