Store status notifications

This commit is contained in:
koalasat 2024-08-26 15:49:03 +02:00
parent 705c928b9c
commit 4f2ec020a9
No known key found for this signature in database
GPG Key ID: 2F7F61C6146AB157
14 changed files with 189 additions and 151 deletions

View File

@ -11,7 +11,6 @@ from rest_framework.authtoken.models import TokenProxy
from api.logics import Logics from api.logics import Logics
from api.models import Currency, LNPayment, MarketTick, OnchainPayment, Order, Robot from api.models import Currency, LNPayment, MarketTick, OnchainPayment, Order, Robot
from api.utils import objects_to_hyperlinks from api.utils import objects_to_hyperlinks
from api.tasks import send_notification
admin.site.unregister(Group) admin.site.unregister(Group)
admin.site.unregister(User) admin.site.unregister(User)
@ -164,9 +163,6 @@ class OrderAdmin(AdminChangeLinksMixin, admin.ModelAdmin):
f"Order {order.id} successfully closed", f"Order {order.id} successfully closed",
messages.SUCCESS, messages.SUCCESS,
) )
send_notification.delay(
order_id=order.id, message="coordinator_cancelled"
)
else: else:
self.message_user( self.message_user(
request, request,
@ -210,7 +206,6 @@ class OrderAdmin(AdminChangeLinksMixin, admin.ModelAdmin):
f"Dispute of order {order.id} solved successfully on favor of the maker", f"Dispute of order {order.id} solved successfully on favor of the maker",
messages.SUCCESS, messages.SUCCESS,
) )
send_notification.delay(order_id=order.id, message="dispute_closed")
else: else:
self.message_user( self.message_user(
@ -249,7 +244,6 @@ class OrderAdmin(AdminChangeLinksMixin, admin.ModelAdmin):
f"Dispute of order {order.id} solved successfully on favor of the taker", f"Dispute of order {order.id} solved successfully on favor of the taker",
messages.SUCCESS, messages.SUCCESS,
) )
send_notification.delay(order_id=order.id, message="dispute_closed")
else: else:
self.message_user( self.message_user(

View File

@ -617,10 +617,10 @@ class CLNNode:
] ]
) )
order.update_status(Order.Status.FAI)
order.expires_at = timezone.now() + timedelta( order.expires_at = timezone.now() + timedelta(
seconds=order.t_to_expire(Order.Status.FAI) seconds=order.t_to_expire(Order.Status.FAI)
) )
order.update_status(Order.Status.FAI)
order.save(update_fields=["expires_at"]) order.save(update_fields=["expires_at"])
print( print(
@ -646,10 +646,10 @@ class CLNNode:
) )
lnpayment.preimage = response.payment_preimage.hex() lnpayment.preimage = response.payment_preimage.hex()
lnpayment.save(update_fields=["status", "fee", "preimage"]) lnpayment.save(update_fields=["status", "fee", "preimage"])
order.update_status(Order.Status.SUC)
order.expires_at = timezone.now() + timedelta( order.expires_at = timezone.now() + timedelta(
seconds=order.t_to_expire(Order.Status.SUC) seconds=order.t_to_expire(Order.Status.SUC)
) )
order.update_status(Order.Status.SUC)
order.save(update_fields=["expires_at"]) order.save(update_fields=["expires_at"])
order.log( order.log(
@ -697,10 +697,10 @@ class CLNNode:
] ]
) )
order.update_status(Order.Status.FAI)
order.expires_at = timezone.now() + timedelta( order.expires_at = timezone.now() + timedelta(
seconds=order.t_to_expire(Order.Status.FAI) seconds=order.t_to_expire(Order.Status.FAI)
) )
order.update_status(Order.Status.FAI)
order.save(update_fields=["expires_at"]) order.save(update_fields=["expires_at"])
print( print(
@ -737,10 +737,10 @@ class CLNNode:
"in_flight", "in_flight",
] ]
) )
order.update_status(Order.Status.FAI)
order.expires_at = timezone.now() + timedelta( order.expires_at = timezone.now() + timedelta(
seconds=order.t_to_expire(Order.Status.FAI) seconds=order.t_to_expire(Order.Status.FAI)
) )
order.update_status(Order.Status.FAI)
order.save(update_fields=["expires_at"]) order.save(update_fields=["expires_at"])
order.log( order.log(

View File

@ -594,11 +594,10 @@ class LNDNode:
] ]
) )
order.update_status(Order.Status.FAI)
order.expires_at = timezone.now() + timedelta( order.expires_at = timezone.now() + timedelta(
seconds=order.t_to_expire(Order.Status.FAI) seconds=order.t_to_expire(Order.Status.FAI)
) )
order.update_status(Order.Status.FAI)
order.save(update_fields=["expires_at"]) order.save(update_fields=["expires_at"])
str_failure_reason = cls.payment_failure_context[ str_failure_reason = cls.payment_failure_context[
@ -625,10 +624,10 @@ class LNDNode:
lnpayment.preimage = response.payment_preimage lnpayment.preimage = response.payment_preimage
lnpayment.save(update_fields=["status", "fee", "preimage"]) lnpayment.save(update_fields=["status", "fee", "preimage"])
order.update_status(Order.Status.SUC)
order.expires_at = timezone.now() + timedelta( order.expires_at = timezone.now() + timedelta(
seconds=order.t_to_expire(Order.Status.SUC) seconds=order.t_to_expire(Order.Status.SUC)
) )
order.update_status(Order.Status.SUC)
order.save(update_fields=["expires_at"]) order.save(update_fields=["expires_at"])
order.log( order.log(
@ -671,10 +670,10 @@ class LNDNode:
update_fields=["status", "last_routing_time", "in_flight"] update_fields=["status", "last_routing_time", "in_flight"]
) )
order.update_status(Order.Status.FAI)
order.expires_at = timezone.now() + timedelta( order.expires_at = timezone.now() + timedelta(
seconds=order.t_to_expire(Order.Status.FAI) seconds=order.t_to_expire(Order.Status.FAI)
) )
order.update_status(Order.Status.FAI)
order.save(update_fields=["expires_at"]) order.save(update_fields=["expires_at"])
order.log( order.log(

View File

@ -8,7 +8,7 @@ from django.utils import timezone
from api.lightning.node import LNNode from api.lightning.node import LNNode
from api.models import Currency, LNPayment, MarketTick, OnchainPayment, Order from api.models import Currency, LNPayment, MarketTick, OnchainPayment, Order
from api.tasks import send_devfund_donation, send_notification, nostr_send_order_event from api.tasks import send_devfund_donation, send_status_notification, send_notification, nostr_send_order_event
from api.utils import get_minning_fee, validate_onchain_address, location_country from api.utils import get_minning_fee, validate_onchain_address, location_country
from chat.models import Message from chat.models import Message
@ -180,10 +180,10 @@ class Logics:
if order.has_range: if order.has_range:
order.amount = amount order.amount = amount
order.taker = user order.taker = user
order.update_status(Order.Status.TAK)
order.expires_at = timezone.now() + timedelta( order.expires_at = timezone.now() + timedelta(
seconds=order.t_to_expire(Order.Status.TAK) seconds=order.t_to_expire(Order.Status.TAK)
) )
order.update_status(Order.Status.TAK)
order.save(update_fields=["amount", "taker", "expires_at"]) order.save(update_fields=["amount", "taker", "expires_at"])
order.log( order.log(
f"Taken by Robot({user.robot.id},{user.username}) for {order.amount} fiat units" f"Taken by Robot({user.robot.id},{user.username}) for {order.amount} fiat units"
@ -267,9 +267,9 @@ class Logics:
return False return False
elif order.status == Order.Status.WFB: elif order.status == Order.Status.WFB:
order.update_status(Order.Status.EXP)
order.expiry_reason = Order.ExpiryReasons.NMBOND order.expiry_reason = Order.ExpiryReasons.NMBOND
cls.cancel_bond(order.maker_bond) cls.cancel_bond(order.maker_bond)
order.update_status(Order.Status.EXP)
order.save(update_fields=["expiry_reason"]) order.save(update_fields=["expiry_reason"])
order.log("Order expired while waiting for maker bond") order.log("Order expired while waiting for maker bond")
@ -279,10 +279,9 @@ class Logics:
elif order.status in [Order.Status.PUB, Order.Status.PAU]: elif order.status in [Order.Status.PUB, Order.Status.PAU]:
cls.return_bond(order.maker_bond) cls.return_bond(order.maker_bond)
order.update_status(Order.Status.EXP)
order.expiry_reason = Order.ExpiryReasons.NTAKEN order.expiry_reason = Order.ExpiryReasons.NTAKEN
order.save(update_fields=["expiry_reason"]) order.save(update_fields=["expiry_reason"])
send_notification.delay(order_id=order.id, message="order_expired_untaken") order.update_status(Order.Status.EXP)
order.log("Order expired while public or paused") order.log("Order expired while public or paused")
order.log("Maker bond was <b>unlocked</b>") order.log("Maker bond was <b>unlocked</b>")
@ -307,8 +306,8 @@ class Logics:
cls.settle_bond(order.maker_bond) cls.settle_bond(order.maker_bond)
cls.settle_bond(order.taker_bond) cls.settle_bond(order.taker_bond)
cls.cancel_escrow(order) cls.cancel_escrow(order)
order.update_status(Order.Status.EXP)
order.expiry_reason = Order.ExpiryReasons.NESINV order.expiry_reason = Order.ExpiryReasons.NESINV
order.update_status(Order.Status.EXP)
order.save(update_fields=["expiry_reason"]) order.save(update_fields=["expiry_reason"])
order.log( order.log(
@ -330,8 +329,8 @@ class Logics:
cls.cancel_escrow(order) cls.cancel_escrow(order)
except Exception: except Exception:
pass pass
order.update_status(Order.Status.EXP)
order.expiry_reason = Order.ExpiryReasons.NESCRO order.expiry_reason = Order.ExpiryReasons.NESCRO
order.update_status(Order.Status.EXP)
order.save(update_fields=["expiry_reason"]) order.save(update_fields=["expiry_reason"])
# Reward taker with part of the maker bond # Reward taker with part of the maker bond
cls.add_slashed_rewards(order, order.maker_bond, order.taker_bond) cls.add_slashed_rewards(order, order.maker_bond, order.taker_bond)
@ -352,7 +351,9 @@ class Logics:
pass pass
taker_bond = order.taker_bond taker_bond = order.taker_bond
cls.publish_order(order) cls.publish_order(order)
send_notification.delay(order_id=order.id, message="order_published") send_status_notification.delay(
order_id=order.id, status=Order.Status.PUB
)
# Reward maker with part of the taker bond # Reward maker with part of the taker bond
cls.add_slashed_rewards(order, taker_bond, order.maker_bond) cls.add_slashed_rewards(order, taker_bond, order.maker_bond)
@ -371,8 +372,8 @@ class Logics:
cls.settle_bond(order.maker_bond) cls.settle_bond(order.maker_bond)
cls.return_bond(order.taker_bond) cls.return_bond(order.taker_bond)
cls.return_escrow(order) cls.return_escrow(order)
order.update_status(Order.Status.EXP)
order.expiry_reason = Order.ExpiryReasons.NINVOI order.expiry_reason = Order.ExpiryReasons.NINVOI
order.update_status(Order.Status.EXP)
order.save(update_fields=["expiry_reason"]) order.save(update_fields=["expiry_reason"])
# Reward taker with part of the maker bond # Reward taker with part of the maker bond
cls.add_slashed_rewards(order, order.maker_bond, order.taker_bond) cls.add_slashed_rewards(order, order.maker_bond, order.taker_bond)
@ -389,7 +390,9 @@ class Logics:
cls.return_escrow(order) cls.return_escrow(order)
taker_bond = order.taker_bond taker_bond = order.taker_bond
cls.publish_order(order) cls.publish_order(order)
send_notification.delay(order_id=order.id, message="order_published") send_status_notification.delay(
order_id=order.id, status=Order.Status.PUB
)
# Reward maker with part of the taker bond # Reward maker with part of the taker bond
cls.add_slashed_rewards(order, taker_bond, order.maker_bond) cls.add_slashed_rewards(order, taker_bond, order.maker_bond)
@ -498,7 +501,6 @@ class Logics:
seconds=order.t_to_expire(Order.Status.DIS) seconds=order.t_to_expire(Order.Status.DIS)
) )
order.save(update_fields=["is_disputed", "expires_at"]) order.save(update_fields=["is_disputed", "expires_at"])
send_notification.delay(order_id=order.id, message="dispute_opened")
return True return True
@ -530,10 +532,10 @@ class Logics:
cls.settle_bond(order.taker_bond) cls.settle_bond(order.taker_bond)
order.is_disputed = True order.is_disputed = True
order.update_status(Order.Status.DIS)
order.expires_at = timezone.now() + timedelta( order.expires_at = timezone.now() + timedelta(
seconds=order.t_to_expire(Order.Status.DIS) seconds=order.t_to_expire(Order.Status.DIS)
) )
order.update_status(Order.Status.DIS)
order.save(update_fields=["is_disputed", "expires_at"]) order.save(update_fields=["is_disputed", "expires_at"])
# User could be None if a dispute is open automatically due to time expiration. # User could be None if a dispute is open automatically due to time expiration.
@ -548,7 +550,6 @@ class Logics:
).append(str(order.id)) ).append(str(order.id))
robot.save(update_fields=["num_disputes", "orders_disputes_started"]) robot.save(update_fields=["num_disputes", "orders_disputes_started"])
send_notification.delay(order_id=order.id, message="dispute_opened")
order.log( order.log(
f"Dispute was opened {f'by Robot({user.robot.id},{user.username})' if user else ''}" f"Dispute was opened {f'by Robot({user.robot.id},{user.username})' if user else ''}"
) )
@ -587,10 +588,10 @@ class Logics:
None, None,
"", "",
]: ]:
order.update_status(Order.Status.WFR)
order.expires_at = timezone.now() + timedelta( order.expires_at = timezone.now() + timedelta(
seconds=order.t_to_expire(Order.Status.WFR) seconds=order.t_to_expire(Order.Status.WFR)
) )
order.update_status(Order.Status.WFR)
order.save(update_fields=["status", "expires_at"]) order.save(update_fields=["status", "expires_at"])
order.log( order.log(
@ -944,11 +945,10 @@ class Logics:
def move_state_updated_payout_method(cls, order): def move_state_updated_payout_method(cls, order):
# If the order status is 'Waiting for invoice'. Move forward to 'chat' # If the order status is 'Waiting for invoice'. Move forward to 'chat'
if order.status == Order.Status.WFI: if order.status == Order.Status.WFI:
order.update_status(Order.Status.CHA)
order.expires_at = timezone.now() + timedelta( order.expires_at = timezone.now() + timedelta(
seconds=order.t_to_expire(Order.Status.CHA) seconds=order.t_to_expire(Order.Status.CHA)
) )
send_notification.delay(order_id=order.id, message="fiat_exchange_starts") order.update_status(Order.Status.CHA)
# If the order status is 'Waiting for both'. Move forward to 'waiting for escrow' # If the order status is 'Waiting for both'. Move forward to 'waiting for escrow'
elif order.status == Order.Status.WF2: elif order.status == Order.Status.WF2:
@ -958,22 +958,19 @@ class Logics:
# If the escrow is locked move to Chat. # If the escrow is locked move to Chat.
elif order.trade_escrow.status == LNPayment.Status.LOCKED: elif order.trade_escrow.status == LNPayment.Status.LOCKED:
order.update_status(Order.Status.CHA)
order.expires_at = timezone.now() + timedelta( order.expires_at = timezone.now() + timedelta(
seconds=order.t_to_expire(Order.Status.CHA) seconds=order.t_to_expire(Order.Status.CHA)
) )
send_notification.delay( order.update_status(Order.Status.CHA)
order_id=order.id, message="fiat_exchange_starts"
)
else: else:
order.update_status(Order.Status.WFE) order.update_status(Order.Status.WFE)
# If the order status is 'Failed Routing'. Retry payment. # If the order status is 'Failed Routing'. Retry payment.
elif order.status == Order.Status.FAI: elif order.status == Order.Status.FAI:
if LNNode.double_check_htlc_is_settled(order.trade_escrow.payment_hash): if LNNode.double_check_htlc_is_settled(order.trade_escrow.payment_hash):
order.update_status(Order.Status.PAY)
order.payout.status = LNPayment.Status.FLIGHT order.payout.status = LNPayment.Status.FLIGHT
order.payout.routing_attempts = 0 order.payout.routing_attempts = 0
order.update_status(Order.Status.PAY)
order.payout.save(update_fields=["status", "routing_attempts"]) order.payout.save(update_fields=["status", "routing_attempts"])
order.save(update_fields=["expires_at"]) order.save(update_fields=["expires_at"])
@ -1034,10 +1031,6 @@ class Logics:
# Return the maker bond (Maker gets returned the bond for cancelling public order) # Return the maker bond (Maker gets returned the bond for cancelling public order)
if cls.return_bond(order.maker_bond): if cls.return_bond(order.maker_bond):
order.update_status(Order.Status.UCA) order.update_status(Order.Status.UCA)
send_notification.delay(
order_id=order.id, message="public_order_cancelled"
)
order.log("Order cancelled by maker while public or paused") order.log("Order cancelled by maker while public or paused")
order.log("Maker bond was <b>unlocked</b>") order.log("Maker bond was <b>unlocked</b>")
@ -1054,9 +1047,6 @@ class Logics:
if cls.return_bond(order.maker_bond): if cls.return_bond(order.maker_bond):
cls.cancel_bond(order.taker_bond) cls.cancel_bond(order.taker_bond)
order.update_status(Order.Status.UCA) order.update_status(Order.Status.UCA)
send_notification.delay(
order_id=order.id, message="public_order_cancelled"
)
order.log("Order cancelled by maker before the taker locked the bond") order.log("Order cancelled by maker before the taker locked the bond")
order.log("Maker bond was <b>unlocked</b>") order.log("Maker bond was <b>unlocked</b>")
@ -1123,7 +1113,9 @@ class Logics:
if valid: if valid:
taker_bond = order.taker_bond taker_bond = order.taker_bond
cls.publish_order(order) cls.publish_order(order)
send_notification.delay(order_id=order.id, message="order_published") send_status_notification.delay(
order_id=order.id, status=Order.Status.PUB
)
# Reward maker with part of the taker bond # Reward maker with part of the taker bond
cls.add_slashed_rewards(order, taker_bond, order.maker_bond) cls.add_slashed_rewards(order, taker_bond, order.maker_bond)
@ -1197,7 +1189,6 @@ class Logics:
cls.return_bond(order.taker_bond) cls.return_bond(order.taker_bond)
cls.return_escrow(order) cls.return_escrow(order)
order.update_status(Order.Status.CCA) order.update_status(Order.Status.CCA)
send_notification.delay(order_id=order.id, message="collaborative_cancelled")
nostr_send_order_event.delay(order_id=order.id) nostr_send_order_event.delay(order_id=order.id)
@ -1210,7 +1201,6 @@ class Logics:
@classmethod @classmethod
def publish_order(cls, order): def publish_order(cls, order):
order.status = Order.Status.PUB
order.expires_at = order.created_at + timedelta( order.expires_at = order.created_at + timedelta(
seconds=order.t_to_expire(Order.Status.PUB) seconds=order.t_to_expire(Order.Status.PUB)
) )
@ -1226,6 +1216,7 @@ class Logics:
order.payout = None order.payout = None
order.payout_tx = None order.payout_tx = None
order.update_status(Order.Status.PUB)
order.save() # update all fields order.save() # update all fields
nostr_send_order_event.delay(order_id=order.id) nostr_send_order_event.delay(order_id=order.id)
@ -1344,7 +1335,6 @@ class Logics:
order.expires_at = timezone.now() + timedelta( order.expires_at = timezone.now() + timedelta(
seconds=order.t_to_expire(Order.Status.WF2) seconds=order.t_to_expire(Order.Status.WF2)
) )
order.status = Order.Status.WF2
order.save( order.save(
update_fields=[ update_fields=[
"status", "status",
@ -1371,10 +1361,11 @@ class Logics:
) )
except Exception: except Exception:
pass pass
send_notification.delay(order_id=order.id, message="order_taken_confirmed")
order.update_status(Order.Status.WF2)
nostr_send_order_event.delay(order_id=order.id) nostr_send_order_event.delay(order_id=order.id)
order.log( order.log(
f"<b>Contract formalized.</b> Maker: Robot({order.maker.robot.id},{order.maker}). Taker: Robot({order.taker.robot.id},{order.taker}). API median price {order.currency.exchange_rate} {dict(Currency.currency_choices)[order.currency.currency]}/BTC. Premium is {order.premium}%. Contract size {order.last_satoshis} Sats" f"<b>Contract formalized.</b> Maker: Robot({order.maker.robot.id},{order.maker}). Taker: Robot({order.taker.robot.id},{order.taker}). API median price {order.currency.exchange_rate} {dict(Currency.currency_choices)[order.currency.currency]}/BTC. Premium is {order.premium}%. Contract size {order.last_satoshis} Sats"
) )
@ -1471,12 +1462,11 @@ class Logics:
order.update_status(Order.Status.WFI) order.update_status(Order.Status.WFI)
# If status is 'Waiting for invoice' move to Chat # If status is 'Waiting for invoice' move to Chat
elif order.status == Order.Status.WFE: elif order.status == Order.Status.WFE:
order.update_status(Order.Status.CHA)
order.expires_at = timezone.now() + timedelta( order.expires_at = timezone.now() + timedelta(
seconds=order.t_to_expire(Order.Status.CHA) seconds=order.t_to_expire(Order.Status.CHA)
) )
order.update_status(Order.Status.CHA)
order.save(update_fields=["expires_at"]) order.save(update_fields=["expires_at"])
send_notification.delay(order_id=order.id, message="fiat_exchange_starts")
@classmethod @classmethod
def gen_escrow_hold_invoice(cls, order, user): def gen_escrow_hold_invoice(cls, order, user):
@ -1644,11 +1634,10 @@ class Logics:
order.payout.status = LNPayment.Status.FLIGHT order.payout.status = LNPayment.Status.FLIGHT
order.payout.save(update_fields=["status"]) order.payout.save(update_fields=["status"])
order.update_status(Order.Status.PAY)
order.contract_finalization_time = timezone.now() order.contract_finalization_time = timezone.now()
order.update_status(Order.Status.PAY)
order.save(update_fields=["contract_finalization_time"]) order.save(update_fields=["contract_finalization_time"])
send_notification.delay(order_id=order.id, message="trade_successful")
order.log("<b>Paying buyer invoice</b>") order.log("<b>Paying buyer invoice</b>")
return True return True
@ -1661,11 +1650,10 @@ class Logics:
order.payout_tx.status = OnchainPayment.Status.QUEUE order.payout_tx.status = OnchainPayment.Status.QUEUE
order.payout_tx.save(update_fields=["status"]) order.payout_tx.save(update_fields=["status"])
order.update_status(Order.Status.SUC)
order.contract_finalization_time = timezone.now() order.contract_finalization_time = timezone.now()
order.update_status(Order.Status.SUC)
order.save(update_fields=["contract_finalization_time"]) order.save(update_fields=["contract_finalization_time"])
send_notification.delay(order_id=order.id, message="trade_successful")
order.log("<b>Paying buyer onchain address</b>") order.log("<b>Paying buyer onchain address</b>")
return True return True
@ -1679,8 +1667,8 @@ class Logics:
if order.status == Order.Status.CHA or order.status == Order.Status.FSE: if order.status == Order.Status.CHA or order.status == Order.Status.FSE:
# If buyer mark fiat sent # If buyer mark fiat sent
if cls.is_buyer(order, user): if cls.is_buyer(order, user):
order.update_status(Order.Status.FSE)
order.is_fiat_sent = True order.is_fiat_sent = True
order.update_status(Order.Status.FSE)
order.save(update_fields=["is_fiat_sent"]) order.save(update_fields=["is_fiat_sent"])
order.log("Buyer confirmed 'fiat sent'") order.log("Buyer confirmed 'fiat sent'")
@ -1744,9 +1732,9 @@ class Logics:
return False, { return False, {
"bad_request": "Only orders in Chat and with fiat sent confirmed can be reverted." "bad_request": "Only orders in Chat and with fiat sent confirmed can be reverted."
} }
order.update_status(Order.Status.CHA)
order.is_fiat_sent = False order.is_fiat_sent = False
order.reverted_fiat_sent = True order.reverted_fiat_sent = True
order.update_status(Order.Status.CHA)
order.save(update_fields=["is_fiat_sent", "reverted_fiat_sent"]) order.save(update_fields=["is_fiat_sent", "reverted_fiat_sent"])
order.log( order.log(

View File

@ -8,7 +8,7 @@ from django.utils import timezone
from api.lightning.node import LNNode from api.lightning.node import LNNode
from api.logics import Logics from api.logics import Logics
from api.models import LNPayment, OnchainPayment, Order from api.models import LNPayment, OnchainPayment, Order
from api.tasks import follow_send_payment, send_notification from api.tasks import follow_send_payment, send_status_notification
def is_same_status(a: LNPayment.Status, b: LNPayment.Status) -> bool: def is_same_status(a: LNPayment.Status, b: LNPayment.Status) -> bool:
@ -229,8 +229,8 @@ class Command(BaseCommand):
if hasattr(lnpayment, "order_made"): if hasattr(lnpayment, "order_made"):
lnpayment.order_made.log("Maker bond <b>locked</b>") lnpayment.order_made.log("Maker bond <b>locked</b>")
Logics.publish_order(lnpayment.order_made) Logics.publish_order(lnpayment.order_made)
send_notification.delay( send_status_notification.delay(
order_id=lnpayment.order_made.id, message="order_published" order_id=lnpayment.order_made.id, status=Order.Status.PUB
) )
return return

View File

@ -6,8 +6,8 @@ from django.core.management.base import BaseCommand
from django.db import transaction from django.db import transaction
from api.models import Robot from api.models import Robot
from api.notifications import Notifications
from api.utils import get_session from api.utils import get_session
from api.tasks import send_telegram_notification
class Command(BaseCommand): class Command(BaseCommand):
@ -17,7 +17,6 @@ class Command(BaseCommand):
bot_token = config("TELEGRAM_TOKEN") bot_token = config("TELEGRAM_TOKEN")
updates_url = f"https://api.telegram.org/bot{bot_token}/getUpdates" updates_url = f"https://api.telegram.org/bot{bot_token}/getUpdates"
session = get_session() session = get_session()
notifications = Notifications()
def handle(self, *args, **options): def handle(self, *args, **options):
offset = 0 offset = 0
@ -49,7 +48,7 @@ class Command(BaseCommand):
continue continue
parts = message.split(" ") parts = message.split(" ")
if len(parts) < 2: if len(parts) < 2:
self.notifications.send_telegram_message( send_telegram_notification.delay(
result["message"]["from"]["id"], result["message"]["from"]["id"],
'You must enable the notifications bot using the RoboSats client. Click on your "Robot robot" -> "Enable Telegram" and follow the link or scan the QR code.', 'You must enable the notifications bot using the RoboSats client. Click on your "Robot robot" -> "Enable Telegram" and follow the link or scan the QR code.',
) )
@ -57,7 +56,7 @@ class Command(BaseCommand):
token = parts[-1] token = parts[-1]
robot = Robot.objects.filter(telegram_token=token).first() robot = Robot.objects.filter(telegram_token=token).first()
if not robot: if not robot:
self.notifications.send_telegram_message( send_telegram_notification.delay(
result["message"]["from"]["id"], result["message"]["from"]["id"],
f'Wops, invalid token! There is no Robot with telegram chat token "{token}"', f'Wops, invalid token! There is no Robot with telegram chat token "{token}"',
) )

View File

@ -10,7 +10,7 @@ from django.db import models
from django.db.models.signals import pre_delete from django.db.models.signals import pre_delete
from django.dispatch import receiver from django.dispatch import receiver
from django.utils import timezone from django.utils import timezone
from api.tasks import send_notification from api.tasks import send_status_notification
if config("TESTING", cast=bool, default=False): if config("TESTING", cast=bool, default=False):
import random import random
@ -350,8 +350,7 @@ class Order(models.Model):
self.log( self.log(
f"Order state went from {old_status}: <i>{Order.Status(old_status).label}</i> to {new_status}: <i>{Order.Status(new_status).label}</i>" f"Order state went from {old_status}: <i>{Order.Status(old_status).label}</i> to {new_status}: <i>{Order.Status(new_status).label}</i>"
) )
if new_status == Order.Status.FAI: send_status_notification.delay(order_id=self.id, status=self.status)
send_notification.delay(order_id=self.id, message="lightning_failed")
@receiver(pre_delete, sender=Order) @receiver(pre_delete, sender=Order)

View File

@ -57,6 +57,18 @@ class Notifications:
except Exception: except Exception:
pass pass
def status_change(self, order):
Notification.objects.create(
title="", description="", robot=order.maker.robot, order=order
)
if order.taker:
Notification.objects.create(
title="", description="", robot=order.taker.robot, order=order
)
return
def welcome(self, user): def welcome(self, user):
"""User enabled Telegram Notifications""" """User enabled Telegram Notifications"""
lang = user.robot.telegram_lang_code lang = user.robot.telegram_lang_code
@ -215,11 +227,6 @@ class Notifications:
return return
def coordinator_cancelled(self, order):
title = f"🛠️ Your order with ID {order.id} has been cancelled by the coordinator {config('COORDINATOR_ALIAS', cast=str, default='NoAlias')} for the upcoming maintenance stop."
self.send_message(order, order.maker.robot, title)
return
def dispute_closed(self, order): def dispute_closed(self, order):
lang = order.maker.robot.telegram_lang_code lang = order.maker.robot.telegram_lang_code
if order.status == Order.Status.MLD: if order.status == Order.Status.MLD:

View File

@ -251,7 +251,6 @@ def cache_market():
print("SOFT LIMIT REACHED. Could not fetch current external market prices.") print("SOFT LIMIT REACHED. Could not fetch current external market prices.")
return return
@shared_task(name="", ignore_result=True, time_limit=120) @shared_task(name="", ignore_result=True, time_limit=120)
def nostr_send_order_event(order_id=None): def nostr_send_order_event(order_id=None):
if order_id: if order_id:
@ -265,63 +264,70 @@ def nostr_send_order_event(order_id=None):
return return
@shared_task(name="send_chat_notification", ignore_result=True, time_limit=120)
@shared_task(name="send_notification", ignore_result=True, time_limit=120) def send_chat_notification(message_id=None, order_id=None):
def send_notification(order_id=None, chat_message_id=None, message=None): if message_id and order_id:
if order_id:
from api.models import Order from api.models import Order
from chat.models import Message
from api.notifications import Notifications
order = Order.objects.get(id=order_id) order = Order.objects.get(id=order_id)
elif chat_message_id: chat_message = Message.objects.get(id=message_id)
from chat.models import Message notifications = Notifications()
chat_message = Message.objects.get(id=chat_message_id)
order = chat_message.order
from api.notifications import Notifications
notifications = Notifications()
if message == "welcome":
notifications.welcome(order)
elif message == "order_expired_untaken":
notifications.order_expired_untaken(order)
elif message == "trade_successful":
notifications.trade_successful(order)
elif message == "public_order_cancelled":
notifications.public_order_cancelled(order)
elif message == "taker_expired_b4bond":
notifications.taker_expired_b4bond(order)
elif message == "order_published":
notifications.order_published(order)
elif message == "order_taken_confirmed":
notifications.order_taken_confirmed(order)
elif message == "fiat_exchange_starts":
notifications.fiat_exchange_starts(order)
elif message == "dispute_opened":
notifications.dispute_opened(order)
elif message == "collaborative_cancelled":
notifications.collaborative_cancelled(order)
elif message == "new_chat_message":
notifications.new_chat_message(order, chat_message) notifications.new_chat_message(order, chat_message)
elif message == "coordinator_cancelled":
notifications.coordinator_cancelled(order)
elif message == "dispute_closed": @shared_task(name="send_telegram_notification", ignore_result=True, time_limit=120)
notifications.dispute_closed(order) def send_telegram_notification(chat_id=None, message=None):
if chat_id:
from api.notifications import Notifications
elif message == "lightning_failed": notifications = Notifications()
notifications.lightning_failed(order)
notifications.send_telegram_message(chat_id, message)
@shared_task(name="send_status_notification", ignore_result=True, time_limit=120)
def send_status_notification(order_id=None, status=None):
if order_id:
from api.models import Order
from api.notifications import Notifications
order = Order.objects.get(id=order_id)
notifications = Notifications()
if status == Order.Status.EXP:
notifications.order_expired_untaken(order)
elif status == Order.Status.PAY or status == Order.Status.SUC:
notifications.trade_successful(order)
elif status == Order.Status.UCA:
notifications.public_order_cancelled(order)
elif status == Order.Status.PUB:
notifications.order_published(order)
elif status == Order.Status.WF2:
notifications.order_taken_confirmed(order)
elif status == Order.Status.CHA:
notifications.fiat_exchange_starts(order)
elif status == Order.Status.DIS:
notifications.dispute_opened(order)
elif status == Order.Status.CCA:
notifications.collaborative_cancelled(order)
elif status == Order.Status.TLD or status == Order.Status.MLD:
notifications.dispute_closed(order)
elif status == Order.Status.FAI:
notifications.lightning_failed(order)
else:
notifications.status_change(order)
return return

View File

@ -4,7 +4,7 @@ from channels.db import database_sync_to_async
from channels.generic.websocket import AsyncWebsocketConsumer from channels.generic.websocket import AsyncWebsocketConsumer
from api.models import Order from api.models import Order
from api.tasks import send_notification from api.tasks import send_chat_notification
from chat.models import ChatRoom, Message from chat.models import ChatRoom, Message
@ -85,7 +85,8 @@ class ChatRoomConsumer(AsyncWebsocketConsumer):
) )
# send Telegram notification for new message (if conditions apply) # send Telegram notification for new message (if conditions apply)
send_notification.delay(chat_message_id=msg_obj.id, message="new_chat_message") send_chat_notification.delay(message_id=msg_obj.id, order_id=order.id)
return msg_obj return msg_obj
@database_sync_to_async @database_sync_to_async

View File

@ -11,7 +11,7 @@ from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response from rest_framework.response import Response
from api.models import Order from api.models import Order
from api.tasks import send_notification from api.tasks import send_chat_notification
from chat.models import ChatRoom, Message from chat.models import ChatRoom, Message
from chat.serializers import ChatSerializer, InMessageSerializer, PostMessageSerializer from chat.serializers import ChatSerializer, InMessageSerializer, PostMessageSerializer
@ -179,9 +179,7 @@ class ChatView(viewsets.ViewSet):
) )
# send Telegram notification for new message (if conditions apply) # send Telegram notification for new message (if conditions apply)
send_notification.delay( send_chat_notification.delay(message_id=new_message.id, order_id=order.id)
chat_message_id=new_message.id, message="new_chat_message"
)
# Send websocket message # Send websocket message
if chatroom.maker == request.user: if chatroom.maker == request.user:

View File

@ -560,6 +560,21 @@ class TradeTest(BaseAPITestCase):
trade.publish_order() trade.publish_order()
trade.take_order() trade.take_order()
trade.lock_taker_bond() trade.lock_taker_bond()
maker_nick = read_file(f"tests/robots/{trade.maker_index}/nickname")
taker_nick = read_file(f"tests/robots/{trade.taker_index}/nickname")
maker_headers = trade.get_robot_auth(trade.maker_index)
response = self.client.get(reverse("notifications"), **maker_headers)
self.assertResponse(response)
notifications_data = list(response.json())
self.assertEqual(notifications_data[0]["order_id"], trade.order_id)
# Does not receive notification because user is online
self.assertEqual(
notifications_data[0]["title"],
f"✅ Hey {maker_nick}, your order was taken by {taker_nick}!🥳",
)
trade.lock_escrow(trade.taker_index) trade.lock_escrow(trade.taker_index)
trade.submit_payout_invoice(trade.maker_index) trade.submit_payout_invoice(trade.maker_index)
@ -571,7 +586,6 @@ class TradeTest(BaseAPITestCase):
self.assertEqual(data["status_message"], Order.Status(Order.Status.CHA).label) self.assertEqual(data["status_message"], Order.Status(Order.Status.CHA).label)
self.assertFalse(data["is_fiat_sent"]) self.assertFalse(data["is_fiat_sent"])
maker_headers = trade.get_robot_auth(trade.maker_index)
maker_nick = read_file(f"tests/robots/{trade.maker_index}/nickname") maker_nick = read_file(f"tests/robots/{trade.maker_index}/nickname")
response = self.client.get(reverse("notifications"), **maker_headers) response = self.client.get(reverse("notifications"), **maker_headers)
self.assertResponse(response) self.assertResponse(response)
@ -845,6 +859,16 @@ class TradeTest(BaseAPITestCase):
self.assert_order_logs(data["id"]) self.assert_order_logs(data["id"])
maker_headers = trade.get_robot_auth(trade.maker_index)
response = self.client.get(reverse("notifications"), **maker_headers)
self.assertResponse(response)
notifications_data = list(response.json())
self.assertEqual(notifications_data[0]["order_id"], trade.order_id)
self.assertEqual(
notifications_data[0]["title"],
f"😪 Hey {data['maker_nick']}, your order with ID {str(trade.order_id)} has expired without a taker.",
)
def test_public_order_expires(self): def test_public_order_expires(self):
""" """
Tests the expiration of a public order Tests the expiration of a public order
@ -917,6 +941,16 @@ class TradeTest(BaseAPITestCase):
self.assert_order_logs(data["id"]) self.assert_order_logs(data["id"])
maker_headers = trade.get_robot_auth(trade.maker_index)
response = self.client.get(reverse("notifications"), **maker_headers)
self.assertResponse(response)
notifications_data = list(response.json())
self.assertEqual(notifications_data[0]["order_id"], trade.order_id)
self.assertEqual(
notifications_data[0]["title"],
f"😪 Hey {data['maker_nick']}, your order with ID {str(trade.order_id)} has expired without a taker.",
)
def test_escrow_locked_expires(self): def test_escrow_locked_expires(self):
""" """
Tests the expiration of a public order Tests the expiration of a public order
@ -953,6 +987,16 @@ class TradeTest(BaseAPITestCase):
self.assert_order_logs(data["id"]) self.assert_order_logs(data["id"])
maker_headers = trade.get_robot_auth(trade.maker_index)
response = self.client.get(reverse("notifications"), **maker_headers)
self.assertResponse(response)
notifications_data = list(response.json())
self.assertEqual(notifications_data[0]["order_id"], trade.order_id)
self.assertEqual(
notifications_data[0]["title"],
f"😪 Hey {data['maker_nick']}, your order with ID {str(trade.order_id)} has expired without a taker.",
)
def test_chat(self): def test_chat(self):
""" """
Tests the chatting REST functionality Tests the chatting REST functionality
@ -1090,7 +1134,7 @@ class TradeTest(BaseAPITestCase):
self.assertEqual(notifications_data[0]["order_id"], trade.order_id) self.assertEqual(notifications_data[0]["order_id"], trade.order_id)
self.assertEqual( self.assertEqual(
notifications_data[0]["title"], notifications_data[0]["title"],
f"⚖️ Hey {data['maker_nick']}, a dispute has been opened on your order with ID {str(trade.order_id)}.", f"⚖️ Hey {data['maker_nick']}, you lost the dispute on your order with ID {str(trade.order_id)}.",
) )
taker_headers = trade.get_robot_auth(trade.taker_index) taker_headers = trade.get_robot_auth(trade.taker_index)
response = self.client.get(reverse("notifications"), **taker_headers) response = self.client.get(reverse("notifications"), **taker_headers)
@ -1099,7 +1143,7 @@ class TradeTest(BaseAPITestCase):
self.assertEqual(notifications_data[0]["order_id"], trade.order_id) self.assertEqual(notifications_data[0]["order_id"], trade.order_id)
self.assertEqual( self.assertEqual(
notifications_data[0]["title"], notifications_data[0]["title"],
f"⚖️ Hey {data['taker_nick']}, a dispute has been opened on your order with ID {str(trade.order_id)}.", f"⚖️ Hey {data['taker_nick']}, you won the dispute on your order with ID {str(trade.order_id)}.",
) )
def test_order_expires_after_only_maker_messaged(self): def test_order_expires_after_only_maker_messaged(self):
@ -1151,7 +1195,7 @@ class TradeTest(BaseAPITestCase):
self.assertEqual(notifications_data[0]["order_id"], trade.order_id) self.assertEqual(notifications_data[0]["order_id"], trade.order_id)
self.assertEqual( self.assertEqual(
notifications_data[0]["title"], notifications_data[0]["title"],
f"⚖️ Hey {data['maker_nick']}, a dispute has been opened on your order with ID {str(trade.order_id)}.", f"⚖️ Hey {data['maker_nick']}, you won the dispute on your order with ID {str(trade.order_id)}.",
) )
taker_headers = trade.get_robot_auth(trade.taker_index) taker_headers = trade.get_robot_auth(trade.taker_index)
response = self.client.get(reverse("notifications"), **taker_headers) response = self.client.get(reverse("notifications"), **taker_headers)
@ -1160,7 +1204,7 @@ class TradeTest(BaseAPITestCase):
self.assertEqual(notifications_data[0]["order_id"], trade.order_id) self.assertEqual(notifications_data[0]["order_id"], trade.order_id)
self.assertEqual( self.assertEqual(
notifications_data[0]["title"], notifications_data[0]["title"],
f"⚖️ Hey {data['taker_nick']}, a dispute has been opened on your order with ID {str(trade.order_id)}.", f"⚖️ Hey {data['taker_nick']}, you lost the dispute on your order with ID {str(trade.order_id)}.",
) )
# def test_dispute_closed_maker_wins(self): # def test_dispute_closed_maker_wins(self):

View File

@ -269,7 +269,7 @@ def pay_invoice(node_name, invoice):
node = get_node(node_name) node = get_node(node_name)
data = {"payment_request": invoice} data = {"payment_request": invoice}
try: try:
response = requests.post( requests.post(
f'http://localhost:{node["port"]}/v1/channels/transactions', f'http://localhost:{node["port"]}/v1/channels/transactions',
json=data, json=data,
headers=node["headers"], headers=node["headers"],
@ -277,7 +277,6 @@ def pay_invoice(node_name, invoice):
# 0.4s is enough for LND to CLN hodl ACCEPT # 0.4s is enough for LND to CLN hodl ACCEPT
timeout=0.2 if LNVENDOR == "LND" else 1, timeout=0.2 if LNVENDOR == "LND" else 1,
) )
print(response.json())
except ReadTimeout: except ReadTimeout:
# Request to pay hodl invoice has timed out: that's good! # Request to pay hodl invoice has timed out: that's good!
return return

View File

@ -5,7 +5,11 @@ from django.urls import reverse
from api.management.commands.clean_orders import Command as CleanOrders from api.management.commands.clean_orders import Command as CleanOrders
from api.management.commands.follow_invoices import Command as FollowInvoices from api.management.commands.follow_invoices import Command as FollowInvoices
from api.models import Order from api.models import Order
from api.tasks import follow_send_payment, send_notification from api.tasks import (
follow_send_payment,
send_status_notification,
send_chat_notification,
)
from tests.utils.node import ( from tests.utils.node import (
add_invoice, add_invoice,
create_address, create_address,
@ -111,7 +115,7 @@ class Trade:
headers = self.get_robot_auth(robot_index, first_encounter) headers = self.get_robot_auth(robot_index, first_encounter)
self.response = self.client.get(path + params, **headers) self.response = self.client.get(path + params, **headers)
@patch("api.tasks.send_notification.delay", send_notification) @patch("api.tasks.send_status_notification.delay", send_status_notification)
def cancel_order(self, robot_index=1): def cancel_order(self, robot_index=1):
path = reverse("order") path = reverse("order")
params = f"?order_id={self.order_id}" params = f"?order_id={self.order_id}"
@ -119,14 +123,14 @@ class Trade:
body = {"action": "cancel"} body = {"action": "cancel"}
self.response = self.client.post(path + params, body, **headers) self.response = self.client.post(path + params, body, **headers)
@patch("api.tasks.send_notification.delay", send_notification) @patch("api.tasks.send_chat_notification.delay", send_chat_notification)
def send_chat_message(self, message, robot_index=1): def send_chat_message(self, message, robot_index=1):
path = reverse("chat") path = reverse("chat")
headers = self.get_robot_auth(robot_index) headers = self.get_robot_auth(robot_index)
body = {"PGP_message": message, "order_id": self.order_id, "offset": 0} body = {"PGP_message": message, "order_id": self.order_id, "offset": 0}
self.response = self.client.post(path, data=body, **headers) self.response = self.client.post(path, data=body, **headers)
@patch("api.tasks.send_notification.delay", send_notification) @patch("api.tasks.send_status_notification.delay", send_status_notification)
def pause_order(self, robot_index=1): def pause_order(self, robot_index=1):
path = reverse("order") path = reverse("order")
params = f"?order_id={self.order_id}" params = f"?order_id={self.order_id}"
@ -134,13 +138,13 @@ class Trade:
body = {"action": "pause"} body = {"action": "pause"}
self.response = self.client.post(path + params, body, **headers) self.response = self.client.post(path + params, body, **headers)
@patch("api.tasks.send_notification.delay", send_notification) @patch("api.tasks.send_status_notification.delay", send_status_notification)
def follow_hold_invoices(self): def follow_hold_invoices(self):
# A background thread checks every 5 second the status of invoices. We invoke directly during test. # A background thread checks every 5 second the status of invoices. We invoke directly during test.
follower = FollowInvoices() follower = FollowInvoices()
follower.follow_hold_invoices() follower.follow_hold_invoices()
@patch("api.tasks.send_notification.delay", send_notification) @patch("api.tasks.send_status_notification.delay", send_status_notification)
def clean_orders(self): def clean_orders(self):
# A background thread checks every 5 second order expirations. We invoke directly during test. # A background thread checks every 5 second order expirations. We invoke directly during test.
cleaner = CleanOrders() cleaner = CleanOrders()
@ -155,7 +159,7 @@ class Trade:
generate_blocks(create_address("robot"), 1) generate_blocks(create_address("robot"), 1)
wait_nodes_sync() wait_nodes_sync()
@patch("api.tasks.send_notification.delay", send_notification) @patch("api.tasks.send_status_notification.delay", send_status_notification)
def publish_order(self): def publish_order(self):
# Maker's first order fetch. Should trigger maker bond hold invoice generation. # Maker's first order fetch. Should trigger maker bond hold invoice generation.
self.get_order() self.get_order()
@ -170,7 +174,7 @@ class Trade:
# Get order # Get order
self.get_order() self.get_order()
@patch("api.tasks.send_notification.delay", send_notification) @patch("api.tasks.send_status_notification.delay", send_status_notification)
def take_order(self): def take_order(self):
path = reverse("order") path = reverse("order")
params = f"?order_id={self.order_id}" params = f"?order_id={self.order_id}"
@ -178,7 +182,7 @@ class Trade:
body = {"action": "take", "amount": self.take_amount} body = {"action": "take", "amount": self.take_amount}
self.response = self.client.post(path + params, body, **headers) self.response = self.client.post(path + params, body, **headers)
@patch("api.tasks.send_notification.delay", send_notification) @patch("api.tasks.send_status_notification.delay", send_status_notification)
def lock_taker_bond(self): def lock_taker_bond(self):
# Takers's first order fetch. Should trigger maker bond hold invoice generation. # Takers's first order fetch. Should trigger maker bond hold invoice generation.
self.get_order(self.taker_index) self.get_order(self.taker_index)
@ -193,7 +197,7 @@ class Trade:
# Get order # Get order
self.get_order(self.taker_index) self.get_order(self.taker_index)
@patch("api.tasks.send_notification.delay", send_notification) @patch("api.tasks.send_status_notification.delay", send_status_notification)
def lock_escrow(self, robot_index): def lock_escrow(self, robot_index):
# Takers's order fetch. Should trigger trade escrow bond hold invoice generation. # Takers's order fetch. Should trigger trade escrow bond hold invoice generation.
self.get_order(robot_index) self.get_order(robot_index)
@ -208,7 +212,7 @@ class Trade:
# Get order # Get order
self.get_order() self.get_order()
@patch("api.tasks.send_notification.delay", send_notification) @patch("api.tasks.send_status_notification.delay", send_status_notification)
def submit_payout_address(self, robot_index=1): def submit_payout_address(self, robot_index=1):
path = reverse("order") path = reverse("order")
params = f"?order_id={self.order_id}" params = f"?order_id={self.order_id}"
@ -227,7 +231,7 @@ class Trade:
} }
self.response = self.client.post(path + params, body, **headers) self.response = self.client.post(path + params, body, **headers)
@patch("api.tasks.send_notification.delay", send_notification) @patch("api.tasks.send_status_notification.delay", send_status_notification)
def submit_payout_invoice(self, robot_index=1, routing_budget=0): def submit_payout_invoice(self, robot_index=1, routing_budget=0):
path = reverse("order") path = reverse("order")
params = f"?order_id={self.order_id}" params = f"?order_id={self.order_id}"
@ -249,7 +253,7 @@ class Trade:
self.response = self.client.post(path + params, body, **headers) self.response = self.client.post(path + params, body, **headers)
@patch("api.tasks.send_notification.delay", send_notification) @patch("api.tasks.send_status_notification.delay", send_status_notification)
def confirm_fiat(self, robot_index=1): def confirm_fiat(self, robot_index=1):
path = reverse("order") path = reverse("order")
params = f"?order_id={self.order_id}" params = f"?order_id={self.order_id}"
@ -257,7 +261,7 @@ class Trade:
body = {"action": "confirm"} body = {"action": "confirm"}
self.response = self.client.post(path + params, body, **headers) self.response = self.client.post(path + params, body, **headers)
@patch("api.tasks.send_notification.delay", send_notification) @patch("api.tasks.send_status_notification.delay", send_status_notification)
def undo_confirm_sent(self, robot_index=1): def undo_confirm_sent(self, robot_index=1):
path = reverse("order") path = reverse("order")
params = f"?order_id={self.order_id}" params = f"?order_id={self.order_id}"
@ -265,14 +269,14 @@ class Trade:
body = {"action": "undo_confirm"} body = {"action": "undo_confirm"}
self.response = self.client.post(path + params, body, **headers) self.response = self.client.post(path + params, body, **headers)
@patch("api.tasks.send_notification.delay", send_notification) @patch("api.tasks.send_status_notification.delay", send_status_notification)
def expire_order(self): def expire_order(self):
# Change order expiry to now # Change order expiry to now
order = Order.objects.get(id=self.order_id) order = Order.objects.get(id=self.order_id)
order.expires_at = datetime.now() order.expires_at = datetime.now()
order.save() order.save()
@patch("api.tasks.send_notification.delay", send_notification) @patch("api.tasks.send_status_notification.delay", send_status_notification)
def change_order_status(self, status): def change_order_status(self, status):
# Change order expiry to now # Change order expiry to now
order = Order.objects.get(id=self.order_id) order = Order.objects.get(id=self.order_id)