feat: purchases added
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import datetime
|
||||
import uuid
|
||||
from typing import Any, AsyncContextManager
|
||||
from contextlib import AbstractAsyncContextManager
|
||||
from typing import Any
|
||||
from unittest.mock import AsyncMock
|
||||
|
||||
import pytest
|
||||
@@ -17,9 +18,10 @@ class MockDatabase:
|
||||
self.target_channels_by_telegram_id: dict[int, domain.TargetChannel] = {}
|
||||
self.external_channels: dict[uuid.UUID, domain.ExternalChannel] = {}
|
||||
self.creatives: dict[uuid.UUID, domain.Creative] = {}
|
||||
self.purchases: dict[uuid.UUID, domain.Purchase] = {}
|
||||
self.m2m_target_external: dict[uuid.UUID, list[uuid.UUID]] = {}
|
||||
|
||||
def transaction(self) -> AsyncContextManager[None]:
|
||||
def transaction(self) -> AbstractAsyncContextManager[None]:
|
||||
return AsyncMock()
|
||||
|
||||
async def get_user(self, *, user_id: uuid.UUID | None = None, telegram_id: int | None = None) -> domain.User | None:
|
||||
@@ -192,10 +194,74 @@ class MockDatabase:
|
||||
async def delete_creative(self, creative_id: uuid.UUID) -> None:
|
||||
self.creatives.pop(creative_id, None)
|
||||
|
||||
async def create_purchase(self, purchase: domain.Purchase) -> domain.Purchase:
|
||||
if not purchase.id:
|
||||
purchase.id = uuid.uuid4()
|
||||
if not hasattr(purchase, 'created_at') or purchase.created_at is None:
|
||||
purchase.created_at = datetime.datetime.now(datetime.UTC)
|
||||
if not hasattr(purchase, 'updated_at') or purchase.updated_at is None:
|
||||
purchase.updated_at = datetime.datetime.now(datetime.UTC)
|
||||
if not hasattr(purchase, 'subscriptions_count') or purchase.subscriptions_count is None:
|
||||
purchase.subscriptions_count = 0
|
||||
if not hasattr(purchase, 'status') or purchase.status is None:
|
||||
purchase.status = domain.PurchaseStatus.ACTIVE
|
||||
# Загружаем связанные объекты
|
||||
target_ch = self.target_channels.get(purchase.target_channel_id)
|
||||
if target_ch:
|
||||
purchase.target_channel = target_ch
|
||||
ext_ch = self.external_channels.get(purchase.external_channel_id)
|
||||
if ext_ch:
|
||||
purchase.external_channel = ext_ch
|
||||
creative = self.creatives.get(purchase.creative_id)
|
||||
if creative:
|
||||
purchase.creative = creative
|
||||
self.purchases[purchase.id] = purchase
|
||||
return purchase
|
||||
|
||||
async def get_purchase(self, user_id: uuid.UUID, purchase_id: uuid.UUID) -> domain.Purchase | None:
|
||||
purchase = self.purchases.get(purchase_id)
|
||||
if purchase and purchase.user_id == user_id:
|
||||
return purchase
|
||||
return None
|
||||
|
||||
async def update_purchase(self, purchase: domain.Purchase) -> domain.Purchase:
|
||||
self.purchases[purchase.id] = purchase
|
||||
return purchase
|
||||
|
||||
async def get_user_purchases(
|
||||
self,
|
||||
user_id: uuid.UUID,
|
||||
*,
|
||||
target_channel_id: uuid.UUID | None = None,
|
||||
external_channel_id: uuid.UUID | None = None,
|
||||
creative_id: uuid.UUID | None = None,
|
||||
include_archived: bool = False,
|
||||
) -> list[domain.Purchase]:
|
||||
result = [p for p in self.purchases.values() if p.user_id == user_id]
|
||||
if target_channel_id:
|
||||
result = [p for p in result if p.target_channel_id == target_channel_id]
|
||||
if external_channel_id:
|
||||
result = [p for p in result if p.external_channel_id == external_channel_id]
|
||||
if creative_id:
|
||||
result = [p for p in result if p.creative_id == creative_id]
|
||||
if not include_archived:
|
||||
result = [p for p in result if p.status == domain.PurchaseStatus.ACTIVE]
|
||||
return sorted(result, key=lambda p: p.placement_date, reverse=True)
|
||||
|
||||
async def delete_purchase(self, purchase_id: uuid.UUID) -> None:
|
||||
self.purchases.pop(purchase_id, None)
|
||||
|
||||
async def check_creative_in_use(self, creative_id: uuid.UUID) -> bool:
|
||||
for purchase in self.purchases.values():
|
||||
if purchase.creative_id == creative_id and purchase.status == domain.PurchaseStatus.ACTIVE:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
class MockTelegramWriter:
|
||||
def __init__(self) -> None:
|
||||
self.sent_messages: list[dict[str, Any]] = []
|
||||
self.invite_link_counter = 0
|
||||
|
||||
async def send_message(self, text: str, chat_id: int) -> None:
|
||||
self.sent_messages.append({'text': text, 'chat_id': chat_id, 'button': None})
|
||||
@@ -208,6 +274,11 @@ class MockTelegramWriter:
|
||||
async def get_chat_member(self, chat_id: int, user_id: int) -> dict[str, Any]:
|
||||
return {}
|
||||
|
||||
async def create_chat_invite_link(self, chat_id: int, requires_approval: bool = False) -> str:
|
||||
self.invite_link_counter += 1
|
||||
link_type = 'approval' if requires_approval else 'public'
|
||||
return f'https://t.me/+{link_type}_link_{self.invite_link_counter}_{chat_id}'
|
||||
|
||||
|
||||
class MockJWTEncoder:
|
||||
def encode_access_token(self, user_id: uuid.UUID, telegram_id: int, username: str | None = None) -> str:
|
||||
|
||||
Reference in New Issue
Block a user