Skip to content

Commit 1f1428f

Browse files
Merge branch 'version-16-hotfix' into mergify/bp/version-16-hotfix/pr-51900
2 parents d067e37 + 8946f12 commit 1f1428f

32 files changed

Lines changed: 457 additions & 159 deletions

File tree

erpnext/accounts/doctype/bank_account/bank_account.js

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,4 @@ frappe.ui.form.on("Bank Account", {
4242
});
4343
}
4444
},
45-
46-
is_company_account: function (frm) {
47-
frm.set_df_property("account", "reqd", frm.doc.is_company_account);
48-
},
4945
});

erpnext/accounts/doctype/bank_account/bank_account.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
"fieldtype": "Link",
5353
"in_list_view": 1,
5454
"label": "Company Account",
55+
"mandatory_depends_on": "is_company_account",
5556
"options": "Account"
5657
},
5758
{
@@ -98,6 +99,7 @@
9899
"in_list_view": 1,
99100
"in_standard_filter": 1,
100101
"label": "Company",
102+
"mandatory_depends_on": "is_company_account",
101103
"options": "Company"
102104
},
103105
{
@@ -252,7 +254,7 @@
252254
"link_fieldname": "default_bank_account"
253255
}
254256
],
255-
"modified": "2025-08-29 12:32:01.081687",
257+
"modified": "2026-01-20 00:46:16.633364",
256258
"modified_by": "Administrator",
257259
"module": "Accounts",
258260
"name": "Bank Account",

erpnext/accounts/doctype/bank_account/bank_account.py

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -51,25 +51,29 @@ def on_trash(self):
5151
delete_contact_and_address("Bank Account", self.name)
5252

5353
def validate(self):
54-
self.validate_company()
55-
self.validate_account()
54+
self.validate_is_company_account()
5655
self.update_default_bank_account()
5756

57+
def validate_is_company_account(self):
58+
if self.is_company_account:
59+
if not self.company:
60+
frappe.throw(_("Company is mandatory for company account"))
61+
62+
if not self.account:
63+
frappe.throw(_("Company Account is mandatory"))
64+
65+
self.validate_account()
66+
5867
def validate_account(self):
59-
if self.account:
60-
if accounts := frappe.db.get_all(
61-
"Bank Account", filters={"account": self.account, "name": ["!=", self.name]}, as_list=1
62-
):
63-
frappe.throw(
64-
_("'{0}' account is already used by {1}. Use another account.").format(
65-
frappe.bold(self.account),
66-
frappe.bold(comma_and([get_link_to_form(self.doctype, x[0]) for x in accounts])),
67-
)
68+
if accounts := frappe.db.get_all(
69+
"Bank Account", filters={"account": self.account, "name": ["!=", self.name]}, as_list=1
70+
):
71+
frappe.throw(
72+
_("'{0}' account is already used by {1}. Use another account.").format(
73+
frappe.bold(self.account),
74+
frappe.bold(comma_and([get_link_to_form(self.doctype, x[0]) for x in accounts])),
6875
)
69-
70-
def validate_company(self):
71-
if self.is_company_account and not self.company:
72-
frappe.throw(_("Company is mandatory for company account"))
76+
)
7377

7478
def update_default_bank_account(self):
7579
if self.is_default and not self.disabled:

erpnext/accounts/doctype/payment_entry/payment_entry.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1104,7 +1104,7 @@ frappe.ui.form.on("Payment Entry", {
11041104

11051105
allocate_party_amount_against_ref_docs: async function (frm, paid_amount, paid_amount_change) {
11061106
await frm.call("allocate_amount_to_references", {
1107-
paid_amount: paid_amount,
1107+
paid_amount: flt(paid_amount),
11081108
paid_amount_change: paid_amount_change,
11091109
allocate_payment_amount: frappe.flags.allocate_payment_amount ?? false,
11101110
});

erpnext/accounts/doctype/sales_invoice/sales_invoice.js

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -115,18 +115,21 @@ erpnext.accounts.SalesInvoiceController = class SalesInvoiceController extends (
115115
}
116116

117117
if (cint(doc.update_stock) != 1) {
118-
// show Make Delivery Note button only if Sales Invoice is not created from Delivery Note
119-
var from_delivery_note = false;
120-
from_delivery_note = this.frm.doc.items.some(function (item) {
121-
return item.delivery_note ? true : false;
122-
});
123-
124-
if (!from_delivery_note && !is_delivered_by_supplier) {
125-
this.frm.add_custom_button(
126-
__("Delivery"),
127-
this.frm.cscript["Make Delivery Note"],
128-
__("Create")
118+
if (!is_delivered_by_supplier) {
119+
const should_create_delivery_note = doc.items.some(
120+
(item) =>
121+
item.qty - item.delivered_qty > 0 &&
122+
!item.scio_detail &&
123+
!item.dn_detail &&
124+
!item.delivered_by_supplier
129125
);
126+
if (should_create_delivery_note) {
127+
this.frm.add_custom_button(
128+
__("Delivery Note"),
129+
this.frm.cscript["Make Delivery Note"],
130+
__("Create")
131+
);
132+
}
130133
}
131134
}
132135

erpnext/accounts/doctype/sales_invoice/sales_invoice.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2422,7 +2422,10 @@ def update_item(source_doc, target_doc, source_parent):
24222422
"cost_center": "cost_center",
24232423
},
24242424
"postprocess": update_item,
2425-
"condition": lambda doc: doc.delivered_by_supplier != 1 and not doc.scio_detail,
2425+
"condition": lambda doc: doc.delivered_by_supplier != 1
2426+
and not doc.scio_detail
2427+
and not doc.dn_detail
2428+
and doc.qty - doc.delivered_qty > 0,
24262429
},
24272430
"Sales Taxes and Charges": {"doctype": "Sales Taxes and Charges", "reset_value": True},
24282431
"Sales Team": {

erpnext/assets/doctype/asset/asset.js

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -116,14 +116,6 @@ frappe.ui.form.on("Asset", {
116116
__("Manage")
117117
);
118118

119-
frm.add_custom_button(
120-
__("Repair Asset"),
121-
function () {
122-
frm.trigger("create_asset_repair");
123-
},
124-
__("Manage")
125-
);
126-
127119
frm.add_custom_button(
128120
__("Split Asset"),
129121
function () {
@@ -155,6 +147,14 @@ frappe.ui.form.on("Asset", {
155147
},
156148
__("Manage")
157149
);
150+
151+
frm.add_custom_button(
152+
__("Repair Asset"),
153+
function () {
154+
frm.trigger("create_asset_repair");
155+
},
156+
__("Manage")
157+
);
158158
}
159159

160160
if (!frm.doc.calculate_depreciation) {

erpnext/controllers/stock_controller.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -552,7 +552,7 @@ def update_bundle_details(self, bundle_details, table_name, row, is_rejected=Fal
552552
if is_rejected:
553553
serial_nos = row.get("rejected_serial_no")
554554
type_of_transaction = "Inward" if not self.is_return else "Outward"
555-
qty = row.get("rejected_qty")
555+
qty = row.get("rejected_qty") * row.get("conversion_factor", 1.0)
556556
warehouse = row.get("rejected_warehouse")
557557

558558
if (

erpnext/controllers/subcontracting_controller.py

Lines changed: 37 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -166,29 +166,46 @@ def validate_items(self):
166166
_("Row {0}: Item {1} must be a subcontracted item.").format(item.idx, item.item_name)
167167
)
168168

169-
if self.doctype != "Subcontracting Receipt" and item.qty > flt(
170-
get_pending_subcontracted_quantity(
171-
self.doctype,
172-
self.purchase_order if self.doctype == "Subcontracting Order" else self.sales_order,
173-
).get(
174-
item.purchase_order_item
175-
if self.doctype == "Subcontracting Order"
176-
else item.sales_order_item
177-
)
178-
/ item.subcontracting_conversion_factor,
179-
frappe.get_precision(
169+
if self.doctype != "Subcontracting Receipt":
170+
order_item_doctype = (
180171
"Purchase Order Item"
181172
if self.doctype == "Subcontracting Order"
182-
else "Sales Order Item",
183-
"qty",
184-
),
185-
):
186-
frappe.throw(
187-
_(
188-
"Row {0}: Item {1}'s quantity cannot be higher than the available quantity."
189-
).format(item.idx, item.item_name)
173+
else "Sales Order Item"
174+
)
175+
176+
order_name = (
177+
self.purchase_order if self.doctype == "Subcontracting Order" else self.sales_order
178+
)
179+
order_item_field = frappe.scrub(order_item_doctype)
180+
181+
if not item.get(order_item_field):
182+
frappe.throw(
183+
_("Row {0}: Item {1} must be linked to a {2}.").format(
184+
item.idx, item.item_name, order_item_doctype
185+
)
186+
)
187+
188+
pending_qty = flt(
189+
flt(
190+
get_pending_subcontracted_quantity(
191+
order_item_doctype,
192+
order_name,
193+
).get(item.get(order_item_field))
194+
)
195+
/ item.subcontracting_conversion_factor,
196+
frappe.get_precision(
197+
order_item_doctype,
198+
"qty",
199+
),
190200
)
191201

202+
if item.qty > pending_qty:
203+
frappe.throw(
204+
_(
205+
"Row {0}: Item {1}'s quantity cannot be higher than the available quantity."
206+
).format(item.idx, item.item_name)
207+
)
208+
192209
if self.doctype != "Subcontracting Inward Order":
193210
item.amount = item.qty * item.rate
194211

@@ -1333,9 +1350,7 @@ def get_item_details(items):
13331350

13341351

13351352
def get_pending_subcontracted_quantity(doctype, name):
1336-
table = frappe.qb.DocType(
1337-
"Purchase Order Item" if doctype == "Subcontracting Order" else "Sales Order Item"
1338-
)
1353+
table = frappe.qb.DocType(doctype)
13391354
query = (
13401355
frappe.qb.from_(table)
13411356
.select(table.name, table.stock_qty, table.subcontracted_qty)

erpnext/controllers/subcontracting_inward_controller.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -720,6 +720,7 @@ def update_inward_order_received_items_for_raw_materials_receipt(self):
720720
item.db_set("scio_detail", scio_rm.name)
721721

722722
if data:
723+
precision = self.precision("customer_provided_item_cost", "items")
723724
result = frappe.get_all(
724725
"Subcontracting Inward Order Received Item",
725726
filters={
@@ -734,10 +735,17 @@ def update_inward_order_received_items_for_raw_materials_receipt(self):
734735
table = frappe.qb.DocType("Subcontracting Inward Order Received Item")
735736
case_expr_qty, case_expr_rate = Case(), Case()
736737
for d in result:
737-
d.received_qty += (
738-
data[d.name].transfer_qty if self._action == "submit" else -data[d.name].transfer_qty
738+
current_qty = flt(data[d.name].transfer_qty) * (1 if self._action == "submit" else -1)
739+
current_rate = flt(data[d.name].rate)
740+
741+
# Calculate weighted average rate
742+
old_total = d.rate * d.received_qty
743+
current_total = current_rate * current_qty
744+
745+
d.received_qty = d.received_qty + current_qty
746+
d.rate = (
747+
flt((old_total + current_total) / d.received_qty, precision) if d.received_qty else 0.0
739748
)
740-
d.rate += data[d.name].rate if self._action == "submit" else -data[d.name].rate
741749

742750
if not d.required_qty and not d.received_qty:
743751
deleted_docs.append(d.name)

0 commit comments

Comments
 (0)