diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.json b/erpnext/accounts/doctype/journal_entry/journal_entry.json
index 906760ec312..b229a20f7eb 100644
--- a/erpnext/accounts/doctype/journal_entry/journal_entry.json
+++ b/erpnext/accounts/doctype/journal_entry/journal_entry.json
@@ -557,7 +557,7 @@
"table_fieldname": "payment_entries"
}
],
- "modified": "2023-11-23 12:11:04.128015",
+ "modified": "2024-07-18 15:32:29.413598",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Journal Entry",
diff --git a/erpnext/accounts/doctype/payment_order/payment_order.js b/erpnext/accounts/doctype/payment_order/payment_order.js
index a041f290639..0180d5550d4 100644
--- a/erpnext/accounts/doctype/payment_order/payment_order.js
+++ b/erpnext/accounts/doctype/payment_order/payment_order.js
@@ -36,7 +36,7 @@ frappe.ui.form.on("Payment Order", {
// payment Entry
if (frm.doc.docstatus === 1 && frm.doc.payment_order_type === "Payment Request") {
- frm.add_custom_button(__("Create Payment Entries"), function () {
+ frm.add_custom_button(__("Create Journal Entries"), function () {
frm.trigger("make_payment_records");
});
}
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
index c29ec5fd12f..ff5550489c2 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
@@ -59,25 +59,6 @@ erpnext.accounts.PurchaseInvoice = class PurchaseInvoice extends erpnext.buying.
this.show_stock_ledger();
}
- if (this.frm.doc.repost_required && this.frm.doc.docstatus===1) {
- this.frm.set_intro(__("Accounting entries for this invoice need to be reposted. Please click on 'Repost' button to update."));
- this.frm.add_custom_button(__('Repost Accounting Entries'),
- () => {
- this.frm.call({
- doc: this.frm.doc,
- method: 'repost_accounting_entries',
- freeze: true,
- freeze_message: __('Reposting...'),
- callback: (r) => {
- if (!r.exc) {
- frappe.msgprint(__('Accounting Entries are reposted.'));
- me.frm.refresh();
- }
- }
- });
- }).removeClass('btn-default').addClass('btn-warning');
- }
-
if(!doc.is_return && doc.docstatus == 1 && doc.outstanding_amount != 0){
if(doc.on_hold) {
this.frm.add_custom_button(
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
index 6b0ec8e8c85..1a4d497b23b 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
@@ -170,7 +170,6 @@
"against_expense_account",
"column_break_63",
"unrealized_profit_loss_account",
- "repost_required",
"subscription_section",
"auto_repeat",
"update_auto_repeat_reference",
@@ -361,7 +360,8 @@
"description": "Once set, this invoice will be on hold till the set date",
"fieldname": "release_date",
"fieldtype": "Date",
- "label": "Release Date"
+ "label": "Release Date",
+ "search_index": 1
},
{
"fieldname": "cb_17",
@@ -1590,15 +1590,6 @@
"fieldtype": "Check",
"label": "Use Company Default Round Off Cost Center"
},
- {
- "default": "0",
- "fieldname": "repost_required",
- "fieldtype": "Check",
- "hidden": 1,
- "label": "Repost Required",
- "options": "Account",
- "read_only": 1
- },
{
"default": "0",
"fieldname": "use_transaction_date_exchange_rate",
@@ -1619,7 +1610,7 @@
"idx": 204,
"is_submittable": 1,
"links": [],
- "modified": "2024-03-20 15:57:00.736868",
+ "modified": "2024-07-25 19:42:36.931278",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Purchase Invoice",
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
index fd018309282..698744b6151 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
@@ -590,18 +590,17 @@ class PurchaseInvoice(BuyingController):
self.process_common_party_accounting()
def on_update_after_submit(self):
- if hasattr(self, "repost_required"):
- fields_to_check = [
- "cash_bank_account",
- "write_off_account",
- "unrealized_profit_loss_account",
- ]
- child_tables = {"items": ("expense_account",), "taxes": ("account_head",)}
- self.needs_repost = self.check_if_fields_updated(fields_to_check, child_tables)
- if self.needs_repost:
- self.validate_for_repost()
- self.db_set("repost_required", self.needs_repost)
- self.repost_accounting_entries()
+ fields_to_check = [
+ "cash_bank_account",
+ "write_off_account",
+ "unrealized_profit_loss_account",
+ "is_opening",
+ ]
+ child_tables = {"items": ("expense_account",), "taxes": ("account_head",)}
+ self.needs_repost = self.check_if_fields_updated(fields_to_check, child_tables)
+ if self.needs_repost:
+ self.validate_for_repost()
+ self.repost_accounting_entries()
def make_gl_entries(self, gl_entries=None, from_repost=False):
update_outstanding = "No" if (cint(self.is_paid) or self.write_off_account) else "Yes"
@@ -1499,6 +1498,9 @@ class PurchaseInvoice(BuyingController):
self.db_set("release_date", None)
def set_tax_withholding(self):
+ self.set("advance_tax", [])
+ self.set("tax_withheld_vouchers", [])
+
if not self.apply_tds:
return
@@ -1540,8 +1542,6 @@ class PurchaseInvoice(BuyingController):
self.remove(d)
## Add pending vouchers on which tax was withheld
- self.set("tax_withheld_vouchers", [])
-
for voucher_no, voucher_details in voucher_wise_amount.items():
self.append(
"tax_withheld_vouchers",
@@ -1556,7 +1556,6 @@ class PurchaseInvoice(BuyingController):
self.calculate_taxes_and_totals()
def allocate_advance_tds(self, tax_withholding_details, advance_taxes):
- self.set("advance_tax", [])
for tax in advance_taxes:
allocated_amount = 0
pending_amount = flt(tax.tax_amount - tax.allocated_amount)
diff --git a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
index b3a3a9634fb..f1f7f54a135 100644
--- a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
@@ -1917,8 +1917,6 @@ class TestPurchaseInvoice(FrappeTestCase, StockTestMixin):
["Service - _TC", 1000, 0.0, nowdate()],
]
check_gl_entries(self, pi.name, expected_gle, nowdate())
- pi.load_from_db()
- self.assertFalse(pi.repost_required)
def test_default_cost_center_for_purchase(self):
from erpnext.accounts.doctype.cost_center.test_cost_center import create_cost_center
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
index 4c899b901ca..bc458ffa272 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
@@ -49,25 +49,6 @@ erpnext.accounts.SalesInvoiceController = class SalesInvoiceController extends e
this.frm.toggle_reqd("due_date", !this.frm.doc.is_return);
- if (this.frm.doc.repost_required && this.frm.doc.docstatus===1) {
- this.frm.set_intro(__("Accounting entries for this invoice needs to be reposted. Please click on 'Repost' button to update."));
- this.frm.add_custom_button(__('Repost Accounting Entries'),
- () => {
- this.frm.call({
- doc: this.frm.doc,
- method: 'repost_accounting_entries',
- freeze: true,
- freeze_message: __('Reposting...'),
- callback: (r) => {
- if (!r.exc) {
- frappe.msgprint(__('Accounting Entries are reposted'));
- me.frm.refresh();
- }
- }
- });
- }).removeClass('btn-default').addClass('btn-warning');
- }
-
if (this.frm.doc.is_return) {
this.frm.return_print_format = "Sales Invoice Return";
}
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
index cf7d01c4035..632392511bd 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
@@ -213,7 +213,6 @@
"is_internal_customer",
"is_discounted",
"remarks",
- "repost_required",
"connections_tab"
],
"fields": [
@@ -2184,7 +2183,7 @@
"link_fieldname": "consolidated_invoice"
}
],
- "modified": "2024-05-08 18:02:28.549041",
+ "modified": "2024-07-18 15:30:39.428519",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice",
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
index d01e494e60d..a254c917189 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
@@ -385,7 +385,6 @@ class SalesInvoice(SellingController):
self.repost_future_sle_and_gle()
self.db_set("status", "Cancelled")
- self.db_set("repost_required", 0)
if frappe.db.get_single_value("Selling Settings", "sales_update_frequency") == "Each Transaction":
update_company_current_month_sales(self.company)
@@ -532,24 +531,23 @@ class SalesInvoice(SellingController):
data.sales_invoice = sales_invoice
def on_update_after_submit(self):
- if hasattr(self, "repost_required"):
- fields_to_check = [
- "additional_discount_account",
- "cash_bank_account",
- "account_for_change_amount",
- "write_off_account",
- "loyalty_redemption_account",
- "unrealized_profit_loss_account",
- ]
- child_tables = {
- "items": ("income_account", "expense_account", "discount_account"),
- "taxes": ("account_head",),
- }
- self.needs_repost = self.check_if_fields_updated(fields_to_check, child_tables)
- if self.needs_repost:
- self.validate_for_repost()
- self.db_set("repost_required", self.needs_repost)
- self.repost_accounting_entries()
+ fields_to_check = [
+ "additional_discount_account",
+ "cash_bank_account",
+ "account_for_change_amount",
+ "write_off_account",
+ "loyalty_redemption_account",
+ "unrealized_profit_loss_account",
+ "is_opening",
+ ]
+ child_tables = {
+ "items": ("income_account", "expense_account", "discount_account"),
+ "taxes": ("account_head",),
+ }
+ self.needs_repost = self.check_if_fields_updated(fields_to_check, child_tables)
+ if self.needs_repost:
+ self.validate_for_repost()
+ self.repost_accounting_entries()
def set_paid_amount(self):
paid_amount = 0.0
diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
index 159ed405686..9e81fcf502f 100644
--- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
@@ -2896,9 +2896,6 @@ class TestSalesInvoice(FrappeTestCase):
check_gl_entries(self, si.name, expected_gle, add_days(nowdate(), -1))
- si.load_from_db()
- self.assertFalse(si.repost_required)
-
def test_asset_depreciation_on_sale_with_pro_rata(self):
"""
Tests if an Asset set to depreciate yearly on June 30, that gets sold on Sept 30, creates an additional depreciation entry on its date of sale.
diff --git a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py
index d8b2079e5ac..c26c7568924 100644
--- a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py
+++ b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py
@@ -236,6 +236,11 @@ def get_tax_amount(party_type, parties, inv, tax_details, posting_date, pan_no=N
vouchers, voucher_wise_amount = get_invoice_vouchers(
parties, tax_details, inv.company, party_type=party_type
)
+
+ payment_entry_vouchers = get_payment_entry_vouchers(
+ parties, tax_details, inv.company, party_type=party_type
+ )
+
advance_vouchers = get_advance_vouchers(
parties,
company=inv.company,
@@ -243,7 +248,8 @@ def get_tax_amount(party_type, parties, inv, tax_details, posting_date, pan_no=N
to_date=tax_details.to_date,
party_type=party_type,
)
- taxable_vouchers = vouchers + advance_vouchers
+
+ taxable_vouchers = vouchers + advance_vouchers + payment_entry_vouchers
tax_deducted_on_advances = 0
if inv.doctype == "Purchase Invoice":
@@ -355,6 +361,20 @@ def get_invoice_vouchers(parties, tax_details, company, party_type="Supplier"):
return vouchers, voucher_wise_amount
+def get_payment_entry_vouchers(parties, tax_details, company, party_type="Supplier"):
+ payment_entry_filters = {
+ "party_type": party_type,
+ "party": ("in", parties),
+ "docstatus": 1,
+ "apply_tax_withholding_amount": 1,
+ "posting_date": ["between", (tax_details.from_date, tax_details.to_date)],
+ "tax_withholding_category": tax_details.get("tax_withholding_category"),
+ "company": company,
+ }
+
+ return frappe.db.get_all("Payment Entry", filters=payment_entry_filters, pluck="name")
+
+
def get_advance_vouchers(parties, company=None, from_date=None, to_date=None, party_type="Supplier"):
"""
Use Payment Ledger to fetch unallocated Advance Payments
diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
index f17cab8d112..11177a10772 100644
--- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
+++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
@@ -139,6 +139,7 @@ class ReceivablePayableReport:
paid_in_account_currency=0.0,
credit_note_in_account_currency=0.0,
outstanding_in_account_currency=0.0,
+ cost_center=ple.cost_center,
)
self.get_invoices(ple)
@@ -253,7 +254,7 @@ class ReceivablePayableReport:
row.paid -= amount
row.paid_in_account_currency -= amount_in_account_currency
- if ple.cost_center:
+ if not row.cost_center and ple.cost_center:
row.cost_center = str(ple.cost_center)
def update_sub_total_row(self, row, party):
diff --git a/erpnext/accounts/report/accounts_receivable/test_accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/test_accounts_receivable.py
index 5e2adc42d84..c4baa4e4842 100644
--- a/erpnext/accounts/report/accounts_receivable/test_accounts_receivable.py
+++ b/erpnext/accounts/report/accounts_receivable/test_accounts_receivable.py
@@ -53,11 +53,13 @@ class TestAccountsReceivable(AccountsTestMixin, FrappeTestCase):
si = si.submit()
return si
- def create_payment_entry(self, docname):
+ def create_payment_entry(self, docname, do_not_submit=False):
pe = get_payment_entry("Sales Invoice", docname, bank_account=self.cash, party_amount=40)
pe.paid_from = self.debit_to
pe.insert()
- pe.submit()
+ if not do_not_submit:
+ pe.submit()
+ return pe
def create_credit_note(self, docname, do_not_submit=False):
credit_note = create_sales_invoice(
@@ -984,3 +986,40 @@ class TestAccountsReceivable(AccountsTestMixin, FrappeTestCase):
expected_data_after_payment,
[row.invoice_grand_total, row.invoiced, row.paid, row.outstanding],
)
+
+ def test_cost_center_on_report_output(self):
+ filters = {
+ "company": self.company,
+ "report_date": today(),
+ "range1": 30,
+ "range2": 60,
+ "range3": 90,
+ "range4": 120,
+ }
+
+ # check invoice grand total and invoiced column's value for 3 payment terms
+ si = self.create_sales_invoice(no_payment_schedule=True, do_not_submit=True)
+ si.cost_center = self.cost_center
+ si.save().submit()
+
+ new_cc = frappe.get_doc(
+ {
+ "doctype": "Cost Center",
+ "cost_center_name": "East Wing",
+ "parent_cost_center": self.company + " - " + self.company_abbr,
+ "company": self.company,
+ }
+ )
+ new_cc.save()
+
+ # check invoice grand total, invoiced, paid and outstanding column's value after payment
+ pe = self.create_payment_entry(si.name, do_not_submit=True)
+ pe.cost_center = new_cc.name
+ pe.save().submit()
+ report = execute(filters)
+
+ expected_data_after_payment = [si.name, si.cost_center, 60]
+
+ self.assertEqual(len(report[1]), 1)
+ row = report[1][0]
+ self.assertEqual(expected_data_after_payment, [row.voucher_no, row.cost_center, row.outstanding])
diff --git a/erpnext/accounts/report/gross_profit/gross_profit.py b/erpnext/accounts/report/gross_profit/gross_profit.py
index 5d656bb0a79..d6a0acce427 100644
--- a/erpnext/accounts/report/gross_profit/gross_profit.py
+++ b/erpnext/accounts/report/gross_profit/gross_profit.py
@@ -694,7 +694,8 @@ class GrossProfitGenerator:
def get_average_buying_rate(self, row, item_code):
args = row
- if item_code not in self.average_buying_rate:
+ key = (item_code, row.warehouse)
+ if key not in self.average_buying_rate:
args.update(
{
"voucher_type": row.parenttype,
@@ -705,9 +706,9 @@ class GrossProfitGenerator:
)
average_buying_rate = get_incoming_rate(args)
- self.average_buying_rate[item_code] = flt(average_buying_rate)
+ self.average_buying_rate[key] = flt(average_buying_rate)
- return self.average_buying_rate[item_code]
+ return self.average_buying_rate[key]
def get_last_purchase_rate(self, item_code, row):
purchase_invoice = frappe.qb.DocType("Purchase Invoice")
diff --git a/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py b/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py
index c5d732ed697..f55fef068c1 100644
--- a/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py
+++ b/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py
@@ -312,8 +312,9 @@ def apply_conditions(query, pi, pii, filters):
def get_items(filters, additional_table_columns):
- pi = frappe.qb.DocType("Purchase Invoice")
- pii = frappe.qb.DocType("Purchase Invoice Item")
+ doctype = "Purchase Invoice"
+ pi = frappe.qb.DocType(doctype)
+ pii = frappe.qb.DocType(f"{doctype} Item")
Item = frappe.qb.DocType("Item")
query = (
frappe.qb.from_(pi)
@@ -350,6 +351,7 @@ def get_items(filters, additional_table_columns):
pi.mode_of_payment,
)
.where(pi.docstatus == 1)
+ .where(pii.parenttype == doctype)
)
if filters.get("supplier"):
diff --git a/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py b/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py
index cd50b118715..7bb73143c28 100644
--- a/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py
+++ b/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py
@@ -407,8 +407,9 @@ def apply_group_by_conditions(query, si, ii, filters):
def get_items(filters, additional_query_columns, additional_conditions=None):
- si = frappe.qb.DocType("Sales Invoice")
- sii = frappe.qb.DocType("Sales Invoice Item")
+ doctype = "Sales Invoice"
+ si = frappe.qb.DocType(doctype)
+ sii = frappe.qb.DocType(f"{doctype} Item")
item = frappe.qb.DocType("Item")
query = (
@@ -456,6 +457,7 @@ def get_items(filters, additional_query_columns, additional_conditions=None):
sii.qty,
)
.where(si.docstatus == 1)
+ .where(sii.parenttype == doctype)
)
if additional_query_columns:
diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py
index 7e67085f5dd..0ae4db3673c 100644
--- a/erpnext/accounts/utils.py
+++ b/erpnext/accounts/utils.py
@@ -1571,6 +1571,18 @@ def auto_create_exchange_rate_revaluation_weekly() -> None:
create_err_and_its_journals(companies)
+def auto_create_exchange_rate_revaluation_monthly() -> None:
+ """
+ Executed by background job
+ """
+ companies = frappe.db.get_all(
+ "Company",
+ filters={"auto_exchange_rate_revaluation": 1, "auto_err_frequency": "Montly"},
+ fields=["name", "submit_err_jv"],
+ )
+ create_err_and_its_journals(companies)
+
+
def get_payment_ledger_entries(gl_entries, cancel=0):
ple_map = []
if gl_entries:
diff --git a/erpnext/buying/report/purchase_order_analysis/purchase_order_analysis.py b/erpnext/buying/report/purchase_order_analysis/purchase_order_analysis.py
index b23c3f50b9a..da1c70d3179 100644
--- a/erpnext/buying/report/purchase_order_analysis/purchase_order_analysis.py
+++ b/erpnext/buying/report/purchase_order_analysis/purchase_order_analysis.py
@@ -43,9 +43,10 @@ def get_data(filters):
query = (
frappe.qb.from_(po)
- .from_(po_item)
+ .inner_join(po_item)
+ .on(po_item.parent == po.name)
.left_join(pi_item)
- .on(pi_item.po_detail == po_item.name)
+ .on((pi_item.po_detail == po_item.name) & (pi_item.docstatus == 1))
.select(
po.transaction_date.as_("date"),
po_item.schedule_date.as_("required_date"),
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index 792a0c02caf..a9494cf6e80 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -2376,16 +2376,12 @@ class AccountsController(TransactionBase):
@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"))
+ 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()
@frappe.whitelist()
diff --git a/erpnext/hooks.py b/erpnext/hooks.py
index 021cf4deb63..ae6a15bfd8d 100644
--- a/erpnext/hooks.py
+++ b/erpnext/hooks.py
@@ -463,6 +463,7 @@ scheduler_events = {
"monthly_long": [
"erpnext.accounts.deferred_revenue.process_deferred_accounting",
"erpnext.loan_management.doctype.process_loan_interest_accrual.process_loan_interest_accrual.process_loan_interest_accrual_for_demand_loans",
+ "erpnext.accounts.utils.auto_create_exchange_rate_revaluation_monthly",
],
}
diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js
index 6828dc9c745..d4b978b6e7e 100644
--- a/erpnext/public/js/controllers/transaction.js
+++ b/erpnext/public/js/controllers/transaction.js
@@ -1645,6 +1645,12 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe
apply_price_list(item, reset_plc_conversion) {
// We need to reset plc_conversion_rate sometimes because the call to
// `erpnext.stock.get_item_details.apply_price_list` is sensitive to its value
+
+
+ if (this.frm.doc.doctype === "Material Request") {
+ return;
+ }
+
if (!reset_plc_conversion) {
this.frm.set_value("plc_conversion_rate", "");
}
@@ -1660,7 +1666,7 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe
me.in_apply_price_list = true;
return this.frm.call({
method: "erpnext.stock.get_item_details.apply_price_list",
- args: { args: args },
+ args: { args: args, doc: me.frm.doc },
callback: function(r) {
if (!r.exc) {
frappe.run_serially([
diff --git a/erpnext/setup/doctype/company/company.json b/erpnext/setup/doctype/company/company.json
index 70a0872a2c4..fd121336827 100644
--- a/erpnext/setup/doctype/company/company.json
+++ b/erpnext/setup/doctype/company/company.json
@@ -698,7 +698,7 @@
"fieldname": "auto_err_frequency",
"fieldtype": "Select",
"label": "Frequency",
- "options": "Daily\nWeekly"
+ "options": "Daily\nWeekly\nMonthly"
},
{
"default": "0",
@@ -712,7 +712,7 @@
"image_field": "company_logo",
"is_tree": 1,
"links": [],
- "modified": "2024-05-27 17:32:49.057386",
+ "modified": "2024-07-24 18:17:56.413971",
"modified_by": "Administrator",
"module": "Setup",
"name": "Company",
diff --git a/erpnext/setup/setup_wizard/operations/taxes_setup.py b/erpnext/setup/setup_wizard/operations/taxes_setup.py
index 14fcb800ae7..354a68434b0 100644
--- a/erpnext/setup/setup_wizard/operations/taxes_setup.py
+++ b/erpnext/setup/setup_wizard/operations/taxes_setup.py
@@ -162,7 +162,7 @@ def make_taxes_and_charges_template(company_name, doctype, template):
doc.flags.ignore_links = True
doc.flags.ignore_validate = True
doc.flags.ignore_mandatory = True
- doc.insert(ignore_permissions=True)
+ doc.insert(ignore_permissions=True, ignore_if_duplicate=True)
return doc
@@ -195,7 +195,7 @@ def make_item_tax_template(company_name, template):
# Ingone validations to make doctypes faster
doc.flags.ignore_links = True
doc.flags.ignore_validate = True
- doc.insert(ignore_permissions=True)
+ doc.insert(ignore_permissions=True, ignore_if_duplicate=True)
return doc
@@ -232,7 +232,7 @@ def get_or_create_account(company_name, account):
doc = frappe.get_doc(account)
doc.flags.ignore_links = True
doc.flags.ignore_validate = True
- doc.insert(ignore_permissions=True, ignore_mandatory=True)
+ doc.insert(ignore_permissions=True, ignore_mandatory=True, ignore_if_duplicate=True)
return doc
diff --git a/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py b/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py
index 60a7707228d..c9572d12b64 100644
--- a/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py
+++ b/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py
@@ -237,9 +237,23 @@ def repost(doc):
doc.log_error("Unable to repost item valuation")
message = frappe.message_log.pop() if frappe.message_log else ""
+
+ status = "Failed"
+ # If failed because of timeout, set status to In Progress
+ if traceback and "timeout" in traceback.lower():
+ status = "In Progress"
+
if traceback:
message += "
" + "Traceback:
" + traceback
- frappe.db.set_value(doc.doctype, doc.name, "error_log", message)
+
+ frappe.db.set_value(
+ doc.doctype,
+ doc.name,
+ {
+ "error_log": message,
+ "status": status,
+ },
+ )
outgoing_email_account = frappe.get_cached_value(
"Email Account", {"default_outgoing": 1, "enable_outgoing": 1}, "name"
@@ -247,7 +261,6 @@ def repost(doc):
if outgoing_email_account and not isinstance(e, RecoverableErrors):
notify_error_to_stock_managers(doc, message)
- doc.set_status("Failed")
finally:
if not frappe.flags.in_test:
frappe.db.commit()
diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py
index 364a681cff4..45b251f6630 100644
--- a/erpnext/stock/get_item_details.py
+++ b/erpnext/stock/get_item_details.py
@@ -1297,7 +1297,7 @@ def get_batch_qty(batch_no, warehouse, item_code):
@frappe.whitelist()
-def apply_price_list(args, as_doc=False):
+def apply_price_list(args, as_doc=False, doc=None):
"""Apply pricelist on a document-like dict object and return as
{'parent': dict, 'children': list}
@@ -1336,7 +1336,7 @@ def apply_price_list(args, as_doc=False):
for item in item_list:
args_copy = frappe._dict(args.copy())
args_copy.update(item)
- item_details = apply_price_list_on_item(args_copy)
+ item_details = apply_price_list_on_item(args_copy, doc=doc)
children.append(item_details)
if as_doc:
@@ -1354,10 +1354,10 @@ def apply_price_list(args, as_doc=False):
return {"parent": parent, "children": children}
-def apply_price_list_on_item(args):
+def apply_price_list_on_item(args, doc=None):
item_doc = frappe.db.get_value("Item", args.item_code, ["name", "variant_of"], as_dict=1)
item_details = get_price_list_rate(args, item_doc)
- item_details.update(get_pricing_rule_for_item(args))
+ item_details.update(get_pricing_rule_for_item(args, doc=doc))
return item_details
diff --git a/erpnext/stock/report/product_bundle_balance/product_bundle_balance.js b/erpnext/stock/report/product_bundle_balance/product_bundle_balance.js
index 5cef5c70341..f8779c64e2d 100644
--- a/erpnext/stock/report/product_bundle_balance/product_bundle_balance.js
+++ b/erpnext/stock/report/product_bundle_balance/product_bundle_balance.js
@@ -3,6 +3,14 @@
frappe.query_reports["Product Bundle Balance"] = {
filters: [
+ {
+ fieldname: "company",
+ label: __("Company"),
+ fieldtype: "Link",
+ options: "Company",
+ default: frappe.defaults.get_user_default("Company"),
+ reqd: 1,
+ },
{
fieldname: "date",
label: __("Date"),
diff --git a/erpnext/stock/report/product_bundle_balance/product_bundle_balance.py b/erpnext/stock/report/product_bundle_balance/product_bundle_balance.py
index dd79e7fcaf5..10f8650b525 100644
--- a/erpnext/stock/report/product_bundle_balance/product_bundle_balance.py
+++ b/erpnext/stock/report/product_bundle_balance/product_bundle_balance.py
@@ -224,6 +224,9 @@ def get_stock_ledger_entries(filters, items):
.where((sle2.name.isnull()) & (sle.docstatus < 2) & (sle.item_code.isin(items)))
)
+ if filters.get("company"):
+ query = query.where(sle.company == filters.get("company"))
+
if date := filters.get("date"):
query = query.where(sle.posting_date <= date)
else:
@@ -237,7 +240,7 @@ def get_stock_ledger_entries(filters, items):
if warehouse_details:
wh = frappe.qb.DocType("Warehouse")
query = query.where(
- ExistsCriterion(
+ sle.warehouse.isin(
frappe.qb.from_(wh)
.select(wh.name)
.where((wh.lft >= warehouse_details.lft) & (wh.rgt <= warehouse_details.rgt))
diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py
index 71f4ca00707..42918f56a23 100644
--- a/erpnext/stock/stock_ledger.py
+++ b/erpnext/stock/stock_ledger.py
@@ -209,7 +209,9 @@ def repost_future_sle(
)
affected_transactions.update(obj.affected_transactions)
- distinct_item_warehouses[(args[i].get("item_code"), args[i].get("warehouse"))].reposting_status = True
+ key = (args[i].get("item_code"), args[i].get("warehouse"))
+ if distinct_item_warehouses.get(key):
+ distinct_item_warehouses[key].reposting_status = True
if obj.new_items_found:
for _item_wh, data in distinct_item_warehouses.items():