- Упростить URL: /api/v1/fns/reports/, /api/v1/fns/upload/ - Добавить swagger теги для группировки в документации
123 lines
3.9 KiB
Python
123 lines
3.9 KiB
Python
"""
|
||
Views для приложения парсеров.
|
||
"""
|
||
|
||
import hashlib
|
||
from pathlib import Path
|
||
|
||
from apps.parsers.models import FinancialReport
|
||
from apps.parsers.serializers import (
|
||
FinancialReportDetailSerializer,
|
||
FinancialReportSerializer,
|
||
FNSFileUploadSerializer,
|
||
)
|
||
from apps.parsers.tasks import process_fns_file
|
||
from django.conf import settings
|
||
from drf_yasg.utils import swagger_auto_schema
|
||
from rest_framework import status
|
||
from rest_framework.parsers import MultiPartParser
|
||
from rest_framework.response import Response
|
||
from rest_framework.views import APIView
|
||
from rest_framework.viewsets import ReadOnlyModelViewSet
|
||
|
||
FNS_TAG = "ФНС - Бухгалтерская отчетность"
|
||
|
||
|
||
class FinancialReportViewSet(ReadOnlyModelViewSet):
|
||
"""
|
||
API для просмотра финансовых отчетов ФНС.
|
||
|
||
list:
|
||
Получить список всех отчетов.
|
||
Поддерживает фильтрацию по: ogrn, external_id, status.
|
||
|
||
retrieve:
|
||
Получить детальную информацию об отчете, включая все строки.
|
||
"""
|
||
|
||
queryset = FinancialReport.objects.all().order_by("-created_at")
|
||
filterset_fields = ["ogrn", "external_id", "status", "source"]
|
||
|
||
def get_serializer_class(self):
|
||
if self.action == "retrieve":
|
||
return FinancialReportDetailSerializer
|
||
return FinancialReportSerializer
|
||
|
||
@swagger_auto_schema(tags=[FNS_TAG])
|
||
def list(self, request, *args, **kwargs):
|
||
return super().list(request, *args, **kwargs)
|
||
|
||
@swagger_auto_schema(tags=[FNS_TAG])
|
||
def retrieve(self, request, *args, **kwargs):
|
||
return super().retrieve(request, *args, **kwargs)
|
||
|
||
|
||
class FNSReportUploadView(APIView):
|
||
"""
|
||
API для загрузки файлов бухгалтерской отчетности ФНС.
|
||
|
||
POST:
|
||
Пакетная загрузка файлов.
|
||
Файлы сохраняются во временную директорию и ставятся в очередь
|
||
на обработку через Celery.
|
||
|
||
Request:
|
||
multipart/form-data с полем 'files' (можно несколько файлов)
|
||
|
||
Response:
|
||
{
|
||
"queued": 3,
|
||
"skipped": 1,
|
||
"task_ids": ["uuid1", "uuid2", "uuid3"]
|
||
}
|
||
"""
|
||
|
||
parser_classes = [MultiPartParser]
|
||
|
||
@swagger_auto_schema(tags=[FNS_TAG], request_body=FNSFileUploadSerializer)
|
||
def post(self, request):
|
||
serializer = FNSFileUploadSerializer(data=request.data)
|
||
serializer.is_valid(raise_exception=True)
|
||
|
||
files = serializer.validated_data["files"]
|
||
task_ids = []
|
||
queued = 0
|
||
skipped = 0
|
||
|
||
# Создаём директорию для загрузки
|
||
upload_dir = Path(settings.FNS_WATCH_DIRECTORY)
|
||
upload_dir.mkdir(parents=True, exist_ok=True)
|
||
|
||
from apps.parsers.services import FNSReportService
|
||
|
||
for file in files:
|
||
# Вычисляем хеш файла
|
||
file_content = file.read()
|
||
file_hash = hashlib.sha256(file_content).hexdigest()
|
||
file.seek(0)
|
||
|
||
# Проверяем дубликат
|
||
if FNSReportService.exists_by_hash(file_hash):
|
||
skipped += 1
|
||
continue
|
||
|
||
# Сохраняем файл
|
||
file_path = upload_dir / file.name
|
||
with open(file_path, "wb") as f:
|
||
for chunk in file.chunks():
|
||
f.write(chunk)
|
||
|
||
# Ставим в очередь
|
||
task = process_fns_file.delay(str(file_path))
|
||
task_ids.append(task.id)
|
||
queued += 1
|
||
|
||
return Response(
|
||
{
|
||
"queued": queued,
|
||
"skipped": skipped,
|
||
"task_ids": task_ids,
|
||
},
|
||
status=status.HTTP_202_ACCEPTED,
|
||
)
|