Рефакторинг: вынесена логика импорта/экспорта клиентов в отдельный сервис

- Создан модуль customers/services/import_export.py согласно best practices
- Класс CustomerExporter: содержит логику экспорта в CSV (ранее была в views)
- Класс CustomerImporter: заглушка для будущей реализации импорта
- Views стали тонкими: customer_export и customer_import делегируют работу сервисам
- Улучшена организация кода: соблюдён принцип Single Responsibility
- Уменьшен размер views.py на 30 строк
- Добавлена подробная документация в docstrings классов и методов
- Логику теперь легко тестировать и переиспользовать (например, в Celery tasks)

Преимущества:
- Чистое разделение ответственности
- Упрощённое тестирование
- Возможность переиспользования в асинхронных задачах
- Соответствие Django best practices
This commit is contained in:
2025-12-14 20:55:21 +03:00
parent b41025116c
commit 089ccfa8ae
2 changed files with 113 additions and 37 deletions

View File

@@ -0,0 +1,106 @@
"""
Сервис для импорта и экспорта клиентов.
Этот модуль содержит логику импорта/экспорта клиентов в различных форматах (CSV, Excel).
Разделение на отдельный модуль улучшает организацию кода и следует принципам SRP.
"""
import csv
from django.http import HttpResponse
from django.utils import timezone
from ..models import Customer
class CustomerExporter:
"""
Класс для экспорта клиентов в различные форматы.
"""
@staticmethod
def export_to_csv():
"""
Экспортирует всех клиентов (кроме системного) в CSV файл.
Поля экспорта:
- ID
- Имя
- Email
- Телефон
- Дата создания
Примечание: Баланс кошелька НЕ экспортируется (требование безопасности).
Returns:
HttpResponse: HTTP ответ с CSV файлом для скачивания
"""
# Создаём HTTP ответ с CSV файлом
response = HttpResponse(content_type='text/csv; charset=utf-8')
timestamp = timezone.now().strftime("%Y%m%d_%H%M%S")
response['Content-Disposition'] = f'attachment; filename="customers_export_{timestamp}.csv"'
# Добавляем BOM для корректного открытия в Excel
response.write('\ufeff')
writer = csv.writer(response)
# Заголовки
writer.writerow([
'ID',
'Имя',
'Email',
'Телефон',
'Дата создания',
])
# Данные (исключаем системного клиента)
customers = Customer.objects.filter(is_system_customer=False).order_by('-created_at')
for customer in customers:
writer.writerow([
customer.id,
customer.name or '',
customer.email or '',
str(customer.phone) if customer.phone else '',
customer.created_at.strftime('%Y-%m-%d %H:%M:%S'),
])
return response
class CustomerImporter:
"""
Класс для импорта клиентов из различных форматов.
TODO: Реализовать:
- Парсинг CSV файлов
- Парсинг Excel файлов (.xlsx, .xls)
- Валидация данных (email, телефон)
- Обработка дубликатов
- Пакетное создание клиентов
- Отчёт об ошибках
"""
def __init__(self):
self.errors = []
self.success_count = 0
self.skip_count = 0
def import_from_file(self, file, update_existing=False):
"""
Импорт клиентов из загруженного файла.
Args:
file: Загруженный файл (UploadedFile)
update_existing: Обновлять ли существующих клиентов (по email/телефону)
Returns:
dict: Результат импорта с статистикой
"""
# TODO: Реализовать логику импорта
return {
'success': False,
'message': 'Функция импорта находится в разработке',
'created': 0,
'updated': 0,
'skipped': 0,
'errors': []
}