Skip to content

Commit

Permalink
Merge pull request #38038 from ruthra-kumar/refactor_bulk_transaction
Browse files Browse the repository at this point in the history
refactor: supercharge Bulk actions
  • Loading branch information
ruthra-kumar committed Nov 16, 2023
2 parents 3e884d3 + a393a6b commit ee29526
Show file tree
Hide file tree
Showing 8 changed files with 274 additions and 241 deletions.
Original file line number Diff line number Diff line change
@@ -1,30 +1,21 @@
// Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
// Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt

frappe.ui.form.on('Bulk Transaction Log', {

refresh: function(frm) {
frm.disable_save();
frm.add_custom_button(__('Retry Failed Transactions'), ()=>{
frappe.confirm(__("Retry Failing Transactions ?"), ()=>{
query(frm, 1);
}
);
});
}
});

function query(frm) {
frappe.call({
method: "erpnext.bulk_transaction.doctype.bulk_transaction_log.bulk_transaction_log.retry_failing_transaction",
args: {
log_date: frm.doc.log_date
frappe.ui.form.on("Bulk Transaction Log", {
refresh(frm) {
frm.add_custom_button(__('Succeeded Entries'), function() {
frappe.set_route('List', 'Bulk Transaction Log Detail', {'date': frm.doc.date, 'transaction_status': "Success"});
}, __("View"));
frm.add_custom_button(__('Failed Entries'), function() {
frappe.set_route('List', 'Bulk Transaction Log Detail', {'date': frm.doc.date, 'transaction_status': "Failed"});
}, __("View"));
if (frm.doc.failed) {
frm.add_custom_button(__('Retry Failed Transactions'), function() {
frappe.call({
method: "erpnext.utilities.bulk_transaction.retry",
args: {date: frm.doc.date}
});
});
}
}).then((r) => {
if (r.message === "No Failed Records") {
frappe.show_alert(__(r.message), 5);
} else {
frappe.show_alert(__("Retrying Failed Transactions"), 5);
}
});
}
},
});
Original file line number Diff line number Diff line change
@@ -1,31 +1,64 @@
{
"actions": [],
"allow_rename": 1,
"creation": "2021-11-30 13:41:16.343827",
"allow_copy": 1,
"creation": "2023-11-09 20:14:45.139593",
"default_view": "List",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"log_date",
"logger_data"
"date",
"column_break_bsan",
"log_entries",
"section_break_mdmv",
"succeeded",
"column_break_qryp",
"failed"
],
"fields": [
{
"fieldname": "log_date",
"fieldname": "date",
"fieldtype": "Date",
"label": "Log Date",
"in_list_view": 1,
"in_standard_filter": 1,
"label": "Date",
"read_only": 1
},
{
"fieldname": "logger_data",
"fieldtype": "Table",
"label": "Logger Data",
"options": "Bulk Transaction Log Detail"
"fieldname": "log_entries",
"fieldtype": "Int",
"in_list_view": 1,
"label": "Log Entries",
"read_only": 1
},
{
"fieldname": "column_break_bsan",
"fieldtype": "Column Break"
},
{
"fieldname": "section_break_mdmv",
"fieldtype": "Section Break"
},
{
"fieldname": "succeeded",
"fieldtype": "Int",
"label": "Succeeded",
"read_only": 1
},
{
"fieldname": "column_break_qryp",
"fieldtype": "Column Break"
},
{
"fieldname": "failed",
"fieldtype": "Int",
"label": "Failed",
"read_only": 1
}
],
"index_web_pages_for_search": 1,
"in_create": 1,
"is_virtual": 1,
"links": [],
"modified": "2022-02-03 17:23:02.935325",
"modified": "2023-11-11 04:52:49.347376",
"modified_by": "Administrator",
"module": "Bulk Transaction",
"name": "Bulk Transaction Log",
Expand All @@ -47,5 +80,5 @@
"sort_field": "modified",
"sort_order": "DESC",
"states": [],
"track_changes": 1
"title_field": "date"
}
Original file line number Diff line number Diff line change
@@ -1,67 +1,112 @@
# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
# Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt

from datetime import date

import frappe
from frappe import qb
from frappe.model.document import Document

from erpnext.utilities.bulk_transaction import task, update_logger
from frappe.query_builder.functions import Count
from frappe.utils import cint
from pypika import Order


class BulkTransactionLog(Document):
pass


@frappe.whitelist()
def retry_failing_transaction(log_date=None):
if not log_date:
log_date = str(date.today())
btp = frappe.qb.DocType("Bulk Transaction Log Detail")
data = (
frappe.qb.from_(btp)
.select(btp.transaction_name, btp.from_doctype, btp.to_doctype)
.distinct()
.where(btp.retried != 1)
.where(btp.transaction_status == "Failed")
.where(btp.date == log_date)
).run(as_dict=True)

if data:
if len(data) > 10:
frappe.enqueue(job, queue="long", job_name="bulk_retry", data=data, log_date=log_date)
else:
job(data, log_date)
else:
return "No Failed Records"


def job(data, log_date):
for d in data:
failed = []
try:
frappe.db.savepoint("before_creation_of_record")
task(d.transaction_name, d.from_doctype, d.to_doctype)
except Exception as e:
frappe.db.rollback(save_point="before_creation_of_record")
failed.append(e)
update_logger(
d.transaction_name,
e,
d.from_doctype,
d.to_doctype,
status="Failed",
log_date=log_date,
restarted=1,
)
def db_insert(self, *args, **kwargs):
pass

def load_from_db(self):
log_detail = qb.DocType("Bulk Transaction Log Detail")

has_records = frappe.db.sql(
f"select exists (select * from `tabBulk Transaction Log Detail` where date = '{self.name}');"
)[0][0]
if not has_records:
raise frappe.DoesNotExistError

if not failed:
update_logger(
d.transaction_name,
None,
d.from_doctype,
d.to_doctype,
status="Success",
log_date=log_date,
restarted=1,
succeeded_logs = (
qb.from_(log_detail)
.select(Count(log_detail.date).as_("count"))
.where((log_detail.date == self.name) & (log_detail.transaction_status == "Success"))
.run()
)[0][0] or 0
failed_logs = (
qb.from_(log_detail)
.select(Count(log_detail.date).as_("count"))
.where((log_detail.date == self.name) & (log_detail.transaction_status == "Failed"))
.run()
)[0][0] or 0
total_logs = succeeded_logs + failed_logs
transaction_log = frappe._dict(
{
"date": self.name,
"count": total_logs,
"succeeded": succeeded_logs,
"failed": failed_logs,
}
)
super(Document, self).__init__(serialize_transaction_log(transaction_log))

@staticmethod
def get_list(args):
filter_date = parse_list_filters(args)
limit = cint(args.get("page_length")) or 20
log_detail = qb.DocType("Bulk Transaction Log Detail")

dates_query = (
qb.from_(log_detail)
.select(log_detail.date)
.distinct()
.orderby(log_detail.date, order=Order.desc)
.limit(limit)
)
if filter_date:
dates_query = dates_query.where(log_detail.date == filter_date)
dates = dates_query.run()

transaction_logs = []
if dates:
transaction_logs_query = (
qb.from_(log_detail)
.select(log_detail.date.as_("date"), Count(log_detail.date).as_("count"))
.where(log_detail.date.isin(dates))
.orderby(log_detail.date, order=Order.desc)
.groupby(log_detail.date)
.limit(limit)
)
transaction_logs = transaction_logs_query.run(as_dict=True)

return [serialize_transaction_log(x) for x in transaction_logs]

@staticmethod
def get_count(args):
pass

@staticmethod
def get_stats(args):
pass

def db_update(self, *args, **kwargs):
pass

def delete(self):
pass


def serialize_transaction_log(data):
return frappe._dict(
name=data.date,
date=data.date,
log_entries=data.count,
succeeded=data.succeeded,
failed=data.failed,
)


def parse_list_filters(args):
# parse date filter
filter_date = None
for fil in args.get("filters"):
if isinstance(fil, list):
for elem in fil:
if elem == "date":
filter_date = fil[3]
return filter_date
Original file line number Diff line number Diff line change
@@ -1,79 +1,9 @@
# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors
# Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt

import unittest
from datetime import date
# import frappe
from frappe.tests.utils import FrappeTestCase

import frappe

from erpnext.utilities.bulk_transaction import transaction_processing


class TestBulkTransactionLog(unittest.TestCase):
def setUp(self):
create_company()
create_customer()
create_item()

def test_entry_in_log(self):
so_name = create_so()
transaction_processing([{"name": so_name}], "Sales Order", "Sales Invoice")
doc = frappe.get_doc("Bulk Transaction Log", str(date.today()))
for d in doc.get("logger_data"):
if d.transaction_name == so_name:
self.assertEqual(d.transaction_name, so_name)
self.assertEqual(d.transaction_status, "Success")
self.assertEqual(d.from_doctype, "Sales Order")
self.assertEqual(d.to_doctype, "Sales Invoice")
self.assertEqual(d.retried, 0)


def create_company():
if not frappe.db.exists("Company", "_Test Company"):
frappe.get_doc(
{
"doctype": "Company",
"company_name": "_Test Company",
"country": "India",
"default_currency": "INR",
}
).insert()


def create_customer():
if not frappe.db.exists("Customer", "Bulk Customer"):
frappe.get_doc({"doctype": "Customer", "customer_name": "Bulk Customer"}).insert()


def create_item():
if not frappe.db.exists("Item", "MK"):
frappe.get_doc(
{
"doctype": "Item",
"item_code": "MK",
"item_name": "Milk",
"description": "Milk",
"item_group": "Products",
}
).insert()


def create_so(intent=None):
so = frappe.new_doc("Sales Order")
so.customer = "Bulk Customer"
so.company = "_Test Company"
so.transaction_date = date.today()

so.set_warehouse = "Finished Goods - _TC"
so.append(
"items",
{
"item_code": "MK",
"delivery_date": date.today(),
"qty": 10,
"rate": 80,
},
)
so.insert()
so.submit()
return so.name
class TestBulkTransactionLog(FrappeTestCase):
pass
Loading

0 comments on commit ee29526

Please sign in to comment.