Merge branch 'version-15-hotfix' into mergify/bp/version-15-hotfix/pr-45987

This commit is contained in:
Mihir Kandoi
2025-03-05 13:59:59 +05:30
committed by GitHub
13 changed files with 168 additions and 74 deletions

View File

@@ -50,6 +50,7 @@ def get_group_by_asset_category_data(filters):
flt(row.accumulated_depreciation_as_on_from_date) flt(row.accumulated_depreciation_as_on_from_date)
+ flt(row.depreciation_amount_during_the_period) + flt(row.depreciation_amount_during_the_period)
- flt(row.depreciation_eliminated_during_the_period) - flt(row.depreciation_eliminated_during_the_period)
- flt(row.depreciation_eliminated_via_reversal)
) )
row.net_asset_value_as_on_from_date = flt(row.value_as_on_from_date) - flt( row.net_asset_value_as_on_from_date = flt(row.value_as_on_from_date) - flt(
@@ -247,6 +248,7 @@ def get_group_by_asset_data(filters):
flt(row.accumulated_depreciation_as_on_from_date) flt(row.accumulated_depreciation_as_on_from_date)
+ flt(row.depreciation_amount_during_the_period) + flt(row.depreciation_amount_during_the_period)
- flt(row.depreciation_eliminated_during_the_period) - flt(row.depreciation_eliminated_during_the_period)
- flt(row.depreciation_eliminated_via_reversal)
) )
row.net_asset_value_as_on_from_date = flt(row.value_as_on_from_date) - flt( row.net_asset_value_as_on_from_date = flt(row.value_as_on_from_date) - flt(
@@ -276,6 +278,7 @@ def get_assets_for_grouped_by_category(filters):
f""" f"""
SELECT results.asset_category, SELECT results.asset_category,
sum(results.accumulated_depreciation_as_on_from_date) as accumulated_depreciation_as_on_from_date, sum(results.accumulated_depreciation_as_on_from_date) as accumulated_depreciation_as_on_from_date,
sum(results.depreciation_eliminated_via_reversal) as depreciation_eliminated_via_reversal,
sum(results.depreciation_eliminated_during_the_period) as depreciation_eliminated_during_the_period, sum(results.depreciation_eliminated_during_the_period) as depreciation_eliminated_during_the_period,
sum(results.depreciation_amount_during_the_period) as depreciation_amount_during_the_period sum(results.depreciation_amount_during_the_period) as depreciation_amount_during_the_period
from (SELECT a.asset_category, from (SELECT a.asset_category,
@@ -284,6 +287,11 @@ def get_assets_for_grouped_by_category(filters):
else else
0 0
end), 0) as accumulated_depreciation_as_on_from_date, end), 0) as accumulated_depreciation_as_on_from_date,
ifnull(sum(case when gle.posting_date <= %(to_date)s and ifnull(a.disposal_date, 0) = 0 then
gle.credit
else
0
end), 0) as depreciation_eliminated_via_reversal,
ifnull(sum(case when ifnull(a.disposal_date, 0) != 0 and a.disposal_date >= %(from_date)s ifnull(sum(case when ifnull(a.disposal_date, 0) != 0 and a.disposal_date >= %(from_date)s
and a.disposal_date <= %(to_date)s and gle.posting_date <= a.disposal_date then and a.disposal_date <= %(to_date)s and gle.posting_date <= a.disposal_date then
gle.debit gle.debit
@@ -307,7 +315,6 @@ def get_assets_for_grouped_by_category(filters):
a.docstatus=1 a.docstatus=1
and a.company=%(company)s and a.company=%(company)s
and a.purchase_date <= %(to_date)s and a.purchase_date <= %(to_date)s
and gle.debit != 0
and gle.is_cancelled = 0 and gle.is_cancelled = 0
and gle.account = ifnull(aca.depreciation_expense_account, company.depreciation_expense_account) and gle.account = ifnull(aca.depreciation_expense_account, company.depreciation_expense_account)
{condition} {finance_book_filter} {condition} {finance_book_filter}
@@ -319,6 +326,7 @@ def get_assets_for_grouped_by_category(filters):
else else
a.opening_accumulated_depreciation a.opening_accumulated_depreciation
end), 0) as accumulated_depreciation_as_on_from_date, end), 0) as accumulated_depreciation_as_on_from_date,
0 as depreciation_eliminated_via_reversal,
ifnull(sum(case when a.disposal_date >= %(from_date)s and a.disposal_date <= %(to_date)s then ifnull(sum(case when a.disposal_date >= %(from_date)s and a.disposal_date <= %(to_date)s then
a.opening_accumulated_depreciation a.opening_accumulated_depreciation
else else
@@ -354,6 +362,7 @@ def get_assets_for_grouped_by_asset(filters):
f""" f"""
SELECT results.name as asset, SELECT results.name as asset,
sum(results.accumulated_depreciation_as_on_from_date) as accumulated_depreciation_as_on_from_date, sum(results.accumulated_depreciation_as_on_from_date) as accumulated_depreciation_as_on_from_date,
sum(results.depreciation_eliminated_via_reversal) as depreciation_eliminated_via_reversal,
sum(results.depreciation_eliminated_during_the_period) as depreciation_eliminated_during_the_period, sum(results.depreciation_eliminated_during_the_period) as depreciation_eliminated_during_the_period,
sum(results.depreciation_amount_during_the_period) as depreciation_amount_during_the_period sum(results.depreciation_amount_during_the_period) as depreciation_amount_during_the_period
from (SELECT a.name as name, from (SELECT a.name as name,
@@ -362,6 +371,11 @@ def get_assets_for_grouped_by_asset(filters):
else else
0 0
end), 0) as accumulated_depreciation_as_on_from_date, end), 0) as accumulated_depreciation_as_on_from_date,
ifnull(sum(case when gle.posting_date <= %(to_date)s and ifnull(a.disposal_date, 0) = 0 then
gle.credit
else
0
end), 0) as depreciation_eliminated_via_reversal,
ifnull(sum(case when ifnull(a.disposal_date, 0) != 0 and a.disposal_date >= %(from_date)s ifnull(sum(case when ifnull(a.disposal_date, 0) != 0 and a.disposal_date >= %(from_date)s
and a.disposal_date <= %(to_date)s and gle.posting_date <= a.disposal_date then and a.disposal_date <= %(to_date)s and gle.posting_date <= a.disposal_date then
gle.debit gle.debit
@@ -385,7 +399,6 @@ def get_assets_for_grouped_by_asset(filters):
a.docstatus=1 a.docstatus=1
and a.company=%(company)s and a.company=%(company)s
and a.purchase_date <= %(to_date)s and a.purchase_date <= %(to_date)s
and gle.debit != 0
and gle.is_cancelled = 0 and gle.is_cancelled = 0
and gle.account = ifnull(aca.depreciation_expense_account, company.depreciation_expense_account) and gle.account = ifnull(aca.depreciation_expense_account, company.depreciation_expense_account)
{finance_book_filter} {condition} {finance_book_filter} {condition}
@@ -397,6 +410,7 @@ def get_assets_for_grouped_by_asset(filters):
else else
a.opening_accumulated_depreciation a.opening_accumulated_depreciation
end), 0) as accumulated_depreciation_as_on_from_date, end), 0) as accumulated_depreciation_as_on_from_date,
0 as depreciation_as_on_from_date_credit,
ifnull(sum(case when a.disposal_date >= %(from_date)s and a.disposal_date <= %(to_date)s then ifnull(sum(case when a.disposal_date >= %(from_date)s and a.disposal_date <= %(to_date)s then
a.opening_accumulated_depreciation a.opening_accumulated_depreciation
else else
@@ -503,6 +517,12 @@ def get_columns(filters):
"fieldtype": "Currency", "fieldtype": "Currency",
"width": 270, "width": 270,
}, },
{
"label": _("Depreciation eliminated via reversal"),
"fieldname": "depreciation_eliminated_via_reversal",
"fieldtype": "Currency",
"width": 270,
},
{ {
"label": _("Net Asset value as on") + " " + formatdate(filters.day_before_from_date), "label": _("Net Asset value as on") + " " + formatdate(filters.day_before_from_date),
"fieldname": "net_asset_value_as_on_from_date", "fieldname": "net_asset_value_as_on_from_date",

View File

@@ -307,6 +307,7 @@ class Deferred_Revenue_and_Expense_Report:
.where( .where(
(inv.docstatus == 1) (inv.docstatus == 1)
& (deferred_flag_field == 1) & (deferred_flag_field == 1)
& (inv.company == self.filters.company)
& ( & (
( (
(self.period_list[0].from_date >= inv_item.service_start_date) (self.period_list[0].from_date >= inv_item.service_start_date)

View File

@@ -2,5 +2,27 @@
// For license information, please see license.txt // For license information, please see license.txt
frappe.query_reports["Delivered Items To Be Billed"] = { frappe.query_reports["Delivered Items To Be Billed"] = {
filters: [], filters: [
{
label: __("Company"),
fieldname: "company",
fieldtype: "Link",
options: "Company",
reqd: 1,
default: frappe.defaults.get_default("Company"),
},
{
label: __("As on Date"),
fieldname: "posting_date",
fieldtype: "Date",
reqd: 1,
default: frappe.datetime.get_today(),
},
{
label: __("Delivery Note"),
fieldname: "delivery_note",
fieldtype: "Link",
options: "Delivery Note",
},
],
}; };

View File

@@ -3,6 +3,7 @@
from frappe import _ from frappe import _
from pypika import Order
from erpnext.accounts.report.non_billed_report import get_ordered_to_be_billed_data from erpnext.accounts.report.non_billed_report import get_ordered_to_be_billed_data
@@ -10,7 +11,7 @@ from erpnext.accounts.report.non_billed_report import get_ordered_to_be_billed_d
def execute(filters=None): def execute(filters=None):
columns = get_column() columns = get_column()
args = get_args() args = get_args()
data = get_ordered_to_be_billed_data(args) data = get_ordered_to_be_billed_data(args, filters)
return columns, data return columns, data
@@ -76,13 +77,6 @@ def get_column():
"options": "Project", "options": "Project",
"width": 120, "width": 120,
}, },
{
"label": _("Company"),
"fieldname": "company",
"fieldtype": "Link",
"options": "Company",
"width": 120,
},
] ]
@@ -92,5 +86,6 @@ def get_args():
"party": "customer", "party": "customer",
"date": "posting_date", "date": "posting_date",
"order": "name", "order": "name",
"order_by": "desc", "order_by": Order.desc,
"reference_field": "delivery_note",
} }

View File

@@ -4,11 +4,12 @@
import frappe import frappe
from frappe.model.meta import get_field_precision from frappe.model.meta import get_field_precision
from frappe.query_builder.functions import IfNull, Round
from erpnext import get_default_currency from erpnext import get_default_currency
def get_ordered_to_be_billed_data(args): def get_ordered_to_be_billed_data(args, filters=None):
doctype, party = args.get("doctype"), args.get("party") doctype, party = args.get("doctype"), args.get("party")
child_tab = doctype + " Item" child_tab = doctype + " Item"
precision = ( precision = (
@@ -18,47 +19,57 @@ def get_ordered_to_be_billed_data(args):
or 2 or 2
) )
project_field = get_project_field(doctype, party) doctype = frappe.qb.DocType(doctype)
child_doctype = frappe.qb.DocType(child_tab)
return frappe.db.sql( docname = filters.get(args.get("reference_field"), None)
""" project_field = get_project_field(doctype, child_doctype, party)
Select
`{parent_tab}`.name, `{parent_tab}`.{date_field}, query = (
`{parent_tab}`.{party}, `{parent_tab}`.{party}_name, frappe.qb.from_(doctype)
`{child_tab}`.item_code, .inner_join(child_doctype)
`{child_tab}`.base_amount, .on(doctype.name == child_doctype.parent)
(`{child_tab}`.billed_amt * ifnull(`{parent_tab}`.conversion_rate, 1)), .select(
(`{child_tab}`.base_rate * ifnull(`{child_tab}`.returned_qty, 0)), doctype.name,
(`{child_tab}`.base_amount - doctype[args.get("date")].as_("date"),
(`{child_tab}`.billed_amt * ifnull(`{parent_tab}`.conversion_rate, 1)) - doctype[party],
(`{child_tab}`.base_rate * ifnull(`{child_tab}`.returned_qty, 0))), doctype[party + "_name"],
`{child_tab}`.item_name, `{child_tab}`.description, child_doctype.item_code,
{project_field}, `{parent_tab}`.company child_doctype.base_amount.as_("amount"),
from (child_doctype.billed_amt * IfNull(doctype.conversion_rate, 1)).as_("billed_amount"),
`{parent_tab}`, `{child_tab}` (child_doctype.base_rate * IfNull(child_doctype.returned_qty, 0)).as_("returned_amount"),
where (
`{parent_tab}`.name = `{child_tab}`.parent and `{parent_tab}`.docstatus = 1 child_doctype.base_amount
and `{parent_tab}`.status not in ('Closed', 'Completed') - (child_doctype.billed_amt * IfNull(doctype.conversion_rate, 1))
and `{child_tab}`.amount > 0 - (child_doctype.base_rate * IfNull(child_doctype.returned_qty, 0))
and (`{child_tab}`.base_amount - ).as_("pending_amount"),
round(`{child_tab}`.billed_amt * ifnull(`{parent_tab}`.conversion_rate, 1), {precision}) - child_doctype.item_name,
(`{child_tab}`.base_rate * ifnull(`{child_tab}`.returned_qty, 0))) > 0 child_doctype.description,
order by project_field,
`{parent_tab}`.{order} {order_by}
""".format(
parent_tab="tab" + doctype,
child_tab="tab" + child_tab,
precision=precision,
party=party,
date_field=args.get("date"),
project_field=project_field,
order=args.get("order"),
order_by=args.get("order_by"),
) )
.where(
(doctype.docstatus == 1)
& (doctype.status.notin(["Closed", "Completed"]))
& (doctype.company == filters.get("company"))
& (doctype.posting_date <= filters.get("posting_date"))
& (child_doctype.amount > 0)
& (
child_doctype.base_amount
- Round(child_doctype.billed_amt * IfNull(doctype.conversion_rate, 1), precision)
- (child_doctype.base_rate * IfNull(child_doctype.returned_qty, 0))
)
> 0
)
.orderby(doctype[args.get("order")], order=args.get("order_by"))
) )
if docname:
query = query.where(doctype.name == docname)
def get_project_field(doctype, party): return query.run(as_dict=True)
def get_project_field(doctype, child_doctype, party):
if party == "supplier": if party == "supplier":
doctype = doctype + " Item" return child_doctype.project
return "`tab%s`.project" % (doctype) return doctype.project

View File

@@ -2,5 +2,27 @@
// For license information, please see license.txt // For license information, please see license.txt
frappe.query_reports["Received Items To Be Billed"] = { frappe.query_reports["Received Items To Be Billed"] = {
filters: [], filters: [
{
label: __("Company"),
fieldname: "company",
fieldtype: "Link",
options: "Company",
reqd: 1,
default: frappe.defaults.get_default("Company"),
},
{
label: __("As on Date"),
fieldname: "posting_date",
fieldtype: "Date",
reqd: 1,
default: frappe.datetime.get_today(),
},
{
label: __("Purchase Receipt"),
fieldname: "purchase_receipt",
fieldtype: "Link",
options: "Purchase Receipt",
},
],
}; };

View File

@@ -3,6 +3,7 @@
from frappe import _ from frappe import _
from pypika import Order
from erpnext.accounts.report.non_billed_report import get_ordered_to_be_billed_data from erpnext.accounts.report.non_billed_report import get_ordered_to_be_billed_data
@@ -10,7 +11,7 @@ from erpnext.accounts.report.non_billed_report import get_ordered_to_be_billed_d
def execute(filters=None): def execute(filters=None):
columns = get_column() columns = get_column()
args = get_args() args = get_args()
data = get_ordered_to_be_billed_data(args) data = get_ordered_to_be_billed_data(args, filters)
return columns, data return columns, data
@@ -76,13 +77,6 @@ def get_column():
"options": "Project", "options": "Project",
"width": 120, "width": 120,
}, },
{
"label": _("Company"),
"fieldname": "company",
"fieldtype": "Link",
"options": "Company",
"width": 120,
},
] ]
@@ -92,5 +86,6 @@ def get_args():
"party": "supplier", "party": "supplier",
"date": "posting_date", "date": "posting_date",
"order": "name", "order": "name",
"order_by": "desc", "order_by": Order.desc,
"reference_field": "purchase_receipt",
} }

View File

@@ -93,7 +93,7 @@
}, },
{ {
"hidden": 0, "hidden": 0,
"is_query_report": 0, "is_query_report": 1,
"label": "Accounts Payable", "label": "Accounts Payable",
"link_count": 0, "link_count": 0,
"link_to": "Accounts Payable", "link_to": "Accounts Payable",
@@ -103,7 +103,7 @@
}, },
{ {
"hidden": 0, "hidden": 0,
"is_query_report": 0, "is_query_report": 1,
"label": "Accounts Payable Summary", "label": "Accounts Payable Summary",
"link_count": 0, "link_count": 0,
"link_to": "Accounts Payable Summary", "link_to": "Accounts Payable Summary",
@@ -113,7 +113,7 @@
}, },
{ {
"hidden": 0, "hidden": 0,
"is_query_report": 0, "is_query_report": 1,
"label": "Purchase Register", "label": "Purchase Register",
"link_count": 0, "link_count": 0,
"link_to": "Purchase Register", "link_to": "Purchase Register",
@@ -123,7 +123,7 @@
}, },
{ {
"hidden": 0, "hidden": 0,
"is_query_report": 0, "is_query_report": 1,
"label": "Item-wise Purchase Register", "label": "Item-wise Purchase Register",
"link_count": 0, "link_count": 0,
"link_to": "Item-wise Purchase Register", "link_to": "Item-wise Purchase Register",
@@ -133,7 +133,7 @@
}, },
{ {
"hidden": 0, "hidden": 0,
"is_query_report": 0, "is_query_report": 1,
"label": "Purchase Order Analysis", "label": "Purchase Order Analysis",
"link_count": 0, "link_count": 0,
"link_to": "Purchase Order Analysis", "link_to": "Purchase Order Analysis",
@@ -143,7 +143,7 @@
}, },
{ {
"hidden": 0, "hidden": 0,
"is_query_report": 0, "is_query_report": 1,
"label": "Received Items To Be Billed", "label": "Received Items To Be Billed",
"link_count": 0, "link_count": 0,
"link_to": "Received Items To Be Billed", "link_to": "Received Items To Be Billed",
@@ -153,7 +153,7 @@
}, },
{ {
"hidden": 0, "hidden": 0,
"is_query_report": 0, "is_query_report": 1,
"label": "Supplier Ledger Summary", "label": "Supplier Ledger Summary",
"link_count": 0, "link_count": 0,
"link_to": "Supplier Ledger Summary", "link_to": "Supplier Ledger Summary",

View File

@@ -1234,7 +1234,7 @@ class StockController(AccountsController):
child_tab.item_code, child_tab.item_code,
child_tab.qty, child_tab.qty,
) )
.where(parent_tab.docstatus < 2) .where(parent_tab.docstatus == 1)
) )
if self.doctype == "Purchase Invoice": if self.doctype == "Purchase Invoice":

View File

@@ -396,3 +396,4 @@ erpnext.patches.v15_0.set_difference_amount_in_asset_value_adjustment
erpnext.patches.v14_0.update_posting_datetime erpnext.patches.v14_0.update_posting_datetime
erpnext.stock.doctype.stock_ledger_entry.patches.ensure_sle_indexes erpnext.stock.doctype.stock_ledger_entry.patches.ensure_sle_indexes
erpnext.patches.v15_0.rename_sla_fields erpnext.patches.v15_0.rename_sla_fields
erpnext.patches.v15_0.update_query_report

View File

@@ -0,0 +1,25 @@
import frappe
def execute():
reports = [
"Accounts Payable",
"Accounts Payable Summary",
"Purchase Register",
"Item-wise Purchase Register",
"Purchase Order Analysis",
"Received Items To Be Billed",
"Supplier Ledger Summary",
]
frappe.db.set_value(
"Workspace Link",
{
"parent": "Payables",
"link_type": "Report",
"type": "Link",
"link_to": ["in", reports],
"is_query_report": 0,
},
"is_query_report",
1,
)

View File

@@ -1044,7 +1044,7 @@ def make_delivery_note(source_name, target_doc=None, kwargs=None):
ignore_permissions=True, ignore_permissions=True,
) )
dn_item.qty = flt(sre.reserved_qty) * flt(dn_item.get("conversion_factor", 1)) dn_item.qty = flt(sre.reserved_qty) / flt(dn_item.get("conversion_factor", 1))
if sre.reservation_based_on == "Serial and Batch" and (sre.has_serial_no or sre.has_batch_no): if sre.reservation_based_on == "Serial and Batch" and (sre.has_serial_no or sre.has_batch_no):
dn_item.serial_and_batch_bundle = get_ssb_bundle_for_voucher(sre) dn_item.serial_and_batch_bundle = get_ssb_bundle_for_voucher(sre)

View File

@@ -221,7 +221,7 @@ def update_stock(ctx, out, doc=None):
else: else:
qty -= batch_qty qty -= batch_qty
out.update({"batch_no": batch_no, "actual_batch_qty": qty}) out.update({"batch_no": batch_no, "actual_batch_qty": batch_qty})
if rate: if rate:
out.update({"rate": rate, "price_list_rate": rate}) out.update({"rate": rate, "price_list_rate": rate})
@@ -1051,9 +1051,11 @@ def get_batch_based_item_price(params, item_code) -> float:
if not item_price: if not item_price:
item_price = get_item_price(params, item_code, ignore_party=True, force_batch_no=True) item_price = get_item_price(params, item_code, ignore_party=True, force_batch_no=True)
is_free_item = params.get("items", [{}])[0].get("is_free_item") if (
item_price
if item_price and item_price[0][2] == params.get("uom") and not is_free_item: and item_price[0][2] == params.get("uom")
and not params.get("items", [{}])[0].get("is_free_item", 0)
):
return item_price[0][1] return item_price[0][1]
return 0.0 return 0.0