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():