Skip to content

Commit

Permalink
Merge pull request resilient-tech#1552 from vorasmit/residual-match
Browse files Browse the repository at this point in the history
fix: simplify residual match for more inclusive matches
  • Loading branch information
vorasmit authored Jan 5, 2024
2 parents ddb5640 + 54c3bfb commit 18fd886
Showing 1 changed file with 26 additions and 53 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class Fields(Enum):
SGST = "sgst"
IGST = "igst"
CESS = "cess"
TOTAL_GST = "total_gst"


class Rule(Enum):
Expand Down Expand Up @@ -188,9 +189,7 @@ class MatchStatus(Enum):
Fields.PLACE_OF_SUPPLY: Rule.EXACT_MATCH,
Fields.REVERSE_CHARGE: Rule.EXACT_MATCH,
Fields.TAXABLE_VALUE: Rule.ROUNDING_DIFFERENCE,
Fields.CGST: Rule.ROUNDING_DIFFERENCE,
Fields.SGST: Rule.ROUNDING_DIFFERENCE,
Fields.IGST: Rule.ROUNDING_DIFFERENCE,
Fields.TOTAL_GST: Rule.ROUNDING_DIFFERENCE,
Fields.CESS: Rule.ROUNDING_DIFFERENCE,
},
},
Expand All @@ -203,9 +202,7 @@ class MatchStatus(Enum):
Fields.PLACE_OF_SUPPLY: Rule.EXACT_MATCH,
Fields.REVERSE_CHARGE: Rule.EXACT_MATCH,
Fields.TAXABLE_VALUE: Rule.ROUNDING_DIFFERENCE,
Fields.CGST: Rule.ROUNDING_DIFFERENCE,
Fields.SGST: Rule.ROUNDING_DIFFERENCE,
Fields.IGST: Rule.ROUNDING_DIFFERENCE,
Fields.TOTAL_GST: Rule.ROUNDING_DIFFERENCE,
Fields.CESS: Rule.ROUNDING_DIFFERENCE,
},
},
Expand Down Expand Up @@ -233,9 +230,7 @@ class MatchStatus(Enum):
Fields.PLACE_OF_SUPPLY: Rule.EXACT_MATCH,
Fields.REVERSE_CHARGE: Rule.EXACT_MATCH,
Fields.TAXABLE_VALUE: Rule.ROUNDING_DIFFERENCE,
Fields.CGST: Rule.ROUNDING_DIFFERENCE,
Fields.SGST: Rule.ROUNDING_DIFFERENCE,
Fields.IGST: Rule.ROUNDING_DIFFERENCE,
Fields.TOTAL_GST: Rule.ROUNDING_DIFFERENCE,
Fields.CESS: Rule.ROUNDING_DIFFERENCE,
},
},
Expand Down Expand Up @@ -748,7 +743,7 @@ def reconcile(self, category, amended_category):
# GSTIN Level matching
purchases = self.get_unmatched_purchase_or_bill_of_entry(category)
inward_supplies = self.get_unmatched_inward_supply(category, amended_category)
self.reconcile_for_rules(GSTIN_RULES, purchases, inward_supplies, category)
self.reconcile_for_rules(GSTIN_RULES, purchases, inward_supplies)

# In case of IMPG GST in not available in 2A. So skip PAN level matching.
if category == "IMPG":
Expand All @@ -757,9 +752,9 @@ def reconcile(self, category, amended_category):
# PAN Level matching
purchases = self.get_pan_level_data(purchases)
inward_supplies = self.get_pan_level_data(inward_supplies)
self.reconcile_for_rules(PAN_RULES, purchases, inward_supplies, category)
self.reconcile_for_rules(PAN_RULES, purchases, inward_supplies)

def reconcile_for_rules(self, rules, purchases, inward_supplies, category):
def reconcile_for_rules(self, rules, purchases, inward_supplies):
if not (purchases and inward_supplies):
return

Expand All @@ -769,12 +764,9 @@ def reconcile_for_rules(self, rules, purchases, inward_supplies, category):
inward_supplies,
rule.get("match_status").value,
rule.get("rule"),
category,
)

def reconcile_for_rule(
self, purchases, inward_supplies, match_status, rules, category
):
def reconcile_for_rule(self, purchases, inward_supplies, match_status, rules):
"""
Sequentially reconcile invoices as per rules list.
- Reconciliation only done between invoices of same GSTIN.
Expand All @@ -785,28 +777,18 @@ def reconcile_for_rule(
if not inward_supplies.get(supplier_gstin):
continue

summary_diff = {}
if match_status == "Residual Match" and category != "CDNR":
summary_diff = self.get_summary_difference(
purchases[supplier_gstin], inward_supplies[supplier_gstin]
)

for purchase_invoice_name, purchase in (
purchases[supplier_gstin].copy().items()
):
if summary_diff and not (
abs(summary_diff[purchase.bill_date.month]) < 2
):
continue

for inward_supply_name, inward_supply in (
inward_supplies[supplier_gstin].copy().items()
):
if (
summary_diff
and purchase.bill_date.month != inward_supply.bill_date.month
):
continue
if match_status == "Residual Match":
if (
abs((purchase.bill_date - inward_supply.bill_date).days)
> 10
):
continue

if not self.is_doc_matching(purchase, inward_supply, rules):
continue
Expand All @@ -823,26 +805,6 @@ def reconcile_for_rule(
inward_supplies[supplier_gstin].pop(inward_supply_name)
break

def get_summary_difference(self, data1, data2):
"""
Returns dict with difference of monthly purchase for given supplier data.
Calculated only for Residual Match.
Objective: Residual match is to match Invoices where bill no is completely different.
It should be matched for invoices of a given month only if difference in total invoice
value is negligible for purchase and inward supply.
"""
summary = {}
for doc in data1.values():
summary.setdefault(doc.bill_date.month, 0)
summary[doc.bill_date.month] += BaseUtil.get_total_tax(doc)

for doc in data2.values():
summary.setdefault(doc.bill_date.month, 0)
summary[doc.bill_date.month] -= BaseUtil.get_total_tax(doc)

return summary

def is_doc_matching(self, purchase, inward_supply, rules):
"""
Returns true if all fields match from purchase and inward supply as per rules.
Expand Down Expand Up @@ -911,6 +873,10 @@ def get_amount_difference(self, purchase, inward_supply, field):
if field == "cess":
BaseUtil.update_cess_amount(purchase)

if field == "total_gst":
BaseUtil.update_total_gst_amount(purchase)
BaseUtil.update_total_gst_amount(inward_supply)

return abs(purchase.get(field, 0) - inward_supply.get(field, 0))

def update_matching_doc(
Expand Down Expand Up @@ -1308,7 +1274,14 @@ def get_total_tax(doc):

@staticmethod
def update_cess_amount(doc):
doc.cess = doc.get("cess", 0) + doc.get("cess_non_advol", 0)
if doc.get("cess_non_advol"):
doc.cess = doc.get("cess", 0) + doc.get("cess_non_advol", 0)
doc.cess_non_advol = 0

@staticmethod
def update_total_gst_amount(doc):
if not doc.get("total_gst"):
doc.total_gst = doc.cgst + doc.sgst + doc.igst

@staticmethod
def get_periods(date_range, return_type: ReturnType, reversed_order=False):
Expand Down

0 comments on commit 18fd886

Please sign in to comment.