setup logging and refactor tasks

pull/3/head
lalanza808 5 years ago
parent 1184d18303
commit c6f18d9a88

@ -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=False) 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_shipped', scenario='funds_received',
role='buyer' role='seller'
) )
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_receipt=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()
logger.info(f'[INFO] Buyer shipping info wiped for sale #{sale.id}')
sale.buyer_notified_of_shipment = True
sale.save() sale.save()
return True
else:
### Payments
@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 return False
@periodic_task(crontab(minute='*/5')) item_sales = ItemSale.objects.filter(payment_received=False)
def notify_seller_of_funds_received():
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:
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(0.0): if sale_account.balances()[1] > Decimal(sale.agreed_price_xmr):
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:
print('not enough funds here to transfer. try later')
return False
except Exception as e: except Exception as e:
print('unable to make payment: ', e) logger.error(f'[ERROR] Unable to pay seller for sale #{sale.id}: ')
return False else:
logger.warning(f'[WARNING] Not enough unlocked funds available in account #{sale.escrow_account_index} for sale #{sale.id}.')
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):
print(f'paying out platform wallet, {aof}, remaining funds in account #{sale.escrow_account_index} for sale #{sale.id}') try:
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:
print('not enough funds here to sweep. try later')
return False
except Exception as e: except Exception as e:
print('unable to sweep funds: ', e) logger.error(f'[ERROR] Unable to pay platform for sale #{sale.id} - trying again')
return False else:
logger.warning(f'[WARNING] Not enough unlocked funds available in account #{sale.escrow_account_index} for sale #{sale.id}.')
@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'deleting 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'deleting 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()

@ -1144,7 +1144,7 @@ New color: fd4e05
box-sizing: border-box; box-sizing: border-box;
} }
.sale-qrcode { .center {
display: block; display: block;
margin: 0 auto; margin: 0 auto;
} }

@ -17,7 +17,7 @@
</p> </p>
<p class="sale-info"><strong>Expected Payment (XMR)</strong>: {{ sale.expected_payment_xmr }}</p> <p class="sale-info"><strong>Expected Payment (XMR)</strong>: {{ sale.expected_payment_xmr }}</p>
<p class="sale-info"><strong>Escrow Address</strong>: {{ sale.escrow_address }}</p> <p class="sale-info"><strong>Escrow Address</strong>: {{ sale.escrow_address }}</p>
<img src="data:image/png;base64,{{ qrcode }}" width=200 class="sale-qrcode"> <img src="data:image/png;base64,{{ qrcode }}" width=200 class="center">
<hr> <hr>
<span class="wallet-text"> <span class="wallet-text">
<h2>Need a Wallet?</h2> <h2>Need a Wallet?</h2>
@ -53,11 +53,13 @@
When it does arrive please click the button below to confirm. When it does arrive please click the button below to confirm.
</p> </p>
<p class="sale-info">Stay tuned for updates and thanks for using {{ site_meta.name }}!</p> <p class="sale-info">Stay tuned for updates and thanks for using {{ site_meta.name }}!</p>
<img src="{% static 'images/monero-symbol-800.png' %}" width=200> <img src="{% static 'images/monero-symbol-800.png' %}" width=200 class="center">
<hr> <hr>
<hr> <hr>
<span class="wallet-text">
<p>Click here when you have received your package:</p> <p>Click here when you have received your package:</p>
<p class="sale-info"><a href="{% url 'confirm_receipt' sale.id %}" class="button">Confirm Item Received</a></p> <p class="sale-info"><a href="{% url 'confirm_receipt' sale.id %}" class="button">Confirm Item Received</a></p>
</span>
{% elif sale.item_received %} {% elif sale.item_received %}
<p class="sale-info">Hey {{ sale.bid.bidder.username }},</p> <p class="sale-info">Hey {{ sale.bid.bidder.username }},</p>
<p class="sale-info">It sounds like your order was successful. The seller will be sent their funds from the transaction out of the escrow wallet. You are good to go!</p> <p class="sale-info">It sounds like your order was successful. The seller will be sent their funds from the transaction out of the escrow wallet. You are good to go!</p>
@ -97,7 +99,8 @@
<p class="sale-info"><strong>State</strong>: {{ shipping_address.state }}</p> <p class="sale-info"><strong>State</strong>: {{ shipping_address.state }}</p>
<p class="sale-info"><strong>Country</strong>: {{ shipping_address.country }}</p> <p class="sale-info"><strong>Country</strong>: {{ shipping_address.country }}</p>
<p class="sale-info"><strong>Zip</strong>: {{ shipping_address.zip }}</p> <p class="sale-info"><strong>Zip</strong>: {{ shipping_address.zip }}</p>
<p class="sale-info">If you have shipped the item please confirm by clicking this button:</p> <br>
<p class="sale-info">If you have shipped the item, and <strong>only if you have shipped the item</strong>, please confirm by clicking this button:</p>
<p class="sale-info"><a href="{% url 'confirm_shipment' sale.id %}" class="button">Confirm Item Shipped</a></p> <p class="sale-info"><a href="{% url 'confirm_shipment' sale.id %}" class="button">Confirm Item Shipped</a></p>
{% else %} {% else %}
<br> <br>
@ -108,7 +111,7 @@
<p class="sale-info">Hello {{ sale.item.owner.username }},</p> <p class="sale-info">Hello {{ sale.item.owner.username }},</p>
<p class="sale-info">You've shipped the item, now you need to wait for the buyer to confirm they received it on their end.</p> <p class="sale-info">You've shipped the item, now you need to wait for the buyer to confirm they received it on their end.</p>
<p class="sale-info">Stay tuned for updates and thanks for using {{ site_meta.name }}!</p> <p class="sale-info">Stay tuned for updates and thanks for using {{ site_meta.name }}!</p>
<img src="{% static 'images/monero-symbol-800.png' %}" width=200> <img src="{% static 'images/monero-symbol-800.png' %}" width=200 class="center">
{% elif sale.item_received %} {% elif sale.item_received %}
<p class="sale-info">Hey {{ sale.item.owner.username }},</p> <p class="sale-info">Hey {{ sale.item.owner.username }},</p>
<p class="sale-info">The buyer confirmed receipt of their shipment which means things worked out. It's time for you to get paid!<p> <p class="sale-info">The buyer confirmed receipt of their shipment which means things worked out. It's time for you to get paid!<p>