Files
openclaw/skills/paradiz/scripts/calc_quote.py

126 lines
4.2 KiB
Python
Raw Normal View History

#!/usr/bin/env python3
import argparse
import json
from datetime import date, datetime
def d(s: str) -> date:
return datetime.strptime(s, "%Y-%m-%d").date()
def normalize(h: str) -> str:
return (h or "").strip().lower().replace(" ", "_")
def pick(header_map, *aliases):
for a in aliases:
if a in header_map:
return header_map[a]
return None
def main():
p = argparse.ArgumentParser()
p.add_argument("--excel", required=True)
p.add_argument("--checkin", required=True)
p.add_argument("--checkout", required=True)
p.add_argument("--guests", required=True, type=int)
p.add_argument("--room")
args = p.parse_args()
try:
from openpyxl import load_workbook
except Exception:
print(json.dumps({"ok": False, "error": "Нужен openpyxl: pip install openpyxl"}, ensure_ascii=False))
return
checkin = d(args.checkin)
checkout = d(args.checkout)
nights = (checkout - checkin).days
if nights <= 0:
print(json.dumps({"ok": False, "error": "checkout должен быть позже checkin"}, ensure_ascii=False))
return
wb = load_workbook(args.excel, data_only=True)
ws = wb.active
rows = list(ws.iter_rows(values_only=True))
if not rows:
print(json.dumps({"ok": False, "error": "Пустой Excel"}, ensure_ascii=False))
return
header = [normalize(str(x) if x is not None else "") for x in rows[0]]
hm = {h: i for i, h in enumerate(header) if h}
c_from = pick(hm, "date_from", "from", "checkin_from", "заезд_с")
c_to = pick(hm, "date_to", "to", "checkout_to", "выезд_по")
c_gmin = pick(hm, "guests_min", "min_guests", "гостей_от")
c_gmax = pick(hm, "guests_max", "max_guests", "гостей_до")
c_ppn = pick(hm, "price_per_night", "night_price", "ценааочь")
c_total = pick(hm, "total_price", "цена_итого")
c_curr = pick(hm, "currency", "валюта")
c_room = pick(hm, "room", "room_type", "номер")
c_meal = pick(hm, "meal", "питание")
required = [c_from, c_to]
if any(x is None for x in required) or (c_ppn is None and c_total is None):
print(json.dumps({
"ok": False,
"error": "Неверная структура Excel. Нужны date_from/date_to и price_per_night или total_price"
}, ensure_ascii=False))
return
matches = []
for r in rows[1:]:
if r is None:
continue
try:
rf = r[c_from]
rt = r[c_to]
if isinstance(rf, datetime):
rf = rf.date()
elif isinstance(rf, str):
rf = d(rf)
if isinstance(rt, datetime):
rt = rt.date()
elif isinstance(rt, str):
rt = d(rt)
except Exception:
continue
if not (rf <= checkin and rt >= checkout):
continue
gmin = int(r[c_gmin]) if c_gmin is not None and r[c_gmin] is not None else 1
gmax = int(r[c_gmax]) if c_gmax is not None and r[c_gmax] is not None else 99
if not (gmin <= args.guests <= gmax):
continue
room = str(r[c_room]).strip() if c_room is not None and r[c_room] is not None else "Стандарт"
if args.room and room.lower() != args.room.lower():
continue
if c_total is not None and r[c_total] is not None:
total = float(r[c_total])
else:
total = float(r[c_ppn]) * nights
matches.append({
"room": room,
"meal": str(r[c_meal]).strip() if c_meal is not None and r[c_meal] is not None else "без питания",
"currency": str(r[c_curr]).strip() if c_curr is not None and r[c_curr] is not None else "",
"total": round(total, 2),
"nights": nights,
})
if not matches:
print(json.dumps({"ok": True, "found": 0, "message": "Подходящих тарифов не найдено"}, ensure_ascii=False))
return
matches.sort(key=lambda x: x["total"])
print(json.dumps({"ok": True, "found": len(matches), "options": matches[:3]}, ensure_ascii=False))
if __name__ == "__main__":
main()