diff --git a/erpnext/accounts/deferred_revenue.py b/erpnext/accounts/deferred_revenue.py
index a48ce9b4c637..cd34bf7f8501 100644
--- a/erpnext/accounts/deferred_revenue.py
+++ b/erpnext/accounts/deferred_revenue.py
@@ -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)}"
diff --git a/erpnext/accounts/doctype/bank_clearance/bank_clearance.py b/erpnext/accounts/doctype/bank_clearance/bank_clearance.py
index 92abb8cea89b..ac7883fce138 100644
--- a/erpnext/accounts/doctype/bank_clearance/bank_clearance.py
+++ b/erpnext/accounts/doctype/bank_clearance/bank_clearance.py
@@ -168,7 +168,7 @@ def get_payment_entries_for_bank_clearance(
"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`
diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py
index 593fa48e8560..47626492e845 100644
--- a/erpnext/accounts/doctype/journal_entry/journal_entry.py
+++ b/erpnext/accounts/doctype/journal_entry/journal_entry.py
@@ -259,7 +259,7 @@ def validate_depr_entry_voucher_type(self):
frappe.throw(_("Journal Entry type should be set as Depreciation Entry for asset depreciation"))
def validate_stock_accounts(self):
- stock_accounts = get_stock_accounts(self.company, self.doctype, self.name)
+ stock_accounts = get_stock_accounts(self.company, accounts=self.accounts)
for account in stock_accounts:
account_bal, stock_bal, warehouse_list = get_stock_and_account_balance(
account, self.posting_date, self.company
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py
index 7885d8251298..b645d92cb64f 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.py
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py
@@ -2486,7 +2486,9 @@ def get_party_details(company, party_type, party, date, cost_center=None):
account_balance = get_balance_on(party_account, date, cost_center=cost_center)
_party_name = "title" if party_type == "Shareholder" else party_type.lower() + "_name"
party_name = frappe.db.get_value(party_type, party, _party_name)
- party_balance = get_balance_on(party_type=party_type, party=party, cost_center=cost_center)
+ party_balance = get_balance_on(
+ party_type=party_type, party=party, company=company, cost_center=cost_center
+ )
if party_type in ["Customer", "Supplier"]:
party_bank_account = get_party_bank_account(party_type, party)
bank_account = get_default_company_bank_account(company, party_type, party)
diff --git a/erpnext/accounts/doctype/payment_request/payment_request.py b/erpnext/accounts/doctype/payment_request/payment_request.py
index fd07551897a8..462cae95ba5b 100644
--- a/erpnext/accounts/doctype/payment_request/payment_request.py
+++ b/erpnext/accounts/doctype/payment_request/payment_request.py
@@ -20,6 +20,15 @@
from erpnext.accounts.utils import get_account_currency, get_currency_precision
from erpnext.utilities import payment_app_import_guard
+ALLOWED_DOCTYPES_FOR_PAYMENT_REQUEST = [
+ "Sales Order",
+ "Purchase Order",
+ "Sales Invoice",
+ "Purchase Invoice",
+ "POS Invoice",
+ "Fees",
+]
+
def _get_payment_gateway_controller(*args, **kwargs):
with payment_app_import_guard():
@@ -525,6 +534,9 @@ def make_payment_request(**args):
args = frappe._dict(args)
+ if args.dt not in ALLOWED_DOCTYPES_FOR_PAYMENT_REQUEST:
+ frappe.throw(_("Payment Requests cannot be created against: {0}").format(frappe.bold(args.dt)))
+
ref_doc = frappe.get_doc(args.dt, args.dn)
gateway_account = get_gateway_details(args) or frappe._dict()
diff --git a/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.js b/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.js
index c171713dc611..5711b27da04b 100644
--- a/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.js
+++ b/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.js
@@ -80,8 +80,10 @@ frappe.ui.form.on("POS Closing Entry", {
) {
reset_values(frm);
frappe.run_serially([
+ () => frappe.dom.freeze(__("Loading Invoices! Please Wait...")),
() => frm.trigger("set_opening_amounts"),
() => frm.trigger("get_pos_invoices"),
+ () => frappe.dom.unfreeze(),
]);
}
},
diff --git a/erpnext/accounts/doctype/pos_invoice/pos_invoice.js b/erpnext/accounts/doctype/pos_invoice/pos_invoice.js
index 8707ee88860d..deb8bd7529db 100644
--- a/erpnext/accounts/doctype/pos_invoice/pos_invoice.js
+++ b/erpnext/accounts/doctype/pos_invoice/pos_invoice.js
@@ -57,6 +57,7 @@ erpnext.selling.POSInvoiceController = class POSInvoiceController extends erpnex
}
onload_post_render(frm) {
+ super.onload_post_render();
this.pos_profile(frm);
}
diff --git a/erpnext/accounts/doctype/pricing_rule/utils.py b/erpnext/accounts/doctype/pricing_rule/utils.py
index a74dfea2cca9..572529580e8e 100644
--- a/erpnext/accounts/doctype/pricing_rule/utils.py
+++ b/erpnext/accounts/doctype/pricing_rule/utils.py
@@ -728,14 +728,11 @@ def get_pricing_rule_items(pr_doc, other_items=False) -> list:
def validate_coupon_code(coupon_name):
coupon = frappe.get_doc("Coupon Code", coupon_name)
-
- if coupon.valid_from:
- if coupon.valid_from > getdate(today()):
- frappe.throw(_("Sorry, this coupon code's validity has not started"))
- elif coupon.valid_upto:
- if coupon.valid_upto < getdate(today()):
- frappe.throw(_("Sorry, this coupon code's validity has expired"))
- elif coupon.used >= coupon.maximum_use:
+ if coupon.valid_from and coupon.valid_from > getdate(today()):
+ frappe.throw(_("Sorry, this coupon code's validity has not started"))
+ elif coupon.valid_upto and coupon.valid_upto < getdate(today()):
+ frappe.throw(_("Sorry, this coupon code's validity has expired"))
+ elif coupon.maximum_use and coupon.used >= coupon.maximum_use:
frappe.throw(_("Sorry, this coupon code is no longer valid"))
diff --git a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.json b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.json
index 22be52992803..763607c22a16 100644
--- a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.json
+++ b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.json
@@ -25,6 +25,7 @@
"payment_terms_template",
"sales_partner",
"sales_person",
+ "show_remarks",
"based_on_payment_terms",
"section_break_3",
"customer_collection",
@@ -390,10 +391,16 @@
"fieldname": "ignore_cr_dr_notes",
"fieldtype": "Check",
"label": "Ignore System Generated Credit / Debit Notes"
+ },
+ {
+ "default": "0",
+ "fieldname": "show_remarks",
+ "fieldtype": "Check",
+ "label": "Show Remarks"
}
],
"links": [],
- "modified": "2024-08-13 10:41:18.381165",
+ "modified": "2024-10-18 17:51:39.108481",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Process Statement Of Accounts",
diff --git a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py
index 509199ccae64..bc3ba26beb78 100644
--- a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py
+++ b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py
@@ -70,6 +70,7 @@ class ProcessStatementOfAccounts(Document):
sales_person: DF.Link | None
sender: DF.Link | None
show_net_values_in_party_account: DF.Check
+ show_remarks: DF.Check
start_date: DF.Date | None
subject: DF.Data | None
terms_and_conditions: DF.Link | None
@@ -187,6 +188,7 @@ def get_common_filters(doc):
"finance_book": doc.finance_book if doc.finance_book else None,
"account": [doc.account] if doc.account else None,
"cost_center": [cc.cost_center_name for cc in doc.cost_center],
+ "show_remarks": doc.show_remarks,
}
)
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
index 529086228de5..c680bd461308 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
@@ -1359,14 +1359,15 @@ def make_item_gl_entries(self, gl_entries):
else:
if asset.calculate_depreciation:
- notes = _(
- "This schedule was created when Asset {0} was sold through Sales Invoice {1}."
- ).format(
- get_link_to_form(asset.doctype, asset.name),
- get_link_to_form(self.doctype, self.get("name")),
- )
- depreciate_asset(asset, self.posting_date, notes)
- asset.reload()
+ if not asset.status == "Fully Depreciated":
+ notes = _(
+ "This schedule was created when Asset {0} was sold through Sales Invoice {1}."
+ ).format(
+ get_link_to_form(asset.doctype, asset.name),
+ get_link_to_form(self.doctype, self.get("name")),
+ )
+ depreciate_asset(asset, self.posting_date, notes)
+ asset.reload()
fixed_asset_gl_entries = get_gl_entries_on_asset_disposal(
asset,
diff --git a/erpnext/accounts/party.py b/erpnext/accounts/party.py
index 06e285e4adaf..65054aec53f9 100644
--- a/erpnext/accounts/party.py
+++ b/erpnext/accounts/party.py
@@ -881,16 +881,17 @@ def get_party_shipping_address(doctype: str, name: str) -> str | None:
def get_partywise_advanced_payment_amount(
party_type, posting_date=None, future_payment=0, company=None, party=None
):
+ account_type = frappe.get_cached_value("Party Type", party_type, "account_type")
+
ple = frappe.qb.DocType("Payment Ledger Entry")
+ acc = frappe.qb.DocType("Account")
+
query = (
frappe.qb.from_(ple)
- .select(ple.party, Abs(Sum(ple.amount).as_("amount")))
- .where(
- (ple.party_type.isin(party_type))
- & (ple.amount < 0)
- & (ple.against_voucher_no == ple.voucher_no)
- & (ple.delinked == 0)
- )
+ .inner_join(acc)
+ .on(ple.account == acc.name)
+ .select(ple.party)
+ .where((ple.party_type.isin(party_type)) & (acc.account_type == account_type) & (ple.delinked == 0))
.groupby(ple.party)
)
@@ -909,9 +910,32 @@ def get_partywise_advanced_payment_amount(
if invoice_doctypes := frappe.get_hooks("invoice_doctypes"):
query = query.where(ple.voucher_type.notin(invoice_doctypes))
- data = query.run()
- if data:
- return frappe._dict(data)
+ # Get advance amount from Receivable / Payable Account
+ party_ledger = query.select(Abs(Sum(ple.amount).as_("amount")))
+ party_ledger = party_ledger.where(ple.amount < 0)
+ party_ledger = party_ledger.where(ple.against_voucher_no == ple.voucher_no)
+ party_ledger = party_ledger.where(
+ acc.root_type == ("Liability" if account_type == "Payable" else "Asset")
+ )
+
+ data = party_ledger.run()
+ data = frappe._dict(data or {})
+
+ # Get advance amount from Advance Account
+ advance_ledger = query.select(Sum(ple.amount).as_("amount"), ple.account)
+ advance_ledger = advance_ledger.where(
+ acc.root_type == ("Asset" if account_type == "Payable" else "Liability")
+ )
+ advance_ledger = advance_ledger.groupby(ple.account)
+ advance_ledger = advance_ledger.having(Sum(ple.amount) < 0)
+
+ advance_data = advance_ledger.run()
+
+ for row in advance_data:
+ data.setdefault(row[0], 0)
+ data[row[0]] += abs(row[1])
+
+ return data
def get_default_contact(doctype: str, name: str) -> str | None:
diff --git a/erpnext/accounts/report/balance_sheet/balance_sheet.py b/erpnext/accounts/report/balance_sheet/balance_sheet.py
index 274c8a7a3714..ab2f45d4f8bd 100644
--- a/erpnext/accounts/report/balance_sheet/balance_sheet.py
+++ b/erpnext/accounts/report/balance_sheet/balance_sheet.py
@@ -122,13 +122,13 @@ def get_provisional_profit_loss(
for period in period_list:
key = period if consolidated else period.key
- total_assets = flt(asset[0].get(key))
+ total_assets = flt(asset[-2].get(key))
effective_liability = 0.00
- if liability:
- effective_liability += flt(liability[0].get(key))
- if equity:
- effective_liability += flt(equity[0].get(key))
+ if liability and liability[-1] == {}:
+ effective_liability += flt(liability[-2].get(key))
+ if equity and equity[-1] == {}:
+ effective_liability += flt(equity[-2].get(key))
provisional_profit_loss[key] = total_assets - effective_liability
total_row[key] = provisional_profit_loss[key] + effective_liability
@@ -195,9 +195,9 @@ def get_report_summary(
key = period if consolidated else period.key
if asset:
net_asset += asset[-2].get(key)
- if liability:
+ if liability and liability[-1] == {}:
net_liability += liability[-2].get(key)
- if equity:
+ if equity and equity[-1] == {}:
net_equity += equity[-2].get(key)
if provisional_profit_loss:
net_provisional_profit_loss += provisional_profit_loss.get(key)
diff --git a/erpnext/accounts/report/deferred_revenue_and_expense/deferred_revenue_and_expense.py b/erpnext/accounts/report/deferred_revenue_and_expense/deferred_revenue_and_expense.py
index c6d9eac59662..377777ab2a35 100644
--- a/erpnext/accounts/report/deferred_revenue_and_expense/deferred_revenue_and_expense.py
+++ b/erpnext/accounts/report/deferred_revenue_and_expense/deferred_revenue_and_expense.py
@@ -122,21 +122,24 @@ def simulate_future_posting(self):
"""
simulate future posting by creating dummy gl entries. starts from the last posting date.
"""
- if self.service_start_date != self.service_end_date:
- if add_days(self.last_entry_date, 1) < self.period_list[-1].to_date:
- self.estimate_for_period_list = get_period_list(
- self.filters.from_fiscal_year,
- self.filters.to_fiscal_year,
- add_days(self.last_entry_date, 1),
- self.period_list[-1].to_date,
- "Date Range",
- "Monthly",
- company=self.filters.company,
- )
- for period in self.estimate_for_period_list:
- amount = self.calculate_amount(period.from_date, period.to_date)
- gle = self.make_dummy_gle(period.key, period.to_date, amount)
- self.gle_entries.append(gle)
+ if (
+ self.service_start_date != self.service_end_date
+ and add_days(self.last_entry_date, 1) < self.service_end_date
+ ):
+ self.estimate_for_period_list = get_period_list(
+ self.filters.from_fiscal_year,
+ self.filters.to_fiscal_year,
+ add_days(self.last_entry_date, 1),
+ self.service_end_date,
+ "Date Range",
+ "Monthly",
+ company=self.filters.company,
+ )
+
+ for period in self.estimate_for_period_list:
+ amount = self.calculate_amount(period.from_date, period.to_date)
+ gle = self.make_dummy_gle(period.key, period.to_date, amount)
+ self.gle_entries.append(gle)
def calculate_item_revenue_expense_for_period(self):
"""
diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py
index 1d75fafc1a9d..91904059824f 100644
--- a/erpnext/accounts/utils.py
+++ b/erpnext/accounts/utils.py
@@ -1547,12 +1547,16 @@ def compare_existing_and_expected_gle(existing_gle, expected_gle, precision):
return matched
-def get_stock_accounts(company, voucher_type=None, voucher_no=None):
+def get_stock_accounts(company, voucher_type=None, voucher_no=None, accounts=None):
stock_accounts = [
d.name
for d in frappe.db.get_all("Account", {"account_type": "Stock", "company": company, "is_group": 0})
]
- if voucher_type and voucher_no:
+
+ if accounts:
+ stock_accounts = [row.account for row in accounts if row.account in stock_accounts]
+
+ elif voucher_type and voucher_no:
if voucher_type == "Journal Entry":
stock_accounts = [
d.account
diff --git a/erpnext/assets/doctype/asset_maintenance/asset_maintenance.py b/erpnext/assets/doctype/asset_maintenance/asset_maintenance.py
index b44164f2dae3..70ab7fdc8e84 100644
--- a/erpnext/assets/doctype/asset_maintenance/asset_maintenance.py
+++ b/erpnext/assets/doctype/asset_maintenance/asset_maintenance.py
@@ -144,6 +144,7 @@ def update_maintenance_log(asset_maintenance, item_code, item_name, task):
"has_certificate": task.certificate_required,
"description": task.description,
"assign_to_name": task.assign_to_name,
+ "task_assignee_email": task.assign_to,
"periodicity": str(task.periodicity),
"maintenance_type": task.maintenance_type,
"due_date": task.next_due_date,
diff --git a/erpnext/assets/doctype/asset_maintenance_log/asset_maintenance_log.json b/erpnext/assets/doctype/asset_maintenance_log/asset_maintenance_log.json
index 7d33176e2f37..c948630869b0 100644
--- a/erpnext/assets/doctype/asset_maintenance_log/asset_maintenance_log.json
+++ b/erpnext/assets/doctype/asset_maintenance_log/asset_maintenance_log.json
@@ -23,6 +23,7 @@
"column_break_6",
"maintenance_status",
"assign_to_name",
+ "task_assignee_email",
"due_date",
"completion_date",
"description",
@@ -168,15 +169,22 @@
"in_preview": 1,
"label": "Task Name",
"read_only": 1
+ },
+ {
+ "fieldname": "task_assignee_email",
+ "fieldtype": "Data",
+ "label": "Task Assignee Email",
+ "read_only": 1
}
],
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
- "modified": "2021-01-22 12:33:45.888124",
+ "modified": "2024-09-24 15:12:37.497853",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset Maintenance Log",
+ "naming_rule": "By \"Naming Series\" field",
"owner": "Administrator",
"permissions": [
{
@@ -199,4 +207,4 @@
"sort_order": "DESC",
"track_changes": 1,
"track_seen": 1
-}
\ No newline at end of file
+}
diff --git a/erpnext/assets/doctype/asset_maintenance_log/asset_maintenance_log.py b/erpnext/assets/doctype/asset_maintenance_log/asset_maintenance_log.py
index 95d02714c5b1..140eb1af27eb 100644
--- a/erpnext/assets/doctype/asset_maintenance_log/asset_maintenance_log.py
+++ b/erpnext/assets/doctype/asset_maintenance_log/asset_maintenance_log.py
@@ -37,6 +37,7 @@ class AssetMaintenanceLog(Document):
naming_series: DF.Literal["ACC-AML-.YYYY.-"]
periodicity: DF.Data | None
task: DF.Link | None
+ task_assignee_email: DF.Data | None
task_name: DF.Data | None
# end: auto-generated types
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index 73923464ed96..188cbf0587c3 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -393,12 +393,15 @@ def remove_serial_and_batch_bundle(self):
def validate_return_against_account(self):
if self.doctype in ["Sales Invoice", "Purchase Invoice"] and self.is_return and self.return_against:
cr_dr_account_field = "debit_to" if self.doctype == "Sales Invoice" else "credit_to"
- cr_dr_account_label = "Debit To" if self.doctype == "Sales Invoice" else "Credit To"
- cr_dr_account = self.get(cr_dr_account_field)
- if frappe.get_value(self.doctype, self.return_against, cr_dr_account_field) != cr_dr_account:
+ original_account = frappe.get_value(self.doctype, self.return_against, cr_dr_account_field)
+ if original_account != self.get(cr_dr_account_field):
frappe.throw(
- _("'{0}' account: '{1}' should match the Return Against Invoice").format(
- frappe.bold(cr_dr_account_label), frappe.bold(cr_dr_account)
+ _(
+ "Please set {0} to {1}, the same account that was used in the original invoice {2}."
+ ).format(
+ frappe.bold(_(self.meta.get_label(cr_dr_account_field), context=self.doctype)),
+ frappe.bold(original_account),
+ frappe.bold(self.return_against),
)
)
@@ -3521,6 +3524,9 @@ def validate_fg_item_for_subcontracting(new_data, is_new):
parent.update_billing_percentage()
parent.set_status()
+ parent.validate_uom_is_integer("uom", "qty")
+ parent.validate_uom_is_integer("stock_uom", "stock_qty")
+
# Cancel and Recreate Stock Reservation Entries.
if parent_doctype == "Sales Order":
from erpnext.stock.doctype.stock_reservation_entry.stock_reservation_entry import (
diff --git a/erpnext/controllers/subcontracting_controller.py b/erpnext/controllers/subcontracting_controller.py
index f6f6742cc871..3c7f8b0ccca1 100644
--- a/erpnext/controllers/subcontracting_controller.py
+++ b/erpnext/controllers/subcontracting_controller.py
@@ -1235,6 +1235,17 @@ def add_items_in_ste(ste_doc, row, qty, rm_details, rm_detail_field="sco_rm_deta
def make_return_stock_entry_for_subcontract(
available_materials, order_doc, rm_details, order_doctype="Subcontracting Order"
):
+ def post_process(source_doc, target_doc):
+ target_doc.purpose = "Material Transfer"
+
+ if source_doc.doctype == "Purchase Order":
+ target_doc.purchase_order = source_doc.name
+ else:
+ target_doc.subcontracting_order = source_doc.name
+
+ target_doc.company = source_doc.company
+ target_doc.is_return = 1
+
ste_doc = get_mapped_doc(
order_doctype,
order_doc.name,
@@ -1245,18 +1256,13 @@ def make_return_stock_entry_for_subcontract(
},
},
ignore_child_tables=True,
+ postprocess=post_process,
)
- ste_doc.purpose = "Material Transfer"
-
if order_doctype == "Purchase Order":
- ste_doc.purchase_order = order_doc.name
rm_detail_field = "po_detail"
else:
- ste_doc.subcontracting_order = order_doc.name
rm_detail_field = "sco_rm_detail"
- ste_doc.company = order_doc.company
- ste_doc.is_return = 1
for _key, value in available_materials.items():
if not value.qty:
diff --git a/erpnext/crm/doctype/lead/lead.js b/erpnext/crm/doctype/lead/lead.js
index e50cf9e4dd0b..022d1906e848 100644
--- a/erpnext/crm/doctype/lead/lead.js
+++ b/erpnext/crm/doctype/lead/lead.js
@@ -7,9 +7,9 @@ cur_frm.email_field = "email_id";
erpnext.LeadController = class LeadController extends frappe.ui.form.Controller {
setup() {
this.frm.make_methods = {
- Customer: this.make_customer,
- Quotation: this.make_quotation,
- Opportunity: this.make_opportunity,
+ Customer: this.make_customer.bind(this),
+ Quotation: this.make_quotation.bind(this),
+ Opportunity: this.make_opportunity.bind(this),
};
// For avoiding integration issues.
diff --git a/erpnext/manufacturing/workspace/manufacturing/manufacturing.json b/erpnext/manufacturing/workspace/manufacturing/manufacturing.json
index d2520d6b7eb6..06b9f1b07597 100644
--- a/erpnext/manufacturing/workspace/manufacturing/manufacturing.json
+++ b/erpnext/manufacturing/workspace/manufacturing/manufacturing.json
@@ -1,4 +1,5 @@
{
+ "app": "erpnext",
"charts": [],
"content": "[{\"id\":\"csBCiDglCE\",\"type\":\"header\",\"data\":{\"text\":\"Your Shortcuts\",\"col\":12}},{\"id\":\"YHCQG3wAGv\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"BOM Creator\",\"col\":3}},{\"id\":\"xit0dg7KvY\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"BOM\",\"col\":3}},{\"id\":\"LRhGV9GAov\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Production Plan\",\"col\":3}},{\"id\":\"69KKosI6Hg\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Work Order\",\"col\":3}},{\"id\":\"PwndxuIpB3\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Job Card\",\"col\":3}},{\"id\":\"Ubj6zXcmIQ\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Plant Floor\",\"col\":3}},{\"id\":\"OtMcArFRa5\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"BOM Stock Report\",\"col\":3}},{\"id\":\"76yYsI5imF\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Production Planning Report\",\"col\":3}},{\"id\":\"PIQJYZOMnD\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Learn Manufacturing\",\"col\":3}},{\"id\":\"OaiDqTT03Y\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Forecasting\",\"col\":3}},{\"id\":\"bN_6tHS-Ct\",\"type\":\"spacer\",\"data\":{\"col\":12}},{\"id\":\"yVEFZMqVwd\",\"type\":\"header\",\"data\":{\"text\":\"Reports & Masters\",\"col\":12}},{\"id\":\"rwrmsTI58-\",\"type\":\"card\",\"data\":{\"card_name\":\"Production\",\"col\":4}},{\"id\":\"6dnsyX-siZ\",\"type\":\"card\",\"data\":{\"card_name\":\"Bill of Materials\",\"col\":4}},{\"id\":\"CIq-v5f5KC\",\"type\":\"card\",\"data\":{\"card_name\":\"Reports\",\"col\":4}},{\"id\":\"8RRiQeYr0G\",\"type\":\"card\",\"data\":{\"card_name\":\"Tools\",\"col\":4}},{\"id\":\"Pu8z7-82rT\",\"type\":\"card\",\"data\":{\"card_name\":\"Settings\",\"col\":4}}]",
"creation": "2020-03-02 17:11:37.032604",
@@ -124,11 +125,86 @@
"onboard": 0,
"type": "Link"
},
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Bill of Materials",
+ "link_count": 6,
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Item",
+ "link_count": 0,
+ "link_to": "Item",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Item",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Bill of Materials",
+ "link_count": 0,
+ "link_to": "BOM",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Workstation Type",
+ "link_count": 0,
+ "link_to": "Workstation Type",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Workstation",
+ "link_count": 0,
+ "link_to": "Workstation",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Operation",
+ "link_count": 0,
+ "link_to": "Operation",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Work Order",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Routing",
+ "link_count": 0,
+ "link_to": "Routing",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
{
"hidden": 0,
"is_query_report": 0,
"label": "Reports",
"link_count": 10,
+ "link_type": "DocType",
"onboard": 0,
"type": "Card Break"
},
@@ -233,90 +309,16 @@
},
{
"hidden": 0,
- "is_query_report": 0,
+ "is_query_report": 1,
"label": "Work Order Consumed Materials",
"link_count": 0,
"link_to": "Work Order Consumed Materials",
"link_type": "Report",
"onboard": 0,
"type": "Link"
- },
- {
- "hidden": 0,
- "is_query_report": 0,
- "label": "Bill of Materials",
- "link_count": 6,
- "onboard": 0,
- "type": "Card Break"
- },
- {
- "dependencies": "",
- "hidden": 0,
- "is_query_report": 0,
- "label": "Item",
- "link_count": 0,
- "link_to": "Item",
- "link_type": "DocType",
- "onboard": 1,
- "type": "Link"
- },
- {
- "dependencies": "Item",
- "hidden": 0,
- "is_query_report": 0,
- "label": "Bill of Materials",
- "link_count": 0,
- "link_to": "BOM",
- "link_type": "DocType",
- "onboard": 1,
- "type": "Link"
- },
- {
- "dependencies": "",
- "hidden": 0,
- "is_query_report": 0,
- "label": "Workstation Type",
- "link_count": 0,
- "link_to": "Workstation Type",
- "link_type": "DocType",
- "onboard": 0,
- "type": "Link"
- },
- {
- "dependencies": "",
- "hidden": 0,
- "is_query_report": 0,
- "label": "Workstation",
- "link_count": 0,
- "link_to": "Workstation",
- "link_type": "DocType",
- "onboard": 0,
- "type": "Link"
- },
- {
- "dependencies": "",
- "hidden": 0,
- "is_query_report": 0,
- "label": "Operation",
- "link_count": 0,
- "link_to": "Operation",
- "link_type": "DocType",
- "onboard": 0,
- "type": "Link"
- },
- {
- "dependencies": "Work Order",
- "hidden": 0,
- "is_query_report": 1,
- "label": "Routing",
- "link_count": 0,
- "link_to": "Routing",
- "link_type": "DocType",
- "onboard": 0,
- "type": "Link"
}
],
- "modified": "2024-01-30 21:49:58.577218",
+ "modified": "2024-10-21 14:13:38.777556",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "Manufacturing",
@@ -398,5 +400,6 @@
"type": "Report"
}
],
- "title": "Manufacturing"
+ "title": "Manufacturing",
+ "type": "Workspace"
}
\ No newline at end of file
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 333fca1d1da5..e59938909c7f 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -378,3 +378,4 @@ erpnext.patches.v15_0.add_disassembly_order_stock_entry_type #1
erpnext.patches.v15_0.set_standard_stock_entry_type
erpnext.patches.v15_0.link_purchase_item_to_asset_doc
erpnext.patches.v14_0.update_currency_exchange_settings_for_frankfurter
+erpnext.patches.v15_0.update_task_assignee_email_field_in_asset_maintenance_log
diff --git a/erpnext/patches/v15_0/update_task_assignee_email_field_in_asset_maintenance_log.py b/erpnext/patches/v15_0/update_task_assignee_email_field_in_asset_maintenance_log.py
new file mode 100644
index 000000000000..a6eda9c2e17c
--- /dev/null
+++ b/erpnext/patches/v15_0/update_task_assignee_email_field_in_asset_maintenance_log.py
@@ -0,0 +1,18 @@
+import frappe
+from frappe.query_builder import DocType
+
+
+def execute():
+ if frappe.db.has_column("Asset Maintenance Log", "task_assignee_email"):
+ asset_maintenance_log = DocType("Asset Maintenance Log")
+ asset_maintenance_task = DocType("Asset Maintenance Task")
+ try:
+ (
+ frappe.qb.update(asset_maintenance_log)
+ .set(asset_maintenance_log.task_assignee_email, asset_maintenance_task.assign_to)
+ .join(asset_maintenance_task)
+ .on(asset_maintenance_log.task == asset_maintenance_task.name)
+ .run()
+ )
+ except Exception:
+ frappe.log_error("Failed to update Task Assignee Email Field.")
diff --git a/erpnext/public/js/utils/unreconcile.js b/erpnext/public/js/utils/unreconcile.js
index c6ee8a330c7b..de20f468ccb0 100644
--- a/erpnext/public/js/utils/unreconcile.js
+++ b/erpnext/public/js/utils/unreconcile.js
@@ -4,7 +4,8 @@ erpnext.accounts.unreconcile_payment = {
add_unreconcile_btn(frm) {
if (frm.doc.docstatus == 1) {
if (
- (frm.doc.doctype == "Journal Entry" && frm.doc.voucher_type != "Journal Entry") ||
+ (frm.doc.doctype == "Journal Entry" &&
+ !["Journal Entry", "Bank Entry", "Cash Entry"].includes(frm.doc.voucher_type)) ||
!["Purchase Invoice", "Sales Invoice", "Journal Entry", "Payment Entry"].includes(
frm.doc.doctype
)
diff --git a/erpnext/setup/default_success_action.py b/erpnext/setup/default_success_action.py
index 2b9e75c32652..dba205481843 100644
--- a/erpnext/setup/default_success_action.py
+++ b/erpnext/setup/default_success_action.py
@@ -11,14 +11,17 @@
def get_message(doctype):
- return _("{0} has been submitted successfully").format(_(doctype))
+ # Properly format the string with translated doctype
+ return _("{0} has been submitted successfully").format(doctype)
def get_first_success_message(doctype):
+ # Reuse the get_message function for consistency
return get_message(doctype)
def get_default_success_action():
+ # Loop through each doctype in the list and return formatted actions
return [
{
"doctype": "Success Action",
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.js b/erpnext/stock/doctype/stock_entry/stock_entry.js
index cb442f6666dc..3e82ef51653d 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.js
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.js
@@ -1298,7 +1298,7 @@ erpnext.stock.StockEntry = class StockEntry extends erpnext.stock.StockControlle
this.frm.cscript.toggle_enable_bom();
- if (doc.purpose == "Send to Subcontractor") {
+ if (erpnext.stock.is_subcontracting_or_return_transfer(doc)) {
doc.customer =
doc.customer_name =
doc.customer_address =
@@ -1364,6 +1364,10 @@ erpnext.stock.select_batch_and_serial_no = (frm, item) => {
});
};
+erpnext.stock.is_subcontracting_or_return_transfer = (doc) => {
+ return doc.purpose == "Send to Subcontractor" || (doc.purpose == "Material Transfer" && doc.is_return);
+};
+
function attach_bom_items(bom_no) {
if (!bom_no) {
return;
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.json b/erpnext/stock/doctype/stock_entry/stock_entry.json
index 5ba9f2973a1b..f5fdfafe778c 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.json
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.json
@@ -154,14 +154,14 @@
"search_index": 1
},
{
- "depends_on": "eval:doc.purpose==\"Send to Subcontractor\"",
+ "depends_on": "eval: erpnext.stock.is_subcontracting_or_return_transfer(doc)",
"fieldname": "purchase_order",
"fieldtype": "Link",
"label": "Purchase Order",
"options": "Purchase Order"
},
{
- "depends_on": "eval:doc.purpose==\"Send to Subcontractor\"",
+ "depends_on": "eval: erpnext.stock.is_subcontracting_or_return_transfer(doc)",
"fieldname": "subcontracting_order",
"fieldtype": "Link",
"label": "Subcontracting Order",
@@ -427,13 +427,13 @@
},
{
"collapsible": 1,
- "depends_on": "eval:doc.purpose === \"Send to Subcontractor\"",
+ "depends_on": "eval: erpnext.stock.is_subcontracting_or_return_transfer(doc)",
"fieldname": "contact_section",
"fieldtype": "Section Break",
"label": "Supplier Details"
},
{
- "depends_on": "eval:doc.purpose === \"Send to Subcontractor\"",
+ "depends_on": "eval: erpnext.stock.is_subcontracting_or_return_transfer(doc)",
"fieldname": "supplier",
"fieldtype": "Link",
"label": "Supplier",
@@ -445,7 +445,7 @@
},
{
"bold": 1,
- "depends_on": "eval:doc.purpose === \"Send to Subcontractor\"",
+ "depends_on": "eval: erpnext.stock.is_subcontracting_or_return_transfer(doc)",
"fieldname": "supplier_name",
"fieldtype": "Data",
"label": "Supplier Name",
@@ -455,7 +455,7 @@
"read_only": 1
},
{
- "depends_on": "eval:doc.purpose === \"Send to Subcontractor\"",
+ "depends_on": "eval: erpnext.stock.is_subcontracting_or_return_transfer(doc)",
"fieldname": "supplier_address",
"fieldtype": "Link",
"label": "Supplier Address",
diff --git a/erpnext/templates/pages/order.py b/erpnext/templates/pages/order.py
index 505399f4a5b9..dca5a0c7497d 100644
--- a/erpnext/templates/pages/order.py
+++ b/erpnext/templates/pages/order.py
@@ -4,6 +4,10 @@
import frappe
from frappe import _
+from erpnext.accounts.doctype.payment_request.payment_request import (
+ ALLOWED_DOCTYPES_FOR_PAYMENT_REQUEST,
+)
+
def get_context(context):
context.no_cache = 1
@@ -46,8 +50,10 @@ def get_context(context):
)
context.available_loyalty_points = int(loyalty_program_details.get("loyalty_points"))
- context.show_pay_button = "payments" in frappe.get_installed_apps() and frappe.db.get_single_value(
- "Buying Settings", "show_pay_button"
+ context.show_pay_button = (
+ "payments" in frappe.get_installed_apps()
+ and frappe.db.get_single_value("Buying Settings", "show_pay_button")
+ and context.doc.doctype in ALLOWED_DOCTYPES_FOR_PAYMENT_REQUEST
)
context.show_make_pi_button = False
if context.doc.get("supplier"):