feat: Filter out alternative item rows in taxes and totals for Quotation
- Added a Quotation Item field `is_alternative_item`
- Use filtered rows for taxes and totals computation
diff --git a/erpnext/controllers/taxes_and_totals.py b/erpnext/controllers/taxes_and_totals.py
index 8c403aa..5815cfa 100644
--- a/erpnext/controllers/taxes_and_totals.py
+++ b/erpnext/controllers/taxes_and_totals.py
@@ -24,11 +24,19 @@
def __init__(self, doc: Document):
self.doc = doc
frappe.flags.round_off_applicable_accounts = []
+
+ self._items = self.filter_rows() if self.doc.doctype == "Quotation" else self.doc.get("items")
+
get_round_off_applicable_accounts(self.doc.company, frappe.flags.round_off_applicable_accounts)
self.calculate()
+ def filter_rows(self):
+ """Exclude rows, that do not fulfill the filter criteria, from totals computation."""
+ items = list(filter(lambda item: not item.get("is_alternative_item"), self.doc.get("items")))
+ return items
+
def calculate(self):
- if not len(self.doc.get("items")):
+ if not len(self._items):
return
self.discount_amount_applied = False
@@ -70,7 +78,7 @@
if hasattr(self.doc, "tax_withholding_net_total"):
sum_net_amount = 0
sum_base_net_amount = 0
- for item in self.doc.get("items"):
+ for item in self._items:
if hasattr(item, "apply_tds") and item.apply_tds:
sum_net_amount += item.net_amount
sum_base_net_amount += item.base_net_amount
@@ -79,7 +87,7 @@
self.doc.base_tax_withholding_net_total = sum_base_net_amount
def validate_item_tax_template(self):
- for item in self.doc.get("items"):
+ for item in self._items:
if item.item_code and item.get("item_tax_template"):
item_doc = frappe.get_cached_doc("Item", item.item_code)
args = {
@@ -137,7 +145,7 @@
return
if not self.discount_amount_applied:
- for item in self.doc.get("items"):
+ for item in self._items:
self.doc.round_floats_in(item)
if item.discount_percentage == 100:
@@ -236,7 +244,7 @@
if not any(cint(tax.included_in_print_rate) for tax in self.doc.get("taxes")):
return
- for item in self.doc.get("items"):
+ for item in self._items:
item_tax_map = self._load_item_tax_rate(item.item_tax_rate)
cumulated_tax_fraction = 0
total_inclusive_tax_amount_per_qty = 0
@@ -317,7 +325,7 @@
self.doc.total
) = self.doc.base_total = self.doc.net_total = self.doc.base_net_total = 0.0
- for item in self.doc.get("items"):
+ for item in self._items:
self.doc.total += item.amount
self.doc.total_qty += item.qty
self.doc.base_total += item.base_amount
@@ -354,7 +362,7 @@
]
)
- for n, item in enumerate(self.doc.get("items")):
+ for n, item in enumerate(self._items):
item_tax_map = self._load_item_tax_rate(item.item_tax_rate)
for i, tax in enumerate(self.doc.get("taxes")):
# tax_amount represents the amount of tax for the current step
@@ -363,7 +371,7 @@
# Adjust divisional loss to the last item
if tax.charge_type == "Actual":
actual_tax_dict[tax.idx] -= current_tax_amount
- if n == len(self.doc.get("items")) - 1:
+ if n == len(self._items) - 1:
current_tax_amount += actual_tax_dict[tax.idx]
# accumulate tax amount into tax.tax_amount
@@ -391,7 +399,7 @@
)
# set precision in the last item iteration
- if n == len(self.doc.get("items")) - 1:
+ if n == len(self._items) - 1:
self.round_off_totals(tax)
self._set_in_company_currency(tax, ["tax_amount", "tax_amount_after_discount_amount"])
@@ -570,7 +578,7 @@
def calculate_total_net_weight(self):
if self.doc.meta.get_field("total_net_weight"):
self.doc.total_net_weight = 0.0
- for d in self.doc.items:
+ for d in self._items:
if d.total_weight:
self.doc.total_net_weight += d.total_weight
@@ -630,7 +638,7 @@
if total_for_discount_amount:
# calculate item amount after Discount Amount
- for i, item in enumerate(self.doc.get("items")):
+ for i, item in enumerate(self._items):
distributed_amount = (
flt(self.doc.discount_amount) * item.net_amount / total_for_discount_amount
)
@@ -643,7 +651,7 @@
self.doc.apply_discount_on == "Net Total"
or not taxes
or total_for_discount_amount == self.doc.net_total
- ) and i == len(self.doc.get("items")) - 1:
+ ) and i == len(self._items) - 1:
discount_amount_loss = flt(
self.doc.net_total - net_total - self.doc.discount_amount, self.doc.precision("net_total")
)
diff --git a/erpnext/selling/doctype/quotation_item/quotation_item.json b/erpnext/selling/doctype/quotation_item/quotation_item.json
index ca7dfd2..eaa4d1d 100644
--- a/erpnext/selling/doctype/quotation_item/quotation_item.json
+++ b/erpnext/selling/doctype/quotation_item/quotation_item.json
@@ -49,6 +49,7 @@
"pricing_rules",
"stock_uom_rate",
"is_free_item",
+ "is_alternative_item",
"section_break_43",
"valuation_rate",
"column_break_45",
@@ -643,12 +644,19 @@
"no_copy": 1,
"options": "currency",
"read_only": 1
+ },
+ {
+ "default": "0",
+ "fieldname": "is_alternative_item",
+ "fieldtype": "Check",
+ "label": "Is Alternative Item",
+ "print_hide": 1
}
],
"idx": 1,
"istable": 1,
"links": [],
- "modified": "2022-12-25 02:49:53.926625",
+ "modified": "2023-01-24 08:48:06.290335",
"modified_by": "Administrator",
"module": "Selling",
"name": "Quotation Item",
@@ -656,5 +664,6 @@
"permissions": [],
"sort_field": "modified",
"sort_order": "DESC",
+ "states": [],
"track_changes": 1
}
\ No newline at end of file