diff --git a/check_run/check_run/doctype/check_run/check_run.py b/check_run/check_run/doctype/check_run/check_run.py
index a41678e0..007069ae 100644
--- a/check_run/check_run/doctype/check_run/check_run.py
+++ b/check_run/check_run/doctype/check_run/check_run.py
@@ -43,7 +43,6 @@ def onload(self):
self.set_onload("check_run_submitting", False)
def validate(self):
- self.set_status()
gl_account = frappe.get_value("Bank Account", self.bank_account, "account")
if not gl_account:
frappe.throw(frappe._("This Bank Account is not associated with a General Ledger Account."))
@@ -54,7 +53,8 @@ def validate(self):
self.set_default_payable_account()
self.set_default_dates()
else:
- self.validate_transactions()
+ if self.status == "Draft":
+ self.filter_transactions()
def on_cancel(self):
settings = get_check_run_settings(self)
@@ -73,7 +73,8 @@ def on_cancel(self):
def set_status(self, status=None):
if status:
- self.status = status
+ self.db_set("status", status)
+ return
elif self.status == "Confirm Print":
pass
elif self.docstatus == 0:
@@ -99,40 +100,61 @@ def set_default_dates(self):
if not self.end_date:
self.end_date = getdate()
- def validate_transactions(self):
+ def filter_transactions(self):
if not self.get("transactions"):
return
- selected = [txn for txn in json.loads(self.get("transactions")) if txn["pay"]]
- wrong_status = []
+ transactions = json.loads(self.get("transactions"))
+ for t in transactions:
+ if self.not_outstanding_or_cancelled(t):
+ transactions.remove(t)
+ self.transactions = json.dumps(transactions)
+ selected = [txn for txn in transactions if txn["pay"]]
for t in selected:
if not t["mode_of_payment"]:
frappe.throw(frappe._(f"Mode of Payment Required: {t['party_name']} {t['ref_number']}"))
- filters = {"name": t["name"] if t["doctype"] != "Journal Entry" else t["ref_number"]}
- if frappe.get_value(t["doctype"], filters, "docstatus") != 1:
- wrong_status.append(
- {"party_name": t["party_name"], "ref_number": t["ref_number"] or "", "name": t["name"]}
- )
- if len(wrong_status) < 1:
- return
- invalid_records = ""
- for invalid_record in wrong_status:
- invalid_records += " ".join(invalid_record.values()) + "
"
- frappe.throw(
- frappe._(
- f"The following document(s) have been cancelled, please remove them from Check Run to continue:
{invalid_records}"
+
+ def not_outstanding_or_cancelled(self, transaction):
+ filters = {
+ "name": transaction["name"]
+ if transaction["doctype"] != "Journal Entry"
+ else transaction["ref_number"]
+ }
+ if frappe.get_value(transaction["doctype"], filters, "docstatus") != 1:
+ return True
+ if transaction["doctype"] == "Journal Entry":
+ outstanding_based_on_gle = frappe.db.sql(
+ """
+ SELECT SUM(`tabGL Entry`.debit) - SUM(`tabGL Entry`.credit) AS outstanding_amount
+ FROM `tabGL Entry`
+ WHERE party_type = %(party_type)s
+ AND account = %(account)s
+ AND party = %(party)s
+ AND voucher_no = %(ref)s
+ """,
+ {
+ "account": self.pay_to_account,
+ "party": transaction["party"],
+ "party_type": transaction["party_type"],
+ "ref": filters["name"],
+ },
+ as_dict=True,
)
- )
+ if outstanding_based_on_gle and not outstanding_based_on_gle[0].outstanding_amount:
+ return True
+ else:
+ if frappe.get_value(transaction["doctype"], filters, "outstanding_amount") == 0.0:
+ return True
@frappe.whitelist()
def process_check_run(self):
- # check_run_submitting = frappe.defaults.get_global_default("check_run_submitting")
- # if check_run_submitting:
- # frappe.throw(
- # frappe._(
- # f"""Check run {check_run_submitting} is in process. No other check runs can be submitted until it completes. Click here for details."""
- # )
- # )
- # return
+ check_run_submitting = frappe.defaults.get_global_default("check_run_submitting")
+ if check_run_submitting:
+ frappe.throw(
+ frappe._(
+ f"""Check run {check_run_submitting} is in process. No other check runs can be submitted until it completes. Click here for details."""
+ )
+ )
+ return
self.status = "Submitting"
transactions = self.transactions
transactions = json.loads(transactions)
@@ -267,6 +289,8 @@ def create_payment_entries(self, transactions):
for reference in group:
if not reference:
continue
+ if self.not_outstanding_or_cancelled(reference):
+ continue
if (
settings.automatically_release_on_hold_invoices and reference.doctype == "Purchase Invoice"
):
@@ -295,6 +319,8 @@ def create_payment_entries(self, transactions):
pe.paid_amount = total_amount
pe.base_paid_amount = total_amount
pe.base_grand_total = total_amount
+ if not pe.get("references"): # already paid or cancelled
+ continue
try:
pe.save()
pe.submit()
@@ -545,7 +571,7 @@ def get_entries(doc):
else:
query = query.union(qb)
if query:
- query = query.orderby("due_date", "name").get_sql()
+ query = query.orderby("due_date", "ref_number").get_sql()
transactions = frappe.db.sql(
query, {"company": company, "pay_to_account": pay_to_account, "end_date": end_date}, as_dict=True
diff --git a/check_run/customize.py b/check_run/customize.py
index 2d7e47d9..83d14e93 100644
--- a/check_run/customize.py
+++ b/check_run/customize.py
@@ -1,43 +1,50 @@
import json
from pathlib import Path
-import frappe
-from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
-from frappe.custom.doctype.property_setter.property_setter import make_property_setter
+import frappe
+
def load_customizations():
- customizations_directory = Path().cwd().parent / 'apps' / 'check_run' / 'check_run' / 'check_run' / 'custom'
- files = list(customizations_directory.glob('**/*.json'))
+ customizations_directory = (
+ Path().cwd().parent / "apps" / "check_run" / "check_run" / "check_run" / "custom"
+ )
+ files = list(customizations_directory.glob("**/*.json"))
for file in files:
customizations = json.loads(Path(file).read_text())
- for field in customizations.get('custom_fields'):
- existing_field = frappe.get_value('Custom Field', field.get('name'))
- custom_field = frappe.get_doc("Custom Field", field.get('name')) if existing_field else frappe.new_doc('Custom Field')
- field.pop('modified')
+ for field in customizations.get("custom_fields"):
+ existing_field = frappe.get_value("Custom Field", field.get("name"))
+ custom_field = (
+ frappe.get_doc("Custom Field", field.get("name"))
+ if existing_field
+ else frappe.new_doc("Custom Field")
+ )
+ field.pop("modified")
{custom_field.set(key, value) for key, value in field.items()}
custom_field.flags.ignore_permissions = True
custom_field.flags.ignore_version = True
custom_field.save()
- for prop in customizations.get('property_setters'):
- property_setter = frappe.get_doc({
- "name": prop.get('name'),
- "doctype": "Property Setter",
- "doctype_or_field": prop.get('doctype_or_field'),
- "doc_type": prop.get('doc_type'),
- "field_name": prop.get('field_name'),
- "property": prop.get('property'),
- "value": prop.get('value'),
- "property_type": prop.get('property_type')
- })
+ for prop in customizations.get("property_setters"):
+ property_setter = frappe.get_doc(
+ {
+ "name": prop.get("name"),
+ "doctype": "Property Setter",
+ "doctype_or_field": prop.get("doctype_or_field"),
+ "doc_type": prop.get("doc_type"),
+ "field_name": prop.get("field_name"),
+ "property": prop.get("property"),
+ "value": prop.get("value"),
+ "property_type": prop.get("property_type"),
+ }
+ )
property_setter.flags.ignore_permissions = True
property_setter.insert()
def after_install():
- if not frappe.db.exists('File', 'Home/Check Run'):
- try:
+ if not frappe.db.exists("File", "Home/Check Run"):
+ try:
cr_folder = frappe.new_doc("File")
- cr_folder.update({"file_name":"Check Run", "is_folder": True, "folder":"Home"})
+ cr_folder.update({"file_name": "Check Run", "is_folder": True, "folder": "Home"})
cr_folder.save()
except Exception as e:
- pass
\ No newline at end of file
+ pass