示例#1
0
def qbo_check_customer(sc):
    client = create_qbc()
    customers = Customer.filter(Active=True, FamilyName=sc.last_name, GivenName=sc.first_name, qb=client)
    if(len(customers) == 0):
        return qbo_create_customer(sc)
    else:
        return customers[0].Id
示例#2
0
def create_customer(user, company, name):
    client = get_qbo_client(user, company)
    customer = Customer.filter(Active=True, DisplayName=name, qb=client)
    if len(customer) == 0:
        logger.debug("creating customer: " + name + " as " + user)
        customer = Customer()
        customer.DisplayName = name
        customer = customer.save(qb=client)
        logger.debug("customer saved")
    else:
        customer = customer[0]
    return customer
示例#3
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
示例#4
0
 def test_order_by_with_qb(self):
     with patch.object(self.qb_client, 'query') as query:
         Customer.filter(Active=True,
                         order_by='DisplayName',
                         qb=self.qb_client)
         self.assertTrue(query.called)
示例#5
0
 def test_order_by(self, query):
     Customer.filter(Active=True, order_by='DisplayName')
     query.assert_called_once_with(
         "SELECT * FROM Customer WHERE Active = True ORDERBY DisplayName",
         qb=None)
示例#6
0
    def index(self):
        '''
        Load all customers and 100 invoices and the correlate them.
        Customers get put into three bins: Ready to invoice, current (no need for an invoice) and WTF (we couldn't sort what should happen).
        Send all this to the caller to render.
        '''

        # Look up access tokens from sessions, or make the user login
        access_token = session.get('access_token', None)
        refresh_token = session.get('refresh_token', "")
        realm = session.get('realm', None)

        if not access_token or not refresh_token:
            session['realm'] = realm
            session['access_token'] = access_token
            session['refresh_token'] = refresh_token
            return render_template("quickbooks/login.html")

        refreshed = False
        while True:
            # Now fetch customers and invoices
            try:
                client = get_client(realm, refresh_token)
                customers = Customer.filter(Active=True, qb=client)
                invoices = Invoice.query(
                    "select * from invoice order by metadata.createtime desc maxresults 300",
                    qb=client)
                break

            except quickbooks.exceptions.AuthorizationException as err:
                current_app.logger.error("Auth failed. Refresh token: '%s'" %
                                         client.refresh_token)
                if not refreshed:
                    current_app.logger.debug("Auth failed, trying refresh")
                    refreshed = True
                    current_app.quickbooks_auth_client.refresh()
                    continue

                flash("Authorization failed, please try again: %s" % err)
                current_app.logger.debug(
                    "Auth failed, logging out, starting over.")
                session['access_token'] = None
                return redirect(url_for("quickbooks/.index"))

            except quickbooks.exceptions.QuickbooksException as err:
                flash("Query failed: %s" % err)
                raise InternalServerError

        # Calculate a pile of dates, based on today date. Figure out
        # which quarter we're in, and the dates of this and 2 prior quarters
        dt = datetime.datetime.now()
        today = dt.strftime("%m-%d-%Y")
        q = (dt.month - 1) // 3
        pq = (q + 3) % 4
        ppq = (pq + 3) % 4

        year = dt.year
        (q_start, q_end) = self.calculate_quarter_dates(year, q)
        if pq > q:
            year -= 1
        (pq_start, pq_end) = self.calculate_quarter_dates(year, pq)
        if ppq > pq:
            year -= 1
        (ppq_start, ppq_end) = self.calculate_quarter_dates(year, ppq)

        # Iterate over all the invoices, parse their dates and arrange them into the invoice dict, by customer
        invoice_dict = {}
        for invoice in invoices:
            customer_id = invoice.CustomerRef.value
            if customer_id not in invoice_dict:
                invoice_dict[customer_id] = []

            create_time = parse(invoice.TxnDate).strftime("%m-%d-%Y")
            try:
                begin_dt = parse(invoice.CustomField[1].StringValue)
                begin_date = begin_dt.strftime("%m-%d-%Y")
            except ValueError:
                begin_date = ""
                begin_dt = None

            try:
                end_dt = parse(invoice.CustomField[2].StringValue)
                end_date = end_dt.strftime("%m-%d-%Y")
            except ValueError:
                end_date = ""
                end_dt = None

            try:
                tier = invoice.Line[0].SalesItemLineDetail.ItemRef.name
            except AttributeError:
                tier = ""

            invoice_dict[customer_id].append({
                'customer':
                customer_id,
                'date':
                create_time,
                'sortdate':
                invoice.TxnDate,
                'id':
                invoice.Id,
                'amount':
                invoice.TotalAmt,
                'begin':
                begin_date,
                'begin_dt':
                begin_dt,
                'end':
                end_date,
                'end_dt':
                end_dt,
                'service':
                tier,
                'number':
                invoice.DocNumber,
                'currency':
                invoice.CurrencyRef.value,
                'qty':
                invoice.Line[0].SalesItemLineDetail.Qty,
                'price':
                invoice.Line[0].SalesItemLineDetail.UnitPrice
            })

        # Finally, classify customers into the three bins
        ready_to_invoice = []
        wtf = []
        current = []
        for customer in customers:
            invoices = invoice_dict.get(customer.Id, [])
            invoices = sorted(invoices,
                              key=lambda invoice: invoice['sortdate'],
                              reverse=True)

            # If there are comments in the customer notes field that indicates # arrears or # donotinvoice,
            # we use those as hints to properly create new invoices or to ignore customers
            name = customer.DisplayName or customer.CompanyName
            desc = customer.Notes.lower()
            try:
                price = invoices[0]['price']
            except IndexError:
                price = 0

            if desc.find("arrears") >= 0:
                name += " (arrears)"
                is_arrears = True
            else:
                is_arrears = False

            if desc.find("donotinvoice") >= 0:
                do_not_invoice = True
                name += " (do not invoice)"
            else:
                do_not_invoice = False

            # create the customer object, ready for saving
            cust = {'name': name, 'invoices': invoices, 'id': customer.Id}
            if do_not_invoice:
                current.append(cust)
                continue

            # If there are no previous invoices, go WTF!
            if not invoices:
                wtf.append(cust)
                continue

            # If this customer should not be invoiced or if the last invoice corresponds to this quarter,
            # place them into the current bin
            if do_not_invoice or (invoices[0]['begin'] == q_start
                                  and invoices[0]['end'] == q_end):
                current.append(cust)
                continue

            # If the customer is not invoiced in arrears and the last invoice looks to be from last quarter -> ready to invoice
            if not is_arrears and invoices[0][
                    'begin'] == pq_start and invoices[0]['end'] == pq_end:
                self.add_new_invoice(invoices[0], cust, q_start, q_end, today,
                                     3, price)
                ready_to_invoice.append(cust)
                continue

            # If the customer is not invoiced in arrears and the last invoice is a partial invoice last quarter -> ready to invoice new customer
            if not is_arrears and invoices[0]['end'] == pq_end:
                cust['name'] += " (new customer)"
                self.add_new_invoice(invoices[0], cust, q_start, q_end, today,
                                     3, price)
                ready_to_invoice.append(cust)
                continue

            # If the customer is invoiced in arrears and the last invoice looks to be from last last quarter -> ready to invoice
            if is_arrears and invoices[0]['begin'] == ppq_start and invoices[
                    0]['end'] == ppq_end:
                self.add_new_invoice(invoices[0], cust, pq_start, pq_end,
                                     today, 3, price)
                ready_to_invoice.append(cust)
                continue

            # If the customer is invoiced in arrears and the last invoice was from the prior quarter -> current
            if is_arrears and invoices[0]['begin'] == pq_start and invoices[0][
                    'end'] == pq_end:
                current.append(cust)
                continue

            # Check to see if this is an annual invoice
            try:
                end_dt = invoices[0]['end_dt']
                begin_dt = invoices[0]['begin_dt']
                delta = end_dt - begin_dt
                if delta.days > 359 and delta.days < 366:
                    cust['name'] += " (annual)"
                    if time.mktime(end_dt.timetuple()) <= time.time():
                        end_date = datetime.date(
                            end_dt.year + 1, end_dt.month,
                            end_dt.day).strftime("%m-%d-%Y")
                        begin_date = datetime.date(
                            begin_dt.year + 1, begin_dt.month,
                            begin_dt.day).strftime("%m-%d-%Y")
                        self.add_new_invoice(invoices[0], cust, begin_date,
                                             end_date, today, 12, price)
                        ready_to_invoice.append(cust)
                    else:
                        current.append(cust)

                    continue
            except TypeError:
                wtf.append(cust)
                continue

            # If the end date is after the curent date, then consider it current
            if time.mktime(end_dt.timetuple()) > time.time():
                current.append(cust)
                continue

            # Everyone else, WTF?
            wtf.append(cust)

        return render_template("quickbooks/index.html",
                               ready=ready_to_invoice,
                               wtf=wtf,
                               current=current)
示例#7
0
def qbo_find_sales_account():
    client = create_qbc()
    account = Customer.filter(Active=True, Name="Sales", qb=client)
    return account[0].Id