Skip to content

Commit

Permalink
Merge branch 'frappe:version-14' into version-14
Browse files Browse the repository at this point in the history
  • Loading branch information
jfa-name authored Jan 20, 2025
2 parents aeb9869 + ff3425e commit 65ba7bc
Show file tree
Hide file tree
Showing 184 changed files with 5,482 additions and 2,063 deletions.
1 change: 1 addition & 0 deletions .github/helper/documentation.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

DOCUMENTATION_DOMAINS = [
"docs.erpnext.com",
"docs.frappe.io",
"frappeframework.com",
]

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/patch.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ concurrency:

jobs:
test:
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
timeout-minutes: 60

name: Patch Test
Expand Down
16 changes: 8 additions & 8 deletions CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,22 @@
# the repo. Unless a later match takes precedence,

erpnext/accounts/ @deepeshgarg007 @ruthra-kumar
erpnext/assets/ @anandbaburajan @deepeshgarg007
erpnext/assets/ @khushi8112 @deepeshgarg007
erpnext/loan_management/ @deepeshgarg007
erpnext/regional @deepeshgarg007 @ruthra-kumar
erpnext/selling @deepeshgarg007 @ruthra-kumar
erpnext/support/ @deepeshgarg007
pos*

erpnext/buying/ @rohitwaghchaure @s-aga-r
erpnext/maintenance/ @rohitwaghchaure @s-aga-r
erpnext/manufacturing/ @rohitwaghchaure @s-aga-r
erpnext/quality_management/ @rohitwaghchaure @s-aga-r
erpnext/stock/ @rohitwaghchaure @s-aga-r
erpnext/subcontracting @rohitwaghchaure @s-aga-r
erpnext/buying/ @rohitwaghchaure
erpnext/maintenance/ @rohitwaghchaure
erpnext/manufacturing/ @rohitwaghchaure
erpnext/quality_management/ @rohitwaghchaure
erpnext/stock/ @rohitwaghchaure
erpnext/subcontracting @rohitwaghchaure

erpnext/controllers/ @deepeshgarg007 @rohitwaghchaure
erpnext/patches/ @deepeshgarg007

.github/ @deepeshgarg007
pyproject.toml @ankush
pyproject.toml @akhilnarang
2 changes: 1 addition & 1 deletion erpnext/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

import frappe

__version__ = "14.74.5"
__version__ = "14.79.0"


def get_default_company(user=None):
Expand Down
2 changes: 1 addition & 1 deletion erpnext/accounts/deferred_revenue.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ def build_conditions(process_type, account, company):
)

if account:
conditions += f"AND {deferred_account}='{account}'"
conditions += f"AND {deferred_account}={frappe.db.escape(account)}"
elif company:
conditions += f"AND p.company = {frappe.db.escape(company)}"

Expand Down
4 changes: 2 additions & 2 deletions erpnext/accounts/doctype/account/account.js
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,8 @@ frappe.ui.form.on("Account", {
function () {
frappe.route_options = {
account: frm.doc.name,
from_date: frappe.sys_defaults.year_start_date,
to_date: frappe.sys_defaults.year_end_date,
from_date: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[1],
to_date: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[2],
company: frm.doc.company,
};
frappe.set_route("query-report", "General Ledger");
Expand Down
4 changes: 2 additions & 2 deletions erpnext/accounts/doctype/account/account_tree.js
Original file line number Diff line number Diff line change
Expand Up @@ -279,8 +279,8 @@ frappe.treeview_settings["Account"] = {
click: function (node, btn) {
frappe.route_options = {
account: node.label,
from_date: frappe.sys_defaults.year_start_date,
to_date: frappe.sys_defaults.year_end_date,
from_date: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[1],
to_date: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[2],
company:
frappe.treeview_settings["Account"].treeview.page.fields_dict.company.get_value(),
};
Expand Down
7 changes: 1 addition & 6 deletions erpnext/accounts/doctype/bank_account/bank_account.json
Original file line number Diff line number Diff line change
Expand Up @@ -224,11 +224,6 @@
"link_doctype": "Bank Guarantee",
"link_fieldname": "bank_account"
},
{
"group": "Transactions",
"link_doctype": "Payroll Entry",
"link_fieldname": "bank_account"
},
{
"group": "Transactions",
"link_doctype": "Bank Transaction",
Expand All @@ -255,7 +250,7 @@
"link_fieldname": "default_bank_account"
}
],
"modified": "2024-09-24 06:57:41.292970",
"modified": "2024-10-30 09:41:14.113414",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Bank Account",
Expand Down
2 changes: 1 addition & 1 deletion erpnext/accounts/doctype/bank_account/bank_account.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def autoname(self):
self.name = self.account_name + " - " + self.bank

def on_trash(self):
delete_contact_and_address("BankAccount", self.name)
delete_contact_and_address("Bank Account", self.name)

def validate(self):
self.validate_company()
Expand Down
2 changes: 1 addition & 1 deletion erpnext/accounts/doctype/bank_clearance/bank_clearance.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ def get_payment_entries(self):
"Payment Entry" as payment_document, name as payment_entry,
reference_no as cheque_number, reference_date as cheque_date,
if(paid_from=%(account)s, paid_amount + total_taxes_and_charges, 0) as credit,
if(paid_from=%(account)s, 0, received_amount) as debit,
if(paid_from=%(account)s, 0, received_amount + total_taxes_and_charges) as debit,
posting_date, ifnull(party,if(paid_from=%(account)s,paid_to,paid_from)) as against_account, clearance_date,
if(paid_to=%(account)s, paid_to_account_currency, paid_from_account_currency) as account_currency
from `tabPayment Entry`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

from erpnext import get_default_cost_center
from erpnext.accounts.doctype.bank_transaction.bank_transaction import get_total_allocated_amount
from erpnext.accounts.party import get_party_account
from erpnext.accounts.report.bank_reconciliation_statement.bank_reconciliation_statement import (
get_amounts_not_reflected_in_system,
get_entries,
Expand Down Expand Up @@ -284,54 +285,56 @@ def create_payment_entry_bts(
bank_transaction = frappe.db.get_values(
"Bank Transaction",
bank_transaction_name,
fieldname=["name", "unallocated_amount", "deposit", "bank_account"],
fieldname=["name", "unallocated_amount", "deposit", "bank_account", "currency"],
as_dict=True,
)[0]
paid_amount = bank_transaction.unallocated_amount
payment_type = "Receive" if bank_transaction.deposit > 0.0 else "Pay"

company_account = frappe.get_value("Bank Account", bank_transaction.bank_account, "account")
company = frappe.get_value("Account", company_account, "company")
payment_entry_dict = {
"company": company,
"payment_type": payment_type,
"reference_no": reference_number,
"reference_date": reference_date,
"party_type": party_type,
"party": party,
"posting_date": posting_date,
"paid_amount": paid_amount,
"received_amount": paid_amount,
}
payment_entry = frappe.new_doc("Payment Entry")

payment_entry.update(payment_entry_dict)

if mode_of_payment:
payment_entry.mode_of_payment = mode_of_payment
if project:
payment_entry.project = project
if cost_center:
payment_entry.cost_center = cost_center
if payment_type == "Receive":
payment_entry.paid_to = company_account
else:
payment_entry.paid_from = company_account
payment_type = "Receive" if bank_transaction.deposit > 0.0 else "Pay"

payment_entry.validate()
bank_account = frappe.get_cached_value("Bank Account", bank_transaction.bank_account, "account")
company = frappe.get_cached_value("Account", bank_account, "company")
party_account = get_party_account(party_type, party, company)

bank_currency = bank_transaction.currency
party_currency = frappe.get_cached_value("Account", party_account, "account_currency")

exc_rate = get_exchange_rate(bank_currency, party_currency, posting_date)

amt_in_bank_acc_currency = bank_transaction.unallocated_amount
amount_in_party_currency = bank_transaction.unallocated_amount * exc_rate

pe = frappe.new_doc("Payment Entry")
pe.payment_type = payment_type
pe.company = company
pe.reference_no = reference_number
pe.reference_date = reference_date
pe.party_type = party_type
pe.party = party
pe.posting_date = posting_date
pe.paid_from = party_account if payment_type == "Receive" else bank_account
pe.paid_to = party_account if payment_type == "Pay" else bank_account
pe.paid_from_account_currency = party_currency if payment_type == "Receive" else bank_currency
pe.paid_to_account_currency = party_currency if payment_type == "Pay" else bank_currency
pe.paid_amount = amount_in_party_currency if payment_type == "Receive" else amt_in_bank_acc_currency
pe.received_amount = amount_in_party_currency if payment_type == "Pay" else amt_in_bank_acc_currency
pe.mode_of_payment = mode_of_payment
pe.project = project
pe.cost_center = cost_center

pe.validate()

if allow_edit:
return payment_entry
return pe

payment_entry.insert()
pe.insert()
pe.submit()

payment_entry.submit()
vouchers = json.dumps(
[
{
"payment_doctype": "Payment Entry",
"payment_name": payment_entry.name,
"amount": paid_amount,
"payment_name": pe.name,
"amount": amt_in_bank_acc_currency,
}
]
)
Expand Down Expand Up @@ -455,8 +458,12 @@ def get_linked_payments(
def subtract_allocations(gl_account, vouchers):
"Look up & subtract any existing Bank Transaction allocations"
copied = []

voucher_docs = [(voucher[1], voucher[2]) for voucher in vouchers]
voucher_allocated_amounts = get_total_allocated_amount(voucher_docs)

for voucher in vouchers:
rows = get_total_allocated_amount(voucher[1], voucher[2])
rows = voucher_allocated_amounts.get((voucher[1], voucher[2])) or []
amount = None
for row in rows:
if row["gl_account"] == gl_account:
Expand Down
56 changes: 37 additions & 19 deletions erpnext/accounts/doctype/bank_transaction/bank_transaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
# For license information, please see license.txt

import frappe
from frappe import _
from frappe.model.docstatus import DocStatus
from frappe.utils import flt

Expand Down Expand Up @@ -92,10 +93,16 @@ def allocate_payment_entries(self):
- clear means: set the latest transaction date as clearance date
"""
remaining_amount = self.unallocated_amount
payment_entry_docs = [(pe.payment_document, pe.payment_entry) for pe in self.payment_entries]
pe_bt_allocations = get_total_allocated_amount(payment_entry_docs)

for payment_entry in self.payment_entries:
if payment_entry.allocated_amount == 0.0:
unallocated_amount, should_clear, latest_transaction = get_clearance_details(
self, payment_entry
self,
payment_entry,
pe_bt_allocations.get((payment_entry.payment_document, payment_entry.payment_entry))
or [],
)

if 0.0 == unallocated_amount:
Expand Down Expand Up @@ -156,13 +163,17 @@ def auto_set_party(self):
if self.party_type and self.party:
return

result = AutoMatchParty(
bank_party_account_number=self.bank_party_account_number,
bank_party_iban=self.bank_party_iban,
bank_party_name=self.bank_party_name,
description=self.description,
deposit=self.deposit,
).match()
result = None
try:
result = AutoMatchParty(
bank_party_account_number=self.bank_party_account_number,
bank_party_iban=self.bank_party_iban,
bank_party_name=self.bank_party_name,
description=self.description,
deposit=self.deposit,
).match()
except Exception:
frappe.log_error(title=_("Error in party matching for Bank Transaction {0}").format(self.name))

if result:
party_type, party = result
Expand All @@ -177,7 +188,7 @@ def get_doctypes_for_bank_reconciliation():
return frappe.get_hooks("bank_reconciliation_doctypes")


def get_clearance_details(transaction, payment_entry):
def get_clearance_details(transaction, payment_entry, bt_allocations):
"""
There should only be one bank gle for a voucher.
Could be none for a Bank Transaction.
Expand All @@ -186,7 +197,6 @@ def get_clearance_details(transaction, payment_entry):
"""
gl_bank_account = frappe.db.get_value("Bank Account", transaction.bank_account, "account")
gles = get_related_bank_gl_entries(payment_entry.payment_document, payment_entry.payment_entry)
bt_allocations = get_total_allocated_amount(payment_entry.payment_document, payment_entry.payment_entry)

unallocated_amount = min(
transaction.unallocated_amount,
Expand Down Expand Up @@ -242,44 +252,52 @@ def get_related_bank_gl_entries(doctype, docname):
return result


def get_total_allocated_amount(doctype, docname):
def get_total_allocated_amount(docs):
"""
Gets the sum of allocations for a voucher on each bank GL account
along with the latest bank transaction name & date
NOTE: query may also include just saved vouchers/payments but with zero allocated_amount
"""
if not docs:
return {}

# nosemgrep: frappe-semgrep-rules.rules.frappe-using-db-sql
result = frappe.db.sql(
"""
SELECT total, latest_name, latest_date, gl_account FROM (
SELECT total, latest_name, latest_date, gl_account, payment_document, payment_entry FROM (
SELECT
ROW_NUMBER() OVER w AS rownum,
SUM(btp.allocated_amount) OVER(PARTITION BY ba.account) AS total,
SUM(btp.allocated_amount) OVER(PARTITION BY ba.account, btp.payment_document, btp.payment_entry) AS total,
FIRST_VALUE(bt.name) OVER w AS latest_name,
FIRST_VALUE(bt.date) OVER w AS latest_date,
ba.account AS gl_account
ba.account AS gl_account,
btp.payment_document,
btp.payment_entry
FROM
`tabBank Transaction Payments` btp
LEFT JOIN `tabBank Transaction` bt ON bt.name=btp.parent
LEFT JOIN `tabBank Account` ba ON ba.name=bt.bank_account
WHERE
btp.payment_document = %(doctype)s
AND btp.payment_entry = %(docname)s
(btp.payment_document, btp.payment_entry) IN %(docs)s
AND bt.docstatus = 1
WINDOW w AS (PARTITION BY ba.account ORDER BY bt.date desc)
WINDOW w AS (PARTITION BY ba.account, btp.payment_document, btp.payment_entry ORDER BY bt.date DESC)
) temp
WHERE
rownum = 1
""",
dict(doctype=doctype, docname=docname),
dict(docs=docs),
as_dict=True,
)

payment_allocation_details = {}
for row in result:
# Why is this *sometimes* a byte string?
if isinstance(row["latest_name"], bytes):
row["latest_name"] = row["latest_name"].decode()
row["latest_date"] = frappe.utils.getdate(row["latest_date"])
return result
payment_allocation_details.setdefault((row["payment_document"], row["payment_entry"]), []).append(row)

return payment_allocation_details


def get_paid_amount(payment_entry, currency, gl_bank_account):
Expand Down
21 changes: 14 additions & 7 deletions erpnext/accounts/doctype/budget/budget.py
Original file line number Diff line number Diff line change
Expand Up @@ -460,13 +460,20 @@ def get_actual_expense(args):
def get_accumulated_monthly_budget(monthly_distribution, posting_date, fiscal_year, annual_budget):
distribution = {}
if monthly_distribution:
for d in frappe.db.sql(
"""select mdp.month, mdp.percentage_allocation
from `tabMonthly Distribution Percentage` mdp, `tabMonthly Distribution` md
where mdp.parent=md.name and md.fiscal_year=%s""",
fiscal_year,
as_dict=1,
):
mdp = frappe.qb.DocType("Monthly Distribution Percentage")
md = frappe.qb.DocType("Monthly Distribution")

res = (
frappe.qb.from_(mdp)
.join(md)
.on(mdp.parent == md.name)
.select(mdp.month, mdp.percentage_allocation)
.where(md.fiscal_year == fiscal_year)
.where(md.name == monthly_distribution)
.run(as_dict=True)
)

for d in res:
distribution.setdefault(d.month, d.percentage_allocation)

dt = frappe.db.get_value("Fiscal Year", fiscal_year, "year_start_date")
Expand Down
Loading

0 comments on commit 65ba7bc

Please sign in to comment.