Merge branch 'develop' into make-against-field-dynamic

This commit is contained in:
Gursheen Kaur Anand
2023-11-06 17:06:03 +05:30
committed by GitHub
513 changed files with 7244 additions and 23122 deletions

View File

@@ -13,6 +13,7 @@ from frappe.utils import (
add_days,
add_months,
cint,
comma_and,
flt,
fmt_money,
formatdate,
@@ -181,6 +182,17 @@ class AccountsController(TransactionBase):
self.validate_party_account_currency()
if self.doctype in ["Purchase Invoice", "Sales Invoice"]:
if invalid_advances := [
x for x in self.advances if not x.reference_type or not x.reference_name
]:
frappe.throw(
_(
"Rows: {0} in {1} section are Invalid. Reference Name should point to a valid Payment Entry or Journal Entry."
).format(
frappe.bold(comma_and([x.idx for x in invalid_advances])), frappe.bold(_("Advance Payments"))
)
)
pos_check_field = "is_pos" if self.doctype == "Sales Invoice" else "is_paid"
if cint(self.allocate_advances_automatically) and not cint(self.get(pos_check_field)):
self.set_advances()
@@ -243,13 +255,38 @@ class AccountsController(TransactionBase):
_doc.cancel()
_doc.delete()
def on_trash(self):
# delete references in 'Repost Payment Ledger'
rpi = frappe.qb.DocType("Repost Payment Ledger Items")
frappe.qb.from_(rpi).delete().where(
(rpi.voucher_type == self.doctype) & (rpi.voucher_no == self.name)
).run()
def _remove_references_in_repost_doctypes(self):
repost_doctypes = ["Repost Payment Ledger Items", "Repost Accounting Ledger Items"]
for _doctype in repost_doctypes:
dt = frappe.qb.DocType(_doctype)
rows = (
frappe.qb.from_(dt)
.select(dt.name, dt.parent, dt.parenttype)
.where((dt.voucher_type == self.doctype) & (dt.voucher_no == self.name))
.run(as_dict=True)
)
if rows:
references_map = frappe._dict()
for x in rows:
references_map.setdefault((x.parenttype, x.parent), []).append(x.name)
for doc, rows in references_map.items():
repost_doc = frappe.get_doc(doc[0], doc[1])
for row in rows:
if _doctype == "Repost Payment Ledger Items":
repost_doc.remove(repost_doc.get("repost_vouchers", {"name": row})[0])
else:
repost_doc.remove(repost_doc.get("vouchers", {"name": row})[0])
repost_doc.flags.ignore_validate_update_after_submit = True
repost_doc.flags.ignore_links = True
repost_doc.save(ignore_permissions=True)
def on_trash(self):
self._remove_references_in_repost_doctypes()
self._remove_references_in_unreconcile()
# delete sl and gl entries on deletion of transaction
@@ -547,6 +584,17 @@ class AccountsController(TransactionBase):
self.currency, self.company_currency, transaction_date, args
)
if (
self.currency
and buying_or_selling == "Buying"
and frappe.db.get_single_value("Buying Settings", "use_transaction_date_exchange_rate")
and self.doctype == "Purchase Invoice"
):
self.use_transaction_date_exchange_rate = True
self.conversion_rate = get_exchange_rate(
self.currency, self.company_currency, transaction_date, args
)
def set_missing_item_details(self, for_validate=False):
"""set missing item values"""
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
@@ -1132,7 +1180,9 @@ class AccountsController(TransactionBase):
self.name,
arg.get("referenced_row"),
):
posting_date = frappe.db.get_value(arg.voucher_type, arg.voucher_no, "posting_date")
posting_date = arg.get("difference_posting_date") or frappe.db.get_value(
arg.voucher_type, arg.voucher_no, "posting_date"
)
je = create_gain_loss_journal(
self.company,
posting_date,
@@ -1215,7 +1265,7 @@ class AccountsController(TransactionBase):
je = create_gain_loss_journal(
self.company,
self.posting_date,
args.get("difference_posting_date") if args else self.posting_date,
self.party_type,
self.party,
party_account,
@@ -1473,7 +1523,7 @@ class AccountsController(TransactionBase):
"against_type": against_type,
"against": supplier_or_customer,
dr_or_cr: self.base_discount_amount,
"cost_center": self.cost_center,
"cost_center": self.cost_center or erpnext.get_default_cost_center(self.company),
},
item=self,
)
@@ -2193,6 +2243,46 @@ class AccountsController(TransactionBase):
_("Select finance book for the item {0} at row {1}").format(item.item_code, item.idx)
)
def check_if_fields_updated(self, fields_to_check, child_tables):
# Check if any field affecting accounting entry is altered
doc_before_update = self.get_doc_before_save()
accounting_dimensions = get_accounting_dimensions() + ["cost_center", "project"]
# Check if opening entry check updated
needs_repost = doc_before_update.get("is_opening") != self.is_opening
if not needs_repost:
# Parent Level Accounts excluding party account
fields_to_check += accounting_dimensions
for field in fields_to_check:
if doc_before_update.get(field) != self.get(field):
needs_repost = 1
break
if not needs_repost:
# Check for child tables
for table in child_tables:
needs_repost = check_if_child_table_updated(
doc_before_update.get(table), self.get(table), child_tables[table]
)
if needs_repost:
break
return needs_repost
@frappe.whitelist()
def repost_accounting_entries(self):
if self.repost_required:
repost_ledger = frappe.new_doc("Repost Accounting Ledger")
repost_ledger.company = self.company
repost_ledger.append("vouchers", {"voucher_type": self.doctype, "voucher_no": self.name})
repost_ledger.flags.ignore_permissions = True
repost_ledger.insert()
repost_ledger.submit()
self.db_set("repost_required", 0)
else:
frappe.throw(_("No updates pending for reposting"))
@frappe.whitelist()
def get_tax_rate(account_head):
@@ -3198,6 +3288,23 @@ def update_child_qty_rate(parent_doctype, trans_items, parent_doctype_name, chil
parent.create_stock_reservation_entries()
def check_if_child_table_updated(
child_table_before_update, child_table_after_update, fields_to_check
):
accounting_dimensions = get_accounting_dimensions() + ["cost_center", "project"]
# Check if any field affecting accounting entry is altered
for index, item in enumerate(child_table_after_update):
for field in fields_to_check:
if child_table_before_update[index].get(field) != item.get(field):
return True
for dimension in accounting_dimensions:
if child_table_before_update[index].get(dimension) != item.get(dimension):
return True
return False
@erpnext.allow_regional
def validate_regional(doc):
pass