mirror of
https://github.com/frappe/books.git
synced 2024-12-22 19:09:01 +00:00
incr: get dataimport to work
- need to test on child table docs
This commit is contained in:
parent
0a3fe90990
commit
bd6f110553
@ -164,7 +164,7 @@ function toDocString(value: RawValue, field: Field) {
|
||||
}
|
||||
|
||||
function toDocDate(value: RawValue, field: Field) {
|
||||
if (value === null) {
|
||||
if (value === null || value === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -181,6 +181,10 @@ function toDocDate(value: RawValue, field: Field) {
|
||||
}
|
||||
|
||||
function toDocCurrency(value: RawValue, field: Field, fyo: Fyo) {
|
||||
if (value === '') {
|
||||
return fyo.pesa(0);
|
||||
}
|
||||
|
||||
if (typeof value === 'string') {
|
||||
return fyo.pesa(value);
|
||||
}
|
||||
@ -201,6 +205,10 @@ function toDocCurrency(value: RawValue, field: Field, fyo: Fyo) {
|
||||
}
|
||||
|
||||
function toDocInt(value: RawValue, field: Field): number {
|
||||
if (value === '') {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (typeof value === 'string') {
|
||||
value = parseInt(value);
|
||||
}
|
||||
@ -209,6 +217,10 @@ function toDocInt(value: RawValue, field: Field): number {
|
||||
}
|
||||
|
||||
function toDocFloat(value: RawValue, field: Field): number {
|
||||
if (value === '') {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (typeof value === 'boolean') {
|
||||
return Number(value);
|
||||
}
|
||||
|
@ -2,24 +2,24 @@ import { Fyo } from 'fyo';
|
||||
import NumberSeries from 'fyo/models/NumberSeries';
|
||||
import { DEFAULT_SERIES_START } from 'fyo/utils/consts';
|
||||
import { BaseError } from 'fyo/utils/errors';
|
||||
import { Field, Schema } from 'schemas/types';
|
||||
import { getRandomString } from 'utils';
|
||||
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 {
|
||||
const schema = fyo.schemaMap[schemaName]!;
|
||||
if (schema.naming === 'manual') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (schema.naming === 'autoincrement') {
|
||||
return true;
|
||||
}
|
||||
|
||||
const numberSeries = getNumberSeries(schema);
|
||||
if (schema.naming === 'random') {
|
||||
return true;
|
||||
}
|
||||
|
||||
const numberSeries = fyo.getField(schema.name, 'numberSeries');
|
||||
if (numberSeries) {
|
||||
return true;
|
||||
}
|
||||
|
@ -98,9 +98,9 @@ export abstract class InvoiceItem extends Doc {
|
||||
const itemList = doc.parentdoc!.items as Doc[];
|
||||
const items = itemList.map((d) => d.item as string).filter(Boolean);
|
||||
|
||||
let itemNotFor = 'sales';
|
||||
let itemNotFor = 'Sales';
|
||||
if (doc.isSales) {
|
||||
itemNotFor = 'purchases';
|
||||
itemNotFor = 'Purchases';
|
||||
}
|
||||
|
||||
const baseFilter = { for: ['not in', [itemNotFor]] };
|
||||
|
@ -67,7 +67,7 @@ export class Item extends Doc {
|
||||
return [
|
||||
{
|
||||
label: fyo.t`New Sale`,
|
||||
condition: (doc) => !doc.notInserted && doc.for !== 'purchases',
|
||||
condition: (doc) => !doc.notInserted && doc.for !== 'Purchases',
|
||||
action: async (doc, router) => {
|
||||
const invoice = await fyo.doc.getNewDoc('SalesInvoice');
|
||||
await invoice.append('items', {
|
||||
@ -80,7 +80,7 @@ export class Item extends Doc {
|
||||
},
|
||||
{
|
||||
label: fyo.t`New Purchase`,
|
||||
condition: (doc) => !doc.notInserted && doc.for !== 'sales',
|
||||
condition: (doc) => !doc.notInserted && doc.for !== 'Sales',
|
||||
action: async (doc, router) => {
|
||||
const invoice = await fyo.doc.getNewDoc('PurchaseInvoice');
|
||||
await invoice.append('items', {
|
||||
|
@ -74,20 +74,21 @@
|
||||
"fieldtype": "Select",
|
||||
"options": [
|
||||
{
|
||||
"value": "purchases",
|
||||
"value": "Purchases",
|
||||
"label": "Purchases"
|
||||
},
|
||||
{
|
||||
"value": "sales",
|
||||
"value": "Sales",
|
||||
"label": "Sales"
|
||||
},
|
||||
{
|
||||
"value": "both",
|
||||
"value": "Both",
|
||||
"label": "Both"
|
||||
}
|
||||
],
|
||||
"readOnly": true,
|
||||
"default": "both"
|
||||
"required": true,
|
||||
"default": "Both"
|
||||
},
|
||||
{
|
||||
"fieldname": "incomeAccount",
|
||||
|
@ -65,7 +65,8 @@
|
||||
"fieldname": "hsnCode",
|
||||
"label": "HSN/SAC",
|
||||
"fieldtype": "Int",
|
||||
"placeholder": "HSN/SAC Code"
|
||||
"placeholder": "HSN/SAC Code",
|
||||
"hidden": true
|
||||
}
|
||||
],
|
||||
"tableFields": ["item", "tax", "quantity", "rate", "amount"],
|
||||
|
@ -66,7 +66,8 @@
|
||||
"fieldname": "hsnCode",
|
||||
"label": "HSN/SAC",
|
||||
"fieldtype": "Int",
|
||||
"placeholder": "HSN/SAC Code"
|
||||
"placeholder": "HSN/SAC Code",
|
||||
"hidden": true
|
||||
}
|
||||
],
|
||||
"tableFields": ["item", "tax", "quantity", "rate", "amount"],
|
||||
|
@ -206,6 +206,8 @@ export default {
|
||||
// valid selection
|
||||
let item = this.items[this.highlightedIndex];
|
||||
await this.selectItem(item);
|
||||
} else if (this.items.length === 1) {
|
||||
await this.selectItem(this.items[0])
|
||||
}
|
||||
},
|
||||
highlightItemUp() {
|
||||
|
@ -31,7 +31,9 @@ export default {
|
||||
actions: { default: [] },
|
||||
type: { type: String, default: 'secondary' },
|
||||
},
|
||||
inject: ['doc'],
|
||||
inject: {
|
||||
doc: { default: null },
|
||||
},
|
||||
components: {
|
||||
Dropdown,
|
||||
Button,
|
||||
|
@ -1,8 +1,10 @@
|
||||
import { Fyo, t } from 'fyo';
|
||||
import { Converter } from 'fyo/core/converter';
|
||||
import { DocValueMap } from 'fyo/core/types';
|
||||
import { Doc } from 'fyo/model/doc';
|
||||
import { isNameAutoSet } from 'fyo/model/naming';
|
||||
import { Noun, Verb } from 'fyo/telemetry/types';
|
||||
import { ModelNameEnum } from 'models/types';
|
||||
import {
|
||||
Field,
|
||||
FieldType,
|
||||
@ -11,16 +13,20 @@ import {
|
||||
SelectOption,
|
||||
TargetField,
|
||||
} from 'schemas/types';
|
||||
import { parseCSV } from '../utils/csvParser';
|
||||
import {
|
||||
getDefaultMapFromList,
|
||||
getMapFromList,
|
||||
getValueMapFromList,
|
||||
} from 'utils';
|
||||
import { generateCSV, parseCSV } from '../utils/csvParser';
|
||||
|
||||
export const importable = [
|
||||
'SalesInvoice',
|
||||
'PurchaseInvoice',
|
||||
'Payment',
|
||||
'JournalEntry',
|
||||
'Customer',
|
||||
'Supplier',
|
||||
'Item',
|
||||
ModelNameEnum.SalesInvoice,
|
||||
ModelNameEnum.PurchaseInvoice,
|
||||
ModelNameEnum.Payment,
|
||||
ModelNameEnum.Party,
|
||||
ModelNameEnum.Item,
|
||||
ModelNameEnum.JournalEntry,
|
||||
];
|
||||
|
||||
type Status = {
|
||||
@ -29,16 +35,7 @@ type Status = {
|
||||
names: string[];
|
||||
};
|
||||
|
||||
type Exclusion = {
|
||||
[key: string]: string[];
|
||||
};
|
||||
|
||||
type Map = Record<string, unknown>;
|
||||
type ObjectMap = Record<string, Map>;
|
||||
|
||||
type LabelTemplateFieldMap = {
|
||||
[key: string]: TemplateField;
|
||||
};
|
||||
type Exclusion = Record<string, string[]>;
|
||||
|
||||
type LoadingStatusCallback = (
|
||||
isMakingEntries: boolean,
|
||||
@ -56,33 +53,9 @@ interface TemplateField {
|
||||
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 = {
|
||||
Item: ['image'],
|
||||
Supplier: ['address', 'outstandingAmount', 'supplier', 'image', 'customer'],
|
||||
Customer: ['address', 'outstandingAmount', 'supplier', 'image', 'customer'],
|
||||
Party: ['address', 'outstandingAmount', 'image'],
|
||||
};
|
||||
|
||||
function getFilteredDocFields(
|
||||
@ -97,48 +70,68 @@ function getFilteredDocFields(
|
||||
parentField = '';
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
const primaryFields: Field[] = fyo.schemaMap[schemaName]?.fields ?? [];
|
||||
const primaryFields: Field[] = fyo.schemaMap[schemaName]!.fields;
|
||||
const fields: TemplateField[] = [];
|
||||
const tableTypes: string[][] = [];
|
||||
const exclusionFields: string[] = exclusion[schemaName] ?? [];
|
||||
|
||||
primaryFields.forEach((field) => {
|
||||
const { label, fieldtype, fieldname, readOnly, required, hidden } = field;
|
||||
for (const field of primaryFields) {
|
||||
const { label, fieldtype, fieldname, required } = field;
|
||||
|
||||
if (
|
||||
!(fieldname === 'name' && !parentField) &&
|
||||
(readOnly ||
|
||||
(hidden && typeof hidden === 'number') ||
|
||||
exclusionFields.includes(fieldname))
|
||||
) {
|
||||
return;
|
||||
if (shouldSkip(field, exclusionFields, parentField)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (fieldtype === FieldTypeEnum.Table && (field as TargetField).target) {
|
||||
tableTypes.push([(field as TargetField).target, fieldname]);
|
||||
return;
|
||||
if (fieldtype === FieldTypeEnum.Table) {
|
||||
const { target } = field as TargetField;
|
||||
tableTypes.push([target, fieldname]);
|
||||
continue;
|
||||
}
|
||||
|
||||
let options: SelectOption[] = [];
|
||||
if ((field as OptionField).options !== undefined) {
|
||||
options = (field as OptionField).options;
|
||||
}
|
||||
const options: SelectOption[] = (field as OptionField).options ?? [];
|
||||
|
||||
fields.push({
|
||||
label,
|
||||
fieldname,
|
||||
schemaName: schemaName,
|
||||
schemaName,
|
||||
options,
|
||||
fieldtype,
|
||||
parentField,
|
||||
required: Boolean(required ?? false),
|
||||
required: required ?? false,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
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[] {
|
||||
const fields: TemplateField[] = [];
|
||||
if (!schemaName) {
|
||||
@ -147,46 +140,28 @@ function getTemplateFields(schemaName: string, fyo: Fyo): TemplateField[] {
|
||||
|
||||
const schemaNames: string[][] = [[schemaName]];
|
||||
while (schemaNames.length > 0) {
|
||||
const dt = schemaNames.pop();
|
||||
if (!dt) {
|
||||
const sn = schemaNames.pop();
|
||||
if (!sn) {
|
||||
break;
|
||||
}
|
||||
|
||||
const [templateFields, tableTypes] = getFilteredDocFields(dt, fyo);
|
||||
const [templateFields, tableTypes] = getFilteredDocFields(sn, fyo);
|
||||
fields.push(...templateFields);
|
||||
schemaNames.push(...tableTypes);
|
||||
}
|
||||
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 {
|
||||
schemaName: string;
|
||||
templateFields: TemplateField[];
|
||||
map: Map;
|
||||
labelTemplateFieldMap: Record<string, TemplateField> = {};
|
||||
template: string;
|
||||
indices: number[] = [];
|
||||
parsedLabels: string[] = [];
|
||||
parsedValues: string[][] = [];
|
||||
assignedMap: Map = {}; // target: import
|
||||
requiredMap: Map = {};
|
||||
labelTemplateFieldMap: LabelTemplateFieldMap = {};
|
||||
assignedMap: Record<string, string> = {}; // target: import
|
||||
requiredMap: Record<string, boolean> = {};
|
||||
shouldSubmit: boolean = false;
|
||||
labelIndex: number = -1;
|
||||
csv: string[][] = [];
|
||||
@ -196,38 +171,30 @@ export class Importer {
|
||||
this.schemaName = schemaName;
|
||||
this.fyo = fyo;
|
||||
this.templateFields = getTemplateFields(schemaName, this.fyo);
|
||||
this.map = getLabelFieldMap(this.templateFields);
|
||||
this.template = getTemplate(this.templateFields);
|
||||
this.assignedMap = this.assignableLabels.reduce((acc: Map, k) => {
|
||||
acc[k] = '';
|
||||
return acc;
|
||||
}, {});
|
||||
this.requiredMap = this.templateFields.reduce((acc: Map, k) => {
|
||||
acc[k.label] = k.required;
|
||||
return acc;
|
||||
}, {});
|
||||
this.labelTemplateFieldMap = this.templateFields.reduce(
|
||||
(acc: LabelTemplateFieldMap, k) => {
|
||||
acc[k.label] = k;
|
||||
return acc;
|
||||
},
|
||||
{}
|
||||
);
|
||||
this.template = generateCSV([this.templateFields.map((t) => t.label)]);
|
||||
this.labelTemplateFieldMap = getMapFromList(this.templateFields, 'label');
|
||||
this.assignedMap = getDefaultMapFromList(this.templateFields, '', 'label');
|
||||
this.requiredMap = getValueMapFromList(
|
||||
this.templateFields,
|
||||
'label',
|
||||
'required'
|
||||
) as Record<string, boolean>;
|
||||
}
|
||||
|
||||
get assignableLabels() {
|
||||
const req: string[] = [];
|
||||
const nreq: string[] = [];
|
||||
Object.keys(this.map).forEach((k) => {
|
||||
if (this.requiredMap[k]) {
|
||||
req.push(k);
|
||||
return;
|
||||
|
||||
for (const label in this.labelTemplateFieldMap) {
|
||||
if (this.requiredMap[label]) {
|
||||
req.push(label);
|
||||
continue;
|
||||
}
|
||||
|
||||
nreq.push(k);
|
||||
});
|
||||
nreq.push(label);
|
||||
}
|
||||
|
||||
return [...req, ...nreq];
|
||||
return [req, nreq].flat();
|
||||
}
|
||||
|
||||
get unassignedLabels() {
|
||||
@ -332,23 +299,23 @@ export class Importer {
|
||||
});
|
||||
}
|
||||
|
||||
getDocs(): Map[] {
|
||||
getDocs(): DocValueMap[] {
|
||||
const fields = this.columnLabels.map((k) => this.labelTemplateFieldMap[k]);
|
||||
const nameIndex = fields.findIndex(({ fieldname }) => fieldname === 'name');
|
||||
|
||||
const docMap: ObjectMap = {};
|
||||
const docMap: Record<string, DocValueMap> = {};
|
||||
|
||||
const assignedMatrix = this.assignedMatrix;
|
||||
for (let r = 0; r < assignedMatrix.length; r++) {
|
||||
const row = assignedMatrix[r];
|
||||
const cts: ObjectMap = {};
|
||||
const cts: Record<string, DocValueMap> = {};
|
||||
const name = row[nameIndex];
|
||||
|
||||
docMap[name] ??= {};
|
||||
|
||||
for (let f = 0; f < fields.length; f++) {
|
||||
const field = fields[f];
|
||||
const value = formatValue(row[f], field.fieldtype);
|
||||
const value = Converter.toDocValue(row[f], field, this.fyo);
|
||||
|
||||
if (field.parentField) {
|
||||
cts[field.parentField] ??= {};
|
||||
@ -361,7 +328,7 @@ export class Importer {
|
||||
|
||||
for (const k of Object.keys(cts)) {
|
||||
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);
|
||||
}
|
||||
|
||||
async makeEntry(doc: Doc, docObj: Map) {
|
||||
await doc.setMultiple(docObj as DocValueMap);
|
||||
await doc.sync();
|
||||
async makeEntry(doc: Doc, docObj: DocValueMap) {
|
||||
await doc.setAndSync(docObj);
|
||||
if (this.shouldSubmit) {
|
||||
await doc.submit();
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
<template>
|
||||
<div class="flex flex-col overflow-hidden w-full">
|
||||
<!-- Header -->
|
||||
<PageHeader :title="t`Data Import`">
|
||||
<DropdownWithActions
|
||||
:actions="actions"
|
||||
@ -13,6 +14,7 @@
|
||||
>{{ primaryLabel }}</Button
|
||||
>
|
||||
</PageHeader>
|
||||
|
||||
<div
|
||||
class="flex px-8 mt-2 text-base w-full flex-col gap-8"
|
||||
v-if="!complete"
|
||||
@ -21,8 +23,8 @@
|
||||
<div class="flex flex-row justify-start items-center w-full gap-2">
|
||||
<FormControl
|
||||
:df="importableDf"
|
||||
input-class="bg-gray-100 text-gray-900 text-base"
|
||||
class="w-40"
|
||||
input-class="bg-transparent text-gray-900 text-base"
|
||||
class="w-40 bg-gray-100 rounded"
|
||||
:value="importType"
|
||||
size="small"
|
||||
@change="setImportType"
|
||||
@ -330,9 +332,11 @@ import HowTo from 'src/components/HowTo.vue';
|
||||
import PageHeader from 'src/components/PageHeader.vue';
|
||||
import { importable, Importer } from 'src/dataImport';
|
||||
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 Loading from '../components/Loading.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
PageHeader,
|
||||
@ -356,6 +360,11 @@ export default {
|
||||
messageLoading: '',
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
if (fyo.store.isDevelopment) {
|
||||
window.di = this;
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
labelIndex() {
|
||||
return this.importer.labelIndex;
|
||||
@ -435,14 +444,14 @@ export default {
|
||||
label: this.t`Import Type`,
|
||||
fieldtype: 'AutoComplete',
|
||||
placeholder: this.t`Import Type`,
|
||||
getList: () => importable.map((i) => fyo.models[i].label),
|
||||
options: Object.keys(this.labelSchemaNameMap)
|
||||
};
|
||||
},
|
||||
labelSchemaNameMap() {
|
||||
return importable
|
||||
.map((i) => ({
|
||||
name: i,
|
||||
label: fyo.models[i].label,
|
||||
label: fyo.schemaMap[i].label,
|
||||
}))
|
||||
.reduce((acc, { name, label }) => {
|
||||
acc[label] = name;
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { NounEnum, Verb } from 'fyo/telemetry/types';
|
||||
import ChartOfAccounts from 'src/pages/ChartOfAccounts.vue';
|
||||
import Dashboard from 'src/pages/Dashboard/Dashboard.vue';
|
||||
import DataImport from 'src/pages/DataImport.vue';
|
||||
import GetStarted from 'src/pages/GetStarted.vue';
|
||||
// import DataImport from 'src/pages/DataImport.vue';
|
||||
import InvoiceForm from 'src/pages/InvoiceForm.vue';
|
||||
import JournalEntryForm from 'src/pages/JournalEntryForm.vue';
|
||||
import ListView from 'src/pages/ListView/ListView.vue';
|
||||
@ -107,13 +107,12 @@ const routes: RouteRecordRaw[] = [
|
||||
edit: (route) => route.query,
|
||||
},
|
||||
},
|
||||
/*
|
||||
{
|
||||
path: '/data-import',
|
||||
name: 'Data Import',
|
||||
component: DataImport,
|
||||
},
|
||||
*/ {
|
||||
{
|
||||
path: '/settings',
|
||||
name: 'Settings',
|
||||
component: Settings,
|
||||
|
@ -87,17 +87,17 @@ function getCreateList(): SearchItem[] {
|
||||
{
|
||||
label: t`Sales Items`,
|
||||
schemaName: ModelNameEnum.Item,
|
||||
filter: { for: 'sales' },
|
||||
filter: { for: 'Sales' },
|
||||
},
|
||||
{
|
||||
label: t`Purchase Items`,
|
||||
schemaName: ModelNameEnum.Item,
|
||||
filter: { for: 'purchases' },
|
||||
filter: { for: 'Purchases' },
|
||||
},
|
||||
{
|
||||
label: t`Common Items`,
|
||||
schemaName: ModelNameEnum.Item,
|
||||
filter: { for: 'both' },
|
||||
filter: { for: 'Both' },
|
||||
},
|
||||
].map(({ label, filter, schemaName }) => {
|
||||
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`Sales Items`,
|
||||
route: `/list/Item/for/sales/${t`Sales Items`}`,
|
||||
route: `/list/Item/for/Sales/${t`Sales 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`,
|
||||
route: `/list/Item/for/both/${t`Common Items`}`,
|
||||
route: `/list/Item/for/Both/${t`Common Items`}`,
|
||||
},
|
||||
].map((i) => ({ ...i, group: 'List' } as SearchItem));
|
||||
|
||||
|
@ -69,7 +69,7 @@ function getCompleteSidebar(): SidebarConfig {
|
||||
{
|
||||
label: t`Sales Items`,
|
||||
name: 'sales-items',
|
||||
route: `/list/Item/for/sales/${t`Sales Items`}`,
|
||||
route: `/list/Item/for/Sales/${t`Sales Items`}`,
|
||||
schemaName: 'Item',
|
||||
},
|
||||
],
|
||||
@ -101,7 +101,7 @@ function getCompleteSidebar(): SidebarConfig {
|
||||
{
|
||||
label: t`Purchase Items`,
|
||||
name: 'purchase-items',
|
||||
route: `/list/Item/for/purchases/${t`Purchase Items`}`,
|
||||
route: `/list/Item/for/Purchases/${t`Purchase Items`}`,
|
||||
schemaName: 'Item',
|
||||
},
|
||||
],
|
||||
@ -118,20 +118,21 @@ function getCompleteSidebar(): SidebarConfig {
|
||||
route: '/list/JournalEntry',
|
||||
schemaName: 'JournalEntry',
|
||||
},
|
||||
{
|
||||
label: t`Common Items`,
|
||||
name: 'common-items',
|
||||
route: `/list/Item/for/both/${t`Common Items`}`,
|
||||
schemaName: 'Item',
|
||||
},
|
||||
{
|
||||
label: t`Party`,
|
||||
name: 'party',
|
||||
route: '/list/Party/role/Both',
|
||||
schemaName: 'Party',
|
||||
},
|
||||
{
|
||||
label: t`Common Items`,
|
||||
name: 'common-items',
|
||||
route: `/list/Item/for/Both/${t`Common Items`}`,
|
||||
schemaName: 'Item',
|
||||
},
|
||||
],
|
||||
},
|
||||
/*
|
||||
{
|
||||
label: t`Reports`,
|
||||
name: t`reports`,
|
||||
@ -172,6 +173,7 @@ function getCompleteSidebar(): SidebarConfig {
|
||||
},
|
||||
],
|
||||
},
|
||||
*/
|
||||
{
|
||||
label: t`Setup`,
|
||||
name: t`setup`,
|
||||
@ -192,7 +194,7 @@ function getCompleteSidebar(): SidebarConfig {
|
||||
{
|
||||
label: t`Data Import`,
|
||||
name: 'data-import',
|
||||
route: '/data_import',
|
||||
route: '/data-import',
|
||||
},
|
||||
{
|
||||
label: t`Settings`,
|
||||
|
@ -47,16 +47,16 @@ export async function openQuickEdit({
|
||||
|
||||
defaults = Object.assign({
|
||||
for:
|
||||
purpose === 'sales'
|
||||
? 'purchases'
|
||||
: purpose === 'purchases'
|
||||
? 'sales'
|
||||
: 'both',
|
||||
purpose === 'Sales'
|
||||
? 'Purchases'
|
||||
: purpose === 'Purchases'
|
||||
? 'Sales'
|
||||
: 'Both',
|
||||
});
|
||||
}
|
||||
|
||||
if (forWhat[0] === 'not in' && forWhat[1] === 'sales') {
|
||||
defaults = Object.assign({ for: 'purchases' });
|
||||
if (forWhat[0] === 'not in' && forWhat[1] === 'Sales') {
|
||||
defaults = Object.assign({ for: 'Purchases' });
|
||||
}
|
||||
|
||||
router[method]({
|
||||
|
@ -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.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
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[] {
|
||||
return Object.keys(map).map((n) => map[n]);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user