diff --git a/package.json b/package.json
index bd1cd93..e7e7c5f 100644
--- a/package.json
+++ b/package.json
@@ -3,10 +3,11 @@
"author": "Frappe Technologies Pvt. Ltd.",
"license": "AGPL-3.0-or-later",
"dependencies": {
- "@interactjs/interact": "^1.10.17",
"@interactjs/actions": "^1.10.17",
"@interactjs/auto-start": "^1.10.17",
+ "@interactjs/interact": "^1.10.17",
"@interactjs/modifiers": "^1.10.17",
+ "html2canvas": "^1.4.1",
"pdfjs-dist": "v3.4.120"
}
}
diff --git a/print_designer/custom_fields.py b/print_designer/custom_fields.py
index 981b556..c0c1045 100644
--- a/print_designer/custom_fields.py
+++ b/print_designer/custom_fields.py
@@ -44,5 +44,19 @@
"fieldtype": "JSON",
"label": "Print Designer Settings",
},
+ {
+ "fieldname": "print_designer_preview_img",
+ "hidden": 1,
+ "fieldtype": "Attach Image",
+ "label": "Print Designer Preview Image",
+ },
+ {
+ "depends_on": "eval:doc.print_designer && doc.standard == 'Yes'",
+ "fieldname": "print_designer_template_app",
+ "fieldtype": "Select",
+ "label": "Print Designer Template Location",
+ "default": "print_designer",
+ "insert_after": "standard",
+ },
]
}
diff --git a/print_designer/default_formats.py b/print_designer/default_formats.py
new file mode 100644
index 0000000..2e0e9f9
--- /dev/null
+++ b/print_designer/default_formats.py
@@ -0,0 +1,117 @@
+import os
+import shutil
+from pathlib import Path
+
+import frappe
+from frappe.modules.import_file import import_file_by_path
+from frappe.utils import get_files_path
+
+"""
+features:
+ - Print Designer App can have default formats for all installed apps.
+ - Any Custom/Standard App can have default formats for any installed apps
+ ( This will only install formats if print_designer is installed ).
+ - This will be useful when we have standalone formats that can be used without print designer app.
+
+when print_designer app is installed
+ - get hooks from all installed apps including pd and load default formats from defined folders.
+
+when any new app is installed
+ - if exists in print_designer/default_templates, load default formats for newly installed app.
+ - get hooks from new app and load default formats for all installed apps from app's format dir.
+"""
+
+# TODO: handle override of default formats from different apps or even Custom Formats with same name.
+
+# add default formats for all installed apps.
+def on_print_designer_install():
+ for app in frappe.get_installed_apps():
+ install_default_formats(app=app, load_pd_formats=False)
+
+
+def get_preview_image_folder_path(print_format):
+ app = frappe.scrub(frappe.get_doctype_app(print_format.doc_type))
+ pd_folder = frappe.get_hooks(
+ "pd_standard_format_folder", app_name=print_format.print_designer_template_app
+ )
+ if len(pd_folder) == 0:
+ pd_folder = ["default_templates"]
+ return os.path.join(
+ frappe.get_app_path(print_format.print_designer_template_app), os.path.join(pd_folder[0], app)
+ )
+
+
+def update_preview_img(file):
+ print_format = frappe.get_doc(file.attached_to_doctype, file.attached_to_name)
+ folder = get_preview_image_folder_path(print_format)
+ file_name = print_format.print_designer_preview_img.split("/")[-1]
+ org_path = os.path.join(folder, file_name)
+ target_path = get_files_path(file_name, is_private=1)
+ shutil.copy2(org_path, target_path)
+
+
+# called after install of any new app.
+def install_default_formats(app, filter_by="", load_pd_formats=True):
+ if load_pd_formats:
+ # load formats from print_designer app if some new app is installed and have default formats
+ install_default_formats(app="print_designer", filter_by=app, load_pd_formats=False)
+
+ # get dir path and load formats from installed app
+ pd_folder = frappe.get_hooks("pd_standard_format_folder", app_name=app)
+ if len(pd_folder) == 0:
+ return
+
+ print_formats = get_filtered_formats_by_app(
+ app=app, templates_folder=pd_folder[0], filter_by=filter_by
+ )
+
+ # preview_files = [f for f in print_formats if f.name.endswith("-preview.json")]
+ print_formats = [f for f in print_formats if not f.name.endswith("-preview.json")]
+
+ for json_file_path in print_formats:
+ import_file_by_path(path=json_file_path)
+ frappe.db.commit()
+ # TODO: enable this after this is released in v15 https://github.com/frappe/frappe/pull/25779
+ # for json_file_path in preview_files:
+ # import_file_by_path(path=json_file_path, pre_process=update_preview_img)
+ # frappe.db.commit()
+
+ # for pf in frappe.db.get_all("Print Format", filters={"standard": "Yes", "print_designer": 1}):
+ # updated_url = frappe.db.get_value(
+ # "File",
+ # {
+ # "attached_to_doctype": "Print Format",
+ # "attached_to_name": pf.name,
+ # "attached_to_field": "print_designer_preview_img",
+ # },
+ # "file_url",
+ # )
+ # if updated_url:
+ # frappe.set_value("Print Format", pf.name, "print_designer_preview_img", updated_url)
+
+
+def get_filtered_formats_by_app(app, templates_folder, filter_by=""):
+ app_path = frappe.get_app_path(app)
+ if filter_by == "":
+ folders = Path(os.path.join(app_path, templates_folder))
+ return get_formats_from_folders(folders=folders)
+ else:
+ folder = Path(os.path.join(app_path, templates_folder, filter_by))
+ return get_json_files(folder)
+
+
+def get_formats_from_folders(folders):
+ formats = set()
+ if not folders.exists():
+ return formats
+ for folder in folders.iterdir():
+ if folder.is_dir() and folder.name in frappe.get_installed_apps():
+ formats.update(get_json_files(folder))
+ return formats
+
+
+def get_json_files(folder):
+ formats = set()
+ for json_file in folder.glob("*.json"):
+ formats.add(json_file)
+ return formats
diff --git a/print_designer/hooks.py b/print_designer/hooks.py
index 68e9d5e..4b1079b 100644
--- a/print_designer/hooks.py
+++ b/print_designer/hooks.py
@@ -72,6 +72,7 @@
before_install = "print_designer.install.before_install"
after_install = "print_designer.install.after_install"
+after_app_install = "print_designer.install.after_app_install"
# Uninstallation
# ------------
@@ -110,10 +111,12 @@
# ---------------
# Override standard doctype classes
-# override_doctype_class = {
-# "ToDo": "custom_app.overrides.CustomToDo"
-# }
+override_doctype_class = {
+ "Print Format": "print_designer.print_designer.overrides.print_format.PDPrintFormat",
+}
+# Path Relative to the app folder where default templates should be stored
+pd_standard_format_folder = "default_templates"
# Document Events
# ---------------
# Hook on document methods and events
diff --git a/print_designer/install.py b/print_designer/install.py
index af9200c..22ebc80 100644
--- a/print_designer/install.py
+++ b/print_designer/install.py
@@ -3,6 +3,7 @@
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
from print_designer.custom_fields import CUSTOM_FIELDS
+from print_designer.default_formats import install_default_formats, on_print_designer_install
def check_frappe_version():
@@ -27,3 +28,9 @@ def before_install():
def after_install():
create_custom_fields(CUSTOM_FIELDS, ignore_validate=True)
+ on_print_designer_install()
+
+
+def after_app_install(app):
+ if app != "print_designer":
+ install_default_formats(app)
diff --git a/print_designer/patches.txt b/print_designer/patches.txt
index 1c006ff..6f8c620 100644
--- a/print_designer/patches.txt
+++ b/print_designer/patches.txt
@@ -9,3 +9,4 @@ print_designer.patches.introduce_suffix_dynamic_content
print_designer.patches.introduce_dynamic_containers
print_designer.patches.introduce_dynamic_height
print_designer.patches.remove_unused_rectangle_gs_properties
+execute:from print_designer.patches.create_custom_fields import custom_field_patch; custom_field_patch()
diff --git a/print_designer/patches/create_custom_fields.py b/print_designer/patches/create_custom_fields.py
new file mode 100644
index 0000000..304b916
--- /dev/null
+++ b/print_designer/patches/create_custom_fields.py
@@ -0,0 +1,7 @@
+from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
+
+from print_designer.custom_fields import CUSTOM_FIELDS
+
+
+def custom_field_patch():
+ create_custom_fields(CUSTOM_FIELDS, ignore_validate=True)
diff --git a/print_designer/print_designer/client_scripts/print_format.js b/print_designer/print_designer/client_scripts/print_format.js
index 6e88365..c4bacc9 100644
--- a/print_designer/print_designer/client_scripts/print_format.js
+++ b/print_designer/print_designer/client_scripts/print_format.js
@@ -1,6 +1,16 @@
+const set_template_app_options = (frm) => {
+ frappe.xcall("frappe.core.doctype.module_def.module_def.get_installed_apps").then((r) => {
+ frm.set_df_property("print_designer_template_app", "options", JSON.parse(r));
+ if (!frm.doc.print_designer_template_app) {
+ frm.set_value("print_designer_template_app", "print_designer");
+ }
+ });
+};
+
frappe.ui.form.on("Print Format", {
refresh: function (frm) {
frm.trigger("render_buttons");
+ set_template_app_options(frm);
},
render_buttons: function (frm) {
frm.page.clear_inner_toolbar();
diff --git a/print_designer/print_designer/overrides/print_format.py b/print_designer/print_designer/overrides/print_format.py
new file mode 100644
index 0000000..6b3ca46
--- /dev/null
+++ b/print_designer/print_designer/overrides/print_format.py
@@ -0,0 +1,84 @@
+import os
+import shutil
+
+import frappe
+from frappe.modules.utils import scrub
+from frappe.printing.doctype.print_format.print_format import PrintFormat
+
+
+class PDPrintFormat(PrintFormat):
+ def export_doc(self):
+ if (
+ not self.standard == "Yes"
+ or not frappe.conf.developer_mode
+ or frappe.flags.in_patch
+ or frappe.flags.in_install
+ or frappe.flags.in_migrate
+ or frappe.flags.in_import
+ or frappe.flags.in_setup_wizard
+ ):
+ return
+
+ if not self.print_designer:
+ return super().export_doc()
+
+ self.write_document_file()
+
+ def write_document_file(self):
+ doc = self
+ doc_export = doc.as_dict(no_nulls=True)
+ doc.run_method("before_export", doc_export)
+
+ # create folder
+ folder = self.create_folder(doc.doc_type, doc.name)
+
+ fname = scrub(doc.name)
+
+ # write the data file
+ path = os.path.join(folder, f"{fname}.json")
+ with open(path, "w+") as json_file:
+ json_file.write(frappe.as_json(doc_export))
+ print(f"Wrote document file for {doc.doctype} {doc.name} at {path}")
+ self.export_preview(folder=folder, fname=fname)
+
+ def create_folder(self, dt, dn):
+ app = scrub(frappe.get_doctype_app(dt))
+ dn = scrub(dn)
+ pd_folder = frappe.get_hooks(
+ "pd_standard_format_folder", app_name=self.print_designer_template_app
+ )
+ if len(pd_folder) == 0:
+ pd_folder = ["default_templates"]
+ folder = os.path.join(
+ frappe.get_app_path(self.print_designer_template_app), os.path.join(pd_folder[0], app)
+ )
+ frappe.create_folder(folder)
+ return folder
+
+ def export_preview(self, folder, fname):
+ if self.print_designer_preview_img:
+ try:
+ file = frappe.get_doc(
+ "File",
+ {
+ "file_url": self.print_designer_preview_img,
+ "attached_to_doctype": self.doctype,
+ "attached_to_name": self.name,
+ "attached_to_field": "print_designer_preview_img",
+ },
+ )
+ except frappe.DoesNotExistError:
+ file = None
+ if not file:
+ return
+ file_export = file.as_dict(no_nulls=True)
+ file.run_method("before_export", file_export)
+ org_path = file.get_full_path()
+ target_path = os.path.join(folder, org_path.split("/")[-1])
+ shutil.copy2(org_path, target_path)
+ print(f"Wrote preview file for {self.doctype} {self.name} at {target_path}")
+ # write the data file
+ path = os.path.join(folder, f"print_designer-{fname}-preview.json")
+ with open(path, "w+") as json_file:
+ json_file.write(frappe.as_json(file_export))
+ print(f"Wrote document file for {file.doctype} {file.name} at {path}")
diff --git a/print_designer/print_designer/page/print_designer/jinja/macros/image.html b/print_designer/print_designer/page/print_designer/jinja/macros/image.html
index 7662b9f..0515361 100644
--- a/print_designer/print_designer/page/print_designer/jinja/macros/image.html
+++ b/print_designer/print_designer/page/print_designer/jinja/macros/image.html
@@ -1,14 +1,26 @@
{% macro image(element) -%}
+{%- if element.image.file_url -%}
+ {%- set value = element.image.file_url -%}
+{%- elif element.image.fieldname -%}
+ {%- if element.image.parent == doc.doctype -%}
+ {%- set value = doc.get(element.image.fieldname) -%}
+ {%- else -%}
+ {%- set value = frappe.db.get_value(element.image.doctype, doc[element.image.parentField], element.image.fieldname) -%}
+ {%- endif -%}
+{%- else -%}
+ {%- set value = "" -%}
+{%- endif -%}
+
+{%- if value -%}
+{%- endif -%}
{%- endmacro %}
\ No newline at end of file
diff --git a/print_designer/print_designer/page/print_designer/jinja/old_print_format.html b/print_designer/print_designer/page/print_designer/jinja/old_print_format.html
index 0a54666..8945ea4 100644
--- a/print_designer/print_designer/page/print_designer/jinja/old_print_format.html
+++ b/print_designer/print_designer/page/print_designer/jinja/old_print_format.html
@@ -40,6 +40,20 @@
{%- endmacro %}
{% macro render_image(element) -%}
+
+{%- if element.image.file_url -%}
+ {%- set value = element.image.file_url -%}
+{%- elif element.image.fieldname -%}
+ {%- if element.image.parent == doc.doctype -%}
+ {%- set value = doc.get(element.image.fieldname) -%}
+ {%- else -%}
+ {%- set value = frappe.db.get_value(element.image.doctype, doc[element.image.parentField], element.image.fieldname) -%}
+ {%- endif -%}
+{%- else -%}
+ {%- set value = "" -%}
+{%- endif -%}
+
+{%- if value -%}
+{%- endif -%}
{%- endmacro %}
{% macro render_barcode(element, send_to_jinja) -%}
{%- set field = element.dynamicContent[0] -%}
diff --git a/print_designer/public/js/print_designer/components/layout/AppCanvas.vue b/print_designer/public/js/print_designer/components/layout/AppCanvas.vue
index 4828bc3..c5065ce 100644
--- a/print_designer/public/js/print_designer/components/layout/AppCanvas.vue
+++ b/print_designer/public/js/print_designer/components/layout/AppCanvas.vue
@@ -465,13 +465,6 @@ onMounted(() => {
watchEffect(() => {
if (MainStore.screenStyleSheet) {
- if (MainStore.screenStyleSheet.CssRuleIndex != null) {
- try {
- MainStore.screenStyleSheet.deleteRule(MainStore.screenStyleSheet.CssRuleIndex);
- } catch (error) {
- console.warn("Error Deleting Rule", error);
- }
- }
MainStore.screenStyleSheet.CssRuleIndex = MainStore.addStylesheetRules([
[
":root, ::after, ::before",
@@ -530,13 +523,6 @@ onMounted(() => {
});
watchEffect(() => {
if (MainStore.printStyleSheet && MainStore.page) {
- for (let index = 0; index < MainStore.printStyleSheet.cssRules.length; index++) {
- try {
- MainStore.printStyleSheet.deleteRule(index);
- } catch (error) {
- console.warn("Error Deleting Rule", error);
- }
- }
const convertToMM = (input) => {
let convertedUnit = useChangeValueUnit({
inputString: input,
@@ -568,13 +554,6 @@ watchEffect(() => {
});
watchEffect(() => {
if (MainStore.screenStyleSheet && MainStore.modalLocation) {
- for (let index = 0; index < MainStore.screenStyleSheet.cssRules.length; index++) {
- try {
- MainStore.screenStyleSheet.deleteRule(index);
- } catch (error) {
- console.warn("Error Deleting Rule", error);
- }
- }
MainStore.addStylesheetRules([
[
":root",
diff --git a/print_designer/public/js/print_designer/store/ElementStore.js b/print_designer/public/js/print_designer/store/ElementStore.js
index 40b8b51..eede374 100644
--- a/print_designer/public/js/print_designer/store/ElementStore.js
+++ b/print_designer/public/js/print_designer/store/ElementStore.js
@@ -9,6 +9,9 @@ import {
createBarcode,
} from "../defaultObjects";
import { handlePrintFonts, setCurrentElement } from "../utils";
+
+import html2canvas from "html2canvas";
+
export const useElementStore = defineStore("ElementStore", {
state: () => ({
Elements: new Array(),
@@ -34,10 +37,116 @@ export const useElementStore = defineStore("ElementStore", {
}
return newElement;
},
+ // This is modified version of upload function used in frappe/FileUploader.vue
+ async upload_file(file) {
+ const MainStore = useMainStore();
+ MainStore.print_designer_preview_img = null;
+ return new Promise((resolve, reject) => {
+ let xhr = new XMLHttpRequest();
+ xhr.onreadystatechange = () => {
+ if (xhr.readyState == XMLHttpRequest.DONE) {
+ if (xhr.status === 200) {
+ try {
+ r = JSON.parse(xhr.responseText);
+ if (r.message.doctype === "File") {
+ file_url = r.message.file_url;
+ // if format is not saved then update the preview image value with it
+ if (MainStore.isFormatSaving) {
+ MainStore.print_designer_preview_img = file_url;
+ } else {
+ // if format is already saved then update the print_designer_preview_img field
+ frappe.db.set_value(
+ "Print Format",
+ MainStore.printDesignName,
+ "print_designer_preview_img",
+ file_url
+ );
+ }
+ }
+ } catch (e) {
+ r = xhr.responseText;
+ }
+ }
+ }
+ };
+ xhr.open("POST", "/api/method/upload_file", true);
+ xhr.setRequestHeader("Accept", "application/json");
+ xhr.setRequestHeader("X-Frappe-CSRF-Token", frappe.csrf_token);
+
+ let form_data = new FormData();
+ if (file.file_obj) {
+ form_data.append("file", file.file_obj, file.name);
+ }
+ form_data.append("is_private", 1);
+
+ form_data.append("doctype", "Print Format");
+ form_data.append("docname", MainStore.printDesignName);
+
+ form_data.append("fieldname", "print_designer_preview_img");
+
+ if (file.optimize) {
+ form_data.append("optimize", true);
+ }
+ xhr.send(form_data);
+ });
+ },
+ async generatePreview() {
+ const MainStore = useMainStore();
+ // first delete old preview image
+ const filter = {
+ attached_to_doctype: "Print Format",
+ attached_to_name: MainStore.printDesignName,
+ attached_to_field: "print_designer_preview_img",
+ };
+ // get filename before uploading new file
+ let old_filename = await frappe.db.get_value("File", filter, "name");
+ old_filename = old_filename.message.name;
+ if (old_filename) {
+ frappe.db.delete_doc("File", old_filename);
+ }
+
+ const options = {
+ backgroundColor: "#ffffff",
+ height: MainStore.page.height,
+ width: MainStore.page.width,
+ };
+ const print_stylesheet = document.createElement("style");
+ print_stylesheet.rel = "stylesheet";
+ let st = `.main-container::after {
+ display: none;
+ }`;
+ document.getElementsByClassName("main-container")[0].appendChild(print_stylesheet);
+ print_stylesheet.sheet.insertRule(st, 0);
+ const preview_canvas = await html2canvas(
+ document.getElementsByClassName("main-container")[0],
+ options
+ );
+ document.getElementsByClassName("main-container")[0].removeChild(print_stylesheet);
+ preview_canvas.toBlob(async (blob) => {
+ const file = new File(
+ [blob],
+ `print_designer-${frappe.scrub(MainStore.printDesignName)}-preview.jpg`,
+ { type: "image/jpeg" }
+ );
+ const file_data = {
+ file_obj: file,
+ optimize: 1,
+ name: file.name,
+ private: true,
+ };
+ await this.upload_file(file_data);
+ });
+ },
async saveElements() {
const MainStore = useMainStore();
if (this.checkIfAnyTableIsEmpty()) return;
-
+ if (MainStore.mode == "preview") return;
+ let is_standard = await frappe.db.get_value(
+ "Print Format",
+ MainStore.printDesignName,
+ "standard"
+ );
+ MainStore.is_standard = is_standard.message.standard == "Yes";
// Update the header and footer height with margin
MainStore.page.headerHeightWithMargin =
MainStore.page.headerHeight + MainStore.page.marginTop;
@@ -62,6 +171,9 @@ export const useElementStore = defineStore("ElementStore", {
const [cleanedBodyElements, bodyFonts] = body;
const [cleanedHeaderElements, headerFonts] = header || [[], null];
const [cleanedFooterElements, footerFonts] = footer || [[], null];
+ MainStore.printHeaderFonts = headerFonts;
+ MainStore.printBodyFonts = bodyFonts;
+ MainStore.printFooterFonts = footerFonts;
MainStore.currentFonts.length = 0;
MainStore.currentFonts.push(
@@ -119,12 +231,17 @@ export const useElementStore = defineStore("ElementStore", {
dimensions: footerDimensions,
},
});
+ MainStore.isFormatSaving = true;
+
+ await this.generatePreview();
objectToSave.print_designer_print_format = PrintFormatData;
+ objectToSave.print_designer_preview_img = MainStore.print_designer_preview_img;
if (MainStore.isOlderSchema("1.1.0")) {
await this.printFormatCopyOnOlderSchema(objectToSave);
} else {
await frappe.db.set_value("Print Format", MainStore.printDesignName, objectToSave);
+ MainStore.isFormatSaving = false;
frappe.show_alert(
{
message: `Print Format Saved Successfully`,
@@ -322,12 +439,12 @@ export const useElementStore = defineStore("ElementStore", {
},
cleanUpElementsForSave(elements, type) {
if (this.checkIfPrintFormatIsEmpty(elements, type)) return;
- const fontsArray = [];
+ const fontsObject = {};
const cleanedElements = [];
elements.forEach((container) => {
const cleanedContainer = [];
container.forEach((element) => {
- let newElement = this.childrensSave(element.element, fontsArray);
+ let newElement = this.childrensSave(element.element, fontsObject);
newElement.classes = newElement.classes.filter(
(name) => ["inHeaderFooter", "overlappingHeaderFooter"].indexOf(name) == -1
);
@@ -342,7 +459,7 @@ export const useElementStore = defineStore("ElementStore", {
});
cleanedElements.push(cleanedContainer);
});
- return [cleanedElements, fontsArray];
+ return [cleanedElements, fontsObject];
},
checkIfPrintFormatIsEmpty(elements, type) {
const MainStore = useMainStore();
@@ -377,6 +494,11 @@ export const useElementStore = defineStore("ElementStore", {
delete saveEl.snapPoints;
delete saveEl.snapEdges;
delete saveEl.parent;
+ this.cleanUpDynamicContent(saveEl);
+ if (saveEl.type == "table") {
+ delete saveEl.table.childfields;
+ delete saveEl.table.default_layout;
+ }
if (printFonts && ["text", "table"].indexOf(saveEl.type) != -1) {
handlePrintFonts(saveEl, printFonts);
}
@@ -391,6 +513,55 @@ export const useElementStore = defineStore("ElementStore", {
return saveEl;
},
+ cleanUpDynamicContent(element) {
+ const MainStore = useMainStore();
+ if (
+ ["table", "image"].includes(element.type) ||
+ (["text", "barcode"].includes(element.type) && element.isDynamic)
+ ) {
+ if (["text", "barcode"].indexOf(element.type) != -1) {
+ element.dynamicContent = [
+ ...element.dynamicContent.map((el) => {
+ const newEl = { ...el };
+ if (!el.is_static) {
+ newEl.value = "";
+ }
+ return newEl;
+ }),
+ ];
+ element.selectedDynamicText = null;
+ } else if (element.type === "table") {
+ element.columns = [
+ ...element.columns.map((el) => {
+ const newEl = { ...el };
+ delete newEl.DOMRef;
+ return newEl;
+ }),
+ ];
+ element.columns.forEach((col) => {
+ if (!col.dynamicContent) return;
+ col.dynamicContent = [
+ ...col.dynamicContent.map((el) => {
+ const newEl = { ...el };
+ if (!el.is_static) {
+ newEl.value = "";
+ }
+ return newEl;
+ }),
+ ];
+ col.selectedDynamicText = null;
+ });
+ } else {
+ element.image = { ...element.image };
+ if (MainStore.is_standard) {
+ // remove file_url and file_name if format is standard
+ ["value", "name", "file_name", "file_url", "modified"].forEach((key) => {
+ element.image[key] = "";
+ });
+ }
+ }
+ }
+ },
getPrintFormatData({ header, body, footer }) {
const headerElements = this.createWrapperElement(
header.elements,
@@ -443,56 +614,100 @@ export const useElementStore = defineStore("ElementStore", {
return wrapperContainers.childrens.map((el) => this.childrensSave(el));
},
async printFormatCopyOnOlderSchema(objectToSave) {
- const MainStore = useMainStore();
- let nextFormatCopyNumber = 0;
- for (let i = 0; i < 100; i++) {
- const pf_exists = await frappe.db.exists(
- "Print Format",
- MainStore.printDesignName + " ( Copy " + (i ? i : "") + " )"
- );
- if (pf_exists) continue;
- nextFormatCopyNumber = i;
- break;
- }
- const newName =
- MainStore.printDesignName +
- " ( Copy " +
- (nextFormatCopyNumber ? nextFormatCopyNumber : "") +
- " )";
// TODO: have better message.
let message = __(
"This Print Format was created from older version of Print Designer."
);
message += "
";
message += __(
- "It is not compatible with current version so instead we will make copy of this format for you using new version"
+ "It is not compatible with current version so instead make copy of this format using new version"
);
message += "
";
- message += __(`Do you want to save it as ${newName} ?`);
+ message += __(`Do you want to save copy of it ?`);
frappe.confirm(
message,
async () => {
- await frappe.db.insert({
- doctype: "Print Format",
- name: newName,
- doc_type: MainStore.doctype,
- print_designer: 1,
- print_designer_header: objectToSave.print_designer_header,
- print_designer_body: objectToSave.print_designer_body,
- print_designer_after_table: null,
- print_designer_footer: objectToSave.print_designer_footer,
- print_designer_print_format: objectToSave.print_designer_print_format,
- print_designer_settings: objectToSave.print_designer_settings,
- });
- frappe.set_route("print-designer", newName);
+ this.promptUserForNewFormatName(objectToSave);
},
async () => {
+ frappe.show_alert(
+ {
+ message: `Print Format not saved`,
+ indicator: "red",
+ },
+ 5
+ );
+ // intentionally throwing error to stop the saving the format
throw new Error(__("Print Format not saved"));
}
);
},
+ async promptUserForNewFormatName(objectToSave) {
+ const MainStore = useMainStore();
+ let nextFormatCopyNumber = 0;
+ for (let i = 0; i < 100; i++) {
+ const pf_exists = await frappe.db.exists(
+ "Print Format",
+ MainStore.printDesignName + " ( Copy " + (i ? i : "") + " )"
+ );
+ if (pf_exists) continue;
+ nextFormatCopyNumber = i;
+ break;
+ }
+ // This is just default value for the new print format name
+ const print_format_name =
+ MainStore.printDesignName +
+ " ( Copy " +
+ (nextFormatCopyNumber ? nextFormatCopyNumber : "") +
+ " )";
+ let d = new frappe.ui.Dialog({
+ title: "New Print Format",
+ fields: [
+ {
+ label: "Name",
+ fieldname: "print_format_name",
+ fieldtype: "Data",
+ reqd: 1,
+ default: print_format_name,
+ },
+ ],
+ size: "small",
+ primary_action_label: "Save",
+ static: true,
+ async primary_action(values) {
+ try {
+ await frappe.db.insert({
+ doctype: "Print Format",
+ name: values.print_format_name,
+ doc_type: MainStore.doctype,
+ print_designer: 1,
+ print_designer_header: objectToSave.print_designer_header,
+ print_designer_body: objectToSave.print_designer_body,
+ print_designer_after_table: null,
+ print_designer_footer: objectToSave.print_designer_footer,
+ print_designer_print_format: objectToSave.print_designer_print_format,
+ print_designer_settings: objectToSave.print_designer_settings,
+ });
+ d.hide();
+ frappe.set_route("print-designer", values.print_format_name);
+ } catch (error) {
+ console.error(error);
+ }
+ },
+ });
+ d.get_close_btn().on("click", () => {
+ frappe.show_alert(
+ {
+ message: `Print Format not saved`,
+ indicator: "red",
+ },
+ 5
+ );
+ });
+ d.show();
+ },
handleDynamicContent(element) {
const MainStore = useMainStore();
if (
@@ -502,12 +717,25 @@ export const useElementStore = defineStore("ElementStore", {
if (["text", "barcode"].indexOf(element.type) != -1) {
element.dynamicContent = [
...element.dynamicContent.map((el) => {
- return { ...el };
+ const newEl = { ...el };
+ if (!el.is_static) {
+ newEl.value = "";
+ }
+ return newEl;
}),
];
element.selectedDynamicText = null;
MainStore.dynamicData.push(...element.dynamicContent);
} else if (element.type === "table") {
+ if (element.table) {
+ const mf = MainStore.metaFields.find(
+ (field) => field.fieldname == element.table.fieldname
+ );
+ if (mf) {
+ element.table = mf;
+ }
+ }
+
element.columns = [
...element.columns.map((el) => {
return { ...el };
@@ -517,7 +745,11 @@ export const useElementStore = defineStore("ElementStore", {
if (!col.dynamicContent) return;
col.dynamicContent = [
...col.dynamicContent.map((el) => {
- return { ...el };
+ const newEl = { ...el };
+ if (!el.is_static) {
+ newEl.value = "";
+ }
+ return newEl;
}),
];
col.selectedDynamicText = null;
diff --git a/yarn.lock b/yarn.lock
index 8f1cafd..8893f97 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -106,6 +106,11 @@ balanced-match@^1.0.0:
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
+base64-arraybuffer@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz#1c37589a7c4b0746e34bd1feb951da2df01c1bdc"
+ integrity sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==
+
brace-expansion@^1.1.7:
version "1.1.11"
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
@@ -143,6 +148,13 @@ console-control-strings@^1.0.0, console-control-strings@^1.1.0:
resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e"
integrity sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==
+css-line-break@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/css-line-break/-/css-line-break-2.1.0.tgz#bfef660dfa6f5397ea54116bb3cb4873edbc4fa0"
+ integrity sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==
+ dependencies:
+ utrie "^1.0.2"
+
debug@4:
version "4.3.4"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
@@ -216,6 +228,14 @@ has-unicode@^2.0.1:
resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9"
integrity sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==
+html2canvas@^1.4.1:
+ version "1.4.1"
+ resolved "https://registry.yarnpkg.com/html2canvas/-/html2canvas-1.4.1.tgz#7cef1888311b5011d507794a066041b14669a543"
+ integrity sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==
+ dependencies:
+ css-line-break "^2.1.0"
+ text-segmentation "^1.0.3"
+
https-proxy-agent@^5.0.0:
version "5.0.1"
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6"
@@ -451,6 +471,13 @@ tar@^6.1.11:
mkdirp "^1.0.3"
yallist "^4.0.0"
+text-segmentation@^1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/text-segmentation/-/text-segmentation-1.0.3.tgz#52a388159efffe746b24a63ba311b6ac9f2d7943"
+ integrity sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==
+ dependencies:
+ utrie "^1.0.2"
+
tr46@~0.0.3:
version "0.0.3"
resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
@@ -461,6 +488,13 @@ util-deprecate@^1.0.1:
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==
+utrie@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/utrie/-/utrie-1.0.2.tgz#d42fe44de9bc0119c25de7f564a6ed1b2c87a645"
+ integrity sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==
+ dependencies:
+ base64-arraybuffer "^1.0.2"
+
web-streams-polyfill@^3.2.1:
version "3.2.1"
resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz#71c2718c52b45fd49dbeee88634b3a60ceab42a6"