Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Is there an easy way to create an customer/invoice via this project? #38

Open
Ryang20718 opened this issue Apr 8, 2024 · 14 comments
Open

Comments

@Ryang20718
Copy link

I see there's classes such as Customer, Invoice which I presume are created for common use cases.

Say my goal is to programmatically create a customer/invoice, is there a quickstart guide for doing so?

I.e once I'm authed with QB desktop, is there a way to create a customer and send that request to the webconnector to process?
either via raw xml or a model?

If yall could post a short snippet on either this README example https://github.com/weltlink/django-quickbooks#implementation

or provide guidance on how I would add this customer to the QBD Task queue, that would be greatly appreciated!
Trying to understand what the django_quickbooks.services is used for....

from django_quickbooks.objects import BillAddress, ShipAddress, Customer
from django_quickbooks.services.customer import CustomerService
from lxml import etree

customer_xml = """<?xml version="1.0"?><?qbxml version="13.0"?>
<QBXML>
    <QBXMLMsgsRq onError="stopOnError">
        <CustomerAddRq>
            <CustomerAdd>
                <Name>Amazon</Name>
                <FullName>Amazon</FullName>
                <IsActive>true</IsActive>
                <CompanyName>Amazon</CompanyName>
                <BillAddress>
                    <Addr1>2305 Litton Ln</Addr1>
                    <City>Hebron</City>
                    <State>Kentucky</State>
                    <PostalCode>41048</PostalCode>
                    <Country>United States</Country>
                    <Note>Nice address</Note>
                </BillAddress>
                <ShipAddress>
                    <Addr1>2305 Litton Ln</Addr1>
                    <City>Hebron</City>
                    <State>Kentucky</State>
                    <PostalCode>41048</PostalCode>
                    <Country>United States</Country>
                    <Note>Nice address</Note>
                </ShipAddress>
                <Phone>998909090909</Phone>
                <AltPhone>998909090910</AltPhone>
                <Fax>998909090911</Fax>
                <Email>[email protected]</Email>
                <Contact>Someone from Amazon</Contact>
                <AltContact>Some other one from Amazon</AltContact>
            </CustomerAdd>
        </CustomerAddRq>
    </QBXMLMsgsRq>
</QBXML>"""

root_lxml = etree.fromstring(customer_xml)
customer = Customer.from_lxml(root_lxml)
cs = CustomerService()
cs.add(customer)
@hassaanalansary
Copy link
Collaborator

hassaanalansary commented Apr 8, 2024

Hello @Ryang20718

you need to create a QBDTask to sync your Model object to

This is a snippet pulled from my production code

# Add something like this to your post_save signal.
            QBDTask.objects.update_or_create(
                qb_operation=QUICKBOOKS_ENUMS.OPP_MOD,
                qb_resource=QUICKBOOKS_ENUMS.RESOURCE_CUSTOMER_POS,
                object_id=instance.id,
                content_type=ContentType.objects.get_for_model(instance),
                realm_id=YOUR_REALM_ID,
            )

it should call you ModelClass.to_qbd_obj()

Something Extra
you may also want to add something
like this to handle the signal coming back from QB in your settings.py if you want to get qbd_object_id propagated into your DB

QBWC_SETTINGS = {
"LOCAL_MODEL_CLASSES": {
        "CustomerPOS": "Inventory.models.Customer",
        "ItemInventoryPOS": "Inventory.models.Sku",
        "VoucherPOS": "Inventory.models.OrderVoucher",
    },
    "RESPONSE_PROCESSORS": (),
    "POS_RESPONSE_PROCESSORS": (
        "Inventory.qbd.ItemInventoryResponseProcessor",
        "Inventory.qbd.SkuAddResponseProcessor", # Custom one I made
        "django_quickbooks.processors.VoucherQueryResponseProcessor", # Default one
    ),
}

notice that `POS_RESPONSE_PROCESSORS` are only in my fork because it supports QBPOS
you can use `RESPONSE_PROCESSORS` for QB Finance

let me know if you find this helpful or if you need more help

@Ryang20718
Copy link
Author

@hassaanalansary Really appreciate the help here! If you could provide some pointers on where to place the QBDTask in relationship to a class, I think that would clear up all my confusion!

so I would need to create a class in order to leverage the customer/invoice classes

i.e if I have this in my models.py

class Customer(QBDModelMixin):
    first_name = models.CharField(max_length=255, null=True)
    last_name = models.CharField(max_length=255, null=True)
    email = models.CharField(max_length=255, blank=True, null=True)
    phone = models.CharField(max_length=10)
    street = models.CharField(max_length=255, blank=True, null=True)
    zip = models.CharField(max_length=255, blank=True, null=True)
    city = models.CharField(max_length=255, blank=True, null=True)
    state = models.CharField(max_length=255, blank=True, null=True)
    
    def __str__(self):
        return f'{self.first_name} {self.last_name}'
           
    def to_qbd_obj(self, **fields):
        from django_quickbooks.objects import Customer as QBCustomer
        # map your fields to the qbd_obj fields
        return QBCustomer(Name=self.__str__(),
                          IsActive=True,
                          Phone=self.phone,
                          )

    @classmethod			  
    def from_qbd_obj(cls, qbd_obj):
        # map qbd_obj fields to your model fields
        return cls(
            first_name=qbd_obj.Name,
            phone=qbd_obj.Phone,
            qbd_object_id=qbd_obj.ListID,
            qbd_object_version=qbd_obj.EditSequence
        )

in my views.py,

I can instantiate the object

	from .models import Customer
	sample_customer = Customer(
		first_name="John",
		last_name="Doe",
		email="[email protected]",
		phone="1234567890",
		street="123 Main St",
		zip="12345",
		city="Anytown",
		state="CA"
	)

However, based on your snippet above,
where am I supposed to place the following? I understand the realm ID is based on the QWC, but what object is instance supposed to be? is that supposed to be the instance of the object?

            QBDTask.objects.update_or_create(
                qb_operation=QUICKBOOKS_ENUMS.OPP_MOD,
                qb_resource=QUICKBOOKS_ENUMS.RESOURCE_CUSTOMER_POS,
                object_id=instance.id,
                content_type=ContentType.objects.get_for_model(instance),
                realm_id=YOUR_REALM_ID,
            )

@hassaanalansary
Copy link
Collaborator

Instance is supposed to be Customer in your case

@Ryang20718
Copy link
Author

so If I have the following Customer class defined above in models.py

and the following in views.py, navigating to the URL to invoke hello should add a task to the QBWC?

from django.shortcuts import render
from django.http import HttpResponse

from django_quickbooks.models import QBDTask
from django_quickbooks import QUICKBOOKS_ENUMS
from django.contrib.contenttypes.models import ContentType
from django_quickbooks.services.invoice import InvoiceService
from django_quickbooks.services.customer import CustomerService
from qbPy.models import Customer

def create_customer():
	sample_customer = Customer(
		first_name="John",
		last_name="Doe",
		email="[email protected]",
		phone="1234567890",
		street="123 Main St",
		zip="12345",
		city="Anytown",
		state="CA"
	)

	QBDTask.objects.update_or_create(
		qb_operation=QUICKBOOKS_ENUMS.OPP_MOD,
		qb_resource=QUICKBOOKS_ENUMS.RESOURCE_CUSTOMER,
		object_id=sample_customer.id,
		content_type=ContentType.objects.get_for_model(sample_customer),
		realm_id="073924d0-30a1-4e53-b8ce-121f184ae6d3",
	)

def hello(request):
	create_customer()
	return HttpResponse("Tried creating a customer")

Assuming QuickBooks Desktop is Auth'd and connected to QBWC, if I were to invoke the app via update selected in QBWC, I should be seeing the customer appear in QB desktop right? Currently I'm not quite sure if this is correct or if I'm missing something? 😅
png-qb

@hassaanalansary
Copy link
Collaborator

Yes, however your code doesn't really create the customer in the database
You should .save()
And make sure you have redis working

@Ryang20718
Copy link
Author

ah, I see

I changed django_quickbooks to use redismanager rather than rabbit mq in the settings and have a redis server running.

I think I'm getting closer to reaching the final step of creating a customer programatically ❗ However, parsing the XML response results in an exception when trying to dynamically import... is this expected?

full code
from django.shortcuts import render
from django.http import HttpResponse

from django_quickbooks.models import QBDTask
from django_quickbooks import QUICKBOOKS_ENUMS
from django.contrib.contenttypes.models import ContentType
from django_quickbooks.services.invoice import InvoiceService
from django_quickbooks.services.customer import CustomerService
from qbPy.models import Customer

def create_customer():
	sample_customer = Customer(
		first_name="Joh2n",
		last_name="Doe",
		email="[email protected]",
		phone="1234567890",
		street="123 Main St",
		zip="12345",
		city="Anytown",
		state="CA"
	)
	sample_customer.save()
	QBDTask.objects.update_or_create(
		qb_operation=QUICKBOOKS_ENUMS.OPP_MOD,
		qb_resource=QUICKBOOKS_ENUMS.RESOURCE_CUSTOMER,
		object_id=sample_customer.id,
		content_type=ContentType.objects.get_for_model(sample_customer),
		realm_id="795c2f85-00a3-4f1d-9968-8e6bbf971da5",
	)

def hello(request):
	create_customer()
	return HttpResponse("Tried creating a customer")

stack trace
sendRequestXML() has been called
ticket: d96ddcf4-f574-11ee-ba0d-e7cd672c55f7
strHCPResponse <?xml version="1.0" ?>
<QBXML>
<QBXMLMsgsRs>
<HostQueryRs requestID="0" statusCode="0" statusSeverity="Info" statusMessage="Status OK">
<HostRet>
<ProductName>Intuit QuickBooks Enterprise Solutions 23.0</ProductName>
<MajorVersion>33</MajorVersion>
<MinorVersion>0</MinorVersion>
<Country>US</Country>
<SupportedQBXMLVersion>1.0</SupportedQBXMLVersion>
<SupportedQBXMLVersion>1.1</SupportedQBXMLVersion>
<SupportedQBXMLVersion>2.0</SupportedQBXMLVersion>
<SupportedQBXMLVersion>2.1</SupportedQBXMLVersion>
<SupportedQBXMLVersion>3.0</SupportedQBXMLVersion>
<SupportedQBXMLVersion>4.0</SupportedQBXMLVersion>
<SupportedQBXMLVersion>4.1</SupportedQBXMLVersion>
<SupportedQBXMLVersion>5.0</SupportedQBXMLVersion>
<SupportedQBXMLVersion>6.0</SupportedQBXMLVersion>
<SupportedQBXMLVersion>7.0</SupportedQBXMLVersion>
<SupportedQBXMLVersion>8.0</SupportedQBXMLVersion>
<SupportedQBXMLVersion>9.0</SupportedQBXMLVersion>
<SupportedQBXMLVersion>10.0</SupportedQBXMLVersion>
<SupportedQBXMLVersion>11.0</SupportedQBXMLVersion>
<SupportedQBXMLVersion>12.0</SupportedQBXMLVersion>
<SupportedQBXMLVersion>13.0</SupportedQBXMLVersion>
<SupportedQBXMLVersion>14.0</SupportedQBXMLVersion>
<SupportedQBXMLVersion>15.0</SupportedQBXMLVersion>
<SupportedQBXMLVersion>16.0</SupportedQBXMLVersion>
<IsAutomaticLogin>false</IsAutomaticLogin>
<QBFileMode>SingleUser</QBFileMode>
</HostRet>
</HostQueryRs>
<CompanyQueryRs requestID="1" statusCode="0" statusSeverity="Info" statusMessage="Status OK">
<CompanyRet>
<IsSampleCompany>false</IsSampleCompany>
<CompanyName>testing123</CompanyName>
<LegalCompanyName>testing123</LegalCompanyName>
<Address>
<State>LA</State>
<Country>US</Country>
</Address>
<AddressBlock>
<Addr1>LA </Addr1>
</AddressBlock>
<LegalAddress>
<State>LA</State>
<Country>US</Country>
</LegalAddress>
<Email>[email protected]</Email>
<FirstMonthFiscalYear>January</FirstMonthFiscalYear>
<FirstMonthIncomeTaxYear>January</FirstMonthIncomeTaxYear>
<TaxForm>Form1040</TaxForm>
<SubscribedServices>
<Service>
<Name>QuickBooks Online Banking</Name>
<Domain>banking.qb</Domain>
<ServiceStatus>Never</ServiceStatus>
</Service>
<Service>
<Name>QuickBooks Online Billing</Name>
<Domain>billing.qb</Domain>
<ServiceStatus>Never</ServiceStatus>
</Service>
<Service>
<Name>QuickBooks Online Billing Level 1 Service</Name>
<Domain>qbob1.qbn</Domain>
<ServiceStatus>Never</ServiceStatus>
</Service>
<Service>
<Name>QuickBooks Online Billing Level 2 Service</Name>
<Domain>qbob2.qbn</Domain>
<ServiceStatus>Never</ServiceStatus>
</Service>
<Service>
<Name>QuickBooks Online Billing Payment Service</Name>
<Domain>qbobpay.qbn</Domain>
<ServiceStatus>Never</ServiceStatus>
</Service>
<Service>
<Name>QuickBooks Bill Payment</Name>
<Domain>billpay.qb</Domain>
<ServiceStatus>Never</ServiceStatus>
</Service>
<Service>
<Name>QuickBooks Online Billing Paper Mailing Service</Name>
<Domain>qbobpaper.qbn</Domain>
<ServiceStatus>Never</ServiceStatus>
</Service>
<Service>
<Name>QuickBooks Payroll Service</Name>
<Domain>payroll.qb</Domain>
<ServiceStatus>Never</ServiceStatus>
</Service>
<Service>
<Name>QuickBooks Basic Payroll Service</Name>
<Domain>payrollbsc.qb</Domain>
<ServiceStatus>Never</ServiceStatus>
</Service>
<Service>
<Name>QuickBooks Basic Disk Payroll Service</Name>
<Domain>payrollbscdisk.qb</Domain>
<ServiceStatus>Never</ServiceStatus>
</Service>
<Service>
<Name>QuickBooks Deluxe Payroll Service</Name>
<Domain>payrolldlx.qb</Domain>
<ServiceStatus>Never</ServiceStatus>
</Service>
<Service>
<Name>QuickBooks Premier Payroll Service</Name>
<Domain>payrollprm.qb</Domain>
<ServiceStatus>Never</ServiceStatus>
</Service>
<Service>
<Name>Basic Plus Federal</Name>
<Domain>basic_plus_fed.qb</Domain>
<ServiceStatus>Never</ServiceStatus>
</Service>
<Service>
<Name>Basic Plus Federal and State</Name>
<Domain>basic_plus_fed_state.qb</Domain>
<ServiceStatus>Never</ServiceStatus>
</Service>
<Service>
<Name>Basic Plus Direct Deposit</Name>
<Domain>basic_plus_dd.qb</Domain>
<ServiceStatus>Never</ServiceStatus>
</Service>
<Service>
<Name>Merchant Account Service</Name>
<Domain>mas.qbn</Domain>
<ServiceStatus>Never</ServiceStatus>
</Service>
</SubscribedServices>
<AccountantCopy>
<AccountantCopyExists>false</AccountantCopyExists>
</AccountantCopy>
<DataExtRet>
<OwnerID>{55a9fd50-79e9-44e4-8fef-98411c2e8785}</OwnerID>
<DataExtName>AppLock</DataExtName>
<DataExtType>STR255TYPE</DataExtType>
<DataExtValue>LOCKED:BP-W-03:638481560711509765</DataExtValue>
</DataExtRet>
<DataExtRet>
<OwnerID>{55a9fd50-79e9-44e4-8fef-98411c2e8785}</OwnerID>
<DataExtName>FileID</DataExtName>
<DataExtType>STR255TYPE</DataExtType>
<DataExtValue>{30830c9c-c1b7-4773-a12d-b193437a8fef}</DataExtValue>
</DataExtRet>
</CompanyRet>
</CompanyQueryRs>
<PreferencesQueryRs requestID="2" statusCode="0" statusSeverity="Info" statusMessage="Status OK">
<PreferencesRet>
<AccountingPreferences>
<IsUsingAccountNumbers>false</IsUsingAccountNumbers>
<IsRequiringAccounts>true</IsRequiringAccounts>
<IsUsingClassTracking>false</IsUsingClassTracking>
<IsUsingAuditTrail>true</IsUsingAuditTrail>
<IsAssigningJournalEntryNumbers>true</IsAssigningJournalEntryNumbers>
</AccountingPreferences>
<FinanceChargePreferences>
<AnnualInterestRate>0.00</AnnualInterestRate>
<MinFinanceCharge>0.00</MinFinanceCharge>
<GracePeriod>0</GracePeriod>
<IsAssessingForOverdueCharges>false</IsAssessingForOverdueCharges>
<CalculateChargesFrom>DueDate</CalculateChargesFrom>
<IsMarkedToBePrinted>false</IsMarkedToBePrinted>
</FinanceChargePreferences>
<JobsAndEstimatesPreferences>
<IsUsingEstimates>true</IsUsingEstimates>
<IsUsingProgressInvoicing>false</IsUsingProgressInvoicing>
<IsPrintingItemsWithZeroAmounts>false</IsPrintingItemsWithZeroAmounts>
</JobsAndEstimatesPreferences>
<MultiCurrencyPreferences>
<IsMultiCurrencyOn>false</IsMultiCurrencyOn>
</MultiCurrencyPreferences>
<MultiLocationInventoryPreferences>
<IsMultiLocationInventoryAvailable>false</IsMultiLocationInventoryAvailable>
<IsMultiLocationInventoryEnabled>false</IsMultiLocationInventoryEnabled>
</MultiLocationInventoryPreferences>
<PurchasesAndVendorsPreferences>
<IsUsingInventory>false</IsUsingInventory>
<DaysBillsAreDue>10</DaysBillsAreDue>
<IsAutomaticallyUsingDiscounts>false</IsAutomaticallyUsingDiscounts>
</PurchasesAndVendorsPreferences>
<ReportsPreferences>
<AgingReportBasis>AgeFromDueDate</AgingReportBasis>
<SummaryReportBasis>Accrual</SummaryReportBasis>
</ReportsPreferences>
<SalesAndCustomersPreferences>
<IsTrackingReimbursedExpensesAsIncome>false</IsTrackingReimbursedExpensesAsIncome>
<IsAutoApplyingPayments>true</IsAutoApplyingPayments>
<PriceLevels>
<IsUsingPriceLevels>true</IsUsingPriceLevels>
<IsRoundingSalesPriceUp>true</IsRoundingSalesPriceUp>
</PriceLevels>
</SalesAndCustomersPreferences>
<TimeTrackingPreferences>
<FirstDayOfWeek>Monday</FirstDayOfWeek>
</TimeTrackingPreferences>
<CurrentAppAccessRights>
<IsAutomaticLoginAllowed>true</IsAutomaticLoginAllowed>
<AutomaticLoginUserName>Admin</AutomaticLoginUserName>
<IsPersonalDataAccessAllowed>false</IsPersonalDataAccessAllowed>
</CurrentAppAccessRights>
<ItemsAndInventoryPreferences>
<EnhancedInventoryReceivingEnabled>false</EnhancedInventoryReceivingEnabled>
<IsTrackingSerialOrLotNumber>None</IsTrackingSerialOrLotNumber>
<IsInventoryExpirationDateEnabled>false</IsInventoryExpirationDateEnabled>
<FIFOEnabled>false</FIFOEnabled>
<IsRSBEnabled>false</IsRSBEnabled>
<IsBarcodeEnabled>false</IsBarcodeEnabled>
</ItemsAndInventoryPreferences>
</PreferencesRet>
</PreferencesQueryRs>
</QBXMLMsgsRs>
</QBXML>

strCompanyFileName C:\Users\Public\Documents\Intuit\QuickBooks\Company Files\testing123.qbw
qbXMLCountry US
[08/Apr/2024 06:54:32] "POST /qwc/ HTTP/1.1" 200 659
receiveResponseXML()
ticket=d96ddcf4-f574-11ee-ba0d-e7cd672c55f7
response=
hresult=0x80040400
message=QuickBooks found an error when parsing the provided XML text stream.
FK
not enough values to unpack (expected 2, got 1)
Traceback (most recent call last):
  File "/root/quickbooks-py/.venv/lib/python3.10/site-packages/spyne/application.py", line 173, in process_request
    ctx.out_object = self.call_wrapper(ctx)
  File "/root/quickbooks-py/.venv/lib/python3.10/site-packages/spyne/application.py", line 242, in call_wrapper
    return ctx.descriptor.service_class.call_wrapper(ctx)
  File "/root/quickbooks-py/.venv/lib/python3.10/site-packages/spyne/service.py", line 194, in call_wrapper
    return ctx.function(*args)
  File "/root/quickbooks-py/.venv/src/django-quickbooks/django_quickbooks/views/service.py", line 174, in receiveResponseXML
    return session_manager.process_response(ticket, response, hresult, message)
  File "/root/quickbooks-py/.venv/src/django-quickbooks/django_quickbooks/session_manager.py", line 64, in process_response
    processors = get_processors()
  File "/root/quickbooks-py/.venv/src/django-quickbooks/django_quickbooks/__init__.py", line 70, in get_processors
    for processor_class in qbwc_settings.RESPONSE_PROCESSORS:
  File "/root/quickbooks-py/.venv/src/django-quickbooks/django_quickbooks/settings.py", line 126, in __getattr__
    val = perform_import(val, attr)
  File "/root/quickbooks-py/.venv/src/django-quickbooks/django_quickbooks/settings.py", line 75, in perform_import
    return [import_from_string(item, setting_name) for item in val]
  File "/root/quickbooks-py/.venv/src/django-quickbooks/django_quickbooks/settings.py", line 75, in <listcomp>
    return [import_from_string(item, setting_name) for item in val]
  File "/root/quickbooks-py/.venv/src/django-quickbooks/django_quickbooks/settings.py", line 88, in import_from_string
    module = import_module(module_path)
  File "/usr/lib/python3.10/importlib/__init__.py", line 126, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 1050, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1027, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1006, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 688, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 883, in exec_module
  File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
  File "/root/quickbooks-py/.venv/src/django-quickbooks/django_quickbooks/processors/__init__.py", line 4, in <module>
    from django_quickbooks.processors.customer import \
  File "/root/quickbooks-py/.venv/src/django-quickbooks/django_quickbooks/processors/customer.py", line 5, in <module>
    LocalCustomer = qbwc_settings.LOCAL_MODEL_CLASSES['Customer']
  File "/root/quickbooks-py/.venv/src/django-quickbooks/django_quickbooks/settings.py", line 130, in __getattr__
    val[key] = import_from_string(value, value)
  File "/root/quickbooks-py/.venv/src/django-quickbooks/django_quickbooks/settings.py", line 87, in import_from_string
    module_path, class_name = val.rsplit('.', 1)
ValueError: not enough values to unpack (expected 2, got 1)

@hassaanalansary
Copy link
Collaborator

hassaanalansary commented Apr 8, 2024

I noticed 2 things
You are trying to perform an action on the Customer resource in QB but you didn't provide django_quiclbooks with the mapping between your Customer model and qb Cusotmer model.

You need to add 'Customer' to your LOCAL_MODEL_CLASSES in settings.py
And you are issuing qb_operation=QUICKBOOKS_ENUMS.OPP_MOD on a non existent customer

@Ryang20718
Copy link
Author

Added a check when importing

        if "." not in val:
            return

and switching the enums to OP_ADD worked :). Appreciate all the help!

Sorry to abuse this issue for an unrelated question; what steps would I need to take to query existing customers already in quickbooks that I haven't added from this django app? (I assume sending an XML to query should be sufficient, but is there an example on how to do so?)

@hassaanalansary
Copy link
Collaborator

sorry missed your message:
I imagine you have figured it out by now

you can do so by add QBDTask for qb_operation=QUICKBOOKS_ENUMS.OPP_QR to the Resource that you want to query

@hassaanalansary
Copy link
Collaborator

If you want, can you please open a PR with documentation about the issues that you have faced and how you have fixed them?
This will others trying to use this project.

@Ryang20718
Copy link
Author

If you want, can you please open a PR with documentation about the issues that you have faced and how you have fixed them?
This will others trying to use this project.

Definitely, I can do that. Hoping to do that once I confirm I have a solid understanding of querying as well 😓

@Ryang20718
Copy link
Author

Ryang20718 commented Apr 15, 2024

you can do so by add QBDTask for qb_operation=QUICKBOOKS_ENUMS.OPP_QR to the Resource that you want to query

here's what I did.

I created a customer from quickbooks UI and then wanted to see if I could fetch that object via a query. Query is below. I received an XML response. However, is this right? I assume after reading the xml, I can just convert the xml to the actual object?

def query_customer():
	print("QUERYING CUSTOMER")
	sample_customer = CustomerModel(
		first_name="john",
		last_name="doe33",
		email="[email protected]",
		phone="1234567890",
		street="123 Main St",
		zip="12345",
		city="Anytown",
		state="CA"
	)
	sample_customer.save()
	res = QBDTask.objects.update_or_create(
		qb_operation=QUICKBOOKS_ENUMS.OPP_QR,
		qb_resource=QUICKBOOKS_ENUMS.RESOURCE_CUSTOMER,
		object_id=sample_customer.id,
		content_type=ContentType.objects.get_for_model(sample_customer),
		realm_id="af1a9c3c-fdbc-45a2-9b2d-57646df3dc19",
	)
	print("FINISHED QUERYING", sample_customer)

What's not clear to me is:

  • From reading the code, it seems this library should only be able to fetch objects that were previously created using this library? Is it possible to read an object from quickbooks that wasn't created with this library?

@hassaanalansary
Copy link
Collaborator

when you issue the query task. QB desktop will send you the customers in a response

all responses are handled ResponseProcessor
refer to my first comment
you need to define RESPONSE_PROCESSORS in your settings.py
either use the builtin processors or you can define one and use it
"RESPONSE_PROCESSORS": (),
this is the builtin customers response processors

class CustomerQueryResponseProcessor(ResponseProcessor, ResponseProcessorMixin):
    resource = QUICKBOOKS_ENUMS.RESOURCE_CUSTOMER
    op_type = QUICKBOOKS_ENUMS.OPP_QR
    local_model_class = LocalCustomer
    obj_class = Customer

    def process(self, realm):
        cont = super().process(realm)
        if not cont:
            return False
        for customer_ret in list(self._response_body):
            customer = self.obj_class.from_lxml(customer_ret)
            local_customer = None
            if customer.ListID:
                local_customer = self.find_by_list_id(customer.ListID)
            if not local_customer and customer.Name:
                local_customer = self.find_by_name(customer.Name)

            if local_customer:
                self.update(local_customer, customer)
            else:
                self.create(customer)
        return True

you can inherit from it or define your own

if you have more questions you can send me an email, I will be more than happy to get in a meeting with you.

@Ryon-NG
Copy link

Ryon-NG commented Aug 8, 2024

Hi there! XML/QB noob here, this thread has already been super helpful in programmatic customer creation. Would you mind also posting your solution to creating an invoice?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants