diff --git a/PriceLevelQuery.xml b/PriceLevelQuery.xml new file mode 100644 index 0000000..c550da9 --- /dev/null +++ b/PriceLevelQuery.xml @@ -0,0 +1,75 @@ + + + + + + + IDTYPE + + STRTYPE + + INTTYPE + + ENUMTYPE + DATETIMETYPE + DATETIMETYPE + + + + ENUMTYPE + STRTYPE + + + + STRTYPE + STRTYPE + + + + IDTYPE + STRTYPE + + + + IDTYPE + + STRTYPE + + + + STRTYPE + + + + + IDTYPE + DATETIMETYPE + DATETIMETYPE + STRTYPE + STRTYPE + BOOLTYPE + + ENUMTYPE + + PERCENTTYPE + + + + IDTYPE + STRTYPE + + + PRICETYPE + + PERCENTTYPE + + + + IDTYPE + STRTYPE + + + + + + diff --git a/QBClasses.py b/QBClasses.py index 8cfec3f..e6c2dcf 100644 --- a/QBClasses.py +++ b/QBClasses.py @@ -75,7 +75,7 @@ class GeneralSummaryReportQuery(baseQBQuery): print(f'{kwargs = }') super().__init__( ) ## Required variable - self.includeRetElements_allowed = ["ReportTitle", "ReportSubtitle", "ReportBasis", "NumRows", "NumColumns", "NumColTitleRows", "ReportData", ] + self.includeRetElements_allowed = ["ReportTitle", "ReportSubtitle", "ReportBasis", "NumRows", "NumColumns", "NumColTitleRows", "ReportData", "DataRow"] self.onError = "stopOnError" self.retName = 'ReportRet' self.defaultFilterKey = "ListID" @@ -95,8 +95,8 @@ class GeneralSummaryReportQuery(baseQBQuery): if 'GeneralSummaryReportType' in kwargs: enum=cleanIncludeRetElements(self.ENUM_GeneralSummaryReportType, kwargs['GeneralSummaryReportType']) - print(enum) - self.QBDict[self.classRq]["GeneralSummaryReportType"]=enum[0] + print(f'{enum = }') + self.QBDict[self.classNameRq]["GeneralSummaryReportType"]=enum[0] else: print("Error -> GeneralSummaryReportType is required") return @@ -180,8 +180,8 @@ class GeneralSummaryReportQuery(baseQBQuery): self.QBDict[self.classNameRq]["IncludeSubColumns"]=kwargs['IncludeSubColumns'] if 'ReportCalendar' in kwargs: self.QBDict[self.classNameRq]["ReportCalendar"]=cleanIncludeRetElements(['CalendarYear', 'FiscalYear', 'TaxYear'], kwargs['ReportCalendar'], default_val='CalendarYear') - if 'ReturnsRows' in kwargs: - self.QBDict[self.classNameRq]["ReturnsRows"]=cleanIncludeRetElements(['ActiveOnly', 'NonZero', 'All'], kwargs['ReturnsRows'], default_val='ActiveOnly') + if 'ReturnRows' in kwargs: + self.QBDict[self.classNameRq]["ReturnRows"]=cleanIncludeRetElements(['ActiveOnly', 'NonZero', 'All'], kwargs['ReturnRows'], default_val='ActiveOnly') if 'ReturnColumns' in kwargs: self.QBDict[self.classNameRq]["ReturnColumns"]=cleanIncludeRetElements(['ActiveOnly', 'NonZero', 'All'], kwargs['ReturnColumns'], default_val='ActiveOnly') if 'ReportBasis' in kwargs: @@ -199,6 +199,69 @@ class GeneralSummaryReportQuery(baseQBQuery): # print(f'{self.QBDict = }') if self.__class__.__name__==self.className: self.runCheck() ### running the qbxml connection to get data ### + + +class PriceLevelQuery(baseQBQuery): + def __init__(self, *args, **kwargs): + print(f'{args = }') + print(f'{kwargs = }') + super().__init__( ) + ## Required variable + self.includeRetElements_allowed = ["ListID", "TimeCreated", "TimeModified", "EditSequence", "Name", "isActive", "PriceLevelType", "PriceLevelFixedPercentage", + "PriceLevelPerItemRet", "ItemRef", "CustomPrice", "CustomePricePercent", "CurrencyRef"] + self.onError = "stopOnError" + self.retName = 'PriceLevelRet' + self.defaultFilterKey = "ListID" + self.className = "PriceLevelQuery" + self.classNameRq:str = self.__class__.__name__ + 'Rq' + if 'debug' in kwargs and isinstance(kwargs['debug'], bool): + self.class_debug=kwargs["debug"] + + self.QBDict[self.classNameRq]={} #Required + ### End Required variable + + self.ENUM_ActiveStatus = ['ActiveOnly', 'InactiveOnly', 'All'] + self.ENUM_MatchCriterion = ['StartsWith', 'Contains', 'EndsWith'] + + if 'ListID' in kwargs: + self.QBDict[self.classNameRq]["ListID"]=kwargs['ListID'] + elif 'FullName' in kwargs: + self.QBDict[self.classNameRq]["FullName"]=kwargs['FullName'] + else: + if 'MaxReturned' in kwargs: + self.QBDict[self.classNameRq]["MaxReturned"]=kwargs['MaxReturned'] + if 'ActiveStatus' in kwargs: + enum=cleanIncludeRetElements(self.ENUM_ActiveStatus, kwargs['ActiveStatus']) + self.QBDict[self.classNameRq]["ActiveStatus"]=enum[0] + if 'FromModifiedDate' in kwargs: + self.QBDict[self.classNameRq]["FromModifiedDate"]=kwargs['FromModifiedDate'] + if 'ToModifiedDate' in kwargs: + self.QBDict[self.classNameRq]["ToModifiedDate"]=kwargs['ToModifiedDate'] + if 'NameFilter_MatchCriterion' in kwargs and 'NameFilter_Name' in kwargs: + enum= cleanIncludeRetElements(self.ENUM_MatchCriterion, kwargs['NameFilter_MatchCriterion']) + self.QBDict[self.classNameRq]["NameFilter"]={'MatchCriterion': enum[0], 'Name': kwargs['NameFilter_Name']} + elif 'NameRangeFilter_FromName' in kwargs or 'NameRangeFilter_ToName' in kwargs: + self.QBDict[self.classNameRq]["NameRangeFilter"]={'FromName':kwargs.get('NameRangeFilter_FromName', None), 'ToReportDate':kwargs.get('NameRangeFilter_ToName', None)} + if 'ItemRef_ListID' in kwargs or 'ItemRef_FullName' in kwargs: + self.QBDict[self.classNameRq]["ItemRef"]={'ListID':kwargs.get('ItemRef_ListID', None), 'FullName':kwargs.get('ItemRef_FullName', None)} + if 'CurrencyFilter_ListID' in kwargs: + self.QBDict[self.classNameRq]["CurrencyFilter"]=kwargs['CurrencyFilter_ListID'] + elif 'CurrencyFilter_FullName' in kwargs: + self.QBDict[self.classNameRq]["CurrencyFilter"]=kwargs['CurrencyFilter_FullName'] + if 'IncludeRetElement' in kwargs: + IRE = cleanIncludeRetElements(self.includeRetElements_allowed, kwargs["IncludeRetElement"]) #IRE->IncludeRetElements cleaned version + print(f"{IRE = }") + if len(IRE)>0: + if self.defaultFilterKey not in IRE: #defaultFilterKey is for BaseClass.count() eg: after instantiate, then print obj.count() + IRE.append(self.defaultFilterKey) + self.QBDict[self.classNameRq]["IncludeRetElement"]=IRE + + # print(self.classNameRq) + # print(f'{self.QBDict = }') + if self.__class__.__name__==self.className: + self.runCheck() ### running the qbxml connection to get data ### + + import xmltodict def LineAdd(lineAdd:Union[list, dict])->dict: if not(isinstance(lineAdd, list) or isinstance(lineAdd, dict)): @@ -1092,6 +1155,73 @@ class InvoiceQuery(baseQBQuery): if self.__class__.__name__==self.className: self.runCheck() ### running the qbxml connection to get data ### +@timing +def InventoryStockStatusByVendor(ReportEntityFilter_FullName:str='TACO') -> dict: + # g= GeneralSummaryReportQuery(debug=False, GeneralSummaryReportType="ProfitAndLossStandard", ReportDateMacro="ThisYear") + g= GeneralSummaryReportQuery(debug=False, GeneralSummaryReportType="InventoryStockStatusByVendor", ReportEntityFilter_FullName=ReportEntityFilter_FullName, ) + # g= GeneralSummaryReportQuery(debug=False, GeneralSummaryReportType="InventoryStockStatusByVendor", ReportItemFilter_FullName=['TACH:RLC:BBS009PO45-500','TACH:RLC:BBS009PO45-400'], ReportEntityFilter_FullName='TACO' ) + # print(g, type(g)) + # print(type(g.all())) + # print(g.all()) + # print(g.response_string) + # print(g.all()) + # pprint.pprint(g.filter("reportdata").all()) + # abc = g.filter("reportdata").all() + # print(abc) + # print() + # pprint.pprint(g.filter('datarow').all(abc), sort_dicts=False) + datarows = g.filter('datarow').all() + # pprint.pprint(datarows, sort_dicts=False) + # print(type(datarows)) + dt = {} + if len(datarows[0]['DataRow'])==0: + return dt + for datarow in datarows[0]['DataRow']: + # print(datarow,) + FullName=datarow['RowData']['@value'] + if len(FullName.split(':'))==3: + ShortName=datarow['ColData'][0]['@value'] + QOH, QOSO, QA, UOM, QOPO, min, max, ND = None, None, None, None, None, None, None, None + for coldata in datarow['ColData']: + if coldata['@colID']=='5': + QOH=coldata['@value'] + elif coldata['@colID']=='6': + QOSO=coldata['@value'] + elif coldata['@colID']=='8': + QA=coldata['@value'] + elif coldata['@colID']=='9': + UOM=coldata['@value'] + elif coldata['@colID']=='11': + QOPO=coldata['@value'] + elif coldata['@colID']=='3': + min=coldata['@value'] + elif coldata['@colID']=='4': + max=coldata['@value'] + elif coldata['@colID']=='13': + ND=coldata['@value'] #Next Delivery Date + dt[FullName]={'ShortName':ShortName, 'QOH':QOH, 'QOSO':QOSO, 'QA':QA, 'QOPO':QOPO, 'UOM':UOM, 'min':min, 'max':max, 'ND':ND} + # print(f'{dt = }') + # print(len(dt)) + return dt + """ + {'@rowNumber': '1016', + 'ColData': [{'@colID': '1', + '@value': 'EDG-P1251-1/42'}, + {'@colID': '2', + '@value': 'EDGING 42 X 1 MM P1251'}, + {'@colID': '5', '@value': '1'}, # QOH + {'@colID': '6', '@value': '0'}, # QOSO + {'@colID': '7', '@value': '0'}, #assembly + {'@colID': '8', '@value': '1'}, # QA(available)(QOH-QOSO-assembly) + {'@colID': '9', '@value': 'Roll'}, #base_uom + {'@colID': '10', '@value': 'false'}, + {'@colID': '11', '@value': '0'}, #QOPO + {'@colID': '12', '@value': '0'}, #ReorderqTY + {'@colID': '13', '@value': '13/04/2022'}, #NextDeliver + {'@colID': '14', '@value': '0'}], + 'RowData': {'@rowType': 'item', + '@value': 'TEDG:P142:EDG-P1251-1/42'}}, + """ if __name__ == "__main__": @@ -1121,15 +1251,7 @@ if __name__ == "__main__": print(g.count()) - @timing - def main(): - g= GeneralSummaryReportQuery(debug=False, GeneralSummaryReportType="ProfitAndLossStandard", ReportDateMacro="ThisYear") - print(g, type(g)) - print(type(g.all())) - print(g.all()) - print(g.response_string) - pprint.pprint(g.filter("reportdata").all()) - print(g.count(), g.all()) + @timing def iteminventoryquery(): @@ -1160,7 +1282,7 @@ if __name__ == "__main__": @timing def customerquery(): - g= CustomerQuery(MaxReturned=3, IncludeRetElement=["fullname", "name", "CompanyName", "BillAddressBlock", "ShipAddressBlock"]) + g= CustomerQuery(MaxReturned=3, IncludeRetElement=["fullname", "name", "CompanyName", "BillAddressBlock", "ShipAddressBlock", "Notes", "AdditionalNotesRet", 'creditlimit']) # g= CustomerQuery(MaxReturned=20, ActiveStatus="ActiveOnly", MatchCriterion="StartsWith", Name="to", IncludeRetElement=["fullname", "name", "billaddressblock", "currencyfilter"]) # print(g.IncludeRetElements_allowed) print("init finish") @@ -1168,14 +1290,14 @@ if __name__ == "__main__": print("before g.all") print(f'{g.all() = }') print("after g.all") - pprint.pprint(f'{g.filter(["FullName", "Name"]).all() = }') + pprint.pprint(f'{g.filter(["FullName", "Name", "Notes"]).all() = }') print(f'{g.filter() = }') # pprint.pprint(g.filter(["FullName", "abc", "BillAddressBlock"]).all()) - print(f'{g.filter(["FullName", "abc", "BillAddressBlock"]).all() = }') - print("") - print(f'{g.filter([ "Addr1", "Addr2", "Addr3", "Addr4", "Addr5"]).all() = }') - print(f'{g.filter([ "Addr1", "Addr2", "Addr3", "Addr4", "Addr5"]) = }') - print(f'{g.filter(["fullname", "name"]).lastValue() = }') + # print(f'{g.filter(["FullName", "abc", "BillAddressBlock"]).all() = }') + # print("") + # print(f'{g.filter([ "Addr1", "Addr2", "Addr3", "Addr4", "Addr5"]).all() = }') + # print(f'{g.filter([ "Addr1", "Addr2", "Addr3", "Addr4", "Addr5"]) = }') + # print(f'{g.filter(["fullname", "name"]).lastValue() = }') def readxmltodict(): import xmltodict @@ -1223,10 +1345,22 @@ if __name__ == "__main__": print(recursiveDict(varDict, f, enumDict)) f.close + @timing + def pricelevel(): + g = PriceLevelQuery(FullName = 'B 202112', ItemRef_FullName = "TEDG:WG42:EDG-905/42") + g = PriceLevelQuery( NameFilter_MatchCriterion='Contains', NameFilter_Name='202112' ) + # print(g.filter('PriceLevelPerItemRet').all()) + print(g.all()) + print(len(g.filter('PriceLevelPerItemRet').all())) + for x in g.all(): + print([y for y in x]) + print(f"{x.get('Name')} : {len(x.get('PriceLevelPerItemRet'))}") + + pricelevel() # invoicequery() - salesorderquery() + # salesorderquery() # transactionquery() - # main() + # pprint.pprint(InventoryStockStatusByVendor(), sort_dicts=False) # iteminventoryquery() # customerquery() # readxmltodict() diff --git a/server.py b/server.py index 6006fd3..b470f59 100644 --- a/server.py +++ b/server.py @@ -42,6 +42,7 @@ class baseQBQuery: self.statusMessage = "" self.statusSeverity = "" self.statusOk = False + self.retCount = -1 if self.__class__.__name__=="baseQBQuery": print("baseqbquey same with classname") else: @@ -112,6 +113,8 @@ class baseQBQuery: # QBXML = ET.fromstring(self.response_string) # print(xmltodict.parse(self.response_string)) self.varDict = xmltodict.parse(self.response_string) + # print("isDataOK", self.varDict) + if self.class_debug: pprint.pprint("isDataOK", self.varDict) self.listOfDict.varDict = self.varDict @@ -123,13 +126,15 @@ class baseQBQuery: self.statusMessage = self.listOfDict.firstValue().get('@statusMessage',None) self.listOfDict.filterKey = ["@statusSeverity"] self.statusSeverity = self.listOfDict.firstValue().get('@statusSeverity') + self.listOfDict.filterKey = ["@retCount"] + self.retCount = self.listOfDict.firstValue().get('@retCount') self.listOfDict.filterKey = [self.retName] if self.class_debug: print(f'isDataOK -> {self.listOfDict.firstValue() = }') if self.listOfDict.firstValue().get(self.retName,None)==None: return False - print(f'{self.statusCode = }, {self.statusMessage = }, {self.statusSeverity = }') + print(f'{self.statusCode = }, {self.statusMessage = }, {self.statusSeverity = } {self.retCount = }') varDict = self.varDict['QBXML']['QBXMLMsgsRs'][self.__class__.__name__+"Rs"] return True # isStatusOK=None @@ -201,7 +206,7 @@ class baseQBQuery: def filter(self, key=None): - print(f'{key = }') + print(f'filter {key = }') # print(f'{self.statusOk = }') if not self.runCheck(): print("not runcheck") @@ -214,7 +219,7 @@ class baseQBQuery: elif isinstance(key, dict): key = [x for x,y in key.items()] elif key is None: - # print(f"key is none. {self.retName = }") + print(f"key is none. {self.retName = }") return self.ListOfDict(self.retName, self.varDict, self.retName, self.includeRetElements_allowed, self.statusOk)#.firstValue()#[self.retName] else: return [] @@ -239,7 +244,7 @@ class baseQBQuery: if temp: temp = temp[self.retName] else: - return {'status':"Error", 'statusCode': self.statusCode, 'statusMessage':self.statusMessage, 'statusSeverity': self.statusSeverity} + return {'status':"Error", 'statusCode': self.statusCode, 'statusMessage':self.statusMessage, 'statusSeverity': self.statusSeverity, 'retCount':self.retCount} if self.requestID: temp['requestID']=self.requestID # print(f'{temp = }') @@ -257,8 +262,9 @@ class baseQBQuery: class ListOfDict: def __init__(self, key, var, retName, includeRetElements_allowed:list ,statusOk:bool = True) -> None: - # print(f'{key =}, {var =}') + # print(f'ListOFDict{key =}, {var =}') # self.first = self.find_firstListOfDict(key) + print(f'{retName = }') if key: if isinstance(key, str): self.filterKey = [key] @@ -266,7 +272,7 @@ class baseQBQuery: self.filterKey = key else: self.filterKey = [retName] - # print(f"{self.filterKey = }") + print(f"ListOfDict {self.filterKey = }") self.varDict = var self.statusOk = statusOk self._includeRetElements_allowed = includeRetElements_allowed @@ -313,6 +319,7 @@ class baseQBQuery: def all(self, var:dict=None, dataRetList:list=None) -> list: # print(f'{self.statusOk = }') + # print(f'all {var = } {dataRetList = }') if not self.statusOk: return [] _lst = [x for x in self.findKeyInDict(var, dataRetList)] @@ -411,6 +418,7 @@ class baseQBQuery: found = False tempDct = {} for fKey in self.filterKey: + # print(f'{fKey = } {self.filterKey = }') # if self.filterKey in var: if fKey in var: found = True diff --git a/utils.py b/utils.py index 2b4aba1..e0e81eb 100644 --- a/utils.py +++ b/utils.py @@ -133,6 +133,7 @@ def cleanIncludeRetElements(includeRetElements_allowed:list, includeRetElements: if len(iREs)>0: return iREs else: + print(f'cleanIncludeRetElements -> {includeRetElements = } is not in the allowed list. {includeRetElements_allowed = }') return [default_val] if __name__=='__main__':