주소 그룹 순차 배치: 템플릿 export 시 주소별 통합 풀에서 순서대로 채움

This commit is contained in:
user01
2026-05-25 01:21:04 +09:00
parent f609fc87f8
commit afe2ec03c2

50
app.py
View File

@@ -810,20 +810,6 @@ def export():
wp_lookup = {wp['id']: wp for wp in t['workplaces']} wp_lookup = {wp['id']: wp for wp in t['workplaces']}
tab_name = t['name'] tab_name = t['name']
# 주소가 같은 근무처 그룹 내에서 배치 인원을 순환 재분배 (export 전용)
addr_groups = {}
for wp in t['workplaces']:
addr_groups.setdefault(wp['address'], []).append(wp['id'])
export_assignments = dict(t['assignments'])
for addr, wp_ids in addr_groups.items():
if len(wp_ids) <= 1:
continue
group_wids = [wid for wid, wpid in export_assignments.items() if wpid in wp_ids]
if not group_wids:
continue
for i, wid in enumerate(group_wids):
export_assignments[wid] = wp_ids[i % len(wp_ids)]
suffix_map = {'unassigned': '미배치', 'assigned': '배치결과', 'all': '배치결과'} suffix_map = {'unassigned': '미배치', 'assigned': '배치결과', 'all': '배치결과'}
suffix = suffix_map.get(export_type, '배치결과') suffix = suffix_map.get(export_type, '배치결과')
@@ -840,7 +826,7 @@ def export():
ws.title = '미배치 근로자' ws.title = '미배치 근로자'
ws.append(['이름', '희망사항', '주소', '생년월일', '연락처', '성별']) ws.append(['이름', '희망사항', '주소', '생년월일', '연락처', '성별'])
for w in t['workers']: for w in t['workers']:
if w['id'] not in export_assignments: if w['id'] not in t['assignments']:
ws.append([w['name'], w['hope'], w['address'], w['dob'], w['phone'], w['gender']]) ws.append([w['name'], w['hope'], w['address'], w['dob'], w['phone'], w['gender']])
elif export_type == 'assigned': elif export_type == 'assigned':
@@ -849,11 +835,18 @@ def export():
template_path = f'{base}_template.xlsx' if base else '' template_path = f'{base}_template.xlsx' if base else ''
if template_path and os.path.exists(template_path): if template_path and os.path.exists(template_path):
wb = openpyxl.load_workbook(template_path) wb = openpyxl.load_workbook(template_path)
wp_workers = {} # 주소 → 근무지명 목록, 근무지명 → 주소 매핑
for w in t['workers']: wp_name_to_addr = {}
a_id = export_assignments.get(w['id']) for wp in t['workplaces']:
if a_id and a_id in wp_lookup: wp_name_to_addr[wp['name']] = wp['address']
wp_workers.setdefault(wp_lookup[a_id]['name'], []).append(w) # 주소 그룹별 배치된 근로자 (주소가 같은 모든 근무처에 배치된 근로자 통합)
wp_ids_by_addr = {}
for wp in t['workplaces']:
wp_ids_by_addr.setdefault(wp['address'], set()).add(wp['id'])
addr_workers = {}
for addr, id_set in wp_ids_by_addr.items():
addr_workers[addr] = [w for w in t['workers']
if t['assignments'].get(w['id']) in id_set]
used_names = set() used_names = set()
for sn in wb.sheetnames: for sn in wb.sheetnames:
ws = wb[sn] ws = wb[sn]
@@ -874,7 +867,10 @@ def export():
current_wp = v current_wp = v
if not current_wp: if not current_wp:
continue continue
candidates = [w for w in wp_workers.get(current_wp, []) addr = wp_name_to_addr.get(current_wp)
if not addr:
continue
candidates = [w for w in addr_workers.get(addr, [])
if w['id'] not in used_names] if w['id'] not in used_names]
for w in candidates[:1]: for w in candidates[:1]:
if name_col is not None and cells[name_col].value is None: if name_col is not None and cells[name_col].value is None:
@@ -889,14 +885,14 @@ def export():
cells[addr_col].value = w['address'] cells[addr_col].value = w['address']
used_names.add(w['id']) used_names.add(w['id'])
# 템플릿에 없는 나머지 배치된 근로자는 추가 시트로 내보내기 # 템플릿에 없는 나머지 배치된 근로자는 추가 시트로 내보내기
all_assigned = {w['id'] for w in t['workers'] if w['id'] in export_assignments} all_assigned = {w['id'] for w in t['workers'] if w['id'] in t['assignments']}
remaining = all_assigned - used_names remaining = all_assigned - used_names
if remaining: if remaining:
ws_extra = wb.create_sheet('추가 배치') ws_extra = wb.create_sheet('추가 배치')
ws_extra.append(['이름', '연락처', '생년월일', '희망사항', '주소', '성별', '배치근무지', '근무지주소']) ws_extra.append(['이름', '연락처', '생년월일', '희망사항', '주소', '성별', '배치근무지', '근무지주소'])
for w in t['workers']: for w in t['workers']:
if w['id'] in remaining: if w['id'] in remaining:
a_id = export_assignments.get(w['id']) a_id = t['assignments'].get(w['id'])
wn = wp_lookup[a_id]['name'] if a_id in wp_lookup else '' wn = wp_lookup[a_id]['name'] if a_id in wp_lookup else ''
wa = wp_lookup[a_id]['address'] if a_id in wp_lookup else '' wa = wp_lookup[a_id]['address'] if a_id in wp_lookup else ''
ws_extra.append([w['name'], w['phone'], w['dob'], w['hope'], w['address'], w['gender'], wn, wa]) ws_extra.append([w['name'], w['phone'], w['dob'], w['hope'], w['address'], w['gender'], wn, wa])
@@ -906,7 +902,7 @@ def export():
ws1.title = '배치 현황' ws1.title = '배치 현황'
ws1.append(['이름', '연락처', '생년월일', '희망사항', '주소', '성별', '배치근무지', '근무지주소']) ws1.append(['이름', '연락처', '생년월일', '희망사항', '주소', '성별', '배치근무지', '근무지주소'])
for w in t['workers']: for w in t['workers']:
a_id = export_assignments.get(w['id']) a_id = t['assignments'].get(w['id'])
if not a_id: if not a_id:
continue continue
wn = wp_lookup[a_id]['name'] if a_id in wp_lookup else '' wn = wp_lookup[a_id]['name'] if a_id in wp_lookup else ''
@@ -923,7 +919,7 @@ def export():
addr_groups2[key]['workplace_ids'].append(wp['id']) addr_groups2[key]['workplace_ids'].append(wp['id'])
for addr, g in addr_groups2.items(): for addr, g in addr_groups2.items():
combined_name = ', '.join(g['names']) combined_name = ', '.join(g['names'])
aw = [w['name'] for w in t['workers'] if export_assignments.get(w['id']) in g['workplace_ids']] aw = [w['name'] for w in t['workers'] if t['assignments'].get(w['id']) in g['workplace_ids']]
ws2.append([combined_name, addr, len(aw), ', '.join(aw)]) ws2.append([combined_name, addr, len(aw), ', '.join(aw)])
else: # all (전체) else: # all (전체)
@@ -931,7 +927,7 @@ def export():
ws1.title = '배치 현황' ws1.title = '배치 현황'
ws1.append(['이름', '연락처', '생년월일', '희망사항', '주소', '성별', '배치근무지', '근무지주소']) ws1.append(['이름', '연락처', '생년월일', '희망사항', '주소', '성별', '배치근무지', '근무지주소'])
for w in t['workers']: for w in t['workers']:
a_id = export_assignments.get(w['id']) a_id = t['assignments'].get(w['id'])
wn = wp_lookup[a_id]['name'] if a_id and a_id in wp_lookup else '' wn = wp_lookup[a_id]['name'] if a_id and a_id in wp_lookup else ''
wa = wp_lookup[a_id]['address'] if a_id and a_id in wp_lookup else '' wa = wp_lookup[a_id]['address'] if a_id and a_id in wp_lookup else ''
ws1.append([w['name'], w['phone'], w['dob'], w['hope'], w['address'], w['gender'], wn, wa]) ws1.append([w['name'], w['phone'], w['dob'], w['hope'], w['address'], w['gender'], wn, wa])
@@ -946,7 +942,7 @@ def export():
addr_groups2[key]['workplace_ids'].append(wp['id']) addr_groups2[key]['workplace_ids'].append(wp['id'])
for addr, g in addr_groups2.items(): for addr, g in addr_groups2.items():
combined_name = ', '.join(g['names']) combined_name = ', '.join(g['names'])
aw = [w['name'] for w in t['workers'] if export_assignments.get(w['id']) in g['workplace_ids']] aw = [w['name'] for w in t['workers'] if t['assignments'].get(w['id']) in g['workplace_ids']]
ws2.append([combined_name, addr, len(aw), ', '.join(aw)]) ws2.append([combined_name, addr, len(aw), ', '.join(aw)])
buf = io.BytesIO() buf = io.BytesIO()