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

chore: release v14 #44210

Merged
merged 35 commits into from
Nov 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
c23868a
fix: backport german translations from develop (#44046)
barredterra Nov 13, 2024
f03e301
fix: broken apply on other item pricing rule
ruthra-kumar Sep 12, 2024
5452f8a
Merge pull request #44139 from frappe/mergify/bp/version-14-hotfix/pr…
ruthra-kumar Nov 14, 2024
137ef78
fix: correctly set 'cannot_add_rows' property on allocations table field
UmakanthKaspa Nov 14, 2024
f5135cd
Merge pull request #44152 from frappe/mergify/bp/version-14-hotfix/pr…
ruthra-kumar Nov 15, 2024
cc9b22c
fix: apply posting date sorting to invoices in Payment Reconciliation…
Nov 11, 2024
1019d98
fix: remove trailing whitespace
UmakanthKaspa Nov 11, 2024
b9a0f4f
Merge pull request #44154 from frappe/mergify/bp/version-14-hotfix/pr…
ruthra-kumar Nov 15, 2024
36898f6
fix: broken UI on currency exchange
ruthra-kumar Nov 15, 2024
c9fa4af
Merge pull request #44159 from frappe/mergify/bp/version-14-hotfix/pr…
ruthra-kumar Nov 15, 2024
33e835c
fix: Get Entries not showing accounts with no gain or loss in Exchang…
vishakhdesai Sep 28, 2024
c3e2ff2
fix: linters
vishakhdesai Sep 28, 2024
313ea39
Merge pull request #44161 from frappe/mergify/bp/version-14-hotfix/pr…
ruthra-kumar Nov 15, 2024
f871f08
fix: stock ledger variance report filter options (backport #44137) (#…
mergify[bot] Nov 15, 2024
8a94d7b
fix:Unable to pause job card (#42839)
TurkerTunali Nov 15, 2024
f9b52b2
refactor: set 'cannot_add_rows' directly in the allocations table fie…
Nov 15, 2024
e09f101
fix: set conversion factor before applying price list
vishakhdesai Nov 14, 2024
85d398e
Merge pull request #44177 from frappe/mergify/bp/version-14-hotfix/pr…
ruthra-kumar Nov 18, 2024
339beff
Merge pull request #44179 from frappe/mergify/bp/version-14-hotfix/pr…
ruthra-kumar Nov 18, 2024
f3cbbef
fix: set default party type in Payment Entry
vishakhdesai Nov 13, 2024
2fcab32
Merge pull request #44181 from frappe/mergify/bp/version-14-hotfix/pr…
ruthra-kumar Nov 18, 2024
a7de8c1
feat: new DocTypes "Code List" and "Common Code" (backport #43425) (#…
mergify[bot] Nov 18, 2024
24b5b3c
fix: check if pricing rule matches with coupon code (#44104)
nikolas-beckel Nov 19, 2024
9f3dfb3
Merge pull request #44216 from frappe/mergify/bp/version-14-hotfix/pr…
ruthra-kumar Nov 19, 2024
bd0f11e
fix: validate sales team to ensure all sales person are enabled
ljain112 Nov 19, 2024
356da69
fix: disable conversion to user tz for sales order calender
ljain112 Nov 19, 2024
09b21b8
Merge pull request #44234 from frappe/mergify/bp/version-14-hotfix/pr…
ruthra-kumar Nov 20, 2024
e8c3617
refactor: Update `Payment Request` search query in PE's reference
Abdeali099 Nov 19, 2024
859672c
Merge pull request #44232 from frappe/mergify/bp/version-14-hotfix/pr…
ruthra-kumar Nov 20, 2024
ec40131
fix: non group pos warehouse
Nihantra-Patel Nov 20, 2024
5bfbdb8
Merge pull request #44238 from frappe/mergify/bp/version-14-hotfix/pr…
ruthra-kumar Nov 20, 2024
227c912
Merge pull request #44241 from frappe/mergify/bp/version-14-hotfix/pr…
ruthra-kumar Nov 20, 2024
23fb4f3
fix: payment reco for jv with negative dr or cr amount
ljain112 Nov 18, 2024
5fa4fd8
fix: added test cases
ljain112 Nov 19, 2024
24126b0
Merge pull request #44244 from frappe/mergify/bp/version-14-hotfix/pr…
ruthra-kumar Nov 20, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,21 @@ def validate_mandatory(self):
if not (self.company and self.posting_date):
frappe.throw(_("Please select Company and Posting Date to getting entries"))

def before_submit(self):
self.remove_accounts_without_gain_loss()

def remove_accounts_without_gain_loss(self):
self.accounts = [account for account in self.accounts if account.gain_loss]

if not self.accounts:
frappe.throw(_("At least one account with exchange gain or loss is required"))

frappe.msgprint(
_("Removing rows without exchange gain or loss"),
alert=True,
indicator="yellow",
)

def on_cancel(self):
self.ignore_linked_doctypes = "GL Entry"

Expand Down Expand Up @@ -226,23 +241,23 @@ def calculate_new_account_balance(company, posting_date, account_details):
new_exchange_rate = get_exchange_rate(d.account_currency, company_currency, posting_date)
new_balance_in_base_currency = flt(d.balance_in_account_currency * new_exchange_rate)
gain_loss = flt(new_balance_in_base_currency, precision) - flt(d.balance, precision)
if gain_loss:
accounts.append(
{
"account": d.account,
"party_type": d.party_type,
"party": d.party,
"account_currency": d.account_currency,
"balance_in_base_currency": d.balance,
"balance_in_account_currency": d.balance_in_account_currency,
"zero_balance": d.zero_balance,
"current_exchange_rate": current_exchange_rate,
"new_exchange_rate": new_exchange_rate,
"new_balance_in_base_currency": new_balance_in_base_currency,
"new_balance_in_account_currency": d.balance_in_account_currency,
"gain_loss": gain_loss,
}
)

accounts.append(
{
"account": d.account,
"party_type": d.party_type,
"party": d.party,
"account_currency": d.account_currency,
"balance_in_base_currency": d.balance,
"balance_in_account_currency": d.balance_in_account_currency,
"zero_balance": d.zero_balance,
"current_exchange_rate": current_exchange_rate,
"new_exchange_rate": new_exchange_rate,
"new_balance_in_base_currency": new_balance_in_base_currency,
"new_balance_in_account_currency": d.balance_in_account_currency,
"gain_loss": gain_loss,
}
)

# Handle Accounts with '0' balance in Account/Base Currency
for d in [x for x in account_details if x.zero_balance]:
Expand All @@ -266,23 +281,22 @@ def calculate_new_account_balance(company, posting_date, account_details):
current_exchange_rate * d.balance_in_account_currency
)

if gain_loss:
accounts.append(
{
"account": d.account,
"party_type": d.party_type,
"party": d.party,
"account_currency": d.account_currency,
"balance_in_base_currency": d.balance,
"balance_in_account_currency": d.balance_in_account_currency,
"zero_balance": d.zero_balance,
"current_exchange_rate": current_exchange_rate,
"new_exchange_rate": new_exchange_rate,
"new_balance_in_base_currency": new_balance_in_base_currency,
"new_balance_in_account_currency": new_balance_in_account_currency,
"gain_loss": gain_loss,
}
)
accounts.append(
{
"account": d.account,
"party_type": d.party_type,
"party": d.party,
"account_currency": d.account_currency,
"balance_in_base_currency": d.balance,
"balance_in_account_currency": d.balance_in_account_currency,
"zero_balance": d.zero_balance,
"current_exchange_rate": current_exchange_rate,
"new_exchange_rate": new_exchange_rate,
"new_balance_in_base_currency": new_balance_in_base_currency,
"new_balance_in_account_currency": new_balance_in_account_currency,
"gain_loss": gain_loss,
}
)

return accounts

Expand Down
18 changes: 18 additions & 0 deletions erpnext/accounts/doctype/payment_entry/payment_entry.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ frappe.ui.form.on('Payment Entry', {
}

erpnext.accounts.dimensions.setup_dimension_filters(frm, frm.doctype);

if (frm.is_new()) {
set_default_party_type(frm);
}
},

setup: function(frm) {
Expand Down Expand Up @@ -320,6 +324,7 @@ frappe.ui.form.on('Payment Entry', {
},

payment_type: function(frm) {
set_default_party_type(frm);
if(frm.doc.payment_type == "Internal Transfer") {
$.each(["party", "party_balance", "paid_from", "paid_to",
"references", "total_allocated_amount"], function(i, field) {
Expand Down Expand Up @@ -1511,3 +1516,16 @@ frappe.ui.form.on('Payment Entry Deduction', {
frm.events.set_unallocated_amount(frm);
},
});

function set_default_party_type(frm) {
if (frm.doc.party) return;

let party_type;
if (frm.doc.payment_type == "Receive") {
party_type = "Customer";
} else if (frm.doc.payment_type == "Pay") {
party_type = "Supplier";
}

if (party_type) frm.set_value("party_type", party_type);
}
Original file line number Diff line number Diff line change
Expand Up @@ -144,12 +144,14 @@ def get_jv_entries(self):
if self.get("cost_center"):
conditions.append(jea.cost_center == self.cost_center)

dr_or_cr = (
"credit_in_account_currency"
if erpnext.get_party_account_type(self.party_type) == "Receivable"
else "debit_in_account_currency"
)
conditions.append(jea[dr_or_cr].gt(0))
account_type = erpnext.get_party_account_type(self.party_type)

if account_type == "Receivable":
dr_or_cr = jea.credit_in_account_currency - jea.debit_in_account_currency
elif account_type == "Payable":
dr_or_cr = jea.debit_in_account_currency - jea.credit_in_account_currency

conditions.append(dr_or_cr.gt(0))

if self.bank_cash_account:
conditions.append(jea.against_account.like(f"%%{self.bank_cash_account}%%"))
Expand All @@ -164,7 +166,7 @@ def get_jv_entries(self):
je.posting_date,
je.remark.as_("remarks"),
jea.name.as_("reference_row"),
jea[dr_or_cr].as_("amount"),
dr_or_cr.as_("amount"),
jea.is_advance,
jea.exchange_rate,
jea.account_currency.as_("currency"),
Expand Down Expand Up @@ -299,6 +301,10 @@ def get_invoice_entries(self):
if self.invoice_limit:
non_reconciled_invoices = non_reconciled_invoices[: self.invoice_limit]

non_reconciled_invoices = sorted(
non_reconciled_invoices, key=lambda k: k["posting_date"] or getdate(nowdate())
)

self.add_invoice_entries(non_reconciled_invoices)

def add_invoice_entries(self, non_reconciled_invoices):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -615,6 +615,42 @@ def test_journal_against_invoice(self):
self.assertEqual(len(pr.get("invoices")), 0)
self.assertEqual(len(pr.get("payments")), 0)

def test_negative_debit_or_credit_journal_against_invoice(self):
transaction_date = nowdate()
amount = 100
si = self.create_sales_invoice(qty=1, rate=amount, posting_date=transaction_date)

# credit debtors account to record a payment
je = self.create_journal_entry(self.bank, self.debit_to, amount, transaction_date)
je.accounts[1].party_type = "Customer"
je.accounts[1].party = self.customer
je.accounts[1].credit_in_account_currency = 0
je.accounts[1].debit_in_account_currency = -1 * amount
je.save()
je.submit()

pr = self.create_payment_reconciliation()

pr.get_unreconciled_entries()
invoices = [x.as_dict() for x in pr.get("invoices")]
payments = [x.as_dict() for x in pr.get("payments")]
pr.allocate_entries(frappe._dict({"invoices": invoices, "payments": payments}))

# Difference amount should not be calculated for base currency accounts
for row in pr.allocation:
self.assertEqual(flt(row.get("difference_amount")), 0.0)

pr.reconcile()

# assert outstanding
si.reload()
self.assertEqual(si.status, "Paid")
self.assertEqual(si.outstanding_amount, 0)

# check PR tool output
self.assertEqual(len(pr.get("invoices")), 0)
self.assertEqual(len(pr.get("payments")), 0)

def test_journal_against_journal(self):
transaction_date = nowdate()
sales = "Sales - _PR"
Expand Down Expand Up @@ -937,6 +973,100 @@ def test_difference_amount_via_journal_entry(self):
frappe.db.get_value("Journal Entry", jea_parent.parent, "voucher_type"), "Exchange Gain Or Loss"
)

def test_difference_amount_via_negative_debit_or_credit_journal_entry(self):
# Make Sale Invoice
si = self.create_sales_invoice(
qty=1, rate=100, posting_date=nowdate(), do_not_save=True, do_not_submit=True
)
si.customer = self.customer4
si.currency = "EUR"
si.conversion_rate = 85
si.debit_to = self.debtors_eur
si.save().submit()

# Make payment using Journal Entry
je1 = self.create_journal_entry("HDFC - _PR", self.debtors_eur, 100, nowdate())
je1.multi_currency = 1
je1.accounts[0].exchange_rate = 1
je1.accounts[0].credit_in_account_currency = -8000
je1.accounts[0].credit = -8000
je1.accounts[0].debit_in_account_currency = 0
je1.accounts[0].debit = 0
je1.accounts[1].party_type = "Customer"
je1.accounts[1].party = self.customer4
je1.accounts[1].exchange_rate = 80
je1.accounts[1].credit_in_account_currency = 100
je1.accounts[1].credit = 8000
je1.accounts[1].debit_in_account_currency = 0
je1.accounts[1].debit = 0
je1.save()
je1.submit()

je2 = self.create_journal_entry("HDFC - _PR", self.debtors_eur, 200, nowdate())
je2.multi_currency = 1
je2.accounts[0].exchange_rate = 1
je2.accounts[0].credit_in_account_currency = -16000
je2.accounts[0].credit = -16000
je2.accounts[0].debit_in_account_currency = 0
je2.accounts[0].debit = 0
je2.accounts[1].party_type = "Customer"
je2.accounts[1].party = self.customer4
je2.accounts[1].exchange_rate = 80
je2.accounts[1].credit_in_account_currency = 200
je1.accounts[1].credit = 16000
je1.accounts[1].debit_in_account_currency = 0
je1.accounts[1].debit = 0
je2.save()
je2.submit()

pr = self.create_payment_reconciliation()
pr.party = self.customer4
pr.receivable_payable_account = self.debtors_eur
pr.get_unreconciled_entries()

self.assertEqual(len(pr.invoices), 1)
self.assertEqual(len(pr.payments), 2)

# Test exact payment allocation
invoices = [x.as_dict() for x in pr.invoices]
payments = [pr.payments[0].as_dict()]
pr.allocate_entries(frappe._dict({"invoices": invoices, "payments": payments}))

self.assertEqual(pr.allocation[0].allocated_amount, 100)
self.assertEqual(pr.allocation[0].difference_amount, -500)

# Test partial payment allocation (with excess payment entry)
pr.set("allocation", [])
pr.get_unreconciled_entries()
invoices = [x.as_dict() for x in pr.invoices]
payments = [pr.payments[1].as_dict()]
pr.allocate_entries(frappe._dict({"invoices": invoices, "payments": payments}))
pr.allocation[0].difference_account = "Exchange Gain/Loss - _PR"

self.assertEqual(pr.allocation[0].allocated_amount, 100)
self.assertEqual(pr.allocation[0].difference_amount, -500)

# Check if difference journal entry gets generated for difference amount after reconciliation
pr.reconcile()
total_credit_amount = frappe.db.get_all(
"Journal Entry Account",
{"account": self.debtors_eur, "docstatus": 1, "reference_name": si.name},
"sum(credit) as amount",
group_by="reference_name",
)[0].amount

# total credit includes the exchange gain/loss amount
self.assertEqual(flt(total_credit_amount, 2), 8500)

jea_parent = frappe.db.get_all(
"Journal Entry Account",
filters={"account": self.debtors_eur, "docstatus": 1, "reference_name": si.name, "credit": 500},
fields=["parent"],
)[0]
self.assertEqual(
frappe.db.get_value("Journal Entry", jea_parent.parent, "voucher_type"), "Exchange Gain Or Loss"
)

def test_difference_amount_via_payment_entry(self):
# Make Sale Invoice
si = self.create_sales_invoice(
Expand Down
11 changes: 6 additions & 5 deletions erpnext/accounts/doctype/payment_request/payment_request.py
Original file line number Diff line number Diff line change
Expand Up @@ -838,17 +838,18 @@ def validate_payment(doc, method=None):
@frappe.whitelist()
def get_open_payment_requests_query(doctype, txt, searchfield, start, page_len, filters):
# permission checks in `get_list()`
reference_doctype = filters.get("reference_doctype")
reference_name = filters.get("reference_doctype")
filters = frappe._dict(filters)

if not reference_doctype or not reference_name:
if not filters.reference_doctype or not filters.reference_name:
return []

if txt:
filters.name = ["like", f"%{txt}%"]

open_payment_requests = frappe.get_list(
"Payment Request",
filters={
"reference_doctype": filters["reference_doctype"],
"reference_name": filters["reference_name"],
**filters,
"status": ["!=", "Paid"],
"outstanding_amount": ["!=", 0], # for compatibility with old data
"docstatus": 1,
Expand Down
18 changes: 14 additions & 4 deletions erpnext/accounts/doctype/pricing_rule/pricing_rule.py
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,20 @@ def get_pricing_rule_for_item(args, doc=None, for_validate=False):
if isinstance(pricing_rule, str):
pricing_rule = frappe.get_cached_doc("Pricing Rule", pricing_rule)
update_pricing_rule_uom(pricing_rule, args)
pricing_rule.apply_rule_on_other_items = get_pricing_rule_items(pricing_rule) or []
fetch_other_item = True if pricing_rule.apply_rule_on_other else False
pricing_rule.apply_rule_on_other_items = (
get_pricing_rule_items(pricing_rule, other_items=fetch_other_item) or []
)

if pricing_rule.coupon_code_based == 1:
if not args.coupon_code:
return item_details

coupon_code = frappe.db.get_value(
doctype="Coupon Code", filters={"pricing_rule": pricing_rule.name}, fieldname="name"
)
if args.coupon_code != coupon_code:
continue

if pricing_rule.get("suggestion"):
continue
Expand All @@ -386,9 +399,6 @@ def get_pricing_rule_for_item(args, doc=None, for_validate=False):
pricing_rule.apply_rule_on_other_items
)

if pricing_rule.coupon_code_based == 1 and args.coupon_code is None:
return item_details

if not pricing_rule.validate_applied_rule:
if pricing_rule.price_or_product_discount == "Price":
apply_price_discount_rule(pricing_rule, item_details, args)
Expand Down
10 changes: 10 additions & 0 deletions erpnext/accounts/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -579,6 +579,16 @@ def update_reference_in_journal_entry(d, journal_entry, do_not_save=False):
if jv_detail.get("reference_type") in ("Sales Order", "Purchase Order"):
frappe.get_doc(jv_detail.reference_type, jv_detail.reference_name).set_total_advance_paid()

rev_dr_or_cr = (
"debit_in_account_currency"
if d["dr_or_cr"] == "credit_in_account_currency"
else "credit_in_account_currency"
)
if jv_detail.get(rev_dr_or_cr):
d["dr_or_cr"] = rev_dr_or_cr
d["allocated_amount"] = d["allocated_amount"] * -1
d["unadjusted_amount"] = d["unadjusted_amount"] * -1

if flt(d["unadjusted_amount"]) - flt(d["allocated_amount"]) != 0:
# adjust the unreconciled balance
amount_in_account_currency = flt(d["unadjusted_amount"]) - flt(d["allocated_amount"])
Expand Down
Loading
Loading