mirror of
https://github.com/frappe/erpnext.git
synced 2026-04-20 23:35:11 +00:00
Merge pull request #39881 from frappe/version-14-hotfix
chore: release v14
This commit is contained in:
@@ -105,7 +105,7 @@ frappe.require("assets/erpnext/js/financial_statements.js", function() {
|
||||
"to_fiscal_year": data.fiscal_year
|
||||
};
|
||||
|
||||
if(data.based_on == 'cost_center'){
|
||||
if(data.based_on == 'Cost Center'){
|
||||
frappe.route_options["cost_center"] = data.account
|
||||
} else {
|
||||
frappe.route_options["project"] = data.account
|
||||
|
||||
@@ -322,7 +322,7 @@ frappe.ui.form.on('Asset', {
|
||||
},
|
||||
|
||||
make_schedules_editable: function(frm) {
|
||||
if (frm.doc.finance_books.length) {
|
||||
if (frm.doc.finance_books && frm.doc.finance_books.length) {
|
||||
var is_manual_hence_editable = frm.doc.finance_books.filter(d => d.depreciation_method == "Manual").length > 0
|
||||
? true : false;
|
||||
var is_shift_hence_editable = frm.doc.finance_books.filter(d => d.shift_based).length > 0
|
||||
|
||||
@@ -508,7 +508,7 @@ def modify_depreciation_schedule_for_asset_repairs(asset):
|
||||
|
||||
|
||||
def reverse_depreciation_entry_made_after_disposal(asset, date):
|
||||
if not asset.calculate_depreciation:
|
||||
if not asset.calculate_depreciation or not asset.get("schedules"):
|
||||
return
|
||||
|
||||
row = -1
|
||||
|
||||
@@ -7,6 +7,7 @@ frappe.provide("erpnext.assets");
|
||||
erpnext.assets.AssetCapitalization = class AssetCapitalization extends erpnext.stock.StockController {
|
||||
setup() {
|
||||
this.setup_posting_date_time_check();
|
||||
this.frm.ignore_doctypes_on_cancel_all = ["Asset Movement"];
|
||||
}
|
||||
|
||||
onload() {
|
||||
|
||||
@@ -77,15 +77,17 @@ class AssetCapitalization(StockController):
|
||||
"Stock Ledger Entry",
|
||||
"Repost Item Valuation",
|
||||
"Asset",
|
||||
"Asset Movement"
|
||||
)
|
||||
self.cancel_target_asset()
|
||||
self.update_stock_ledger()
|
||||
self.make_gl_entries()
|
||||
self.restore_consumed_asset_items()
|
||||
|
||||
|
||||
def cancel_target_asset(self):
|
||||
if self.entry_type == "Capitalization" and self.target_asset:
|
||||
asset_doc = frappe.get_doc("Asset", self.target_asset)
|
||||
asset_doc.db_set("capitalized_in", None)
|
||||
if asset_doc.docstatus == 1:
|
||||
asset_doc.cancel()
|
||||
|
||||
|
||||
@@ -190,8 +190,8 @@ class BuyingController(SubcontractingController):
|
||||
lc_voucher_data = frappe.db.sql(
|
||||
"""select sum(applicable_charges), cost_center
|
||||
from `tabLanded Cost Item`
|
||||
where docstatus = 1 and purchase_receipt_item = %s""",
|
||||
d.name,
|
||||
where docstatus = 1 and purchase_receipt_item = %s and receipt_document = %s""",
|
||||
(d.name, self.name),
|
||||
)
|
||||
d.landed_cost_voucher_amount = lc_voucher_data[0][0] if lc_voucher_data else 0.0
|
||||
if not d.cost_center and lc_voucher_data and lc_voucher_data[0][1]:
|
||||
|
||||
@@ -831,6 +831,9 @@ class StockController(AccountsController):
|
||||
"Stock Reconciliation",
|
||||
)
|
||||
|
||||
if not frappe.get_all("Putaway Rule", limit=1):
|
||||
return
|
||||
|
||||
if self.doctype == "Purchase Invoice" and self.get("update_stock") == 0:
|
||||
valid_doctype = False
|
||||
|
||||
|
||||
@@ -65,6 +65,7 @@ def make_order(source_name):
|
||||
def update_item(source, target, source_parent):
|
||||
target_qty = source.get("qty") - source.get("ordered_qty")
|
||||
target.qty = target_qty if not flt(target_qty) < 0 else 0
|
||||
target.rate = source.get("rate")
|
||||
item = get_item_defaults(target.item_code, source_parent.company)
|
||||
if item:
|
||||
target.item_name = item.get("item_name")
|
||||
@@ -86,6 +87,10 @@ def make_order(source_name):
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
if target_doc.doctype == "Purchase Order":
|
||||
target_doc.set_missing_values()
|
||||
|
||||
return target_doc
|
||||
|
||||
|
||||
|
||||
@@ -38,7 +38,8 @@
|
||||
"in_list_view": 1,
|
||||
"label": "Item Code",
|
||||
"options": "Item",
|
||||
"reqd": 1
|
||||
"reqd": 1,
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "item_name",
|
||||
@@ -53,7 +54,8 @@
|
||||
"in_standard_filter": 1,
|
||||
"label": "For Warehouse",
|
||||
"options": "Warehouse",
|
||||
"reqd": 1
|
||||
"reqd": 1,
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"columns": 1,
|
||||
@@ -141,7 +143,8 @@
|
||||
"fieldname": "from_warehouse",
|
||||
"fieldtype": "Link",
|
||||
"label": "From Warehouse",
|
||||
"options": "Warehouse"
|
||||
"options": "Warehouse",
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"fetch_from": "item_code.safety_stock",
|
||||
@@ -199,7 +202,7 @@
|
||||
],
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2023-09-12 12:09:08.358326",
|
||||
"modified": "2024-02-11 16:21:11.977018",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Manufacturing",
|
||||
"name": "Material Request Plan Item",
|
||||
|
||||
@@ -298,7 +298,8 @@
|
||||
"no_copy": 1,
|
||||
"options": "\nDraft\nSubmitted\nNot Started\nIn Process\nCompleted\nClosed\nCancelled\nMaterial Requested",
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
"read_only": 1,
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "amended_from",
|
||||
@@ -436,7 +437,7 @@
|
||||
"index_web_pages_for_search": 1,
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2023-12-26 16:31:13.740777",
|
||||
"modified": "2024-02-11 15:42:47.642481",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Manufacturing",
|
||||
"name": "Production Plan",
|
||||
|
||||
@@ -576,7 +576,10 @@ class ProductionPlan(Document):
|
||||
"project": self.project,
|
||||
}
|
||||
|
||||
key = (d.item_code, d.sales_order, d.warehouse)
|
||||
key = (d.item_code, d.sales_order, d.sales_order_item, d.warehouse)
|
||||
if self.combine_items:
|
||||
key = (d.item_code, d.sales_order, d.warehouse)
|
||||
|
||||
if not d.sales_order:
|
||||
key = (d.name, d.item_code, d.warehouse)
|
||||
|
||||
@@ -1691,23 +1694,23 @@ def get_reserved_qty_for_production_plan(item_code, warehouse):
|
||||
return reserved_qty_for_production_plan - reserved_qty_for_production
|
||||
|
||||
|
||||
@frappe.request_cache
|
||||
def get_non_completed_production_plans():
|
||||
table = frappe.qb.DocType("Production Plan")
|
||||
child = frappe.qb.DocType("Production Plan Item")
|
||||
|
||||
query = (
|
||||
return (
|
||||
frappe.qb.from_(table)
|
||||
.inner_join(child)
|
||||
.on(table.name == child.parent)
|
||||
.select(table.name)
|
||||
.distinct()
|
||||
.where(
|
||||
(table.docstatus == 1)
|
||||
& (table.status.notin(["Completed", "Closed"]))
|
||||
& (child.planned_qty > child.ordered_qty)
|
||||
)
|
||||
).run(as_dict=True)
|
||||
|
||||
return list(set([d.name for d in query]))
|
||||
).run(pluck="name")
|
||||
|
||||
|
||||
def get_raw_materials_of_sub_assembly_items(
|
||||
|
||||
@@ -448,7 +448,8 @@
|
||||
"no_copy": 1,
|
||||
"options": "Production Plan",
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
"read_only": 1,
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "production_plan_item",
|
||||
@@ -600,7 +601,7 @@
|
||||
"image_field": "image",
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2023-08-11 18:35:49.852069",
|
||||
"modified": "2024-02-11 15:47:13.454422",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Manufacturing",
|
||||
"name": "Work Order",
|
||||
|
||||
@@ -36,7 +36,8 @@
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Item Code",
|
||||
"options": "Item"
|
||||
"options": "Item",
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "source_warehouse",
|
||||
@@ -141,7 +142,7 @@
|
||||
],
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2022-09-28 10:50:43.512562",
|
||||
"modified": "2024-02-11 15:45:32.318374",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Manufacturing",
|
||||
"name": "Work Order Item",
|
||||
|
||||
@@ -1047,6 +1047,7 @@ def validate_cancelled_item(item_code, docstatus=None):
|
||||
frappe.throw(_("Item {0} is cancelled").format(item_code))
|
||||
|
||||
|
||||
@frappe.request_cache
|
||||
def get_last_purchase_details(item_code, doc_name=None, conversion_rate=1.0):
|
||||
"""returns last purchase details in stock uom"""
|
||||
# get last purchase order item details
|
||||
|
||||
@@ -38,6 +38,7 @@ class LandedCostVoucher(Document):
|
||||
def validate(self):
|
||||
self.check_mandatory()
|
||||
self.validate_receipt_documents()
|
||||
self.validate_line_items()
|
||||
init_landed_taxes_and_totals(self)
|
||||
self.set_total_taxes_and_charges()
|
||||
if not self.get("items"):
|
||||
@@ -45,6 +46,26 @@ class LandedCostVoucher(Document):
|
||||
|
||||
self.set_applicable_charges_on_item()
|
||||
|
||||
def validate_line_items(self):
|
||||
for d in self.get("items"):
|
||||
if (
|
||||
d.docstatus == 0
|
||||
and d.purchase_receipt_item
|
||||
and not frappe.db.exists(
|
||||
d.receipt_document_type + " Item",
|
||||
{"name": d.purchase_receipt_item, "parent": d.receipt_document},
|
||||
)
|
||||
):
|
||||
frappe.throw(
|
||||
_("Row {0}: {2} Item {1} does not exist in {2} {3}").format(
|
||||
d.idx,
|
||||
frappe.bold(d.purchase_receipt_item),
|
||||
d.receipt_document_type,
|
||||
frappe.bold(d.receipt_document),
|
||||
),
|
||||
title=_("Incorrect Reference Document (Purchase Receipt Item)"),
|
||||
)
|
||||
|
||||
def check_mandatory(self):
|
||||
if not self.get("purchase_receipts"):
|
||||
frappe.throw(_("Please enter Receipt Document"))
|
||||
|
||||
@@ -228,9 +228,17 @@ frappe.ui.form.on('Material Request', {
|
||||
const qty_fields = ['actual_qty', 'projected_qty', 'min_order_qty'];
|
||||
|
||||
if(!r.exc) {
|
||||
$.each(r.message, function(k, v) {
|
||||
if(!d[k] || in_list(qty_fields, k)) d[k] = v;
|
||||
$.each(r.message, function(key, value) {
|
||||
if(!d[key] || qty_fields.includes(key)) {
|
||||
d[key] = value;
|
||||
}
|
||||
});
|
||||
|
||||
if (d.price_list_rate != r.message.price_list_rate) {
|
||||
d.price_list_rate = r.message.price_list_rate;
|
||||
|
||||
frappe.model.set_value(d.doctype, d.name, "rate", d.price_list_rate);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -432,7 +440,6 @@ frappe.ui.form.on("Material Request Item", {
|
||||
item.amount = flt(item.qty) * flt(item.rate);
|
||||
frappe.model.set_value(doctype, name, "amount", item.amount);
|
||||
refresh_field("amount", item.name, item.parentfield);
|
||||
frm.events.get_item_data(frm, item, false);
|
||||
},
|
||||
|
||||
item_code: function(frm, doctype, name) {
|
||||
@@ -452,7 +459,12 @@ frappe.ui.form.on("Material Request Item", {
|
||||
set_schedule_date(frm);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
conversion_factor: function(frm, doctype, name) {
|
||||
const item = locals[doctype][name];
|
||||
frm.events.get_item_data(frm, item, false);
|
||||
},
|
||||
});
|
||||
|
||||
erpnext.buying.MaterialRequestController = class MaterialRequestController extends erpnext.buying.BuyingController {
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
"received_qty",
|
||||
"rate_and_amount_section_break",
|
||||
"rate",
|
||||
"price_list_rate",
|
||||
"col_break3",
|
||||
"amount",
|
||||
"accounting_details_section",
|
||||
@@ -474,13 +475,22 @@
|
||||
"fieldtype": "Link",
|
||||
"label": "WIP Composite Asset",
|
||||
"options": "Asset"
|
||||
},
|
||||
{
|
||||
"fieldname": "price_list_rate",
|
||||
"fieldtype": "Currency",
|
||||
"hidden": 1,
|
||||
"label": "Price List Rate",
|
||||
"options": "currency",
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
}
|
||||
],
|
||||
"idx": 1,
|
||||
"index_web_pages_for_search": 1,
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2023-11-14 18:37:59.599115",
|
||||
"modified": "2024-02-08 16:30:56.137858",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Material Request Item",
|
||||
|
||||
@@ -572,9 +572,7 @@ class PurchaseReceipt(BuyingController):
|
||||
)
|
||||
|
||||
stock_value_diff = (
|
||||
flt(d.base_net_amount)
|
||||
+ flt(d.item_tax_amount / self.conversion_rate)
|
||||
+ flt(d.landed_cost_voucher_amount)
|
||||
flt(d.base_net_amount) + flt(d.item_tax_amount) + flt(d.landed_cost_voucher_amount)
|
||||
)
|
||||
elif warehouse_account.get(d.warehouse):
|
||||
stock_value_diff = get_stock_value_difference(self.name, d.name, d.warehouse)
|
||||
|
||||
@@ -11,7 +11,6 @@ from erpnext.stock.doctype.warehouse.warehouse import get_child_warehouses
|
||||
|
||||
|
||||
def get_web_item_qty_in_stock(item_code, item_warehouse_field, warehouse=None):
|
||||
in_stock, stock_qty = 0, ""
|
||||
template_item_code, is_stock_item = frappe.db.get_value(
|
||||
"Item", item_code, ["variant_of", "is_stock_item"]
|
||||
)
|
||||
@@ -52,10 +51,11 @@ def get_web_item_qty_in_stock(item_code, item_warehouse_field, warehouse=None):
|
||||
.where((BIN.item_code == item_code) & (BIN.warehouse == warehouse))
|
||||
).run()
|
||||
|
||||
stock_qty = stock_qty[0][0]
|
||||
if stock_qty:
|
||||
total_stock += adjust_qty_for_expired_items(item_code, stock_qty, warehouse)
|
||||
|
||||
in_stock = total_stock > 0 and 1 or 0
|
||||
in_stock = int(total_stock > 0)
|
||||
|
||||
return frappe._dict(
|
||||
{"in_stock": in_stock, "stock_qty": total_stock, "is_stock_item": is_stock_item}
|
||||
@@ -63,20 +63,16 @@ def get_web_item_qty_in_stock(item_code, item_warehouse_field, warehouse=None):
|
||||
|
||||
|
||||
def adjust_qty_for_expired_items(item_code, stock_qty, warehouse):
|
||||
batches = frappe.get_all("Batch", filters=[{"item": item_code}], fields=["expiry_date", "name"])
|
||||
batches = frappe.get_all("Batch", filters={"item": item_code}, fields=["expiry_date", "name"])
|
||||
expired_batches = get_expired_batches(batches)
|
||||
stock_qty = [list(item) for item in stock_qty]
|
||||
|
||||
for batch in expired_batches:
|
||||
if warehouse:
|
||||
stock_qty[0][0] = max(0, stock_qty[0][0] - get_batch_qty(batch, warehouse))
|
||||
stock_qty = max(0, stock_qty - get_batch_qty(batch, warehouse))
|
||||
else:
|
||||
stock_qty[0][0] = max(0, stock_qty[0][0] - qty_from_all_warehouses(get_batch_qty(batch)))
|
||||
stock_qty = max(0, stock_qty - qty_from_all_warehouses(get_batch_qty(batch)))
|
||||
|
||||
if not stock_qty[0][0]:
|
||||
break
|
||||
|
||||
return stock_qty[0][0] if stock_qty else 0
|
||||
return stock_qty
|
||||
|
||||
|
||||
def get_expired_batches(batches):
|
||||
|
||||
Reference in New Issue
Block a user