顧客仕様を実装するにあたって、最初に行うのは、仕様の検討です。具体的な実装の目安がついたら、次に行うのは、顧客勤務表Excelから、予定へのインポートです。つまり、人力解(Excel)から、予定へインポートする作業です。それには、一部署でしたら、手入力してもよいのですが、多数の部署の場合は、インポートするスクリプトを書きます。
インポートの目的は、
1)初期状態の把握(人力解の達成度把握)
2)実装の検討、確認用
です。
で、インポートしてみると、多数のハード制約違反が見つかるのが普通です。私の理解の誤りも見つかりますが、大半は、お聞きしていた仕様そのものが達成されていないことにあります。
実装にあたっては、本当に達成そのものが難しいものがあります。当然そのような制約は、ソフト制約としますが、例えば、6連勤務の禁止や、明けの後の休み、等、これは当然ハード制約だろう、と思える制約も、時々達成出来ていないことが把握できます。
しかし、多くの達成できていない中でも、達成できている項目があるのも事実です。そういう風に人力勤務表を眺めていると、作成者が何を最重要視しているかが、判るときもあります。
お伝えしたいのは、多くの労力を要した勤務表作りの経験は、スケジュールナースにおいて無用ということではありません。むしろ、必要なことなのではないか? とも思います。何が大変か?という経験は、ほぼそのままスケジュールナースのエンジンでも、同じように大変なことなのです。
<インポートスクリプト例>
import os import ctypes import win32gui, win32con def get_open_file_name(title): filter='xlsx\0*.xlsx\0' customfilter='Other file types\0*.*\0' fname, customfilter, flags=win32gui.GetOpenFileNameW( InitialDir=project_file_path, Flags=win32con.OFN_ALLOWMULTISELECT|win32con.OFN_EXPLORER, File='', DefExt='xlsx', Title=title,#'Excel予定シートを開く', Filter=filter, CustomFilter=customfilter, FilterIndex=0) print ('読み込みファイル名:', repr(fname)) print(fname,flags) return str(fname) def output_question(): MessageBox = ctypes.windll.user32.MessageBoxW res=MessageBox(HWND, 'スタッフ希望を入力しますか?', '人力解全体を出力しますか?', 3) print(res) if res==7 or res==2:##いいえ、キャンセル return False return True def post_main(): #import pdb #pdb.set_trace() print('\n\n*********ポスト処理を実行中です。*************\n') import win32com.client#pywin32をインポート #すでにExcelが起動されている場合はそのタスクが使われる #エラー終了するとタスクは残ります try : xl = win32com.client.Dispatch("Excel.Application") except: print("can not invoke excel") exit() #動いている様子を見てみる xl.Visible = True os.chdir(project_file_path) #file=os.path.join(project_file_path,"ex1.xlsx") #file.replace("/","\\") file=get_open_file_name("人力解を開く") wb=xl.workbooks.Open(file) # Excelシートオブジェクト ws = wb.Worksheets(1) # 指定したシートを選択 # Select()の使用前にシートのActivate()が必要 ws.Activate() #v=ws.Range("A3").Value #print(v) wk = ws.UsedRange # 使用範囲を取得 columns = wk.Columns.Count # 行数 rows = wk.Rows.Count # 列数 cells = wk.Value days=0 day_list=[] for col in range(0,columns): v=cells[0][col]#,colws.Cells(1,col).Value if v!=None: days+=1 day_list.append(v) #print(v,v.year,v.month, v.day) print('Days',days) name_list=[] data_list=[] preferred_list=[] for row in range(3,1000,3): v=ws.Cells(row,1).Value if v !=None: print(v) name_list.append(v) list=[] plist=[] for col in range(2,2+days): v=ws.Cells(row+2,col).Value list.append(v) v=ws.Cells(row+1,col).Interior.ColorIndex plist.append(v) data_list.append(list) preferred_list.append(plist) else: break wb.Close() print("persons=",len(name_list),len(data_list)) print(data_list) print(preferred_list) output_preferred_schedule=output_question() file=get_open_file_name("書き込みする予定ファイルを選択") wb=xl.workbooks.Open(file) # Excelシートオブジェクト ws = xl.Worksheets(1) # 指定したシートを選択 # Select()の使用前にシートのActivate()が必要 ws.Activate() start_col=0 for col in range(2,100): v=ws.Cells(2,col).Text #print(v) if v!=None and v=="1": start_col=col break print(start_col) start_row=4 wk = ws.UsedRange # 使用範囲を取得 columns = wk.Columns.Count # 行数 rows = wk.Rows.Count for r in range(rows+1):#len(name_list)): name=ws.Cells(r+start_row,1).Value processed=False for k in range(len(name_list)): if name==name_list[k]: processed=True for c in range(days): #print(r,c) if output_preferred_schedule: if preferred_list[r][c]>0: ws.Cells(r+start_row,c+start_col).Value=data_list[k][c] else: ws.Cells(r+start_row,c+start_col).Value=data_list[k][c] if not processed: for c in range(days): ws.Cells(r+start_row,c+start_col).Value=''#clear wb.Save() wb.Close() xl.Quit() post_main()