-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
17 changed files
with
302 additions
and
43 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
from typing import AsyncIterable, NewType | ||
|
||
from aiohttp import ClientSession | ||
from dishka import Provider, Scope, provide | ||
|
||
from fanfan.config import TimepadConfig | ||
from fanfan.infrastructure.timepad.client import TimepadClient | ||
|
||
TimepadSession = NewType("TimepadSession", ClientSession) | ||
|
||
|
||
class TimepadProvider(Provider): | ||
scope = Scope.APP | ||
|
||
@provide(scope=Scope.REQUEST) | ||
async def get_timepad_session( | ||
self, config: TimepadConfig | ||
) -> AsyncIterable[TimepadSession]: | ||
async with ClientSession( | ||
headers={"Authorization": f"Bearer {config.client_id.get_secret_value()}"} | ||
) as session: | ||
yield session | ||
|
||
@provide(scope=Scope.REQUEST) | ||
async def get_timepad_client(self, session: TimepadSession) -> TimepadClient: | ||
return TimepadClient(session) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
import asyncio | ||
import logging | ||
import math | ||
|
||
from dishka import FromDishka | ||
from dishka.integrations.taskiq import inject | ||
|
||
from fanfan.application.exceptions.ticket import TicketAlreadyExist, TicketNotFound | ||
from fanfan.application.services import TicketService | ||
from fanfan.common.enums import UserRole | ||
from fanfan.config import TimepadConfig | ||
from fanfan.infrastructure.db import UnitOfWork | ||
from fanfan.infrastructure.scheduler import broker | ||
from fanfan.infrastructure.timepad.client import TimepadClient | ||
from fanfan.infrastructure.timepad.models import OrderStatus | ||
|
||
ORDERS_PER_REQUEST = 100 | ||
PARTICIPANT_NOMINATIONS = [ | ||
"Участник сценической программы", | ||
"Участник не сценических конкурсов", | ||
] | ||
|
||
logger = logging.getLogger("__name__") | ||
|
||
|
||
@broker.task(schedule=[{"cron": "0 * * * *"}], retry_on_error=True, max_retries=3) | ||
@inject | ||
async def update_tickets( | ||
client: FromDishka[TimepadClient], | ||
config: FromDishka[TimepadConfig], | ||
uow: FromDishka[UnitOfWork], | ||
) -> None: | ||
if not (config.client_id or config.event_id): | ||
logger.info( | ||
"TimePad client id or event id was not provided, skipping importing" | ||
) | ||
return None | ||
added_tickets, deleted_tickets = 0, 0 | ||
step = 0 | ||
service = TicketService(uow) | ||
init = await client.get_orders(config.event_id) | ||
logger.info(f"Tickets import started, about to process {init.total} orders") | ||
while step != math.ceil(init.total / ORDERS_PER_REQUEST): | ||
orders = await client.get_orders( | ||
config.event_id, limit=ORDERS_PER_REQUEST, skip=step * ORDERS_PER_REQUEST | ||
) | ||
for order in orders.values: | ||
if order.status.name in [ | ||
OrderStatus.PAID, | ||
OrderStatus.OK, | ||
OrderStatus.PAID_OFFLINE, | ||
OrderStatus.PAID_UR, | ||
]: | ||
for ticket in order.tickets: | ||
try: | ||
await service.create_ticket( | ||
ticket_id=ticket.number, | ||
role=UserRole.PARTICIPANT | ||
if ticket.ticket_type.name in PARTICIPANT_NOMINATIONS | ||
else UserRole.VISITOR, | ||
) | ||
added_tickets += 1 | ||
except TicketAlreadyExist: | ||
pass | ||
else: | ||
for ticket in order.tickets: | ||
try: | ||
await service.delete_ticket(ticket_id=ticket.number) | ||
deleted_tickets += 1 | ||
except TicketNotFound: | ||
pass | ||
logger.info( | ||
f"Ongoing import: {added_tickets} tickets added, {deleted_tickets} " | ||
f"tickets deleted" | ||
) | ||
await asyncio.sleep(3) | ||
step += 1 | ||
logger.info( | ||
f"Import done: {added_tickets} tickets added, {deleted_tickets} tickets deleted" | ||
) | ||
return None |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
from aiohttp import ClientSession | ||
from dataclass_rest import get | ||
from dataclass_rest.http.aiohttp import AiohttpClient | ||
|
||
from fanfan.infrastructure.timepad.models import RegistrationOrdersResponse | ||
|
||
TIMEPAD_API_BASE_URL = "https://api.timepad.ru/" | ||
|
||
|
||
class TimepadClient(AiohttpClient): | ||
def __init__(self, session: ClientSession): | ||
super().__init__(base_url=TIMEPAD_API_BASE_URL, session=session) | ||
|
||
@get("v1/events/{event_id}/orders") | ||
async def get_orders( | ||
self, | ||
event_id: int, | ||
limit: int = 10, | ||
skip: int = 0, | ||
) -> RegistrationOrdersResponse: | ||
pass |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
import enum | ||
from dataclasses import dataclass | ||
from typing import List | ||
|
||
|
||
class OrderStatus(enum.StrEnum): | ||
NOT_PAID = "notpaid" | ||
OK = "ok" | ||
PAID = "paid" | ||
INACTIVE = "inactive" | ||
DELETED = "deleted" | ||
BLOCKED = "blocked" | ||
RETURNED = "returned" | ||
BOOKED = "booked" | ||
PENDING = "pending" | ||
REJECTED = "rejected" | ||
BOOKED_OFFLINE = "booked_offline" | ||
PAID_OFFLINE = "paid_offline" | ||
PAID_UR = "paid_ur" | ||
TRANSFER_PAYMENT = "transfer_payment" | ||
RETURN_PAYMENT_REQUEST = "return_payment_request" | ||
RETURN_PAYMENT_REJECT = "return_payment_reject" | ||
RETURN_ORG = "return_org" | ||
RETURN_TP = "return_tp" | ||
|
||
|
||
@dataclass | ||
class TicketTypeResponse: | ||
name: str | ||
|
||
|
||
@dataclass | ||
class TicketResponse: | ||
number: str | ||
ticket_type: TicketTypeResponse | ||
|
||
|
||
@dataclass | ||
class OrderStatusResponse: | ||
name: OrderStatus | ||
title: str | ||
|
||
|
||
@dataclass | ||
class RegistrationOrderResponse: | ||
status: OrderStatusResponse | ||
tickets: List[TicketResponse] | ||
|
||
|
||
@dataclass | ||
class RegistrationOrdersResponse: | ||
total: int | ||
values: List[RegistrationOrderResponse] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.