Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Fixes Related to IMS and Purchase Reconciliation Tool #2998

Merged
merged 13 commits into from
Jan 24, 2025
Merged
2 changes: 2 additions & 0 deletions india_compliance/gst_india/api_classes/taxpayer_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -367,9 +367,11 @@ def get(self, *args, **kwargs):
return self._request("get", *args, **kwargs, params=params)

def post(self, *args, **kwargs):
self.default_log_values.update(update_gstr_action=True)
return self._request("post", *args, **kwargs)

def put(self, *args, **kwargs):
self.default_log_values.update(update_gstr_action=True)
return self._request("put", *args, **kwargs)

def before_request(self, request_args):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,7 @@ class IMS extends reconciliation.reconciliation_tabs {
},
{
label: "Bill No.",
fieldname: "bill_no",
fieldname: "bill_no_date",
align: "center",
width: 120,
},
Expand Down Expand Up @@ -414,7 +414,7 @@ class IMS extends reconciliation.reconciliation_tabs {

data.push({
supplier_name_gstin: this.get_supplier_name_gstin(row),
bill_no: row.bill_no,
bill_no_date: this.get_bill_no_bill_date(row),
classification: row._inward_supply.classification,
ims_action: row.ims_action || "",
match_status: row.match_status,
Expand All @@ -424,6 +424,7 @@ class IMS extends reconciliation.reconciliation_tabs {
inward_supply_name: row.inward_supply_name,
pending_upload: row.pending_upload,
is_supplier_return_filed: row.is_supplier_return_filed,
linked_voucher_type: row._purchase_invoice.doctype,
});
});

Expand Down Expand Up @@ -530,7 +531,7 @@ class IMS extends reconciliation.reconciliation_tabs {
.join("");

const action_performed_html = `
<div class="action-performed-summary m-3 d-flex justify-content-around align-items-center" style="border-bottom: 1px solid var(--border-color);">
<div class="action-performed-summary mt-3 mb-3 w-100 d-flex justify-content-around align-items-center" style="border-bottom: 1px solid var(--border-color);">
${action_performed_cards}
</div>
`;
Expand All @@ -553,6 +554,14 @@ class IMS extends reconciliation.reconciliation_tabs {
me.update_filter(e, "ims_action", action, me);
});
}

get_bill_no_bill_date(row) {
return `
${row.bill_no}
<br/>
${frappe.datetime.str_to_user(row.bill_date) || ""}
`;
}
}

class IMSAction {
Expand Down Expand Up @@ -580,10 +589,14 @@ class IMSAction {
);
}

// Download Button
this.frm.add_custom_button(__("Download Invoices"), () => {
render_empty_state(this.frm);
this.download_ims_data();
});

// Export button
this.frm.add_custom_button(__("Export"), () => this.export_data());
}

setup_row_actions() {
Expand Down Expand Up @@ -767,6 +780,21 @@ class IMSAction {
indicator: "green",
});
}

async export_data() {
if (!this.frm.reconciliation_tabs.filtered_data) {
await this.frm.ims_actions.get_ims_data();
vorasmit marked this conversation as resolved.
Show resolved Hide resolved
}

const url = `${DOC_PATH}.download_excel_report`;
open_url_post(`/api/method/${url}`, {
data: JSON.stringify(this.frm.reconciliation_tabs.filtered_data),
doc: JSON.stringify({
company: this.frm.doc.company,
company_gstin: this.frm.doc.company_gstin,
}),
});
}
}

class DetailViewDialog extends reconciliation.detail_view_dialog {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@
from india_compliance.gst_india.doctype.purchase_reconciliation_tool import (
ReconciledData,
)
from india_compliance.gst_india.doctype.purchase_reconciliation_tool.purchase_reconciliation_tool import (
BuildExcel,
)
from india_compliance.gst_india.doctype.purchase_reconciliation_tool.purchase_reconciliation_utils import (
get_formatted_options,
)
Expand All @@ -32,6 +35,7 @@
from india_compliance.gst_india.doctype.purchase_reconciliation_tool.purchase_reconciliation_utils import (
unlink_documents as _unlink_documents,
)
from india_compliance.gst_india.utils.exporter import ExcelExporter
from india_compliance.gst_india.utils.gstr_2 import (
GSTRCategory,
ReturnType,
Expand Down Expand Up @@ -259,6 +263,14 @@ def check_action_status(company_gstin, action):
return process_save_or_reset_ims(ims_log, action)


@frappe.whitelist()
def download_excel_report(data, doc):
frappe.has_permission("GST Invoice Management System", "export", throw=True)

build_data = BuildExcelIMS(doc, data)
build_data.export_data()


def download_and_upload_ims_invoices(company_gstin):
"""
1. This function will download invoices from GST Portal,
Expand Down Expand Up @@ -384,37 +396,148 @@ def process_save_or_reset_ims(return_log, action):

if status_cd in ["P", "PE"]:
# Exclude erroneous invoices from previous IMS action update
# This is enqueued because linking of integration request is enqueued
# This is enqueued because creation of integration request is enqueued
# TODO: flag for re-upload?
frappe.enqueue(
update_previous_ims_action,
queue="long",
integration_request=doc.integration_request,
request_id=doc.request_id,
error_report=response.get("error_report") or dict(),
)

return response


def update_previous_ims_action(integration_request, error_report=None):
uploaded_invoices = get_uploaded_invoices(integration_request)
def update_previous_ims_action(request_id, error_report=None):
uploaded_invoices = get_uploaded_invoices(request_id)

for category, invoices in uploaded_invoices.items():
_class = get_data_handler(ReturnType.IMS.value, category.upper())
_class().update_previous_ims_action(invoices, error_report.get(category, []))


def get_uploaded_invoices(integration_request):
def get_uploaded_invoices(request_id):
request_data = frappe.parse_json(
frappe.db.get_value(
"Integration Request", {"name": integration_request}, "data"
)
frappe.db.get_value("Integration Request", {"request_id": request_id}, "data")
Ninad1306 marked this conversation as resolved.
Show resolved Hide resolved
)

if not request_data:
return {}
frappe.throw(_("Request data not found"))

if isinstance(request_data, str):
request_data = frappe.parse_json(request_data)

return request_data["body"]["data"]["invdata"]


class BuildExcelIMS(BuildExcel):
def export_data(self):
"""Exports data to an excel file"""
excel = ExcelExporter()
excel.create_sheet(
sheet_name="Invoice Data",
filters=self.filters,
headers=self.invoice_header,
data=self.data,
default_data_format={"bg_color": self.COLOR_PALLATE.light_gray},
default_header_format={"bg_color": self.COLOR_PALLATE.dark_gray},
)

excel.remove_sheet("Sheet")
file_name = self.get_file_name()
excel.export(file_name)

def set_headers(self):
"""Sets headers for the excel file"""
self.invoice_header = self.get_invoice_columns()

def set_filters(self):
"""Add filters to the sheet"""
self.filters = frappe._dict(
{
"Company Name": self.doc.company,
"GSTIN": self.doc.company_gstin,
}
)

def get_file_name(self):
"""Returns file name for the excel file"""
return f"{self.doc.company}_{self.doc.company_gstin}_report"

def get_invoice_columns(self):
return [
{
"label": "Supplier Name",
"fieldname": "supplier_name",
"data_format": {"horizontal": "center"},
},
{
"label": "Supplier GSTIN",
"fieldname": "supplier_gstin",
"data_format": {"horizontal": "center"},
},
{
"label": "Bill No",
"fieldname": "bill_no",
"data_format": {
"horizontal": "center",
"bg_color": self.COLOR_PALLATE.light_green,
},
},
{
"label": "Bill Date",
"fieldname": "bill_date",
"data_format": {
"horizontal": "center",
"bg_color": self.COLOR_PALLATE.light_blue,
},
},
{
"label": "Match Status",
"fieldname": "match_status",
"data_format": {"horizontal": "center"},
},
{
"label": "IMS Action",
"fieldname": "ims_action",
"data_format": {"horizontal": "center"},
},
{
"label": "Inward Supply Name",
"fieldname": "inward_supply_name",
"data_format": {"horizontal": "center"},
},
{
"label": "Linked Voucher",
"fieldname": "purchase_invoice_name",
"data_format": {"horizontal": "center"},
},
{
"label": "Taxable Amount Diff \n 2A/2B - Purchase",
"fieldname": "taxable_value_difference",
"fieldtype": "Float",
"data_format": {
"bg_color": self.COLOR_PALLATE.light_pink,
"number_format": "0.00",
"horizontal": "center",
},
},
{
"label": "Tax Difference \n 2A/2B - Purchase",
"fieldname": "tax_difference",
"fieldtype": "Float",
"data_format": {
"bg_color": self.COLOR_PALLATE.light_pink,
"number_format": "0.00",
"horizontal": "center",
},
},
{
"label": "Classification",
"fieldname": "classification",
"data_format": {"horizontal": "center"},
"header_format": {
"width": 11,
},
},
]
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"engine": "InnoDB",
"field_order": [
"request_type",
"request_id",
"token",
"status",
"creation_time",
Expand Down Expand Up @@ -44,12 +45,18 @@
"label": "Integration Request",
"options": "Integration Request",
"read_only": 1
},
{
"fieldname": "request_id",
"fieldtype": "Data",
"hidden": 1,
"label": "Request id"
}
],
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2024-09-12 12:36:05.679413",
"modified": "2025-01-22 16:33:57.014368",
"modified_by": "Administrator",
"module": "GST India",
"name": "GSTR Action",
Expand Down
20 changes: 1 addition & 19 deletions india_compliance/gst_india/doctype/gstr_action/gstr_action.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ def set_gstr_actions(doc, request_type, token, request_id, status=None):

row = {
"request_type": request_type,
"request_id": request_id,
"token": token,
"creation_time": frappe.utils.now_datetime(),
}
Expand All @@ -24,22 +25,3 @@ def set_gstr_actions(doc, request_type, token, request_id, status=None):

doc.append("actions", row)
doc.save()
enqueue_link_integration_request(token, request_id)


def enqueue_link_integration_request(token, request_id):
"""
Integration request is enqueued. Hence, it's name is not available immediately.
Hence, link it after the request is processed.
"""
frappe.enqueue(
link_integration_request, queue="long", token=token, request_id=request_id
)


def link_integration_request(token, request_id):
doc_name = frappe.db.get_value("Integration Request", {"request_id": request_id})
if doc_name:
frappe.db.set_value(
"GSTR Action", {"token": token}, {"integration_request": doc_name}
)
Original file line number Diff line number Diff line change
Expand Up @@ -1137,6 +1137,7 @@ def process_data(self, reconciliation_data: list, retain_doc: bool = False):
"differences": "",
"action": "",
"classification": "",
"is_reverse_charge": "",
}

for data in reconciliation_data:
Expand All @@ -1154,7 +1155,13 @@ def process_data(self, reconciliation_data: list, retain_doc: bool = False):
BaseUtil.update_cess_amount(purchase)

def update_fields(self, data, purchase, inward_supply):
for field in ("supplier_name", "supplier_gstin", "bill_no", "bill_date"):
for field in (
"supplier_name",
"supplier_gstin",
"bill_no",
"bill_date",
"is_reverse_charge",
):
data[field] = purchase.get(field) or inward_supply.get(field)

data.update(
Expand Down
Loading
Loading