Untitled
unknown
plain_text
2 years ago
6.1 kB
10
Indexable
from __future__ import annotations
import os
import time
from logging import getLogger
from pathlib import Path
import click
import pandas as pd
from interstore_transfer_opt.application import TransferModelDefault
from interstore_transfer_opt.constants import NOW_DATETIME, PROJECT_ROOT
from interstore_transfer_opt.domain import Attributes, Condition, Decision, GeneralConfig, ModeConfig, OverallTransferPlan, read_sales_csv, read_stock_csv, read_store_master
from interstore_transfer_opt.error import InputAlerts
from interstore_transfer_opt.tool import PROGRESS_BAR
LOAD_DATA_PROGRESS = 5
PREPROCESS_PROGRESS = 10
OPTIMIZE_PROGRESS = 90
FINISH_PROGRESS = 100
logger = getLogger(__name__)
def get_latest_path(path: Path | str, ptn: str) -> Path:
path = Path(path)
list_sls_csv = [str(p) for p in path.glob(ptn)]
if len(list_sls_csv) == 0:
raise ValueError(f"Not found: {path}")
return Path(max(list_sls_csv, key=os.path.getctime))
@click.command("run_transfer_model")
@click.option("--input", "path_input", type=click.Path(exists=True), default=PROJECT_ROOT / "data")
@click.option("--output", "path_output", type=click.Path(), default=PROJECT_ROOT / "output")
def main(path_input: str, path_output: str):
path_input = Path(path_input)
path_output = Path(path_output)
path_output.mkdir(exist_ok=True, parents=True)
path_config_general = path_input / "config_general.xlsx"
path_config_mode = path_input / "config_mode"
path_download = path_input / "download"
path_sales = get_latest_path(path_download, ptn="AIM_TOOL_CAL_INTERSTORE_TSF_01_SLS_ACT_*.csv")
path_stock = get_latest_path(path_download, ptn="AIM_TOOL_CAL_INTERSTORE_TSF_02_STK_ACT_*.csv")
path_store_master = path_download / "StoreMaster.csv"
path_decision = get_latest_path(path_input, ptn="input_*.xlsx")
logger.info("Loading data...")
sales = read_sales_csv(path_sales)
stock = read_stock_csv(path_stock)
store_master = read_store_master(path_store_master, bu=1)
result_general_config = GeneralConfig.read_excel(path_config_general)
result_mode_config = ModeConfig.read_dir(path_config_mode)
result_decision = Decision.read_excel(path_decision)
PROGRESS_BAR.set_progress(LOAD_DATA_PROGRESS, "Data loaded")
if result_mode_config.is_success() and result_general_config.is_success() and result_decision.is_success():
general_config = result_general_config.get()
mode_config = result_mode_config.get()
decision = result_decision.get()
else:
logger.error("Failed to load data.")
errors = []
if not result_general_config.is_success():
errors += result_general_config.get_errors().data
if not result_mode_config.is_success():
errors += result_mode_config.get_errors().data
if not result_decision.is_success():
errors += result_decision.get_errors().data
alerts = InputAlerts(errors)
alerts.to_excel(path_output / "alerts.xlsx")
return
logger.info("Processing data...")
result_condition = Condition.from_raw_data(general_config, mode_config, decision, sales, stock)
PROGRESS_BAR.set_progress(LOAD_DATA_PROGRESS, "Preprocess finished")
if not result_condition.is_success():
logger.error("Failed to process data.")
alerts = result_condition.get_errors()
alerts.to_excel(path_output / "alerts.xlsx")
return
result_attrs = Attributes.from_raw_data(decision, sales, store_master)
if result_attrs.is_success():
attributes = result_attrs.get()
else:
logger.error("Failed to load attributes error. The direction file will miss some info.")
attributes = None
condition = result_condition.get()
condition.to_excel(path_output / f"シミュレーション_{NOW_DATETIME}.xlsx")
send_capacity = decision.df_store["TtlSendUb"].fillna(9999).astype(int)
recv_capacity = decision.df_store["TtlRecvUb"].fillna(9999).astype(int)
results = {}
elapsed_time = {}
idx_lane_used = pd.Index([], dtype=str)
sum_codes = decision.df_product["SUM"].unique()
opt_percentage = OPTIMIZE_PROGRESS - PREPROCESS_PROGRESS
if len(sum_codes) == 0:
sum_cd_percentage = opt_percentage
else:
sum_cd_percentage = opt_percentage/len(sum_codes)
total_progress = PREPROCESS_PROGRESS
logger.info("Start running transfer model")
for sum_cd in sum_codes:
logger.info("=====================================")
logger.info(sum_cd)
logger.info("=====================================")
condition_target = condition.filter(sum_cd=sum_cd)
if condition_target.df_lane_product.empty:
logger.warning(f"No stock: {sum_cd}")
continue
st = time.time()
model = TransferModelDefault()
model.build(condition_target, send_capacity=send_capacity, recv_capacity=recv_capacity, idx_lane_used=idx_lane_used)
model.solve()
elapsed_time[sum_cd] = time.time() - st
result = model.result()
send_capacity = send_capacity.sub(result.send(), fill_value=0)
recv_capacity = recv_capacity.sub(result.recv(), fill_value=0)
idx_lane_used = idx_lane_used.union(result.idx_lane_used())
results[sum_cd] = result
total_progress += sum_cd_percentage
PROGRESS_BAR.set_progress(total_progress, "Preprocess finished")
result_overall = OverallTransferPlan.from_sumwise_plans(results, condition, attributes)
result_overall.write_review(path_output / f"チェック用_{NOW_DATETIME}.xlsx")
result_overall.write_direction(path_output / f"振替指示_{NOW_DATETIME}.xlsx")
df_elapsed_time = pd.Series(elapsed_time)
df_elapsed_time.to_csv(path_output / f"実行時間_{NOW_DATETIME}.csv", encoding="utf-8-sig")
PROGRESS_BAR.set_progress(FINISH_PROGRESS, "Simulation process completed")
if __name__ == "__main__":
main()
Editor is loading...