feat(api): полное API для всех парсеров с документацией
This commit is contained in:
@@ -1,13 +1,164 @@
|
||||
"""
|
||||
Сериализаторы для приложения парсеров.
|
||||
|
||||
Все сериализаторы read-only, так как данные загружаются только через парсеры.
|
||||
"""
|
||||
|
||||
from apps.parsers.models import FinancialReport, FinancialReportLine
|
||||
from apps.parsers.models import (
|
||||
FinancialReport,
|
||||
FinancialReportLine,
|
||||
IndustrialCertificateRecord,
|
||||
InspectionRecord,
|
||||
ManufacturerRecord,
|
||||
ParserLoadLog,
|
||||
ProcurementRecord,
|
||||
Proxy,
|
||||
)
|
||||
from rest_framework import serializers
|
||||
|
||||
# =============================================================================
|
||||
# Минпромторг - Сертификаты промышленного производства
|
||||
# =============================================================================
|
||||
|
||||
|
||||
class IndustrialCertificateSerializer(serializers.ModelSerializer):
|
||||
"""
|
||||
Сертификат промышленного производства РФ.
|
||||
|
||||
Данные загружаются из Минпромторга.
|
||||
"""
|
||||
|
||||
class Meta:
|
||||
model = IndustrialCertificateRecord
|
||||
fields = [
|
||||
"id",
|
||||
"load_batch",
|
||||
"issue_date",
|
||||
"certificate_number",
|
||||
"expiry_date",
|
||||
"certificate_file_url",
|
||||
"organisation_name",
|
||||
"inn",
|
||||
"ogrn",
|
||||
"created_at",
|
||||
"updated_at",
|
||||
]
|
||||
read_only_fields = fields
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# Минпромторг - Реестр производителей
|
||||
# =============================================================================
|
||||
|
||||
|
||||
class ManufacturerSerializer(serializers.ModelSerializer):
|
||||
"""
|
||||
Производитель из реестра Минпромторга.
|
||||
|
||||
Данные загружаются из Минпромторга.
|
||||
"""
|
||||
|
||||
class Meta:
|
||||
model = ManufacturerRecord
|
||||
fields = [
|
||||
"id",
|
||||
"load_batch",
|
||||
"full_legal_name",
|
||||
"inn",
|
||||
"ogrn",
|
||||
"address",
|
||||
"created_at",
|
||||
"updated_at",
|
||||
]
|
||||
read_only_fields = fields
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# Единый реестр проверок (proverki.gov.ru)
|
||||
# =============================================================================
|
||||
|
||||
|
||||
class InspectionSerializer(serializers.ModelSerializer):
|
||||
"""
|
||||
Проверка из Единого реестра проверок.
|
||||
|
||||
Поддерживает ФЗ-294 и ФЗ-248.
|
||||
"""
|
||||
|
||||
class Meta:
|
||||
model = InspectionRecord
|
||||
fields = [
|
||||
"id",
|
||||
"load_batch",
|
||||
"registration_number",
|
||||
"inn",
|
||||
"ogrn",
|
||||
"organisation_name",
|
||||
"control_authority",
|
||||
"inspection_type",
|
||||
"inspection_form",
|
||||
"start_date",
|
||||
"end_date",
|
||||
"status",
|
||||
"legal_basis",
|
||||
"result",
|
||||
"is_federal_law_248",
|
||||
"data_year",
|
||||
"data_month",
|
||||
"created_at",
|
||||
"updated_at",
|
||||
]
|
||||
read_only_fields = fields
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# Государственные закупки (zakupki.gov.ru)
|
||||
# =============================================================================
|
||||
|
||||
|
||||
class ProcurementSerializer(serializers.ModelSerializer):
|
||||
"""
|
||||
Государственная закупка из ЕИС zakupki.gov.ru.
|
||||
|
||||
Поддерживает 44-ФЗ и 223-ФЗ.
|
||||
"""
|
||||
|
||||
class Meta:
|
||||
model = ProcurementRecord
|
||||
fields = [
|
||||
"id",
|
||||
"load_batch",
|
||||
"purchase_number",
|
||||
"purchase_name",
|
||||
"customer_inn",
|
||||
"customer_kpp",
|
||||
"customer_ogrn",
|
||||
"customer_name",
|
||||
"max_price",
|
||||
"currency_code",
|
||||
"placement_method",
|
||||
"publish_date",
|
||||
"end_date",
|
||||
"status",
|
||||
"law_type",
|
||||
"purchase_object_info",
|
||||
"href",
|
||||
"region_code",
|
||||
"data_year",
|
||||
"data_month",
|
||||
"created_at",
|
||||
"updated_at",
|
||||
]
|
||||
read_only_fields = fields
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# ФНС - Бухгалтерская отчетность
|
||||
# =============================================================================
|
||||
|
||||
|
||||
class FinancialReportLineSerializer(serializers.ModelSerializer):
|
||||
"""Сериализатор строки финансового отчета."""
|
||||
"""Строка финансового отчета."""
|
||||
|
||||
class Meta:
|
||||
model = FinancialReportLine
|
||||
@@ -23,7 +174,11 @@ class FinancialReportLineSerializer(serializers.ModelSerializer):
|
||||
|
||||
|
||||
class FinancialReportSerializer(serializers.ModelSerializer):
|
||||
"""Сериализатор финансового отчета."""
|
||||
"""
|
||||
Финансовый отчет ФНС.
|
||||
|
||||
Данные загружаются из Excel файлов.
|
||||
"""
|
||||
|
||||
lines_count = serializers.SerializerMethodField()
|
||||
|
||||
@@ -50,7 +205,7 @@ class FinancialReportSerializer(serializers.ModelSerializer):
|
||||
|
||||
|
||||
class FinancialReportDetailSerializer(FinancialReportSerializer):
|
||||
"""Сериализатор финансового отчета с детализацией строк."""
|
||||
"""Финансовый отчет с детализацией строк."""
|
||||
|
||||
lines = FinancialReportLineSerializer(many=True, read_only=True)
|
||||
|
||||
@@ -59,7 +214,11 @@ class FinancialReportDetailSerializer(FinancialReportSerializer):
|
||||
|
||||
|
||||
class FNSFileUploadSerializer(serializers.Serializer):
|
||||
"""Сериализатор для загрузки файлов FNS."""
|
||||
"""
|
||||
Сериализатор для загрузки файлов FNS.
|
||||
|
||||
Принимает список Excel файлов в формате fin_{id}_{ogrn}.xlsx
|
||||
"""
|
||||
|
||||
files = serializers.ListField(
|
||||
child=serializers.FileField(),
|
||||
@@ -81,3 +240,55 @@ class FNSFileUploadSerializer(serializers.Serializer):
|
||||
)
|
||||
|
||||
return value
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# Служебные модели
|
||||
# =============================================================================
|
||||
|
||||
|
||||
class ParserLoadLogSerializer(serializers.ModelSerializer):
|
||||
"""
|
||||
Лог загрузки парсера.
|
||||
|
||||
Информация о каждой загрузке данных из внешнего источника.
|
||||
"""
|
||||
|
||||
source_display = serializers.CharField(source="get_source_display", read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = ParserLoadLog
|
||||
fields = [
|
||||
"id",
|
||||
"batch_id",
|
||||
"source",
|
||||
"source_display",
|
||||
"records_count",
|
||||
"status",
|
||||
"error_message",
|
||||
"created_at",
|
||||
"updated_at",
|
||||
]
|
||||
read_only_fields = fields
|
||||
|
||||
|
||||
class ProxySerializer(serializers.ModelSerializer):
|
||||
"""
|
||||
Прокси-сервер для парсеров.
|
||||
|
||||
Используется для обхода блокировок при парсинге.
|
||||
"""
|
||||
|
||||
class Meta:
|
||||
model = Proxy
|
||||
fields = [
|
||||
"id",
|
||||
"address",
|
||||
"is_active",
|
||||
"last_used_at",
|
||||
"fail_count",
|
||||
"description",
|
||||
"created_at",
|
||||
"updated_at",
|
||||
]
|
||||
read_only_fields = fields
|
||||
|
||||
@@ -1,10 +1,66 @@
|
||||
from apps.parsers.views import FinancialReportViewSet, FNSReportUploadView
|
||||
"""
|
||||
URL конфигурация для приложения парсеров.
|
||||
|
||||
Все эндпоинты только для чтения (GET, GET list).
|
||||
"""
|
||||
|
||||
from apps.parsers.views import (
|
||||
FinancialReportViewSet,
|
||||
FNSReportUploadView,
|
||||
IndustrialCertificateViewSet,
|
||||
InspectionViewSet,
|
||||
ManufacturerViewSet,
|
||||
ParserLoadLogViewSet,
|
||||
ProcurementViewSet,
|
||||
ProxyViewSet,
|
||||
)
|
||||
from django.urls import include, path
|
||||
from rest_framework.routers import DefaultRouter
|
||||
|
||||
app_name = "parsers"
|
||||
|
||||
# FNS router
|
||||
# =============================================================================
|
||||
# Минпромторг: /api/v1/minpromtorg/
|
||||
# =============================================================================
|
||||
|
||||
minpromtorg_router = DefaultRouter()
|
||||
minpromtorg_router.register(
|
||||
r"certificates", IndustrialCertificateViewSet, basename="certificates"
|
||||
)
|
||||
minpromtorg_router.register(
|
||||
r"manufacturers", ManufacturerViewSet, basename="manufacturers"
|
||||
)
|
||||
|
||||
minpromtorg_urlpatterns = [
|
||||
path("", include(minpromtorg_router.urls)),
|
||||
]
|
||||
|
||||
# =============================================================================
|
||||
# Единый реестр проверок: /api/v1/proverki/
|
||||
# =============================================================================
|
||||
|
||||
proverki_router = DefaultRouter()
|
||||
proverki_router.register(r"", InspectionViewSet, basename="inspections")
|
||||
|
||||
proverki_urlpatterns = [
|
||||
path("", include(proverki_router.urls)),
|
||||
]
|
||||
|
||||
# =============================================================================
|
||||
# Государственные закупки: /api/v1/zakupki/
|
||||
# =============================================================================
|
||||
|
||||
zakupki_router = DefaultRouter()
|
||||
zakupki_router.register(r"", ProcurementViewSet, basename="procurements")
|
||||
|
||||
zakupki_urlpatterns = [
|
||||
path("", include(zakupki_router.urls)),
|
||||
]
|
||||
|
||||
# =============================================================================
|
||||
# ФНС - Бухгалтерская отчетность: /api/v1/fns/
|
||||
# =============================================================================
|
||||
|
||||
fns_router = DefaultRouter()
|
||||
fns_router.register(r"reports", FinancialReportViewSet, basename="fns-reports")
|
||||
|
||||
@@ -13,4 +69,20 @@ fns_urlpatterns = [
|
||||
path("", include(fns_router.urls)),
|
||||
]
|
||||
|
||||
# =============================================================================
|
||||
# Системные (логи, прокси): /api/v1/system/
|
||||
# =============================================================================
|
||||
|
||||
system_router = DefaultRouter()
|
||||
system_router.register(r"logs", ParserLoadLogViewSet, basename="parser-logs")
|
||||
system_router.register(r"proxies", ProxyViewSet, basename="proxies")
|
||||
|
||||
system_urlpatterns = [
|
||||
path("", include(system_router.urls)),
|
||||
]
|
||||
|
||||
# =============================================================================
|
||||
# Legacy urlpatterns (пусто, используется app_name)
|
||||
# =============================================================================
|
||||
|
||||
urlpatterns = []
|
||||
|
||||
@@ -1,53 +1,296 @@
|
||||
"""
|
||||
Views для приложения парсеров.
|
||||
|
||||
Все ViewSets только для чтения (GET, GET list).
|
||||
Добавление и удаление данных - через парсеры и админку.
|
||||
"""
|
||||
|
||||
import hashlib
|
||||
from pathlib import Path
|
||||
|
||||
from apps.parsers.models import FinancialReport
|
||||
from apps.parsers.models import (
|
||||
FinancialReport,
|
||||
IndustrialCertificateRecord,
|
||||
InspectionRecord,
|
||||
ManufacturerRecord,
|
||||
ParserLoadLog,
|
||||
ProcurementRecord,
|
||||
Proxy,
|
||||
)
|
||||
from apps.parsers.serializers import (
|
||||
FinancialReportDetailSerializer,
|
||||
FinancialReportSerializer,
|
||||
FNSFileUploadSerializer,
|
||||
IndustrialCertificateSerializer,
|
||||
InspectionSerializer,
|
||||
ManufacturerSerializer,
|
||||
ParserLoadLogSerializer,
|
||||
ProcurementSerializer,
|
||||
ProxySerializer,
|
||||
)
|
||||
from apps.parsers.tasks import process_fns_file
|
||||
from django.conf import settings
|
||||
from drf_yasg import openapi
|
||||
from drf_yasg.utils import swagger_auto_schema
|
||||
from rest_framework import status
|
||||
from rest_framework.parsers import MultiPartParser
|
||||
from rest_framework.permissions import IsAdminUser, IsAuthenticated
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.views import APIView
|
||||
from rest_framework.viewsets import ReadOnlyModelViewSet
|
||||
|
||||
# =============================================================================
|
||||
# Swagger Tags (для группировки в документации)
|
||||
# =============================================================================
|
||||
|
||||
MINPROMTORG_TAG = "Минпромторг"
|
||||
PROVERKI_TAG = "Единый реестр проверок"
|
||||
ZAKUPKI_TAG = "Государственные закупки"
|
||||
FNS_TAG = "ФНС - Бухгалтерская отчетность"
|
||||
SYSTEM_TAG = "Системные"
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# Минпромторг - Сертификаты промышленного производства
|
||||
# =============================================================================
|
||||
|
||||
|
||||
class IndustrialCertificateViewSet(ReadOnlyModelViewSet):
|
||||
"""
|
||||
API для просмотра сертификатов промышленного производства.
|
||||
|
||||
Данные загружаются из Минпромторга.
|
||||
Только чтение - добавление через парсер/админку.
|
||||
"""
|
||||
|
||||
queryset = IndustrialCertificateRecord.objects.all().order_by("-created_at")
|
||||
serializer_class = IndustrialCertificateSerializer
|
||||
permission_classes = [IsAuthenticated]
|
||||
filterset_fields = ["inn", "ogrn", "certificate_number", "load_batch"]
|
||||
search_fields = ["organisation_name", "certificate_number", "inn", "ogrn"]
|
||||
|
||||
@swagger_auto_schema(
|
||||
tags=[MINPROMTORG_TAG],
|
||||
operation_summary="Список сертификатов",
|
||||
operation_description=(
|
||||
"Возвращает список сертификатов промышленного производства.\n"
|
||||
"Поддерживает фильтрацию по: inn, ogrn, certificate_number, load_batch.\n"
|
||||
"Поддерживает поиск по: organisation_name, certificate_number, inn, ogrn."
|
||||
),
|
||||
)
|
||||
def list(self, request, *args, **kwargs):
|
||||
return super().list(request, *args, **kwargs)
|
||||
|
||||
@swagger_auto_schema(
|
||||
tags=[MINPROMTORG_TAG],
|
||||
operation_summary="Детали сертификата",
|
||||
operation_description="Возвращает информацию о конкретном сертификате.",
|
||||
)
|
||||
def retrieve(self, request, *args, **kwargs):
|
||||
return super().retrieve(request, *args, **kwargs)
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# Минпромторг - Реестр производителей
|
||||
# =============================================================================
|
||||
|
||||
|
||||
class ManufacturerViewSet(ReadOnlyModelViewSet):
|
||||
"""
|
||||
API для просмотра реестра производителей.
|
||||
|
||||
Данные загружаются из Минпромторга.
|
||||
Только чтение - добавление через парсер/админку.
|
||||
"""
|
||||
|
||||
queryset = ManufacturerRecord.objects.all().order_by("-created_at")
|
||||
serializer_class = ManufacturerSerializer
|
||||
permission_classes = [IsAuthenticated]
|
||||
filterset_fields = ["inn", "ogrn", "load_batch"]
|
||||
search_fields = ["full_legal_name", "inn", "ogrn", "address"]
|
||||
|
||||
@swagger_auto_schema(
|
||||
tags=[MINPROMTORG_TAG],
|
||||
operation_summary="Список производителей",
|
||||
operation_description=(
|
||||
"Возвращает список производителей из реестра Минпромторга.\n"
|
||||
"Поддерживает фильтрацию по: inn, ogrn, load_batch.\n"
|
||||
"Поддерживает поиск по: full_legal_name, inn, ogrn, address."
|
||||
),
|
||||
)
|
||||
def list(self, request, *args, **kwargs):
|
||||
return super().list(request, *args, **kwargs)
|
||||
|
||||
@swagger_auto_schema(
|
||||
tags=[MINPROMTORG_TAG],
|
||||
operation_summary="Детали производителя",
|
||||
operation_description="Возвращает информацию о конкретном производителе.",
|
||||
)
|
||||
def retrieve(self, request, *args, **kwargs):
|
||||
return super().retrieve(request, *args, **kwargs)
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# Единый реестр проверок (proverki.gov.ru)
|
||||
# =============================================================================
|
||||
|
||||
|
||||
class InspectionViewSet(ReadOnlyModelViewSet):
|
||||
"""
|
||||
API для просмотра проверок из Единого реестра проверок.
|
||||
|
||||
Данные из ФГИС "Единый реестр проверок" (Генпрокуратура РФ).
|
||||
Поддерживает ФЗ-294 (традиционные) и ФЗ-248 (новые с 2021).
|
||||
Только чтение - добавление через парсер/админку.
|
||||
"""
|
||||
|
||||
queryset = InspectionRecord.objects.all().order_by("-created_at")
|
||||
serializer_class = InspectionSerializer
|
||||
permission_classes = [IsAuthenticated]
|
||||
filterset_fields = [
|
||||
"inn",
|
||||
"ogrn",
|
||||
"registration_number",
|
||||
"is_federal_law_248",
|
||||
"data_year",
|
||||
"data_month",
|
||||
"load_batch",
|
||||
]
|
||||
search_fields = [
|
||||
"organisation_name",
|
||||
"registration_number",
|
||||
"inn",
|
||||
"ogrn",
|
||||
"control_authority",
|
||||
]
|
||||
|
||||
@swagger_auto_schema(
|
||||
tags=[PROVERKI_TAG],
|
||||
operation_summary="Список проверок",
|
||||
operation_description=(
|
||||
"Возвращает список проверок из Единого реестра.\n"
|
||||
"Поддерживает фильтрацию по: inn, ogrn, registration_number, "
|
||||
"is_federal_law_248, data_year, data_month, load_batch.\n"
|
||||
"Поддерживает поиск по: organisation_name, registration_number, "
|
||||
"inn, ogrn, control_authority."
|
||||
),
|
||||
)
|
||||
def list(self, request, *args, **kwargs):
|
||||
return super().list(request, *args, **kwargs)
|
||||
|
||||
@swagger_auto_schema(
|
||||
tags=[PROVERKI_TAG],
|
||||
operation_summary="Детали проверки",
|
||||
operation_description="Возвращает информацию о конкретной проверке.",
|
||||
)
|
||||
def retrieve(self, request, *args, **kwargs):
|
||||
return super().retrieve(request, *args, **kwargs)
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# Государственные закупки (zakupki.gov.ru)
|
||||
# =============================================================================
|
||||
|
||||
|
||||
class ProcurementViewSet(ReadOnlyModelViewSet):
|
||||
"""
|
||||
API для просмотра государственных закупок.
|
||||
|
||||
Данные из ЕИС zakupki.gov.ru.
|
||||
Поддерживает 44-ФЗ и 223-ФЗ.
|
||||
Только чтение - добавление через парсер/админку.
|
||||
"""
|
||||
|
||||
queryset = ProcurementRecord.objects.all().order_by("-created_at")
|
||||
serializer_class = ProcurementSerializer
|
||||
permission_classes = [IsAuthenticated]
|
||||
filterset_fields = [
|
||||
"customer_inn",
|
||||
"customer_ogrn",
|
||||
"purchase_number",
|
||||
"law_type",
|
||||
"status",
|
||||
"region_code",
|
||||
"data_year",
|
||||
"data_month",
|
||||
"load_batch",
|
||||
]
|
||||
search_fields = [
|
||||
"purchase_name",
|
||||
"purchase_number",
|
||||
"customer_name",
|
||||
"customer_inn",
|
||||
"customer_ogrn",
|
||||
]
|
||||
|
||||
@swagger_auto_schema(
|
||||
tags=[ZAKUPKI_TAG],
|
||||
operation_summary="Список закупок",
|
||||
operation_description=(
|
||||
"Возвращает список государственных закупок.\n"
|
||||
"Поддерживает фильтрацию по: customer_inn, customer_ogrn, "
|
||||
"purchase_number, law_type, status, region_code, "
|
||||
"data_year, data_month, load_batch.\n"
|
||||
"Поддерживает поиск по: purchase_name, purchase_number, "
|
||||
"customer_name, customer_inn, customer_ogrn."
|
||||
),
|
||||
)
|
||||
def list(self, request, *args, **kwargs):
|
||||
return super().list(request, *args, **kwargs)
|
||||
|
||||
@swagger_auto_schema(
|
||||
tags=[ZAKUPKI_TAG],
|
||||
operation_summary="Детали закупки",
|
||||
operation_description="Возвращает информацию о конкретной закупке.",
|
||||
)
|
||||
def retrieve(self, request, *args, **kwargs):
|
||||
return super().retrieve(request, *args, **kwargs)
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# ФНС - Бухгалтерская отчетность
|
||||
# =============================================================================
|
||||
|
||||
|
||||
class FinancialReportViewSet(ReadOnlyModelViewSet):
|
||||
"""
|
||||
API для просмотра финансовых отчетов ФНС.
|
||||
|
||||
list:
|
||||
Получить список всех отчетов.
|
||||
Поддерживает фильтрацию по: ogrn, external_id, status.
|
||||
|
||||
retrieve:
|
||||
Получить детальную информацию об отчете, включая все строки.
|
||||
Данные загружаются из Excel файлов (fin_{id}_{ogrn}.xlsx).
|
||||
Только чтение - добавление через загрузку файлов.
|
||||
"""
|
||||
|
||||
queryset = FinancialReport.objects.all().order_by("-created_at")
|
||||
filterset_fields = ["ogrn", "external_id", "status", "source"]
|
||||
permission_classes = [IsAuthenticated]
|
||||
filterset_fields = ["ogrn", "external_id", "status", "source", "load_batch"]
|
||||
search_fields = ["ogrn", "external_id", "file_name"]
|
||||
|
||||
def get_serializer_class(self):
|
||||
if self.action == "retrieve":
|
||||
return FinancialReportDetailSerializer
|
||||
return FinancialReportSerializer
|
||||
|
||||
@swagger_auto_schema(tags=[FNS_TAG])
|
||||
@swagger_auto_schema(
|
||||
tags=[FNS_TAG],
|
||||
operation_summary="Список отчетов",
|
||||
operation_description=(
|
||||
"Возвращает список финансовых отчетов ФНС.\n"
|
||||
"Поддерживает фильтрацию по: ogrn, external_id, status, "
|
||||
"source, load_batch.\n"
|
||||
"Поддерживает поиск по: ogrn, external_id, file_name."
|
||||
),
|
||||
)
|
||||
def list(self, request, *args, **kwargs):
|
||||
return super().list(request, *args, **kwargs)
|
||||
|
||||
@swagger_auto_schema(tags=[FNS_TAG])
|
||||
@swagger_auto_schema(
|
||||
tags=[FNS_TAG],
|
||||
operation_summary="Детали отчета",
|
||||
operation_description=(
|
||||
"Возвращает детальную информацию об отчете, "
|
||||
"включая все строки бухгалтерской отчетности."
|
||||
),
|
||||
)
|
||||
def retrieve(self, request, *args, **kwargs):
|
||||
return super().retrieve(request, *args, **kwargs)
|
||||
|
||||
@@ -56,25 +299,59 @@ class FNSReportUploadView(APIView):
|
||||
"""
|
||||
API для загрузки файлов бухгалтерской отчетности ФНС.
|
||||
|
||||
POST:
|
||||
Пакетная загрузка файлов.
|
||||
Файлы сохраняются во временную директорию и ставятся в очередь
|
||||
на обработку через Celery.
|
||||
|
||||
Request:
|
||||
multipart/form-data с полем 'files' (можно несколько файлов)
|
||||
|
||||
Response:
|
||||
{
|
||||
"queued": 3,
|
||||
"skipped": 1,
|
||||
"task_ids": ["uuid1", "uuid2", "uuid3"]
|
||||
}
|
||||
Файлы сохраняются во временную директорию и ставятся в очередь
|
||||
на обработку через Celery.
|
||||
"""
|
||||
|
||||
parser_classes = [MultiPartParser]
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
@swagger_auto_schema(tags=[FNS_TAG], request_body=FNSFileUploadSerializer)
|
||||
@swagger_auto_schema(
|
||||
tags=[FNS_TAG],
|
||||
operation_summary="Загрузка файлов",
|
||||
operation_description=(
|
||||
"Пакетная загрузка файлов бухгалтерской отчетности.\n\n"
|
||||
"**Формат файла:** fin_{id}_{ogrn}.xlsx\n\n"
|
||||
"**Ответ:**\n"
|
||||
"- queued: количество файлов в очереди\n"
|
||||
"- skipped: количество пропущенных (дубликаты)\n"
|
||||
"- task_ids: ID задач для отслеживания статуса"
|
||||
),
|
||||
manual_parameters=[
|
||||
openapi.Parameter(
|
||||
name="files",
|
||||
in_=openapi.IN_FORM,
|
||||
type=openapi.TYPE_FILE,
|
||||
required=True,
|
||||
description="Файл(ы) для загрузки (fin_*.xlsx)",
|
||||
),
|
||||
],
|
||||
consumes=["multipart/form-data"],
|
||||
responses={
|
||||
202: openapi.Response(
|
||||
description="Файлы приняты в обработку",
|
||||
schema=openapi.Schema(
|
||||
type=openapi.TYPE_OBJECT,
|
||||
properties={
|
||||
"queued": openapi.Schema(
|
||||
type=openapi.TYPE_INTEGER,
|
||||
description="Количество файлов в очереди",
|
||||
),
|
||||
"skipped": openapi.Schema(
|
||||
type=openapi.TYPE_INTEGER,
|
||||
description="Количество пропущенных",
|
||||
),
|
||||
"task_ids": openapi.Schema(
|
||||
type=openapi.TYPE_ARRAY,
|
||||
items=openapi.Schema(type=openapi.TYPE_STRING),
|
||||
description="ID задач Celery",
|
||||
),
|
||||
},
|
||||
),
|
||||
),
|
||||
400: "Ошибка валидации файлов",
|
||||
},
|
||||
)
|
||||
def post(self, request):
|
||||
serializer = FNSFileUploadSerializer(data=request.data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
@@ -120,3 +397,76 @@ class FNSReportUploadView(APIView):
|
||||
},
|
||||
status=status.HTTP_202_ACCEPTED,
|
||||
)
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# Системные (логи загрузок, прокси)
|
||||
# =============================================================================
|
||||
|
||||
|
||||
class ParserLoadLogViewSet(ReadOnlyModelViewSet):
|
||||
"""
|
||||
API для просмотра логов загрузок парсеров.
|
||||
|
||||
Информация о каждой загрузке данных из внешних источников.
|
||||
Только для администраторов.
|
||||
"""
|
||||
|
||||
queryset = ParserLoadLog.objects.all().order_by("-created_at")
|
||||
serializer_class = ParserLoadLogSerializer
|
||||
permission_classes = [IsAdminUser]
|
||||
filterset_fields = ["source", "status", "batch_id"]
|
||||
|
||||
@swagger_auto_schema(
|
||||
tags=[SYSTEM_TAG],
|
||||
operation_summary="Список логов загрузок",
|
||||
operation_description=(
|
||||
"Возвращает историю загрузок данных парсерами.\n"
|
||||
"Доступно только администраторам.\n"
|
||||
"Поддерживает фильтрацию по: source, status, batch_id."
|
||||
),
|
||||
)
|
||||
def list(self, request, *args, **kwargs):
|
||||
return super().list(request, *args, **kwargs)
|
||||
|
||||
@swagger_auto_schema(
|
||||
tags=[SYSTEM_TAG],
|
||||
operation_summary="Детали загрузки",
|
||||
operation_description="Возвращает информацию о конкретной загрузке.",
|
||||
)
|
||||
def retrieve(self, request, *args, **kwargs):
|
||||
return super().retrieve(request, *args, **kwargs)
|
||||
|
||||
|
||||
class ProxyViewSet(ReadOnlyModelViewSet):
|
||||
"""
|
||||
API для просмотра списка прокси-серверов.
|
||||
|
||||
Используется для отладки и мониторинга парсеров.
|
||||
Только для администраторов.
|
||||
"""
|
||||
|
||||
queryset = Proxy.objects.all().order_by("-last_used_at")
|
||||
serializer_class = ProxySerializer
|
||||
permission_classes = [IsAdminUser]
|
||||
filterset_fields = ["is_active"]
|
||||
|
||||
@swagger_auto_schema(
|
||||
tags=[SYSTEM_TAG],
|
||||
operation_summary="Список прокси",
|
||||
operation_description=(
|
||||
"Возвращает список прокси-серверов для парсеров.\n"
|
||||
"Доступно только администраторам.\n"
|
||||
"Поддерживает фильтрацию по: is_active."
|
||||
),
|
||||
)
|
||||
def list(self, request, *args, **kwargs):
|
||||
return super().list(request, *args, **kwargs)
|
||||
|
||||
@swagger_auto_schema(
|
||||
tags=[SYSTEM_TAG],
|
||||
operation_summary="Детали прокси",
|
||||
operation_description="Возвращает информацию о конкретном прокси.",
|
||||
)
|
||||
def retrieve(self, request, *args, **kwargs):
|
||||
return super().retrieve(request, *args, **kwargs)
|
||||
|
||||
Reference in New Issue
Block a user