Merge branch 'develop' of https://github.com/frappe/erpnext into revert_dynamic_splitting

This commit is contained in:
Deepesh Garg 2024-01-17 12:33:07 +05:30
commit 120bfdf33d
10 changed files with 134 additions and 45 deletions

View File

@ -202,8 +202,7 @@
"fieldname": "purchase_date",
"fieldtype": "Date",
"label": "Purchase Date",
"mandatory_depends_on": "eval:!doc.is_existing_asset",
"read_only": 1,
"mandatory_depends_on": "eval:!doc.is_existing_asset && !doc.is_composite_asset",
"read_only_depends_on": "eval:!doc.is_existing_asset && !doc.is_composite_asset"
},
{
@ -590,7 +589,7 @@
"link_fieldname": "target_asset"
}
],
"modified": "2024-01-05 17:36:53.131512",
"modified": "2024-01-15 17:35:49.226603",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset",

View File

@ -162,6 +162,7 @@ class Asset(AccountsController):
def on_cancel(self):
self.validate_cancellation()
self.cancel_movement_entries()
self.cancel_capitalization()
self.delete_depreciation_entries()
cancel_asset_depr_schedules(self)
self.set_status()
@ -517,6 +518,16 @@ class Asset(AccountsController):
movement = frappe.get_doc("Asset Movement", movement.get("name"))
movement.cancel()
def cancel_capitalization(self):
asset_capitalization = frappe.db.get_value(
"Asset Capitalization",
{"target_asset": self.name, "docstatus": 1, "entry_type": "Capitalization"},
)
if asset_capitalization:
asset_capitalization = frappe.get_doc("Asset Capitalization", asset_capitalization)
asset_capitalization.cancel()
def delete_depreciation_entries(self):
if self.calculate_depreciation:
for row in self.get("finance_books"):

View File

@ -136,11 +136,19 @@ class AssetCapitalization(StockController):
"Stock Ledger Entry",
"Repost Item Valuation",
"Serial and Batch Bundle",
"Asset",
)
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)
if asset_doc.docstatus == 1:
asset_doc.cancel()
def set_title(self):
self.title = self.target_asset_name or self.target_item_name or self.target_item_code

View File

@ -7,6 +7,7 @@ from frappe.model.document import Document
from frappe.utils import (
add_days,
add_months,
add_years,
cint,
date_diff,
flt,
@ -18,6 +19,7 @@ from frappe.utils import (
)
import erpnext
from erpnext.accounts.utils import get_fiscal_year
class AssetDepreciationSchedule(Document):
@ -283,12 +285,20 @@ class AssetDepreciationSchedule(Document):
depreciation_amount = 0
number_of_pending_depreciations = final_number_of_depreciations - start
yearly_opening_wdv = value_after_depreciation
current_fiscal_year_end_date = None
for n in range(start, final_number_of_depreciations):
# If depreciation is already completed (for double declining balance)
if skip_row:
continue
schedule_date = add_months(row.depreciation_start_date, n * cint(row.frequency_of_depreciation))
if not current_fiscal_year_end_date:
current_fiscal_year_end_date = get_fiscal_year(row.depreciation_start_date)[2]
elif getdate(schedule_date) > getdate(current_fiscal_year_end_date):
current_fiscal_year_end_date = add_years(current_fiscal_year_end_date, 1)
yearly_opening_wdv = value_after_depreciation
if n > 0 and len(self.get("depreciation_schedule")) > n - 1:
prev_depreciation_amount = self.get("depreciation_schedule")[n - 1].depreciation_amount
else:
@ -298,6 +308,7 @@ class AssetDepreciationSchedule(Document):
self,
asset_doc,
value_after_depreciation,
yearly_opening_wdv,
row,
n,
prev_depreciation_amount,
@ -401,8 +412,9 @@ class AssetDepreciationSchedule(Document):
if not depreciation_amount:
continue
value_after_depreciation -= flt(
depreciation_amount, asset_doc.precision("gross_purchase_amount")
value_after_depreciation = flt(
value_after_depreciation - flt(depreciation_amount),
asset_doc.precision("gross_purchase_amount"),
)
# Adjust depreciation amount in the last period based on the expected value after useful life
@ -582,6 +594,7 @@ def get_depreciation_amount(
asset_depr_schedule,
asset,
depreciable_value,
yearly_opening_wdv,
fb_row,
schedule_idx=0,
prev_depreciation_amount=0,
@ -597,6 +610,7 @@ def get_depreciation_amount(
asset,
fb_row,
depreciable_value,
yearly_opening_wdv,
schedule_idx,
prev_depreciation_amount,
has_wdv_or_dd_non_yearly_pro_rata,
@ -744,19 +758,23 @@ def get_wdv_or_dd_depr_amount(
asset,
fb_row,
depreciable_value,
yearly_opening_wdv,
schedule_idx,
prev_depreciation_amount,
has_wdv_or_dd_non_yearly_pro_rata,
asset_depr_schedule,
):
return get_default_wdv_or_dd_depr_amount(
asset,
fb_row,
depreciable_value,
schedule_idx,
prev_depreciation_amount,
has_wdv_or_dd_non_yearly_pro_rata,
asset_depr_schedule,
return (
get_default_wdv_or_dd_depr_amount(
asset,
fb_row,
depreciable_value,
schedule_idx,
prev_depreciation_amount,
has_wdv_or_dd_non_yearly_pro_rata,
asset_depr_schedule,
),
None,
)

View File

@ -6,10 +6,12 @@ import json
from collections import OrderedDict, defaultdict
import frappe
from frappe import scrub
from frappe import qb, scrub
from frappe.desk.reportview import get_filters_cond, get_match_cond
from frappe.query_builder.functions import Concat, Sum
from frappe.query_builder import Criterion, CustomFunction
from frappe.query_builder.functions import Concat, Locate, Sum
from frappe.utils import nowdate, today, unique
from pypika import Order
import erpnext
from erpnext.stock.get_item_details import _get_item_tax_template
@ -344,37 +346,46 @@ def bom(doctype, txt, searchfield, start, page_len, filters):
@frappe.whitelist()
@frappe.validate_and_sanitize_search_inputs
def get_project_name(doctype, txt, searchfield, start, page_len, filters):
doctype = "Project"
cond = ""
proj = qb.DocType("Project")
qb_filter_and_conditions = []
qb_filter_or_conditions = []
ifelse = CustomFunction("IF", ["condition", "then", "else"])
if filters and filters.get("customer"):
cond = """(`tabProject`.customer = %s or
ifnull(`tabProject`.customer,"")="") and""" % (
frappe.db.escape(filters.get("customer"))
)
qb_filter_and_conditions.append(proj.customer == filters.get("customer"))
qb_filter_and_conditions.append(proj.status.notin(["Completed", "Cancelled"]))
q = qb.from_(proj)
fields = get_fields(doctype, ["name", "project_name"])
searchfields = frappe.get_meta(doctype).get_search_fields()
searchfields = " or ".join(["`tabProject`." + field + " like %(txt)s" for field in searchfields])
for x in fields:
q = q.select(proj[x])
return frappe.db.sql(
"""select {fields} from `tabProject`
where
`tabProject`.status not in ('Completed', 'Cancelled')
and {cond} {scond} {match_cond}
order by
(case when locate(%(_txt)s, `tabProject`.name) > 0 then locate(%(_txt)s, `tabProject`.name) else 99999 end),
`tabProject`.idx desc,
`tabProject`.name asc
limit {page_len} offset {start}""".format(
fields=", ".join(["`tabProject`.{0}".format(f) for f in fields]),
cond=cond,
scond=searchfields,
match_cond=get_match_cond(doctype),
start=start,
page_len=page_len,
),
{"txt": "%{0}%".format(txt), "_txt": txt.replace("%", "")},
)
# don't consider 'customer' and 'status' fields for pattern search, as they must be exactly matched
searchfields = [
x for x in frappe.get_meta(doctype).get_search_fields() if x not in ["customer", "status"]
]
# pattern search
if txt:
for x in searchfields:
qb_filter_or_conditions.append(proj[x].like(f"%{txt}%"))
q = q.where(Criterion.all(qb_filter_and_conditions)).where(Criterion.any(qb_filter_or_conditions))
# ordering
if txt:
# project_name containing search string 'txt' will be given higher precedence
q = q.orderby(ifelse(Locate(txt, proj.project_name) > 0, Locate(txt, proj.project_name), 99999))
q = q.orderby(proj.idx, order=Order.desc).orderby(proj.name)
if page_len:
q = q.limit(page_len)
if start:
q = q.offset(start)
return q.run()
@frappe.whitelist()

View File

@ -68,7 +68,7 @@ class TestQueries(unittest.TestCase):
self.assertGreaterEqual(len(query(txt="_Test Item Home Desktop Manufactured")), 1)
def test_project_query(self):
query = add_default_params(queries.get_project_name, "BOM")
query = add_default_params(queries.get_project_name, "Project")
self.assertGreaterEqual(len(query(txt="_Test Project")), 1)

View File

@ -94,6 +94,9 @@ frappe.ui.form.on("Sales Order", {
frm.set_value("reserve_stock", 0);
frm.set_df_property("reserve_stock", "read_only", 1);
frm.set_df_property("reserve_stock", "hidden", 1);
frm.fields_dict.items.grid.update_docfield_property('reserve_stock', 'hidden', 1);
frm.fields_dict.items.grid.update_docfield_property('reserve_stock', 'default', 0);
frm.fields_dict.items.grid.update_docfield_property('reserve_stock', 'read_only', 1);
}
})
}

View File

@ -200,6 +200,7 @@ class SalesOrder(SellingController):
self.validate_for_items()
self.validate_warehouse()
self.validate_drop_ship()
self.validate_reserved_stock()
self.validate_serial_no_based_delivery()
validate_against_blanket_order(self)
validate_inter_company_party(
@ -660,6 +661,17 @@ class SalesOrder(SellingController):
).format(item.item_code)
)
def validate_reserved_stock(self):
"""Clean reserved stock flag for non-stock Item"""
enable_stock_reservation = frappe.db.get_single_value(
"Stock Settings", "enable_stock_reservation"
)
for item in self.items:
if item.reserve_stock and (not enable_stock_reservation or not cint(item.is_stock_item)):
item.reserve_stock = 0
def has_unreserved_stock(self) -> bool:
"""Returns True if there is any unreserved item in the Sales Order."""

View File

@ -10,6 +10,7 @@
"item_code",
"customer_item_code",
"ensure_delivery_based_on_produced_serial_no",
"is_stock_item",
"reserve_stock",
"col_break1",
"delivery_date",
@ -867,6 +868,7 @@
{
"allow_on_submit": 1,
"default": "1",
"depends_on": "eval:doc.is_stock_item",
"fieldname": "reserve_stock",
"fieldtype": "Check",
"label": "Reserve Stock",
@ -891,6 +893,16 @@
"label": "Production Plan Qty",
"no_copy": 1,
"read_only": 1
},
{
"default": "0",
"fetch_from": "item_code.is_stock_item",
"fieldname": "is_stock_item",
"fieldtype": "Check",
"hidden": 1,
"label": "Is Stock Item",
"print_hide": 1,
"report_hide": 1
}
],
"idx": 1,

View File

@ -186,7 +186,7 @@
"idx": 1,
"in_create": 1,
"links": [],
"modified": "2023-11-01 16:51:17.079107",
"modified": "2024-01-16 15:11:46.140323",
"modified_by": "Administrator",
"module": "Stock",
"name": "Bin",
@ -213,6 +213,21 @@
"read": 1,
"report": 1,
"role": "Stock User"
},
{
"read": 1,
"report": 1,
"role": "Stock Manager"
},
{
"read": 1,
"report": 1,
"role": "Purchase Manager"
},
{
"read": 1,
"report": 1,
"role": "Sales Manager"
}
],
"quick_entry": 1,