# -*- coding: utf-8 -*- import json import logging import re import time from odoo import api, fields, models, _ from odoo.exceptions import UserError, ValidationError _logger = logging.getLogger(__name__) try: import requests except Exception: # pragma: no cover requests = None class PremiumOrderWizard(models.TransientModel): _name = "premium.order.wizard" _description = "Премиум: заявка на сервис" service_id = fields.Many2one("premium.service", string="Сервис", required=True) company_name = fields.Char(string="Название компании", required=True) inn = fields.Char(string="ИНН") # будет браться из VAT email = fields.Char(string="Email", required=True) phone_telegram = fields.Char(string="Телефон/Телеграм") contact_person = fields.Char(string="Контактное лицо") @api.model def default_get(self, fields_list): res = super().default_get(fields_list) company = self.env.company res.setdefault("company_name", company.name) res.setdefault("inn", company.vat) res.setdefault("email", company.email or self.env.user.email) res.setdefault("phone_telegram", company.phone or company.mobile) res.setdefault("contact_person", self.env.user.name) _logger.info("Premium order wizard default values: %s", res) return res @api.constrains("email") def _check_email(self): email_regex = r"^[\w\.-]+@[\w\.-]+\.\w+$" for rec in self: if rec.email and not re.match(email_regex, rec.email): raise ValidationError(_("Некорректный формат email.")) @api.constrains("inn") def _check_inn(self): for rec in self: if rec.inn and (not rec.inn.isdigit() or len(rec.inn) not in (10, 12)): raise ValidationError(_("ИНН должен содержать 10 или 12 цифр.")) @api.onchange("email") def _onchange_email(self): if self.email and not re.match(r"^[\w\.-]+@[\w\.-]+\.\w+$", self.email): return { "warning": { "title": _("Предупреждение"), "message": _("Некорректный формат email."), } } @api.onchange("inn") def _onchange_inn(self): if self.inn and (not self.inn.isdigit() or len(self.inn) not in (10, 12)): return { "warning": { "title": _("Предупреждение"), "message": _("ИНН должен содержать 10 или 12 цифр."), } } def _build_payload(self): self.ensure_one() service = self.service_id payload = { "service_id": service.id, "service_name": service.name, "service_category": service.category, "service_author_url": service.author_url, "service_description": (service.description or ""), "company_name": self.company_name, "inn": self.inn, "email": self.email, "phone": self.phone_telegram, "contact_name": self.contact_person, "source_db": self.env.cr.dbname, } _logger.info("Premium order payload built: %s", payload) return payload def action_submit(self): self.ensure_one() if not self.email or not self.company_name: raise UserError(_("Заполните обязательные поля: Email и Название компании.")) if requests is None: raise UserError(_("Библиотека requests недоступна на сервере Odoo.")) icp = self.env["ir.config_parameter"].sudo() base_url = (icp.get_param("premium.project_api_url") or "").strip() token = (icp.get_param("premium.project_api_token") or "").strip() _logger.info("Premium API configuration - URL: %s, Token present: %s", base_url, bool(token)) if not base_url: raise UserError( _("Не настроен адрес Project API (Settings → Technical → Parameters → System Parameters).") ) if base_url.endswith("/newlead/"): url = base_url else: url = base_url.rstrip("/") + "/newlead/" _logger.info("Premium API final URL: %s", url) headers = {"Content-Type": "application/json"} if token: headers["X-API-Key"] = token payload = self._build_payload() _logger.info("Attempting to send payload to %s: %s", url, payload) retries = 3 for attempt in range(1, retries + 1): try: _logger.info("Premium order attempt %s of %s", attempt, retries) resp = requests.post(url, json=payload, headers=headers, timeout=15) _logger.info("Response status: %s, headers: %s", resp.status_code, dict(resp.headers)) ok = resp.status_code in (200, 201) try: body = resp.json() _logger.info("Response body: %s", body) except Exception as e: body = {} _logger.warning("Failed to parse response JSON: %s", e) _logger.info("Response text: %s", resp.text) if ok and (body.get("ok") is True): _logger.info("Premium order successful, lead_id: %s", body.get("lead_id")) return { "type": "ir.actions.client", "tag": "display_notification", "params": { "title": _("Заявка успешно отправлена"), "type": "success", "sticky": False, }, } else: _logger.error("Premium order failed: %s %s", resp.status_code, body) if attempt == retries: raise UserError( _("Сервис временно недоступен, пожалуйста, отправьте заявку на info@inf-centre.ru") ) except requests.exceptions.ConnectionError as e: _logger.warning("Connection error on attempt %s: %s", attempt, e) if attempt == retries: _logger.exception("Premium order connection exception: %s", e) raise UserError( _("Не удалось подключиться к серверу Project. Проверьте настройки подключения или отправьте заявку на info@inf-centre.ru") ) time.sleep(3) except Exception as e: _logger.warning("Attempt %s failed: %s", attempt, e) if attempt == retries: _logger.exception("Premium order exception: %s", e) raise UserError( _("Сервис временно недоступен, пожалуйста, отправьте заявку на info@inf-centre.ru") ) time.sleep(3)