Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file.
Empty file.
6 changes: 3 additions & 3 deletions di/digital_invoicing/print_format/di_sales_tax_invoice/di_sales_tax_invoice.json
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -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<div class=\"di-print\">\r\n\t<div class=\"di-header\">\r\n\t\t<h2>{{ company.company_name }}</h2>\r\n\t\t<p>{{ di_settings.address or company.get(\"address\") or \"\" }}</p>\r\n\t\t<p><strong>Sales Tax Invoice</strong></p>\r\n\t</div>\r\n\r\n\t<table style=\"margin-bottom:10px;\">\r\n\t\t<tr>\r\n\t\t\t<td style=\"width:50%;border:none;vertical-align:top;padding:0 10px 0 0;\">\r\n\t\t\t\t<table class=\"di-info-table\">\r\n\t\t\t\t\t<tr><td colspan=\"2\" style=\"font-weight:bold;font-size:12px;\">Seller Details</td></tr>\r\n\t\t\t\t\t<tr><td class=\"label-col\">Business Name:</td><td>{{ company.company_name }}</td></tr>\r\n\t\t\t\t\t<tr><td class=\"label-col\">NTN/CNIC:</td><td>{{ di_settings.ntn_cnic or company.get(\"tax_id\") or \"\" }}</td></tr>\r\n\t\t\t\t\t{% if di_settings.strn_no %}<tr><td class=\"label-col\">STRN:</td><td>{{ di_settings.strn_no }}</td></tr>{% endif %}\r\n\t\t\t\t\t<tr><td class=\"label-col\">Province:</td><td>{{ di_settings.province or \"\" }}</td></tr>\r\n\t\t\t\t\t<tr><td class=\"label-col\">Address:</td><td>{{ di_settings.address or \"\" }}</td></tr>\r\n\t\t\t\t</table>\r\n\t\t\t</td>\r\n\t\t\t<td style=\"width:50%;border:none;vertical-align:top;padding:0 0 0 10px;\">\r\n\t\t\t\t<table class=\"di-info-table\">\r\n\t\t\t\t\t<tr><td colspan=\"2\" style=\"font-weight:bold;font-size:12px;\">Buyer Details</td></tr>\r\n\t\t\t\t\t<tr><td class=\"label-col\">Business Name:</td><td>{{ doc.customer_name or \"\" }}</td></tr>\r\n\t\t\t\t\t<tr><td class=\"label-col\">NTN/CNIC:</td><td>{{ customer.ntn_cnic if customer else \"\" }}</td></tr>\r\n\t\t\t\t\t<tr><td class=\"label-col\">Registration:</td><td>{{ customer.registration_type if customer else \"\" }}</td></tr>\r\n\t\t\t\t\t<tr><td class=\"label-col\">Province:</td><td>{{ customer.province if customer else \"\" }}</td></tr>\r\n\t\t\t\t\t<tr><td class=\"label-col\">Address:</td><td>{{ customer.di_address if customer else \"\" }}</td></tr>\r\n\t\t\t\t</table>\r\n\t\t\t</td>\r\n\t\t</tr>\r\n\t</table>\r\n\r\n\t<table class=\"di-info-table\" style=\"margin-bottom:10px;\">\r\n\t\t<tr>\r\n\t\t\t<td class=\"label-col\">Invoice No:</td><td>{{ doc.name }}</td>\r\n\t\t\t<td class=\"label-col\">Date:</td><td>{{ doc.posting_date }}</td>\r\n\t\t\t{% if doc.di_integration_id %}\r\n\t\t\t<td class=\"label-col\">FBR Invoice No:</td><td>{{ doc.di_integration_id }}</td>\r\n\t\t\t{% endif %}\r\n\t\t</tr>\r\n\t</table>\r\n\r\n\t<!-- Items Table -->\r\n\t<table>\r\n\t\t<thead>\r\n\t\t\t<tr>\r\n\t\t\t\t<th style=\"width:30px;\">#</th>\r\n\t\t\t\t<th>HS Code</th>\r\n\t\t\t\t<th>Description</th>\r\n\t\t\t\t<th>Sale Type</th>\r\n\t\t\t\t<th class=\"di-right\">Qty</th>\r\n\t\t\t\t<th>UOM</th>\r\n\t\t\t\t<th class=\"di-right\">Value (Excl. ST)</th>\r\n\t\t\t\t<th class=\"di-right\">ST Rate</th>\r\n\t\t\t\t<th class=\"di-right\">Sales Tax</th>\r\n\t\t\t\t<th class=\"di-right\">Further Tax</th>\r\n\t\t\t\t<th class=\"di-right\">FED</th>\r\n\t\t\t\t<th class=\"di-right\">Total</th>\r\n\t\t\t</tr>\r\n\t\t</thead>\r\n\t\t<tbody>\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<tr>\r\n\t\t\t\t<td>{{ item.idx }}</td>\r\n\t\t\t\t<td>{{ item.di_hs_code or \"\" }}</td>\r\n\t\t\t\t<td>{{ item.item_name }}</td>\r\n\t\t\t\t<td>{{ item.di_sale_type or \"\" }}</td>\r\n\t\t\t\t<td class=\"di-right\">{{ item.qty }}</td>\r\n\t\t\t\t<td>{{ item.di_hs_uom or item.uom or \"\" }}</td>\r\n\t\t\t\t<td class=\"di-right\">{{ frappe.utils.fmt_money(item.net_amount, currency=doc.currency) }}</td>\r\n\t\t\t\t<td class=\"di-right\">{{ st.rate }}%</td>\r\n\t\t\t\t<td class=\"di-right\">{{ frappe.utils.fmt_money(st.amount, currency=doc.currency) }}</td>\r\n\t\t\t\t<td class=\"di-right\">{{ frappe.utils.fmt_money(ft.amount, currency=doc.currency) }}</td>\r\n\t\t\t\t<td class=\"di-right\">{{ frappe.utils.fmt_money(item.di_fed_payable or 0, currency=doc.currency) }}</td>\r\n\t\t\t\t<td class=\"di-right\">{{ frappe.utils.fmt_money(item.amount, currency=doc.currency) }}</td>\r\n\t\t\t</tr>\r\n\t\t\t{% endfor %}\r\n\t\t</tbody>\r\n\t</table>\r\n\r\n\t<!-- Totals -->\r\n\t<table style=\"width:50%;margin-left:auto;margin-top:10px;\">\r\n\t\t<tr class=\"di-totals\">\r\n\t\t\t<td style=\"border:none;\">Net Total:</td>\r\n\t\t\t<td style=\"border:none;\">{{ frappe.utils.fmt_money(doc.net_total, currency=doc.currency) }}</td>\r\n\t\t</tr>\r\n\t\t{% for tax in doc.taxes %}\r\n\t\t<tr class=\"di-totals\">\r\n\t\t\t<td style=\"border:none;\">{{ tax.description }}:</td>\r\n\t\t\t<td style=\"border:none;\">{{ frappe.utils.fmt_money(tax.tax_amount, currency=doc.currency) }}</td>\r\n\t\t</tr>\r\n\t\t{% endfor %}\r\n\t\t<tr class=\"di-totals\" style=\"font-size:13px;\">\r\n\t\t\t<td style=\"border-top:2px solid #333;border-bottom:none;border-left:none;border-right:none;\">Grand Total:</td>\r\n\t\t\t<td style=\"border-top:2px solid #333;border-bottom:none;border-left:none;border-right:none;\">{{ frappe.utils.fmt_money(doc.grand_total, currency=doc.currency) }}</td>\r\n\t\t</tr>\r\n\t</table>\r\n\r\n\t<!-- FBR Section (only if posted) -->\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<div class=\"di-fbr-section\">\r\n\t\t{% if di_qr %}\r\n\t\t<div>\r\n\t\t\t<img src=\"{{ di_qr }}\" class=\"di-qr-code\" alt=\"FBR QR Code\" />\r\n\t\t</div>\r\n\t\t{% endif %}\r\n\t\t<div class=\"di-fbr-info\">\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<img src=\"{{ fbr_logo }}\" style=\"height:30px;margin-bottom:5px;\" alt=\"FBR Logo\" />\r\n\t\t\t{% endif %}\r\n\t\t\t<p><strong>FBR Invoice Number:</strong> {{ doc.di_integration_id }}</p>\r\n\t\t\t<p><strong>Date & Time:</strong> {{ doc.di_posting_datetime }}</p>\r\n\t\t\t<p style=\"font-size:9px;margin-top:5px;\">\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 <strong>https://e.fbr.gov.pk</strong>\r\n\t\t\t</p>\r\n\t\t</div>\r\n\t</div>\r\n\t{% endif %}\r\n</div>\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<div class=\"di-print\">\r\n\t<div class=\"di-header\">\r\n\t\t<h2>{{ company.company_name }}</h2>\r\n\t\t<p>{{ di_settings.address or company.get(\"address\") or \"\" }}</p>\r\n\t\t<p><strong>Sales Tax Invoice</strong></p>\r\n\t</div>\r\n\r\n\t<table style=\"margin-bottom:10px;\">\r\n\t\t<tr>\r\n\t\t\t<td style=\"width:50%;border:none;vertical-align:top;padding:0 10px 0 0;\">\r\n\t\t\t\t<table class=\"di-info-table\">\r\n\t\t\t\t\t<tr><td colspan=\"2\" style=\"font-weight:bold;font-size:12px;\">Seller Details</td></tr>\r\n\t\t\t\t\t<tr><td class=\"label-col\">Business Name:</td><td>{{ company.company_name }}</td></tr>\r\n\t\t\t\t\t<tr><td class=\"label-col\">NTN/CNIC:</td><td>{{ di_settings.ntn_cnic or company.get(\"tax_id\") or \"\" }}</td></tr>\r\n\t\t\t\t\t{% if di_settings.strn_no %}<tr><td class=\"label-col\">STRN:</td><td>{{ di_settings.strn_no }}</td></tr>{% endif %}\r\n\t\t\t\t\t<tr><td class=\"label-col\">Province:</td><td>{{ di_settings.province or \"\" }}</td></tr>\r\n\t\t\t\t\t<tr><td class=\"label-col\">Address:</td><td>{{ di_settings.address or \"\" }}</td></tr>\r\n\t\t\t\t</table>\r\n\t\t\t</td>\r\n\t\t\t<td style=\"width:50%;border:none;vertical-align:top;padding:0 0 0 10px;\">\r\n\t\t\t\t<table class=\"di-info-table\">\r\n\t\t\t\t\t<tr><td colspan=\"2\" style=\"font-weight:bold;font-size:12px;\">Buyer Details</td></tr>\r\n\t\t\t\t\t<tr><td class=\"label-col\">Business Name:</td><td>{{ doc.customer_name or \"\" }}</td></tr>\r\n\t\t\t\t\t<tr><td class=\"label-col\">NTN/CNIC:</td><td>{{ customer.ntn_cnic if customer else \"\" }}</td></tr>\r\n\t\t\t\t\t<tr><td class=\"label-col\">Registration:</td><td>{{ customer.registration_type if customer else \"\" }}</td></tr>\r\n\t\t\t\t\t<tr><td class=\"label-col\">Province:</td><td>{{ customer.province if customer else \"\" }}</td></tr>\r\n\t\t\t\t\t<tr><td class=\"label-col\">Address:</td><td>{{ customer.di_address if customer else \"\" }}</td></tr>\r\n\t\t\t\t</table>\r\n\t\t\t</td>\r\n\t\t</tr>\r\n\t</table>\r\n\r\n\t<table class=\"di-info-table\" style=\"margin-bottom:10px;\">\r\n\t\t<tr>\r\n\t\t\t<td class=\"label-col\">Invoice No:</td><td>{{ doc.name }}</td>\r\n\t\t\t<td class=\"label-col\">Date:</td><td>{{ doc.posting_date }}</td>\r\n\t\t\t{% if doc.di_integration_id %}\r\n\t\t\t<td class=\"label-col\">FBR Invoice No:</td><td>{{ doc.di_integration_id }}</td>\r\n\t\t\t{% endif %}\r\n\t\t</tr>\r\n\t</table>\r\n\r\n\t<!-- Items Table -->\r\n\t<table>\r\n\t\t<thead>\r\n\t\t\t<tr>\r\n\t\t\t\t<th style=\"width:30px;\">#</th>\r\n\t\t\t\t<th>HS Code</th>\r\n\t\t\t\t<th>Description</th>\r\n\t\t\t\t<th>Sale Type</th>\r\n\t\t\t\t<th class=\"di-right\">Qty</th>\r\n\t\t\t\t<th>UOM</th>\r\n\t\t\t\t<th class=\"di-right\">Value (Excl. ST)</th>\r\n\t\t\t\t<th class=\"di-right\">ST Rate</th>\r\n\t\t\t\t<th class=\"di-right\">Sales Tax</th>\r\n\t\t\t\t<th class=\"di-right\">Further Tax</th>\r\n\t\t\t\t<th class=\"di-right\">FED</th>\r\n\t\t\t\t<th class=\"di-right\">Total</th>\r\n\t\t\t</tr>\r\n\t\t</thead>\r\n\t\t<tbody>\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<tr>\r\n\t\t\t\t<td>{{ item.idx }}</td>\r\n\t\t\t\t<td>{{ item.di_hs_code or \"\" }}</td>\r\n\t\t\t\t<td>{{ item.item_name }}</td>\r\n\t\t\t\t<td>{{ item.di_sale_type or \"\" }}</td>\r\n\t\t\t\t<td class=\"di-right\">{{ item.qty }}</td>\r\n\t\t\t\t<td>{{ item.di_hs_uom or item.uom or \"\" }}</td>\r\n\t\t\t\t<td class=\"di-right\">{{ frappe.utils.fmt_money(item.net_amount, currency=doc.currency) }}</td>\r\n\t\t\t\t<td class=\"di-right\">{{ st.rate }}%</td>\r\n\t\t\t\t<td class=\"di-right\">{{ frappe.utils.fmt_money(st.amount, currency=doc.currency) }}</td>\r\n\t\t\t\t<td class=\"di-right\">{{ frappe.utils.fmt_money(ft.amount, currency=doc.currency) }}</td>\r\n\t\t\t\t<td class=\"di-right\">{{ frappe.utils.fmt_money(item.di_fed_payable or 0, currency=doc.currency) }}</td>\r\n\t\t\t\t<td class=\"di-right\">{{ frappe.utils.fmt_money(item.amount, currency=doc.currency) }}</td>\r\n\t\t\t</tr>\r\n\t\t\t{% endfor %}\r\n\t\t</tbody>\r\n\t</table>\r\n\r\n\t<!-- Totals -->\r\n\t<table style=\"width:50%;margin-left:auto;margin-top:10px;\">\r\n\t\t<tr class=\"di-totals\">\r\n\t\t\t<td style=\"border:none;\">Net Total:</td>\r\n\t\t\t<td style=\"border:none;\">{{ frappe.utils.fmt_money(doc.net_total, currency=doc.currency) }}</td>\r\n\t\t</tr>\r\n\t\t{% for tax in doc.taxes %}\r\n\t\t<tr class=\"di-totals\">\r\n\t\t\t<td style=\"border:none;\">{{ tax.description }}:</td>\r\n\t\t\t<td style=\"border:none;\">{{ frappe.utils.fmt_money(tax.tax_amount, currency=doc.currency) }}</td>\r\n\t\t</tr>\r\n\t\t{% endfor %}\r\n\t\t<tr class=\"di-totals\" style=\"font-size:13px;\">\r\n\t\t\t<td style=\"border-top:2px solid #333;border-bottom:none;border-left:none;border-right:none;\">Grand Total:</td>\r\n\t\t\t<td style=\"border-top:2px solid #333;border-bottom:none;border-left:none;border-right:none;\">{{ frappe.utils.fmt_money(doc.grand_total, currency=doc.currency) }}</td>\r\n\t\t</tr>\r\n\t</table>\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<div class=\"di-fbr-section\">\r\n\t\t{% if di_qr %}\r\n\t\t<div>\r\n\t\t\t<img src=\"{{ di_qr }}\" class=\"di-qr-code\" alt=\"FBR QR Code\" />\r\n\t\t</div>\r\n\t\t{% endif %}\r\n\t\t<div class=\"di-fbr-info\">\r\n\t\t\t<img src=\"/assets/di/images/fbrlogo.png\" style=\"height:30px;margin-bottom:5px;\" alt=\"FBR Logo\" />\r\n\t\t\t<p><strong>FBR Invoice Number:</strong> {{ doc.di_integration_id }}</p>\r\n\t\t\t<p><strong>Date & Time:</strong> {{ doc.di_posting_datetime }}</p>\r\n\t\t\t<p style=\"font-size:9px;margin-top:5px;\">\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 <strong>https://e.fbr.gov.pk</strong>\r\n\t\t\t</p>\r\n\t\t</div>\r\n\t</div>\r\n\t{% endif %}\r\n</div>\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",
Expand All @@ -30,4 +30,4 @@
"raw_printing": 0,
"show_section_headings": 0,
"standard": "Yes"
}
}
1 change: 0 additions & 1 deletion di/hooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,6 @@
jinja = {
"methods": [
"di.integrations.qr_code.generate_qr_code",
"di.integrations.qr_code.get_fbr_logo_data_uri",
]
}

Expand Down
23 changes: 0 additions & 23 deletions di/integrations/qr_code.py
Original file line number Diff line number Diff line change
Expand Up @@ -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}"
Binary file added di/public/images/fbrlogo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading