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' % (name, value, name) if not option_xml else '<%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'' 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)