meraproject/services/user-reader/app/labor_day.py

106 lines
3.2 KiB
Python
Raw Normal View History

"""Производственный календарь — порт 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)