以下のように出力しました。
各日、次のような出力です。
当直
内科拘束
整形拘束
短時間宿直シフトは、暦日通りに出力しています。スケジュールナースのシフトから補正しています。
プロジェクトの全Pythonソースです。mainのPython部(制約)が最初、post部のPythonのmain def post_main() が最後に配置することが注意点です。制約のpythonとpostのpythonは、別プロセスであることにも注意してください。通信はできません。
post処理では、shift_solutionがシフト解配列として利用可能ですので、ひたすら解を読んで上記フォーマットとなるように整形しています。タスク解(診療科)も利用可能ですが、上記フォーマット出力するには、シフト解のみで十分です。
本プロジェクトは、大変に複雑な仕様です。本コードは、そのための開発デバッグ検証用も兼ねており、開発当初から、改変を積み重ねてきました。冗長なコードになっているのはそのためです。
ユーザには、スケジュール解ではなく、開発当初より、本Excel解を提出してデバッグにご協力いただきました。元々の顧客フォーマットが上のようなものなので、違和感なく検証いただけたと思います。Excel解の提出のフェーズが完了しました。以降、スケジュールナースプロジェクトを使用した、デバッグフェーズに移行します。
import sc3
import sys
import os
import csv
import re
import win32gui, win32con
import pywin.dialogs.list
import calendar
from collections import namedtuple
for person in 非常勤:
for day in 今月:
if shift_schedules[person][day][0]=='':
v=sc3.GetShiftVar(person,day,'その他')
s='非常勤は予定入力がないときはその他 '+staffdef[person]+' '+daydef[day]
sc3.AddHard(v,s)
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='csv',
Title=title,#
Filter=filter,
CustomFilter=customfilter,
FilterIndex=0)
return str(fname)
def draw拘束(ws,c,person,str):
if person in 内科:
ws.Cells(c.Row+3,c.Column).Value=str
elif person in 整形外科:
ws.Cells(c.Row+4,c.Column).Value=str
def day_solution_analysis(ws,c,n,day):
#clear
宿日直person=-1
日直person=-1
宿直person=-1
for person in 非常勤:
if shift_solution[person][day]=='その他':
continue
if '宿日直' in shift_solution[person][day]:
if 宿日直person!=-1:
print("fatal error 宿日直は、 most one work per a day")
exit()
宿日直person=person
continue
if '日直(日中のみ)' == shift_solution[person][day]:
if 日直person!=-1:
print("fatal error 日直は、 most one work per a day")
exit()
日直person=person
continue
if '宿直'in shift_solution[person][day]:
if 宿直person!=-1:
print("fatal error 宿直は、 at most one work per a day")
exit()
宿直person=person
continue
print("fatal error ")
exit()
list=[]
短宿person=-1
拘束宿list=[]
拘束日直list=[]
日直拘束宿日直person=-1
宿直拘束宿日直person=-1
for person in 常勤:
if shift_solution[person][day]=='その他':
continue
if shift_solution[person][day]=='宿日直':
if 宿日直person!=-1:
print("fatal error 宿日直は、 most one work per a day")
exit()
宿日直person=person
continue
if '30分'in shift_solution[person][day] or '60分' in shift_solution[person][day] or '90分' in shift_solution[person][day]:
if 短宿person!=-1:
print(staffdef[person],daydef[day])
print("fatal error 短宿は、 at most one work per a day")
exit()
短宿person=person
print(staffdef[短宿person],daydef[day],shift_solution[短宿person][day])
continue
if '日直(日中のみ)' in shift_solution[person][day] :
if 日直person!=-1:
print(staffdef[person],daydef[day])
print("fatal error 日直は、 at most one work per a day")
exit()
日直person=person
continue
if '宿直'==shift_solution[person][day] :
if 宿直person!=-1:
print("fatal error 宿直は、 at most one work per a day")
exit()
宿直person=person
continue
if '日直拘束宿日直'==shift_solution[person][day]:
if 日直拘束宿日直person!=-1:
print("fatal error 日直拘束宿日直は、 at most one work per a day")
exit()
日直拘束宿日直person=person
continue
if '宿直拘束宿日直'==shift_solution[person][day]:
if 宿直拘束宿日直person!=-1:
print("fatal error 宿直拘束宿日直は、 at most one work per a day")
exit()
宿直拘束宿日直person=person
continue
if '拘束宿'==shift_solution[person][day]:
拘束宿list.append(person)
continue
if '拘束日直'==shift_solution[person][day]:
拘束日直list.append(person)
continue
#print("list add",staffdef[person])
list.append((person,shift_solution[person][day]))
if 短宿person!=-1:#Draw 短縮
print(短宿person,staffdef[短宿person],daydef[day],n,shift_solution[短宿person][day])
str=staffdef[短宿person]+' '
if '拘束' in shift_solution[短宿person][day]:
draw拘束(ws,c,短宿person,staffdef[短宿person])
if shift_solution[短宿person][day]=='夜30分宿直' or shift_solution[短宿person][day]=='夜30分宿直拘束付':
str +='17:00~17:30'
ws.Cells(c.Row+1,c.Column+1).Value=str
elif shift_solution[短宿person][day]=='夜60分宿直' or shift_solution[短宿person][day]=='夜60分宿直拘束付':
str +='17:00~18:00'
ws.Cells(c.Row+1,c.Column+1).Value=str
elif shift_solution[短宿person][day]=='朝30分宿直' or shift_solution[短宿person][day]=='朝30分宿日直拘束付':
str +='8:00~8:30'
print("!!朝30分",staffdef[person],daydef[day],n.Row,n.Column)
if n!=None:
print(staffdef[短宿person],daydef[day])
ws.Cells(n.Row+1,n.Column+1).Value=str
elif shift_solution[短宿person][day]=='朝60分宿直' or shift_solution[短宿person][day]=='朝60分宿日直拘束付':
str +='7:30~8:30'
if n!=None:
ws.Cells(n.Row+1,n.Column+1).Value=str
print(staffdef[短宿person],daydef[day],n.Row+1,n.Column,ws.Cells(n.Row+1,n.Column).Value)
elif shift_solution[短宿person][day]=='朝90分宿直' or shift_solution[短宿person][day]=='朝90分宿日直拘束付':
str +='7:00~8:30'
if n!=None:
ws.Cells(n.Row+1,n.Column+1).Value=str
if 日直person!=-1 or 日直拘束宿日直person!=-1:
if 宿直person==-1 and 宿直拘束宿日直person==-1:
print("fatal error 日直があるなら宿直もないとだめ")
exit()
if 宿直person!=-1:
strlast=staffdef[宿直person]
else:
strlast=staffdef[宿直拘束宿日直person]
if 日直person!=-1:
str=staffdef[日直person]+'/'+strlast
ws.Cells(c.Row+2,c.Column).Value=str
if 宿直拘束宿日直person!=-1:
draw拘束(ws,c,宿直拘束宿日直person,strlast)
else:
draw拘束(ws,c,宿直person,strlast)
elif 日直拘束宿日直person!=-1:
str=staffdef[日直拘束宿日直person]+'/'+strlast
ws.Cells(c.Row+2,c.Column).Value=str
draw拘束(ws,c,日直拘束宿日直person,str)
elif 宿日直person!=-1:
str=staffdef[宿日直person]
ws.Cells(c.Row+2,c.Column).Value=str
draw拘束(ws,c,宿日直person,str)
elif 宿直person!=-1:
str=staffdef[宿直person]
ws.Cells(c.Row+2,c.Column).Value=str
draw拘束(ws,c,宿直person,str)
else:
print("fatal error ")
exit()
if len(拘束日直list)==1:
str=staffdef[拘束日直list[0]]
if 宿直person==-1 and len(拘束宿list)!=1:
print("fatal error 拘束日直があるなら、拘束宿日直もしくは宿直もないとだめ")
exit()
if 拘束日直list[0] in 内科:
if 宿直person not in 内科 and 拘束宿list[0] not in 内科:
print("fatal error")
exit()
elif 拘束日直list[0] in 整形外科:
if 宿直person not in 整形外科 and 拘束宿list[0] not in 整形外科:
print("fatal error")
exit()
if 宿直person !=-1:
str=staffdef[拘束日直list[0]]+'/'+staffdef[宿直person]
elif len(拘束宿list)==1:
str=staffdef[拘束日直list[0]]+'/'+staffdef[拘束宿list[0]]
print("拘束日直list[0]",str)
draw拘束(ws,c,拘束日直list[0],str)
elif len(拘束日直list)==2:
if 宿直person==-1 or len(拘束宿list)!=1:
print("fatal error 拘束日直があるなら、拘束宿直および宿直どちらもないとだめ")
exit()
if 拘束日直list[0] in 内科:
if 宿直person in 内科:
str=staffdef[拘束日直list[0]]+'/'+staffdef[宿直person]
draw拘束(ws,c,拘束日直list[0],str)
str=staffdef[拘束日直list[1]]+'/'+staffdef[拘束宿list[0]]
draw拘束(ws,c,拘束日直list[1],str)
elif 拘束宿list[0] in 内科:
str=staffdef[拘束日直list[0]]+'/'+staffdef[拘束宿list[0]]
draw拘束(ws,c,拘束日直list[0],str)
str=staffdef[拘束日直list[1]]+'/'+staffdef[宿直person]
draw拘束(ws,c,拘束日直list[1],str)
else:
print("fatal error 拘束日直が内科なら、拘束宿直および宿直どちらは内科")
exit()
elif 拘束日直list[0] in 整形外科:
if 宿直person in 整形外科:
str=staffdef[拘束日直list[0]]+'/'+staffdef[宿直person]
draw拘束(ws,c,拘束日直list[0],str)
str=staffdef[拘束日直list[1]]+'/'+staffdef[拘束宿list[0]]
draw拘束(ws,c,拘束日直list[1],str)
elif 拘束宿list[0] in 整形外科:
str=staffdef[拘束日直list[0]]+'/'+staffdef[拘束宿list[0]]
draw拘束(ws,c,拘束日直list[0],str)
str=staffdef[拘束日直list[1]]+'/'+staffdef[宿直person]
draw拘束(ws,c,拘束日直list[1],str)
else:
print("fatal error 拘束日直が整形外科なら、拘束宿直および宿直どちらは整形外科")
exit()
elif len(拘束宿list) >=1:
for person in 拘束宿list:
str=staffdef[person]
draw拘束(ws,c,person,str)
#draw拘束(ws,c,拘束宿person,str)
if len(list) <=2:
for tuple in list:
if '拘束宿日直' not in tuple[1]:
print(staffdef[tuple[0]],tuple[1])
print("fatal error ")
exit()
str=staffdef[tuple[0]]
print('拘束宿日直',str)
draw拘束(ws,c,tuple[0],str)
else:
print("len(list)",len(list),len(拘束宿list),len(拘束日直list))
print("fatal error programming error")
exit()
def get_sheet_name():
s=daydef[制約開始日]
year_str=s[0:4]
month=int(s[5:7])
sheet_name=year_str+'年'+str(month)+'月'
return sheet_name
def get_year():
s=daydef[制約開始日]
year_str=s[0:4]
return int(year_str)
def get_month():
s=daydef[制約開始日]
month=int(s[5:7])
return month
def get_day():
s=daydef[制約開始日]
day=int(s[8:10])
return day
def find_address(moncal,D):
row=0
for r in moncal:
if D not in r:
row+=1
continue
return (row,r.index(D))
#次月最初の日:最終行の最終列+1を出す
row=len(moncal)-1
col=len(moncal[row])
return (row,col)
raise IndexError
def init_row_columns():
global start_row
global start_column
global row_interval
global column_interval
start_row=6
start_column=2
row_interval=6
column_interval=2
def findcell(ws,moncal,D):
tuple=find_address(moncal,D)
init_row_columns()
row=start_row+row_interval*tuple[0]
column=start_column+column_interval*tuple[1]
c=namedtuple("Row","Column")
c.Row=row
c.Column=column
return c
def clear_cells(ws):
init_row_columns()
for r in range(6):
for d in range(7):
row=start_row+r*row_interval
column=start_column+d*column_interval
print(row,column)
ws.Cells(row ,column+1).Value=""
ws.Cells(row ,column).Value=""
ws.Cells(row+1,column+1).Value=""
ws.Cells(row+1,column).Value=""
ws.Cells(row+2,column+1).Value=""
ws.Cells(row+2,column).Value=""
ws.Cells(row+3,column).Value=""
ws.Cells(row+4,column).Value=""
def post_main():
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 = False
#file=get_open_file_name("Open Excel File")
#print(file)
os.chdir(project_file_path)
filename="2024当直拘束表.xlsx"
file=os.path.join(project_file_path,filename)
file.replace("/","\\") #なぜか逆スラッシュでないと動かない
wb = xl.Workbooks.Open(file)
# Excelシートオブジェクト
ws = wb.Worksheets(get_sheet_name())
# 指定したシートを選択
# Select()の使用前にシートのActivate()が必要
ws.Activate()
calendar.setfirstweekday(6)#日曜日を最初に
mon_cal=calendar.monthcalendar(get_year(),get_month())#行列でリスト
print(findcell(ws,mon_cal,1))
clear_cells(ws)
for day in 今月区間:
D=day-制約開始日+1
print(D)
c=findcell(ws,mon_cal,D)
n=findcell(ws,mon_cal,D+1)
#print(c.Row,c.Column)
day_solution_analysis(ws,c,n,day)
wb.Close(True)# Trueで保存。False=Defaultでブックを保存せずにクローズ
# Excel終了
xl.Quit()
print('\n\n*********ポスト処理を実行終了しました。*************\n')

0 件のコメント:
コメントを投稿