mirror of https://github.com/stijndcl/didier
Work on interest system
parent
a1345f9138
commit
de7b5cd960
|
@ -1,25 +1,29 @@
|
||||||
from datetime import date
|
from datetime import date
|
||||||
from typing import Optional, Union
|
from typing import List, Optional, Union
|
||||||
|
|
||||||
|
from sqlalchemy import select
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
from database.crud import users
|
from database.crud import users
|
||||||
from database.exceptions import currency as exceptions
|
from database.exceptions import currency as exceptions
|
||||||
from database.schemas import Bank, NightlyData
|
from database.schemas import Bank, BankSavings, NightlyData
|
||||||
from database.utils.math.currency import (
|
from database.utils.math.currency import (
|
||||||
capacity_upgrade_price,
|
capacity_upgrade_price,
|
||||||
|
interest_rate,
|
||||||
interest_upgrade_price,
|
interest_upgrade_price,
|
||||||
rob_upgrade_price,
|
rob_upgrade_price,
|
||||||
|
savings_cap,
|
||||||
)
|
)
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
"add_dinks",
|
"add_dinks",
|
||||||
|
"apply_daily_interest",
|
||||||
"claim_nightly",
|
"claim_nightly",
|
||||||
"deduct_dinks",
|
"deduct_dinks",
|
||||||
"gamble_dinks",
|
"gamble_dinks",
|
||||||
"get_bank",
|
"get_bank",
|
||||||
"get_nightly_data",
|
"get_nightly_data",
|
||||||
"invest",
|
"save",
|
||||||
"upgrade_capacity",
|
"upgrade_capacity",
|
||||||
"upgrade_interest",
|
"upgrade_interest",
|
||||||
"upgrade_rob",
|
"upgrade_rob",
|
||||||
|
@ -36,15 +40,30 @@ async def get_bank(session: AsyncSession, user_id: int) -> Bank:
|
||||||
return user.bank
|
return user.bank
|
||||||
|
|
||||||
|
|
||||||
|
async def get_savings(session: AsyncSession, user_id: int) -> BankSavings:
|
||||||
|
"""Get a user's savings info"""
|
||||||
|
user = await users.get_or_add_user(session, user_id)
|
||||||
|
return user.savings
|
||||||
|
|
||||||
|
|
||||||
async def get_nightly_data(session: AsyncSession, user_id: int) -> NightlyData:
|
async def get_nightly_data(session: AsyncSession, user_id: int) -> NightlyData:
|
||||||
"""Get a user's nightly info"""
|
"""Get a user's nightly info"""
|
||||||
user = await users.get_or_add_user(session, user_id)
|
user = await users.get_or_add_user(session, user_id)
|
||||||
return user.nightly_data
|
return user.nightly_data
|
||||||
|
|
||||||
|
|
||||||
async def invest(session: AsyncSession, user_id: int, amount: Union[str, int], *, bank: Optional[Bank] = None) -> int:
|
async def save(
|
||||||
|
session: AsyncSession,
|
||||||
|
user_id: int,
|
||||||
|
amount: Union[str, int],
|
||||||
|
*,
|
||||||
|
bank: Optional[Bank] = None,
|
||||||
|
savings: Optional[BankSavings] = None
|
||||||
|
) -> int:
|
||||||
"""Invest some of your Dinks"""
|
"""Invest some of your Dinks"""
|
||||||
bank = bank or await get_bank(session, user_id)
|
bank = bank or await get_bank(session, user_id)
|
||||||
|
savings = savings or await get_savings(session, user_id)
|
||||||
|
|
||||||
if amount == "all":
|
if amount == "all":
|
||||||
amount = bank.dinks
|
amount = bank.dinks
|
||||||
|
|
||||||
|
@ -54,29 +73,44 @@ async def invest(session: AsyncSession, user_id: int, amount: Union[str, int], *
|
||||||
# Don't allow investing more dinks than you own
|
# Don't allow investing more dinks than you own
|
||||||
amount = min(bank.dinks, int(amount))
|
amount = min(bank.dinks, int(amount))
|
||||||
|
|
||||||
|
# Don't allow exceeding the limit
|
||||||
|
limit = savings_cap(bank.capacity_level)
|
||||||
|
|
||||||
|
if savings.saved >= limit:
|
||||||
|
raise exceptions.SavingsCapExceeded
|
||||||
|
|
||||||
|
if savings.saved + amount > limit:
|
||||||
|
amount = max(0, limit - savings.saved)
|
||||||
|
|
||||||
bank.dinks -= amount
|
bank.dinks -= amount
|
||||||
bank.invested += amount
|
savings.saved += amount
|
||||||
|
|
||||||
session.add(bank)
|
session.add(bank)
|
||||||
|
session.add(savings)
|
||||||
await session.commit()
|
await session.commit()
|
||||||
|
|
||||||
return amount
|
return amount
|
||||||
|
|
||||||
|
|
||||||
async def withdraw(session: AsyncSession, user_id: int, amount: Union[str, int], *, bank: Optional[Bank] = None) -> int:
|
async def withdraw(session: AsyncSession, user_id: int, amount: Union[str, int], *, bank: Optional[Bank] = None) -> int:
|
||||||
"""Withdraw your invested Dinks"""
|
"""Withdraw your saved Dinks"""
|
||||||
bank = bank or await get_bank(session, user_id)
|
bank = bank or await get_bank(session, user_id)
|
||||||
|
savings = await get_savings(session, user_id)
|
||||||
|
|
||||||
if amount == "all":
|
if amount == "all":
|
||||||
amount = bank.invested
|
amount = savings.saved
|
||||||
|
|
||||||
# Don't allow withdrawing more dinks than you own
|
# Don't allow withdrawing more dinks than you own
|
||||||
amount = min(bank.invested, int(amount))
|
amount = min(savings.saved, int(amount))
|
||||||
|
|
||||||
bank.dinks += amount
|
bank.dinks += amount
|
||||||
bank.invested -= amount
|
savings.saved -= amount
|
||||||
|
savings.daily_minimum = min(savings.daily_minimum, savings.saved)
|
||||||
|
|
||||||
session.add(bank)
|
session.add(bank)
|
||||||
|
session.add(savings)
|
||||||
await session.commit()
|
await session.commit()
|
||||||
|
|
||||||
return amount
|
return amount
|
||||||
|
|
||||||
|
|
||||||
|
@ -218,3 +252,22 @@ async def rob(
|
||||||
session.add(robber)
|
session.add(robber)
|
||||||
session.add(robbed)
|
session.add(robbed)
|
||||||
await session.commit()
|
await session.commit()
|
||||||
|
|
||||||
|
|
||||||
|
async def apply_daily_interest(session: AsyncSession):
|
||||||
|
"""Apply daily interest rates to all accounts with saved Dinks"""
|
||||||
|
statement = select(BankSavings)
|
||||||
|
all_savings: List[BankSavings] = list((await session.execute(statement)).scalars().all())
|
||||||
|
|
||||||
|
for savings_account in all_savings:
|
||||||
|
if savings_account.saved == 0:
|
||||||
|
continue
|
||||||
|
|
||||||
|
bank = await get_bank(session, savings_account.user_id)
|
||||||
|
rate = interest_rate(bank.interest_level)
|
||||||
|
|
||||||
|
savings_account.saved = float(savings_account.saved * rate)
|
||||||
|
savings_account.daily_minimum = savings_account.saved
|
||||||
|
session.add(savings_account)
|
||||||
|
|
||||||
|
await session.commit()
|
||||||
|
|
|
@ -3,7 +3,7 @@ from typing import Optional
|
||||||
from sqlalchemy import select
|
from sqlalchemy import select
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
from database.schemas import Bank, NightlyData, User
|
from database.schemas import Bank, BankSavings, NightlyData, User
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
"get_or_add_user",
|
"get_or_add_user",
|
||||||
|
@ -37,8 +37,12 @@ async def get_or_add_user(session: AsyncSession, user_id: int, *, options: Optio
|
||||||
user.bank = bank
|
user.bank = bank
|
||||||
user.nightly_data = nightly_data
|
user.nightly_data = nightly_data
|
||||||
|
|
||||||
|
savings = BankSavings(user_id=user_id)
|
||||||
|
user.savings = savings
|
||||||
|
|
||||||
session.add(bank)
|
session.add(bank)
|
||||||
session.add(nightly_data)
|
session.add(nightly_data)
|
||||||
|
session.add(savings)
|
||||||
session.add(user)
|
session.add(user)
|
||||||
|
|
||||||
await session.commit()
|
await session.commit()
|
||||||
|
|
|
@ -7,3 +7,7 @@ class DoubleNightly(Exception):
|
||||||
|
|
||||||
class NotEnoughDinks(Exception):
|
class NotEnoughDinks(Exception):
|
||||||
"""Exception raised when trying to do something you don't have the Dinks for"""
|
"""Exception raised when trying to do something you don't have the Dinks for"""
|
||||||
|
|
||||||
|
|
||||||
|
class SavingsCapExceeded(Exception):
|
||||||
|
"""Exception raised when trying to save more Dinks than the cap allows"""
|
||||||
|
|
|
@ -12,6 +12,7 @@ from database import enums
|
||||||
__all__ = [
|
__all__ = [
|
||||||
"Base",
|
"Base",
|
||||||
"Bank",
|
"Bank",
|
||||||
|
"BankSavings",
|
||||||
"Birthday",
|
"Birthday",
|
||||||
"Bookmark",
|
"Bookmark",
|
||||||
"CommandStats",
|
"CommandStats",
|
||||||
|
@ -52,7 +53,6 @@ class Bank(Base):
|
||||||
user_id: Mapped[int] = mapped_column(BigInteger, ForeignKey("users.user_id"))
|
user_id: Mapped[int] = mapped_column(BigInteger, ForeignKey("users.user_id"))
|
||||||
|
|
||||||
dinks: Mapped[int] = mapped_column(BigInteger, server_default="0", nullable=False)
|
dinks: Mapped[int] = mapped_column(BigInteger, server_default="0", nullable=False)
|
||||||
invested: Mapped[int] = mapped_column(BigInteger, server_default="0", nullable=False)
|
|
||||||
|
|
||||||
# Interest rate
|
# Interest rate
|
||||||
interest_level: Mapped[int] = mapped_column(server_default="1", nullable=False)
|
interest_level: Mapped[int] = mapped_column(server_default="1", nullable=False)
|
||||||
|
@ -66,6 +66,20 @@ class Bank(Base):
|
||||||
user: Mapped[User] = relationship(uselist=False, back_populates="bank", lazy="selectin")
|
user: Mapped[User] = relationship(uselist=False, back_populates="bank", lazy="selectin")
|
||||||
|
|
||||||
|
|
||||||
|
class BankSavings(Base):
|
||||||
|
"""Savings information for a user's bank"""
|
||||||
|
|
||||||
|
__tablename__ = "savings"
|
||||||
|
|
||||||
|
savings_id: Mapped[int] = mapped_column(primary_key=True)
|
||||||
|
user_id: Mapped[int] = mapped_column(BigInteger, ForeignKey("users.user_id"))
|
||||||
|
|
||||||
|
saved: Mapped[int] = mapped_column(BigInteger, server_default="0", nullable=False)
|
||||||
|
daily_minimum: Mapped[int] = mapped_column(BigInteger, server_default="0", nullable=False)
|
||||||
|
|
||||||
|
user: Mapped[User] = relationship(uselist=False, back_populates="savings", lazy="selectin")
|
||||||
|
|
||||||
|
|
||||||
class Birthday(Base):
|
class Birthday(Base):
|
||||||
"""A user's birthday"""
|
"""A user's birthday"""
|
||||||
|
|
||||||
|
@ -350,3 +364,6 @@ class User(Base):
|
||||||
reminders: Mapped[List[Reminder]] = relationship(
|
reminders: Mapped[List[Reminder]] = relationship(
|
||||||
back_populates="user", uselist=True, lazy="selectin", cascade="all, delete-orphan"
|
back_populates="user", uselist=True, lazy="selectin", cascade="all, delete-orphan"
|
||||||
)
|
)
|
||||||
|
savings: Mapped[List[BankSavings]] = relationship(
|
||||||
|
back_populates="user", uselist=False, lazy="selectin", cascade="all, delete-orphan"
|
||||||
|
)
|
||||||
|
|
|
@ -4,6 +4,8 @@ __all__ = [
|
||||||
"capacity_upgrade_price",
|
"capacity_upgrade_price",
|
||||||
"interest_upgrade_price",
|
"interest_upgrade_price",
|
||||||
"rob_upgrade_price",
|
"rob_upgrade_price",
|
||||||
|
"interest_rate",
|
||||||
|
"savings_cap",
|
||||||
"jail_chance",
|
"jail_chance",
|
||||||
"jail_time",
|
"jail_time",
|
||||||
"rob_amount",
|
"rob_amount",
|
||||||
|
@ -16,7 +18,7 @@ def interest_upgrade_price(level: int) -> int:
|
||||||
base_cost = 600
|
base_cost = 600
|
||||||
growth_rate = 1.8
|
growth_rate = 1.8
|
||||||
|
|
||||||
return math.floor(base_cost * (growth_rate**level))
|
return math.floor(base_cost * (growth_rate ** (level - 1)))
|
||||||
|
|
||||||
|
|
||||||
def capacity_upgrade_price(level: int) -> int:
|
def capacity_upgrade_price(level: int) -> int:
|
||||||
|
@ -24,7 +26,7 @@ def capacity_upgrade_price(level: int) -> int:
|
||||||
base_cost = 800
|
base_cost = 800
|
||||||
growth_rate = 1.6
|
growth_rate = 1.6
|
||||||
|
|
||||||
return math.floor(base_cost * (growth_rate**level))
|
return math.floor(base_cost * (growth_rate ** (level - 1)))
|
||||||
|
|
||||||
|
|
||||||
def rob_upgrade_price(level: int) -> int:
|
def rob_upgrade_price(level: int) -> int:
|
||||||
|
@ -32,7 +34,23 @@ def rob_upgrade_price(level: int) -> int:
|
||||||
base_cost = 950
|
base_cost = 950
|
||||||
growth_rate = 1.9
|
growth_rate = 1.9
|
||||||
|
|
||||||
return math.floor(base_cost * (growth_rate**level))
|
return math.floor(base_cost * (growth_rate ** (level - 1)))
|
||||||
|
|
||||||
|
|
||||||
|
def interest_rate(level: int) -> float:
|
||||||
|
"""Calculate the amount of interest you will receive"""
|
||||||
|
base_rate = 1.025
|
||||||
|
growth_rate = 0.03
|
||||||
|
|
||||||
|
return base_rate + (growth_rate * (level - 1))
|
||||||
|
|
||||||
|
|
||||||
|
def savings_cap(level: int) -> int:
|
||||||
|
"""Calculate the maximum amount you can save"""
|
||||||
|
base_limit = 1000
|
||||||
|
growth_rate = 1.10
|
||||||
|
|
||||||
|
return math.floor(base_limit * (growth_rate ** (level - 1)))
|
||||||
|
|
||||||
|
|
||||||
def jail_chance(level: int) -> float:
|
def jail_chance(level: int) -> float:
|
||||||
|
|
|
@ -10,16 +10,23 @@ from discord.ext import commands
|
||||||
|
|
||||||
import settings
|
import settings
|
||||||
from database.crud import currency as crud
|
from database.crud import currency as crud
|
||||||
|
from database.crud import users
|
||||||
from database.crud.jail import get_user_jail, imprison
|
from database.crud.jail import get_user_jail, imprison
|
||||||
from database.exceptions.currency import DoubleNightly, NotEnoughDinks
|
from database.exceptions.currency import (
|
||||||
|
DoubleNightly,
|
||||||
|
NotEnoughDinks,
|
||||||
|
SavingsCapExceeded,
|
||||||
|
)
|
||||||
from database.utils.math.currency import (
|
from database.utils.math.currency import (
|
||||||
capacity_upgrade_price,
|
capacity_upgrade_price,
|
||||||
|
interest_rate,
|
||||||
interest_upgrade_price,
|
interest_upgrade_price,
|
||||||
jail_chance,
|
jail_chance,
|
||||||
jail_time,
|
jail_time,
|
||||||
rob_amount,
|
rob_amount,
|
||||||
rob_chance,
|
rob_chance,
|
||||||
rob_upgrade_price,
|
rob_upgrade_price,
|
||||||
|
savings_cap,
|
||||||
)
|
)
|
||||||
from didier import Didier
|
from didier import Didier
|
||||||
from didier.utils.discord import colours
|
from didier.utils.discord import colours
|
||||||
|
@ -51,17 +58,20 @@ class Currency(commands.Cog):
|
||||||
"""Award a user `amount` Didier Dinks."""
|
"""Award a user `amount` Didier Dinks."""
|
||||||
async with self.client.postgres_session as session:
|
async with self.client.postgres_session as session:
|
||||||
await crud.add_dinks(session, user.id, amount)
|
await crud.add_dinks(session, user.id, amount)
|
||||||
plural = pluralize("Didier Dink", amount)
|
|
||||||
await ctx.reply(
|
plural = pluralize("Didier Dink", amount)
|
||||||
f"{ctx.author.display_name} has awarded **{user.display_name}** with **{amount}** {plural}.",
|
await ctx.reply(
|
||||||
mention_author=False,
|
f"{ctx.author.display_name} has awarded **{user.display_name}** with **{amount}** {plural}.",
|
||||||
)
|
mention_author=False,
|
||||||
|
)
|
||||||
|
|
||||||
@commands.group(name="bank", aliases=["b"], case_insensitive=True, invoke_without_command=True)
|
@commands.group(name="bank", aliases=["b"], case_insensitive=True, invoke_without_command=True)
|
||||||
async def bank(self, ctx: commands.Context):
|
async def bank(self, ctx: commands.Context):
|
||||||
"""Show your Didier Bank information."""
|
"""Show your Didier Bank information."""
|
||||||
async with self.client.postgres_session as session:
|
async with self.client.postgres_session as session:
|
||||||
bank = await crud.get_bank(session, ctx.author.id)
|
user = await users.get_or_add_user(session, ctx.author.id)
|
||||||
|
bank = user.bank
|
||||||
|
savings = user.savings
|
||||||
|
|
||||||
embed = discord.Embed(title="Bank of Didier", colour=discord.Colour.blue())
|
embed = discord.Embed(title="Bank of Didier", colour=discord.Colour.blue())
|
||||||
embed.set_author(name=ctx.author.display_name)
|
embed.set_author(name=ctx.author.display_name)
|
||||||
|
@ -69,9 +79,10 @@ class Currency(commands.Cog):
|
||||||
if ctx.author.avatar is not None:
|
if ctx.author.avatar is not None:
|
||||||
embed.set_thumbnail(url=ctx.author.avatar.url)
|
embed.set_thumbnail(url=ctx.author.avatar.url)
|
||||||
|
|
||||||
embed.add_field(name="Interest level", value=bank.interest_level)
|
embed.add_field(name="Interest rate", value=round(interest_rate(bank.interest_level), 2))
|
||||||
embed.add_field(name="Capacity level", value=bank.capacity_level)
|
embed.add_field(name="Maximum capacity", value=round(savings_cap(bank.capacity_level), 2))
|
||||||
embed.add_field(name="Currently invested", value=bank.invested, inline=False)
|
embed.add_field(name="Currently saved", value=savings.saved, inline=False)
|
||||||
|
embed.add_field(name="Daily minimum", value=savings.daily_minimum, inline=False)
|
||||||
|
|
||||||
await ctx.reply(embed=embed, mention_author=False)
|
await ctx.reply(embed=embed, mention_author=False)
|
||||||
|
|
||||||
|
@ -135,52 +146,61 @@ class Currency(commands.Cog):
|
||||||
"""Check your Didier Dinks."""
|
"""Check your Didier Dinks."""
|
||||||
async with ctx.typing(), self.client.postgres_session as session:
|
async with ctx.typing(), self.client.postgres_session as session:
|
||||||
bank = await crud.get_bank(session, ctx.author.id)
|
bank = await crud.get_bank(session, ctx.author.id)
|
||||||
plural = pluralize("Didier Dink", bank.dinks)
|
|
||||||
await ctx.reply(f"You have **{bank.dinks}** {plural}.", mention_author=False)
|
|
||||||
|
|
||||||
@commands.command(name="invest", aliases=["deposit", "dep", "i"]) # type: ignore[arg-type]
|
plural = pluralize("Didier Dink", bank.dinks)
|
||||||
async def invest(self, ctx: commands.Context, amount: typing.Annotated[typing.Union[str, int], abbreviated_number]):
|
await ctx.reply(f"You have **{bank.dinks}** {plural}.", mention_author=False)
|
||||||
"""Invest `amount` Didier Dinks into your bank.
|
|
||||||
|
@commands.command(name="save", aliases=["deposit", "dep", "s"]) # type: ignore[arg-type]
|
||||||
|
async def save(self, ctx: commands.Context, amount: typing.Annotated[typing.Union[str, int], abbreviated_number]):
|
||||||
|
"""Add `amount` Didier Dinks into your bank's savings account.
|
||||||
|
|
||||||
The `amount`-argument can take both raw numbers, and abbreviations of big numbers. Additionally, passing
|
The `amount`-argument can take both raw numbers, and abbreviations of big numbers. Additionally, passing
|
||||||
`all` or `*` as the value will invest all of your Didier Dinks.
|
`all` or `*` as the value will invest all of your Didier Dinks.
|
||||||
|
|
||||||
Example usage:
|
Example usage:
|
||||||
```
|
```
|
||||||
didier invest all
|
didier save all
|
||||||
didier invest 500
|
didier save 500
|
||||||
didier invest 25k
|
didier save 25k
|
||||||
didier invest 5.3b
|
didier save 5.3b
|
||||||
```
|
```
|
||||||
"""
|
"""
|
||||||
if isinstance(amount, int) and amount <= 0:
|
if isinstance(amount, int) and amount <= 0:
|
||||||
return await ctx.reply("Amount of Didier Dinks to invest must be a strictly positive integer.")
|
return await ctx.reply("Amount of Didier Dinks to invest must be a strictly positive integer.")
|
||||||
|
|
||||||
async with self.client.postgres_session as session:
|
async with self.client.postgres_session as session:
|
||||||
invested = await crud.invest(session, ctx.author.id, amount)
|
try:
|
||||||
plural = pluralize("Didier Dink", invested)
|
saved = await crud.save(session, ctx.author.id, amount)
|
||||||
|
except SavingsCapExceeded:
|
||||||
|
return await ctx.reply(
|
||||||
|
"You have already exceeded the savings cap for your level. Upgrade your bank's capacity to save "
|
||||||
|
"more."
|
||||||
|
)
|
||||||
|
|
||||||
if invested == 0:
|
plural = pluralize("Didier Dink", saved)
|
||||||
await ctx.reply("You don't have any Didier Dinks to invest.", mention_author=False)
|
|
||||||
else:
|
|
||||||
await ctx.reply(f"You have invested **{invested}** {plural}.", mention_author=False)
|
|
||||||
|
|
||||||
@commands.command(name="withdraw", aliases=["uninvest", "w"]) # type: ignore[arg-type]
|
if saved == 0:
|
||||||
|
await ctx.reply("You don't have any Didier Dinks to invest.", mention_author=False)
|
||||||
|
else:
|
||||||
|
await ctx.reply(f"You have saved **{saved}** {plural}.", mention_author=False)
|
||||||
|
|
||||||
|
@commands.command(name="withdraw", aliases=["undeposit", "unsave", "w"]) # type: ignore[arg-type]
|
||||||
async def withdraw(
|
async def withdraw(
|
||||||
self, ctx: commands.Context, amount: typing.Annotated[typing.Union[str, int], abbreviated_number]
|
self, ctx: commands.Context, amount: typing.Annotated[typing.Union[str, int], abbreviated_number]
|
||||||
):
|
):
|
||||||
"""Withdraw some of your invested Didier Dinks from your bank."""
|
"""Withdraw some of your Didier Dinks from your bank's savings account."""
|
||||||
if isinstance(amount, int) and amount <= 0:
|
if isinstance(amount, int) and amount <= 0:
|
||||||
return await ctx.reply("Amount of Didier Dinks to invest must be a strictly positive integer.")
|
return await ctx.reply("Amount of Didier Dinks to invest must be a strictly positive integer.")
|
||||||
|
|
||||||
async with self.client.postgres_session as session:
|
async with self.client.postgres_session as session:
|
||||||
withdrawn = await crud.withdraw(session, ctx.author.id, amount)
|
withdrawn = await crud.withdraw(session, ctx.author.id, amount)
|
||||||
plural = pluralize("Didier Dink", withdrawn)
|
|
||||||
|
|
||||||
if withdrawn == 0:
|
plural = pluralize("Didier Dink", withdrawn)
|
||||||
await ctx.reply("You don't have any Didier Dinks to withdraw.", mention_author=False)
|
|
||||||
else:
|
if withdrawn == 0:
|
||||||
await ctx.reply(f"You have withdrawn **{withdrawn}** {plural}.", mention_author=False)
|
await ctx.reply("You don't have any Didier Dinks to withdraw.", mention_author=False)
|
||||||
|
else:
|
||||||
|
await ctx.reply(f"You have withdrawn **{withdrawn}** {plural}.", mention_author=False)
|
||||||
|
|
||||||
@commands.hybrid_command(name="nightly") # type: ignore[arg-type]
|
@commands.hybrid_command(name="nightly") # type: ignore[arg-type]
|
||||||
async def nightly(self, ctx: commands.Context):
|
async def nightly(self, ctx: commands.Context):
|
||||||
|
|
|
@ -10,6 +10,7 @@ from overrides import overrides
|
||||||
import settings
|
import settings
|
||||||
from database import enums
|
from database import enums
|
||||||
from database.crud.birthdays import get_birthdays_on_day
|
from database.crud.birthdays import get_birthdays_on_day
|
||||||
|
from database.crud.currency import apply_daily_interest
|
||||||
from database.crud.reminders import get_all_reminders_for_category
|
from database.crud.reminders import get_all_reminders_for_category
|
||||||
from database.crud.ufora_announcements import remove_old_announcements
|
from database.crud.ufora_announcements import remove_old_announcements
|
||||||
from database.schemas import Reminder
|
from database.schemas import Reminder
|
||||||
|
@ -77,6 +78,7 @@ class Tasks(commands.Cog):
|
||||||
|
|
||||||
# Start other tasks
|
# Start other tasks
|
||||||
self.reminders.start()
|
self.reminders.start()
|
||||||
|
self.daily_interest.start()
|
||||||
asyncio.create_task(self.get_error_channel())
|
asyncio.create_task(self.get_error_channel())
|
||||||
|
|
||||||
@overrides
|
@overrides
|
||||||
|
@ -318,11 +320,18 @@ class Tasks(commands.Cog):
|
||||||
async with self.client.postgres_session as session:
|
async with self.client.postgres_session as session:
|
||||||
await remove_old_announcements(session)
|
await remove_old_announcements(session)
|
||||||
|
|
||||||
|
@tasks.loop(time=DAILY_RESET_TIME)
|
||||||
|
async def daily_interest(self):
|
||||||
|
"""Give everyone's daily interest"""
|
||||||
|
async with self.client.postgres_session as session:
|
||||||
|
await apply_daily_interest(session)
|
||||||
|
|
||||||
@check_birthdays.error
|
@check_birthdays.error
|
||||||
@pull_schedules.error
|
@pull_schedules.error
|
||||||
@pull_ufora_announcements.error
|
@pull_ufora_announcements.error
|
||||||
@reminders.error
|
@reminders.error
|
||||||
@remove_old_ufora_announcements.error
|
@remove_old_ufora_announcements.error
|
||||||
|
@daily_interest.error
|
||||||
async def _on_tasks_error(self, error: BaseException):
|
async def _on_tasks_error(self, error: BaseException):
|
||||||
"""Error handler for all tasks"""
|
"""Error handler for all tasks"""
|
||||||
self.client.dispatch("task_error", error)
|
self.client.dispatch("task_error", error)
|
||||||
|
|
|
@ -6,6 +6,7 @@ from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
from database.crud import users
|
from database.crud import users
|
||||||
from database.schemas import (
|
from database.schemas import (
|
||||||
Bank,
|
Bank,
|
||||||
|
BankSavings,
|
||||||
UforaAnnouncement,
|
UforaAnnouncement,
|
||||||
UforaCourse,
|
UforaCourse,
|
||||||
UforaCourseAlias,
|
UforaCourseAlias,
|
||||||
|
@ -38,6 +39,14 @@ async def bank(postgres: AsyncSession, user: User) -> Bank:
|
||||||
return _bank
|
return _bank
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
async def savings(postgres: AsyncSession, user: User) -> BankSavings:
|
||||||
|
"""Fixture to fetch the test user's savings account"""
|
||||||
|
_savings = user.savings
|
||||||
|
await postgres.refresh(_savings)
|
||||||
|
return _savings
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
async def ufora_course(postgres: AsyncSession) -> UforaCourse:
|
async def ufora_course(postgres: AsyncSession) -> UforaCourse:
|
||||||
"""Fixture to create a course"""
|
"""Fixture to create a course"""
|
||||||
|
|
|
@ -6,7 +6,7 @@ from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
from database.crud import currency as crud
|
from database.crud import currency as crud
|
||||||
from database.exceptions import currency as exceptions
|
from database.exceptions import currency as exceptions
|
||||||
from database.schemas import Bank
|
from database.schemas import Bank, BankSavings
|
||||||
|
|
||||||
|
|
||||||
async def test_add_dinks(postgres: AsyncSession, bank: Bank):
|
async def test_add_dinks(postgres: AsyncSession, bank: Bank):
|
||||||
|
@ -40,40 +40,43 @@ async def test_claim_nightly_unavailable(postgres: AsyncSession, bank: Bank):
|
||||||
assert bank.dinks == crud.NIGHTLY_AMOUNT
|
assert bank.dinks == crud.NIGHTLY_AMOUNT
|
||||||
|
|
||||||
|
|
||||||
async def test_invest(postgres: AsyncSession, bank: Bank):
|
async def test_save(postgres: AsyncSession, bank: Bank, savings: BankSavings):
|
||||||
"""Test investing some Dinks"""
|
"""Test saving some Dinks"""
|
||||||
bank.dinks = 100
|
bank.dinks = 100
|
||||||
postgres.add(bank)
|
postgres.add(bank)
|
||||||
await postgres.commit()
|
await postgres.commit()
|
||||||
|
|
||||||
await crud.invest(postgres, bank.user_id, 20)
|
await crud.save(postgres, bank.user_id, 20, bank=bank, savings=savings)
|
||||||
await postgres.refresh(bank)
|
await postgres.refresh(bank)
|
||||||
|
await postgres.refresh(savings)
|
||||||
|
|
||||||
assert bank.dinks == 80
|
assert bank.dinks == 80
|
||||||
assert bank.invested == 20
|
assert savings.saved == 20
|
||||||
|
|
||||||
|
|
||||||
async def test_invest_all(postgres: AsyncSession, bank: Bank):
|
async def test_save_all(postgres: AsyncSession, bank: Bank, savings: BankSavings):
|
||||||
"""Test investing all dinks"""
|
"""Test saving all dinks"""
|
||||||
bank.dinks = 100
|
bank.dinks = 100
|
||||||
postgres.add(bank)
|
postgres.add(bank)
|
||||||
await postgres.commit()
|
await postgres.commit()
|
||||||
|
|
||||||
await crud.invest(postgres, bank.user_id, "all")
|
await crud.save(postgres, bank.user_id, "all", bank=bank, savings=savings)
|
||||||
await postgres.refresh(bank)
|
await postgres.refresh(bank)
|
||||||
|
await postgres.refresh(savings)
|
||||||
|
|
||||||
assert bank.dinks == 0
|
assert bank.dinks == 0
|
||||||
assert bank.invested == 100
|
assert savings.saved == 100
|
||||||
|
|
||||||
|
|
||||||
async def test_invest_more_than_owned(postgres: AsyncSession, bank: Bank):
|
async def test_save_more_than_owned(postgres: AsyncSession, bank: Bank, savings: BankSavings):
|
||||||
"""Test investing more Dinks than you own"""
|
"""Test saving more Dinks than you own"""
|
||||||
bank.dinks = 100
|
bank.dinks = 100
|
||||||
postgres.add(bank)
|
postgres.add(bank)
|
||||||
await postgres.commit()
|
await postgres.commit()
|
||||||
|
|
||||||
await crud.invest(postgres, bank.user_id, 200)
|
await crud.save(postgres, bank.user_id, 200, bank=bank, savings=savings)
|
||||||
await postgres.refresh(bank)
|
await postgres.refresh(bank)
|
||||||
|
await postgres.refresh(savings)
|
||||||
|
|
||||||
assert bank.dinks == 0
|
assert bank.dinks == 0
|
||||||
assert bank.invested == 100
|
assert savings.saved == 100
|
||||||
|
|
Loading…
Reference in New Issue