顧客仕様を実装するにあたって、最初に行うのは、仕様の検討です。具体的な実装の目安がついたら、次に行うのは、顧客勤務表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()











