2026-07-29 세션 — AL설정(엑셀 설정탭) 관리 페이지 CRUD + 발주서 헤더 컴팩트화
논의·대안
페페 지시(4항목): ① NAS 원부자재발주서.xlsx의 「설정」 탭(AL 프로파일별 공제상수)을 관리하는 페이지를 만들고 CRUD 가능하게 ② AL발주서(/field/al-orderpaper) 페이지에 그 관리 페이지 접속 버튼 추가 ③ 새 발주서 작업 중에도 설정을 추가·수정할 수 있게(발주서 페이지에도 접속 버튼) ④ 운영 배포. 작업 중 추가 지시 = 발주서 페이지 업체정보 란을 컴팩트하게(발주내용 테이블 공간 확보가 우선).
- 첫 지시의 파일 경로는
부자재 발주서 일지.xlsm이었으나 그 파일은 시트가주문조회/RawData뿐이라 「설정」 탭이 없다 → 페페가 곧바로원부자재발주서.xlsx가 맞다고 정정. 이 파일이 기존 AL발주서 계산엔진(al_calc.py)의 원 출처와 동일하다. - 저장소 선택: 기존엔 설정 49행이 정적 자산
api/pfs/al_orderpaper/assets/seoljeong_constants.json에 박혀 있었다. 웹에서 CRUD하려면 배포 때 덮이지 않는 곳이어야 하므로 RDS 테이블al_profile신규로 옮기고, JSON은 초기 시딩·복구 원본으로만 남겼다(파일 수정 방식은 배포마다 사용자 편집이 날아가 탈락). - 캐시 vs 매요청 조회:
al_calc는 모듈 전역에 상수를 캐시하고 있었다. 설정이 편집 가능해지면 uwsgi 워커별 캐시가 갈라진다 → 캐시 대신 서비스가 요청당 1회profile_map()조회 후 행마다 재사용(49행이라 비용 무시 가능). - 편집 중 설정 수정 동선: (a) 발주서 안에 설정 편집 모달 이식 (b) 새 창으로 관리 페이지. (b) 채택 — UI 중복이 없고 작성 중인 발주서를 잃지 않는다. 대신 창 복귀(
window focus) 시 설정 재조회 + 전 행 재계산을 붙여 "고친 값이 반영 안 됨"을 막았다. - 행 삭제 방식: 발주서 항목처럼 delete-insert로 전량 교체할 수도 있으나 설정은 마스터 데이터라 upsert +
remove_ynsoft delete(번호·감사이력 보존)로 갔다.
결정
- 테이블
al_profile(patch43) = 업체·품명·목대W/H뺄·유리W/H뺄·큰손갭·큰손마감+ ·sort_no·remove_yn+ 감사컬럼. 수치는 VARCHAR (엑셀 원본이 숫자/공란 혼재 +al_calc._num이 이미 문자 파싱 + Decimal jsonify 회피). - 행 순서(
sort_no)가 곧 엑셀 VLOOKUP 첫매치 순서 — 중복 품명(AA*494(작은손)+3면AA-496,AA*495(큰손)+3면AA-4962건 실재)은 위 행이 이기고 아래 행은 死행. 화면에서 NO 칸을 노랗게 칠해 死행을 보이게 했다. - 신규 페이지
/field/al-profile— 사이드바 메뉴에는 넣지 않음(menu_catalog 미등록). 접근은 AL발주서의 버튼 2곳(목록 툴바·편집 툴바)뿐 = 페페 지시 그대로. - 저장은 화면 전체 1콜(
POST /api/al-orderpaper/profiles {rows:[...]}). 서버가 soft delete → upsert 순으로 처리. - 발주서 헤더 = 라벨 세로쌓기 폐지, 업체 1곳당 1줄(placeholder 인라인) + 헤더 접기 토글(요약줄 유지, localStorage 기억).
산출물·커밋
- 신규:
api/pfs/al_orderpaper/dao/al_profile_dao.py(DDL·최초 1회 시딩·select/profile_map/save_bulk/delete/reset),web/templates/basic/field/field_al_profile.html,web/static/js/al_profile.js,migrations/patch43_al_profile.sql. - 수정:
al_calc.compute_item(..., consts=)(테이블 상수 주입, 미지정 시 JSON 폴백),al_orderpaper_service(get/save/reset_profiles·_compute_items가 요청당 1회 map 조회),al_orderpaper_controller(POST/profiles, POST/profiles/reset, DELETE/profiles/<no>),field_controller(라우트),field_al_orderpaper.html·al_orderpaper.js(버튼 2곳·focus 재조회·헤더 컴팩트/접기). - 검증 스크립트:
scripts/_al_profile_probe_test.py,scripts/_al_profile_e2e_test.py,scripts/_al_profile_probe_prod.py,scripts/_al_profile_ui_check.py(로컬 Playwright, 자격증명은C:\dev\.secrets\pfs_login.env에서 직접 읽어 값 노출 없음). - 커밋:
master f99e739→ 버그수정master d38661e→ 스크립트master 6f228b9, 운영deploy-live a0faf03(파일 10개 포워드 반영,api/config.py무관).
🔴 잡은 버그 1건 (테스트 E2E가 걸러냄)
save_bulk가 INSERT를 먼저 하고 그 뒤에 "화면에 없는 행 soft delete"를 돌렸다. 신규 행은 아직 번호가 없어 keep 목록에 못 들어가므로 방금 넣은 행이 같은 트랜잭션 안에서 즉시 지워졌다(저장 응답은 saved:50인데 조회하면 49행 — 조용한 실패). → soft delete를 INSERT보다 먼저 실행하고, UPDATE 절에 remove_yn='0'을 함께 세팅하도록 수정.
검증
- 로컬:
al_calc.py자체검사 PASS(consts 주입 우선·미등록 품명 상수0 케이스 추가), Python/JS 구문검사, SQL 플레이스홀더 수 대조. - 엑셀↔시딩 정합:
원부자재발주서.xlsx「설정」 49행 vs 시딩 원본 JSON = 실제 불일치 0(공란 50칸이0으로 정규화된 것뿐, 계산상 동일). - 테스트 서버 CRUD E2E 16항목 PASS — 초기 49행 / 기존행 UPDATE(번호 유지) / 신규행 INSERT / 빈칸→0 / 계산 반영(큰손갭 0→20 → W 395→385, 유리 가로뺄 6→0) / 신규 프로파일 계산 / 화면에서 뺀 행 soft delete / 단건 DELETE / 엑셀 원본 복구 후 값·순서·계산 원복.
- UI 검증(Playwright) 테스트 18 / 운영 18 항목 PASS — 49행 렌더·중복 2행 하이라이트·검색 필터(상원 4행)·행 추가·미저장 경고·버튼 2곳 노출·헤더 폼 높이 106px·그리드 시작 y 262px(접으면 195px)·업체 5필드 같은 줄·라이브 계산·콘솔 오류 0.
- 운영 실측(SSM): HEAD
a0faf03,pfs-live.uwsgiactive, 4개 경로 200,al_profile테이블 생성 + 49행 시딩 완료, 중복 품명 2건 그대로.
다음
- 페페 육안: 실제 설정값 편집 → 발주서 계산 반영 확인. 프로파일 신규 추가는 화면에서 바로 가능.
- 팩스발송 버튼은 여전히 스텁(사무실PC 로컬 팩스 에이전트 미구현) — 이번 범위 밖.
- 엑셀 원본이 바뀌면
assets/seoljeong_constants.json은 자동 추종하지 않는다(복구 버튼의 기준값이므로 원본 개정 시 갱신 필요).
관계
- 주제 그룹: pfs-al-orderpaper
- 관련 문서:
pfs-handoff,pfs-traps, 코디 메모리wonbujae-orderpaper-al-glass-engine