From b6883a24c722343c8800d2bde888a413335b352d Mon Sep 17 00:00:00 2001 From: bcomsugi Date: Sun, 16 Jun 2024 04:47:55 +0700 Subject: [PATCH] 2024 --- QBClasses.py | 63 +++++++++-- server.py | 311 +++++++++++++++++++++++++++++++++------------------ 2 files changed, 257 insertions(+), 117 deletions(-) diff --git a/QBClasses.py b/QBClasses.py index 7ccc519..4c8a8cc 100644 --- a/QBClasses.py +++ b/QBClasses.py @@ -1,12 +1,13 @@ from server import baseQBQuery +import pprint class ItemInventoryQuery(baseQBQuery): def __init__(self, *args, **kwargs): print(f'{args = }') print(f'{kwargs = }') super().__init__(*args, **kwargs) + self.retName = 'ItemInventoryRet' self.QBDict[self.__class__.__name__ + "Rq"]={} - print(self.QBDict) if 'ListID' in kwargs: self.QBDict[self.__class__.__name__ + "Rq"]["ListID"]=kwargs['ListID'] elif 'FullName' in kwargs: @@ -29,23 +30,26 @@ class ItemInventoryQuery(baseQBQuery): if 'OwnerID' in kwargs: self.QBDict[self.__class__.__name__ + "Rq"]["OwnerID"]=kwargs['OwnerID'] - print(self.__class__.__name__ + "Rq") - print(self.QBDict) + # print(self.__class__.__name__ + "Rq") + # print(self.QBDict) class GeneralSummaryReportQuery(baseQBQuery): def __init__(self, *args, **kwargs): print(f'{args = }') print(f'{kwargs = }') - super().__init__(*args, **kwargs) + super().__init__( ) + self.retName = 'ReportRet' self.QBDict[self.__class__.__name__ + "Rq"]={} - print(self.QBDict) + self.QBDict[self.__class__.__name__ + "Rq"]["GeneralSummaryReportType"]="InventoryStockStatusByItem" if 'GeneralSummaryReportType' in kwargs: self.QBDict[self.__class__.__name__ + "Rq"]["GeneralSummaryReportType"]=kwargs['GeneralSummaryReportType'] + else: + return None if 'FromReportDate' in kwargs or 'ToReportDate' in kwargs: self.QBDict[self.__class__.__name__ + "Rq"]["ReportPeriod"]={'FromReportDate':kwargs.get('FromReportDate', ""), 'ToReportDate':kwargs.get('ToReportDate', "")} elif 'ReportDateMacro' in kwargs: - self.QBDict[self.__class__.__name__ + "Rq"]["ReportDateMacro"]=kwargs.get('FromReportDate', "") + self.QBDict[self.__class__.__name__ + "Rq"]["ReportDateMacro"]=kwargs.get('ReportDateMacro', "") elif 'FullName' in kwargs: self.QBDict[self.__class__.__name__ + "Rq"]["FullName"]=kwargs['FullName'] @@ -68,8 +72,47 @@ class GeneralSummaryReportQuery(baseQBQuery): self.QBDict[self.__class__.__name__ + "Rq"]["OwnerID"]=kwargs['OwnerID'] print(self.__class__.__name__ + "Rq") - print(self.QBDict) + print(f'{self.QBDict = }') -x=ItemInventoryQuery('bagus', 'kedua', key5=5, key2="hore", FullName1='hooooo', FromName1="sg", ToName1="sugi", IncludeRetElement=['Name', 'FullName'], MaxReturned="2") -x.create_QBXML() -x.connect_to_quickbooks() \ No newline at end of file + +# x=ItemInventoryQuery('bagus', 'kedua', key5=5, key2="hore", FullName1='hooooo', FromName1="sg", ToName1="sugi", IncludeRetElement1=['Name', 'FullName'], MaxReturned="2") +# x.create_QBXML() +# x.connect_to_quickbooks() +# # print(x.find_firstListOfDict("FullName")['FullName']) + +# # print(x.find_firstListOfDictValue("PurchaseCost")) +# # print(x.find_firstListOfDict("PurchaseCost")) +# # print(x.find_allListOfDict("FullName")) +# # pprint.pprint(x.Rs) +# # print("ada" if list(x.find_listOfDict("FullName")) else "ga") + +# print(x.filter("FullName")) +# y=x.filter("Name") +# print(type(x.filter("FullName1"))) +# print(type(y)) +# print(x.filter("FullName1").all()) +# _test=x.filter("FullName1").all() +# if _test: +# print(_test) +# try: +# print(x.filter("FullName1").all()[-1]) +# except Exception as e: +# print(e) +# print(x.filter("FullName1").first()) +# print(x.filter("FullName1").firstValue()) +# print(x.filter("FullName1").last()) +# print(x.filter("FullName1").lastValue()) +# print(x.filter("FullName").count()) +# print(y.last()) +# print(y.lastValue()) +# pprint.pprint(x.all()) +# a1=x.filter("FullName") +# print(a1) +# a2 = x.filter("Name") +# print(a2) +# print(a1) + +g= GeneralSummaryReportQuery(GeneralSummaryReportType="ProfitAndLossStandard", ReportDateMacro="ThisYear") +print(type(g.all())) +print(g.all()) +pprint.pprint(g.filter("ColData").all()) \ No newline at end of file diff --git a/server.py b/server.py index 01b7156..c1765a8 100644 --- a/server.py +++ b/server.py @@ -4,37 +4,20 @@ import win32com.client import xml.etree.ElementTree as ET class baseQBQuery: - def __init__(self, *args, **kwargs) -> None: - # print(f'kwargs:{kwargs}') - # print(args) + def __init__(self, *args, **kwargs, ) -> None: + # print(f'{kwargs = }') + # print(f'{args = }') self.onError = "continueOnError" - self.GeneralSummaryReportType = kwargs['GeneralSummaryReportType'] if 'GeneralSummaryReportType' in kwargs else 'SalesByCustomerSummary' - self.ReportPeriod = kwargs['ReportPeriod'] if 'ReportPeriod' in kwargs else None - self.ReportDateMacro = None - if 'ReportDateMacro' in kwargs: - if kwargs['ReportDateMacro'] in ['All', 'Today', 'ThisWeek', 'ThisWeekToDate', 'ThisMonth', 'ThisMonthToDate', 'ThisQuarter', 'ThisQuarterToDate', 'ThisYear', 'ThisYearToDate', 'Yesterday', 'LastWeek', 'LastWeekToDate', 'LastMonth', 'LastMonthToDate', 'LastQuarter', 'LastQuarterToDate', 'LastYear', 'LastYearToDate', 'NextWeek', 'NextFourWeeks', 'NextMonth', 'NextQuarter', 'NextYear']: - self.ReportDateMacro = kwargs['ReportDateMacro'] - self.FromReportDate = self.validate_date(kwargs['FromReportDate']) if 'FromReportDate' in kwargs else None - self.ToReportDate = self.validate_date(kwargs['ToReportDate']) if 'ToReportDate' in kwargs else None - self.ReportEntityFilter = kwargs['ReportEntityFilter'] if 'ReportEntityFilter' in kwargs else None - self.FullName = kwargs['FullName'] if 'FullName' in kwargs else None - # print(self.ReportDateMacro, self.ReportPeriod, self.FromReportDate, self.ToReportDate) self.QBXML = None self.QBDict = {} self.response_string = None - - # def create_sub_element(self, ET, parentNode, thisNode, text="\n", whiteSpace = 0, attrib =None): - # if type(attrib) is not dict: - # attrib = {} - # ele = ET.SubElement(parentNode, thisNode) - # for x in attrib: - # ele.set(x, attrib[x]) - # ele.text = text - # tail = "\n" - # for x in range(whiteSpace): - # tail = tail + " " - # ele.tail = tail - # return ele + self.Rs = None + self.varDict = {} + self.retName = None + self.listOfDict = self.ListOfDict(None, self.varDict, self.retName) + self.statusCode = -1 + self.statusMessage = "" + self.statusSeverity = "" def create_QBXML(self): dataDict = { ### Header for qmxml with version attribute @@ -61,86 +44,74 @@ class baseQBQuery: firstKey = str(list(self.QBDict.keys())[0]) dataDict["?qbxml"]["QBXML"] = {"QBXMLMsgsRq": { ### Example with multiple FullName Item ### "@onError": self.onError, - # self.__class__.__name__+"Rq": self.QBDict[self.__class__.__name__+"Rq"]}} firstKey: self.QBDict[firstKey]}} - print(dataDict) - # print(xmltodict.unparse(dataDict, pretty=True)) + # print(f'{dataDict = }') # # QBXML = '' + xmltodict.unparse(dataDict, pretty=True) self.QBXML = xmltodict.unparse(dataDict, pretty=True).replace("", "") print(self.QBXML) return self.QBXML - # def create_QBXML(self): - # root = ET.Element("QBXML") - # root.tail = "\n" - # root.text = "\n " - # QBXMLMsgsRq = ET.SubElement(root, "QBXMLMsgsRq") - # QBXMLMsgsRq.set("onError", "continueOnError") - # QBXMLMsgsRq.tail = "\n" - # QBXMLMsgsRq.text = "\n " - # GeneralSummaryReportQueryRq = self.create_sub_element(ET, QBXMLMsgsRq, "GeneralSummaryReportQueryRq","\n " ) - # GeneralSummaryReportType = self.create_sub_element(ET, GeneralSummaryReportQueryRq, 'GeneralSummaryReportType', self.GeneralSummaryReportType) - # if self.ReportDateMacro: - # GeneralSummaryReportType = self.create_sub_element(ET, GeneralSummaryReportQueryRq, "ReportDateMacro", self.ReportDateMacro) - # elif type(self.FromReportDate) is datetime.date or type(self.ToReportDate) is datetime.date: - # ReportPeriod = self.create_sub_element(ET, GeneralSummaryReportQueryRq, "ReportPeriod", "\n ",) - # if type(self.FromReportDate) is datetime.date: - # FromReportDate = self.create_sub_element(ET, ReportPeriod, "FromReportDate", self.FromReportDate.strftime('%Y-%m-%d'),4) - # if type(self.ToReportDate) is datetime.date: - # ToReportDate = self.create_sub_element(ET, ReportPeriod, "ToReportDate", self.ToReportDate.strftime('%Y-%m-%d')) - - # mydata = ET.tostring(root, encoding = "unicode") - - # qbxml_query = """\n""" - # qbxml_query = qbxml_query + """""" - # qbxml_query = qbxml_query + "\n" + mydata - - # return qbxml_query - + def connect_to_quickbooks(self, qbxml_query=None): # Connect to Quickbooks - # sessionManager = win32com.client.Dispatch("QBXMLRP2.RequestProcessor") - # sessionManager.OpenConnection('', 'DASA') - # enumfodnc= win32com.client.Dispatch('QBXMLRP2.RequestProcessor') - # print(enumfodnc) - # print(enumfodnc.qbFileOpenDoNotCare) sessionManager = win32com.client.Dispatch("QBXMLRP2.RequestProcessor") sessionManager.OpenConnection('', 'DASA2') # ticket = sessionManager.BeginSession("z:\\DBW Bogor.qbw", 2) ticket = sessionManager.BeginSession("", 2) # Send query and receive response - # response_string = sessionManager.ProcessRequest(ticket, qbxml_query) self.response_string = sessionManager.ProcessRequest(ticket, self.QBXML) # Disconnect from Quickbooks sessionManager.EndSession(ticket) # Close the company file sessionManager.CloseConnection() # Close the connection - print(self.response_string) + # print(f'{self.response_string = }') self.isDataOK() return self.response_string def isDataOK(self): - print("isdataok") + # print("isdataok") # QBXML = ET.fromstring(self.response_string) # print(xmltodict.parse(self.response_string)) - varDict = xmltodict.parse(self.response_string) - pprint.pprint(varDict) - for _ in self.gen_dict_extract("@statusMessage", varDict): - print(_) - if 'Status OK'.lower()==_.lower(): - print(_) - isStatusOK = True - break - else: - isStatusOK=False - if isStatusOK: - print(self.returnRet(varDict)) + self.varDict = xmltodict.parse(self.response_string) + pprint.pprint(self.varDict) + self.listOfDict.varDict = self.varDict + self.listOfDict.filterKey = "@statusCode" + self.statusCode = self.listOfDict.firstValue() + self.listOfDict.filterKey = "@statusMessage" + self.statusMessage = self.listOfDict.firstValue() + self.listOfDict.filterKey = "@statusSeverity" + self.statusSeverity = self.listOfDict.firstValue() + print(f'{self.statusCode = }, {self.statusMessage = }, {self.statusSeverity = }') + # isStatusOK=None + + # for _ in self.find_listOfDict("FullName", ): ###berhasil + # print(f'{_ = }') + # for _ in self.gen_dict_extract("@statusMessage", self.varDict): + # print(_) + # if 'Status OK'.lower()==_.lower(): + # print(_) + # isStatusOK = True + # break + # else: + # isStatusOK=False + + # if self.ListOfDict.find_firstListOfDict("@statusMessage")['@statusMessage'].lower()=="status OK".lower(): + # # print(f'{self.retName = }') + # self.Rs = self.find_firstListOfDict(self.retName)[self.retName] + # # self.Rs=self.returnRet(self.varDict) + # # # print(self.find_listOfDict("FullName", )) ###test + # # print(self.find_listOfDict("FullName", self.find_listOfDict("QBXMLMsgsRs1", ))) ###test + # # # print(self.find_listOfDict("@statusMessage", )) ###test + # # for _ in self.find_listOfDict("QBXMLMsgsRs",): ###trial blm berhasil + # # print(f'2{_ = }') + # # print(f'{self.Rs = }') + # # print(type(self.Rs)) + # # print(self.find_firstListOfDict("FullName")['FullName']) + # # print(self.find_firstListOfDict("FullName")) + # # print(self.find_allListOfDict("FullName")) def returnRet(self, varDict): - print("returnRet") - pprint.pprint(varDict) - stillNoRetFound = True - counter = 0 + # pprint.pprint(self.varDict) print(f'{varDict = }') varDict = varDict['QBXML']['QBXMLMsgsRs'][self.__class__.__name__+"Rs"] print(f'{varDict = }') @@ -151,6 +122,156 @@ class baseQBQuery: return varDict[key] return None + def runCheck(self): + if self.varDict: + return True + if self.response_string: + return True + if self.Rs: + return True + if self.QBDict: + self.create_QBXML() + self.connect_to_quickbooks() + return True + return False + + def filter(self, key): + if not self.runCheck(): + return None + return self.ListOfDict(key, self.varDict, self.retName) + ### dont use this way, better returning class because the value if you assign to variable, the valu will be the last filterKey inputed + ### if return class, every filterKey is an object, different from other filterKey + self.listOfDict.varDict = self.varDict + self.listOfDict.filterKey = key + return self.listOfDict + ### + + def all(self): + if not self.runCheck(): + return None + return self.ListOfDict(None, self.varDict, self.retName).firstValue() + ### dont use this way + self.listOfDict.varDict = self.varDict + self.listOfDict.filterKey = self.retName + return self.listOfDict + ### + + + + class ListOfDict: + def __init__(self, key, var, retName) -> None: + # print(f'{key =}, {var =}') + # self.first = self.find_firstListOfDict(key) + if key: + self.filterKey = key + else: + self.filterKey = retName + # print(f"{self.filterKey = }") + self.varDict = var + # print("listofDict") + + def __repr__(self) -> str: + return str(self.all()) + + def filter(self, filterKey): + self.filterKey=filterKey + + + def all(self, var:dict=None, dataRetList:list=None): + + _lst = [x[self.filterKey] for x in self.find_listOfDict(var, dataRetList)] + # if _lst: + return _lst + # else: + # return [None] + + def allOnlyValue(self, var:dict=None, dataRetList:list=None): + _lst = [x for x in self.find_listOfDict(var, dataRetList)] + + def first(self, var:dict=None, dataRetList:list=None): + return next(self.find_listOfDict( var, dataRetList), None) + + def firstValue(self, var:dict=None, dataRetList:list=None): + # return self.first(var, dataRetList)[self.filterKey] + _val=self.first(var, dataRetList) + if _val: + return _val[self.filterKey] + else: + return None + + def last(self, var:dict=None, dataRetList:list=None): + # *_, last = self.find_listOfDict( var, dataRetList) + _val= self.all(var, dataRetList) + if _val:return _val[-1] + else: return None + + def lastValue(self, var:dict=None, dataRetList:list=None): + _val=self.last(var, dataRetList) + # print(f"lastValue {_val =}") + if _val: + return _val[self.filterKey] + else: + return None + + def count(self, var:dict=None, dataRetList:list=None): + return len(self.all()) + + def find_listOfDict(self, var:dict=None, dataRetList:list=None, ): + # print("genfinekeys") + if var==None: + var=self.varDict + # print(f"{var = }") + if dataRetList is None: + dataRetList = [] + if isinstance(var, list): + # print("list var") + for _ in var: + yield from self.find_listOfDict( _, ) + elif isinstance(var, dict): + # print("dict var") + if self.filterKey in var: + dataRetList.append({self.filterKey: var[self.filterKey]}) + # print(f"{dataRetList = }") + yield {self.filterKey: var[self.filterKey]} + else: + # print(f'dict else var={var}') + for _ in var: + # print(_) + yield from self.find_listOfDict(var[_], ) + return dataRetList + + # def find_allListOfDict(self, key, var:dict=None, dataRetList:list=None): + # return [x for x in self.find_listOfDict(key, var, dataRetList)] + + # def find_firstListOfDictValue(self, key, var:dict=None, dataRetList:list=None): + # return self.find_firstListOfDict(key, var, dataRetList)[key] + + # def find_firstListOfDict(self, key, var:dict=None, dataRetList:list=None): + # return next(self.find_listOfDict(key, var, dataRetList), None) + + # def find_listOfDict(self, key, var:dict=None, dataRetList:list=None, ): + # # print("genfinekeys") + # if var==None: + # var=self.varDict + # # print(f"{var = }") + # if dataRetList is None: + # dataRetList = [] + # if isinstance(var, list): + # # print("list var") + # for _ in var: + # yield from self.find_listOfDict(key, _, ) + # elif isinstance(var, dict): + # # print("dict var") + # if key in var: + # dataRetList.append({key: var[key]}) + # # print(f"{dataRetList = }") + # yield {key: var[key]} + # else: + # # print(f'dict else var={var}') + # for _ in var: + # # print(_) + # yield from self.find_listOfDict(key, var[_], ) + # return dataRetList def gen_dict_extract(self, key, var:dict=None): ### Utils if var==None: @@ -314,30 +435,6 @@ class baseQBQuery: # except ValueError: # return None # # raise ValueError("Incorrect data format, should be YYYY-MM-DD") -print('### GeneralSummaryReport ###') + if __name__ == '__main__': - ini=GeneralSummaryReportQuery(ReportDateMacro='LastYear') - # ini=GeneralSummaryReportQuery(FromReportDate='2023-01-11', ToReportDate='2023-01-12') - ini=GeneralSummaryReportQuery(GeneralSummaryReportType='SalesByItemSummary') - # ini=GeneralSummaryReportQuery(GeneralSummaryReportType='SalesByRepSummary') - # ini=GeneralSummaryReportQuery(GeneralSummaryReportType='PurchaseByVendorSummary') - # ini=GeneralSummaryReportQuery(GeneralSummaryReportType='ProfitAndLossStandard') - # ini=GeneralSummaryReportQuery(GeneralSummaryReportType='PhysicalInventoryWorksheet') - # ini=GeneralSummaryReportQuery(GeneralSummaryReportType='InventoryStockStatusByItem') - print(ini.create_QBXML()) - # print(f'print ini:{ini}') - # print(type(ini.get_datarow())) - # print(ini.get_total()) - # print(f'ini.getdatarow:{ini.get_datarow()}') - ini.connect_to_quickbooks() - df=pd.DataFrame(ini.get_datarow()[0]) - headers=list(df.columns) - print(df.tail(10)) - df.columns=['CustomerFullName', 'TotalSales'] - # df['TotalSales']=df['TotalSales'].astype(float) - df['TotalSales']=pd.to_numeric(df['TotalSales']) - # df['TotalSales']=df['TotalSales'].astype('Int64') - print(df.loc[df['TotalSales']>0]) - print(df.tail(10)) - print(headers) - print(list(df.keys().values)) \ No newline at end of file + pass \ No newline at end of file