diff --git a/skills/paradiz/SKILL.md b/skills/paradiz/SKILL.md index 7ac886a..521ee83 100644 --- a/skills/paradiz/SKILL.md +++ b/skills/paradiz/SKILL.md @@ -138,6 +138,7 @@ python3 {baseDir}/scripts/save_booking.py \ Файлы бронирований: - текстовый журнал: `{baseDir}/data/bookings.txt` - структурированный журнал: `{baseDir}/data/bookings.jsonl` +- клиентский лист брони (.rtf): `{baseDir}/data/booking_<номер_брони>.rtf` из шаблона `{baseDir}/data/shablon_broni.rtf` ### Этап 9 — Во время и после проживания diff --git a/skills/paradiz/scripts/save_booking.py b/skills/paradiz/scripts/save_booking.py index d899776..e8b853d 100755 --- a/skills/paradiz/scripts/save_booking.py +++ b/skills/paradiz/scripts/save_booking.py @@ -5,6 +5,7 @@ import os from datetime import datetime from pathlib import Path from urllib import parse, request +import re def send_telegram(bot_token: str, chat_id: str, text: str) -> None: @@ -20,6 +21,49 @@ def send_telegram(bot_token: str, chat_id: str, text: str) -> None: raise RuntimeError(f"Telegram HTTP {resp.status}") +def _extract_amount(s: str) -> float: + cleaned = re.sub(r"[^0-9,\.]", "", s or "").replace(",", ".") + if not cleaned: + return 0.0 + try: + return float(cleaned) + except Exception: + return 0.0 + + +def render_booking_rtf(template_path: Path, output_path: Path, data: dict) -> None: + if not template_path.exists(): + return + txt = template_path.read_text(encoding="utf-8", errors="ignore") + + total_num = _extract_amount(data.get("total", "")) + prepay_num = _extract_amount(data.get("prepay", "")) + rest_num = max(0.0, total_num - prepay_num) + + repl = { + "BKGNFIO": data.get("guest", ""), + "BKGNNUMBER": data.get("booking_number", ""), + "BKGNDATE": data.get("created_at", ""), + "BKGNBEGINDATE": data.get("checkin", ""), + "BKGNENDDATE": data.get("checkout", ""), + "BKGNCATEGORY": data.get("room", ""), + "BKGNNPEOPLE": str(data.get("guests", "")), + "BKGNCOSTFULL": data.get("total", ""), + "BKGNCOSTPAYFULL": data.get("prepay", ""), + "BKGNCOSTRESTFULL": f"{rest_num:,.0f} ₽".replace(",", " "), + "BKGNNUMDAYS": str(data.get("nights", "")), + "CICLSERVICENAME": data.get("room", ""), + "CICLNUMDAYS": str(data.get("nights", "")), + "CICLDAYDICOST": data.get("day_price", ""), + } + + for k, v in repl.items(): + txt = txt.replace(k, str(v)) + + output_path.parent.mkdir(parents=True, exist_ok=True) + output_path.write_text(txt, encoding="utf-8") + + def load_telegram_from_config(): cfg = Path('/home/openclaw/.openclaw/openclaw.json') if not cfg.exists(): @@ -64,11 +108,23 @@ def main(): p.add_argument("--notes", default="", help="Комментарий") p.add_argument("--file", default="/home/openclaw/.openclaw/workspace/skills/paradiz/data/bookings.txt") p.add_argument("--notify", action="store_true", help="Отправить Telegram-уведомление") + p.add_argument("--template", default="/home/openclaw/.openclaw/workspace/skills/paradiz/data/shablon_broni.rtf", help="Путь к шаблону RTF") + p.add_argument("--rtf-out", default="", help="Путь сохранения заполненного листа брони (.rtf)") args = p.parse_args() - now = datetime.now().strftime("%Y-%m-%d %H:%M:%S") + dt_now = datetime.now() + now = dt_now.strftime("%Y-%m-%d %H:%M:%S") + booking_number = dt_now.strftime("PDZ-%Y%m%d-%H%M%S") + + d1 = datetime.strptime(args.checkin, "%Y-%m-%d") + d2 = datetime.strptime(args.checkout, "%Y-%m-%d") + nights = max(0, (d2 - d1).days) + total_num = _extract_amount(args.total) + day_price = f"{(total_num / nights):,.0f} ₽".replace(",", " ") if nights else "" + entry = { "created_at": now, + "booking_number": booking_number, "guest": args.guest, "phone": args.phone, "email": args.email, @@ -79,13 +135,15 @@ def main(): "total": args.total, "prepay": args.prepay, "notes": args.notes, + "nights": nights, + "day_price": day_price, } out = Path(args.file) out.parent.mkdir(parents=True, exist_ok=True) human = ( - f"[{now}] БРОНЬ\n" + f"[{now}] БРОНЬ {booking_number}\n" f"Гость: {args.guest}\n" f"Телефон: {args.phone}\n" f"Email: {args.email}\n" @@ -105,6 +163,13 @@ def main(): with jsonl.open("a", encoding="utf-8") as jf: jf.write(json.dumps(entry, ensure_ascii=False) + "\n") + # Генерируем клиентский лист брони из шаблона RTF + rtf_out = args.rtf_out.strip() if args.rtf_out else str(out.parent / f"booking_{booking_number}.rtf") + try: + render_booking_rtf(Path(args.template), Path(rtf_out), entry) + except Exception: + pass + sent = False err = None if args.notify: @@ -118,6 +183,7 @@ def main(): if bot_token and chat_id: text = ( "📌 Новая бронь Парадиз\n" + f"Номер брони: {booking_number}\n" f"Гость: {args.guest}\n" f"Телефон: {args.phone}\n" f"Email: {args.email}\n" @@ -136,7 +202,7 @@ def main(): else: err = "PARADIZ_TG_BOT_TOKEN / PARADIZ_TG_CHAT_ID не заданы" - print(json.dumps({"ok": True, "saved": str(out), "jsonl": str(jsonl), "telegram_sent": sent, "telegram_error": err}, ensure_ascii=False)) + print(json.dumps({"ok": True, "booking_number": booking_number, "saved": str(out), "jsonl": str(jsonl), "rtf": str(rtf_out), "telegram_sent": sent, "telegram_error": err}, ensure_ascii=False)) if __name__ == "__main__":