"""Производственный календарь — порт themes/merakomis/day/model.php.""" from __future__ import annotations from datetime import date, timedelta from app.labor import _column_lookup, _prefixed_col, _resolve_table from app.main import _quote_ident, _table_columns from app.merakomis_schema import DAY_TABLE, DAY_TYPE_NO_WORK PER_HOUR_DEFAULT = 8 def _load_day_row(cur, db: str, day: date) -> dict | None: table = _resolve_table(cur, db, DAY_TABLE) cols = _table_columns(cur, db, table) lut = _column_lookup(cols) date_col = _prefixed_col(lut, DAY_TABLE, "date") if not date_col: return None type_col = _prefixed_col(lut, DAY_TABLE, "type") text_col = _prefixed_col(lut, DAY_TABLE, "text") hours_col = _prefixed_col(lut, DAY_TABLE, "hours") tq = _quote_ident(table) sel = [f"{_quote_ident(date_col)} AS d"] if type_col: sel.append(f"{_quote_ident(type_col)} AS type") if text_col: sel.append(f"{_quote_ident(text_col)} AS text") if hours_col: sel.append(f"{_quote_ident(hours_col)} AS hours") cur.execute( f"SELECT {', '.join(sel)} FROM {tq} WHERE {_quote_ident(date_col)} = %s LIMIT 1", (day.isoformat(),), ) return cur.fetchone() def get_work_hours_in_date(day: date) -> float: if day.weekday() < 5: return float(PER_HOUR_DEFAULT) return 0.0 def get_work_hours_by_date(cur, db: str, day: date) -> float: row = _load_day_row(cur, db, day) if row and row.get("hours") is not None: return float(row["hours"]) return get_work_hours_in_date(day) def is_no_work_day(cur, db: str, day: date) -> bool: row = _load_day_row(cur, db, day) if row and int(row.get("type") or 0) == DAY_TYPE_NO_WORK: return True return day.weekday() >= 5 def format_day_row(row: dict) -> dict: d = row.get("d") or row.get("date") if isinstance(d, date): ds = d.isoformat() else: ds = str(d)[:10] return { "date": ds, "type": int(row.get("type") or 0), "text": (row.get("text") or "").strip(), } def get_by_range_formatted(cur, db: str, begin: date, end: date) -> dict[str, dict]: table = _resolve_table(cur, db, DAY_TABLE) cols = _table_columns(cur, db, table) lut = _column_lookup(cols) date_col = _prefixed_col(lut, DAY_TABLE, "date") type_col = _prefixed_col(lut, DAY_TABLE, "type") text_col = _prefixed_col(lut, DAY_TABLE, "text") if not date_col: return {} tq = _quote_ident(table) parts = [f"{_quote_ident(date_col)} AS d"] if type_col: parts.append(f"{_quote_ident(type_col)} AS type") if text_col: parts.append(f"{_quote_ident(text_col)} AS text") cur.execute( f""" SELECT {', '.join(parts)} FROM {tq} WHERE {_quote_ident(date_col)} BETWEEN %s AND %s """, (begin.isoformat(), end.isoformat()), ) out: dict[str, dict] = {} for row in cur.fetchall(): fmt = format_day_row(row) out[fmt["date"]] = fmt return out def iter_dates(begin: date, end: date): d = begin while d <= end: yield d d += timedelta(days=1)