def deposit_api(): # receives and processes deposit notifications from BTCPay # forward all IPNs forward_url = fetch('forward_url') if forward_url is not None and forward_url != '': r = requests.post(forward_url, json=request.get_json()) if not r.ok: app.logger.error(f'IPN Rejected by Forwarding URL: \ {r.status_code}, {r.url}, {r.reason}, {r.text}') Thread( target=repeat_ipn, args=(forward_url, request.get_json()) ).start() if not request.json: return "No JSON Data.", 200 elif 'status' in request.json: app.logger.info(f'IPN: {request.json["status"]} {request.json["id"]}') # check for duplicates if app.redis.get(request.json['id']) is not None: return "Duplicate IPN", 200 btc_client = fetch('btc_client') deposit = btc_client.get_invoice(request.json['id']) if not isinstance(deposit, dict): return "Spam IPN", 200 if request.json['status'] == 'paid' and (deposit['status'] == 'paid' or deposit['status'] == 'confirmed' or deposit['status'] == 'complete') \ and fetch('mail_on'): # emails buyer when invoice is "paid" dest = deposit['buyer']['email'] qb_inv = None btcp_inv = deposit['id'] amt = float(deposit['price']) Thread( target=send, args=(dest, qb_inv, btcp_inv, amt) ).start() return "Buyer email sent.", 200 if deposit['status'] == 'confirmed' or \ deposit['status'] == 'complete': # then post deposit amount = deposit.get('price') tax = deposit.get('taxIncluded') if amount is None: return "No Payment to Record.", 200 if tax is None: tax = 0 btcp_id = str(deposit.get('id')) qbo.post_deposit( amount=float(amount), tax=float(tax), btcp_id=btcp_id, ) return "Payment Accepted", 201 else: return "IPN received.", 200 else: return "Ignore.", 200
def paymentapi(): # receives and processes invoice notifications from BTCPay if not request.json: return "No JSON Data.", 200 elif 'status' in request.json: app.logger.info(f'IPN: {request.json["status"]} {request.json["id"]}') # check for duplicates cache_status = app.redis.get(request.json['id']) if cache_status == 'payment': app.logger.info(f'IPN: {request.json["id"]} already recorded') return "IPN Already Recorded", 200 btc_client = fetch('btc_client') invoice = btc_client.get_invoice(request.json['id']) if not isinstance(invoice, dict): app.logger.info(f'IPN: {request.json["id"]} is spam') return "Spam IPN", 200 if request.json['status'] == 'paid' and (invoice['status'] == 'paid' or invoice['status'] == 'confirmed' or invoice['status'] == 'complete') \ and fetch('mail_on'): # emails buyer when invoice is "paid" dest = invoice['buyer']['email'] qb_inv = invoice['orderId'] btcp_inv = invoice['id'] amt = float(invoice['price']) Thread( target=send, args=(dest, qb_inv, btcp_inv, amt) ).start() # update cache so we don't send customer multiple emails app.redis.set(btcp_inv, 'paid', ex=21600) return "Buyer email sent.", 200 elif (request.json['status'] == 'confirmed') and \ (invoice['status'] == 'confirmed' or invoice['status'] == 'complete'): ''' Lightning payments will send 3 IPNs simultaneously, so we must that that only one is processed. ''' doc_number = invoice['orderId'] amount = float(invoice['price']) if amount > 0 and doc_number is not None: qbo.post_payment( doc_number=str(doc_number), amount=amount, btcp_id=invoice['id'] ) return "Payment Accepted", 201 else: app.logger.info(f'IPN: {request.json["id"]} was invalid inv') return "Payment was zero or invalid invoice #.", 200 else: return "IPN received.", 200 else: app.logger.info(f'IPN: {request.json["id"]} contains no status field') return "Ignore.", 200
def get_auth_url(): # asks Intuit server for a valid authorization URL # returns authorization URL callback_url = app.config.get('CALLBACK_URL') session_manager = Oauth2SessionManager( client_id=fetch('qb_id'), client_secret=fetch('qb_secret'), base_url=callback_url, ) authorize_url = session_manager.get_authorize_url(callback_url) return authorize_url
def refresh_stored_tokens(): # refresh stored QBO tokens callback_url = app.config.get('CALLBACK_URL') realm_id = fetch('realm_id') session_manager = Oauth2SessionManager( client_id=fetch('qb_id'), client_secret=fetch('qb_secret'), base_url=callback_url, access_token=fetch('access_token'), refresh_token=fetch('refresh_token'), ) result = session_manager.refresh_access_tokens(return_result=True) save('access_token', session_manager.access_token) save('refresh_token', session_manager.refresh_token) session_manager = Oauth2SessionManager( client_id=realm_id, client_secret=fetch('qb_secret'), access_token=fetch('access_token'), ) sandbox = fetch('qb_sandbox') qbclient = QuickBooks(sandbox=sandbox, session_manager=session_manager, company_id=realm_id) QuickBooks.enable_global() save('session_manager', session_manager) save('qbclient', qbclient) return str(result)
def mail(): recipient = input('Enter recipient: ') msg = 'Subject: Hi\nHow are you?' click.echo(fetch('mail_on')) click.echo(fetch('mail_user')) click.echo(fetch('mail_host')) click.echo(fetch('mail_port')) click.echo(fetch('mail_from')) smtp = smtplib.SMTP(fetch('mail_host'), fetch('mail_port')) click.echo(smtp.ehlo()) if fetch('mail_port') == 587: click.echo(smtp.starttls()) click.echo(smtp.login(fetch('mail_user'), fetch('mail_pswd'))) smtp.sendmail('*****@*****.**', recipient, msg)
def verify(): # receives/processes form data from public facing pmt page data = request.form customer = qbo.verify_invoice( doc_number=str(data['orderId']), email=str(data['email']) ) # create BTCPay invoice from submitted form data if customer is not None: btc_client = fetch('btc_client') inv_data = btc_client.create_invoice({ "price": data['amount'], "currency": "USD", "buyer": { "name": customer.DisplayName, "email": data['email'], }, "orderId": data['orderId'], "fullNotifications": True, "notificationURL": data['notificationUrl'], "redirectURL": data['redirectUrl'] }) inv_url = inv_data['url'] return redirect(inv_url) else: no_match = ''' The email and invoice number provided do not match. Please try again. If multiple emails are associated to the invoice, you must use the primary one. ''' return no_match
def backtest_all(from_, to_, pair): cache_data_by_period = {} for period in INTERVALS: data = fetch(pair, time_period={ 'from': from_, 'to': to_ }, interval=period) cache_data_by_period[period] = parse_date_period(data) items = product(FAST_PERIOD, SLOW_PERIOD, SIGNAL_PERIOD, INTERVALS) def run(item): macd = MACD(pair, *item, plato_ids=None) data = deepcopy(cache_data_by_period[item[3]]) stock = macd.calculate_coefficient(data) stock['advise'] = calc_advise(stock) backtest = Backtester(stock, stock) trades = backtest.calc_trades() statistics = backtest.get_statistics(trades, to_) Backtest.new_backtest(item, item, statistics, from_, to_) collections.deque(map(run, items))
def get_data(self, _from, _to): _from = _from - self.time_period * 60 * self.skip_data key = f'{self.time_period}_{_from}' if cache_platradeinfo.get(key) is None: data = fetch(self.pair, interval=self.time_period, time_period={'from': _from, 'to': _to}) cache_platradeinfo[key] = parse_date_period(data) return cache_platradeinfo.get(key)
def authqbo(): status = login(request.cookies) if status is not None: return redirect(status) # calls fn to grab qbo auth url and then redirects there if fetch('qb_secret') is not None: return redirect(qbo.get_auth_url()) else: return redirect(url_for('set_keys'))
def set_global_vars(realmid, code): # stores Intuit tokens # stores QBO client object # stores session manager object for future token refreshes callback_url = app.config.get('CALLBACK_URL') session_manager = Oauth2SessionManager( client_id=fetch('qb_id'), client_secret=fetch('qb_secret'), base_url=callback_url, ) realm_id = realmid data = session_manager.get_access_tokens( auth_code=code, return_result=True, ) # sanity check: if no valid response from Intuit, abort fn if 'token_type' not in data: return None access_token = session_manager.access_token refresh_token = session_manager.refresh_token session_manager = Oauth2SessionManager( client_id=realm_id, client_secret=fetch('qb_secret'), access_token=access_token, ) sandbox = fetch('qb_sandbox') qbclient = QuickBooks(sandbox=sandbox, session_manager=session_manager, company_id=realm_id) QuickBooks.enable_global() save('realm_id', realm_id) save('access_token', access_token) save('refresh_token', refresh_token) save('session_manager', session_manager) save('qbclient', qbclient) from app import tasks
def verify_invoice(doc_number="", email=""): # checks QBO to ensure invoice number matches email provided # if match, returns QBO customer object attached to invoice # if mismatch, returns None refresh_stored_tokens() qb = fetch('qbclient') invoice_list = Invoice.filter(DocNumber=doc_number, qb=qb) if invoice_list: customers = Customer.filter(id=invoice_list[0].CustomerRef.value, qb=qb) else: return None if customers: if customers[0].PrimaryEmailAddr.Address.lower() == email.lower(): return customers[0] else: return None else: return None
def post_deposit(amount, tax, btcp_id): # post deposit to QBO if tax is None: tax = float(0) refresh_stored_tokens() qb = fetch('qbclient') # check if BTCPay income acct is already in QBO income_acct_list = Account.filter(Name="BTCPay Sales", qb=qb) try: # if income acct exits, grab it income_acct = income_acct_list[0] except IndexError: # if income acct is not in QBO, create it new_acct = Account() new_acct.Name = "BTCPay Sales" new_acct.AccountSubType = "OtherPrimaryIncome" new_acct.save(qb=qb) # set newly created acct as income acct income_acct_list = Account.filter(Name="BTCPay Sales", qb=qb) income_acct = income_acct_list[0] # check if BTCPay Sales Tax acct is already in QBO sales_tax_acct_list = Account.filter(Name="Sales Tax from BTCPay", qb=qb) try: # if sales tax liability acct exits, grab it sales_tax_acct = sales_tax_acct_list[0] except IndexError: # if sales tax acct is not in QBO, create it new_acct = Account() new_acct.Name = "Sales Tax from BTCPay" new_acct.AccountSubType = "OtherCurrentLiabilities" new_acct.save(qb=qb) # set newly created acct as sales tax account sales_tax_acct_list = Account.filter(Name="Sales Tax from BTCPay", qb=qb) sales_tax_acct = sales_tax_acct_list[0] # check if QBO has asset acct for Bitcoin-BTCPay deposit_acct_list = Account.filter(Name="Bitcoin-BTCPay", qb=qb) try: # if Bitcoin-BTCPay is in QBO, set as deposit acct deposit_acct = deposit_acct_list[0] except IndexError: # if Bitcoin-BTCPay is not in QBO, create it as deposit acct new_acct = Account() new_acct.Name = "Bitcoin-BTCPay" new_acct.AccountSubType = "OtherCurrentAssets" new_acct.save(qb=qb) # set newly created Bitcoin-BTCPay acct as deposit acct deposit_acct_list = Account.filter(Name="Bitcoin-BTCPay", qb=qb) deposit_acct = deposit_acct_list[0] # create deposit description = 'BTCPay: ' + btcp_id income_acct_ref = Ref() income_acct_ref.value = income_acct.Id detail = DepositLineDetail() detail.AccountRef = income_acct_ref line = DepositLine() line.DepositLineDetail = detail deposit_account_ref = Ref() deposit_account_ref.value = deposit_acct.Id line.Amount = amount - tax line.Description = description # create sales tax line sales_tax_acct_ref = Ref() sales_tax_acct_ref.value = sales_tax_acct.Id line2 = DepositLine() detail2 = DepositLineDetail() detail2.AccountRef = sales_tax_acct_ref line2.DepositLineDetail = detail2 line2.Description = description line2.Amount = tax deposit = Deposit() deposit.Line.append(line) deposit.Line.append(line2) deposit.DepositToAccountRef = deposit_account_ref deposit.save(qb=qb) # save payment to temp redis store to fliter duplicates app.redis.set(btcp_id, 'deposit', ex=21600) return 'Deposit Made: ' + str(deposit)
def post_payment(doc_number="", amount=0, btcp_id=''): # post payment to QBO ''' doc_number: QBO invoice number amount: payment amount btcp_id: BTCPay invoice number ''' refresh_stored_tokens() qb = fetch('qbclient') # check if BTCPay is already in QBO as a pmt method pmt_method_list = PaymentMethod.filter(Name="BTCPay", qb=qb) try: # if BTCPay is already in QBO, set it as pmt method pmt_method = pmt_method_list[0] except IndexError: # if BTCPay is not in QBO, create it as pmt method new_pmt_method = PaymentMethod() new_pmt_method.Name = "BTCPay" new_pmt_method.save(qb=qb) # set newly created BTCPay pmt method as pmt method pmt_method_list = PaymentMethod.filter(Name="BTCPay", qb=qb) pmt_method = pmt_method_list[0] # check if QBO has asset acct for Bitcoin-BTCPay deposit_acct_list = Account.filter(Name="Bitcoin-BTCPay", qb=qb) try: # if Bitcoin-BTCPay is in QBO, set as deposit acct deposit_acct = deposit_acct_list[0] except IndexError: # if Bitcoin-BTCPay is not in QBO, create it as deposit acct new_acct = Account() new_acct.Name = "Bitcoin-BTCPay" new_acct.AccountSubType = "OtherCurrentAssets" new_acct.save(qb=qb) # set newly created Bitcoin-BTCPay acct as deposit acct deposit_acct_list = Account.filter(Name="Bitcoin-BTCPay", qb=qb) deposit_acct = deposit_acct_list[0] # pull list of invoice objects matching invoice number from QBO invoice_list = Invoice.filter(DocNumber=doc_number, qb=qb) try: # only one invoice can match the inv #, so pull it from list invoice = invoice_list[0] except IndexError: app.logger.warning(f'No such invoice exists: {doc_number}') return None else: # convert invoice object to linked invoice object linked_invoice = invoice.to_linked_txn() description = 'BTCPay: ' + btcp_id payment_line = PaymentLine() payment_line.Amount = amount payment_line.Description = description # attach linked invoice object to payment line object payment_line.LinkedTxn.append(linked_invoice) payment = Payment() payment.TotalAmt = amount payment.CustomerRef = invoice.CustomerRef # create deposit acct reference object from deposit acct object deposit_account_ref = Ref() deposit_account_ref.value = deposit_acct.Id # create pmt method reference object from pmt method object pmt_method_ref = Ref() pmt_method_ref.name = pmt_method.Name # attach pmt method ref, dep acct ref, and pmt line obj to pmt obj payment.PaymentMethodRef = pmt_method_ref payment.DepositToAccountRef = deposit_account_ref payment.Line.append(payment_line) payment.save(qb=qb) # save payment to temp redis store to fliter duplicates app.redis.set(btcp_id, 'payment', ex=21600) return "Payment Made: " + str(payment)
def printqb(): # prints QBO API ID and token to screen click.echo(fetch('qb_id')) click.echo(fetch('qb_sandbox')) click.echo(os.getenv('CALLBACK_URL'))