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

incr: get dataimport to work

- need to test on child table docs
This commit is contained in:
18alantom 2022-05-05 16:14:26 +05:30
parent 0a3fe90990
commit bd6f110553
16 changed files with 192 additions and 172 deletions

View File

@ -164,7 +164,7 @@ function toDocString(value: RawValue, field: Field) {
} }
function toDocDate(value: RawValue, field: Field) { function toDocDate(value: RawValue, field: Field) {
if (value === null) { if (value === null || value === '') {
return null; return null;
} }
@ -181,6 +181,10 @@ function toDocDate(value: RawValue, field: Field) {
} }
function toDocCurrency(value: RawValue, field: Field, fyo: Fyo) { function toDocCurrency(value: RawValue, field: Field, fyo: Fyo) {
if (value === '') {
return fyo.pesa(0);
}
if (typeof value === 'string') { if (typeof value === 'string') {
return fyo.pesa(value); return fyo.pesa(value);
} }
@ -201,6 +205,10 @@ function toDocCurrency(value: RawValue, field: Field, fyo: Fyo) {
} }
function toDocInt(value: RawValue, field: Field): number { function toDocInt(value: RawValue, field: Field): number {
if (value === '') {
return 0;
}
if (typeof value === 'string') { if (typeof value === 'string') {
value = parseInt(value); value = parseInt(value);
} }
@ -209,6 +217,10 @@ function toDocInt(value: RawValue, field: Field): number {
} }
function toDocFloat(value: RawValue, field: Field): number { function toDocFloat(value: RawValue, field: Field): number {
if (value === '') {
return 0;
}
if (typeof value === 'boolean') { if (typeof value === 'boolean') {
return Number(value); return Number(value);
} }

View File

@ -2,24 +2,24 @@ import { Fyo } from 'fyo';
import NumberSeries from 'fyo/models/NumberSeries'; import NumberSeries from 'fyo/models/NumberSeries';
import { DEFAULT_SERIES_START } from 'fyo/utils/consts'; import { DEFAULT_SERIES_START } from 'fyo/utils/consts';
import { BaseError } from 'fyo/utils/errors'; import { BaseError } from 'fyo/utils/errors';
import { Field, Schema } from 'schemas/types';
import { getRandomString } from 'utils'; import { getRandomString } from 'utils';
import { Doc } from './doc'; import { Doc } from './doc';
export function getNumberSeries(schema: Schema): Field | undefined {
const numberSeries = schema.fields.find(
(f) => f.fieldname === 'numberSeries'
);
return numberSeries;
}
export function isNameAutoSet(schemaName: string, fyo: Fyo): boolean { export function isNameAutoSet(schemaName: string, fyo: Fyo): boolean {
const schema = fyo.schemaMap[schemaName]!; const schema = fyo.schemaMap[schemaName]!;
if (schema.naming === 'manual') {
return false;
}
if (schema.naming === 'autoincrement') { if (schema.naming === 'autoincrement') {
return true; return true;
} }
const numberSeries = getNumberSeries(schema); if (schema.naming === 'random') {
return true;
}
const numberSeries = fyo.getField(schema.name, 'numberSeries');
if (numberSeries) { if (numberSeries) {
return true; return true;
} }

View File

@ -98,9 +98,9 @@ export abstract class InvoiceItem extends Doc {
const itemList = doc.parentdoc!.items as Doc[]; const itemList = doc.parentdoc!.items as Doc[];
const items = itemList.map((d) => d.item as string).filter(Boolean); const items = itemList.map((d) => d.item as string).filter(Boolean);
let itemNotFor = 'sales'; let itemNotFor = 'Sales';
if (doc.isSales) { if (doc.isSales) {
itemNotFor = 'purchases'; itemNotFor = 'Purchases';
} }
const baseFilter = { for: ['not in', [itemNotFor]] }; const baseFilter = { for: ['not in', [itemNotFor]] };

View File

@ -67,7 +67,7 @@ export class Item extends Doc {
return [ return [
{ {
label: fyo.t`New Sale`, label: fyo.t`New Sale`,
condition: (doc) => !doc.notInserted && doc.for !== 'purchases', condition: (doc) => !doc.notInserted && doc.for !== 'Purchases',
action: async (doc, router) => { action: async (doc, router) => {
const invoice = await fyo.doc.getNewDoc('SalesInvoice'); const invoice = await fyo.doc.getNewDoc('SalesInvoice');
await invoice.append('items', { await invoice.append('items', {
@ -80,7 +80,7 @@ export class Item extends Doc {
}, },
{ {
label: fyo.t`New Purchase`, label: fyo.t`New Purchase`,
condition: (doc) => !doc.notInserted && doc.for !== 'sales', condition: (doc) => !doc.notInserted && doc.for !== 'Sales',
action: async (doc, router) => { action: async (doc, router) => {
const invoice = await fyo.doc.getNewDoc('PurchaseInvoice'); const invoice = await fyo.doc.getNewDoc('PurchaseInvoice');
await invoice.append('items', { await invoice.append('items', {

View File

@ -74,20 +74,21 @@
"fieldtype": "Select", "fieldtype": "Select",
"options": [ "options": [
{ {
"value": "purchases", "value": "Purchases",
"label": "Purchases" "label": "Purchases"
}, },
{ {
"value": "sales", "value": "Sales",
"label": "Sales" "label": "Sales"
}, },
{ {
"value": "both", "value": "Both",
"label": "Both" "label": "Both"
} }
], ],
"readOnly": true, "readOnly": true,
"default": "both" "required": true,
"default": "Both"
}, },
{ {
"fieldname": "incomeAccount", "fieldname": "incomeAccount",

View File

@ -65,7 +65,8 @@
"fieldname": "hsnCode", "fieldname": "hsnCode",
"label": "HSN/SAC", "label": "HSN/SAC",
"fieldtype": "Int", "fieldtype": "Int",
"placeholder": "HSN/SAC Code" "placeholder": "HSN/SAC Code",
"hidden": true
} }
], ],
"tableFields": ["item", "tax", "quantity", "rate", "amount"], "tableFields": ["item", "tax", "quantity", "rate", "amount"],

View File

@ -66,7 +66,8 @@
"fieldname": "hsnCode", "fieldname": "hsnCode",
"label": "HSN/SAC", "label": "HSN/SAC",
"fieldtype": "Int", "fieldtype": "Int",
"placeholder": "HSN/SAC Code" "placeholder": "HSN/SAC Code",
"hidden": true
} }
], ],
"tableFields": ["item", "tax", "quantity", "rate", "amount"], "tableFields": ["item", "tax", "quantity", "rate", "amount"],

View File

@ -206,6 +206,8 @@ export default {
// valid selection // valid selection
let item = this.items[this.highlightedIndex]; let item = this.items[this.highlightedIndex];
await this.selectItem(item); await this.selectItem(item);
} else if (this.items.length === 1) {
await this.selectItem(this.items[0])
} }
}, },
highlightItemUp() { highlightItemUp() {

View File

@ -31,7 +31,9 @@ export default {
actions: { default: [] }, actions: { default: [] },
type: { type: String, default: 'secondary' }, type: { type: String, default: 'secondary' },
}, },
inject: ['doc'], inject: {
doc: { default: null },
},
components: { components: {
Dropdown, Dropdown,
Button, Button,

View File

@ -1,8 +1,10 @@
import { Fyo, t } from 'fyo'; import { Fyo, t } from 'fyo';
import { Converter } from 'fyo/core/converter';
import { DocValueMap } from 'fyo/core/types'; import { DocValueMap } from 'fyo/core/types';
import { Doc } from 'fyo/model/doc'; import { Doc } from 'fyo/model/doc';
import { isNameAutoSet } from 'fyo/model/naming'; import { isNameAutoSet } from 'fyo/model/naming';
import { Noun, Verb } from 'fyo/telemetry/types'; import { Noun, Verb } from 'fyo/telemetry/types';
import { ModelNameEnum } from 'models/types';
import { import {
Field, Field,
FieldType, FieldType,
@ -11,16 +13,20 @@ import {
SelectOption, SelectOption,
TargetField, TargetField,
} from 'schemas/types'; } from 'schemas/types';
import { parseCSV } from '../utils/csvParser'; import {
getDefaultMapFromList,
getMapFromList,
getValueMapFromList,
} from 'utils';
import { generateCSV, parseCSV } from '../utils/csvParser';
export const importable = [ export const importable = [
'SalesInvoice', ModelNameEnum.SalesInvoice,
'PurchaseInvoice', ModelNameEnum.PurchaseInvoice,
'Payment', ModelNameEnum.Payment,
'JournalEntry', ModelNameEnum.Party,
'Customer', ModelNameEnum.Item,
'Supplier', ModelNameEnum.JournalEntry,
'Item',
]; ];
type Status = { type Status = {
@ -29,16 +35,7 @@ type Status = {
names: string[]; names: string[];
}; };
type Exclusion = { type Exclusion = Record<string, string[]>;
[key: string]: string[];
};
type Map = Record<string, unknown>;
type ObjectMap = Record<string, Map>;
type LabelTemplateFieldMap = {
[key: string]: TemplateField;
};
type LoadingStatusCallback = ( type LoadingStatusCallback = (
isMakingEntries: boolean, isMakingEntries: boolean,
@ -56,33 +53,9 @@ interface TemplateField {
parentField: string; parentField: string;
} }
function formatValue(value: string, fieldtype: FieldType): unknown {
switch (fieldtype) {
case FieldTypeEnum.Date:
if (value === '') {
return '';
}
return new Date(value);
case FieldTypeEnum.Currency:
// @ts-ignore
return this.fyo.pesa(value || 0);
case FieldTypeEnum.Int:
case FieldTypeEnum.Float: {
const n = parseFloat(value);
if (!Number.isNaN(n)) {
return n;
}
return 0;
}
default:
return value;
}
}
const exclusion: Exclusion = { const exclusion: Exclusion = {
Item: ['image'], Item: ['image'],
Supplier: ['address', 'outstandingAmount', 'supplier', 'image', 'customer'], Party: ['address', 'outstandingAmount', 'image'],
Customer: ['address', 'outstandingAmount', 'supplier', 'image', 'customer'],
}; };
function getFilteredDocFields( function getFilteredDocFields(
@ -97,48 +70,68 @@ function getFilteredDocFields(
parentField = ''; parentField = '';
} }
// @ts-ignore const primaryFields: Field[] = fyo.schemaMap[schemaName]!.fields;
const primaryFields: Field[] = fyo.schemaMap[schemaName]?.fields ?? [];
const fields: TemplateField[] = []; const fields: TemplateField[] = [];
const tableTypes: string[][] = []; const tableTypes: string[][] = [];
const exclusionFields: string[] = exclusion[schemaName] ?? []; const exclusionFields: string[] = exclusion[schemaName] ?? [];
primaryFields.forEach((field) => { for (const field of primaryFields) {
const { label, fieldtype, fieldname, readOnly, required, hidden } = field; const { label, fieldtype, fieldname, required } = field;
if ( if (shouldSkip(field, exclusionFields, parentField)) {
!(fieldname === 'name' && !parentField) && continue;
(readOnly ||
(hidden && typeof hidden === 'number') ||
exclusionFields.includes(fieldname))
) {
return;
} }
if (fieldtype === FieldTypeEnum.Table && (field as TargetField).target) { if (fieldtype === FieldTypeEnum.Table) {
tableTypes.push([(field as TargetField).target, fieldname]); const { target } = field as TargetField;
return; tableTypes.push([target, fieldname]);
continue;
} }
let options: SelectOption[] = []; const options: SelectOption[] = (field as OptionField).options ?? [];
if ((field as OptionField).options !== undefined) {
options = (field as OptionField).options;
}
fields.push({ fields.push({
label, label,
fieldname, fieldname,
schemaName: schemaName, schemaName,
options, options,
fieldtype, fieldtype,
parentField, parentField,
required: Boolean(required ?? false), required: required ?? false,
}); });
}); }
return [fields, tableTypes]; return [fields, tableTypes];
} }
function shouldSkip(
field: Field,
exclusionFields: string[],
parentField: string
): boolean {
if (field.meta) {
return true;
}
if (field.fieldname === 'name' && parentField) {
return true;
}
if (field.required) {
return false;
}
if (exclusionFields.includes(field.fieldname)) {
return true;
}
if (field.hidden || field.readOnly) {
return true;
}
return false;
}
function getTemplateFields(schemaName: string, fyo: Fyo): TemplateField[] { function getTemplateFields(schemaName: string, fyo: Fyo): TemplateField[] {
const fields: TemplateField[] = []; const fields: TemplateField[] = [];
if (!schemaName) { if (!schemaName) {
@ -147,46 +140,28 @@ function getTemplateFields(schemaName: string, fyo: Fyo): TemplateField[] {
const schemaNames: string[][] = [[schemaName]]; const schemaNames: string[][] = [[schemaName]];
while (schemaNames.length > 0) { while (schemaNames.length > 0) {
const dt = schemaNames.pop(); const sn = schemaNames.pop();
if (!dt) { if (!sn) {
break; break;
} }
const [templateFields, tableTypes] = getFilteredDocFields(dt, fyo); const [templateFields, tableTypes] = getFilteredDocFields(sn, fyo);
fields.push(...templateFields); fields.push(...templateFields);
schemaNames.push(...tableTypes); schemaNames.push(...tableTypes);
} }
return fields; return fields;
} }
function getLabelFieldMap(templateFields: TemplateField[]): Map {
const map: Map = {};
templateFields.reduce((acc, tf) => {
const key = tf.label as string;
acc[key] = tf.fieldname;
return acc;
}, map);
return map;
}
function getTemplate(templateFields: TemplateField[]): string {
const labels = templateFields.map(({ label }) => `"${label}"`).join(',');
return [labels, ''].join('\n');
}
export class Importer { export class Importer {
schemaName: string; schemaName: string;
templateFields: TemplateField[]; templateFields: TemplateField[];
map: Map; labelTemplateFieldMap: Record<string, TemplateField> = {};
template: string; template: string;
indices: number[] = []; indices: number[] = [];
parsedLabels: string[] = []; parsedLabels: string[] = [];
parsedValues: string[][] = []; parsedValues: string[][] = [];
assignedMap: Map = {}; // target: import assignedMap: Record<string, string> = {}; // target: import
requiredMap: Map = {}; requiredMap: Record<string, boolean> = {};
labelTemplateFieldMap: LabelTemplateFieldMap = {};
shouldSubmit: boolean = false; shouldSubmit: boolean = false;
labelIndex: number = -1; labelIndex: number = -1;
csv: string[][] = []; csv: string[][] = [];
@ -196,38 +171,30 @@ export class Importer {
this.schemaName = schemaName; this.schemaName = schemaName;
this.fyo = fyo; this.fyo = fyo;
this.templateFields = getTemplateFields(schemaName, this.fyo); this.templateFields = getTemplateFields(schemaName, this.fyo);
this.map = getLabelFieldMap(this.templateFields); this.template = generateCSV([this.templateFields.map((t) => t.label)]);
this.template = getTemplate(this.templateFields); this.labelTemplateFieldMap = getMapFromList(this.templateFields, 'label');
this.assignedMap = this.assignableLabels.reduce((acc: Map, k) => { this.assignedMap = getDefaultMapFromList(this.templateFields, '', 'label');
acc[k] = ''; this.requiredMap = getValueMapFromList(
return acc; this.templateFields,
}, {}); 'label',
this.requiredMap = this.templateFields.reduce((acc: Map, k) => { 'required'
acc[k.label] = k.required; ) as Record<string, boolean>;
return acc;
}, {});
this.labelTemplateFieldMap = this.templateFields.reduce(
(acc: LabelTemplateFieldMap, k) => {
acc[k.label] = k;
return acc;
},
{}
);
} }
get assignableLabels() { get assignableLabels() {
const req: string[] = []; const req: string[] = [];
const nreq: string[] = []; const nreq: string[] = [];
Object.keys(this.map).forEach((k) => {
if (this.requiredMap[k]) { for (const label in this.labelTemplateFieldMap) {
req.push(k); if (this.requiredMap[label]) {
return; req.push(label);
continue;
} }
nreq.push(k); nreq.push(label);
}); }
return [...req, ...nreq]; return [req, nreq].flat();
} }
get unassignedLabels() { get unassignedLabels() {
@ -332,23 +299,23 @@ export class Importer {
}); });
} }
getDocs(): Map[] { getDocs(): DocValueMap[] {
const fields = this.columnLabels.map((k) => this.labelTemplateFieldMap[k]); const fields = this.columnLabels.map((k) => this.labelTemplateFieldMap[k]);
const nameIndex = fields.findIndex(({ fieldname }) => fieldname === 'name'); const nameIndex = fields.findIndex(({ fieldname }) => fieldname === 'name');
const docMap: ObjectMap = {}; const docMap: Record<string, DocValueMap> = {};
const assignedMatrix = this.assignedMatrix; const assignedMatrix = this.assignedMatrix;
for (let r = 0; r < assignedMatrix.length; r++) { for (let r = 0; r < assignedMatrix.length; r++) {
const row = assignedMatrix[r]; const row = assignedMatrix[r];
const cts: ObjectMap = {}; const cts: Record<string, DocValueMap> = {};
const name = row[nameIndex]; const name = row[nameIndex];
docMap[name] ??= {}; docMap[name] ??= {};
for (let f = 0; f < fields.length; f++) { for (let f = 0; f < fields.length; f++) {
const field = fields[f]; const field = fields[f];
const value = formatValue(row[f], field.fieldtype); const value = Converter.toDocValue(row[f], field, this.fyo);
if (field.parentField) { if (field.parentField) {
cts[field.parentField] ??= {}; cts[field.parentField] ??= {};
@ -361,7 +328,7 @@ export class Importer {
for (const k of Object.keys(cts)) { for (const k of Object.keys(cts)) {
docMap[name][k] ??= []; docMap[name][k] ??= [];
(docMap[name][k] as Map[]).push(cts[k]); (docMap[name][k] as DocValueMap[]).push(cts[k]);
} }
} }
@ -423,9 +390,8 @@ export class Importer {
this.parsedValues.push(emptyRow); this.parsedValues.push(emptyRow);
} }
async makeEntry(doc: Doc, docObj: Map) { async makeEntry(doc: Doc, docObj: DocValueMap) {
await doc.setMultiple(docObj as DocValueMap); await doc.setAndSync(docObj);
await doc.sync();
if (this.shouldSubmit) { if (this.shouldSubmit) {
await doc.submit(); await doc.submit();
} }

View File

@ -1,5 +1,6 @@
<template> <template>
<div class="flex flex-col overflow-hidden w-full"> <div class="flex flex-col overflow-hidden w-full">
<!-- Header -->
<PageHeader :title="t`Data Import`"> <PageHeader :title="t`Data Import`">
<DropdownWithActions <DropdownWithActions
:actions="actions" :actions="actions"
@ -13,6 +14,7 @@
>{{ primaryLabel }}</Button >{{ primaryLabel }}</Button
> >
</PageHeader> </PageHeader>
<div <div
class="flex px-8 mt-2 text-base w-full flex-col gap-8" class="flex px-8 mt-2 text-base w-full flex-col gap-8"
v-if="!complete" v-if="!complete"
@ -21,8 +23,8 @@
<div class="flex flex-row justify-start items-center w-full gap-2"> <div class="flex flex-row justify-start items-center w-full gap-2">
<FormControl <FormControl
:df="importableDf" :df="importableDf"
input-class="bg-gray-100 text-gray-900 text-base" input-class="bg-transparent text-gray-900 text-base"
class="w-40" class="w-40 bg-gray-100 rounded"
:value="importType" :value="importType"
size="small" size="small"
@change="setImportType" @change="setImportType"
@ -330,9 +332,11 @@ import HowTo from 'src/components/HowTo.vue';
import PageHeader from 'src/components/PageHeader.vue'; import PageHeader from 'src/components/PageHeader.vue';
import { importable, Importer } from 'src/dataImport'; import { importable, Importer } from 'src/dataImport';
import { fyo } from 'src/initFyo'; import { fyo } from 'src/initFyo';
import { getSavePath, saveData, showMessageDialog } from 'src/utils'; import { getSavePath, saveData } from 'src/utils/ipcCalls';
import { showMessageDialog } from 'src/utils/ui';
import { IPC_ACTIONS } from 'utils/messages'; import { IPC_ACTIONS } from 'utils/messages';
import Loading from '../components/Loading.vue'; import Loading from '../components/Loading.vue';
export default { export default {
components: { components: {
PageHeader, PageHeader,
@ -356,6 +360,11 @@ export default {
messageLoading: '', messageLoading: '',
}; };
}, },
mounted() {
if (fyo.store.isDevelopment) {
window.di = this;
}
},
computed: { computed: {
labelIndex() { labelIndex() {
return this.importer.labelIndex; return this.importer.labelIndex;
@ -435,14 +444,14 @@ export default {
label: this.t`Import Type`, label: this.t`Import Type`,
fieldtype: 'AutoComplete', fieldtype: 'AutoComplete',
placeholder: this.t`Import Type`, placeholder: this.t`Import Type`,
getList: () => importable.map((i) => fyo.models[i].label), options: Object.keys(this.labelSchemaNameMap)
}; };
}, },
labelSchemaNameMap() { labelSchemaNameMap() {
return importable return importable
.map((i) => ({ .map((i) => ({
name: i, name: i,
label: fyo.models[i].label, label: fyo.schemaMap[i].label,
})) }))
.reduce((acc, { name, label }) => { .reduce((acc, { name, label }) => {
acc[label] = name; acc[label] = name;

View File

@ -1,8 +1,8 @@
import { NounEnum, Verb } from 'fyo/telemetry/types'; import { NounEnum, Verb } from 'fyo/telemetry/types';
import ChartOfAccounts from 'src/pages/ChartOfAccounts.vue'; import ChartOfAccounts from 'src/pages/ChartOfAccounts.vue';
import Dashboard from 'src/pages/Dashboard/Dashboard.vue'; import Dashboard from 'src/pages/Dashboard/Dashboard.vue';
import DataImport from 'src/pages/DataImport.vue';
import GetStarted from 'src/pages/GetStarted.vue'; import GetStarted from 'src/pages/GetStarted.vue';
// import DataImport from 'src/pages/DataImport.vue';
import InvoiceForm from 'src/pages/InvoiceForm.vue'; import InvoiceForm from 'src/pages/InvoiceForm.vue';
import JournalEntryForm from 'src/pages/JournalEntryForm.vue'; import JournalEntryForm from 'src/pages/JournalEntryForm.vue';
import ListView from 'src/pages/ListView/ListView.vue'; import ListView from 'src/pages/ListView/ListView.vue';
@ -107,13 +107,12 @@ const routes: RouteRecordRaw[] = [
edit: (route) => route.query, edit: (route) => route.query,
}, },
}, },
/*
{ {
path: '/data-import', path: '/data-import',
name: 'Data Import', name: 'Data Import',
component: DataImport, component: DataImport,
}, },
*/ { {
path: '/settings', path: '/settings',
name: 'Settings', name: 'Settings',
component: Settings, component: Settings,

View File

@ -87,17 +87,17 @@ function getCreateList(): SearchItem[] {
{ {
label: t`Sales Items`, label: t`Sales Items`,
schemaName: ModelNameEnum.Item, schemaName: ModelNameEnum.Item,
filter: { for: 'sales' }, filter: { for: 'Sales' },
}, },
{ {
label: t`Purchase Items`, label: t`Purchase Items`,
schemaName: ModelNameEnum.Item, schemaName: ModelNameEnum.Item,
filter: { for: 'purchases' }, filter: { for: 'Purchases' },
}, },
{ {
label: t`Common Items`, label: t`Common Items`,
schemaName: ModelNameEnum.Item, schemaName: ModelNameEnum.Item,
filter: { for: 'both' }, filter: { for: 'Both' },
}, },
].map(({ label, filter, schemaName }) => { ].map(({ label, filter, schemaName }) => {
const fk = Object.keys(filter)[0] as 'for' | 'role'; const fk = Object.keys(filter)[0] as 'for' | 'role';
@ -163,15 +163,15 @@ function getListViewList(): SearchItem[] {
{ label: t`Suppliers`, route: `/list/Party/role/Supplier/${t`Suppliers`}` }, { label: t`Suppliers`, route: `/list/Party/role/Supplier/${t`Suppliers`}` },
{ {
label: t`Sales Items`, label: t`Sales Items`,
route: `/list/Item/for/sales/${t`Sales Items`}`, route: `/list/Item/for/Sales/${t`Sales Items`}`,
}, },
{ {
label: t`Purchase Items`, label: t`Purchase Items`,
route: `/list/Item/for/purchases/${t`Purchase Items`}`, route: `/list/Item/for/Purchases/${t`Purchase Items`}`,
}, },
{ {
label: t`Common Items`, label: t`Common Items`,
route: `/list/Item/for/both/${t`Common Items`}`, route: `/list/Item/for/Both/${t`Common Items`}`,
}, },
].map((i) => ({ ...i, group: 'List' } as SearchItem)); ].map((i) => ({ ...i, group: 'List' } as SearchItem));

View File

@ -69,7 +69,7 @@ function getCompleteSidebar(): SidebarConfig {
{ {
label: t`Sales Items`, label: t`Sales Items`,
name: 'sales-items', name: 'sales-items',
route: `/list/Item/for/sales/${t`Sales Items`}`, route: `/list/Item/for/Sales/${t`Sales Items`}`,
schemaName: 'Item', schemaName: 'Item',
}, },
], ],
@ -101,7 +101,7 @@ function getCompleteSidebar(): SidebarConfig {
{ {
label: t`Purchase Items`, label: t`Purchase Items`,
name: 'purchase-items', name: 'purchase-items',
route: `/list/Item/for/purchases/${t`Purchase Items`}`, route: `/list/Item/for/Purchases/${t`Purchase Items`}`,
schemaName: 'Item', schemaName: 'Item',
}, },
], ],
@ -118,20 +118,21 @@ function getCompleteSidebar(): SidebarConfig {
route: '/list/JournalEntry', route: '/list/JournalEntry',
schemaName: 'JournalEntry', schemaName: 'JournalEntry',
}, },
{
label: t`Common Items`,
name: 'common-items',
route: `/list/Item/for/both/${t`Common Items`}`,
schemaName: 'Item',
},
{ {
label: t`Party`, label: t`Party`,
name: 'party', name: 'party',
route: '/list/Party/role/Both', route: '/list/Party/role/Both',
schemaName: 'Party', schemaName: 'Party',
}, },
{
label: t`Common Items`,
name: 'common-items',
route: `/list/Item/for/Both/${t`Common Items`}`,
schemaName: 'Item',
},
], ],
}, },
/*
{ {
label: t`Reports`, label: t`Reports`,
name: t`reports`, name: t`reports`,
@ -172,6 +173,7 @@ function getCompleteSidebar(): SidebarConfig {
}, },
], ],
}, },
*/
{ {
label: t`Setup`, label: t`Setup`,
name: t`setup`, name: t`setup`,
@ -192,7 +194,7 @@ function getCompleteSidebar(): SidebarConfig {
{ {
label: t`Data Import`, label: t`Data Import`,
name: 'data-import', name: 'data-import',
route: '/data_import', route: '/data-import',
}, },
{ {
label: t`Settings`, label: t`Settings`,

View File

@ -47,16 +47,16 @@ export async function openQuickEdit({
defaults = Object.assign({ defaults = Object.assign({
for: for:
purpose === 'sales' purpose === 'Sales'
? 'purchases' ? 'Purchases'
: purpose === 'purchases' : purpose === 'Purchases'
? 'sales' ? 'Sales'
: 'both', : 'Both',
}); });
} }
if (forWhat[0] === 'not in' && forWhat[1] === 'sales') { if (forWhat[0] === 'not in' && forWhat[1] === 'Sales') {
defaults = Object.assign({ for: 'purchases' }); defaults = Object.assign({ for: 'Purchases' });
} }
router[method]({ router[method]({

View File

@ -1,5 +1,4 @@
/** /**
* Functions in utils/*.ts can be used by the frontend or the backends
* And so should not contain and platforma specific imports. * And so should not contain and platforma specific imports.
*/ */
export function getValueMapFromList<T, K extends keyof T, V extends keyof T>( export function getValueMapFromList<T, K extends keyof T, V extends keyof T>(
@ -48,6 +47,32 @@ export function getMapFromList<T, K extends keyof T>(
return acc; return acc;
} }
export function getDefaultMapFromList<T, K extends keyof T, D>(
list: T[] | string[],
defaultValue: D,
name?: K
): Record<string, D> {
const acc: Record<string, D> = {};
if (typeof list[0] === 'string') {
for (const l of list as string[]) {
acc[l] = defaultValue;
}
return acc;
}
if (!name) {
return {};
}
for (const l of list as T[]) {
const key = String(l[name]);
acc[key] = defaultValue;
}
return acc;
}
export function getListFromMap<T>(map: Record<string, T>): T[] { export function getListFromMap<T>(map: Record<string, T>): T[] {
return Object.keys(map).map((n) => map[n]); return Object.keys(map).map((n) => map[n]);
} }