From 9934cebe02c79d1eeb69fca9f5ba17520ffc0a78 Mon Sep 17 00:00:00 2001 From: Ali Raza Date: Mon, 8 Jun 2026 21:40:54 +0500 Subject: [PATCH] feat: add fbr logo image and remove unused logo retrieval function --- di/digital_invoicing/print_format/__init__.py | 0 .../di_sales_tax_invoice/__init__.py | 0 .../di_sales_tax_invoice.json | 6 ++--- di/hooks.py | 1 - di/integrations/qr_code.py | 23 ------------------ di/public/images/fbrlogo.png | Bin 0 -> 2070 bytes 6 files changed, 3 insertions(+), 27 deletions(-) create mode 100755 di/digital_invoicing/print_format/__init__.py mode change 100644 => 100755 di/digital_invoicing/print_format/di_sales_tax_invoice/__init__.py mode change 100644 => 100755 di/digital_invoicing/print_format/di_sales_tax_invoice/di_sales_tax_invoice.json create mode 100755 di/public/images/fbrlogo.png diff --git a/di/digital_invoicing/print_format/__init__.py b/di/digital_invoicing/print_format/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/di/digital_invoicing/print_format/di_sales_tax_invoice/__init__.py b/di/digital_invoicing/print_format/di_sales_tax_invoice/__init__.py old mode 100644 new mode 100755 diff --git a/di/digital_invoicing/print_format/di_sales_tax_invoice/di_sales_tax_invoice.json b/di/digital_invoicing/print_format/di_sales_tax_invoice/di_sales_tax_invoice.json old mode 100644 new mode 100755 index ab6fc88..957d430 --- a/di/digital_invoicing/print_format/di_sales_tax_invoice/di_sales_tax_invoice.json +++ b/di/digital_invoicing/print_format/di_sales_tax_invoice/di_sales_tax_invoice.json @@ -10,14 +10,14 @@ "docstatus": 0, "doctype": "Print Format", "font_size": 0, - "html": "{% set company = frappe.get_doc(\"Company\", doc.company) %}\r\n{% set di_settings = frappe.db.get_value(\"DI Settings\", {\"company\": doc.company}, [\"ntn_cnic\", \"strn_no\", \"province\", \"address\"], as_dict=1) %}\r\n{% set customer = frappe.get_doc(\"Customer\", doc.customer) if doc.customer else None %}\r\n\r\n
\r\n\t
\r\n\t\t

{{ company.company_name }}

\r\n\t\t

{{ di_settings.address or company.get(\"address\") or \"\" }}

\r\n\t\t

Sales Tax Invoice

\r\n\t
\r\n\r\n\t\r\n\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\r\n\t
\r\n\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t{% if di_settings.strn_no %}{% endif %}\r\n\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t
Seller Details
Business Name:{{ company.company_name }}
NTN/CNIC:{{ di_settings.ntn_cnic or company.get(\"tax_id\") or \"\" }}
STRN:{{ di_settings.strn_no }}
Province:{{ di_settings.province or \"\" }}
Address:{{ di_settings.address or \"\" }}
\r\n\t\t\t
\r\n\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t
Buyer Details
Business Name:{{ doc.customer_name or \"\" }}
NTN/CNIC:{{ customer.ntn_cnic if customer else \"\" }}
Registration:{{ customer.registration_type if customer else \"\" }}
Province:{{ customer.province if customer else \"\" }}
Address:{{ customer.di_address if customer else \"\" }}
\r\n\t\t\t
\r\n\r\n\t\r\n\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t{% if doc.di_integration_id %}\r\n\t\t\t\r\n\t\t\t{% endif %}\r\n\t\t\r\n\t
Invoice No:{{ doc.name }}Date:{{ doc.posting_date }}FBR Invoice No:{{ doc.di_integration_id }}
\r\n\r\n\t\r\n\t\r\n\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\r\n\t\t\r\n\t\t\t{% for item in doc.items %}\r\n\t\t\t{% set st = namespace(rate=0, amount=0, found=false) %}\r\n\t\t\t{% set ft = namespace(amount=0) %}\r\n\t\t\t{% for tax in doc.taxes %}\r\n\t\t\t\t{% set item_tax = json.loads(tax.item_wise_tax_detail or \"{}\").get(item.item_code) %}\r\n\t\t\t\t{% if item_tax is iterable and item_tax is not string %}\r\n\t\t\t\t\t{% if tax.di_tax_type == \"Further Tax\" %}\r\n\t\t\t\t\t\t{% set ft.amount = item_tax[1] if item_tax|length > 1 else 0 %}\r\n\t\t\t\t\t{% elif tax.di_tax_type == \"Sales Tax\" %}\r\n\t\t\t\t\t\t{% set st.rate = item_tax[0] if item_tax|length > 0 else 0 %}\r\n\t\t\t\t\t\t{% set st.amount = item_tax[1] if item_tax|length > 1 else 0 %}\r\n\t\t\t\t\t\t{% set st.found = true %}\r\n\t\t\t\t\t{% endif %}\r\n\t\t\t\t{% endif %}\r\n\t\t\t{% endfor %}\r\n\t\t\t{% if not st.found and doc.taxes %}\r\n\t\t\t\t{% set fallback = json.loads(doc.taxes[0].item_wise_tax_detail or \"{}\").get(item.item_code) %}\r\n\t\t\t\t{% if fallback is iterable and fallback is not string %}\r\n\t\t\t\t\t{% set st.rate = fallback[0] if fallback|length > 0 else 0 %}\r\n\t\t\t\t\t{% set st.amount = fallback[1] if fallback|length > 1 else 0 %}\r\n\t\t\t\t{% endif %}\r\n\t\t\t{% endif %}\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t{% endfor %}\r\n\t\t\r\n\t
#HS CodeDescriptionSale TypeQtyUOMValue (Excl. ST)ST RateSales TaxFurther TaxFEDTotal
{{ item.idx }}{{ item.di_hs_code or \"\" }}{{ item.item_name }}{{ item.di_sale_type or \"\" }}{{ item.qty }}{{ item.di_hs_uom or item.uom or \"\" }}{{ frappe.utils.fmt_money(item.net_amount, currency=doc.currency) }}{{ st.rate }}%{{ frappe.utils.fmt_money(st.amount, currency=doc.currency) }}{{ frappe.utils.fmt_money(ft.amount, currency=doc.currency) }}{{ frappe.utils.fmt_money(item.di_fed_payable or 0, currency=doc.currency) }}{{ frappe.utils.fmt_money(item.amount, currency=doc.currency) }}
\r\n\r\n\t\r\n\t\r\n\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\r\n\t\t{% for tax in doc.taxes %}\r\n\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\r\n\t\t{% endfor %}\r\n\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\r\n\t
Net Total:{{ frappe.utils.fmt_money(doc.net_total, currency=doc.currency) }}
{{ tax.description }}:{{ frappe.utils.fmt_money(tax.tax_amount, currency=doc.currency) }}
Grand Total:{{ frappe.utils.fmt_money(doc.grand_total, currency=doc.currency) }}
\r\n\r\n\t\r\n\t{% if doc.is_di_posted and doc.di_integration_id %}\r\n\t{% set di_qr = generate_qr_code(doc.di_integration_id) %}\r\n\t
\r\n\t\t{% if di_qr %}\r\n\t\t
\r\n\t\t\t\"FBR\r\n\t\t
\r\n\t\t{% endif %}\r\n\t\t
\r\n\t\t\t{% set fbr_logo = get_fbr_logo_data_uri() %}\r\n\t\t\t{% if fbr_logo %}\r\n\t\t\t\"FBR\r\n\t\t\t{% endif %}\r\n\t\t\t

FBR Invoice Number: {{ doc.di_integration_id }}

\r\n\t\t\t

Date & Time: {{ doc.di_posting_datetime }}

\r\n\t\t\t

\r\n\t\t\t\tThis invoice has been reported to FBR through Digital Invoicing System.\r\n\t\t\t\tVerify this invoice at https://e.fbr.gov.pk\r\n\t\t\t

\r\n\t\t
\r\n\t
\r\n\t{% endif %}\r\n
\r\n", + "html": "{% set company = frappe.get_doc(\"Company\", doc.company) %}\r\n{% set di_settings = frappe.db.get_value(\"DI Settings\", {\"company\": doc.company}, [\"ntn_cnic\", \"strn_no\", \"province\", \"address\"], as_dict=1) %}\r\n{% set customer = frappe.get_doc(\"Customer\", doc.customer) if doc.customer else None %}\r\n\r\n
\r\n\t
\r\n\t\t

{{ company.company_name }}

\r\n\t\t

{{ di_settings.address or company.get(\"address\") or \"\" }}

\r\n\t\t

Sales Tax Invoice

\r\n\t
\r\n\r\n\t\r\n\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\r\n\t
\r\n\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t{% if di_settings.strn_no %}{% endif %}\r\n\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t
Seller Details
Business Name:{{ company.company_name }}
NTN/CNIC:{{ di_settings.ntn_cnic or company.get(\"tax_id\") or \"\" }}
STRN:{{ di_settings.strn_no }}
Province:{{ di_settings.province or \"\" }}
Address:{{ di_settings.address or \"\" }}
\r\n\t\t\t
\r\n\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t
Buyer Details
Business Name:{{ doc.customer_name or \"\" }}
NTN/CNIC:{{ customer.ntn_cnic if customer else \"\" }}
Registration:{{ customer.registration_type if customer else \"\" }}
Province:{{ customer.province if customer else \"\" }}
Address:{{ customer.di_address if customer else \"\" }}
\r\n\t\t\t
\r\n\r\n\t\r\n\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t{% if doc.di_integration_id %}\r\n\t\t\t\r\n\t\t\t{% endif %}\r\n\t\t\r\n\t
Invoice No:{{ doc.name }}Date:{{ doc.posting_date }}FBR Invoice No:{{ doc.di_integration_id }}
\r\n\r\n\t\r\n\t\r\n\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\r\n\t\t\r\n\t\t\t{% for item in doc.items %}\r\n\t\t\t{% set st = namespace(rate=0, amount=0, found=false) %}\r\n\t\t\t{% set ft = namespace(amount=0) %}\r\n\t\t\t{% for tax in doc.taxes %}\r\n\t\t\t\t{% set item_tax = json.loads(tax.item_wise_tax_detail or \"{}\").get(item.item_code) %}\r\n\t\t\t\t{% if item_tax is iterable and item_tax is not string %}\r\n\t\t\t\t\t{% if tax.di_tax_type == \"Further Tax\" %}\r\n\t\t\t\t\t\t{% set ft.amount = item_tax[1] if item_tax|length > 1 else 0 %}\r\n\t\t\t\t\t{% elif tax.di_tax_type == \"Sales Tax\" %}\r\n\t\t\t\t\t\t{% set st.rate = item_tax[0] if item_tax|length > 0 else 0 %}\r\n\t\t\t\t\t\t{% set st.amount = item_tax[1] if item_tax|length > 1 else 0 %}\r\n\t\t\t\t\t\t{% set st.found = true %}\r\n\t\t\t\t\t{% endif %}\r\n\t\t\t\t{% endif %}\r\n\t\t\t{% endfor %}\r\n\t\t\t{% if not st.found and doc.taxes %}\r\n\t\t\t\t{% set fallback = json.loads(doc.taxes[0].item_wise_tax_detail or \"{}\").get(item.item_code) %}\r\n\t\t\t\t{% if fallback is iterable and fallback is not string %}\r\n\t\t\t\t\t{% set st.rate = fallback[0] if fallback|length > 0 else 0 %}\r\n\t\t\t\t\t{% set st.amount = fallback[1] if fallback|length > 1 else 0 %}\r\n\t\t\t\t{% endif %}\r\n\t\t\t{% endif %}\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t{% endfor %}\r\n\t\t\r\n\t
#HS CodeDescriptionSale TypeQtyUOMValue (Excl. ST)ST RateSales TaxFurther TaxFEDTotal
{{ item.idx }}{{ item.di_hs_code or \"\" }}{{ item.item_name }}{{ item.di_sale_type or \"\" }}{{ item.qty }}{{ item.di_hs_uom or item.uom or \"\" }}{{ frappe.utils.fmt_money(item.net_amount, currency=doc.currency) }}{{ st.rate }}%{{ frappe.utils.fmt_money(st.amount, currency=doc.currency) }}{{ frappe.utils.fmt_money(ft.amount, currency=doc.currency) }}{{ frappe.utils.fmt_money(item.di_fed_payable or 0, currency=doc.currency) }}{{ frappe.utils.fmt_money(item.amount, currency=doc.currency) }}
\r\n\r\n\t\r\n\t\r\n\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\r\n\t\t{% for tax in doc.taxes %}\r\n\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\r\n\t\t{% endfor %}\r\n\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\r\n\t
Net Total:{{ frappe.utils.fmt_money(doc.net_total, currency=doc.currency) }}
{{ tax.description }}:{{ frappe.utils.fmt_money(tax.tax_amount, currency=doc.currency) }}
Grand Total:{{ frappe.utils.fmt_money(doc.grand_total, currency=doc.currency) }}
\r\n\t\r\n\t{% if doc.is_di_posted and doc.di_integration_id %}\r\n\t{% set di_qr = generate_qr_code(doc.di_integration_id) %}\r\n\t
\r\n\t\t{% if di_qr %}\r\n\t\t
\r\n\t\t\t\"FBR\r\n\t\t
\r\n\t\t{% endif %}\r\n\t\t
\r\n\t\t\t\"FBR\r\n\t\t\t

FBR Invoice Number: {{ doc.di_integration_id }}

\r\n\t\t\t

Date & Time: {{ doc.di_posting_datetime }}

\r\n\t\t\t

\r\n\t\t\t\tThis invoice has been reported to FBR through Digital Invoicing System.\r\n\t\t\t\tVerify this invoice at https://e.fbr.gov.pk\r\n\t\t\t

\r\n\t\t
\r\n\t
\r\n\t{% endif %}\r\n
\r\n", "idx": 0, "line_breaks": 0, "margin_bottom": 0.0, "margin_left": 0.0, "margin_right": 0.0, "margin_top": 0.0, - "modified": "2026-06-08 12:56:25.394656", + "modified": "2026-06-08 21:39:53.332233", "modified_by": "Administrator", "module": "Digital Invoicing", "name": "DI Sales Tax Invoice", @@ -30,4 +30,4 @@ "raw_printing": 0, "show_section_headings": 0, "standard": "Yes" -} \ No newline at end of file +} diff --git a/di/hooks.py b/di/hooks.py index 6aecc3d..8dfeba7 100755 --- a/di/hooks.py +++ b/di/hooks.py @@ -81,7 +81,6 @@ jinja = { "methods": [ "di.integrations.qr_code.generate_qr_code", - "di.integrations.qr_code.get_fbr_logo_data_uri", ] } diff --git a/di/integrations/qr_code.py b/di/integrations/qr_code.py index 1ce93e4..8526909 100755 --- a/di/integrations/qr_code.py +++ b/di/integrations/qr_code.py @@ -42,26 +42,3 @@ def generate_qr_code(invoice_number): encoded = base64.b64encode(buffer.getvalue()).decode("utf-8") return f"data:image/png;base64,{encoded}" - - -def get_fbr_logo_data_uri(): - """Return the FBR DI logo as a base64 data URI. - - Looks for the logo file in the app's public directory. - """ - import os - - logo_path = os.path.join( - os.path.dirname(os.path.dirname(__file__)), - "public", - "images", - "fbr_di_logo.png", - ) - - if not os.path.exists(logo_path): - return "" - - with open(logo_path, "rb") as f: - encoded = base64.b64encode(f.read()).decode("utf-8") - - return f"data:image/png;base64,{encoded}" diff --git a/di/public/images/fbrlogo.png b/di/public/images/fbrlogo.png new file mode 100755 index 0000000000000000000000000000000000000000..1b7d4cca19c08e5638490b762289794f168a199c GIT binary patch literal 2070 zcmV+x2-00apDOOv0o&;Sx801qDkBSp5$;1X7x01FtNx6}X!4@GgRk+IRS!P(^L z@!H_)B3++#lf3{70`$2f0Tu=L`TGb4000C42T>LaQ=2YlrSS9jJT(dB!zlO8D)ql5 z1TG8*P85KsDCycS`rk15*)I6fEAz4;31AupI1dIu5daSZ07Qj#oy99A2Ou5h!7<3>)gd$pv zB6*o3o1!GSsUtFeA-cpY0U8Evmn4#;C9bU|;k6{uwk6T3Aenj=EF=a1G-t=WL94D# zou*ZgpId#DV*nU204r2XfwfzPwuPU<_q`l`000KDNklYO+7s0@U21cULB^*BGX&A<{cdw#_d|#B)qEi@@l_tiIN2wax(-)$eZCtJ4NM?auHzyF9;m|KVfp z#f#d(hxZrfmuGx>f9GU6&OBkr&YyjHzPY)%wYAmjwcAIX8p5k}j@s>B4@SbI=bxUP zGmQ0#qFps+WzLth156w{`F0*c5?$C!gDsR zl4d)V)d+|EX}#)=sn@qgr(@iDhnDK@@pf0r+SpBwtt$3uLpmGLQ53Cv`}@A6)%u1w znPzs9fxBXx-`@^w_8NN4XhS^X<+p$=yZiuY#GlMpOmjo$-5X~o!+Y*w*q*z)&9pWi z+^UNo@20I8uneh+WJg3M@JkksPG`~ICi&4=N+_{J`pEMrWO?#wnD z^t(=q_t)P%Kp>v!nTCFdyxDd667$k3{CNNT%L4@CWf|+c{fK;`yICSmS>6|DX{L^5 z%E?S|W~#B4z&n{q8J=^;G8c*`jfgZrmKaTfc`u7U2N1Q4(igd?oYZVoJh!Ag@CLq&IhF8ozKoVic$PflMDZeQYQxKG zyq_Mg)oR)D@=D+_QXH?T4xZ%I9kkTJ<8RNfmSW-!m}kjjJ^~(n5n^Te3Pr#h42ty8 zmUDoIdmxFH;z{Tvg(BcF5(Y_5l4VppF(BG0j)5oI*LZO*Z~0ZiN*Ax}w{J7aIWsaI z^R5;f&y?6__;O}+JpajgOuURQngp9na4{<0y%&g#r;0RQ9BI5b(s*&C@!}|G*Ff78 zeu5`E=b=T{cXU3^yN4E>$D~^ajjp(s0KU$1Zpt12`IO1~u!(LN)P(8oNyG5ms=25f zSR{Dp09^zWuT1gK`Fue6&<2I_*x1+u`2l9RP$&TS1FaO0P-JU7ynD_?$OU;fgkYQi zAb6}FNz+h+&`$=2ik2Hqx}Zes9Dqo87V%7xccTegnRi2ZlC*@pvgl=6WblwmD5*)^ zXv*-M%$dTdc+P+!h^Afi@GJ(8k}p+&gV*F=Xh@Htrw6B*W%{Lv06buhj8`HM&e--` z0jtS#91b2T1Mwb(_bvAT^+5ijJ9(SMbEk%BXCmRDVeEL$=J0GF^B&@bcojOq-P9bu zsW82-!`Ofudu1d#daMX|52P(*b)lVGlH$SonX$)KVqqf{FUIL|U*{qRni23|S%QbJ zYVdf6&mP_qaPeTeh-b6QA-;vj9~CSI;DJbZW!w#x(`C-WfM-6kOvslQJd}i8MMfqD zvspagLi+J?rD%ASJ87waY(&-MKN!}bvkM8%baKQBNU`%0|8+%xbxVJLV z@aS*+p+9