mirror of
https://github.com/frappe/erpnext.git
synced 2026-08-27 05:45:19 +00:00
refactor: reversal capability on exchange rate revaluation
(cherry picked from commit a0b14c0607)
# Conflicts:
# erpnext/accounts/doctype/exchange_rate_revaluation/exchange_rate_revaluation.py
This commit is contained in:
@@ -22,17 +22,27 @@ frappe.ui.form.on("Exchange Rate Revaluation", {
|
|||||||
refresh: function (frm) {
|
refresh: function (frm) {
|
||||||
if (frm.doc.docstatus == 1) {
|
if (frm.doc.docstatus == 1) {
|
||||||
frappe.call({
|
frappe.call({
|
||||||
method: "check_journal_entry_condition",
|
method: "check_journal_and_reversal",
|
||||||
doc: frm.doc,
|
doc: frm.doc,
|
||||||
callback: function (r) {
|
callback: function (r) {
|
||||||
if (r.message) {
|
if (r.message) {
|
||||||
frm.add_custom_button(
|
if (!r.message.journals_posted) {
|
||||||
__("Journal Entries"),
|
frm.add_custom_button(
|
||||||
function () {
|
__("Journal Entries"),
|
||||||
return frm.events.make_jv(frm);
|
function () {
|
||||||
},
|
return frm.events.make_jv(frm);
|
||||||
__("Create")
|
},
|
||||||
);
|
__("Create")
|
||||||
|
);
|
||||||
|
} else if (!r.message.reversals_posted) {
|
||||||
|
frm.add_custom_button(
|
||||||
|
__("Reversal Journal Entries"),
|
||||||
|
function () {
|
||||||
|
return frm.events.make_reverse_journal(frm);
|
||||||
|
},
|
||||||
|
__("Create")
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -100,6 +110,14 @@ frappe.ui.form.on("Exchange Rate Revaluation", {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
make_reverse_journal: function (frm) {
|
||||||
|
frappe.call({
|
||||||
|
method: "make_reverse_journal",
|
||||||
|
doc: frm.doc,
|
||||||
|
freeze: true,
|
||||||
|
freeze_message: __("Reversing Journals..."),
|
||||||
|
});
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
frappe.ui.form.on("Exchange Rate Revaluation Account", {
|
frappe.ui.form.on("Exchange Rate Revaluation Account", {
|
||||||
|
|||||||
@@ -7,8 +7,13 @@ from frappe import _, qb
|
|||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
from frappe.model.meta import get_field_precision
|
from frappe.model.meta import get_field_precision
|
||||||
from frappe.query_builder import Criterion, Order
|
from frappe.query_builder import Criterion, Order
|
||||||
|
<<<<<<< HEAD
|
||||||
from frappe.query_builder.functions import NullIf, Sum
|
from frappe.query_builder.functions import NullIf, Sum
|
||||||
from frappe.utils import flt, get_link_to_form
|
from frappe.utils import flt, get_link_to_form
|
||||||
|
=======
|
||||||
|
from frappe.query_builder.functions import Max, NullIf, Sum
|
||||||
|
from frappe.utils import flt, get_link_to_form, nowdate
|
||||||
|
>>>>>>> a0b14c0607 (refactor: reversal capability on exchange rate revaluation)
|
||||||
|
|
||||||
import erpnext
|
import erpnext
|
||||||
from erpnext.accounts.doctype.journal_entry.journal_entry import get_balance_on
|
from erpnext.accounts.doctype.journal_entry.journal_entry import get_balance_on
|
||||||
@@ -93,22 +98,28 @@ class ExchangeRateRevaluation(Document):
|
|||||||
self.ignore_linked_doctypes = ["GL Entry", "Payment Ledger Entry"]
|
self.ignore_linked_doctypes = ["GL Entry", "Payment Ledger Entry"]
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def check_journal_entry_condition(self):
|
def check_journal_and_reversal(self):
|
||||||
exchange_gain_loss_account = self.get_for_unrealized_gain_loss_account()
|
exchange_gain_loss_account = self.get_for_unrealized_gain_loss_account()
|
||||||
|
|
||||||
|
journals_posted = False
|
||||||
|
reversals_posted = False
|
||||||
|
|
||||||
|
je = qb.DocType("Journal Entry")
|
||||||
jea = qb.DocType("Journal Entry Account")
|
jea = qb.DocType("Journal Entry Account")
|
||||||
journals = (
|
journals = (
|
||||||
qb.from_(jea)
|
qb.from_(je)
|
||||||
.select(jea.parent)
|
.join(jea)
|
||||||
|
.on(je.name == jea.parent)
|
||||||
|
.select(je.name)
|
||||||
.distinct()
|
.distinct()
|
||||||
.where(
|
.where(
|
||||||
(jea.reference_type == "Exchange Rate Revaluation")
|
(jea.reference_type == "Exchange Rate Revaluation")
|
||||||
& (jea.reference_name == self.name)
|
& (jea.reference_name == self.name)
|
||||||
& (jea.docstatus == 1)
|
& (jea.docstatus == 1)
|
||||||
|
& (je.reversal_of.isnull()) # omit journals that have reversals
|
||||||
)
|
)
|
||||||
.run()
|
.run(pluck="name")
|
||||||
)
|
)
|
||||||
|
|
||||||
if journals:
|
if journals:
|
||||||
gle = qb.DocType("GL Entry")
|
gle = qb.DocType("GL Entry")
|
||||||
total_amt = (
|
total_amt = (
|
||||||
@@ -123,12 +134,31 @@ class ExchangeRateRevaluation(Document):
|
|||||||
.run()
|
.run()
|
||||||
)
|
)
|
||||||
|
|
||||||
if total_amt and total_amt[0][0] != self.total_gain_loss:
|
if total_amt and total_amt[0][0] == self.total_gain_loss:
|
||||||
return True
|
journals_posted = True
|
||||||
else:
|
else:
|
||||||
return False
|
journals_posted = False
|
||||||
|
|
||||||
return True
|
# reverse journals
|
||||||
|
reverse_journals = (
|
||||||
|
qb.from_(je)
|
||||||
|
.join(jea)
|
||||||
|
.on(je.name == jea.parent)
|
||||||
|
.select(je.name)
|
||||||
|
.where(
|
||||||
|
(jea.reference_type == "Exchange Rate Revaluation")
|
||||||
|
& (jea.reference_name == self.name)
|
||||||
|
& (jea.docstatus == 1)
|
||||||
|
& (je.reversal_of.notnull())
|
||||||
|
)
|
||||||
|
.run(pluck="name")
|
||||||
|
)
|
||||||
|
if reverse_journals:
|
||||||
|
reversals_posted = True
|
||||||
|
else:
|
||||||
|
reversals_posted = False
|
||||||
|
|
||||||
|
return {"journals_posted": journals_posted, "reversals_posted": reversals_posted}
|
||||||
|
|
||||||
def fetch_and_calculate_accounts_data(self):
|
def fetch_and_calculate_accounts_data(self):
|
||||||
accounts = self.get_accounts_data()
|
accounts = self.get_accounts_data()
|
||||||
@@ -342,6 +372,7 @@ class ExchangeRateRevaluation(Document):
|
|||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def make_jv_entries(self):
|
def make_jv_entries(self):
|
||||||
|
frappe.has_permission("Journal Entry", "write", throw=True)
|
||||||
zero_balance_jv = self.make_jv_for_zero_balance()
|
zero_balance_jv = self.make_jv_for_zero_balance()
|
||||||
if zero_balance_jv:
|
if zero_balance_jv:
|
||||||
frappe.msgprint(
|
frappe.msgprint(
|
||||||
@@ -568,6 +599,38 @@ class ExchangeRateRevaluation(Document):
|
|||||||
journal_entry.save()
|
journal_entry.save()
|
||||||
return journal_entry
|
return journal_entry
|
||||||
|
|
||||||
|
@frappe.whitelist()
|
||||||
|
def make_reverse_journal(self):
|
||||||
|
frappe.has_permission("Journal Entry", "write", throw=True)
|
||||||
|
je = qb.DocType("Journal Entry")
|
||||||
|
jea = qb.DocType("Journal Entry Account")
|
||||||
|
journals = (
|
||||||
|
qb.from_(je)
|
||||||
|
.join(jea)
|
||||||
|
.on(je.name == jea.parent)
|
||||||
|
.select(je.name)
|
||||||
|
.distinct()
|
||||||
|
.where(
|
||||||
|
(jea.reference_type == "Exchange Rate Revaluation")
|
||||||
|
& (jea.reference_name == self.name)
|
||||||
|
& (jea.docstatus == 1)
|
||||||
|
& (je.reversal_of.isnull()) # omit journals that have reversals
|
||||||
|
)
|
||||||
|
.run(pluck="name")
|
||||||
|
)
|
||||||
|
if journals:
|
||||||
|
from erpnext.accounts.doctype.journal_entry.mapper import make_reverse_journal_entry
|
||||||
|
|
||||||
|
for x in journals:
|
||||||
|
reversal = make_reverse_journal_entry(x)
|
||||||
|
reversal.posting_date = nowdate()
|
||||||
|
reversal.submit()
|
||||||
|
frappe.msgprint(
|
||||||
|
_("Revaluation journal for {0} has been created: {1}").format(
|
||||||
|
frappe.bold(x), get_link_to_form("Journal Entry", reversal.name)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def calculate_exchange_rate_using_last_gle(company, account, party_type, party):
|
def calculate_exchange_rate_using_last_gle(company, account, party_type, party):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -132,7 +132,7 @@ class TestExchangeRateRevaluation(ERPNextTestSuite, AccountsTestMixin):
|
|||||||
err = err.save().submit()
|
err = err.save().submit()
|
||||||
|
|
||||||
# Create JV for ERR
|
# Create JV for ERR
|
||||||
self.assertTrue(err.check_journal_entry_condition())
|
self.assertTrue(err.check_journal_and_reversal())
|
||||||
err_journals = err.make_jv_entries()
|
err_journals = err.make_jv_entries()
|
||||||
je = frappe.get_doc("Journal Entry", err_journals.get("zero_balance_jv"))
|
je = frappe.get_doc("Journal Entry", err_journals.get("zero_balance_jv"))
|
||||||
je = je.submit()
|
je = je.submit()
|
||||||
@@ -221,7 +221,7 @@ class TestExchangeRateRevaluation(ERPNextTestSuite, AccountsTestMixin):
|
|||||||
err = err.save().submit()
|
err = err.save().submit()
|
||||||
|
|
||||||
# Create JV for ERR
|
# Create JV for ERR
|
||||||
self.assertTrue(err.check_journal_entry_condition())
|
self.assertTrue(err.check_journal_and_reversal())
|
||||||
err_journals = err.make_jv_entries()
|
err_journals = err.make_jv_entries()
|
||||||
je = frappe.get_doc("Journal Entry", err_journals.get("zero_balance_jv"))
|
je = frappe.get_doc("Journal Entry", err_journals.get("zero_balance_jv"))
|
||||||
je = je.submit()
|
je = je.submit()
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
frappe.listview_settings["Journal Entry"] = {
|
frappe.listview_settings["Journal Entry"] = {
|
||||||
add_fields: ["voucher_type", "posting_date", "total_debit", "company", "remark"],
|
add_fields: ["voucher_type", "posting_date", "total_debit", "company", "remark", "reversal_of"],
|
||||||
get_indicator: function (doc) {
|
get_indicator: function (doc) {
|
||||||
if (doc.docstatus === 1) {
|
if (doc.docstatus === 1) {
|
||||||
|
if (doc.reversal_of && doc.voucher_type == "Exchange Rate Revaluation") {
|
||||||
|
return [__("Reversal Of Exchange Rate Revaluation"), "blue"];
|
||||||
|
}
|
||||||
return [__(doc.voucher_type), "blue", `voucher_type,=,${doc.voucher_type}`];
|
return [__(doc.voucher_type), "blue", `voucher_type,=,${doc.voucher_type}`];
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user