2
0
mirror of https://github.com/frappe/books.git synced 2024-11-10 07:40:55 +00:00

feat: code to generate templates

This commit is contained in:
18alantom 2022-02-21 17:57:01 +05:30
parent 91e8fa52f4
commit 23e504a67d
3 changed files with 159 additions and 14 deletions

View File

@ -1,3 +1,6 @@
import { Field, FieldType } from '@/types/model';
import frappe from 'frappe';
export const importable = [
'SalesInvoice',
'PurchaseInvoice',
@ -7,3 +10,88 @@ export const importable = [
'Supplier',
'Item',
];
interface TemplateField {
label: string;
fieldname: string;
required: boolean;
}
type LabelFieldMap = {
[key: string]: string;
};
export function getTemplateFields(doctype: string): TemplateField[] {
const fields: TemplateField[] = [];
// @ts-ignore
const primaryFields: Field[] = frappe.models[doctype].fields;
const tableTypes: string[] = [];
primaryFields.forEach(
({ label, fieldtype, childtype, fieldname, required }) => {
if (fieldtype === FieldType.Table && childtype) {
tableTypes.push(childtype);
}
fields.push({
label,
fieldname,
required: Boolean(required ?? false),
});
}
);
tableTypes.forEach((childtype) => {
// @ts-ignore
const childFields: Field[] = frappe.models[childtype].fields;
childFields.forEach(({ label, fieldtype, fieldname, required }) => {
if (fieldtype === FieldType.Table) {
return;
}
fields.push({ label, fieldname, required: Boolean(required ?? false) });
});
});
return fields;
}
function getLabelFieldMap(templateFields: TemplateField[]): LabelFieldMap {
const map: LabelFieldMap = {};
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[];
_map: LabelFieldMap;
_template: string;
constructor(doctype: string) {
this.doctype = doctype;
this.templateFields = getTemplateFields(doctype);
this._map = getLabelFieldMap(this.templateFields);
this._template = getTemplate(this.templateFields);
}
get map() {
return this._map;
}
get template() {
return this._template;
}
}

View File

@ -37,11 +37,7 @@
input-class="bg-gray-100 text-gray-900 text-base"
class="w-1/4"
:value="importType"
@change="
(v) => {
importType = v;
}
"
@change="setImportType"
/>
<p
class="text-base text-base"
@ -55,8 +51,13 @@
<div v-if="importType">
<hr class="mb-6" />
<div class="flex flex-row justify-between text-base">
<Button class="w-1/4" :padding="false">{{ secondaryLabel }}</Button>
<Button class="w-1/4" type="primary" @click="getFile">{{
<Button
class="w-1/4"
:padding="false"
@click="handleSecondaryClick"
>{{ secondaryLabel }}</Button
>
<Button class="w-1/4" type="primary" @click="handlePrimaryClick">{{
primaryLabel
}}</Button>
</div>
@ -68,17 +69,18 @@
<script>
import FormControl from '@/components/Controls/FormControl';
import PageHeader from '@/components/PageHeader.vue';
import { importable } from '@/dataImport';
import { importable, Importer } from '@/dataImport';
import frappe from 'frappe';
import Button from '@/components/Button.vue';
import { ipcRenderer } from 'electron';
import { IPC_ACTIONS } from '@/messages';
import { showToast } from '@/utils';
import { getSavePath, saveData, showToast } from '@/utils';
export default {
components: { PageHeader, FormControl, Button },
data() {
return {
file: null,
importer: null,
importType: '',
};
},
@ -130,13 +132,42 @@ export default {
methods: {
cancel() {
this.file = null;
this.importer = null;
this.importType = '';
},
handlePrimaryClick() {},
handleSecondaryClick() {},
saveTemplate() {},
getImportData() {},
async getFile() {
handlePrimaryClick() {
if (!this.file) {
this.selectFile();
return;
}
this.importData();
},
handleSecondaryClick() {
if (!this.file) {
this.saveTemplate();
return;
}
this.toggleView();
},
async saveTemplate() {
const template = this.importer.template;
const templateName = this.importType + ' ' + this.t`Template`;
const { cancelled, filePath } = await getSavePath(templateName, 'csv');
if (cancelled || filePath === '') {
return;
}
await saveData(template, filePath);
},
importData() {},
toggleView() {},
setImportType(importType) {
this.importType = importType;
this.importer = new Importer(this.labelDoctypeMap[this.importType]);
},
async selectFile() {
const options = {
title: this.t`Select File`,
properties: ['openFile'],

26
src/types/model.ts Normal file
View File

@ -0,0 +1,26 @@
export enum FieldType {
Data = 'Data',
Select = 'Select',
Link = 'Link',
Date = 'Date',
Table = 'Table',
AutoComplete = 'AutoComplete',
Check = 'Check',
AttachImage = 'AttachImage',
DynamicLink = 'DynamicLink',
Int = 'Int',
Float = 'Float',
Currency = 'Currency',
Text = 'Text',
Color = 'Color',
}
export interface Field {
fieldname: string;
fieldtype: FieldType;
label: string;
childtype?: string;
target?: string;
default?: unknown;
required?: number;
}