Exemple #1
0
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
Exemple #2
0
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
Exemple #3
0
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
Exemple #4
0
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)
Exemple #5
0
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)
Exemple #6
0
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
Exemple #7
0
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)
Exemple #9
0
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'))
Exemple #10
0
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
Exemple #11
0
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
Exemple #12
0
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)
Exemple #13
0
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)
Exemple #14
0
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'))