104 lines
3.1 KiB
Python
104 lines
3.1 KiB
Python
import logging
|
|
import datetime
|
|
import pytz
|
|
|
|
from scheduler.asyncio import Scheduler
|
|
|
|
from settings import TIMEZONE, SCHEDULE_SYNC_INTERVAL
|
|
from orders import order_issue, order_check
|
|
from db.queries import orders_pool_by_id, orders_pool_scheduled, orders_pool_since, skip_day_contains, order_status_outstanding
|
|
from util import order_time, sqlite_time
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
WEEKDAYS = [0, 1, 2, 3, 4]
|
|
WEEKENDS = [5, 6]
|
|
|
|
GRACE_PERIOD = datetime.timedelta(seconds=10)
|
|
|
|
class OrderScheduler():
|
|
def __init__(self, loop):
|
|
self.tz = pytz.timezone(TIMEZONE)
|
|
|
|
self.scheduler = Scheduler(loop=loop, tzinfo=self.tz)
|
|
|
|
self.scheduled_pools = {}
|
|
for orders_pool in orders_pool_scheduled():
|
|
self.schedule_pool(orders_pool)
|
|
|
|
for order_status in order_status_outstanding():
|
|
self.scheduler.once(
|
|
datetime.datetime.fromisoformat(order_status.due_at) + GRACE_PERIOD,
|
|
self.scheduled_check,
|
|
args=(order_status.id,)
|
|
)
|
|
|
|
self.last_update = datetime.datetime.now(datetime.UTC)
|
|
self.scheduler.cyclic(
|
|
datetime.timedelta(seconds=SCHEDULE_SYNC_INTERVAL),
|
|
self.update_schedule
|
|
)
|
|
|
|
logger.info(self.scheduler)
|
|
|
|
def schedule_pool(self, orders_pool):
|
|
if orders_pool.id in self.scheduled_pools:
|
|
self.scheduler.delete_job(self.scheduled_pools[orders_pool.id])
|
|
del self.scheduled_pools[orders_pool.id]
|
|
|
|
if orders_pool.scheduled:
|
|
self.scheduled_pools[orders_pool.id] = self.scheduler.daily(
|
|
[order_time(t) for t in orders_pool.time.split(",")],
|
|
self.scheduled_order,
|
|
args=(orders_pool.id,)
|
|
)
|
|
|
|
async def scheduled_order(self, orders_pool_id):
|
|
orders_pool = orders_pool_by_id(orders_pool_id)
|
|
|
|
# Skip weekends or weekdays
|
|
day_of_week = datetime.datetime.now(tz=self.tz).weekday()
|
|
if (
|
|
(not orders_pool.weekends and day_of_week in WEEKENDS)
|
|
or
|
|
(not orders_pool.weekdays and day_of_week in WEEKDAYS)
|
|
):
|
|
logger.info(f'{orders_pool.name}[{orders_pool.user.telegram_username}] Not scheduled for today')
|
|
return
|
|
|
|
# Skip stored dates
|
|
today = datetime.datetime.now(tz=self.tz).strftime("%Y-%m-%d")
|
|
logger.info('Today %s' % today)
|
|
if (skip_day_contains(orders_pool.user, today)):
|
|
logger.info('Today is a skip day')
|
|
return
|
|
|
|
logger.info(f'Issuing order for {orders_pool.name}[{orders_pool.user.telegram_username}]')
|
|
|
|
order_status = await order_issue(orders_pool)
|
|
|
|
if order_status is not None:
|
|
# Schedule check
|
|
self.scheduler.once(
|
|
order_status.due_at + GRACE_PERIOD,
|
|
self.scheduled_check,
|
|
args=(order_status.id,)
|
|
)
|
|
|
|
async def scheduled_check(self, outstanding_order_id):
|
|
await order_check(outstanding_order_id)
|
|
|
|
async def update_schedule(self):
|
|
last_update_sqlite = sqlite_time(self.last_update)
|
|
|
|
updated = False
|
|
|
|
for orders_pool_updated in orders_pool_since(last_update_sqlite):
|
|
logger.info(f'Updating schedule for {orders_pool_updated}')
|
|
self.schedule_pool(orders_pool_updated)
|
|
updated = True
|
|
|
|
if updated:
|
|
logger.info(self.scheduler)
|
|
|
|
self.last_update = datetime.datetime.now(datetime.UTC)
|