Skip to content

Commit

Permalink
Merge branch 'main' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
maharshivpatel committed Mar 27, 2024
2 parents fb19b9f + 1e7eabc commit 921cc72
Show file tree
Hide file tree
Showing 31 changed files with 688 additions and 123 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,10 @@ There are many ways you can contribute even if you don't code:
- [HomeBrew](https://brew.sh/) and `brew install pkg-config cairo pango libpng jpeg giflib librsvg pixman`
- If you have **xcode 10.0 or higher** installed, in order to build from source you need **NPM 6.4.1 or higher** `npm install -g npm@latest`.
3. Linux ARM CPU Installation Error
- If error has `node-pre-gyp WARN Pre-built binaries not installable for canvas@x.x.x and node@x.x.x` it means that there aren't any pre-built binaries for your system so it will try to compile them
- In order to do that you need `sudo apt-get update && sudo apt-get install build-essential libcairo2-dev libpango1.0-dev libjpeg-dev libgif-dev librsvg2-dev`
## License
[GNU Affero General Public License v3.0](license.txt)
8 changes: 6 additions & 2 deletions print_designer/hooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
# ------------------

# include js, css files in header of desk.html
app_include_js = "pdf.worker.bundle.js"
# app_include_js = ""


# include js, css files in header of web template
Expand All @@ -26,7 +26,10 @@
# webform_include_css = {"doctype": "public/css/doctype.css"}

# include js in page
page_js = {"print": "print_designer/client_scripts/print.js"}
page_js = {
"print": "print_designer/client_scripts/print.js",
"point-of-sale": "print_designer/client_scripts/point_of_sale.js",
}

# include js in doctype views
doctype_js = {"Print Format": "print_designer/client_scripts/print_format.js"}
Expand Down Expand Up @@ -84,6 +87,7 @@
pdf_body_html = "print_designer.pdf.pdf_body_html"
pdf_footer_html = "print_designer.pdf.pdf_header_footer_html"

get_print_format_template = "print_designer.pdf.get_print_format_template"
# Desk Notifications
# ------------------
# See frappe.core.notifications.get_notification_config
Expand Down
5 changes: 4 additions & 1 deletion print_designer/patches.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,7 @@ print_designer.patches.update_white_space_property
print_designer.patches.introduce_barcode
print_designer.patches.introduce_jinja
print_designer.patches.introduce_schema_versioning
print_designer.patches.rerun_introduce_jinja
print_designer.patches.rerun_introduce_jinja
print_designer.patches.introduce_table_alt_row_styles
print_designer.patches.introduce_column_style
print_designer.patches.introduce_suffix_dynamic_content
18 changes: 18 additions & 0 deletions print_designer/patches/introduce_column_style.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import frappe

from print_designer.patches.patch_utils import patch_formats


def execute():
"""Modify Formats to work with New Column Style Feature"""

def element_callback(el):
el["selectedColumn"] = None
for col in el["columns"]:
col["style"] = {}
col["applyStyleToHeader"] = False

patch_formats(
{"element": element_callback},
types=["table"],
)
17 changes: 17 additions & 0 deletions print_designer/patches/introduce_suffix_dynamic_content.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import frappe

from print_designer.patches.patch_utils import patch_formats


def execute():
"""Introduce suffix to dynamic content elements"""

def dynamic_content_callback(el):
if not el.get("is_static", True):
if not "suffix" in el:
el["suffix"] = None

patch_formats(
{"dynamic_content": dynamic_content_callback},
types=["text", "table"],
)
30 changes: 30 additions & 0 deletions print_designer/patches/introduce_table_alt_row_styles.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import frappe

from print_designer.patches.patch_utils import patch_formats


def execute():
"""Add altStyle object for alternate rows in table elements and in globalStyles of print formats that uses print designer"""
print_formats = frappe.get_all(
"Print Format",
filters={"print_designer": 1},
fields=["name", "print_designer_settings"],
as_list=1,
)
for pf in print_formats:
settings = frappe.parse_json(pf[1])
if settings:
# If globalStyles is not present, skip
if not (gs := settings.get("globalStyles")):
continue

gs["table"]["altStyle"] = {}
frappe.db.set_value("Print Format", pf[0], "print_designer_settings", frappe.as_json(settings))

def element_callback(el):
el["altStyle"] = {}

patch_formats(
{"element": element_callback},
types=["table"],
)
63 changes: 47 additions & 16 deletions print_designer/pdf.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,36 @@
import hashlib
import html
import json

import frappe
from frappe.monitor import add_data_to_monitor
from frappe.utils.error import log_error
from frappe.utils.jinja_globals import is_rtl


def pdf_header_footer_html(soup, head, content, styles, html_id, css):
if soup.find(id="__print_designer"):
return frappe.render_template(
"print_designer/page/print_designer/jinja/header_footer.html",
{
"head": head,
"content": content,
"styles": styles,
"html_id": html_id,
"css": css,
"headerFonts": soup.find(id="headerFontsLinkTag"),
"footerFonts": soup.find(id="footerFontsLinkTag"),
"lang": frappe.local.lang,
"layout_direction": "rtl" if is_rtl() else "ltr",
},
)
try:
return frappe.render_template(
"print_designer/page/print_designer/jinja/header_footer.html",
{
"head": head,
"content": content,
"styles": styles,
"html_id": html_id,
"css": css,
"headerFonts": soup.find(id="headerFontsLinkTag"),
"footerFonts": soup.find(id="footerFontsLinkTag"),
"lang": frappe.local.lang,
"layout_direction": "rtl" if is_rtl() else "ltr",
},
)
except Exception as e:
error = log_error(title=e, reference_doctype="Print Format")
frappe.throw(
msg=f"Something went wrong ( Error ) : If you don't know what just happened, and wish to file a ticket or issue on github, please copy the error from <b>Error Log {error.name}</b> or ask Administrator.",
exc=e,
)
else:
from frappe.utils.pdf import pdf_footer_html, pdf_header_html

Expand All @@ -35,7 +46,11 @@ def pdf_header_footer_html(soup, head, content, styles, html_id, css):

def pdf_body_html(print_format, jenv, args, template):
if print_format and print_format.print_designer and print_format.print_designer_body:
template = jenv.loader.get_source(jenv, "print_designer/page/print_designer/jinja/main.html")[0]
print_format_name = hashlib.md5(print_format.name.encode(), usedforsecurity=False).hexdigest()
add_data_to_monitor(print_designer=print_format_name, print_designer_action="download_pdf")
# DEPRECATED: remove this in few months added for backward compatibility incase user didn't update frappe framework.
if not frappe.get_hooks("get_print_format_template"):
template = jenv.loader.get_source(jenv, "print_designer/page/print_designer/jinja/main.html")[0]
args.update(
{
"headerElement": json.loads(print_format.print_designer_header),
Expand All @@ -49,5 +64,21 @@ def pdf_body_html(print_format, jenv, args, template):
template_source = template.replace(
"<!-- user_generated_jinja_code -->", args["settings"].get("userProvidedJinja", "")
)
template = jenv.from_string(template_source)
try:
template = jenv.from_string(template_source)
return template.render(args, filters={"len": len})

except Exception as e:
error = log_error(title=e, reference_doctype="Print Format", reference_name=print_format.name)
if frappe.conf.developer_mode:
return f"<h1><b>Something went wrong while rendering the print format.</b> <hr/> If you don't know what just happened, and wish to file a ticket or issue on Github <hr /> Please copy the error from <code>Error Log {error.name}</code> or ask Administrator.<hr /><h3>Error rendering print format: {error.reference_name}</h3><h4>{error.method}</h4><pre>{html.escape(error.error)}</pre>"
else:
return f"<h1><b>Something went wrong while rendering the print format.</b> <hr/> If you don't know what just happened, and wish to file a ticket or issue on Github <hr /> Please copy the error from <code>Error Log {error.name}</code> or ask Administrator.</h1>"

return template.render(args, filters={"len": len})


def get_print_format_template(jenv, print_format):
# if print format is created using print designer, then use print designer template
if print_format and print_format.print_designer and print_format.print_designer_body:
return jenv.loader.get_source(jenv, "print_designer/page/print_designer/jinja/main.html")[0]
26 changes: 26 additions & 0 deletions print_designer/print_designer/client_scripts/point_of_sale.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// overrides the print util function that is used in the point of sale page.
// we should ideally change util function in framework to extend it. this is workaround until that.
const original_util = frappe.utils.print;
frappe.utils.print = (doctype, docname, print_format, letterhead, lang_code) => {
if (frappe.model.get_value("Print Format", print_format, "print_designer")) {
let w = window.open(
frappe.urllib.get_full_url(
"/app/print/" +
encodeURIComponent(doctype) +
"/" +
encodeURIComponent(docname) +
"?format=" +
encodeURIComponent(print_format) +
"&no_letterhead=0" +
"&trigger_print=1" +
(lang_code ? "&_lang=" + lang_code : "")
)
);
if (!w) {
frappe.msgprint(__("Please enable pop-ups"));
return;
}
} else {
original_util(doctype, docname, print_format, letterhead, lang_code);
}
};
40 changes: 29 additions & 11 deletions print_designer/print_designer/client_scripts/print.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,10 +104,13 @@ frappe.ui.form.PrintView = class PrintView extends frappe.ui.form.PrintView {
}
async designer_pdf(print_format) {
if (typeof pdfjsLib == "undefined") {
await frappe.require("assets/print_designer/js/pdf.min.js", () => {
pdfjsLib.GlobalWorkerOptions.workerSrc =
frappe.boot.assets_json["pdf.worker.bundle.js"];
});
await frappe.require(
["assets/print_designer/js/pdf.min.js", "pdf.worker.bundle.js"],
() => {
pdfjsLib.GlobalWorkerOptions.workerSrc =
frappe.boot.assets_json["pdf.worker.bundle.js"];
}
);
}
let me = this;
let print_designer_settings = JSON.parse(print_format.print_designer_settings);
Expand Down Expand Up @@ -142,16 +145,26 @@ frappe.ui.form.PrintView = class PrintView extends frappe.ui.form.PrintView {
await renderPage(this.pdfDoc, pageno);
}
this.pdf_download_btn.prop("disabled", false);
if (frappe.route_options.trigger_print) {
this.printit();
}
this.print_btn.prop("disabled", false);
} catch (err) {
console.log(err);
frappe.show_alert(
{
message: "Unable to generate PDF",
indicator: "red",
console.error(err);
frappe.msgprint({
title: __("Unable to generate PDF"),
message: `There was error while generating PDF. Please check the error log for more details.`,
indicator: "red",
primary_action: {
label: "Open Error Log",
action(values) {
frappe.set_route("List", "Error Log", {
doctype: "Error Log",
reference_doctype: "Print Format",
});
},
},
5
);
});
}
/**
* Get page info from document, resize canvas accordingly, and render page.
Expand Down Expand Up @@ -235,6 +248,11 @@ frappe.ui.form.PrintView = class PrintView extends frappe.ui.form.PrintView {
setTimeout(() => {
iframe.focus();
iframe.contentWindow.print();
if (frappe.route_options.trigger_print) {
setTimeout(function () {
window.close();
}, 5000);
}
}, 1);
};
} else {
Expand Down
22 changes: 14 additions & 8 deletions print_designer/print_designer/page/print_designer/jinja/main.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{% macro render_statictext(element, send_to_jinja) -%}
<div style="position: absolute; top:{% if 'printY' in element %}{{ element.printY }}{% else %}{{ element.startY }}{% endif %}px; left:{% if 'printX' in element %}{{ element.printX }}{% else %}{{ element.startX }}{% endif %}px;{% if element.isFixedSize %}width:{{ element.width }}px;height:{{ element.height }}px;{% else %}width:fit-content; height:fit-content; max-width: {{ settings.page.width - settings.page.marginLeft - settings.page.marginRight - element.startX }}px; {%endif%}" class="
<div style="position: absolute; top:{% if 'printY' in element %}{{ element.printY }}{% else %}{{ element.startY }}{% endif %}px; left:{% if 'printX' in element %}{{ element.printX }}{% else %}{{ element.startX }}{% endif %}px;{% if element.isFixedSize %}width:{{ element.width }}px;height:{{ element.height }}px;{% else %}width:fit-content; height:fit-content; max-width: {{ (settings.page.width - settings.page.marginLeft - settings.page.marginRight - element.startX) + 2 }}px; white-space:nowrap; {%endif%}" class="
{{ element.classes | join(' ') }}">
<p style="{% if element.isFixedSize %}width:{{ element.width }}px;height:{{ element.height }}px;{% else %}width:fit-content; height:fit-content; max-width: {{ settings.page.width - settings.page.marginLeft - settings.page.marginRight - element.startX }}px; {%endif%} {{convert_css(element.style)}}"
<p style="{% if element.isFixedSize %}width:{{ element.width }}px;height:{{ element.height }}px;{% else %}width:fit-content; height:fit-content; max-width: {{ (settings.page.width - settings.page.marginLeft - settings.page.marginRight - element.startX ) + 2 }}px; white-space:nowrap;{%endif%} {{convert_css(element.style)}}"
class="staticText {{ element.classes | join(' ') }}">
{% if element.parseJinja %}
<!-- third Arg is row which is not sent outside table -->
Expand All @@ -18,9 +18,9 @@
{% endif %}
{% endmacro %}
{% macro render_dynamictext(element, send_to_jinja) -%}
<div style="position: absolute; top:{% if 'printY' in element %}{{ element.printY }}{% else %}{{ element.startY }}{% endif %}px; left:{% if 'printX' in element %}{{ element.printX }}{% else %}{{ element.startX }}{% endif %}px;{% if element.isFixedSize %}width:{{ element.width }}px;height:{{ element.height }}px;{% else %}width:fit-content; height:fit-content; max-width: {{ settings.page.width - settings.page.marginLeft - settings.page.marginRight - element.startX }}px;{%endif%}" class="
<div style="position: absolute; top:{% if 'printY' in element %}{{ element.printY }}{% else %}{{ element.startY }}{% endif %}px; left:{% if 'printX' in element %}{{ element.printX }}{% else %}{{ element.startX }}{% endif %}px;{% if element.isFixedSize %}width:{{ element.width }}px;height:{{ element.height }}px;{% else %}width:fit-content; height:fit-content; white-space:nowrap; max-width: {{ (settings.page.width - settings.page.marginLeft - settings.page.marginRight - element.startX) + 2 }}px;{%endif%}" class="
{{ element.classes | join(' ') }}">
<div style="{% if element.isFixedSize %}width:{{ element.width }}px;height:{{ element.height }}px;{% else %}width:fit-content; height:fit-content; max-width: {{ settings.page.width - settings.page.marginLeft - settings.page.marginRight - element.startX }}px;{%endif%} {{convert_css(element.style)}}"
<div style="{% if element.isFixedSize %}width:{{ element.width }}px;height:{{ element.height }}px;{% else %}width:fit-content; height:fit-content; white-space:nowrap; max-width: {{ (settings.page.width - settings.page.marginLeft - settings.page.marginRight - element.startX) + 2 }}px;{%endif%} {{convert_css(element.style)}}"
class="dynamicText {{ element.classes | join(' ') }}">
{% for field in element.dynamicContent %}
<!-- third Arg is row which is not sent outside table -->
Expand Down Expand Up @@ -90,7 +90,7 @@
{% if element.columns %}
<tr>
{% for column in element.columns%}
<th style="{% if column.width %}width: {{column.width}}%; max-width: {{column.width}}%;{%endif%} {{convert_css(element.headerStyle)}}border-top-style: solid !important;border-bottom-style: solid !important;{%if loop.first%}border-left-style: solid !important;{%elif loop.last%}border-right-style: solid !important;{%endif%}">
<th style="{% if column.width %}width: {{column.width}}%; max-width: {{column.width}}%;{%endif%} {{convert_css(element.headerStyle)}}border-top-style: solid !important;border-bottom-style: solid !important;{%if loop.first%}border-left-style: solid !important;{%elif loop.last%}border-right-style: solid !important;{%endif%}{%- if column.applyStyleToHeader and column.style -%}{{convert_css(column.style)}}{%- endif -%}">
{{ _(column.label) }}
</th>
{% endfor %}
Expand All @@ -103,7 +103,7 @@
<tr>
{% set isLastRow = loop.last %}
{% for column in element.columns%}
<td style="{{convert_css(element.style)}}{%if isLastRow%}border-bottom-style: solid !important;{%endif%}{%if loop.first%}border-left-style: solid !important;{%elif loop.last%}border-right-style: solid !important;{%endif%}">
<td style="{{convert_css(element.style)}}{%if row.idx % 2 == 0 %}{{convert_css(element.altStyle)}}{%endif%}{%if isLastRow%}border-bottom-style: solid !important;{%endif%}{%if loop.first%}border-left-style: solid !important;{%elif loop.last%}border-right-style: solid !important;{%endif%}{%- if column.style -%}{{convert_css(column.style)}}{%- endif -%}">
{% if column is mapping %}
{% for field in column.dynamicContent%}
{{ render_spantag(field, element, row, send_to_jinja) }}
Expand Down Expand Up @@ -142,14 +142,20 @@
{% set span_value = render_spanvalue(field, element, row, send_to_jinja) %}
<span class="{% if not field.is_static and field.is_labelled %}baseSpanTag{% endif %}">
{% if not field.is_static and field.is_labelled and span_value %}
<span class="{% if row %}printTable{% else %}dynamicText{% endif %} label-text labelSpanTag" style="user-select:auto;{%if element.labelStyle %}{{convert_css(element.labelStyle)}}{%endif%}{%if field.labelStyle %}{{convert_css(field.labelStyle)}}{%endif%}">
<span class="{% if row %}printTable{% else %}dynamicText{% endif %} label-text labelSpanTag" style="user-select:auto; {%if element.labelStyle %}{{convert_css(element.labelStyle)}}{%endif%}{%if field.labelStyle %}{{convert_css(field.labelStyle)}}{%endif%} white-space:nowrap; ">
{{ _(field.label) }}
</span>
{% endif %}
<span class="dynamic-span {% if not field.is_static and field.is_labelled %}valueSpanTag{%endif%} {{page_class(field)}} }}"
style="{{convert_css(field.style)}} user-select:auto;">
style="{%- if element.style.get('color') -%}{{ convert_css({'color': element.style.get('color')})}}{%- endif -%} {{convert_css(field.style)}} user-select:auto;">
{{ span_value }}
</span>
{% if field.suffix and span_value %}
<span class="dynamic-span"
style="{%- if element.style.get('color') -%}{{ convert_css({'color': element.style.get('color')})}}{%- endif -%} {{convert_css(field.style)}} user-select:auto;">
{{ _(field.suffix) }}
</span>
{% endif %}
{% if field.nextLine %}
<br/>
{% endif %}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,8 @@ const set_current_doc = async (format_name) => {
format_name,
"print_designer_settings"
);
if (!settings.message) return;
settings = JSON.parse(settings.message.print_designer_settings || "{}");
if (!settings.message?.print_designer_settings) return;
settings = JSON.parse(settings.message.print_designer_settings);
settings["currentDoc"] = currentDoc;
await frappe.db.set_value(
"Print Format",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ def render_user_text_withdoc(string, doctype, docname=None, row=None, send_to_ji
if not docname or docname == "":
return render_user_text(string=string, doc={}, row=row, send_to_jinja=send_to_jinja)
doc = frappe.get_cached_doc(doctype, docname)
doc.check_permission()
return render_user_text(string=string, doc=doc, row=row, send_to_jinja=send_to_jinja)


Expand Down Expand Up @@ -132,7 +133,7 @@ def convert_css(css_obj):
string_css += (
"".join(["-" + i.lower() if i.isupper() else i for i in item[0]]).lstrip("-")
+ ":"
+ str(item[1])
+ str(item[1] if item[1] != "" or item[0] != "backgroundColor" else "transparent")
+ "!important;"
)
string_css += "user-select: all;"
Expand Down
Loading

0 comments on commit 921cc72

Please sign in to comment.