Skip to content

Commit

Permalink
Merge pull request #3007 from resilient-tech/mergify/bp/version-15-ho…
Browse files Browse the repository at this point in the history
…tfix/pr-2998

fix: Fixes Related to IMS and Purchase Reconciliation Tool (backport #2998)
  • Loading branch information
mergify[bot] authored Jan 24, 2025
2 parents d33f862 + 894eab4 commit 4783378
Show file tree
Hide file tree
Showing 16 changed files with 249 additions and 91 deletions.
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 @@ -149,7 +149,7 @@ def __init__(self):
self.PI_ITEM = frappe.qb.DocType("Purchase Invoice Item")

def get_all(self, names=None, filters=None):
query = self.get_query(filters=filters)
query = self.get_query(filters=filters, additional_fields=["posting_date"])

if names:
query = query.where(self.PI.name.isin(names))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ div[data-page-route="GST Invoice Management System"]
margin-top: 0;
}

div[data-page-route="GST Invoice Management System"] [data-fieldname="data_section"] {
padding-top: 0;
}

div[data-page-route="GST Invoice Management System"]
[data-fieldname="invoice_html"]
.form-tabs-list {
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();
}

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 @@ -4,6 +4,7 @@
import frappe
from frappe import _
from frappe.model.document import Document
from frappe.utils import format_date

from india_compliance.gst_india.api_classes.taxpayer_base import (
TaxpayerBaseAPI,
Expand All @@ -23,6 +24,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 +36,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 @@ -92,6 +97,8 @@ def get_invoice_data(self, inward_supply=None, purchase=None, filters=None):

invoice_data = []
for doc in inward_supplies:
_purchase_invoice = purchases.pop(doc.link_name, frappe._dict())

invoice_data.append(
frappe._dict(
{
Expand All @@ -101,10 +108,11 @@ def get_invoice_data(self, inward_supply=None, purchase=None, filters=None):
"is_pending_action_allowed": doc.is_pending_action_allowed,
"is_supplier_return_filed": doc.is_supplier_return_filed,
"doc_type": doc.doc_type,
"_inward_supply": doc,
"_purchase_invoice": purchases.pop(
doc.link_name, frappe._dict()
"posting_date": format_date(
_purchase_invoice.pop("posting_date", None)
),
"_inward_supply": doc,
"_purchase_invoice": _purchase_invoice,
}
)
)
Expand Down Expand Up @@ -259,6 +267,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 +400,140 @@ 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")
)

if not request_data:
return {}
frappe.throw(
_(
"Integration Request linked with data upload not found for request id {0}"
).format(request_id)
)

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={"horizontal": "center"},
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",
"header_format": {"width": 35},
},
{
"label": "Supplier GSTIN",
"fieldname": "supplier_gstin",
},
{
"label": "Bill No",
"fieldname": "bill_no",
},
{
"label": "Bill Date",
"fieldname": "bill_date",
},
{
"label": "Match Status",
"fieldname": "match_status",
},
{
"label": "IMS Action",
"fieldname": "ims_action",
},
{
"label": "Inward Supply Name",
"fieldname": "inward_supply_name",
},
{
"label": "Linked Voucher",
"fieldname": "purchase_invoice_name",
},
{
"label": "Posting Date",
"fieldname": "posting_date",
},
{
"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": "right",
},
},
{
"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": "right",
},
},
{
"label": "Classification",
"fieldname": "classification",
"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}
)
Loading

0 comments on commit 4783378

Please sign in to comment.