Merge pull request #43774 from frappe/version-15-hotfix

chore: release v15
This commit is contained in:
ruthra kumar
2024-10-23 10:17:07 +05:30
committed by GitHub
29 changed files with 272 additions and 159 deletions

View File

@@ -58,7 +58,7 @@ def build_conditions(process_type, account, company):
) )
if account: if account:
conditions += f"AND {deferred_account}='{account}'" conditions += f"AND {deferred_account}='{frappe.db.escape(account)}'"
elif company: elif company:
conditions += f"AND p.company = {frappe.db.escape(company)}" conditions += f"AND p.company = {frappe.db.escape(company)}"

View File

@@ -168,7 +168,7 @@ def get_payment_entries_for_bank_clearance(
"Payment Entry" as payment_document, name as payment_entry, "Payment Entry" as payment_document, name as payment_entry,
reference_no as cheque_number, reference_date as cheque_date, 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, 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, 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 if(paid_to=%(account)s, paid_to_account_currency, paid_from_account_currency) as account_currency
from `tabPayment Entry` from `tabPayment Entry`

View File

@@ -259,7 +259,7 @@ class JournalEntry(AccountsController):
frappe.throw(_("Journal Entry type should be set as Depreciation Entry for asset depreciation")) frappe.throw(_("Journal Entry type should be set as Depreciation Entry for asset depreciation"))
def validate_stock_accounts(self): 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: for account in stock_accounts:
account_bal, stock_bal, warehouse_list = get_stock_and_account_balance( account_bal, stock_bal, warehouse_list = get_stock_and_account_balance(
account, self.posting_date, self.company account, self.posting_date, self.company

View File

@@ -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) 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 = "title" if party_type == "Shareholder" else party_type.lower() + "_name"
party_name = frappe.db.get_value(party_type, party, _party_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"]: if party_type in ["Customer", "Supplier"]:
party_bank_account = get_party_bank_account(party_type, party) party_bank_account = get_party_bank_account(party_type, party)
bank_account = get_default_company_bank_account(company, party_type, party) bank_account = get_default_company_bank_account(company, party_type, party)

View File

@@ -20,6 +20,15 @@ from erpnext.accounts.party import get_party_account, get_party_bank_account
from erpnext.accounts.utils import get_account_currency, get_currency_precision from erpnext.accounts.utils import get_account_currency, get_currency_precision
from erpnext.utilities import payment_app_import_guard 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): def _get_payment_gateway_controller(*args, **kwargs):
with payment_app_import_guard(): with payment_app_import_guard():
@@ -525,6 +534,9 @@ def make_payment_request(**args):
args = frappe._dict(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) ref_doc = frappe.get_doc(args.dt, args.dn)
gateway_account = get_gateway_details(args) or frappe._dict() gateway_account = get_gateway_details(args) or frappe._dict()

View File

@@ -80,8 +80,10 @@ frappe.ui.form.on("POS Closing Entry", {
) { ) {
reset_values(frm); reset_values(frm);
frappe.run_serially([ frappe.run_serially([
() => frappe.dom.freeze(__("Loading Invoices! Please Wait...")),
() => frm.trigger("set_opening_amounts"), () => frm.trigger("set_opening_amounts"),
() => frm.trigger("get_pos_invoices"), () => frm.trigger("get_pos_invoices"),
() => frappe.dom.unfreeze(),
]); ]);
} }
}, },

View File

@@ -57,6 +57,7 @@ erpnext.selling.POSInvoiceController = class POSInvoiceController extends erpnex
} }
onload_post_render(frm) { onload_post_render(frm) {
super.onload_post_render();
this.pos_profile(frm); this.pos_profile(frm);
} }

View File

@@ -728,14 +728,11 @@ def get_pricing_rule_items(pr_doc, other_items=False) -> list:
def validate_coupon_code(coupon_name): def validate_coupon_code(coupon_name):
coupon = frappe.get_doc("Coupon Code", coupon_name) coupon = frappe.get_doc("Coupon Code", coupon_name)
if coupon.valid_from and coupon.valid_from > getdate(today()):
if coupon.valid_from: frappe.throw(_("Sorry, this coupon code's validity has not started"))
if coupon.valid_from > getdate(today()): elif coupon.valid_upto and coupon.valid_upto < getdate(today()):
frappe.throw(_("Sorry, this coupon code's validity has not started")) frappe.throw(_("Sorry, this coupon code's validity has expired"))
elif coupon.valid_upto: elif coupon.maximum_use and coupon.used >= coupon.maximum_use:
if coupon.valid_upto < getdate(today()):
frappe.throw(_("Sorry, this coupon code's validity has expired"))
elif coupon.used >= coupon.maximum_use:
frappe.throw(_("Sorry, this coupon code is no longer valid")) frappe.throw(_("Sorry, this coupon code is no longer valid"))

View File

@@ -25,6 +25,7 @@
"payment_terms_template", "payment_terms_template",
"sales_partner", "sales_partner",
"sales_person", "sales_person",
"show_remarks",
"based_on_payment_terms", "based_on_payment_terms",
"section_break_3", "section_break_3",
"customer_collection", "customer_collection",
@@ -390,10 +391,16 @@
"fieldname": "ignore_cr_dr_notes", "fieldname": "ignore_cr_dr_notes",
"fieldtype": "Check", "fieldtype": "Check",
"label": "Ignore System Generated Credit / Debit Notes" "label": "Ignore System Generated Credit / Debit Notes"
},
{
"default": "0",
"fieldname": "show_remarks",
"fieldtype": "Check",
"label": "Show Remarks"
} }
], ],
"links": [], "links": [],
"modified": "2024-08-13 10:41:18.381165", "modified": "2024-10-18 17:51:39.108481",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Process Statement Of Accounts", "name": "Process Statement Of Accounts",

View File

@@ -70,6 +70,7 @@ class ProcessStatementOfAccounts(Document):
sales_person: DF.Link | None sales_person: DF.Link | None
sender: DF.Link | None sender: DF.Link | None
show_net_values_in_party_account: DF.Check show_net_values_in_party_account: DF.Check
show_remarks: DF.Check
start_date: DF.Date | None start_date: DF.Date | None
subject: DF.Data | None subject: DF.Data | None
terms_and_conditions: DF.Link | 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, "finance_book": doc.finance_book if doc.finance_book else None,
"account": [doc.account] if doc.account else None, "account": [doc.account] if doc.account else None,
"cost_center": [cc.cost_center_name for cc in doc.cost_center], "cost_center": [cc.cost_center_name for cc in doc.cost_center],
"show_remarks": doc.show_remarks,
} }
) )

View File

@@ -1359,14 +1359,15 @@ class SalesInvoice(SellingController):
else: else:
if asset.calculate_depreciation: if asset.calculate_depreciation:
notes = _( if not asset.status == "Fully Depreciated":
"This schedule was created when Asset {0} was sold through Sales Invoice {1}." notes = _(
).format( "This schedule was created when Asset {0} was sold through Sales Invoice {1}."
get_link_to_form(asset.doctype, asset.name), ).format(
get_link_to_form(self.doctype, self.get("name")), 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() depreciate_asset(asset, self.posting_date, notes)
asset.reload()
fixed_asset_gl_entries = get_gl_entries_on_asset_disposal( fixed_asset_gl_entries = get_gl_entries_on_asset_disposal(
asset, asset,

View File

@@ -881,16 +881,17 @@ def get_party_shipping_address(doctype: str, name: str) -> str | None:
def get_partywise_advanced_payment_amount( def get_partywise_advanced_payment_amount(
party_type, posting_date=None, future_payment=0, company=None, party=None 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") ple = frappe.qb.DocType("Payment Ledger Entry")
acc = frappe.qb.DocType("Account")
query = ( query = (
frappe.qb.from_(ple) frappe.qb.from_(ple)
.select(ple.party, Abs(Sum(ple.amount).as_("amount"))) .inner_join(acc)
.where( .on(ple.account == acc.name)
(ple.party_type.isin(party_type)) .select(ple.party)
& (ple.amount < 0) .where((ple.party_type.isin(party_type)) & (acc.account_type == account_type) & (ple.delinked == 0))
& (ple.against_voucher_no == ple.voucher_no)
& (ple.delinked == 0)
)
.groupby(ple.party) .groupby(ple.party)
) )
@@ -909,9 +910,32 @@ def get_partywise_advanced_payment_amount(
if invoice_doctypes := frappe.get_hooks("invoice_doctypes"): if invoice_doctypes := frappe.get_hooks("invoice_doctypes"):
query = query.where(ple.voucher_type.notin(invoice_doctypes)) query = query.where(ple.voucher_type.notin(invoice_doctypes))
data = query.run() # Get advance amount from Receivable / Payable Account
if data: party_ledger = query.select(Abs(Sum(ple.amount).as_("amount")))
return frappe._dict(data) 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: def get_default_contact(doctype: str, name: str) -> str | None:

View File

@@ -122,13 +122,13 @@ def get_provisional_profit_loss(
for period in period_list: for period in period_list:
key = period if consolidated else period.key 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 effective_liability = 0.00
if liability: if liability and liability[-1] == {}:
effective_liability += flt(liability[0].get(key)) effective_liability += flt(liability[-2].get(key))
if equity: if equity and equity[-1] == {}:
effective_liability += flt(equity[0].get(key)) effective_liability += flt(equity[-2].get(key))
provisional_profit_loss[key] = total_assets - effective_liability provisional_profit_loss[key] = total_assets - effective_liability
total_row[key] = provisional_profit_loss[key] + 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 key = period if consolidated else period.key
if asset: if asset:
net_asset += asset[-2].get(key) net_asset += asset[-2].get(key)
if liability: if liability and liability[-1] == {}:
net_liability += liability[-2].get(key) net_liability += liability[-2].get(key)
if equity: if equity and equity[-1] == {}:
net_equity += equity[-2].get(key) net_equity += equity[-2].get(key)
if provisional_profit_loss: if provisional_profit_loss:
net_provisional_profit_loss += provisional_profit_loss.get(key) net_provisional_profit_loss += provisional_profit_loss.get(key)

View File

@@ -122,21 +122,24 @@ class Deferred_Item:
""" """
simulate future posting by creating dummy gl entries. starts from the last posting date. simulate future posting by creating dummy gl entries. starts from the last posting date.
""" """
if self.service_start_date != self.service_end_date: if (
if add_days(self.last_entry_date, 1) < self.period_list[-1].to_date: self.service_start_date != self.service_end_date
self.estimate_for_period_list = get_period_list( and add_days(self.last_entry_date, 1) < self.service_end_date
self.filters.from_fiscal_year, ):
self.filters.to_fiscal_year, self.estimate_for_period_list = get_period_list(
add_days(self.last_entry_date, 1), self.filters.from_fiscal_year,
self.period_list[-1].to_date, self.filters.to_fiscal_year,
"Date Range", add_days(self.last_entry_date, 1),
"Monthly", self.service_end_date,
company=self.filters.company, "Date Range",
) "Monthly",
for period in self.estimate_for_period_list: company=self.filters.company,
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) 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): def calculate_item_revenue_expense_for_period(self):
""" """

View File

@@ -1547,12 +1547,16 @@ def compare_existing_and_expected_gle(existing_gle, expected_gle, precision):
return matched 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 = [ stock_accounts = [
d.name d.name
for d in frappe.db.get_all("Account", {"account_type": "Stock", "company": company, "is_group": 0}) 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": if voucher_type == "Journal Entry":
stock_accounts = [ stock_accounts = [
d.account d.account

View File

@@ -144,6 +144,7 @@ def update_maintenance_log(asset_maintenance, item_code, item_name, task):
"has_certificate": task.certificate_required, "has_certificate": task.certificate_required,
"description": task.description, "description": task.description,
"assign_to_name": task.assign_to_name, "assign_to_name": task.assign_to_name,
"task_assignee_email": task.assign_to,
"periodicity": str(task.periodicity), "periodicity": str(task.periodicity),
"maintenance_type": task.maintenance_type, "maintenance_type": task.maintenance_type,
"due_date": task.next_due_date, "due_date": task.next_due_date,

View File

@@ -23,6 +23,7 @@
"column_break_6", "column_break_6",
"maintenance_status", "maintenance_status",
"assign_to_name", "assign_to_name",
"task_assignee_email",
"due_date", "due_date",
"completion_date", "completion_date",
"description", "description",
@@ -168,15 +169,22 @@
"in_preview": 1, "in_preview": 1,
"label": "Task Name", "label": "Task Name",
"read_only": 1 "read_only": 1
},
{
"fieldname": "task_assignee_email",
"fieldtype": "Data",
"label": "Task Assignee Email",
"read_only": 1
} }
], ],
"index_web_pages_for_search": 1, "index_web_pages_for_search": 1,
"is_submittable": 1, "is_submittable": 1,
"links": [], "links": [],
"modified": "2021-01-22 12:33:45.888124", "modified": "2024-09-24 15:12:37.497853",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Assets", "module": "Assets",
"name": "Asset Maintenance Log", "name": "Asset Maintenance Log",
"naming_rule": "By \"Naming Series\" field",
"owner": "Administrator", "owner": "Administrator",
"permissions": [ "permissions": [
{ {
@@ -199,4 +207,4 @@
"sort_order": "DESC", "sort_order": "DESC",
"track_changes": 1, "track_changes": 1,
"track_seen": 1 "track_seen": 1
} }

View File

@@ -37,6 +37,7 @@ class AssetMaintenanceLog(Document):
naming_series: DF.Literal["ACC-AML-.YYYY.-"] naming_series: DF.Literal["ACC-AML-.YYYY.-"]
periodicity: DF.Data | None periodicity: DF.Data | None
task: DF.Link | None task: DF.Link | None
task_assignee_email: DF.Data | None
task_name: DF.Data | None task_name: DF.Data | None
# end: auto-generated types # end: auto-generated types

View File

@@ -393,12 +393,15 @@ class AccountsController(TransactionBase):
def validate_return_against_account(self): def validate_return_against_account(self):
if self.doctype in ["Sales Invoice", "Purchase Invoice"] and self.is_return and self.return_against: 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_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" original_account = frappe.get_value(self.doctype, self.return_against, cr_dr_account_field)
cr_dr_account = self.get(cr_dr_account_field) if original_account != self.get(cr_dr_account_field):
if frappe.get_value(self.doctype, self.return_against, cr_dr_account_field) != cr_dr_account:
frappe.throw( 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 update_child_qty_rate(parent_doctype, trans_items, parent_doctype_name, chil
parent.update_billing_percentage() parent.update_billing_percentage()
parent.set_status() 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. # Cancel and Recreate Stock Reservation Entries.
if parent_doctype == "Sales Order": if parent_doctype == "Sales Order":
from erpnext.stock.doctype.stock_reservation_entry.stock_reservation_entry import ( from erpnext.stock.doctype.stock_reservation_entry.stock_reservation_entry import (

View File

@@ -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( def make_return_stock_entry_for_subcontract(
available_materials, order_doc, rm_details, order_doctype="Subcontracting Order" 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( ste_doc = get_mapped_doc(
order_doctype, order_doctype,
order_doc.name, order_doc.name,
@@ -1245,18 +1256,13 @@ def make_return_stock_entry_for_subcontract(
}, },
}, },
ignore_child_tables=True, ignore_child_tables=True,
postprocess=post_process,
) )
ste_doc.purpose = "Material Transfer"
if order_doctype == "Purchase Order": if order_doctype == "Purchase Order":
ste_doc.purchase_order = order_doc.name
rm_detail_field = "po_detail" rm_detail_field = "po_detail"
else: else:
ste_doc.subcontracting_order = order_doc.name
rm_detail_field = "sco_rm_detail" rm_detail_field = "sco_rm_detail"
ste_doc.company = order_doc.company
ste_doc.is_return = 1
for _key, value in available_materials.items(): for _key, value in available_materials.items():
if not value.qty: if not value.qty:

View File

@@ -7,9 +7,9 @@ cur_frm.email_field = "email_id";
erpnext.LeadController = class LeadController extends frappe.ui.form.Controller { erpnext.LeadController = class LeadController extends frappe.ui.form.Controller {
setup() { setup() {
this.frm.make_methods = { this.frm.make_methods = {
Customer: this.make_customer, Customer: this.make_customer.bind(this),
Quotation: this.make_quotation, Quotation: this.make_quotation.bind(this),
Opportunity: this.make_opportunity, Opportunity: this.make_opportunity.bind(this),
}; };
// For avoiding integration issues. // For avoiding integration issues.

View File

@@ -1,4 +1,5 @@
{ {
"app": "erpnext",
"charts": [], "charts": [],
"content": "[{\"id\":\"csBCiDglCE\",\"type\":\"header\",\"data\":{\"text\":\"<span class=\\\"h4\\\"><b>Your Shortcuts</b></span>\",\"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\":\"<span class=\\\"h4\\\"><b>Reports &amp; Masters</b></span>\",\"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}}]", "content": "[{\"id\":\"csBCiDglCE\",\"type\":\"header\",\"data\":{\"text\":\"<span class=\\\"h4\\\"><b>Your Shortcuts</b></span>\",\"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\":\"<span class=\\\"h4\\\"><b>Reports &amp; Masters</b></span>\",\"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", "creation": "2020-03-02 17:11:37.032604",
@@ -124,11 +125,86 @@
"onboard": 0, "onboard": 0,
"type": "Link" "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, "hidden": 0,
"is_query_report": 0, "is_query_report": 0,
"label": "Reports", "label": "Reports",
"link_count": 10, "link_count": 10,
"link_type": "DocType",
"onboard": 0, "onboard": 0,
"type": "Card Break" "type": "Card Break"
}, },
@@ -233,90 +309,16 @@
}, },
{ {
"hidden": 0, "hidden": 0,
"is_query_report": 0, "is_query_report": 1,
"label": "Work Order Consumed Materials", "label": "Work Order Consumed Materials",
"link_count": 0, "link_count": 0,
"link_to": "Work Order Consumed Materials", "link_to": "Work Order Consumed Materials",
"link_type": "Report", "link_type": "Report",
"onboard": 0, "onboard": 0,
"type": "Link" "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", "modified_by": "Administrator",
"module": "Manufacturing", "module": "Manufacturing",
"name": "Manufacturing", "name": "Manufacturing",
@@ -398,5 +400,6 @@
"type": "Report" "type": "Report"
} }
], ],
"title": "Manufacturing" "title": "Manufacturing",
"type": "Workspace"
} }

View File

@@ -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.set_standard_stock_entry_type
erpnext.patches.v15_0.link_purchase_item_to_asset_doc erpnext.patches.v15_0.link_purchase_item_to_asset_doc
erpnext.patches.v14_0.update_currency_exchange_settings_for_frankfurter erpnext.patches.v14_0.update_currency_exchange_settings_for_frankfurter
erpnext.patches.v15_0.update_task_assignee_email_field_in_asset_maintenance_log

View File

@@ -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.")

View File

@@ -4,7 +4,8 @@ erpnext.accounts.unreconcile_payment = {
add_unreconcile_btn(frm) { add_unreconcile_btn(frm) {
if (frm.doc.docstatus == 1) { if (frm.doc.docstatus == 1) {
if ( 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( !["Purchase Invoice", "Sales Invoice", "Journal Entry", "Payment Entry"].includes(
frm.doc.doctype frm.doc.doctype
) )

View File

@@ -11,14 +11,17 @@ doctype_list = [
def get_message(doctype): 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): def get_first_success_message(doctype):
# Reuse the get_message function for consistency
return get_message(doctype) return get_message(doctype)
def get_default_success_action(): def get_default_success_action():
# Loop through each doctype in the list and return formatted actions
return [ return [
{ {
"doctype": "Success Action", "doctype": "Success Action",

View File

@@ -1298,7 +1298,7 @@ erpnext.stock.StockEntry = class StockEntry extends erpnext.stock.StockControlle
this.frm.cscript.toggle_enable_bom(); 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 =
doc.customer_name = doc.customer_name =
doc.customer_address = 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) { function attach_bom_items(bom_no) {
if (!bom_no) { if (!bom_no) {
return; return;

View File

@@ -154,14 +154,14 @@
"search_index": 1 "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", "fieldname": "purchase_order",
"fieldtype": "Link", "fieldtype": "Link",
"label": "Purchase Order", "label": "Purchase Order",
"options": "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", "fieldname": "subcontracting_order",
"fieldtype": "Link", "fieldtype": "Link",
"label": "Subcontracting Order", "label": "Subcontracting Order",
@@ -427,13 +427,13 @@
}, },
{ {
"collapsible": 1, "collapsible": 1,
"depends_on": "eval:doc.purpose === \"Send to Subcontractor\"", "depends_on": "eval: erpnext.stock.is_subcontracting_or_return_transfer(doc)",
"fieldname": "contact_section", "fieldname": "contact_section",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"label": "Supplier Details" "label": "Supplier Details"
}, },
{ {
"depends_on": "eval:doc.purpose === \"Send to Subcontractor\"", "depends_on": "eval: erpnext.stock.is_subcontracting_or_return_transfer(doc)",
"fieldname": "supplier", "fieldname": "supplier",
"fieldtype": "Link", "fieldtype": "Link",
"label": "Supplier", "label": "Supplier",
@@ -445,7 +445,7 @@
}, },
{ {
"bold": 1, "bold": 1,
"depends_on": "eval:doc.purpose === \"Send to Subcontractor\"", "depends_on": "eval: erpnext.stock.is_subcontracting_or_return_transfer(doc)",
"fieldname": "supplier_name", "fieldname": "supplier_name",
"fieldtype": "Data", "fieldtype": "Data",
"label": "Supplier Name", "label": "Supplier Name",
@@ -455,7 +455,7 @@
"read_only": 1 "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", "fieldname": "supplier_address",
"fieldtype": "Link", "fieldtype": "Link",
"label": "Supplier Address", "label": "Supplier Address",

View File

@@ -4,6 +4,10 @@
import frappe import frappe
from frappe import _ from frappe import _
from erpnext.accounts.doctype.payment_request.payment_request import (
ALLOWED_DOCTYPES_FOR_PAYMENT_REQUEST,
)
def get_context(context): def get_context(context):
context.no_cache = 1 context.no_cache = 1
@@ -46,8 +50,10 @@ def get_context(context):
) )
context.available_loyalty_points = int(loyalty_program_details.get("loyalty_points")) 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( context.show_pay_button = (
"Buying Settings", "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 context.show_make_pi_button = False
if context.doc.get("supplier"): if context.doc.get("supplier"):