mirror of
https://github.com/frappe/erpnext.git
synced 2026-08-13 14:41:53 +00:00
fix: restrict state-changing whitelisted endpoints to POST (#56858)
Add methods=["POST"] to 50 whitelisted functions that create or modify documents (get_doc followed by insert/save/submit), so they can no longer be invoked via GET requests. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -188,7 +188,7 @@ def get_closing_balance_as_per_statement(bank_account: str, date: str):
|
||||
return {"balance": 0, "date": None}
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
@frappe.whitelist(methods=["POST"])
|
||||
def set_closing_balance_as_per_statement(bank_account: str, date: str | datetime.date, balance: float):
|
||||
"""
|
||||
Set the closing balance as per statement for a bank account and date
|
||||
|
||||
@@ -116,7 +116,7 @@ def get_account_balance(bank_account: str, till_date: str | date, company: str):
|
||||
return flt(balance_as_per_system) - flt(total_debit) + flt(total_credit) + amounts_not_reflected_in_system
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
@frappe.whitelist(methods=["POST"])
|
||||
def update_bank_transaction(
|
||||
bank_transaction_name: str, reference_number: str, party_type: str | None = None, party: str | None = None
|
||||
):
|
||||
@@ -146,7 +146,7 @@ def update_bank_transaction(
|
||||
)[0]
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
@frappe.whitelist(methods=["POST"])
|
||||
def create_journal_entry_bts(
|
||||
bank_transaction_name: str,
|
||||
reference_number: str | None = None,
|
||||
@@ -305,7 +305,7 @@ def create_journal_entry_bts(
|
||||
return reconcile_vouchers(bank_transaction_name, vouchers, is_new_voucher=True)
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
@frappe.whitelist(methods=["POST"])
|
||||
def create_payment_entry_bts(
|
||||
bank_transaction_name: str,
|
||||
reference_number: str | None = None,
|
||||
@@ -500,7 +500,7 @@ def create_bulk_internal_transfer(bank_transaction_names: list[str | int], bank_
|
||||
return output
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
@frappe.whitelist(methods=["POST"])
|
||||
def create_internal_transfer(
|
||||
bank_transaction_name: str | int,
|
||||
posting_date: str | date,
|
||||
@@ -1057,7 +1057,7 @@ def get_auto_reconcile_message(partially_reconciled, reconciled):
|
||||
return alert_message, indicator
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
@frappe.whitelist(methods=["POST"])
|
||||
def reconcile_vouchers(bank_transaction_name: str | int, vouchers: str | list, is_new_voucher: bool = False):
|
||||
# updated clear date of all the vouchers based on the bank transaction
|
||||
vouchers = frappe.parse_json(vouchers)
|
||||
|
||||
@@ -397,7 +397,7 @@ def unreconcile_transaction(transaction_name: str | int):
|
||||
frappe.get_doc(voucher["doctype"], voucher["name"]).cancel()
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
@frappe.whitelist(methods=["POST"])
|
||||
def unreconcile_transaction_entry(bank_transaction_id: str | int, voucher_type: str, voucher_id: str | int):
|
||||
"""
|
||||
Removes a single payment entry from a bank transaction - for example only undoing one voucher instead of undoing the entire transaction
|
||||
|
||||
@@ -34,7 +34,7 @@ def upload_bank_statement():
|
||||
return {"columns": columns, "data": data}
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
@frappe.whitelist(methods=["POST"])
|
||||
def create_bank_entries(columns: str, data: str | list, bank_account: str):
|
||||
header_map = get_header_mapping(columns, bank_account)
|
||||
|
||||
|
||||
@@ -184,7 +184,7 @@ class BisectAccountingStatements(Document):
|
||||
self.get_report_summary()
|
||||
self.update_node()
|
||||
|
||||
@frappe.whitelist()
|
||||
@frappe.whitelist(methods=["POST"])
|
||||
def bisect_left(self):
|
||||
if self.current_node is not None:
|
||||
cur_node = frappe.get_doc("Bisect Nodes", self.current_node)
|
||||
@@ -198,7 +198,7 @@ class BisectAccountingStatements(Document):
|
||||
else:
|
||||
frappe.msgprint(_("No more children on Left"))
|
||||
|
||||
@frappe.whitelist()
|
||||
@frappe.whitelist(methods=["POST"])
|
||||
def bisect_right(self):
|
||||
if self.current_node is not None:
|
||||
cur_node = frappe.get_doc("Bisect Nodes", self.current_node)
|
||||
@@ -212,7 +212,7 @@ class BisectAccountingStatements(Document):
|
||||
else:
|
||||
frappe.msgprint(_("No more children on Right"))
|
||||
|
||||
@frappe.whitelist()
|
||||
@frappe.whitelist(methods=["POST"])
|
||||
def move_up(self):
|
||||
if self.current_node is not None:
|
||||
cur_node = frappe.get_doc("Bisect Nodes", self.current_node)
|
||||
|
||||
@@ -878,7 +878,7 @@ def get_fiscal_year_date_range(from_fiscal_year, to_fiscal_year):
|
||||
return from_year.year_start_date, to_year.year_end_date
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
@frappe.whitelist(methods=["POST"])
|
||||
def revise_budget(budget_name: str):
|
||||
old_budget = frappe.get_doc("Budget", budget_name)
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ class ChequePrintTemplate(Document):
|
||||
pass
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
@frappe.whitelist(methods=["POST"])
|
||||
def create_or_update_cheque_print_format(template_name: str):
|
||||
frappe.only_for("System Manager")
|
||||
|
||||
|
||||
@@ -718,7 +718,7 @@ class PaymentRequest(Document):
|
||||
row_number += TO_SKIP_NEW_ROW
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
@frappe.whitelist(methods=["POST"])
|
||||
def make_payment_request(**args):
|
||||
"""Make payment request"""
|
||||
|
||||
|
||||
@@ -224,7 +224,7 @@ def get_children(doctype: str, parent: str | None = None, location: str | None =
|
||||
)
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
@frappe.whitelist(methods=["POST"])
|
||||
def add_node():
|
||||
from frappe.desk.treeview import make_tree_args
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ def make_supplier_quotation_from_rfq(
|
||||
|
||||
|
||||
# This method is used to make supplier quotation from supplier's portal.
|
||||
@frappe.whitelist()
|
||||
@frappe.whitelist(methods=["POST"])
|
||||
def create_supplier_quotation(doc: str | Document | dict):
|
||||
doc = frappe.parse_json(doc)
|
||||
|
||||
|
||||
@@ -185,7 +185,7 @@ def refresh_scorecards():
|
||||
frappe.get_doc("Supplier Scorecard", sc_name).save()
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
@frappe.whitelist(methods=["POST"])
|
||||
def make_all_scorecards(docname: str):
|
||||
sc = frappe.get_doc("Supplier Scorecard", docname)
|
||||
supplier = frappe.get_doc("Supplier", sc.supplier)
|
||||
|
||||
@@ -1724,7 +1724,7 @@ def get_missing_company_details(doctype: str, docname: str):
|
||||
}
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
@frappe.whitelist(methods=["POST"])
|
||||
def update_company_master_and_address(current_doctype: str, name: str, company: str, details: dict | str):
|
||||
from frappe.utils import validate_email_address
|
||||
|
||||
|
||||
@@ -653,7 +653,7 @@ def check_item_quality_inspection(doctype: str, docstatus: str | int, items: str
|
||||
return [item for item in items if item.get("item_code") in inspection_required_items]
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
@frappe.whitelist(methods=["POST"])
|
||||
def make_quality_inspections(
|
||||
company: str, doctype: str, docname: str, items: str | list, inspection_type: str
|
||||
):
|
||||
|
||||
@@ -380,7 +380,7 @@ def get_lead_with_phone_number(number):
|
||||
return lead
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
@frappe.whitelist(methods=["POST"])
|
||||
def add_lead_to_prospect(lead: str, prospect: str):
|
||||
prospect = frappe.get_doc("Prospect", prospect)
|
||||
prospect.append("leads", {"lead": lead})
|
||||
|
||||
@@ -110,7 +110,7 @@ def make_quotation(source_name: str, target_doc: str | Document | None = None):
|
||||
return target_doc
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
@frappe.whitelist(methods=["POST"])
|
||||
def make_lead_from_communication(communication: str, ignore_communication_links: bool = False):
|
||||
"""raise a issue from email"""
|
||||
|
||||
|
||||
@@ -124,7 +124,7 @@ def make_supplier_quotation(source_name: str, target_doc: str | Document | None
|
||||
return doclist
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
@frappe.whitelist(methods=["POST"])
|
||||
def make_opportunity_from_communication(
|
||||
communication: str, company: str, ignore_communication_links: bool = False
|
||||
):
|
||||
|
||||
@@ -389,7 +389,7 @@ def get_item_details(item_code: str):
|
||||
}
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
@frappe.whitelist(methods=["POST"])
|
||||
def set_multiple_status(names: str | list[str], status: str):
|
||||
names = frappe.parse_json(names)
|
||||
for name in names:
|
||||
|
||||
@@ -50,7 +50,7 @@ def get_plaid_configuration():
|
||||
return "disabled"
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
@frappe.whitelist(methods=["POST"])
|
||||
def add_institution(token: str, response: str | dict):
|
||||
response = frappe.parse_json(response)
|
||||
|
||||
@@ -79,7 +79,7 @@ def add_institution(token: str, response: str | dict):
|
||||
return bank
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
@frappe.whitelist(methods=["POST"])
|
||||
def add_bank_accounts(response: str | dict, bank: str | dict, company: str):
|
||||
response = frappe.parse_json(response)
|
||||
bank = frappe.parse_json(bank)
|
||||
|
||||
@@ -1070,7 +1070,7 @@ def get_bom_operations(doctype: str, txt: str, searchfield: str, start: int, pag
|
||||
return frappe.get_all("BOM Operation", filters=filters, fields=["operation"], as_list=1)
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
@frappe.whitelist(methods=["POST"])
|
||||
def set_work_order_ops(name: str):
|
||||
po = frappe.get_doc("Work Order", name)
|
||||
po.set_work_order_operations()
|
||||
|
||||
@@ -223,7 +223,7 @@ class Workstation(Document):
|
||||
|
||||
return schedule_date
|
||||
|
||||
@frappe.whitelist()
|
||||
@frappe.whitelist(methods=["POST"])
|
||||
def start_job(self, job_card: str, from_time: DateTimeLikeObject, employee: str):
|
||||
doc = frappe.get_doc("Job Card", job_card)
|
||||
doc.check_permission("write")
|
||||
@@ -233,7 +233,7 @@ class Workstation(Document):
|
||||
|
||||
return doc
|
||||
|
||||
@frappe.whitelist()
|
||||
@frappe.whitelist(methods=["POST"])
|
||||
def complete_job(self, job_card: str, qty: float, to_time: DateTimeLikeObject):
|
||||
doc = frappe.get_doc("Job Card", job_card)
|
||||
doc.check_permission("submit")
|
||||
|
||||
@@ -628,7 +628,7 @@ def allow_to_make_project_update(project, time, frequency):
|
||||
return True
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
@frappe.whitelist(methods=["POST"])
|
||||
def create_duplicate_project(prev_doc: str | dict, project_name: str):
|
||||
"""Create duplicate project based on the old project"""
|
||||
import json
|
||||
@@ -779,7 +779,7 @@ def create_kanban_board_if_not_exists(project: str):
|
||||
return True
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
@frappe.whitelist(methods=["POST"])
|
||||
def set_project_status(project: str, status: str):
|
||||
"""
|
||||
set status for project and all related tasks
|
||||
|
||||
@@ -369,7 +369,7 @@ def get_project(doctype: str, txt: str, searchfield: str, start: int, page_len:
|
||||
)
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
@frappe.whitelist(methods=["POST"])
|
||||
def set_multiple_status(names: str | list, status: str):
|
||||
names = frappe.parse_json(names)
|
||||
for name in names:
|
||||
@@ -451,7 +451,7 @@ def get_children(
|
||||
return tasks
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
@frappe.whitelist(methods=["POST"])
|
||||
def add_node():
|
||||
from frappe.desk.treeview import make_tree_args
|
||||
|
||||
@@ -465,7 +465,7 @@ def add_node():
|
||||
frappe.get_doc(args).insert()
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
@frappe.whitelist(methods=["POST"])
|
||||
def add_multiple_tasks(data: str | list, parent: str):
|
||||
data = frappe.parse_json(data)
|
||||
new_doc = {"doctype": "Task", "parent_task": parent if parent != "All Tasks" else ""}
|
||||
|
||||
@@ -148,7 +148,7 @@ def get_children(
|
||||
)
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
@frappe.whitelist(methods=["POST"])
|
||||
def add_node():
|
||||
from frappe.desk.treeview import make_tree_args
|
||||
|
||||
|
||||
@@ -196,7 +196,7 @@ class Customer(TransactionBase):
|
||||
if sum(member.allocated_percentage or 0 for member in self.sales_team) != 100:
|
||||
frappe.throw(_("Total contribution percentage should be equal to 100"))
|
||||
|
||||
@frappe.whitelist()
|
||||
@frappe.whitelist(methods=["POST"])
|
||||
def get_customer_group_details(self):
|
||||
doc = frappe.get_doc("Customer Group", self.customer_group)
|
||||
self.accounts = []
|
||||
|
||||
@@ -840,7 +840,7 @@ def set_delivery_date(items: list, sales_order: str) -> None:
|
||||
item.schedule_date = delivery_by_bundle.get(item.product_bundle)
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
@frappe.whitelist(methods=["POST"])
|
||||
def make_work_orders(items: str | dict, sales_order: str, company: str, project: str | None = None):
|
||||
"""Make Work Orders against the given Sales Order for the given `items`"""
|
||||
items = frappe.parse_json(items).get("items")
|
||||
|
||||
@@ -347,7 +347,7 @@ def check_opening_entry(user: str):
|
||||
return open_vouchers
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
@frappe.whitelist(methods=["POST"])
|
||||
def create_opening_voucher(pos_profile: str, company: str, balance_details: str | list):
|
||||
balance_details = frappe.parse_json(balance_details)
|
||||
|
||||
@@ -438,7 +438,7 @@ def get_past_order_list(search_term: str, status: str, limit: int = 20):
|
||||
return invoice_list
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
@frappe.whitelist(methods=["POST"])
|
||||
def set_customer_info(fieldname: str, customer: str, value: str = ""):
|
||||
customer_doc = frappe.get_doc("Customer", customer)
|
||||
customer_doc.check_permission("write")
|
||||
|
||||
@@ -1007,7 +1007,7 @@ def get_children(doctype: str, parent: str | None = None, company: str | None =
|
||||
)
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
@frappe.whitelist(methods=["POST"])
|
||||
def add_node():
|
||||
from frappe.desk.treeview import make_tree_args
|
||||
|
||||
@@ -1118,7 +1118,7 @@ def get_billing_shipping_address(
|
||||
return {"primary_address": primary_address, "shipping_address": shipping_address}
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
@frappe.whitelist(methods=["POST"])
|
||||
def create_transaction_deletion_request(company: str):
|
||||
frappe.only_for("System Manager")
|
||||
|
||||
|
||||
@@ -95,7 +95,7 @@ def get_children(
|
||||
return frappe.get_all("Department", fields=fields, filters=filters, order_by="name")
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
@frappe.whitelist(methods=["POST"])
|
||||
def add_node():
|
||||
from frappe.desk.treeview import make_tree_args
|
||||
|
||||
|
||||
@@ -432,7 +432,7 @@ def deactivate_sales_person(status: str, employee: str):
|
||||
frappe.db.set_value("Sales Person", sales_person, "enabled", 0)
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
@frappe.whitelist(methods=["POST"])
|
||||
def create_user(employee: str, email: str | None = None, create_user_permission: int = 0) -> str:
|
||||
emp = frappe.get_doc("Employee", employee)
|
||||
emp.check_permission("write")
|
||||
|
||||
@@ -301,7 +301,7 @@ def get_batches_by_oldest(item_code: str, warehouse: str):
|
||||
return batches_dates
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
@frappe.whitelist(methods=["POST"])
|
||||
def split_batch(batch_no: str, item_code: str, warehouse: str, qty: float, new_batch_id: str | None = None):
|
||||
"""Split the batch into a new batch"""
|
||||
batch = frappe.get_doc(doctype="Batch", item=item_code, batch_id=new_batch_id).insert()
|
||||
|
||||
@@ -511,7 +511,7 @@ def get_material_requests_based_on_supplier(
|
||||
return material_requests
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
@frappe.whitelist(methods=["POST"])
|
||||
def raise_work_orders(material_request: str, company: str):
|
||||
mr = frappe.get_doc("Material Request", material_request)
|
||||
errors = []
|
||||
|
||||
@@ -191,7 +191,7 @@ def get_children(
|
||||
return frappe.get_list(doctype, fields=fields, filters=filters, order_by="name")
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
@frappe.whitelist(methods=["POST"])
|
||||
def add_node():
|
||||
from frappe.desk.treeview import make_tree_args
|
||||
|
||||
|
||||
@@ -182,7 +182,7 @@ def get_columns(filters):
|
||||
]
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
@frappe.whitelist(methods=["POST"])
|
||||
def create_reposting_entries(rows: str | list, company: str):
|
||||
if isinstance(rows, str):
|
||||
rows = parse_json(rows)
|
||||
|
||||
@@ -306,7 +306,7 @@ def get_columns():
|
||||
]
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
@frappe.whitelist(methods=["POST"])
|
||||
def create_reposting_entries(rows: str | list, item_code: str | None = None, warehouse: str | None = None):
|
||||
if isinstance(rows, str):
|
||||
rows = parse_json(rows)
|
||||
|
||||
@@ -22,7 +22,7 @@ def make_subcontract_return(source_name: str, target_doc: Document | str | None
|
||||
return make_return_doc("Subcontracting Receipt", source_name, target_doc)
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
@frappe.whitelist(methods=["POST"])
|
||||
def make_purchase_receipt(
|
||||
source_name: Document | str,
|
||||
target_doc: Document | str | None = None,
|
||||
|
||||
@@ -117,7 +117,7 @@ class Issue(Document):
|
||||
communication.flags.ignore_mandatory = True
|
||||
communication.save()
|
||||
|
||||
@frappe.whitelist()
|
||||
@frappe.whitelist(methods=["POST"])
|
||||
def split_issue(self, subject: str, communication_id: str):
|
||||
from copy import deepcopy
|
||||
|
||||
@@ -273,7 +273,7 @@ def make_task(source_name: str, target_doc: str | Document | None = None):
|
||||
return get_mapped_doc("Issue", source_name, {"Issue": {"doctype": "Task"}}, target_doc)
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
@frappe.whitelist(methods=["POST"])
|
||||
def make_issue_from_communication(communication: str, ignore_communication_links: bool = False):
|
||||
"""raise a issue from email"""
|
||||
|
||||
|
||||
@@ -779,7 +779,7 @@ def get_response_and_resolution_duration(doc):
|
||||
return priority
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
@frappe.whitelist(methods=["POST"])
|
||||
def reset_service_level_agreement(doctype: str, docname: str, reason: str, user: str):
|
||||
if not frappe.db.get_single_value("Support Settings", "allow_resetting_service_level_agreement"):
|
||||
frappe.throw(_("Allow Resetting Service Level Agreement from Support Settings."))
|
||||
|
||||
@@ -127,7 +127,7 @@ class CallLog(Document):
|
||||
self.employee_user_id = employees[0].get("user_id")
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
@frappe.whitelist(methods=["POST"])
|
||||
def add_call_summary_and_call_type(call_log: str, summary: str, call_type: str):
|
||||
doc = frappe.get_doc("Call Log", call_log)
|
||||
doc.type_of_call = call_type
|
||||
|
||||
Reference in New Issue
Block a user