feat(D04): 업체 지정 · 확정 API · 완료 메일 · 시험 (531-1 · 531-2)

This commit is contained in:
2026-10-25 19:49:39 +09:00
parent f93d996279
commit 20081ee362
6 changed files with 817 additions and 8 deletions
+21 -8
View File
@@ -29,10 +29,14 @@ SHP_SUFFIXES = (".shp", ".shx", ".dbf", ".prj", ".cpg")
MIME_ZIP = "application/zip"
MIME_XLSX = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
# 용화 `.prj` 원문(ESRI WKT) — 양식 일치용으로 그대로 씀.
# 용화 `.prj` 원문(ESRI WKT) 그대로 — 양식 일치(시험이 용화 파일과 바이트 비교).
_YONGHWA_PRJ = (
Path(__file__).resolve().parents[1]
/ "resources/knowledge/original/실무문서/2026년 임도 용화/예정노선/대상지_일월.용화.2.2.prj"
'PROJCS["PCS_ITRF2000_UTM_K",GEOGCS["GCS_ITRF_2000",DATUM["D_ITRF_2000",'
'SPHEROID["GRS_1980",6378137.0,298.257222101]],PRIMEM["Greenwich",0.0],'
'UNIT["Degree",0.0174532925199433]],PROJECTION["Transverse_Mercator"],'
'PARAMETER["False_Easting",1000000.0],PARAMETER["False_Northing",2000000.0],'
'PARAMETER["Central_Meridian",127.5],PARAMETER["Scale_Factor",0.9996],'
'PARAMETER["Latitude_Of_Origin",38.0],UNIT["METER",1.0]]'
)
_SCHEMA = {
"geometry": "LineString",
@@ -49,11 +53,16 @@ _BAD_FILENAME = re.compile(r'[\\/:*?"<>|\r\n\t]')
@dataclass
class YearRoute:
"""한 연도의 노선 — `points` 는 `crs_epsg` 좌표의 (x, y) 꺾은선(시점 → 종점)."""
"""한 연도의 노선 — `points` 는 `crs_epsg` 좌표의 (x, y) 꺾은선(시점 → 종점).
누가거리 두 값이 있으면 그대로 칸에 쓰고(D03 이은 값), 없으면 연도 순서로 이어 셈.
"""
year: int
points: list[tuple[float, float]]
crs_epsg: int
start_station_m: float | None = None
end_station_m: float | None = None
@dataclass
@@ -115,7 +124,7 @@ def _write_shapefile(
frame.to_file(
out, driver="ESRI Shapefile", encoding="cp949", engine="fiona", schema=_SCHEMA
)
out.with_suffix(".prj").write_bytes(_YONGHWA_PRJ.read_bytes())
out.with_suffix(".prj").write_text(_YONGHWA_PRJ, encoding="ascii")
out.with_suffix(".cpg").write_text("949", encoding="ascii")
return {suffix: out.with_suffix(suffix).read_bytes() for suffix in SHP_SUFFIXES}
@@ -191,16 +200,20 @@ def build_export(
if len(points) < 2:
raise ValueError(f"{item.year}년 노선 점이 2개 미만입니다.")
length_m = polyline_length_m(points)
if item.start_station_m is not None and item.end_station_m is not None:
start, end = float(item.start_station_m), float(item.end_station_m)
else:
start, end = station, station + length_m
rows.append(
{
"year": item.year,
"points": points,
"length_m": length_m,
"start_station": station,
"end_station": station + length_m,
"start_station": start,
"end_station": end,
}
)
station += length_m
station = end
bundle = ExportBundle()
region_name = safe_name(region)