mirror of
https://github.com/frappe/erpnext.git
synced 2026-02-18 17:15:04 +00:00
Merge branch 'version-13-hotfix' into backport/v13-h/32304
This commit is contained in:
@@ -5,6 +5,7 @@ from typing import Dict, List, Tuple
|
||||
|
||||
import frappe
|
||||
from frappe import _
|
||||
from frappe.query_builder.functions import Sum
|
||||
|
||||
Filters = frappe._dict
|
||||
Row = frappe._dict
|
||||
@@ -14,15 +15,50 @@ QueryArgs = Dict[str, str]
|
||||
|
||||
|
||||
def execute(filters: Filters) -> Tuple[Columns, Data]:
|
||||
filters = frappe._dict(filters or {})
|
||||
columns = get_columns()
|
||||
data = get_data(filters)
|
||||
return columns, data
|
||||
|
||||
|
||||
def get_data(filters: Filters) -> Data:
|
||||
query_args = get_query_args(filters)
|
||||
data = run_query(query_args)
|
||||
wo = frappe.qb.DocType("Work Order")
|
||||
se = frappe.qb.DocType("Stock Entry")
|
||||
|
||||
query = (
|
||||
frappe.qb.from_(wo)
|
||||
.inner_join(se)
|
||||
.on(wo.name == se.work_order)
|
||||
.select(
|
||||
wo.name,
|
||||
wo.status,
|
||||
wo.production_item,
|
||||
wo.qty,
|
||||
wo.produced_qty,
|
||||
wo.process_loss_qty,
|
||||
(wo.produced_qty - wo.process_loss_qty).as_("actual_produced_qty"),
|
||||
Sum(se.total_incoming_value).as_("total_fg_value"),
|
||||
Sum(se.total_outgoing_value).as_("total_rm_value"),
|
||||
)
|
||||
.where(
|
||||
(wo.process_loss_qty > 0)
|
||||
& (wo.company == filters.company)
|
||||
& (se.docstatus == 1)
|
||||
& (se.posting_date.between(filters.from_date, filters.to_date))
|
||||
)
|
||||
.groupby(se.work_order)
|
||||
)
|
||||
|
||||
if "item" in filters:
|
||||
query.where(wo.production_item == filters.item)
|
||||
|
||||
if "work_order" in filters:
|
||||
query.where(wo.name == filters.work_order)
|
||||
|
||||
data = query.run(as_dict=True)
|
||||
|
||||
update_data_with_total_pl_value(data)
|
||||
|
||||
return data
|
||||
|
||||
|
||||
@@ -67,54 +103,7 @@ def get_columns() -> Columns:
|
||||
]
|
||||
|
||||
|
||||
def get_query_args(filters: Filters) -> QueryArgs:
|
||||
query_args = {}
|
||||
query_args.update(filters)
|
||||
query_args.update(get_filter_conditions(filters))
|
||||
return query_args
|
||||
|
||||
|
||||
def run_query(query_args: QueryArgs) -> Data:
|
||||
return frappe.db.sql(
|
||||
"""
|
||||
SELECT
|
||||
wo.name, wo.status, wo.production_item, wo.qty,
|
||||
wo.produced_qty, wo.process_loss_qty,
|
||||
(wo.produced_qty - wo.process_loss_qty) as actual_produced_qty,
|
||||
sum(se.total_incoming_value) as total_fg_value,
|
||||
sum(se.total_outgoing_value) as total_rm_value
|
||||
FROM
|
||||
`tabWork Order` wo INNER JOIN `tabStock Entry` se
|
||||
ON wo.name=se.work_order
|
||||
WHERE
|
||||
process_loss_qty > 0
|
||||
AND wo.company = %(company)s
|
||||
AND se.docstatus = 1
|
||||
AND se.posting_date BETWEEN %(from_date)s AND %(to_date)s
|
||||
{item_filter}
|
||||
{work_order_filter}
|
||||
GROUP BY
|
||||
se.work_order
|
||||
""".format(
|
||||
**query_args
|
||||
),
|
||||
query_args,
|
||||
as_dict=1,
|
||||
)
|
||||
|
||||
|
||||
def update_data_with_total_pl_value(data: Data) -> None:
|
||||
for row in data:
|
||||
value_per_unit_fg = row["total_fg_value"] / row["actual_produced_qty"]
|
||||
row["total_pl_value"] = row["process_loss_qty"] * value_per_unit_fg
|
||||
|
||||
|
||||
def get_filter_conditions(filters: Filters) -> QueryArgs:
|
||||
filter_conditions = dict(item_filter="", work_order_filter="")
|
||||
if "item" in filters:
|
||||
production_item = filters.get("item")
|
||||
filter_conditions.update({"item_filter": f"AND wo.production_item='{production_item}'"})
|
||||
if "work_order" in filters:
|
||||
work_order_name = filters.get("work_order")
|
||||
filter_conditions.update({"work_order_filter": f"AND wo.name='{work_order_name}'"})
|
||||
return filter_conditions
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
|
||||
import frappe
|
||||
from frappe.query_builder.functions import IfNull
|
||||
from frappe.utils import cint
|
||||
|
||||
|
||||
@@ -16,70 +17,70 @@ def execute(filters=None):
|
||||
def get_item_list(wo_list, filters):
|
||||
out = []
|
||||
|
||||
# Add a row for each item/qty
|
||||
for wo_details in wo_list:
|
||||
desc = frappe.db.get_value("BOM", wo_details.bom_no, "description")
|
||||
if wo_list:
|
||||
bin = frappe.qb.DocType("Bin")
|
||||
bom = frappe.qb.DocType("BOM")
|
||||
bom_item = frappe.qb.DocType("BOM Item")
|
||||
|
||||
for wo_item_details in frappe.db.get_values(
|
||||
"Work Order Item", {"parent": wo_details.name}, ["item_code", "source_warehouse"], as_dict=1
|
||||
):
|
||||
# Add a row for each item/qty
|
||||
for wo_details in wo_list:
|
||||
desc = frappe.db.get_value("BOM", wo_details.bom_no, "description")
|
||||
|
||||
item_list = frappe.db.sql(
|
||||
"""SELECT
|
||||
bom_item.item_code as item_code,
|
||||
ifnull(ledger.actual_qty*bom.quantity/bom_item.stock_qty,0) as build_qty
|
||||
FROM
|
||||
`tabBOM` as bom, `tabBOM Item` AS bom_item
|
||||
LEFT JOIN `tabBin` AS ledger
|
||||
ON bom_item.item_code = ledger.item_code
|
||||
AND ledger.warehouse = ifnull(%(warehouse)s,%(filterhouse)s)
|
||||
WHERE
|
||||
bom.name = bom_item.parent
|
||||
and bom_item.item_code = %(item_code)s
|
||||
and bom.name = %(bom)s
|
||||
GROUP BY
|
||||
bom_item.item_code""",
|
||||
{
|
||||
"bom": wo_details.bom_no,
|
||||
"warehouse": wo_item_details.source_warehouse,
|
||||
"filterhouse": filters.warehouse,
|
||||
"item_code": wo_item_details.item_code,
|
||||
},
|
||||
as_dict=1,
|
||||
)
|
||||
for wo_item_details in frappe.db.get_values(
|
||||
"Work Order Item", {"parent": wo_details.name}, ["item_code", "source_warehouse"], as_dict=1
|
||||
):
|
||||
item_list = (
|
||||
frappe.qb.from_(bom)
|
||||
.from_(bom_item)
|
||||
.left_join(bin)
|
||||
.on(
|
||||
(bom_item.item_code == bin.item_code)
|
||||
& (bin.warehouse == IfNull(wo_item_details.source_warehouse, filters.warehouse))
|
||||
)
|
||||
.select(
|
||||
bom_item.item_code.as_("item_code"),
|
||||
IfNull(bin.actual_qty * bom.quantity / bom_item.stock_qty, 0).as_("build_qty"),
|
||||
)
|
||||
.where(
|
||||
(bom.name == bom_item.parent)
|
||||
& (bom_item.item_code == wo_item_details.item_code)
|
||||
& (bom.name == wo_details.bom_no)
|
||||
)
|
||||
.groupby(bom_item.item_code)
|
||||
).run(as_dict=1)
|
||||
|
||||
stock_qty = 0
|
||||
count = 0
|
||||
buildable_qty = wo_details.qty
|
||||
for item in item_list:
|
||||
count = count + 1
|
||||
if item.build_qty >= (wo_details.qty - wo_details.produced_qty):
|
||||
stock_qty = stock_qty + 1
|
||||
elif buildable_qty >= item.build_qty:
|
||||
buildable_qty = item.build_qty
|
||||
stock_qty = 0
|
||||
count = 0
|
||||
buildable_qty = wo_details.qty
|
||||
for item in item_list:
|
||||
count = count + 1
|
||||
if item.build_qty >= (wo_details.qty - wo_details.produced_qty):
|
||||
stock_qty = stock_qty + 1
|
||||
elif buildable_qty >= item.build_qty:
|
||||
buildable_qty = item.build_qty
|
||||
|
||||
if count == stock_qty:
|
||||
build = "Y"
|
||||
else:
|
||||
build = "N"
|
||||
if count == stock_qty:
|
||||
build = "Y"
|
||||
else:
|
||||
build = "N"
|
||||
|
||||
row = frappe._dict(
|
||||
{
|
||||
"work_order": wo_details.name,
|
||||
"status": wo_details.status,
|
||||
"req_items": cint(count),
|
||||
"instock": stock_qty,
|
||||
"description": desc,
|
||||
"source_warehouse": wo_item_details.source_warehouse,
|
||||
"item_code": wo_item_details.item_code,
|
||||
"bom_no": wo_details.bom_no,
|
||||
"qty": wo_details.qty,
|
||||
"buildable_qty": buildable_qty,
|
||||
"ready_to_build": build,
|
||||
}
|
||||
)
|
||||
row = frappe._dict(
|
||||
{
|
||||
"work_order": wo_details.name,
|
||||
"status": wo_details.status,
|
||||
"req_items": cint(count),
|
||||
"instock": stock_qty,
|
||||
"description": desc,
|
||||
"source_warehouse": wo_item_details.source_warehouse,
|
||||
"item_code": wo_item_details.item_code,
|
||||
"bom_no": wo_details.bom_no,
|
||||
"qty": wo_details.qty,
|
||||
"buildable_qty": buildable_qty,
|
||||
"ready_to_build": build,
|
||||
}
|
||||
)
|
||||
|
||||
out.append(row)
|
||||
out.append(row)
|
||||
|
||||
return out
|
||||
|
||||
|
||||
Reference in New Issue
Block a user