@ -1,3 +1,4 @@
import logging
from decimal import Decimal
from decimal import Decimal
from huey import crontab
from huey import crontab
from huey . contrib . djhuey import periodic_task
from huey . contrib . djhuey import periodic_task
@ -10,6 +11,8 @@ from core.models import UserShippingAddress
from sales . models import ItemSale
from sales . models import ItemSale
logger = logging . getLogger ( ' django.server ' )
class EmailTemplate :
class EmailTemplate :
def __init__ ( self , item , scenario , role ) :
def __init__ ( self , item , scenario , role ) :
context = {
context = {
@ -48,116 +51,116 @@ class EmailTemplate:
return res
return res
@periodic_task ( crontab ( minute = ' */3 ' ) )
### Notifications
@periodic_task ( crontab ( minute = ' * ' ) )
def notify_buyer_of_pending_sale ( ) :
def notify_buyer_of_pending_sale ( ) :
item_sales = ItemSale . objects . filter ( buyer_notified = False , sale_cancelled = False )
item_sales = ItemSale . objects . filter ( buyer_notified = False , sale_cancelled = False )
for sale in item_sales :
for sale in item_sales :
logger . info ( f ' [INFO] Sale # { sale . id } just created, notifying buyer. ' )
email_template = EmailTemplate (
email_template = EmailTemplate (
item = sale ,
item = sale ,
scenario = ' sale_created ' ,
scenario = ' sale_created ' ,
role = ' buyer '
role = ' buyer '
)
)
sent = email_template . send ( )
email_template . send ( )
if sent == 1 :
sale . buyer_notified = True
sale . buyer_notified = True
sale . save ( )
sale . save ( )
return True
else :
return False
@periodic_task ( crontab ( minute = ' * /3 ' ) )
@periodic_task ( crontab ( minute = ' * ' ) )
def notify_ buyer_of_shipment_confirmation ( ) :
def notify_seller_of_funds_received ( ) :
item_sales = ItemSale . objects . filter ( item_shipped= True ) . filter ( buyer_notified_of_shipment = Fals e)
item_sales = ItemSale . objects . filter ( seller_notified = False , buyer_notified = True ) . filter ( payment_received = True )
for sale in item_sales :
for sale in item_sales :
logger . info ( f ' [INFO] Funds received from buyer for sale # { sale . id } , notifying seller. ' )
email_template = EmailTemplate (
email_template = EmailTemplate (
item = sale ,
item = sale ,
scenario = ' item_shipp ed' ,
scenario = ' funds_receiv ed' ,
role = ' buy er'
role = ' sell er'
)
)
sent = email_template . send ( )
email_template . send ( )
if sent == 1 :
sale . seller_notified = True
sale . buyer_notified_of_shipment = True
sale . save ( )
sale . save ( )
bidder_profile = UserShippingAddress . objects . get ( user = sale . bid . bidder )
bidder_profile . delete ( )
return True
else :
return False
@periodic_task ( crontab ( minute = ' * /3 ' ) )
@periodic_task ( crontab ( minute = ' * ' ) )
def notify_ seller_of_shipment_receipt ( ) :
def notify_buyer_of_shipment_confirmation ( ) :
item_sales = ItemSale . objects . filter ( item_shipped = True , item_received = False ) . filter ( seller_notified_of_receip t= False )
item_sales = ItemSale . objects . filter ( item_shipped = True ) . filter ( buyer_notified_of_shipment = False )
for sale in item_sales :
for sale in item_sales :
logger . info ( f ' [INFO] Item shipped for sale # { sale . id } , notifying buyer. ' )
email_template = EmailTemplate (
email_template = EmailTemplate (
item = sale ,
item = sale ,
scenario = ' item_shipped ' ,
scenario = ' item_shipped ' ,
role = ' buyer '
role = ' buyer '
)
)
sent = email_template . send ( )
email_template . send ( )
if sent == 1 :
bidder_profile = UserShippingAddress . objects . get ( user = sale . bid . bidder )
sale . seller_notified_of_receipt = True
bidder_profile . delete ( )
sale . save ( )
logger . info ( f ' [INFO] Buyer shipping info wiped for sale # { sale . id } ' )
return True
sale . buyer_notified_of_shipment = True
else :
sale . save ( )
return False
@periodic_task ( crontab ( minute = ' */5 ' ) )
def notify_seller_of_funds_received ( ) :
### Payments
item_sales = ItemSale . objects . filter ( seller_notified = False , buyer_notified = True ) . filter ( payment_received = True )
@periodic_task ( crontab ( minute = ' * ' ) )
def poll_for_buyer_escrow_payments ( ) :
aw = AuctionWallet ( )
if aw . connected is False :
logging . error ( ' Auction wallet is not connected. Quitting. ' )
return False
item_sales = ItemSale . objects . filter ( payment_received = False )
for sale in item_sales :
for sale in item_sales :
email_template = EmailTemplate (
logger . info ( f ' [INFO] Polling escrow address # { sale . escrow_account_index } for sale # { sale . id } for new funds. ' )
item = sale ,
sale_account = aw . wallet . accounts [ sale . escrow_account_index ]
scenario = ' funds_received ' ,
balance = sale_account . balances ( ) [ 1 ]
role = ' seller '
sale . received_payment_xmr = balance
)
if balance > = Decimal ( sale . expected_payment_xmr ) :
sent = email_template . send ( )
logger . info ( f ' [INFO] Found payment of { sale . received_payment_xmr } XMR for sale # { sale . id } . ' )
if sent == 1 :
sale . payment_received = True
sale . seller_notified = True
sale . save ( )
sale . save ( )
return True
else :
return False
@periodic_task ( crontab ( minute = ' */ 10 ' ) )
@periodic_task ( crontab ( minute = ' */5 ' ) )
def pay_sellers_on_sold_items ( ) :
def pay_sellers_on_sold_items ( ) :
aw = AuctionWallet ( )
aw = AuctionWallet ( )
if aw . connected is False :
if aw . connected is False :
logging . error ( ' Auction wallet is not connected. Quitting. ' )
return False
return False
item_sales = ItemSale . objects . filter ( item_received = True , payment_received = True ) . filter ( seller_paid = False )
item_sales = ItemSale . objects . filter ( item_received = True , payment_received = True ) . filter ( seller_paid = False )
for sale in item_sales :
for sale in item_sales :
try :
logger . info ( f ' [INFO] Sending { sale . agreed_price_xmr } XMR from wallet account # { sale . escrow_account_index } to item owner \' s payout address for sale # { sale . id } . ' )
print ( f ' sending agreed payment, { sale . agreed_price_xmr } XMR, from account index # { sale . escrow_account_index } to { sale . item . owner . username } for sale # { sale . id } ( { sale . item . name } ) ' )
sale_account = aw . wallet . accounts [ sale . escrow_account_index ]
sale_account = aw . wallet . accounts [ sale . escrow_account_index ]
if sale_account . balances ( ) [ 1 ] > Decimal ( sale . agreed_price_xmr ) :
if sale_account . balances ( ) [ 1 ] > Decimal ( 0.0 ) :
try :
aw . wallet . accounts [ sale . escrow_account_index ] . transfer (
aw . wallet . accounts [ sale . escrow_account_index ] . transfer (
sale . item . payout_address , sale . agreed_price_xmr , relay = True
sale . item . payout_address , sale . agreed_price_xmr
)
)
sale . seller_paid = True
sale . seller_paid = True
sale . escrow_complete = True
sale . escrow_complete = True
sale . save ( )
sale . save ( )
else :
except Exception as e :
print ( ' not enough funds here to transfer. try later ' )
logger . error ( f ' [ERROR] Unable to pay seller for sale # { sale . id } : ' )
return False
else :
except Exception as e :
logger . warning ( f ' [WARNING] Not enough unlocked funds available in account # { sale . escrow_account_index } for sale # { sale . id } . ' )
print ( ' unable to make payment: ' , e )
return False
if sale . seller_paid and sale . seller_notified_of_payout is False :
email_template = EmailTemplate (
email_template = EmailTemplate (
item = sale ,
item = sale ,
scenario = ' sale_completed ' ,
scenario = ' sale_completed ' ,
role = ' seller '
role = ' seller '
)
)
if sale . seller_notified_of_payout is False :
sent = email_template . send ( )
sent = email_template . send ( )
sale . seller_notified_of_payout = True
sale . seller_notified_of_payout = True
sale . save ( )
sale . save ( )
@periodic_task ( crontab ( hour= ' * /3 ' ) )
@periodic_task ( crontab ( minute= ' 0 ' , hour= ' * ' ) )
def pay_platform_on_sold_items ( ) :
def pay_platform_on_sold_items ( ) :
aw = AuctionWallet ( )
aw = AuctionWallet ( )
if aw . connected is False :
if aw . connected is False :
logging . error ( ' Auction wallet is not connected. Quitting. ' )
return False
return False
aof = settings . PLATFORM_WALLET_ADDRESS
aof = settings . PLATFORM_WALLET_ADDRESS
@ -166,68 +169,43 @@ def pay_platform_on_sold_items():
item_sales = ItemSale . objects . filter ( escrow_complete = True , seller_paid = True , item_received = True ) . filter ( platform_paid = False )
item_sales = ItemSale . objects . filter ( escrow_complete = True , seller_paid = True , item_received = True ) . filter ( platform_paid = False )
for sale in item_sales :
for sale in item_sales :
logger . info ( f ' [INFO] Paying platform fees for sale # { sale . id } to wallet { aof } . ' )
sale_account = aw . wallet . accounts [ sale . escrow_account_index ]
sale_account = aw . wallet . accounts [ sale . escrow_account_index ]
try :
if sale_account . balances ( ) [ 1 ] > = Decimal ( 0.0 ) :
if sale_account . balances ( ) [ 1 ] > = Decimal ( 0.0 ) :
try :
print ( f ' paying out platform wallet, { aof } , remaining funds in account # { sale . escrow_account_index } for sale # { sale . id } ' )
aw . wallet . accounts [ sale . escrow_account_index ] . sweep_all ( aof )
aw . wallet . accounts [ sale . escrow_account_index ] . sweep_all ( aof )
sale . platform_paid = True
sale . platform_paid = True
sale . sale_finalized = True
sale . sale_finalized = True
sale . save ( )
sale . save ( )
return True
return True
else :
except Exception as e :
print ( ' not enough funds here to sweep. try later ' )
logger . error ( f ' [ERROR] Unable to pay platform for sale # { sale . id } - trying again ' )
return False
else :
except Exception as e :
logger . warning ( f ' [WARNING] Not enough unlocked funds available in account # { sale . escrow_account_index } for sale # { sale . id } . ' )
print ( ' unable to sweep funds: ' , e )
return False
@periodic_task ( crontab ( minute = ' */3 ' ) )
def poll_for_buyer_escrow_payments ( ) :
aw = AuctionWallet ( )
if aw . connected is False :
return False
item_sales = ItemSale . objects . filter ( payment_received = False )
for sale in item_sales :
sale_account = aw . wallet . accounts [ sale . escrow_account_index ]
sale . received_payment_xmr = sale_account . balance ( )
if sale_account . balance ( ) > = Decimal ( str ( sale . expected_payment_xmr ) ) :
sale . payment_received = True
sale . save ( )
if settings . DEBUG :
print ( ' [+] Sale: # {} - Balance: {} - Payment Received: {} ' . format (
sale . id , sale . received_payment_xmr , sale . payment_received
) )
@periodic_task ( crontab ( hour= ' */8 ' ) )
@periodic_task ( crontab ( minute = ' 0 ' , hour = ' */12 ' ) )
def close_completed_items_sales ( ) :
def close_completed_items_sales ( ) :
item_sales = ItemSale . objects . filter ( platform_paid = True , sale_finalized = True )
item_sales = ItemSale . objects . filter ( platform_paid = True , sale_finalized = True )
for sale in item_sales :
for sale in item_sales :
print ( f ' d eleting item #{ sale . item . id } and all accompanying bids, sales, meta ' )
logger . info ( f ' [INFO] Deleting item # { sale . item . id } and all accompanying bids, sales, meta, etc. ' )
sale . item . delete ( )
sale . item . delete ( )
@periodic_task ( crontab ( minute = ' * /6 ' ) )
@periodic_task ( crontab ( minute = ' * ' ) )
def closed_cancelled_sales ( ) :
def closed_cancelled_sales ( ) :
aw = AuctionWallet ( )
aw = AuctionWallet ( )
if aw . connected is False :
if aw . connected is False :
logging . error ( ' Auction wallet is not connected. Quitting. ' )
return False
return False
item_sales = ItemSale . objects . filter ( sale_cancelled = True )
item_sales = ItemSale . objects . filter ( sale_cancelled = True )
for sale in item_sales :
for sale in item_sales :
print ( f ' d eleting sale #{ sale . id } and transferring back any sent funds to the buyer ' )
logger . info ( f ' [INFO] Deleting sale # { sale . id } and transferring back any sent funds to the buyer. ' )
sale_account = aw . wallet . accounts [ sale . escrow_account_index ]
sale_account = aw . wallet . accounts [ sale . escrow_account_index ]
if sale_account . balance ( ) > Decimal ( 0.0 ) :
if sale_account . balances ( ) [ 0 ] > Decimal ( 0.0 ) :
try :
try :
sale_account . sweep_all ( sale . bid . return_address )
sale_account . sweep_all ( sale . bid . return_address )
sale . delete ( )
sale . delete ( )
except Exception as e :
except Exception as e :
print ( ' unable to sweep all: ' , e )
logger . error ( f ' [ERROR] Unable to return funds to use for sale # { sale . id } . ' )
return False
else :
else :
sale . delete ( )
sale . delete ( )