เมื่อเพิ่ม "Daily" เป็นตัวเลือก frequency ใน Sales Forecast:
- ✅ สร้าง Sales Forecast ได้
- ✅ สร้าง MPS ได้
- ❌ สร้าง MRP ไม่ได้ (ข้อมูลหายไปเงียบๆ)
ปัญหาอยู่ที่ฟังก์ชัน convert_to_daily_bucket_data() ในไฟล์ MRP Report
erpnext/manufacturing/report/material_requirements_planning_report/material_requirements_planning_report.py
ฟังก์ชันนี้แปลงข้อมูล forecast ทั้งหมดเป็นรายวัน แต่รองรับแค่ Monthly กับ Weekly:
# บรรทัด ~1237-1277
def convert_to_daily_bucket_data(data):
bucketed_data = []
for row in data:
if row.frequency == "Monthly":
# แปลง monthly → daily (หาร qty ด้วยจำนวนวันในเดือน)
...
elif row.frequency == "Weekly":
# แปลง weekly → daily (หาร qty ด้วย 7)
...
# ← ไม่มี else สำหรับ "Daily" → ข้อมูลถูกข้ามไปเงียบๆ!
return bucketed_data # ← list ว่าง ถ้าทุก row เป็น Dailyเมื่อ MRP ได้ข้อมูลว่าง → ไม่สามารถสร้าง Production Plan ต่อได้
ไฟล์: erpnext/manufacturing/doctype/sales_forecast/sales_forecast.json
บรรทัด: ~153
- "options": "Weekly\nMonthly",
+ "options": "Daily\nWeekly\nMonthly",หรือใช้ Property Setter (ไม่ต้องแก้ไฟล์ core):
# รันใน bench console: bench --site yoursite.com console
frappe.make_property_setter({
"doctype": "Sales Forecast",
"fieldname": "frequency",
"property": "options",
"value": "Daily\nWeekly\nMonthly",
})
frappe.db.commit()ไฟล์: erpnext/manufacturing/doctype/sales_forecast/sales_forecast.py
บรรทัด: ~25
- frequency: DF.Literal["Weekly", "Monthly"]
+ frequency: DF.Literal["Daily", "Weekly", "Monthly"]หมายเหตุ: บรรทัดนี้อยู่ในบล็อก auto-generated types — จะถูก overwrite ถ้ารัน
bench generate-typestubsแต่ไม่กระทบการทำงานจริง
ไฟล์: sales_forecast.py → ฟังก์ชัน generate_manual_demand()
บรรทัด: ~46-49
if self.frequency == "Monthly":
delivery_date = add_to_date(self.from_date, months=index + 1)
- else:
+ elif self.frequency == "Weekly":
delivery_date = add_to_date(self.from_date, weeks=index + 1)
+ else: # Daily
+ delivery_date = add_to_date(self.from_date, days=index + 1)ไฟล์: material_requirements_planning_report.py
ฟังก์ชัน: convert_to_daily_bucket_data()
บรรทัด: ~1275 (เพิ่มก่อน return bucketed_data)
elif row.frequency == "Weekly":
# Convert weekly data to daily buckets
start_date = getdate(row.delivery_date)
for i in range(7):
bucketed_data.append(
frappe._dict(
{
"frequency": "Daily",
"item_code": row.item_code,
"delivery_date": add_days(start_date, i),
"sales_forecast": row.sales_forecast,
"stock_uom": row.stock_uom,
"qty": row.qty / 7,
}
)
)
+ elif row.frequency == "Daily":
+ # ข้อมูลเป็นรายวันอยู่แล้ว — ส่งผ่านตรงๆ
+ bucketed_data.append(
+ frappe._dict(
+ {
+ "frequency": "Daily",
+ "item_code": row.item_code,
+ "delivery_date": getdate(row.delivery_date),
+ "sales_forecast": row.sales_forecast,
+ "stock_uom": row.stock_uom,
+ "qty": row.qty,
+ }
+ )
+ )
return bucketed_dataเพราะเมื่อรัน bench update การแก้ไขจะถูก overwrite ทั้งหมด
bench new-app daily_manufacturing
bench --site yoursite.com install-app daily_manufacturingใน custom app สร้างไฟล์ daily_manufacturing/overrides.py:
import frappe
from frappe.utils import getdate
import erpnext.manufacturing.report.material_requirements_planning_report.material_requirements_planning_report as mrp_report
from erpnext.manufacturing.doctype.sales_forecast.sales_forecast import SalesForecast
from frappe.utils import add_to_date
# --- Override 1: เพิ่ม Daily ใน generate_manual_demand() ---
original_generate = SalesForecast.generate_manual_demand
def patched_generate_manual_demand(self):
forecast_demand = []
for row in self.selected_items:
item_details = frappe.db.get_value(
"Item", row.item_code, ["item_name", "stock_uom as uom"], as_dict=True
)
for index in range(self.demand_number):
if self.frequency == "Monthly":
delivery_date = add_to_date(self.from_date, months=index + 1)
elif self.frequency == "Weekly":
delivery_date = add_to_date(self.from_date, weeks=index + 1)
else: # Daily
delivery_date = add_to_date(self.from_date, days=index + 1)
forecast_demand.append({
"item_code": row.item_code,
"delivery_date": delivery_date,
"item_name": item_details.item_name,
"uom": item_details.uom,
"demand_qty": 1.0,
})
for demand in forecast_demand:
self.append("items", demand)
SalesForecast.generate_manual_demand = patched_generate_manual_demand
# --- Override 2: เพิ่ม Daily ใน convert_to_daily_bucket_data() ---
original_convert = mrp_report.convert_to_daily_bucket_data
def patched_convert_to_daily_bucket_data(data):
daily_rows = [r for r in data if r.frequency == "Daily"]
non_daily = [r for r in data if r.frequency != "Daily"]
# ให้ฟังก์ชันเดิมจัดการ Monthly + Weekly
result = original_convert(non_daily)
# เพิ่ม Daily rows ตรงๆ (ไม่ต้องแปลง — เป็นรายวันอยู่แล้ว)
for row in daily_rows:
result.append(frappe._dict({
"frequency": "Daily",
"item_code": row.item_code,
"delivery_date": getdate(row.delivery_date),
"sales_forecast": row.sales_forecast,
"stock_uom": row.stock_uom,
"qty": row.qty,
}))
return result
mrp_report.convert_to_daily_bucket_data = patched_convert_to_daily_bucket_dataใน daily_manufacturing/__init__.py:
# Import overrides on app load
from daily_manufacturing import overrides # noqa: F401เพิ่ม Property Setter สำหรับ frequency field ใน daily_manufacturing/setup.py:
import frappe
def after_install():
frappe.make_property_setter({
"doctype": "Sales Forecast",
"fieldname": "frequency",
"property": "options",
"value": "Daily\nWeekly\nMonthly",
})
frappe.db.commit()ใน hooks.py:
after_install = "daily_manufacturing.setup.after_install"หลังติดตั้ง:
- สร้าง Sales Forecast → เลือก frequency = Daily ✅
- สร้าง MPS ✅
- สร้าง MRP → ต้องมีข้อมูลแสดง ✅
- View MRP → เห็นข้อมูลรายวัน ✅
- สร้าง Purchase Order / Work Order ✅
วิเคราะห์โดย Claude Code — Bunchee Online (bunchee.online)