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 @@ -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();
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 @@ -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")
Ninad1306 marked this conversation as resolved.
Show resolved Hide resolved
)

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
Loading