From f70d757b82ecafc69552a92b1e884546c89b409f Mon Sep 17 00:00:00 2001 From: s-aga-r Date: Sat, 14 Jan 2023 21:08:52 +0530 Subject: [PATCH 01/13] fix: zero rm-cost in SCR --- .../doctype/subcontracting_receipt/subcontracting_receipt.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py index 7e1915bb71..e8faa4868f 100644 --- a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py +++ b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py @@ -63,6 +63,11 @@ class SubcontractingReceipt(SubcontractingController): self.set_items_expense_account() def validate(self): + if ( + frappe.db.get_single_value("Buying Settings", "backflush_raw_materials_of_subcontract_based_on") + == "BOM" + ): + self.supplied_items = [] super(SubcontractingReceipt, self).validate() self.set_missing_values() self.validate_posting_time() From 906ad10d16d2d154cb230b0b0f3fab3d12a35701 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Sun, 15 Jan 2023 17:32:57 +0530 Subject: [PATCH 02/13] fix: Return against internal purchase invoice (#33635) --- erpnext/controllers/accounts_controller.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index 788dc4982e..6fa44c93c2 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -394,7 +394,7 @@ class AccountsController(TransactionBase): self.get("inter_company_reference") or self.get("inter_company_invoice_reference") or self.get("inter_company_order_reference") - ): + ) and not self.get("is_return"): msg = _("Internal Sale or Delivery Reference missing.") msg += _("Please create purchase from internal sale or delivery document itself") frappe.throw(msg, title=_("Internal Sales Reference Missing")) From 67cf7e1728627069e94727faffe8e388955a4a6c Mon Sep 17 00:00:00 2001 From: Raffael Meyer <14891507+barredterra@users.noreply.github.com> Date: Sun, 15 Jan 2023 13:04:16 +0100 Subject: [PATCH 03/13] refactor: use DocStatus (#33594) --- .../doctype/repost_payment_ledger/repost_payment_ledger.py | 2 +- erpnext/controllers/sales_and_purchase_return.py | 2 +- erpnext/controllers/taxes_and_totals.py | 7 ++++--- erpnext/selling/doctype/sales_order/sales_order.py | 2 +- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/erpnext/accounts/doctype/repost_payment_ledger/repost_payment_ledger.py b/erpnext/accounts/doctype/repost_payment_ledger/repost_payment_ledger.py index 9f6828fb73..7fab62c9ec 100644 --- a/erpnext/accounts/doctype/repost_payment_ledger/repost_payment_ledger.py +++ b/erpnext/accounts/doctype/repost_payment_ledger/repost_payment_ledger.py @@ -27,7 +27,7 @@ def start_payment_ledger_repost(docname=None): """ if docname: repost_doc = frappe.get_doc("Repost Payment Ledger", docname) - if repost_doc.docstatus == 1 and repost_doc.repost_status in ["Queued", "Failed"]: + if repost_doc.docstatus.is_submitted() and repost_doc.repost_status in ["Queued", "Failed"]: try: for entry in repost_doc.repost_vouchers: doc = frappe.get_doc(entry.voucher_type, entry.voucher_no) diff --git a/erpnext/controllers/sales_and_purchase_return.py b/erpnext/controllers/sales_and_purchase_return.py index 15c82af856..8bd09982bf 100644 --- a/erpnext/controllers/sales_and_purchase_return.py +++ b/erpnext/controllers/sales_and_purchase_return.py @@ -37,7 +37,7 @@ def validate_return_against(doc): if ( ref_doc.company == doc.company and ref_doc.get(party_type) == doc.get(party_type) - and ref_doc.docstatus == 1 + and ref_doc.docstatus.is_submitted() ): # validate posting date time return_posting_datetime = "%s %s" % (doc.posting_date, doc.get("posting_time") or "00:00:00") diff --git a/erpnext/controllers/taxes_and_totals.py b/erpnext/controllers/taxes_and_totals.py index c6a634ba80..8c403aa9bf 100644 --- a/erpnext/controllers/taxes_and_totals.py +++ b/erpnext/controllers/taxes_and_totals.py @@ -6,6 +6,7 @@ import json import frappe from frappe import _, scrub +from frappe.model.document import Document from frappe.utils import cint, flt, round_based_on_smallest_currency_fraction import erpnext @@ -20,7 +21,7 @@ from erpnext.stock.get_item_details import _get_item_tax_template class calculate_taxes_and_totals(object): - def __init__(self, doc): + def __init__(self, doc: Document): self.doc = doc frappe.flags.round_off_applicable_accounts = [] get_round_off_applicable_accounts(self.doc.company, frappe.flags.round_off_applicable_accounts) @@ -677,7 +678,7 @@ class calculate_taxes_and_totals(object): ) def calculate_total_advance(self): - if self.doc.docstatus < 2: + if not self.doc.docstatus.is_cancelled(): total_allocated_amount = sum( flt(adv.allocated_amount, adv.precision("allocated_amount")) for adv in self.doc.get("advances") @@ -708,7 +709,7 @@ class calculate_taxes_and_totals(object): ) ) - if self.doc.docstatus == 0: + if self.doc.docstatus.is_draft(): if self.doc.get("write_off_outstanding_amount_automatically"): self.doc.write_off_amount = 0 diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py index 7c0601e3dd..accf5f22a6 100755 --- a/erpnext/selling/doctype/sales_order/sales_order.py +++ b/erpnext/selling/doctype/sales_order/sales_order.py @@ -208,7 +208,7 @@ class SalesOrder(SellingController): for quotation in set(d.prevdoc_docname for d in self.get("items")): if quotation: doc = frappe.get_doc("Quotation", quotation) - if doc.docstatus == 2: + if doc.docstatus.is_cancelled(): frappe.throw(_("Quotation {0} is cancelled").format(quotation)) doc.set_status(update=True) From 11cf694d9a1833758788d87baf70db35a87c2f08 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Sat, 14 Jan 2023 12:22:22 +0530 Subject: [PATCH 04/13] perf: improve reconciliation speed on JE's with 1000's of rows 1. No need to keep old PLE's on reconciliation. 2. Added Validation to catch debit-credit mismatch on JE's 3. Only update outstanding amount for newly reconciled invoices --- erpnext/accounts/utils.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py index 445dcc53c6..a03de9e194 100644 --- a/erpnext/accounts/utils.py +++ b/erpnext/accounts/utils.py @@ -439,8 +439,7 @@ def reconcile_against_document(args): # nosemgrep # cancel advance entry doc = frappe.get_doc(voucher_type, voucher_no) frappe.flags.ignore_party_validation = True - gl_map = doc.build_gl_map() - create_payment_ledger_entry(gl_map, cancel=1, adv_adj=1) + _delete_pl_entries(voucher_type, voucher_no) for entry in entries: check_if_advance_entry_modified(entry) @@ -452,11 +451,23 @@ def reconcile_against_document(args): # nosemgrep else: update_reference_in_payment_entry(entry, doc, do_not_save=True) + if doc.doctype == "Journal Entry": + try: + doc.validate_total_debit_and_credit() + except Exception as validation_exception: + raise frappe.ValidationError(_(f"Validation Error for {doc.name}")) from validation_exception + doc.save(ignore_permissions=True) # re-submit advance entry doc = frappe.get_doc(entry.voucher_type, entry.voucher_no) gl_map = doc.build_gl_map() - create_payment_ledger_entry(gl_map, cancel=0, adv_adj=1) + create_payment_ledger_entry(gl_map, update_outstanding="No", cancel=0, adv_adj=1) + + # Only update outstanding for newly linked vouchers + for entry in entries: + update_voucher_outstanding( + entry.against_voucher_type, entry.against_voucher, entry.account, entry.party_type, entry.party + ) frappe.flags.ignore_party_validation = False From 828eaf09301d84ebf78afb69e620c8d38a51e036 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Sun, 15 Jan 2023 18:09:51 +0530 Subject: [PATCH 05/13] fix: minor filter issue while reconciliation tool from bench console --- .../doctype/payment_reconciliation/payment_reconciliation.py | 1 + 1 file changed, 1 insertion(+) diff --git a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py index ac033f7db6..13712cee01 100644 --- a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py +++ b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py @@ -471,6 +471,7 @@ class PaymentReconciliation(Document): def build_qb_filter_conditions(self, get_invoices=False, get_return_invoices=False): self.common_filter_conditions.clear() + self.accounting_dimension_filter_conditions.clear() self.ple_posting_date_filter.clear() ple = qb.DocType("Payment Ledger Entry") From 2c50f43cdd6c185e0a5474e9a73ab6d3e404d765 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Sun, 15 Jan 2023 20:51:54 +0530 Subject: [PATCH 06/13] fix: attribute error while submitting Repost PLE --- .../repost_payment_ledger/repost_payment_ledger.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/erpnext/accounts/doctype/repost_payment_ledger/repost_payment_ledger.py b/erpnext/accounts/doctype/repost_payment_ledger/repost_payment_ledger.py index 9f6828fb73..eb8633dd3b 100644 --- a/erpnext/accounts/doctype/repost_payment_ledger/repost_payment_ledger.py +++ b/erpnext/accounts/doctype/repost_payment_ledger/repost_payment_ledger.py @@ -7,7 +7,6 @@ import frappe from frappe import _, qb from frappe.model.document import Document from frappe.query_builder.custom import ConstantColumn -from frappe.utils.background_jobs import is_job_queued from erpnext.accounts.utils import _delete_pl_entries, create_payment_ledger_entry @@ -102,10 +101,9 @@ def execute_repost_payment_ledger(docname): job_name = "payment_ledger_repost_" + docname - if not is_job_queued(job_name): - frappe.enqueue( - method="erpnext.accounts.doctype.repost_payment_ledger.repost_payment_ledger.start_payment_ledger_repost", - docname=docname, - is_async=True, - job_name=job_name, - ) + frappe.enqueue( + method="erpnext.accounts.doctype.repost_payment_ledger.repost_payment_ledger.start_payment_ledger_repost", + docname=docname, + is_async=True, + job_name=job_name, + ) From b3759890d703764d8b4a40125fb6df466a2e4b82 Mon Sep 17 00:00:00 2001 From: s-aga-r Date: Sun, 15 Jan 2023 21:09:16 +0530 Subject: [PATCH 07/13] chore: `Sales Order` link in `Pick List` --- erpnext/stock/doctype/pick_list/pick_list_dashboard.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/erpnext/stock/doctype/pick_list/pick_list_dashboard.py b/erpnext/stock/doctype/pick_list/pick_list_dashboard.py index 92e57bed22..7fbcbafbac 100644 --- a/erpnext/stock/doctype/pick_list/pick_list_dashboard.py +++ b/erpnext/stock/doctype/pick_list/pick_list_dashboard.py @@ -1,7 +1,10 @@ def get_data(): return { "fieldname": "pick_list", + "internal_links": { + "Sales Order": ["locations", "sales_order"], + }, "transactions": [ - {"items": ["Stock Entry", "Delivery Note"]}, + {"items": ["Stock Entry", "Sales Order", "Delivery Note"]}, ], } From 8119442c9468768b211996f469dd84d3ac2a8e19 Mon Sep 17 00:00:00 2001 From: Poruri Sai Rahul Date: Mon, 16 Jan 2023 08:47:28 +0530 Subject: [PATCH 08/13] FIX: Remove usage of "six.string_types" (#33603) FIX: Remove usage of six.string_types six is no longer a dependency --- .../doctype/asset_capitalization/asset_capitalization.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py index 7d3b645be7..62a3483629 100644 --- a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py +++ b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py @@ -8,7 +8,6 @@ import frappe # import erpnext from frappe import _ from frappe.utils import cint, flt, get_link_to_form -from six import string_types import erpnext from erpnext.assets.doctype.asset.depreciation import ( @@ -626,7 +625,7 @@ def get_target_asset_details(asset=None, company=None): @frappe.whitelist() def get_consumed_stock_item_details(args): - if isinstance(args, string_types): + if isinstance(args, str): args = json.loads(args) args = frappe._dict(args) @@ -678,7 +677,7 @@ def get_consumed_stock_item_details(args): @frappe.whitelist() def get_warehouse_details(args): - if isinstance(args, string_types): + if isinstance(args, str): args = json.loads(args) args = frappe._dict(args) @@ -694,7 +693,7 @@ def get_warehouse_details(args): @frappe.whitelist() def get_consumed_asset_details(args): - if isinstance(args, string_types): + if isinstance(args, str): args = json.loads(args) args = frappe._dict(args) @@ -746,7 +745,7 @@ def get_consumed_asset_details(args): @frappe.whitelist() def get_service_item_details(args): - if isinstance(args, string_types): + if isinstance(args, str): args = json.loads(args) args = frappe._dict(args) From 333907b7a52890856a2bcfa794e886ae11d2c340 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Mon, 16 Jan 2023 08:49:35 +0530 Subject: [PATCH 09/13] Revert "fix: Updating SO throws ordered_qty not allowed to change after submission" (#33646) --- erpnext/selling/doctype/sales_order_item/sales_order_item.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/erpnext/selling/doctype/sales_order_item/sales_order_item.json b/erpnext/selling/doctype/sales_order_item/sales_order_item.json index 134b5eafd0..d0dabad5c9 100644 --- a/erpnext/selling/doctype/sales_order_item/sales_order_item.json +++ b/erpnext/selling/doctype/sales_order_item/sales_order_item.json @@ -638,7 +638,6 @@ "width": "70px" }, { - "allow_on_submit": 1, "fieldname": "ordered_qty", "fieldtype": "Float", "label": "Ordered Qty", @@ -865,7 +864,7 @@ "idx": 1, "istable": 1, "links": [], - "modified": "2023-01-12 13:13:28.691585", + "modified": "2022-12-25 02:51:10.247569", "modified_by": "Administrator", "module": "Selling", "name": "Sales Order Item", From be382054e5c14aab2b021feba780ef9f78225f81 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Mon, 16 Jan 2023 08:50:39 +0530 Subject: [PATCH 10/13] revert: Reverting changes done on 33495 (#33662) 'ordered_qty' will not be fetched from `tabBin` --- erpnext/stock/doctype/item/test_item.py | 1 - erpnext/stock/get_item_details.py | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/erpnext/stock/doctype/item/test_item.py b/erpnext/stock/doctype/item/test_item.py index 7e426ae4af..53f6b7f8f1 100644 --- a/erpnext/stock/doctype/item/test_item.py +++ b/erpnext/stock/doctype/item/test_item.py @@ -106,7 +106,6 @@ class TestItem(FrappeTestCase): "conversion_factor": 1.0, "reserved_qty": 1, "actual_qty": 5, - "ordered_qty": 10, "projected_qty": 14, } diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py index f7fcb30acd..363dc0a63f 100644 --- a/erpnext/stock/get_item_details.py +++ b/erpnext/stock/get_item_details.py @@ -1181,7 +1181,7 @@ def get_projected_qty(item_code, warehouse): @frappe.whitelist() def get_bin_details(item_code, warehouse, company=None, include_child_warehouses=False): - bin_details = {"projected_qty": 0, "actual_qty": 0, "reserved_qty": 0, "ordered_qty": 0} + bin_details = {"projected_qty": 0, "actual_qty": 0, "reserved_qty": 0} if warehouse: from frappe.query_builder.functions import Coalesce, Sum @@ -1197,7 +1197,6 @@ def get_bin_details(item_code, warehouse, company=None, include_child_warehouses Coalesce(Sum(bin.projected_qty), 0).as_("projected_qty"), Coalesce(Sum(bin.actual_qty), 0).as_("actual_qty"), Coalesce(Sum(bin.reserved_qty), 0).as_("reserved_qty"), - Coalesce(Sum(bin.ordered_qty), 0).as_("ordered_qty"), ) .where((bin.item_code == item_code) & (bin.warehouse.isin(warehouses))) ).run(as_dict=True)[0] From dceef0397a55bdca84d0eda88ad688aed314f349 Mon Sep 17 00:00:00 2001 From: Raffael Meyer <14891507+barredterra@users.noreply.github.com> Date: Mon, 16 Jan 2023 04:23:37 +0100 Subject: [PATCH 11/13] fix: allow to create sales order from expired quotation (#33582) --- erpnext/selling/doctype/quotation/quotation.py | 9 +-------- erpnext/selling/doctype/quotation/test_quotation.py | 11 +++++++---- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/erpnext/selling/doctype/quotation/quotation.py b/erpnext/selling/doctype/quotation/quotation.py index 484b8c9f08..6836d56647 100644 --- a/erpnext/selling/doctype/quotation/quotation.py +++ b/erpnext/selling/doctype/quotation/quotation.py @@ -194,14 +194,7 @@ def get_list_context(context=None): @frappe.whitelist() -def make_sales_order(source_name, target_doc=None): - quotation = frappe.db.get_value( - "Quotation", source_name, ["transaction_date", "valid_till"], as_dict=1 - ) - if quotation.valid_till and ( - quotation.valid_till < quotation.transaction_date or quotation.valid_till < getdate(nowdate()) - ): - frappe.throw(_("Validity period of this quotation has ended.")) +def make_sales_order(source_name: str, target_doc=None): return _make_sales_order(source_name, target_doc) diff --git a/erpnext/selling/doctype/quotation/test_quotation.py b/erpnext/selling/doctype/quotation/test_quotation.py index b151dd5e79..5aaba4fa43 100644 --- a/erpnext/selling/doctype/quotation/test_quotation.py +++ b/erpnext/selling/doctype/quotation/test_quotation.py @@ -136,17 +136,20 @@ class TestQuotation(FrappeTestCase): sales_order.payment_schedule[1].due_date, getdate(add_days(quotation.transaction_date, 30)) ) - def test_valid_till(self): - from erpnext.selling.doctype.quotation.quotation import make_sales_order - + def test_valid_till_before_transaction_date(self): quotation = frappe.copy_doc(test_records[0]) quotation.valid_till = add_days(quotation.transaction_date, -1) self.assertRaises(frappe.ValidationError, quotation.validate) + def test_so_from_expired_quotation(self): + from erpnext.selling.doctype.quotation.quotation import make_sales_order + + quotation = frappe.copy_doc(test_records[0]) quotation.valid_till = add_days(nowdate(), -1) quotation.insert() quotation.submit() - self.assertRaises(frappe.ValidationError, make_sales_order, quotation.name) + + make_sales_order(quotation.name) def test_shopping_cart_without_website_item(self): if frappe.db.exists("Website Item", {"item_code": "_Test Item Home Desktop 100"}): From 312625fdc5f542cb7aa6de0c9b27f7306b065251 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Mon, 16 Jan 2023 13:43:54 +0530 Subject: [PATCH 12/13] fix: Patch to update reference_due_date in Journal Entry (#33616) --- erpnext/patches.txt | 1 + .../update_reference_due_date_in_journal_entry.py | 12 ++++++++++++ 2 files changed, 13 insertions(+) create mode 100644 erpnext/patches/v14_0/update_reference_due_date_in_journal_entry.py diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 7495ab8d0b..cba1ecc2cf 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -269,6 +269,7 @@ erpnext.patches.v13_0.reset_corrupt_defaults erpnext.patches.v13_0.create_accounting_dimensions_for_asset_repair erpnext.patches.v15_0.delete_taxjar_doctypes erpnext.patches.v15_0.create_asset_depreciation_schedules_from_assets +erpnext.patches.v14_0.update_reference_due_date_in_journal_entry [post_model_sync] execute:frappe.delete_doc_if_exists('Workspace', 'ERPNext Integrations Settings') diff --git a/erpnext/patches/v14_0/update_reference_due_date_in_journal_entry.py b/erpnext/patches/v14_0/update_reference_due_date_in_journal_entry.py new file mode 100644 index 0000000000..70003125a5 --- /dev/null +++ b/erpnext/patches/v14_0/update_reference_due_date_in_journal_entry.py @@ -0,0 +1,12 @@ +import frappe + + +def execute(): + if frappe.db.get_value("Journal Entry Account", {"reference_due_date": ""}): + frappe.db.sql( + """ + UPDATE `tabJournal Entry Account` + SET reference_due_date = NULL + WHERE reference_due_date = '' + """ + ) From adaeba15540ae1b917043e584cf11af86585b0af Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Mon, 16 Jan 2023 14:03:54 +0530 Subject: [PATCH 13/13] fix(minor): Label updates in Statement of Accounts (#33639) fix(minor): Label updates in Satement of Accounts --- .../process_statement_of_accounts.html | 1 - erpnext/accounts/report/general_ledger/general_ledger.html | 5 ++--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.html b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.html index 0da44a464e..3920d4cf09 100644 --- a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.html +++ b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.html @@ -49,7 +49,6 @@
{% endif %} - {{ _("Against") }}: {{ row.against }}
{{ _("Remarks") }}: {{ row.remarks }} {% if row.bill_no %}
{{ _("Supplier Invoice No") }}: {{ row.bill_no }} diff --git a/erpnext/accounts/report/general_ledger/general_ledger.html b/erpnext/accounts/report/general_ledger/general_ledger.html index c04f518d7e..475be92add 100644 --- a/erpnext/accounts/report/general_ledger/general_ledger.html +++ b/erpnext/accounts/report/general_ledger/general_ledger.html @@ -25,8 +25,8 @@ {%= __("Date") %} - {%= __("Ref") %} - {%= __("Party") %} + {%= __("Reference") %} + {%= __("Remarks") %} {%= __("Debit") %} {%= __("Credit") %} {%= __("Balance (Dr - Cr)") %} @@ -45,7 +45,6 @@
{% } %} - {{ __("Against") }}: {%= data[i].against %}
{%= __("Remarks") %}: {%= data[i].remarks %} {% if(data[i].bill_no) { %}
{%= __("Supplier Invoice No") %}: {%= data[i].bill_no %}