Files
lottery_ycms/lottery/webapp/services.py
2025-08-03 10:10:10 +09:00

191 lines
9.0 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import json
import logging
from django.core.exceptions import ImproperlyConfigured
from .models import APISettings, Client, Invoice
import requests
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
if not logger.handlers:
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.DEBUG)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
console_handler.setFormatter(formatter)
logger.addHandler(console_handler)
class APIClient:
"""
Класс для подключения к API и получения данных.
Данные API_URL и API_KEY берутся из модели APISettings.
"""
def __init__(self):
self.settings = APISettings.objects.first()
if not self.settings:
logger.error("Настройки API не сконфигурированы. Заполните модель APISettings.")
raise ImproperlyConfigured("Настройки API не сконфигурированы.")
self.api_url = self.settings.api_url.rstrip("/")
self.api_key = self.settings.api_key
self.headers = {"X-API-Key": self.api_key}
logger.debug(f"APIClient инициализирован с базовым URL: {self.api_url}")
def get_clients(self):
url = f"{self.api_url}/api/clients"
logger.debug(f"Запрос клиентов по адресу: {url} с заголовками: {self.headers}")
try:
response = requests.get(url, headers=self.headers, timeout=10)
response.raise_for_status()
data = response.json()
logger.debug("Запрос клиентов успешно выполнен. Данные получены.")
return data
except requests.exceptions.RequestException as e:
logger.error(f"Ошибка при запросе клиентов: {e}")
return None
def get_invoices(self):
url = f"{self.api_url}/api/invoices"
logger.debug(f"Запрос счетов по адресу: {url} с заголовками: {self.headers}")
try:
response = requests.get(url, headers=self.headers, timeout=10)
response.raise_for_status()
data = response.json()
logger.debug("Запрос счетов успешно выполнен. Данные получены.")
return data
except requests.exceptions.RequestException as e:
logger.error(f"Ошибка при запросе счетов: {e}")
return None
class API_SYNC:
"""
Класс для импорта и обновления данных из API.
Методы sync_clients и sync_invoices обновляют существующие записи или создают новые.
"""
def __init__(self):
self.logger = logger
def sync_clients(self):
api_client = APIClient()
data = api_client.get_clients()
new_or_updated = 0
if isinstance(data, dict):
clients_list = data.get("member", [])
self.logger.debug(f"Извлечен список клиентов из ключа 'member', найдено записей: {len(clients_list)}")
elif isinstance(data, list):
clients_list = data
self.logger.debug(f"Получен список клиентов (list), количество записей: {len(clients_list)}")
else:
self.logger.error("Неожиданный формат данных клиентов от API: %s", type(data))
return new_or_updated
for index, item in enumerate(clients_list, start=1):
self.logger.debug(f"Обработка записи клиента {index}: {item}")
if isinstance(item, str):
try:
item = json.loads(item)
self.logger.debug(f"Запись клиента {index} успешно преобразована из строки в словарь.")
except Exception as e:
self.logger.error("Невозможно преобразовать запись клиента %s в словарь: %s; ошибка: %s", index, item, e)
continue
if isinstance(item, dict):
club_card_number = item.get("club_card_num")
if not club_card_number:
self.logger.warning("Запись клиента %s пропущена: отсутствует club_card_num. Запись: %s", index, item)
continue
defaults = {
'name': item.get("name"),
}
telegram_id = item.get("telegram_id")
if telegram_id:
defaults['telegram_id'] = telegram_id # Обновим только если значение есть
obj, created = Client.objects.update_or_create(
club_card_number=club_card_number,
defaults=defaults
)
new_or_updated += 1
if created:
self.logger.info("Запись клиента %s создана: club_card_num %s.", index, club_card_number)
else:
self.logger.info("Запись клиента %s обновлена: club_card_num %s.", index, club_card_number)
else:
self.logger.error("Запись клиента %s имеет неожиданный тип: %s. Значение: %s", index, type(item), item)
return new_or_updated
def sync_invoices(self):
api_client = APIClient()
data = api_client.get_invoices()
new_or_updated = 0
if isinstance(data, dict):
invoices_list = data.get("member", [])
self.logger.debug(f"Извлечен список счетов из ключа 'member', найдено записей: {len(invoices_list)}")
elif isinstance(data, list):
invoices_list = data
self.logger.debug(f"Получен список счетов (list), количество записей: {len(invoices_list)}")
else:
self.logger.error("Неожиданный формат данных счетов от API: %s", type(data))
return new_or_updated
for index, invoice in enumerate(invoices_list, start=1):
self.logger.debug(f"Обработка счета {index}: {invoice}")
if isinstance(invoice, str):
try:
invoice = json.loads(invoice)
self.logger.debug(f"Счет {index} успешно преобразован из строки в словарь.")
except Exception as e:
self.logger.error("Невозможно преобразовать счет %s в словарь: %s; ошибка: %s", index, invoice, e)
continue
if not isinstance(invoice, dict):
self.logger.error("Счет %s имеет неожиданный тип: %s", index, type(invoice))
continue
api_id = invoice.get("@id")
if not api_id:
self.logger.warning("Счет %s пропущен: отсутствует '@id'.", index)
continue
# Извлекаем данные клиента из вложенного объекта
client_data = invoice.get("client", {})
client_name = client_data.get("name")
client_club_card_number = client_data.get("club_card_num")
# Приводим даты (при необходимости, можно использовать парсинг)
created_at = invoice.get("created_at")
closed_at = invoice.get("closed_at")
if closed_at in [None, "N/A"]:
closed_at = None
defaults = {
'invoice_type': invoice.get("@type"),
'created_at': created_at,
'closed_at': closed_at,
'ext_id': invoice.get("ext_id"),
'ext_type': invoice.get("ext_type"),
'client_name': client_name,
'client_club_card_number': client_club_card_number,
'sum': invoice.get("sum"),
'company_number': invoice.get("comp_num"),
'bonus': invoice.get("bonus"),
'start_bonus': invoice.get("start_bonus"),
'deposit_sum': invoice.get("deposit_sum"),
'notes': invoice.get("notes"),
}
obj, created = Invoice.objects.update_or_create(
api_id=api_id,
defaults=defaults
)
new_or_updated += 1
if created:
self.logger.info("Счет %s создан: api_id=%s", index, api_id)
else:
self.logger.info("Счет %s обновлен: api_id=%s", index, api_id)
return new_or_updated