Merge branch 'develop' into erpnext_form_cleanups

This commit is contained in:
Deepesh Garg
2026-02-05 09:50:22 +05:30
committed by GitHub
15 changed files with 391 additions and 236 deletions

View File

@@ -535,10 +535,12 @@ class PaymentRequest(Document):
row_number += TO_SKIP_NEW_ROW row_number += TO_SKIP_NEW_ROW
@frappe.whitelist(allow_guest=True) @frappe.whitelist()
def make_payment_request(**args): def make_payment_request(**args):
"""Make payment request""" """Make payment request"""
frappe.has_permission(doctype="Payment Request", ptype="write", throw=True)
args = frappe._dict(args) args = frappe._dict(args)
if args.dt not in ALLOWED_DOCTYPES_FOR_PAYMENT_REQUEST: if args.dt not in ALLOWED_DOCTYPES_FOR_PAYMENT_REQUEST:
frappe.throw(_("Payment Requests cannot be created against: {0}").format(frappe.bold(args.dt))) frappe.throw(_("Payment Requests cannot be created against: {0}").format(frappe.bold(args.dt)))

View File

@@ -12,56 +12,76 @@
"disabled", "disabled",
"column_break_9", "column_break_9",
"warehouse", "warehouse",
"utm_source",
"utm_campaign",
"utm_medium",
"company_address", "company_address",
"section_break_15", "accounting_tab",
"applicable_for_users",
"section_break_11", "section_break_11",
"payments", "payments",
"set_grand_total_to_default_mop",
"price_list_and_currency_section",
"currency",
"column_break_bptt",
"selling_price_list",
"write_off_section",
"write_off_account",
"column_break_ukpz",
"write_off_cost_center",
"column_break_pkca",
"write_off_limit",
"income_and_expense_account",
"income_account",
"column_break_byzk",
"expense_account",
"taxes_section",
"taxes_and_charges",
"column_break_cjpp",
"tax_category",
"section_break_19",
"account_for_change_amount",
"disable_rounded_total",
"column_break_23",
"apply_discount_on",
"allow_partial_payment",
"accounting_dimensions_section",
"cost_center",
"dimension_col_break",
"project",
"pos_configurations_tab",
"section_break_14", "section_break_14",
"hide_images",
"hide_unavailable_items",
"auto_add_item_to_cart",
"validate_stock_on_save",
"print_receipt_on_order_complete",
"action_on_new_invoice", "action_on_new_invoice",
"validate_stock_on_save",
"column_break_16", "column_break_16",
"update_stock", "update_stock",
"ignore_pricing_rule", "ignore_pricing_rule",
"print_receipt_on_order_complete",
"pos_item_selector_section",
"hide_images",
"column_break_rpny",
"hide_unavailable_items",
"column_break_stcl",
"auto_add_item_to_cart",
"pos_item_details_section",
"allow_rate_change", "allow_rate_change",
"column_break_hwfg",
"allow_discount_change", "allow_discount_change",
"set_grand_total_to_default_mop", "section_break_15",
"allow_partial_payment", "applicable_for_users",
"section_break_23", "section_break_23",
"item_groups", "item_groups",
"column_break_25", "column_break_25",
"customer_groups", "customer_groups",
"more_info_tab",
"section_break_16", "section_break_16",
"print_format", "print_format",
"letter_head", "letter_head",
"column_break0", "column_break0",
"tc_name", "tc_name",
"select_print_heading", "select_print_heading",
"section_break_19", "campaign_section_break",
"selling_price_list", "utm_source",
"currency", "column_break_tvls",
"write_off_account", "utm_campaign",
"write_off_cost_center", "column_break_xygw",
"write_off_limit", "utm_medium"
"account_for_change_amount",
"disable_rounded_total",
"column_break_23",
"income_account",
"expense_account",
"taxes_and_charges",
"tax_category",
"apply_discount_on",
"accounting_dimensions_section",
"cost_center",
"dimension_col_break",
"project"
], ],
"fields": [ "fields": [
{ {
@@ -130,8 +150,7 @@
}, },
{ {
"fieldname": "section_break_14", "fieldname": "section_break_14",
"fieldtype": "Section Break", "fieldtype": "Section Break"
"label": "Configuration"
}, },
{ {
"description": "Only show Items from these Item Groups", "description": "Only show Items from these Item Groups",
@@ -152,6 +171,7 @@
"options": "POS Customer Group" "options": "POS Customer Group"
}, },
{ {
"collapsible": 1,
"fieldname": "section_break_16", "fieldname": "section_break_16",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"label": "Print Settings" "label": "Print Settings"
@@ -191,7 +211,7 @@
{ {
"fieldname": "section_break_19", "fieldname": "section_break_19",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"label": "Accounting" "label": "Miscellaneous"
}, },
{ {
"fieldname": "selling_price_list", "fieldname": "selling_price_list",
@@ -427,9 +447,101 @@
}, },
{ {
"default": "0", "default": "0",
"description": "Applicable on POS Invoice",
"fieldname": "allow_partial_payment", "fieldname": "allow_partial_payment",
"fieldtype": "Check", "fieldtype": "Check",
"label": "Allow Partial Payment" "label": "Allow Partial Payment"
},
{
"fieldname": "column_break_tvls",
"fieldtype": "Column Break"
},
{
"fieldname": "column_break_xygw",
"fieldtype": "Column Break"
},
{
"collapsible": 1,
"fieldname": "campaign_section_break",
"fieldtype": "Section Break",
"label": "Campaign"
},
{
"fieldname": "accounting_tab",
"fieldtype": "Tab Break",
"label": "Accounting"
},
{
"fieldname": "more_info_tab",
"fieldtype": "Tab Break",
"label": "More Info"
},
{
"fieldname": "pos_configurations_tab",
"fieldtype": "Tab Break",
"label": "POS Configurations"
},
{
"fieldname": "price_list_and_currency_section",
"fieldtype": "Section Break",
"label": "Price List & Currency"
},
{
"fieldname": "column_break_bptt",
"fieldtype": "Column Break"
},
{
"fieldname": "write_off_section",
"fieldtype": "Section Break",
"label": "Write Off"
},
{
"fieldname": "column_break_ukpz",
"fieldtype": "Column Break"
},
{
"fieldname": "column_break_pkca",
"fieldtype": "Column Break"
},
{
"fieldname": "income_and_expense_account",
"fieldtype": "Section Break",
"label": "Income and Expense"
},
{
"fieldname": "column_break_byzk",
"fieldtype": "Column Break"
},
{
"fieldname": "taxes_section",
"fieldtype": "Section Break",
"label": "Taxes"
},
{
"fieldname": "column_break_cjpp",
"fieldtype": "Column Break"
},
{
"fieldname": "pos_item_selector_section",
"fieldtype": "Section Break",
"label": "POS Item Selector"
},
{
"fieldname": "column_break_rpny",
"fieldtype": "Column Break"
},
{
"fieldname": "column_break_stcl",
"fieldtype": "Column Break"
},
{
"fieldname": "pos_item_details_section",
"fieldtype": "Section Break",
"label": "POS Item Details"
},
{
"fieldname": "column_break_hwfg",
"fieldtype": "Column Break"
} }
], ],
"grid_page_length": 50, "grid_page_length": 50,
@@ -458,7 +570,7 @@
"link_fieldname": "pos_profile" "link_fieldname": "pos_profile"
} }
], ],
"modified": "2025-06-24 11:19:19.834905", "modified": "2026-02-05 03:38:13.216277",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "POS Profile", "name": "POS Profile",

View File

@@ -8,12 +8,12 @@
"email_append_to": 1, "email_append_to": 1,
"engine": "InnoDB", "engine": "InnoDB",
"field_order": [ "field_order": [
"company",
"title", "title",
"naming_series", "naming_series",
"supplier", "supplier",
"supplier_name", "supplier_name",
"tax_id", "tax_id",
"company",
"column_break_6", "column_break_6",
"posting_date", "posting_date",
"posting_time", "posting_time",
@@ -85,20 +85,24 @@
"taxes_and_charges_added", "taxes_and_charges_added",
"taxes_and_charges_deducted", "taxes_and_charges_deducted",
"total_taxes_and_charges", "total_taxes_and_charges",
"section_break_49", "totals_section",
"grand_total",
"disable_rounded_total",
"rounding_adjustment",
"column_break8",
"use_company_roundoff_cost_center",
"in_words",
"rounded_total",
"base_totals_section",
"base_grand_total", "base_grand_total",
"base_rounding_adjustment", "base_rounding_adjustment",
"base_rounded_total", "column_break_hcca",
"base_in_words", "base_in_words",
"column_break8", "base_rounded_total",
"grand_total", "section_break_ttrv",
"rounding_adjustment",
"use_company_roundoff_cost_center",
"rounded_total",
"in_words",
"total_advance", "total_advance",
"column_break_peap",
"outstanding_amount", "outstanding_amount",
"disable_rounded_total",
"section_tax_withholding_entry", "section_tax_withholding_entry",
"tax_withholding_group", "tax_withholding_group",
"ignore_tax_withholding_threshold", "ignore_tax_withholding_threshold",
@@ -882,15 +886,10 @@
"options": "currency", "options": "currency",
"print_hide": 1 "print_hide": 1
}, },
{
"fieldname": "section_break_49",
"fieldtype": "Section Break",
"label": "Totals"
},
{ {
"fieldname": "base_grand_total", "fieldname": "base_grand_total",
"fieldtype": "Currency", "fieldtype": "Currency",
"label": "Grand Total (Company Currency)", "label": "Grand Total",
"oldfieldname": "grand_total", "oldfieldname": "grand_total",
"oldfieldtype": "Currency", "oldfieldtype": "Currency",
"options": "Company:company:default_currency", "options": "Company:company:default_currency",
@@ -901,7 +900,7 @@
"depends_on": "eval:!doc.disable_rounded_total", "depends_on": "eval:!doc.disable_rounded_total",
"fieldname": "base_rounding_adjustment", "fieldname": "base_rounding_adjustment",
"fieldtype": "Currency", "fieldtype": "Currency",
"label": "Rounding Adjustment (Company Currency)", "label": "Rounding Adjustment",
"no_copy": 1, "no_copy": 1,
"options": "Company:company:default_currency", "options": "Company:company:default_currency",
"print_hide": 1, "print_hide": 1,
@@ -911,7 +910,7 @@
"depends_on": "eval:!doc.disable_rounded_total", "depends_on": "eval:!doc.disable_rounded_total",
"fieldname": "base_rounded_total", "fieldname": "base_rounded_total",
"fieldtype": "Currency", "fieldtype": "Currency",
"label": "Rounded Total (Company Currency)", "label": "Rounded Total",
"no_copy": 1, "no_copy": 1,
"options": "Company:company:default_currency", "options": "Company:company:default_currency",
"print_hide": 1, "print_hide": 1,
@@ -920,7 +919,7 @@
{ {
"fieldname": "base_in_words", "fieldname": "base_in_words",
"fieldtype": "Data", "fieldtype": "Data",
"label": "In Words (Company Currency)", "label": "In Words",
"length": 240, "length": 240,
"oldfieldname": "in_words", "oldfieldname": "in_words",
"oldfieldtype": "Data", "oldfieldtype": "Data",
@@ -1625,8 +1624,7 @@
"hidden": 1, "hidden": 1,
"label": "Item Wise Tax Details", "label": "Item Wise Tax Details",
"no_copy": 1, "no_copy": 1,
"options": "Item Wise Tax Detail", "options": "Item Wise Tax Detail"
"print_hide": 1
}, },
{ {
"collapsible": 1, "collapsible": 1,
@@ -1661,6 +1659,28 @@
"fieldname": "override_tax_withholding_entries", "fieldname": "override_tax_withholding_entries",
"fieldtype": "Check", "fieldtype": "Check",
"label": "Edit Tax Withholding Entries" "label": "Edit Tax Withholding Entries"
},
{
"fieldname": "column_break_hcca",
"fieldtype": "Column Break"
},
{
"fieldname": "section_break_ttrv",
"fieldtype": "Section Break"
},
{
"fieldname": "column_break_peap",
"fieldtype": "Column Break"
},
{
"fieldname": "base_totals_section",
"fieldtype": "Section Break",
"label": "Totals (Company Currency)"
},
{
"fieldname": "totals_section",
"fieldtype": "Section Break",
"label": "Totals"
} }
], ],
"grid_page_length": 50, "grid_page_length": 50,
@@ -1668,7 +1688,7 @@
"idx": 204, "idx": 204,
"is_submittable": 1, "is_submittable": 1,
"links": [], "links": [],
"modified": "2026-02-03 14:23:47.937128", "modified": "2026-02-04 16:32:19.664287",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Purchase Invoice", "name": "Purchase Invoice",

View File

@@ -461,27 +461,6 @@ erpnext.buying.PurchaseOrderController = class PurchaseOrderController extends (
} }
} }
get_items_from_open_material_requests() {
erpnext.utils.map_current_doc({
method: "erpnext.stock.doctype.material_request.material_request.make_purchase_order_based_on_supplier",
args: {
supplier: this.frm.doc.supplier,
},
source_doctype: "Material Request",
source_name: this.frm.doc.supplier,
target: this.frm,
setters: {
company: this.frm.doc.company,
},
get_query_filters: {
docstatus: ["!=", 2],
supplier: this.frm.doc.supplier,
},
get_query_method:
"erpnext.stock.doctype.material_request.material_request.get_material_requests_based_on_supplier",
});
}
validate() { validate() {
set_schedule_date(this.frm); set_schedule_date(this.frm);
} }

View File

@@ -9,23 +9,20 @@
"engine": "InnoDB", "engine": "InnoDB",
"field_order": [ "field_order": [
"supplier_section", "supplier_section",
"company",
"title", "title",
"naming_series", "naming_series",
"supplier",
"supplier_name",
"order_confirmation_no", "order_confirmation_no",
"order_confirmation_date", "order_confirmation_date",
"get_items_from_open_material_requests",
"mps",
"column_break_7", "column_break_7",
"transaction_date", "transaction_date",
"schedule_date", "schedule_date",
"column_break1", "column_break1",
"supplier", "company",
"is_subcontracted", "is_subcontracted",
"supplier_name",
"has_unit_price_items", "has_unit_price_items",
"supplier_warehouse", "supplier_warehouse",
"amended_from",
"accounting_dimensions_section", "accounting_dimensions_section",
"cost_center", "cost_center",
"dimension_col_break", "dimension_col_break",
@@ -79,16 +76,19 @@
"taxes_and_charges_deducted", "taxes_and_charges_deducted",
"total_taxes_and_charges", "total_taxes_and_charges",
"totals_section", "totals_section",
"grand_total",
"disable_rounded_total",
"rounding_adjustment",
"column_break4",
"in_words",
"rounded_total",
"base_totals_section",
"base_grand_total", "base_grand_total",
"base_rounding_adjustment", "base_rounding_adjustment",
"column_break_jkoz",
"base_in_words", "base_in_words",
"base_rounded_total", "base_rounded_total",
"column_break4", "section_break_tnkm",
"grand_total",
"rounding_adjustment",
"rounded_total",
"disable_rounded_total",
"in_words",
"advance_paid", "advance_paid",
"discount_section", "discount_section",
"apply_discount_on", "apply_discount_on",
@@ -154,11 +154,13 @@
"auto_repeat", "auto_repeat",
"update_auto_repeat_reference", "update_auto_repeat_reference",
"additional_info_section", "additional_info_section",
"is_internal_supplier", "party_account_currency",
"represents_company", "represents_company",
"ref_sq", "ref_sq",
"amended_from",
"column_break_74", "column_break_74",
"party_account_currency", "mps",
"is_internal_supplier",
"inter_company_order_reference", "inter_company_order_reference",
"is_old_subcontracting_flow", "is_old_subcontracting_flow",
"connections_tab" "connections_tab"
@@ -206,13 +208,6 @@
"reqd": 1, "reqd": 1,
"search_index": 1 "search_index": 1
}, },
{
"depends_on": "eval:doc.supplier && doc.docstatus===0 && (!(doc.items && doc.items.length) || (doc.items.length==1 && !doc.items[0].item_code))",
"description": "Fetch items based on Default Supplier.",
"fieldname": "get_items_from_open_material_requests",
"fieldtype": "Button",
"label": "Get Items from Open Material Requests"
},
{ {
"bold": 1, "bold": 1,
"fetch_from": "supplier.supplier_name", "fetch_from": "supplier.supplier_name",
@@ -773,7 +768,7 @@
{ {
"fieldname": "base_grand_total", "fieldname": "base_grand_total",
"fieldtype": "Currency", "fieldtype": "Currency",
"label": "Grand Total (Company Currency)", "label": "Grand Total",
"no_copy": 1, "no_copy": 1,
"oldfieldname": "grand_total", "oldfieldname": "grand_total",
"oldfieldtype": "Currency", "oldfieldtype": "Currency",
@@ -785,7 +780,7 @@
"depends_on": "eval:!doc.disable_rounded_total", "depends_on": "eval:!doc.disable_rounded_total",
"fieldname": "base_rounding_adjustment", "fieldname": "base_rounding_adjustment",
"fieldtype": "Currency", "fieldtype": "Currency",
"label": "Rounding Adjustment (Company Currency)", "label": "Rounding Adjustment",
"no_copy": 1, "no_copy": 1,
"options": "Company:company:default_currency", "options": "Company:company:default_currency",
"print_hide": 1, "print_hide": 1,
@@ -794,7 +789,7 @@
{ {
"fieldname": "base_in_words", "fieldname": "base_in_words",
"fieldtype": "Data", "fieldtype": "Data",
"label": "In Words (Company Currency)", "label": "In Words",
"length": 240, "length": 240,
"oldfieldname": "in_words", "oldfieldname": "in_words",
"oldfieldtype": "Data", "oldfieldtype": "Data",
@@ -804,7 +799,7 @@
{ {
"fieldname": "base_rounded_total", "fieldname": "base_rounded_total",
"fieldtype": "Currency", "fieldtype": "Currency",
"label": "Rounded Total (Company Currency)", "label": "Rounded Total",
"oldfieldname": "rounded_total", "oldfieldname": "rounded_total",
"oldfieldtype": "Currency", "oldfieldtype": "Currency",
"options": "Company:company:default_currency", "options": "Company:company:default_currency",
@@ -862,7 +857,7 @@
{ {
"fieldname": "advance_paid", "fieldname": "advance_paid",
"fieldtype": "Currency", "fieldtype": "Currency",
"label": "Advance Paid", "label": "Advance Paid (Company Currency)",
"no_copy": 1, "no_copy": 1,
"options": "party_account_currency", "options": "party_account_currency",
"print_hide": 1, "print_hide": 1,
@@ -1301,8 +1296,21 @@
"hidden": 1, "hidden": 1,
"label": "Item Wise Tax Details", "label": "Item Wise Tax Details",
"no_copy": 1, "no_copy": 1,
"options": "Item Wise Tax Detail", "options": "Item Wise Tax Detail"
"print_hide": 1 },
{
"fieldname": "column_break_jkoz",
"fieldtype": "Column Break"
},
{
"fieldname": "base_totals_section",
"fieldtype": "Section Break",
"label": "Totals (Company Currency)",
"options": "Company:company:default_currency"
},
{
"fieldname": "section_break_tnkm",
"fieldtype": "Section Break"
} }
], ],
"grid_page_length": 50, "grid_page_length": 50,
@@ -1310,7 +1318,7 @@
"idx": 105, "idx": 105,
"is_submittable": 1, "is_submittable": 1,
"links": [], "links": [],
"modified": "2026-02-03 14:44:55.192192", "modified": "2026-02-04 13:01:36.628472",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Buying", "module": "Buying",
"name": "Purchase Order", "name": "Purchase Order",

View File

@@ -1251,10 +1251,26 @@ class JobCard(Document):
frappe.db.set_value("Workstation", self.workstation, "status", status) frappe.db.set_value("Workstation", self.workstation, "status", status)
def add_time_logs(self, **kwargs): def add_time_logs(self, **kwargs):
row = None
kwargs = frappe._dict(kwargs) kwargs = frappe._dict(kwargs)
if not kwargs.employees and kwargs.to_time:
for row in self.time_logs:
if not row.to_time and row.from_time:
row.to_time = kwargs.to_time
row.time_in_mins = time_diff_in_minutes(row.to_time, row.from_time)
if kwargs.completed_qty:
row.completed_qty = kwargs.completed_qty
row.db_update()
else:
self.add_time_logs_for_employess(kwargs)
self.validate_time_logs(save=True)
self.save()
def add_time_logs_for_employess(self, kwargs):
row = None
update_status = False update_status = False
for employee in kwargs.employees: for employee in kwargs.employees:
kwargs.employee = employee.get("employee") kwargs.employee = employee.get("employee")
if kwargs.from_time and not kwargs.to_time: if kwargs.from_time and not kwargs.to_time:
@@ -1290,9 +1306,6 @@ class JobCard(Document):
self.set_status(update_status=update_status) self.set_status(update_status=update_status)
self.validate_time_logs(save=True)
self.save()
def update_workstation_status(self): def update_workstation_status(self):
status_map = { status_map = {
"Open": "Off", "Open": "Off",

View File

@@ -496,7 +496,7 @@ class ProductionPlan(Document):
item_details = get_item_details(data.item_code, throw=False) item_details = get_item_details(data.item_code, throw=False)
if self.combine_items: if self.combine_items:
bom_no = item_details.bom_no bom_no = item_details.get("bom_no")
if data.get("bom_no"): if data.get("bom_no"):
bom_no = data.get("bom_no") bom_no = data.get("bom_no")

View File

@@ -8,6 +8,8 @@ from frappe.utils import getdate, today
from erpnext.stock.report.stock_analytics.stock_analytics import get_period, get_period_date_ranges from erpnext.stock.report.stock_analytics.stock_analytics import get_period, get_period_date_ranges
WORK_ORDER_STATUS_LIST = ["Not Started", "Overdue", "Pending", "Completed", "Closed", "Stopped"]
def execute(filters=None): def execute(filters=None):
columns = get_columns(filters) columns = get_columns(filters)
@@ -16,119 +18,98 @@ def execute(filters=None):
def get_columns(filters): def get_columns(filters):
columns = [{"label": _("Status"), "fieldname": "Status", "fieldtype": "Data", "width": 140}] columns = [{"label": _("Status"), "fieldname": "status", "fieldtype": "Data", "width": 140}]
ranges = get_period_date_ranges(filters) ranges = get_period_date_ranges(filters)
for _dummy, end_date in ranges: for _dummy, end_date in ranges:
period = get_period(end_date, filters) period = get_period(end_date, filters)
columns.append({"label": _(period), "fieldname": scrub(period), "fieldtype": "Float", "width": 120}) columns.append({"label": _(period), "fieldname": scrub(period), "fieldtype": "Float", "width": 120})
return columns return columns
def get_periodic_data(filters, entry): def get_work_orders(filters):
periodic_data = { from_date = filters.get("from_date")
"Not Started": {}, to_date = filters.get("to_date")
"Overdue": {},
"Pending": {},
"Completed": {},
"Closed": {},
"Stopped": {},
}
ranges = get_period_date_ranges(filters) WorkOrder = frappe.qb.DocType("Work Order")
for from_date, end_date in ranges: return (
period = get_period(end_date, filters) frappe.qb.from_(WorkOrder)
for d in entry: .select(WorkOrder.creation, WorkOrder.actual_end_date, WorkOrder.planned_end_date, WorkOrder.status)
if getdate(from_date) <= getdate(d.creation) <= getdate(end_date) and d.status not in [ .where(
"Draft", (WorkOrder.docstatus == 1)
"Submitted", & (WorkOrder.company == filters.get("company"))
"Completed", & (
"Cancelled", (WorkOrder.creation.between(from_date, to_date))
]: | (WorkOrder.actual_end_date.between(from_date, to_date))
if d.status in ["Not Started", "Closed", "Stopped"]: )
periodic_data = update_periodic_data(periodic_data, d.status, period) )
elif getdate(today()) > getdate(d.planned_end_date): .run(as_dict=True)
periodic_data = update_periodic_data(periodic_data, "Overdue", period) )
elif getdate(today()) < getdate(d.planned_end_date):
periodic_data = update_periodic_data(periodic_data, "Pending", period)
if (
getdate(from_date) <= getdate(d.actual_end_date) <= getdate(end_date)
and d.status == "Completed"
):
periodic_data = update_periodic_data(periodic_data, "Completed", period)
return periodic_data
def update_periodic_data(periodic_data, status, period):
if periodic_data.get(status).get(period):
periodic_data[status][period] += 1
else:
periodic_data[status][period] = 1
return periodic_data
def get_data(filters, columns): def get_data(filters, columns):
data = [] ranges = build_ranges(filters)
entry = frappe.get_all( period_labels = [scrub(pd) for _fd, _td, pd in ranges]
"Work Order", periodic_data = {status: {pd: 0 for pd in period_labels} for status in WORK_ORDER_STATUS_LIST}
fields=[ entries = get_work_orders(filters)
"creation",
"actual_end_date",
"planned_end_date",
"status",
],
filters={"docstatus": 1, "company": filters["company"]},
)
periodic_data = get_periodic_data(filters, entry) for d in entries:
if d.status == "Completed":
if not d.actual_end_date:
continue
labels = ["Not Started", "Overdue", "Pending", "Completed", "Closed", "Stopped"] if period := scrub(get_period_for_date(getdate(d.actual_end_date), ranges)):
chart_data = get_chart_data(periodic_data, columns) periodic_data["Completed"][period] += 1
ranges = get_period_date_ranges(filters) continue
for label in labels: creation_date = getdate(d.creation)
work = {} period = scrub(get_period_for_date(creation_date, ranges))
work["Status"] = _(label) if not period:
for _dummy, end_date in ranges: continue
period = get_period(end_date, filters)
if periodic_data.get(label).get(period): if d.status in ("Not Started", "Closed", "Stopped"):
work[scrub(period)] = periodic_data.get(label).get(period) periodic_data[d.status][period] += 1
else:
if d.planned_end_date and getdate(today()) > getdate(d.planned_end_date):
periodic_data["Overdue"][period] += 1
else: else:
work[scrub(period)] = 0.0 periodic_data["Pending"][period] += 1
data.append(work)
return data, chart_data data = []
for status in WORK_ORDER_STATUS_LIST:
row = {"status": _(status)}
for _fd, _td, period in ranges:
row[scrub(period)] = periodic_data[status].get(scrub(period), 0)
data.append(row)
chart = get_chart_data(periodic_data, columns)
return data, chart
def get_period_for_date(date, ranges):
for from_date, to_date, period in ranges:
if from_date <= date <= to_date:
return period
return None
def build_ranges(filters):
ranges = []
for from_date, end_date in get_period_date_ranges(filters):
period = get_period(end_date, filters)
ranges.append((getdate(from_date), getdate(end_date), period))
return ranges
def get_chart_data(periodic_data, columns): def get_chart_data(periodic_data, columns):
labels = [d.get("label") for d in columns[1:]] period_labels = [d.get("label") for d in columns[1:]]
period_fieldnames = [d.get("fieldname") for d in columns[1:]]
not_start, overdue, pending, completed, closed, stopped = [], [], [], [], [], []
datasets = [] datasets = []
for status in WORK_ORDER_STATUS_LIST:
values = [periodic_data.get(status, {}).get(fieldname, 0) for fieldname in period_fieldnames]
datasets.append({"name": _(status), "values": values})
for d in labels: return {"data": {"labels": period_labels, "datasets": datasets}, "type": "line"}
not_start.append(periodic_data.get("Not Started").get(d))
overdue.append(periodic_data.get("Overdue").get(d))
pending.append(periodic_data.get("Pending").get(d))
completed.append(periodic_data.get("Completed").get(d))
closed.append(periodic_data.get("Closed").get(d))
stopped.append(periodic_data.get("Stopped").get(d))
datasets.append({"name": _("Not Started"), "values": not_start})
datasets.append({"name": _("Overdue"), "values": overdue})
datasets.append({"name": _("Pending"), "values": pending})
datasets.append({"name": _("Completed"), "values": completed})
datasets.append({"name": _("Closed"), "values": closed})
datasets.append({"name": _("Stopped"), "values": stopped})
chart = {"data": {"labels": labels, "datasets": datasets}}
chart["type"] = "line"
return chart

View File

@@ -461,4 +461,5 @@ erpnext.patches.v15_0.create_accounting_dimensions_in_advance_taxes_and_charges
execute:frappe.delete_doc_if_exists("Workspace Sidebar", "Opening & Closing") execute:frappe.delete_doc_if_exists("Workspace Sidebar", "Opening & Closing")
erpnext.patches.v16_0.migrate_transaction_deletion_task_flags_to_status # 2 erpnext.patches.v16_0.migrate_transaction_deletion_task_flags_to_status # 2
erpnext.patches.v16_0.set_ordered_qty_in_quotation_item erpnext.patches.v16_0.set_ordered_qty_in_quotation_item
erpnext.patches.v16_0.update_company_custom_field_in_bin erpnext.patches.v16_0.update_company_custom_field_in_bin
erpnext.patches.v15_0.replace_http_with_https_in_sales_partner

View File

@@ -0,0 +1,10 @@
import frappe
from frappe import qb
from pypika.functions import Replace
def execute():
sp = frappe.qb.DocType("Sales Partner")
qb.update(sp).set(sp.partner_website, Replace(sp.partner_website, "http://", "https://")).where(
sp.partner_website.rlike("^http://.*")
).run()

View File

@@ -1733,13 +1733,11 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe
this.frm.set_currency_labels( this.frm.set_currency_labels(
[ [
"advance_paid",
"base_total", "base_total",
"base_net_total", "base_net_total",
"base_total_taxes_and_charges", "base_total_taxes_and_charges",
"base_discount_amount", "base_discount_amount",
"base_grand_total",
"base_rounded_total",
"base_in_words",
"base_taxes_and_charges_added", "base_taxes_and_charges_added",
"base_taxes_and_charges_deducted", "base_taxes_and_charges_deducted",
"total_amount_to_pay", "total_amount_to_pay",
@@ -1762,17 +1760,13 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe
"net_total", "net_total",
"total_taxes_and_charges", "total_taxes_and_charges",
"discount_amount", "discount_amount",
"grand_total",
"taxes_and_charges_added", "taxes_and_charges_added",
"taxes_and_charges_deducted", "taxes_and_charges_deducted",
"tax_withholding_net_total", "tax_withholding_net_total",
"rounded_total",
"in_words",
"paid_amount", "paid_amount",
"write_off_amount", "write_off_amount",
"operating_cost", "operating_cost",
"scrap_material_cost", "scrap_material_cost",
"rounding_adjustment",
"raw_material_cost", "raw_material_cost",
"total_cost", "total_cost",
"totals_section", "totals_section",
@@ -1829,6 +1823,19 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe
this.frm.doc.price_list_currency != company_currency this.frm.doc.price_list_currency != company_currency
); );
let taxes_fields = [
"total_taxes_and_charges",
"taxes_and_charges_deducted",
"taxes_and_charges_added",
"base_taxes_and_charges_added",
"base_taxes_and_charges_deducted",
"base_total_taxes_and_charges",
];
taxes_fields.forEach((field) => {
this.frm.toggle_display(field, this.frm.doc[field] !== 0 || this.frm.doc.docstatus !== 1);
});
let show = let show =
cint(this.frm.doc.discount_amount) || cint(this.frm.doc.discount_amount) ||
(this.frm.doc.taxes || []).filter(function (d) { (this.frm.doc.taxes || []).filter(function (d) {

View File

@@ -50,8 +50,17 @@ class SalesPartner(WebsiteGenerator):
if not self.route: if not self.route:
self.route = "partners/" + self.scrub(self.partner_name) self.route = "partners/" + self.scrub(self.partner_name)
super().validate() super().validate()
if self.partner_website and not self.partner_website.startswith("http"): if self.partner_website:
self.partner_website = "http://" + self.partner_website from urllib.parse import urlsplit, urlunsplit
# scrub http
parts = urlsplit(self.partner_website)
if not parts.netloc and parts.path:
parts = parts._replace(netloc=parts.path, path="")
if not parts.scheme or parts.scheme == "http":
parts = parts._replace(scheme="https")
self.partner_website = urlunsplit(parts)
def get_context(self, context): def get_context(self, context):
address_names = frappe.db.get_all( address_names = frappe.db.get_all(

View File

@@ -77,17 +77,19 @@
"taxes_and_charges_added", "taxes_and_charges_added",
"taxes_and_charges_deducted", "taxes_and_charges_deducted",
"total_taxes_and_charges", "total_taxes_and_charges",
"section_break_46", "totals_section",
"grand_total",
"disable_rounded_total",
"rounding_adjustment",
"column_break_50",
"in_words",
"rounded_total",
"base_totals_section",
"base_grand_total", "base_grand_total",
"base_rounding_adjustment", "base_rounding_adjustment",
"base_rounded_total", "column_break_ugyv",
"base_in_words", "base_in_words",
"column_break_50", "base_rounded_total",
"grand_total",
"rounding_adjustment",
"rounded_total",
"in_words",
"disable_rounded_total",
"section_break_42", "section_break_42",
"apply_discount_on", "apply_discount_on",
"base_discount_amount", "base_discount_amount",
@@ -772,15 +774,10 @@
"options": "currency", "options": "currency",
"print_hide": 1 "print_hide": 1
}, },
{
"fieldname": "section_break_46",
"fieldtype": "Section Break",
"label": "Totals"
},
{ {
"fieldname": "base_grand_total", "fieldname": "base_grand_total",
"fieldtype": "Currency", "fieldtype": "Currency",
"label": "Grand Total (Company Currency)", "label": "Grand Total",
"oldfieldname": "grand_total", "oldfieldname": "grand_total",
"oldfieldtype": "Currency", "oldfieldtype": "Currency",
"options": "Company:company:default_currency", "options": "Company:company:default_currency",
@@ -791,7 +788,7 @@
"depends_on": "eval:!doc.disable_rounded_total", "depends_on": "eval:!doc.disable_rounded_total",
"fieldname": "base_rounding_adjustment", "fieldname": "base_rounding_adjustment",
"fieldtype": "Currency", "fieldtype": "Currency",
"label": "Rounding Adjustment (Company Currency)", "label": "Rounding Adjustment",
"no_copy": 1, "no_copy": 1,
"options": "Company:company:default_currency", "options": "Company:company:default_currency",
"print_hide": 1, "print_hide": 1,
@@ -800,7 +797,7 @@
{ {
"fieldname": "base_in_words", "fieldname": "base_in_words",
"fieldtype": "Data", "fieldtype": "Data",
"label": "In Words (Company Currency)", "label": "In Words",
"length": 240, "length": 240,
"oldfieldname": "in_words", "oldfieldname": "in_words",
"oldfieldtype": "Data", "oldfieldtype": "Data",
@@ -810,7 +807,7 @@
{ {
"fieldname": "base_rounded_total", "fieldname": "base_rounded_total",
"fieldtype": "Currency", "fieldtype": "Currency",
"label": "Rounded Total (Company Currency)", "label": "Rounded Total",
"oldfieldname": "rounded_total", "oldfieldname": "rounded_total",
"oldfieldtype": "Currency", "oldfieldtype": "Currency",
"options": "Company:company:default_currency", "options": "Company:company:default_currency",
@@ -1282,8 +1279,22 @@
"hidden": 1, "hidden": 1,
"label": "Item Wise Tax Details", "label": "Item Wise Tax Details",
"no_copy": 1, "no_copy": 1,
"options": "Item Wise Tax Detail", "options": "Item Wise Tax Detail"
"print_hide": 1 },
{
"fieldname": "totals_section",
"fieldtype": "Section Break",
"label": "Totals"
},
{
"fieldname": "base_totals_section",
"fieldtype": "Section Break",
"label": "Totals (Company Currency)",
"options": "Company:company:default_currency"
},
{
"fieldname": "column_break_ugyv",
"fieldtype": "Column Break"
} }
], ],
"grid_page_length": 50, "grid_page_length": 50,
@@ -1291,7 +1302,7 @@
"idx": 261, "idx": 261,
"is_submittable": 1, "is_submittable": 1,
"links": [], "links": [],
"modified": "2026-01-29 21:24:30.652933", "modified": "2026-02-04 14:36:41.087460",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Stock", "module": "Stock",
"name": "Purchase Receipt", "name": "Purchase Receipt",

View File

@@ -146,7 +146,7 @@
}, },
{ {
"bold": 1, "bold": 1,
"columns": 3, "columns": 2,
"fieldname": "item_code", "fieldname": "item_code",
"fieldtype": "Link", "fieldtype": "Link",
"in_global_search": 1, "in_global_search": 1,
@@ -436,7 +436,6 @@
"columns": 2, "columns": 2,
"fieldname": "net_amount", "fieldname": "net_amount",
"fieldtype": "Currency", "fieldtype": "Currency",
"in_list_view": 1,
"label": "Net Amount", "label": "Net Amount",
"options": "currency", "options": "currency",
"print_hide": 1, "print_hide": 1,
@@ -1141,7 +1140,7 @@
"idx": 1, "idx": 1,
"istable": 1, "istable": 1,
"links": [], "links": [],
"modified": "2025-10-21 10:39:32.659933", "modified": "2026-02-04 14:42:10.646809",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Stock", "module": "Stock",
"name": "Purchase Receipt Item", "name": "Purchase Receipt Item",

View File

@@ -522,6 +522,9 @@ class StockReconciliation(StockController):
if abs(difference_amount) > 0: if abs(difference_amount) > 0:
return True return True
float_precision = frappe.db.get_default("float_precision") or 3
item_dict["rate"] = flt(item_dict.get("rate"), float_precision)
item.valuation_rate = flt(item.valuation_rate, float_precision) if item.valuation_rate else None
if ( if (
(item.qty is None or item.qty == item_dict.get("qty")) (item.qty is None or item.qty == item_dict.get("qty"))
and (item.valuation_rate is None or item.valuation_rate == item_dict.get("rate")) and (item.valuation_rate is None or item.valuation_rate == item_dict.get("rate"))