|
|
|
|
@ -1,4 +1,8 @@
|
|
|
|
|
from sqlalchemy import Select, Delete
|
|
|
|
|
import asyncio
|
|
|
|
|
import os
|
|
|
|
|
from subprocess import PIPE
|
|
|
|
|
from datetime import datetime
|
|
|
|
|
|
|
|
|
|
from src.database.service import search_filter_sort_paginate
|
|
|
|
|
from .model import MasterData
|
|
|
|
|
@ -143,9 +147,14 @@ async def bulk_update(
|
|
|
|
|
records_map = {str(record.id): record for record in records}
|
|
|
|
|
records_by_name = {record.name: record for record in records}
|
|
|
|
|
|
|
|
|
|
# Track if umur_teknis was changed in this batch
|
|
|
|
|
umur_changed = False
|
|
|
|
|
umur_new_value = None
|
|
|
|
|
|
|
|
|
|
# Process updates in batches
|
|
|
|
|
updated_records = []
|
|
|
|
|
for masterdata_id, masterdata_in in zip(ids, updates):
|
|
|
|
|
|
|
|
|
|
masterdata = records_map.get(masterdata_id)
|
|
|
|
|
print("Processing update for ID:", masterdata)
|
|
|
|
|
if not masterdata:
|
|
|
|
|
@ -181,6 +190,13 @@ async def bulk_update(
|
|
|
|
|
for field, val in update_data.items():
|
|
|
|
|
if field in attr_fields:
|
|
|
|
|
setattr(masterdata, field, val)
|
|
|
|
|
# If this record itself represents umur_teknis, detect change
|
|
|
|
|
if getattr(masterdata, "name", None) == "umur_teknis":
|
|
|
|
|
umur_changed = True
|
|
|
|
|
try:
|
|
|
|
|
umur_new_value = float(masterdata.value_num)
|
|
|
|
|
except Exception:
|
|
|
|
|
umur_new_value = None
|
|
|
|
|
else:
|
|
|
|
|
# Field is not a direct attribute: treat it as a named masterdata
|
|
|
|
|
# e.g. payload included {"discount_rate": 5.0}
|
|
|
|
|
@ -191,6 +207,12 @@ async def bulk_update(
|
|
|
|
|
# Update numeric or string value depending on payload
|
|
|
|
|
if isinstance(val, (int, float)):
|
|
|
|
|
other.value_num = val
|
|
|
|
|
if other.name == "umur_teknis":
|
|
|
|
|
umur_changed = True
|
|
|
|
|
try:
|
|
|
|
|
umur_new_value = float(other.value_num)
|
|
|
|
|
except Exception:
|
|
|
|
|
umur_new_value = None
|
|
|
|
|
else:
|
|
|
|
|
other.value_str = str(val)
|
|
|
|
|
# keep updated record available for batch calculations
|
|
|
|
|
@ -242,6 +264,44 @@ async def bulk_update(
|
|
|
|
|
# Commit all changes in a single transaction
|
|
|
|
|
await db_session.commit()
|
|
|
|
|
|
|
|
|
|
# If umur_teknis changed, clear projection rows and trigger recalculation
|
|
|
|
|
if umur_changed:
|
|
|
|
|
try:
|
|
|
|
|
# Determine current year
|
|
|
|
|
current_year = datetime.now(datetime.timezone.utc).year
|
|
|
|
|
|
|
|
|
|
# Import model locally to avoid circular imports
|
|
|
|
|
from src.plant_transaction_data.model import PlantTransactionData
|
|
|
|
|
|
|
|
|
|
# Delete projection rows (is_actual == 0) from current year onward
|
|
|
|
|
del_q = Delete(PlantTransactionData).where(
|
|
|
|
|
PlantTransactionData.is_actual == 0,
|
|
|
|
|
PlantTransactionData.tahun >= current_year,
|
|
|
|
|
)
|
|
|
|
|
await db_session.execute(del_q)
|
|
|
|
|
await db_session.commit()
|
|
|
|
|
|
|
|
|
|
# Trigger recalculation by running the plant module script
|
|
|
|
|
directory_path = os.path.abspath(
|
|
|
|
|
os.path.join(os.path.dirname(__file__), "../modules/plant")
|
|
|
|
|
)
|
|
|
|
|
script_path = os.path.join(directory_path, "run.py")
|
|
|
|
|
|
|
|
|
|
process = await asyncio.create_subprocess_exec(
|
|
|
|
|
"python",
|
|
|
|
|
script_path,
|
|
|
|
|
stdout=PIPE,
|
|
|
|
|
stderr=PIPE,
|
|
|
|
|
cwd=directory_path,
|
|
|
|
|
)
|
|
|
|
|
stdout, stderr = await process.communicate()
|
|
|
|
|
if process.returncode != 0:
|
|
|
|
|
print(f"Plant recalc error: {stderr.decode()}")
|
|
|
|
|
else:
|
|
|
|
|
print(f"Plant recalc output: {stdout.decode()}")
|
|
|
|
|
except Exception as e:
|
|
|
|
|
print(f"Error during umur_teknis recalculation: {e}")
|
|
|
|
|
|
|
|
|
|
return updated_records
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|