diff --git a/django_quickbooks/__init__.py b/django_quickbooks/__init__.py
index 574e05f..765ee7d 100644
--- a/django_quickbooks/__init__.py
+++ b/django_quickbooks/__init__.py
@@ -46,6 +46,8 @@ class QUICKBOOKS_ENUMS:
RESOURCE_BILL = 'Bill'
RESOURCE_ITEM_SERVICE = 'ItemService'
RESOURCE_TXN = 'Txn'
+ RESOURCE_ITEM_INVENTORY_POS = 'ItemInventory'
+ RESOURCE_DEPARTMENT = 'Department'
class QBXML_RESPONSE_STATUS_CODES:
diff --git a/django_quickbooks/data/pos/customer_add_request.xml b/django_quickbooks/data/pos/customer_add_request.xml
new file mode 100644
index 0000000..073ff62
--- /dev/null
+++ b/django_quickbooks/data/pos/customer_add_request.xml
@@ -0,0 +1,77 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+STRTYPE
+ STRTYPE
+ FLOATTYPE
+
+ ENUMTYPE
+ STRTYPE
+ STRTYPE
+ BOOLTYPE
+ STRTYPE
+ BOOLTYPE
+ BOOLTYPE
+ BOOLTYPE
+ BOOLTYPE
+ BOOLTYPE
+ STRTYPE
+ STRTYPE
+ STRTYPE
+ STRTYPE
+ STRTYPE
+ STRTYPE
+
+ ENUMTYPE
+ STRTYPE
+ STRTYPE
+
+ STRTYPE
+ STRTYPE
+ STRTYPE
+ STRTYPE
+ STRTYPE
+ STRTYPE
+
+ STRTYPE
+
+ STRTYPE
+ STRTYPE
+ STRTYPE
+ STRTYPE
+ STRTYPE
+ STRTYPE
+ STRTYPE
+ STRTYPE
+ STRTYPE
+
+
+
+
+
diff --git a/django_quickbooks/data/pos/department_add_request.xml b/django_quickbooks/data/pos/department_add_request.xml
new file mode 100644
index 0000000..e3f27ad
--- /dev/null
+++ b/django_quickbooks/data/pos/department_add_request.xml
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ INTTYPE
+ INTTYPE
+ STRTYPE
+ STRTYPE
+ STRTYPE
+
+
+
+
diff --git a/django_quickbooks/data/pos/item_inventory_add_request.xml b/django_quickbooks/data/pos/item_inventory_add_request.xml
new file mode 100644
index 0000000..51de35b
--- /dev/null
+++ b/django_quickbooks/data/pos/item_inventory_add_request.xml
@@ -0,0 +1,174 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ IDTYPE
+ STRTYPE
+ STRTYPE
+ STRTYPE
+ AMTTYPE
+ IDTYPE
+ STRTYPE
+ STRTYPE
+ STRTYPE
+ BOOLTYPE
+ BOOLTYPE
+ BOOLTYPE
+ BOOLTYPE
+ BOOLTYPE
+
+ ENUMTYPE
+ INTTYPE
+ INTTYPE
+ AMTTYPE
+ QUANTYPE
+ QUANTYPE
+ QUANTYPE
+ QUANTYPE
+ QUANTYPE
+ QUANTYPE
+ QUANTYPE
+ QUANTYPE
+ QUANTYPE
+ QUANTYPE
+ QUANTYPE
+ QUANTYPE
+ QUANTYPE
+ QUANTYPE
+ QUANTYPE
+ QUANTYPE
+ QUANTYPE
+ QUANTYPE
+ QUANTYPE
+ QUANTYPE
+ QUANTYPE
+ QUANTYPE
+ QUANTYPE
+ QUANTYPE
+ QUANTYPE
+ QUANTYPE
+ QUANTYPE
+ QUANTYPE
+ QUANTYPE
+ QUANTYPE
+ QUANTYPE
+ QUANTYPE
+ QUANTYPE
+ QUANTYPE
+ QUANTYPE
+ QUANTYPE
+ QUANTYPE
+ QUANTYPE
+ QUANTYPE
+ QUANTYPE
+ STRTYPE
+ AMTTYPE
+ AMTTYPE
+ AMTTYPE
+ AMTTYPE
+ AMTTYPE
+ AMTTYPE
+ QUANTYPE
+ STRTYPE
+
+ ENUMTYPE
+ STRTYPE
+ STRTYPE
+ STRTYPE
+ STRTYPE
+ IDTYPE
+ STRTYPE
+ AMTTYPE
+ STRTYPE
+ FLOATTYPE
+ STRTYPE
+ STRTYPE
+
+ STRTYPE
+ AMTTYPE
+ QUANTYPE
+ AMTTYPE
+ AMTTYPE
+ AMTTYPE
+ AMTTYPE
+ AMTTYPE
+ STRTYPE
+ STRTYPE
+
+
+ STRTYPE
+ AMTTYPE
+ QUANTYPE
+ AMTTYPE
+ AMTTYPE
+ AMTTYPE
+ AMTTYPE
+ AMTTYPE
+ STRTYPE
+ STRTYPE
+
+
+ STRTYPE
+ AMTTYPE
+ QUANTYPE
+ AMTTYPE
+ AMTTYPE
+ AMTTYPE
+ AMTTYPE
+ AMTTYPE
+ STRTYPE
+ STRTYPE
+
+
+ STRTYPE
+ AMTTYPE
+ STRTYPE
+ IDTYPE
+
+
+ STRTYPE
+ AMTTYPE
+ STRTYPE
+ IDTYPE
+
+
+ STRTYPE
+ AMTTYPE
+ STRTYPE
+ IDTYPE
+
+
+ STRTYPE
+ AMTTYPE
+ STRTYPE
+ IDTYPE
+
+
+
+
+
diff --git a/django_quickbooks/data/pos/item_inventory_add_response.xml b/django_quickbooks/data/pos/item_inventory_add_response.xml
new file mode 100644
index 0000000..1d1c0a4
--- /dev/null
+++ b/django_quickbooks/data/pos/item_inventory_add_response.xml
@@ -0,0 +1,49 @@
+
+
+
+
+
+ 4830375467175280897
+ 2020-02-21T17:50:02+02:00
+ 1.00
+ SYS
+ 1000000001
+ Long Sleeve. Collared
+ Clothing. Toddler. Tops. Long Sleeve. Collared.
+ False
+ True
+ True
+ False
+ 15
+ Inventory
+ 75
+ 300
+ 0.00
+ 1.00
+ 0.00
+ 4.00
+ 3.60
+ 3.60
+ 3.60
+ 1.00
+ 0.00
+ 0.00
+ Optional
+ Modified
+ Tax
+
+ 0.00
+
+
+ 0.00
+
+
+ 0.00
+
+
+ 0.00
+
+
+
+
+
\ No newline at end of file
diff --git a/django_quickbooks/models.py b/django_quickbooks/models.py
index a30ccd4..3bd2d47 100644
--- a/django_quickbooks/models.py
+++ b/django_quickbooks/models.py
@@ -18,6 +18,7 @@ class RealmMixin(models.Model):
id = models.UUIDField(primary_key=True, editable=False, default=uuid4)
name = models.CharField(max_length=155)
password = models.CharField(max_length=128, null=True)
+ qb_type = models.CharField(max_length=5, choices=[('QBFS', 'QBFS'), ('QBPOS', 'QBPOS'), ('QBO', 'QBO')])
objects = RealmQuerySet.as_manager()
@@ -66,11 +67,17 @@ class QBDTaskMixin(models.Model):
class Meta:
abstract = True
+ @property
+ def realm(self):
+ raise NotImplementedError(
+ "'realm' field is required, please add ForeignKey field representing your Realm model")
+
objects = QBDTaskQuerySet.as_manager()
def get_request(self):
obj_class = import_object_cls(self.qb_resource)
service = obj_class.get_service()()
+ service.qb_type = self.realm.qb_type # to generate proper XML
obj = self.content_object if self.content_type and self.object_id else None
if self.qb_operation == QUICKBOOKS_ENUMS.OPP_QR:
diff --git a/django_quickbooks/objects/__init__.py b/django_quickbooks/objects/__init__.py
index 72f7612..9d49f4a 100644
--- a/django_quickbooks/objects/__init__.py
+++ b/django_quickbooks/objects/__init__.py
@@ -29,3 +29,12 @@ def import_object_cls(resource_name):
ItemService, \
InvoiceLine, \
Invoice
+
+from django_quickbooks.objects.customer_pos import \
+ Customer as CustomerPOS
+
+from django_quickbooks.objects.item_inventory_pos import \
+ ItemInventory
+
+from django_quickbooks.objects.department_pos import \
+ Department
diff --git a/django_quickbooks/objects/customer_pos.py b/django_quickbooks/objects/customer_pos.py
new file mode 100644
index 0000000..cb88286
--- /dev/null
+++ b/django_quickbooks/objects/customer_pos.py
@@ -0,0 +1,35 @@
+from django_quickbooks.objects.base import BaseObject
+from django_quickbooks.validators import SchemeValidator
+
+
+class Customer(BaseObject):
+ fields = dict(
+ CompanyName=dict(validator=dict(type=SchemeValidator.STRTYPE)),
+ # CustomerDiscType may have one of the following values: None,PriceLevel,Percentage
+ CustomerDiscType=dict(validator=dict(type=SchemeValidator.STRTYPE)),
+ EMail=dict(validator=dict(type=SchemeValidator.STRTYPE)),
+ FirstName=dict(validator=dict(type=SchemeValidator.STRTYPE)),
+ LastName=dict(required=True, validator=dict(type=SchemeValidator.STRTYPE)),
+ Phone=dict(validator=dict(type=SchemeValidator.STRTYPE)),
+ Notes=dict(validator=dict(type=SchemeValidator.STRTYPE)),
+ Phone2=dict(validator=dict(type=SchemeValidator.STRTYPE)),
+ # PriceLevelNumber may have one of the following values: 1,2,3,4
+ PriceLevelNumber=dict(validator=dict(type=SchemeValidator.STRTYPE)),
+ Salutation=dict(validator=dict(type=SchemeValidator.STRTYPE)),
+ BillAddress=dict(validator=dict(type=SchemeValidator.OBJTYPE)),
+ ShipAddress=dict(validator=dict(type=SchemeValidator.OBJTYPE)),
+ )
+
+ def __init__(self, Name=None, IsActive=None, **kwargs):
+ if Name:
+ self.Name = Name
+
+ if IsActive:
+ self.IsActive = IsActive
+
+ super().__init__(**kwargs)
+
+ @staticmethod
+ def get_service():
+ from django_quickbooks.services.customer import CustomerService
+ return CustomerService
diff --git a/django_quickbooks/objects/department_pos.py b/django_quickbooks/objects/department_pos.py
new file mode 100644
index 0000000..b0e6183
--- /dev/null
+++ b/django_quickbooks/objects/department_pos.py
@@ -0,0 +1,23 @@
+from django_quickbooks.objects.base import BaseObject
+from django_quickbooks.validators import SchemeValidator
+
+
+class Department(BaseObject):
+ fields = dict(
+ DefaultMarginPercent=dict(validator=dict(type=SchemeValidator.INTTYPE)),
+ DefaultMarkupPercent=dict(validator=dict(type=SchemeValidator.INTTYPE)),
+ DepartmentCode=dict(required=True, validator=dict(type=SchemeValidator.STRTYPE, max_length=3)),
+ DepartmentName=dict(validator=dict(type=SchemeValidator.STRTYPE)),
+ TaxCode=dict(validator=dict(type=SchemeValidator.STRTYPE)),
+ )
+
+ def __init__(self, Name=None, **kwargs):
+ if Name:
+ self.DepartmentName = Name
+
+ super().__init__(**kwargs)
+
+ @staticmethod
+ def get_service():
+ from django_quickbooks.services.department import DepartmentService
+ return DepartmentService
diff --git a/django_quickbooks/objects/item_inventory_pos.py b/django_quickbooks/objects/item_inventory_pos.py
new file mode 100644
index 0000000..7ea4af6
--- /dev/null
+++ b/django_quickbooks/objects/item_inventory_pos.py
@@ -0,0 +1,47 @@
+from django_quickbooks.objects.base import BaseObject
+from django_quickbooks.validators import SchemeValidator
+
+
+class ItemInventory(BaseObject):
+ fields = dict(
+ ALU=dict(validator=dict(type=SchemeValidator.STRTYPE, max_length=20)),
+ Cost=dict(validator=dict(type=SchemeValidator.FLOATTYPE)),
+ DepartmentListID=dict(required=True, validator=dict(type=SchemeValidator.IDTYPE)),
+ Desc1=dict(validator=dict(type=SchemeValidator.STRTYPE, max_length=30)),
+ Desc2=dict(validator=dict(type=SchemeValidator.STRTYPE)),
+ IsEligibleForCommission=dict(validator=dict(type=SchemeValidator.BOOLTYPE)),
+ IsPrintingTags=dict(validator=dict(type=SchemeValidator.BOOLTYPE)),
+ IsUnorderable=dict(validator=dict(type=SchemeValidator.BOOLTYPE)),
+ # ItemType may have one of the following values: Inventory, Non - Inventory, Service, Assembly, Group, SpecialOrder
+ ItemType=dict(validator=dict(type=SchemeValidator.STRTYPE)),
+ MSRP=dict(validator=dict(type=SchemeValidator.FLOATTYPE)),
+ OnHandStore01=dict(validator=dict(type=SchemeValidator.INTTYPE)),
+ OrderCost=dict(validator=dict(type=SchemeValidator.FLOATTYPE)),
+ Price1=dict(validator=dict(type=SchemeValidator.FLOATTYPE)), # Original Price
+ Price2=dict(validator=dict(type=SchemeValidator.FLOATTYPE)), # Sale Price
+ Price3=dict(validator=dict(type=SchemeValidator.FLOATTYPE)), # Employee Price
+ Price4=dict(validator=dict(type=SchemeValidator.FLOATTYPE)), # Wholesale Price
+ Price5=dict(validator=dict(type=SchemeValidator.FLOATTYPE)), # Custom Price
+ ReorderPoint=dict(validator=dict(type=SchemeValidator.INTTYPE)),
+ # SerialFlag may have one of the following values: Optional,Prompt
+ SerialFlag=dict(validator=dict(type=SchemeValidator.STRTYPE)),
+ UPC=dict(validator=dict(type=SchemeValidator.STRTYPE, max_length=18)),
+
+ )
+
+ def __init__(self, Name=None, Price=None, Qty=None, Description=None, **kwargs):
+ if Name:
+ self.Desc1 = Name
+ if Price:
+ self.Price1 = Price
+ if Qty:
+ self.OnHandStore01 = Qty
+ if Description:
+ self.Desc2 = Description
+
+ super().__init__(**kwargs)
+
+ @staticmethod
+ def get_service():
+ from django_quickbooks.services.item_inventory import ItemInventoryService
+ return ItemInventoryService
diff --git a/django_quickbooks/processors/base.py b/django_quickbooks/processors/base.py
index 586b80d..8b7451c 100644
--- a/django_quickbooks/processors/base.py
+++ b/django_quickbooks/processors/base.py
@@ -6,6 +6,7 @@
from django_quickbooks import QBXML_RESPONSE_STATUS_CODES
from django_quickbooks.decorators import realm_connection
from django_quickbooks.exceptions import QBXMLParseError, QBXMLStatusError
+from django_quickbooks import utils
class ResponseProcessor:
@@ -13,27 +14,28 @@ class ResponseProcessor:
op_type = None
obj_class = None
- def __init__(self, response, hresult, message):
+ def __init__(self, response, hresult, message, realm):
self._actual_response_type = None
self._response_body = None
self._response = response
self.hresult = hresult
self.message = message
- self._process()
+ self._process(realm.qb_type)
- def _process(self):
+ def _process(self, qb_type):
+ xml_type = utils.get_xml_type(qb_type)
if self.hresult:
raise QBXMLStatusError(self.message)
qbxml_root = etree.fromstring(self._response)
- if qbxml_root.tag != 'QBXML':
- raise QBXMLParseError('QBXML tag not found')
+ if qbxml_root.tag != xml_type:
+ raise QBXMLParseError(f'{xml_type} tag not found')
if len(qbxml_root) != 1:
- raise QBXMLParseError('QBXML has more or less than 1 child')
+ raise QBXMLParseError(f'{xml_type} has more or less than 1 child')
qbxml_msg_rs = qbxml_root[0]
- if qbxml_msg_rs.tag != 'QBXMLMsgsRs':
- raise QBXMLParseError('QBXMLMsgsRs tag not found')
+ if qbxml_msg_rs.tag != f'{xml_type}MsgsRs':
+ raise QBXMLParseError(f'{xml_type}MsgsRs tag not found')
if len(qbxml_msg_rs) != 1:
- raise QBXMLParseError('QBXMLMsgsRs has more or less than 1 child')
+ raise QBXMLParseError(f'{xml_type}MsgsRs has more or less than 1 child')
response_body_root = qbxml_msg_rs[0]
if 'statusCode' not in response_body_root.attrib:
raise QBXMLParseError('statusCode is not found in %s' % response_body_root.tag)
diff --git a/django_quickbooks/services/base.py b/django_quickbooks/services/base.py
index 82547d9..46e0036 100644
--- a/django_quickbooks/services/base.py
+++ b/django_quickbooks/services/base.py
@@ -1,5 +1,6 @@
from django_quickbooks import QUICKBOOKS_ENUMS
from django_quickbooks.utils import get_xml_meta_info, xml_setter
+from django_quickbooks import utils
class Service:
@@ -8,27 +9,36 @@ class Service:
complex_fields = []
mod_fields = []
+ @property
+ def qb_type(self):
+ raise NotImplementedError("qb_type is a required")
+
def _prepare_request(self, req_body):
- xml = xml_setter('QBXMLMsgsRq', req_body, onError='stopOnError')
- xml = xml_setter('QBXML', xml)
- xml = get_xml_meta_info() + xml
+ xml_type = utils.get_xml_type(self.qb_type)
+ xml = xml_setter(f'{xml_type}MsgsRq', req_body, onError='stopOnError')
+ xml = xml_setter(xml_type, xml)
+
+ xml = get_xml_meta_info(self.qb_type) + xml
return xml
def _add(self, resource, object):
xml = ''
xml += xml_setter(resource + QUICKBOOKS_ENUMS.OPP_ADD + 'Rq', object.as_xml(
- opp_type=QUICKBOOKS_ENUMS.OPP_ADD, ref_fields=self.ref_fields, change_fields=self.add_fields, complex_fields=self.complex_fields))
+ opp_type=QUICKBOOKS_ENUMS.OPP_ADD, ref_fields=self.ref_fields, change_fields=self.add_fields,
+ complex_fields=self.complex_fields))
return self._prepare_request(xml)
def _update(self, resource, object):
xml = ''
xml += xml_setter(resource + QUICKBOOKS_ENUMS.OPP_MOD + 'Rq', object.as_xml(
- opp_type=QUICKBOOKS_ENUMS.OPP_MOD, ref_fields=self.ref_fields, change_fields=self.mod_fields, complex_fields=self.complex_fields))
+ opp_type=QUICKBOOKS_ENUMS.OPP_MOD, ref_fields=self.ref_fields, change_fields=self.mod_fields,
+ complex_fields=self.complex_fields))
return self._prepare_request(xml)
def _void(self, resource, object):
xml = ''
- xml += xml_setter(resource + QUICKBOOKS_ENUMS.OPP_VOID + 'Rq', object.as_xml(opp_type=QUICKBOOKS_ENUMS.OPP_VOID))
+ xml += xml_setter(resource + QUICKBOOKS_ENUMS.OPP_VOID + 'Rq',
+ object.as_xml(opp_type=QUICKBOOKS_ENUMS.OPP_VOID))
return self._prepare_request(xml)
def _delete(self, resource, object):
diff --git a/django_quickbooks/services/customer.py b/django_quickbooks/services/customer.py
index 06698af..187bf65 100644
--- a/django_quickbooks/services/customer.py
+++ b/django_quickbooks/services/customer.py
@@ -5,6 +5,8 @@
class CustomerService(Service):
complex_fields = ['BillAddress', 'ShipAddress']
+ qb_type = None
+
def add(self, object):
return self._add(QUICKBOOKS_ENUMS.RESOURCE_CUSTOMER, object)
diff --git a/django_quickbooks/services/department.py b/django_quickbooks/services/department.py
new file mode 100644
index 0000000..28c0e3d
--- /dev/null
+++ b/django_quickbooks/services/department.py
@@ -0,0 +1,24 @@
+from django_quickbooks import QUICKBOOKS_ENUMS
+from django_quickbooks.services.base import Service
+
+
+class DepartmentService(Service):
+ qb_type = None
+
+ def add(self, object):
+ return self._add(QUICKBOOKS_ENUMS.RESOURCE_DEPARTMENT, object)
+
+ def update(self, object):
+ return self._update(QUICKBOOKS_ENUMS.RESOURCE_DEPARTMENT, object)
+
+ def all(self):
+ return self._all(QUICKBOOKS_ENUMS.RESOURCE_DEPARTMENT)
+
+ def find_by_id(self, id):
+ return self._find_by_id(QUICKBOOKS_ENUMS.RESOURCE_DEPARTMENT, id)
+
+ def find_by_department_name(self, department_name):
+ return self._find_by_id(QUICKBOOKS_ENUMS.RESOURCE_DEPARTMENT, department_name, field_name='DepartmentName')
+
+ def find_by_department_code(self, department_code):
+ return self._find_by_id(QUICKBOOKS_ENUMS.RESOURCE_DEPARTMENT, department_code, field_name='DepartmentCode')
diff --git a/django_quickbooks/services/invoice.py b/django_quickbooks/services/invoice.py
index 88571d9..573fe15 100644
--- a/django_quickbooks/services/invoice.py
+++ b/django_quickbooks/services/invoice.py
@@ -8,6 +8,7 @@ class InvoiceService(Service):
add_fields = ['InvoiceLine']
complex_fields = ['BillAddress']
mod_fields = ['InvoiceLine']
+ qb_type = None
def add(self, object):
return self._add(QUICKBOOKS_ENUMS.RESOURCE_INVOICE, object)
diff --git a/django_quickbooks/services/item_inventory.py b/django_quickbooks/services/item_inventory.py
new file mode 100644
index 0000000..c203d30
--- /dev/null
+++ b/django_quickbooks/services/item_inventory.py
@@ -0,0 +1,18 @@
+from django_quickbooks import QUICKBOOKS_ENUMS
+from django_quickbooks.services.base import Service
+
+
+class ItemInventoryService(Service):
+ qb_type = None
+
+ def add(self, object):
+ return self._add(QUICKBOOKS_ENUMS.RESOURCE_ITEM_INVENTORY_POS, object)
+
+ def update(self, object):
+ return self._update(QUICKBOOKS_ENUMS.RESOURCE_ITEM_INVENTORY_POS, object)
+
+ def all(self):
+ return self._all(QUICKBOOKS_ENUMS.RESOURCE_ITEM_INVENTORY_POS)
+
+ def find_by_id(self, id):
+ return self._find_by_id(QUICKBOOKS_ENUMS.RESOURCE_ITEM_INVENTORY_POS, id)
diff --git a/django_quickbooks/services/item_service.py b/django_quickbooks/services/item_service.py
index 7551ec7..ae8c837 100644
--- a/django_quickbooks/services/item_service.py
+++ b/django_quickbooks/services/item_service.py
@@ -3,6 +3,8 @@
class ServiceOfItemService(Service):
+ qb_type = None
+
def all(self):
return self._all(QUICKBOOKS_ENUMS.RESOURCE_ITEM_SERVICE)
diff --git a/django_quickbooks/session_manager.py b/django_quickbooks/session_manager.py
index 9b55bb5..40668ff 100644
--- a/django_quickbooks/session_manager.py
+++ b/django_quickbooks/session_manager.py
@@ -54,7 +54,7 @@ def process_response(self, ticket, response, hresult, message):
processors = get_processors()
for processor in processors:
try:
- processed = processor(response, hresult, message).process(realm)
+ processed = processor(response, hresult, message, realm).process(realm)
if processed:
break
diff --git a/django_quickbooks/settings.py b/django_quickbooks/settings.py
index ad244a1..fc9df36 100644
--- a/django_quickbooks/settings.py
+++ b/django_quickbooks/settings.py
@@ -75,9 +75,10 @@ def import_from_string(val, setting_name):
"""
try:
# Nod to tastypie's use of importlib.
- module_path, class_name = val.rsplit('.', 1)
- module = import_module(module_path)
- return getattr(module, class_name)
+ if val:
+ module_path, class_name = val.rsplit('.', 1)
+ module = import_module(module_path)
+ return getattr(module, class_name)
except (ImportError, AttributeError) as e:
msg = "Could not import '%s' for Quickbooks Web Connector setting '%s'. %s: %s." \
% (val, setting_name, e.__class__.__name__, e)
diff --git a/django_quickbooks/urls.py b/django_quickbooks/urls.py
index 0580384..db24b4a 100644
--- a/django_quickbooks/urls.py
+++ b/django_quickbooks/urls.py
@@ -4,13 +4,14 @@
from django_quickbooks.views import QuickBooksService, Support
+app_name = "django_quickbooks"
urlpatterns = [
path('quickbooks-desktop/support/', Support.as_view()),
path('quickbooks-desktop/', DjangoView.as_view(
services=[QuickBooksService],
tns='http://developer.intuit.com/',
in_protocol=Soap11(validator='lxml'),
- out_protocol=Soap11())
+ out_protocol=Soap11()),
+ name="quickbooks-desktop"
),
]
-
diff --git a/django_quickbooks/utils.py b/django_quickbooks/utils.py
index d73fe84..0a7c50b 100644
--- a/django_quickbooks/utils.py
+++ b/django_quickbooks/utils.py
@@ -3,6 +3,7 @@
from importlib import import_module
from django.utils.six import string_types
+from django_quickbooks.settings import DEFAULTS
def import_callable(path_or_callable):
@@ -38,8 +39,13 @@ def xml_setter(name, value, encode=False, **options):
return '<%s>%s%s>' % (name, value, name) if not option_xml else '<%s %s>%s%s>' % (name, option_xml, value, name)
-def get_xml_meta_info():
- return ''
+def get_xml_meta_info(qb_type):
+ xml_type = get_xml_type(qb_type)
+ if xml_type == 'QBXML':
+ xml_version = 'qbxml version="13.0"'
+ elif xml_type == 'QBPOSXML':
+ xml_version = 'qbposxml version="1.0"'
+ return f'{xml_version}?>'
def random_string(length=10):
@@ -47,6 +53,26 @@ def random_string(length=10):
return ''.join(random.choice(letters) for i in range(length))
+def get_xml_type(qb_type: str) -> str:
+ """
+ :param qb_type: qb_type from realm object values should be in ['QBFS', 'QBPOS', 'QBO']
+ :return: 'QBXML' or 'QBPOSXML'
+ """
+ if qb_type == "QBFS":
+ xml_type = 'QBXML'
+ elif qb_type == "QBPOS":
+ xml_type = 'QBPOSXML'
+ elif not qb_type:
+ raise NotImplementedError(
+ f"qb_type not found, Please Check qb_type in your realm model"
+ f" acceptable values= ['QBFS', 'QBPOS']")
+ else:
+ raise NotImplementedError(
+ f"qb_type not correct, Please Check qb_type in your realm model,"
+ f"'{qb_type}' is not acceptable. acceptable values= ['QBFS', 'QBPOS']")
+ return xml_type
+
+
def convert_qbd_model_to_qbdtask(obj, qb_resource, qb_operation=None, **kwargs):
from django_quickbooks import QUICKBOOKS_ENUMS
from django.contrib.contenttypes.models import ContentType
diff --git a/django_quickbooks/validators.py b/django_quickbooks/validators.py
index 33dbc67..154b8b9 100644
--- a/django_quickbooks/validators.py
+++ b/django_quickbooks/validators.py
@@ -72,6 +72,12 @@ def float_type_validator(value):
ValidationCode.INVALID_TYPE)
+def int_type_validator(value):
+ if not isinstance(value, int):
+ raise ValidationError(VALIDATION_MESSAGES[ValidationCode.INVALID_TYPE] % (type(value), int),
+ ValidationCode.INVALID_TYPE)
+
+
def required_validator(value, required=False):
if not value and required:
raise ValidationError(VALIDATION_MESSAGES[ValidationCode.REQUIRED], ValidationCode.REQUIRED)
@@ -90,6 +96,7 @@ class SchemeValidator:
BOOLTYPE = 'BOOLTYPE'
OBJTYPE = 'OBJTYPE'
FLOATTYPE = 'FLOATTYPE'
+ INTTYPE = 'INTTYPE'
type_validators = dict(
STRTYPE=str_type_validator,
@@ -98,6 +105,7 @@ class SchemeValidator:
BOOLTYPE=bool_type_validator,
OBJTYPE=obj_type_validator,
FLOATTYPE=float_type_validator,
+ INTTYPE=int_type_validator,
)
option_validators = dict(
min_length=min_length_validator,
diff --git a/django_quickbooks/views/service.py b/django_quickbooks/views/service.py
index b002e26..78e09c1 100644
--- a/django_quickbooks/views/service.py
+++ b/django_quickbooks/views/service.py
@@ -168,6 +168,9 @@ def receiveResponseXML(ctx, ticket, response, hresult, message):
if hresult:
print("hresult=" + hresult)
print("message=" + message)
+ # FIXME: I know this is a hacky way to get around encoding, needs a better solution
+ if response.startswith(''):
+ response = response.replace('encoding="windows-1252"', '', 1)
return session_manager.process_response(ticket, response, hresult, message)