2022-02-21 12:27:01 +00:00
|
|
|
import { Field, FieldType } from '@/types/model';
|
|
|
|
import frappe from 'frappe';
|
2022-02-22 08:43:56 +00:00
|
|
|
import { parseCSV } from './csvParser';
|
2022-02-21 12:27:01 +00:00
|
|
|
|
2022-02-21 10:56:57 +00:00
|
|
|
export const importable = [
|
|
|
|
'SalesInvoice',
|
|
|
|
'PurchaseInvoice',
|
|
|
|
'Payment',
|
|
|
|
'JournalEntry',
|
|
|
|
'Customer',
|
|
|
|
'Supplier',
|
|
|
|
'Item',
|
|
|
|
];
|
2022-02-21 12:27:01 +00:00
|
|
|
|
2022-02-22 08:43:56 +00:00
|
|
|
type Exclusion = {
|
|
|
|
[key: string]: string[];
|
|
|
|
};
|
|
|
|
|
|
|
|
type Map = {
|
|
|
|
[key: string]: string;
|
|
|
|
};
|
|
|
|
|
2022-02-21 12:27:01 +00:00
|
|
|
interface TemplateField {
|
|
|
|
label: string;
|
|
|
|
fieldname: string;
|
|
|
|
required: boolean;
|
|
|
|
}
|
|
|
|
|
2022-02-22 08:43:56 +00:00
|
|
|
const exclusion: Exclusion = {
|
|
|
|
Item: ['image'],
|
2022-02-21 12:27:01 +00:00
|
|
|
};
|
|
|
|
|
2022-02-22 08:43:56 +00:00
|
|
|
function getTemplateFields(doctype: string): TemplateField[] {
|
2022-02-21 12:27:01 +00:00
|
|
|
const fields: TemplateField[] = [];
|
2022-02-22 08:43:56 +00:00
|
|
|
if (!doctype) {
|
|
|
|
return [];
|
|
|
|
}
|
2022-02-21 12:27:01 +00:00
|
|
|
|
|
|
|
// @ts-ignore
|
|
|
|
const primaryFields: Field[] = frappe.models[doctype].fields;
|
|
|
|
const tableTypes: string[] = [];
|
2022-02-22 08:43:56 +00:00
|
|
|
let exclusionFields: string[] = exclusion[doctype] ?? [];
|
2022-02-21 12:27:01 +00:00
|
|
|
|
|
|
|
primaryFields.forEach(
|
|
|
|
({ label, fieldtype, childtype, fieldname, required }) => {
|
2022-02-22 08:43:56 +00:00
|
|
|
if (exclusionFields.includes(fieldname)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-02-21 12:27:01 +00:00
|
|
|
if (fieldtype === FieldType.Table && childtype) {
|
|
|
|
tableTypes.push(childtype);
|
|
|
|
}
|
|
|
|
|
|
|
|
fields.push({
|
|
|
|
label,
|
|
|
|
fieldname,
|
|
|
|
required: Boolean(required ?? false),
|
|
|
|
});
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
tableTypes.forEach((childtype) => {
|
2022-02-22 08:43:56 +00:00
|
|
|
exclusionFields = exclusion[childtype] ?? [];
|
|
|
|
|
2022-02-21 12:27:01 +00:00
|
|
|
// @ts-ignore
|
|
|
|
const childFields: Field[] = frappe.models[childtype].fields;
|
|
|
|
childFields.forEach(({ label, fieldtype, fieldname, required }) => {
|
2022-02-22 08:43:56 +00:00
|
|
|
if (
|
|
|
|
exclusionFields.includes(fieldname) ||
|
|
|
|
fieldtype === FieldType.Table
|
|
|
|
) {
|
2022-02-21 12:27:01 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
fields.push({ label, fieldname, required: Boolean(required ?? false) });
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
return fields;
|
|
|
|
}
|
|
|
|
|
2022-02-22 08:43:56 +00:00
|
|
|
function getLabelFieldMap(templateFields: TemplateField[]): Map {
|
|
|
|
const map: Map = {};
|
2022-02-21 12:27:01 +00:00
|
|
|
|
|
|
|
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 {
|
|
|
|
doctype: string;
|
|
|
|
templateFields: TemplateField[];
|
2022-02-22 08:43:56 +00:00
|
|
|
map: Map;
|
|
|
|
template: string;
|
2022-02-22 13:03:21 +00:00
|
|
|
indices: number[] = [];
|
2022-02-22 08:43:56 +00:00
|
|
|
parsedLabels: string[] = [];
|
2022-02-22 13:03:21 +00:00
|
|
|
parsedValues: string[][] = [];
|
2022-02-22 08:43:56 +00:00
|
|
|
assignedMap: Map = {}; // target: import
|
2022-02-21 12:27:01 +00:00
|
|
|
|
|
|
|
constructor(doctype: string) {
|
|
|
|
this.doctype = doctype;
|
|
|
|
this.templateFields = getTemplateFields(doctype);
|
2022-02-22 08:43:56 +00:00
|
|
|
this.map = getLabelFieldMap(this.templateFields);
|
|
|
|
this.template = getTemplate(this.templateFields);
|
|
|
|
this.assignedMap = this.assignableLabels.reduce((acc: Map, k) => {
|
|
|
|
acc[k] = '';
|
|
|
|
return acc;
|
|
|
|
}, {});
|
|
|
|
}
|
|
|
|
|
|
|
|
get assignableLabels() {
|
|
|
|
return Object.keys(this.map);
|
|
|
|
}
|
|
|
|
|
|
|
|
get unassignedLabels() {
|
|
|
|
const assigned = Object.keys(this.assignedMap).map(
|
|
|
|
(k) => this.assignedMap[k]
|
|
|
|
);
|
|
|
|
return this.parsedLabels.filter((l) => !assigned.includes(l));
|
2022-02-21 12:27:01 +00:00
|
|
|
}
|
|
|
|
|
2022-02-22 13:03:21 +00:00
|
|
|
get columnLabels() {
|
2022-02-22 08:43:56 +00:00
|
|
|
const assigned: string[] = [];
|
|
|
|
const unassigned: string[] = [];
|
|
|
|
|
2022-02-22 13:03:21 +00:00
|
|
|
this.assignableLabels.forEach((k) => {
|
|
|
|
if (this.assignedMap[k]) {
|
2022-02-22 08:43:56 +00:00
|
|
|
assigned.push(k);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
unassigned.push(k);
|
|
|
|
});
|
|
|
|
|
2022-02-22 13:03:21 +00:00
|
|
|
return [...assigned];
|
|
|
|
}
|
|
|
|
|
|
|
|
get assignedMatrix() {
|
|
|
|
this.indices = this.columnLabels
|
|
|
|
.map((k) => this.assignedMap[k])
|
|
|
|
.filter(Boolean)
|
|
|
|
.map((k) => this.parsedLabels.indexOf(k));
|
|
|
|
|
|
|
|
const rows = this.parsedValues.length;
|
|
|
|
const cols = this.columnLabels.length;
|
|
|
|
|
|
|
|
const matrix = [];
|
|
|
|
for (let i = 0; i < rows; i++) {
|
|
|
|
const row = [];
|
|
|
|
for (let j = 0; j < cols; j++) {
|
|
|
|
const ix = this.indices[j];
|
|
|
|
const value = this.parsedValues[i][ix] ?? '';
|
|
|
|
row.push(value);
|
|
|
|
}
|
|
|
|
matrix.push(row);
|
|
|
|
}
|
|
|
|
|
|
|
|
return matrix;
|
|
|
|
}
|
|
|
|
|
|
|
|
dropRow(i: number) {
|
|
|
|
this.parsedValues = this.parsedValues.filter((_, ix) => i !== ix);
|
|
|
|
}
|
|
|
|
|
|
|
|
updateValue(value: string, i: number, j: number) {
|
|
|
|
this.parsedValues[i][this.indices[j]] = value ?? '';
|
2022-02-21 12:27:01 +00:00
|
|
|
}
|
|
|
|
|
2022-02-22 08:43:56 +00:00
|
|
|
selectFile(text: string): boolean {
|
|
|
|
const csv = parseCSV(text);
|
|
|
|
this.parsedLabels = csv[0];
|
|
|
|
const values = csv.slice(1);
|
|
|
|
|
|
|
|
if (values.some((v) => v.length !== this.parsedLabels.length)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-02-22 13:03:21 +00:00
|
|
|
this.parsedValues = values;
|
2022-02-22 08:43:56 +00:00
|
|
|
this._setAssigned();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
_setAssigned() {
|
|
|
|
const labels = [...this.parsedLabels];
|
|
|
|
labels.forEach((l) => {
|
|
|
|
if (this.assignedMap[l] !== '') {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
this.assignedMap[l] = l;
|
|
|
|
});
|
2022-02-21 12:27:01 +00:00
|
|
|
}
|
|
|
|
}
|
2022-02-22 08:43:56 +00:00
|
|
|
|
|
|
|
// @ts-ignore
|
|
|
|
window.pc = parseCSV;
|