From 6ea82857f21cac0e8b5ffff9736a7ea0cd93b5a6 Mon Sep 17 00:00:00 2001 From: Mark Veidemanis Date: Sat, 6 May 2023 11:52:42 +0100 Subject: [PATCH] Implement more payout management --- app/urls.py | 5 ++ core/management/commands/scheduling.py | 68 ++++++++++++++++++------ core/migrations/0038_payout_response.py | 18 +++++++ core/models.py | 2 + core/templates/partials/payout-list.html | 27 +++++++++- core/views/payouts.py | 26 ++++++++- 6 files changed, 128 insertions(+), 18 deletions(-) create mode 100644 core/migrations/0038_payout_response.py diff --git a/app/urls.py b/app/urls.py index 1aa78ef..87b6147 100644 --- a/app/urls.py +++ b/app/urls.py @@ -263,6 +263,11 @@ urlpatterns = [ payouts.PayoutDelete.as_view(), name="payout_delete", ), + path( + "payouts/action/delete_all/", + payouts.PayoutDeleteAll.as_view(), + name="payout_delete_all", + ), # Link groups path( "links//", diff --git a/core/management/commands/scheduling.py b/core/management/commands/scheduling.py index b5af9e1..f5fcc0e 100644 --- a/core/management/commands/scheduling.py +++ b/core/management/commands/scheduling.py @@ -8,7 +8,14 @@ from core.clients.aggregators.nordigen import NordigenClient from core.clients.platforms.agora import AgoraClient from core.lib.money import Money from core.lib.notify import sendmsg -from core.models import INTERVAL_CHOICES, Aggregator, LinkGroup, Platform, Requisition +from core.models import ( + INTERVAL_CHOICES, + Aggregator, + LinkGroup, + Payout, + Platform, + Requisition, +) from core.util import logs log = logs.get_logger("scheduling") @@ -29,6 +36,16 @@ async def withdrawal_job(group=None): checks = await money.check_all( link_group=group, nordigen=NordigenClient, agora=AgoraClient ) + + if checks["total_remaining"] > 0: + # More than 0 remaining, so we can't withdraw + await sendmsg( + group.user, + f"{checks['total_remaining']} left until you can withdraw.", + title="Balance update", + ) + continue + print("CHECKS", checks) aggregators = Aggregator.objects.filter( user=group.user, @@ -63,8 +80,10 @@ async def withdrawal_job(group=None): title="Your withdrawal is ready!", ) - if not checks["total_profit_in_xmr"] >= 0: - return + # TODO: UNCOMMENT + # COMMENTED FOR TESTING + # if not checks["total_profit_in_xmr"] >= 0: + # return total_withdrawal = sum(collapsed.values()) if checks["total_xmr_agora"] < total_withdrawal: @@ -84,21 +103,38 @@ async def withdrawal_job(group=None): # run = await AgoraClient(platform) otp_code = TOTP(platform.otp_token).now() - for wallet, amount in collapsed.items(): - print("ITER SEND", wallet, amount) - cast = { - "address": wallet.address, - "amount": amount, - "password": platform.password, - "otp": otp_code, - } + for wallet, pay_list_iter in pay_list.items(): + for amount, reason in pay_list_iter: + print("ITER", wallet, pay_list_iter) + print("ITER SENT", wallet, amount, reason) - print("CAST ADDRESS", cast["address"]) - print("CAST AMOUNT", cast["amount"]) - print("CAST OTP TRUNCATED BY 2", cast["otp"][-2]) + # for wallet, amount in collapsed.items(): + print("ITER SEND", wallet, amount) + cast = { + "address": wallet.address, + "amount": amount, + "password": platform.password, + "otp": otp_code, + } - # sent = await run.call("wallet_send_xmr", **cast) - # print("SENT", sent) + print("CAST ADDRESS", cast["address"]) + print("CAST AMOUNT", cast["amount"]) + print("CAST OTP TRUNCATED BY 2", cast["otp"][-2]) + + # TODO: UNCOMMENT + # sent = await run.call("wallet_send_xmr", **cast) + # print("SENT", sent) + + payout = Payout.objects.create( # noqa + user=group.user, + wallet=wallet, + amount=amount, + description=reason, + ) + + # TODO: UNCOMMENT + # payout.response = sent + # payout.save() async def aggregator_job(): diff --git a/core/migrations/0038_payout_response.py b/core/migrations/0038_payout_response.py new file mode 100644 index 0000000..3e345d7 --- /dev/null +++ b/core/migrations/0038_payout_response.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.7 on 2023-05-06 10:33 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0037_payout'), + ] + + operations = [ + migrations.AddField( + model_name='payout', + name='response', + field=models.JSONField(blank=True, default=dict, null=True), + ), + ] diff --git a/core/models.py b/core/models.py index 99fda56..b7bbd70 100644 --- a/core/models.py +++ b/core/models.py @@ -662,6 +662,8 @@ class Payout(models.Model): wallet = models.ForeignKey(Wallet, on_delete=models.CASCADE) amount = models.FloatField() description = models.CharField(max_length=255, null=True, blank=True) + response = models.JSONField(default=dict, null=True, blank=True) + ts = models.DateTimeField(auto_now_add=True) diff --git a/core/templates/partials/payout-list.html b/core/templates/partials/payout-list.html index 5b38f54..27c58e7 100644 --- a/core/templates/partials/payout-list.html +++ b/core/templates/partials/payout-list.html @@ -31,7 +31,32 @@ {{ item.user }} - {{ item.wallet }} + + + + + + {{ item.amount }} {{ item.description }} {{ item.ts }} diff --git a/core/views/payouts.py b/core/views/payouts.py index 2fcb39b..696d9d5 100644 --- a/core/views/payouts.py +++ b/core/views/payouts.py @@ -1,5 +1,13 @@ from django.contrib.auth.mixins import LoginRequiredMixin -from mixins.views import ObjectCreate, ObjectDelete, ObjectList, ObjectUpdate +from django.shortcuts import render +from django.views import View +from mixins.views import ( + ObjectCreate, + ObjectDelete, + ObjectList, + ObjectNameMixin, + ObjectUpdate, +) from two_factor.views.mixins import OTPRequiredMixin from core.forms import PayoutForm @@ -19,6 +27,7 @@ class PayoutList(LoginRequiredMixin, OTPRequiredMixin, ObjectList): list_url_args = ["type"] submit_url_name = "payout_create" + delete_all_url_name = "payout_delete_all" # def get_context_data(self): # context = super().get_context_data() @@ -80,3 +89,18 @@ class PayoutUpdate(LoginRequiredMixin, OTPRequiredMixin, ObjectUpdate): class PayoutDelete(LoginRequiredMixin, OTPRequiredMixin, ObjectDelete): model = Payout + + +class PayoutDeleteAll(LoginRequiredMixin, OTPRequiredMixin, ObjectNameMixin, View): + template_name = "mixins/partials/notify.html" + model = Payout + + def delete(self, request): + """ + Delete all payouts by the current user. + """ + Payout.objects.filter(user=request.user).delete() + context = {"message": "All payouts deleted", "class": "success"} + response = render(request, self.template_name, context) + response["HX-Trigger"] = f"{self.context_object_name_singular}Event" + return response