diff --git a/ItemInventoryQuery.py b/ItemInventoryQuery.py index ad1785e..439e99f 100644 --- a/ItemInventoryQuery.py +++ b/ItemInventoryQuery.py @@ -179,7 +179,8 @@ if __name__ == "__main__": # ini= ItemInventoryQuery(IncludeRetElement=['FullName', 'DataExtRet'] , OwnerID = str(x), MaxReturned=None) # ini= ItemInventoryQuery( OwnerID = str(x), MaxReturned="10", NameRangeFilter=["TSHT:TS WOODGRAIN:TS-252", "TSHT:TS WOODGRAIN:TS-252"]) # ini= ItemInventoryQuery( OwnerID = str(x), MaxReturned="10", NameRangeFilter=["TSHT:TS LUXURY:TS-L-252", "TSHT:TS LUXURY:TS-L-252"]) - ini= ItemInventoryQuery( OwnerID = str(x), MaxReturned="10") + # ini= ItemInventoryQuery( OwnerID = str(x), MaxReturned="10") + ini= ItemInventoryQuery( OwnerID ="0", MaxReturned=None) # ini= ItemInventoryQuery( OwnerID = str(x)) # ini.to_excel('ItemInventory\ItemInventory_FromQB.xlsx') itu = ini.connect_to_quickbooks(ini.create_QBXML()) @@ -189,7 +190,7 @@ if __name__ == "__main__": print("YEAH") df = pd.DataFrame.from_dict(ini.get_data(itu)) print(df) - # df.to_excel('ItemInventory\ItemInventory_FromQB.xlsx', index=False) + df.to_excel('ItemInventory\ItemInventory_FromQB.xlsx', index=False) modtime = datetime.fromtimestamp(os.path.getmtime('ItemInventory\ItemInventory_FromQB.xlsx')) print(f"modified Time:{modtime}") break diff --git a/SO_to_Inv/PriceLevelQuery.py b/SO_to_Inv/PriceLevelQuery.py index 0f2d770..5abbf97 100644 --- a/SO_to_Inv/PriceLevelQuery.py +++ b/SO_to_Inv/PriceLevelQuery.py @@ -6,6 +6,9 @@ import datetime import pandas as pd from datetime import date import timeit +import pythoncom +import os + class PriceLevelQuery: def __init__(self, **kwargs) -> None: @@ -16,8 +19,13 @@ class PriceLevelQuery: self.IncludeRetElement = kwargs['IncludeRetElement'] if 'IncludeRetElement' in kwargs else [] self.TxnDateRangeFilter = kwargs['TxnDateRangeFilter'] if 'TxnDateRangeFilter' in kwargs else None self.FullName = kwargs['FullName'] if 'FullName' in kwargs and isinstance(kwargs['FullName'], list) else [] + print(f'FULLNAME:{self.FullName}') self.NameFilter = kwargs['NameFilter'] if 'NameFilter' in kwargs else None self.ItemRef = kwargs['ItemRef'] if 'ItemRef' in kwargs else None + self.QBXML = None + self.response_string = None + self.status_ok = False + self.status_msg = None def create_sub_element(self, ET, parentNode, thisNode, text="\n", whiteSpace = 0, attrib =None): if type(attrib) is not dict: @@ -62,7 +70,8 @@ class PriceLevelQuery: qbxml_query = qbxml_query + """""" qbxml_query = qbxml_query + "\n" + mydata # print(f'create_QBXML->qbxml_query: {qbxml_query}') - return qbxml_query + self.QBXML = qbxml_query + return self.QBXML def create_invoiceadd_QBXML(self): root = ET.Element("QBXML") @@ -124,7 +133,7 @@ class PriceLevelQuery: # enumfodnc= win32com.client.Dispatch('QBXMLRP2.RequestProcessor') # print(enumfodnc) # print(enumfodnc.qbFileOpenDoNotCare) - sessionManager = win32com.client.Dispatch("QBXMLRP2.RequestProcessor") + sessionManager = win32com.client.Dispatch("QBXMLRP2.RequestProcessor", pythoncom.CoInitialize()) sessionManager.OpenConnection('', 'DASA2') # ticket = sessionManager.BeginSession("z:\\DBW Bogor.qbw", 2) @@ -137,7 +146,8 @@ class PriceLevelQuery: sessionManager.EndSession(ticket) # Close the company file sessionManager.CloseConnection() # Close the connection # print (f'response_string:{response_string}') - return response_string + self.response_string = response_string + return self.response_string def __str__(self, *args) -> str: # return str(self._get_datarow(self.connect_to_quickbooks(self.create_QBXML()))) @@ -148,10 +158,11 @@ class PriceLevelQuery: def get_sales_order_header(self, *args): return self. _get_sales_order_header(self.connect_to_quickbooks(self.create_QBXML())) - def status_ok(self, QBXML): #for InvoiceAddRS - - tree = ET.fromstring(QBXML) - + def get_status(self, QBXML=None): #for InvoiceAddRS + if not QBXML: + tree = ET.fromstring(self.response_string) + else: + tree = ET.fromstring(QBXML) GSRQRs = tree.find(".//PriceLevelQueryRs") # print(f"GSRQRs:{GSRQRs}") status_code = GSRQRs.attrib #.get('statusCode') @@ -159,10 +170,13 @@ class PriceLevelQuery: # print(GSRQRs.attrib['statusCode']) status=GSRQRs.attrib.get('statusMessage') - print(f'status={status}') + print(f'get_status={status}') + self.status_msg = status_code if 'OK' in status: + self.status_ok = True return True, status_code else: + self.status_ok = False return False, status_code @@ -346,7 +360,7 @@ class PriceLevelQuery: def get_pricelevel(self, response_string=None): if not response_string: response_string = self.connect_to_quickbooks(self.create_QBXML()) - statusok, status = self.status_ok(response_string) + statusok, status = self.get_status(response_string) if statusok: QBXML = ET.fromstring(response_string) PriceLevellist = {} @@ -356,7 +370,6 @@ class PriceLevelQuery: PriceLevelNamelist = [] # PriceLevelName = QBXML.find('.//Name').text - # print(f'PriceLevelPerItemRets count:{len(PriceLevelPerItemRets)}') for PriceLevelRet in PriceLevelRets: PriceLevelPerItemRets = PriceLevelRet.findall('.//PriceLevelPerItemRet') PriceLevelName = PriceLevelRet.find('.//Name').text @@ -375,11 +388,12 @@ class PriceLevelQuery: PriceLeveldf.sort_values(by=['PriceLevelName', 'FullName'], inplace=True) PriceLeveldf=PriceLeveldf.reset_index(drop=True) print(PriceLeveldf) + print(os.getcwd()) PriceLeveldf.to_excel('ItemInventory\PriceLevel.xlsx', sheet_name=PriceLevelName, index=False ) # print(PriceLevellist) - return PriceLevellist + return PriceLevellist, status else: - return None + return None, status def create_open_sales_order_qbxml(self, txnid:list, IncludeLineItems=True): root = ET.Element("QBXML") @@ -421,19 +435,40 @@ class PriceLevelQuery: return None return None + def name_list(self): + self.get_status(self.connect_to_quickbooks(self.create_QBXML())) + namelist = [] + if self.status_ok: + tree = ET.fromstring(self.response_string) + + for _ in tree.iter('Name'): + # print(_.text) + namelist.append(_.text) + if len(namelist)>0: + return namelist + return None + + print('### PriceLevelQuery ###') if __name__ == '__main__': starttime = timeit.default_timer() - # ini=PriceLevelQuery(FullName= '999 HPL', IncludeRetElement = ['TxnID', 'TimeCreated', 'TimeModified','TxnNumber', 'CustomerRef', 'IsManuallyClosed', 'IsFullyInvoiced']) - # ini=PriceLevelQuery(FullName= 'abadi serpong', IncludeRetElement = ['TxnID', 'TimeCreated', 'TimeModified','TxnNumber', 'CustomerRef', 'TxnDate', 'RefNumber', 'IsManuallyClosed', 'IsFullyInvoiced','TotalAmount']) - ini = PriceLevelQuery(FullName = ['t 202202', 'M 202202'], ) + FullName = ['t 202202', 'M 202202', 'b 202202'] + FullName = None + ini = PriceLevelQuery(FullName = FullName, IncludeRetElement=['Name'] ) # ini = PriceLevelQuery( ItemRef="ECO:0:ECO-002") - itu = ini.create_QBXML() - print(f'createQBXML->main:{itu}') - response_string = ini.connect_to_quickbooks(itu) - print(f'response_string:{response_string}') - response_string = None - pricelevel = ini.get_pricelevel() + print(ini.name_list()) + # itu = ini.create_QBXML() + # print(f'createQBXML->main:{itu}') + # response_string = ini.connect_to_quickbooks(itu) + # print(f'response_string:{response_string}') + # response_string = None + # pricelevel, status = ini.get_pricelevel() + # if pricelevel: + # print(f'Success Save Price Level : {FullName}') + # else: + # print(f"Saving Not Success. status: {status}") + + # print(f'pricelevel:{pricelevel}') # print(ini.get_open_sales_order(open_sales_orders)) diff --git a/SO_to_Inv/readSO.py b/SO_to_Inv/readSO.py index 794ee7f..f7895b4 100644 --- a/SO_to_Inv/readSO.py +++ b/SO_to_Inv/readSO.py @@ -8,7 +8,10 @@ from datetime import date import timeit import os import pythoncom +# from icecream import ic +from decimal import Decimal +# ic.configureOutput(includeContext=True, ) class SalesOrderQuery: def __init__(self, **kwargs) -> None: # print(f'kwargs:{kwargs}') @@ -17,20 +20,25 @@ class SalesOrderQuery: self.PriceLevelName = None self.SPPriceLevelName = None self.cwd = kwargs['cwd'] if 'cwd' in kwargs else os.getcwd() + self.TxnID = kwargs['TxnID'] if 'TxnID' in kwargs else None + self.item_inventory_path = "ItemInventory" self.price_level_filename = "PriceLevel.xlsx" self._df_price_level = pd.read_excel(os.path.join(self.cwd, self.item_inventory_path, self.price_level_filename), usecols=['FullName', 'PriceLevelName', 'CustomPrice'],) print(self._df_price_level) - print(type(self._df_price_level.loc[(self._df_price_level['FullName']=="ECO:0:ECO-002") & (self._df_price_level['PriceLevelName']=="T 202202")].values.tolist()[0][2])) + # print(type(self._df_price_level.loc[(self._df_price_level['FullName']=="ECO:0:ECO-002") & (self._df_price_level['PriceLevelName']=="T 202202")].values.tolist()[0][2])) + # print(self._df_price_level.loc[(self._df_price_level['FullName']=="TEDG:S122:EDG-009-1/22") & (self._df_price_level['PriceLevelName']=="T 202202")].values.tolist()[0][2]) self.FullName = kwargs['FullName'] if 'FullName' in kwargs else None self.CustomerPriceLevelName_filename = "CustomerList.xlsx" self._df_customer = pd.read_excel(os.path.join(self.cwd, self.item_inventory_path, self.CustomerPriceLevelName_filename), usecols=['FullName', 'PriceLevelName', 'SPName'],) self._df_customer = self._df_customer.fillna('') print(self._df_customer) - - self.Customer = self._df_customer.loc[(self._df_customer["FullName"]==self.FullName)].values.tolist()[0] - print(f'Customer:{self.Customer}') + self.Customer = None + if self.FullName: + if self.FullName in self._df_customer['FullName'].values: + self.Customer = self._df_customer.loc[(self._df_customer["FullName"]==self.FullName)].values.tolist()[0] + print(f'Customer:{self.Customer}') self.DN = kwargs['DN'] if 'DN' in kwargs else {} self.Reuse = kwargs['Reuse'] if 'Reuse' in kwargs else None @@ -52,9 +60,23 @@ class SalesOrderQuery: # print(self.Reuse) # if not self.Reuse: # self.dfDN, self.ext_doc_no_list = self.get_ext_doc_no_list(self.DN) - # self.RefNumber = kwargs['RefNumber'] if 'RefNumber' in kwargs else self.ext_doc_no_list + self.RefNumber = kwargs['RefNumber'] if 'RefNumber' in kwargs else None # self.get_sales_order_header() - + + + def pprintXml(self, qbxml_query): + import xml.dom.minidom + from xml.sax.saxutils import escape + from lxml import etree + # dom = xml.dom.minidom.parse(xml_fname) # or + if isinstance(qbxml_query, str): + dom = xml.dom.minidom.parseString(qbxml_query) + pretty_xml_as_string = dom.toprettyxml(" ").split('\n') + pretty_xml_as_string = '\n'.join([s for s in pretty_xml_as_string if s.strip() ]) + # print(f'pprintxml:\n{pretty_xml_as_string}') + return pretty_xml_as_string + + def create_sub_element(self, ET, parentNode, thisNode, text="\n", whiteSpace = 0, attrib =None): if type(attrib) is not dict: attrib = {} @@ -79,20 +101,34 @@ class SalesOrderQuery: QBXMLMsgsRq.text = "\n " SalesOrderQueryRq = self.create_sub_element(ET, QBXMLMsgsRq, "SalesOrderQueryRq","\n " ) # SalesOrderType = self.create_sub_element(ET, SalesOrderQueryRq, 'SalesOrderType', self.SalesOrderType) - if self.FullName: - EntityFilter = self.create_sub_element(ET, SalesOrderQueryRq, 'EntityFilter', "\n ") - FullName = self.create_sub_element(ET, EntityFilter, "FullName", self.FullName, 6) - if self.DateMacro: - TxnDateRangeFilter = self.create_sub_element(ET, SalesOrderQueryRq, "TxnDateRangeFilter", "\n ",) - SalesOrderType = self.create_sub_element(ET, TxnDateRangeFilter, "DateMacro", self.DateMacro) - # SalesOrderType = self.create_sub_element(ET, SalesOrderQueryRq, "DateMacro", self.DateMacro) + if self.TxnID: + pass + print(self.TxnID) + if isinstance(self.TxnID, list): + for _ in self.TxnID: + TxnID = self.create_sub_element(ET, SalesOrderQueryRq, "TxnID", _, ) + else: + TxnID = self.create_sub_element(ET, SalesOrderQueryRq, "TxnID", self.TxnID, ) + else: + if self.RefNumber: + pass + RefNumberFilter = self.create_sub_element(ET, SalesOrderQueryRq, 'RefNumberFilter', "\n ",) + MatchCriterion = self.create_sub_element(ET,RefNumberFilter, 'MatchCriterion', "Contains",) + RefNumber = self.create_sub_element(ET, RefNumberFilter, 'RefNumber', self.RefNumber, ) + elif self.FullName: + EntityFilter = self.create_sub_element(ET, SalesOrderQueryRq, 'EntityFilter', "\n ") + FullName = self.create_sub_element(ET, EntityFilter, "FullName", self.FullName, 6) + elif self.DateMacro: + TxnDateRangeFilter = self.create_sub_element(ET, SalesOrderQueryRq, "TxnDateRangeFilter", "\n ",) + SalesOrderType = self.create_sub_element(ET, TxnDateRangeFilter, "DateMacro", self.DateMacro) + # SalesOrderType = self.create_sub_element(ET, SalesOrderQueryRq, "DateMacro", self.DateMacro) - elif type(self.FromTxnDate) is datetime.date or type(self.ToTxnDate) is datetime.date: - TxnDateRangeFilter = self.create_sub_element(ET, SalesOrderQueryRq, "TxnDateRangeFilter", "\n ",) - if type(self.FromTxnDate) is datetime.date: - FromTxnDate = self.create_sub_element(ET, TxnDateRangeFilter, "FromTxnDate", self.FromTxnDate.strftime('%Y-%m-%d'),4) - if type(self.ToTxnDate) is datetime.date: - ToTxnDate = self.create_sub_element(ET, TxnDateRangeFilter, "ToTxnDate", self.ToTxnDate.strftime('%Y-%m-%d')) + elif type(self.FromTxnDate) is datetime.date or type(self.ToTxnDate) is datetime.date: + TxnDateRangeFilter = self.create_sub_element(ET, SalesOrderQueryRq, "TxnDateRangeFilter", "\n ",) + if type(self.FromTxnDate) is datetime.date: + FromTxnDate = self.create_sub_element(ET, TxnDateRangeFilter, "FromTxnDate", self.FromTxnDate.strftime('%Y-%m-%d'),4) + if type(self.ToTxnDate) is datetime.date: + ToTxnDate = self.create_sub_element(ET, TxnDateRangeFilter, "ToTxnDate", self.ToTxnDate.strftime('%Y-%m-%d')) if self.IncludeLineItems: IncludeLineItems = self.create_sub_element(ET, SalesOrderQueryRq, "IncludeLineItems", self.IncludeLineItems, 4) if len(self.IncludeRetElement)>0: @@ -153,8 +189,17 @@ class SalesOrderQuery: return self.get_customer_pricelevel(response_string) return response_string - def create_invoiceadd_QBXML(self): + def create_invoiceadd_QBXML(self, soDict=None): + print('create_ionvoiceadd_QBXML') + txn_date = str(date.today()) + ref_number = None + if soDict: + self.SalesOrderList = soDict['data'] + txn_date = soDict.get('txn_date', str(date.today())) + ref_number = soDict.get('ref_number', None) + # txn_date = str(date.today()) + root = ET.Element("QBXML") root.tail = "\n" root.text = "\n " @@ -168,35 +213,56 @@ class SalesOrderQuery: FullName = self.create_sub_element(ET, CustomerRef, "FullName", self.SalesOrderList[0]['CustomerFullName'], 8 ) TemplateRef = self.create_sub_element(ET, InvoiceAdd, "TemplateRef", "\n ", 8 ) TemplateFullName = self.create_sub_element(ET, TemplateRef, "FullName", "DBW Invoice (11%)", 8 ) - today = str(date.today()) - TxnDate = self.create_sub_element(ET, InvoiceAdd, "TxnDate", today,8) # self.DN['TxnDate'], 8 ) - - RefNumber = self.create_sub_element(ET, InvoiceAdd, "RefNumber", today,8 ) # self.DN['DNRefNum'], 8 ) - ShipDate = self.create_sub_element(ET, InvoiceAdd, "ShipDate", today,8) # self.DN['TxnDate'], 8 ) + # today = str(date.today()) + # print(txn_date) + TxnDate = self.create_sub_element(ET, InvoiceAdd, "TxnDate", txn_date, 8) # self.DN['TxnDate'], 8 ) + if ref_number: + RefNumber = self.create_sub_element(ET, InvoiceAdd, "RefNumber", ref_number, 8 ) # self.DN['DNRefNum'], 8 ) + # ShipDate = self.create_sub_element(ET, InvoiceAdd, "ShipDate", txn_date,8) # self.DN['TxnDate'], 8 ) # Memo = self.create_sub_element(ET, InvoiceAdd, "Memo", self.DN['Memo'], 10 ) disc_amount = 0 for soidx, salesorder in enumerate(self.SalesOrderList): - SOTxnId = salesorder['TxnID'] - disc_amount+=int(salesorder['Disc_Amount']) - print(f'create_invoiceadd_QBXML->SOTxnId: {SOTxnId}') - for itemline in salesorder['SalesOrderLineRet']: - # if 'DNQuantity' in itemline: - InvoiceLineAdd = self.create_sub_element(ET, InvoiceAdd, "InvoiceLineAdd", "\n ", 10 ) - # Quantity = self.create_sub_element(ET, InvoiceLineAdd, "Quantity", str(itemline['DNQuantity'] ), 12 ) - # Quantity = self.create_sub_element(ET, InvoiceLineAdd, "Quantity", str(itemline['BackOrdered'] ), 12 ) - # UnitOfMeasure = self.create_sub_element(ET, InvoiceLineAdd, "UnitOfMeasure", str(itemline['UOM']), 12 ) - LinkToTxn = self.create_sub_element(ET, InvoiceLineAdd, "LinkToTxn", "\n ", 10 ) - TxnID = self.create_sub_element(ET, LinkToTxn, "TxnID", SOTxnId,14 ) - TxnLineID = self.create_sub_element(ET, LinkToTxn, "TxnLineID", itemline['TxnLineID'], 12 ) - if soidx == len(self.SalesOrderList)-1: #last list then set the'400_Sales_discount' - print(f'disc_amount:{format(disc_amount, ".2f")}') - if disc_amount != 0: + disc_amount = 0 + if 'TxnID' in salesorder: + SOTxnId = salesorder['TxnID'] + # disc_amount+=int(salesorder['Disc_Amount']) + print(f'create_invoiceadd_QBXML->SOTxnId: {SOTxnId}') + for itemline in salesorder['SalesOrderLineRet']: + backOrdered = str(itemline['BackOrdered']) + # backOrdered = '1' #testing purpose + if float(backOrdered) > 0: + discPerPcs = float(itemline['discPerPcs']) + discPerItem = float(backOrdered) * discPerPcs + disc_amount += discPerItem + InvoiceLineAdd = self.create_sub_element(ET, InvoiceAdd, "InvoiceLineAdd", "\n ", 10 ) + # Quantity = self.create_sub_element(ET, InvoiceLineAdd, "Quantity", str(itemline['DNQuantity'] ), 12 ) + Quantity = self.create_sub_element(ET, InvoiceLineAdd, "Quantity", backOrdered, 12 ) + # UnitOfMeasure = self.create_sub_element(ET, InvoiceLineAdd, "UnitOfMeasure", str(itemline['UOM']), 12 ) + LinkToTxn = self.create_sub_element(ET, InvoiceLineAdd, "LinkToTxn", "\n ", 10 ) + TxnID = self.create_sub_element(ET, LinkToTxn, "TxnID", SOTxnId,14 ) + TxnLineID = self.create_sub_element(ET, LinkToTxn, "TxnLineID", itemline['TxnLineID'], 12 ) + # if soidx == len(self.SalesOrderList)-1: #last list then set the'400_Sales_discount' + # print(f'disc_amount:{format(disc_amount, ".2f")}') + # if disc_amount != 0: + # # disc_amount=format(disc_amount, ".2f") + # InvoiceLineAdd = self.create_sub_element(ET, InvoiceAdd, "InvoiceLineAdd", "\n ", 10 ) + # ItemRef = self.create_sub_element(ET, InvoiceLineAdd, "ItemRef", "\n ", 12) + # ItemFullName = self.create_sub_element(ET, ItemRef, "FullName", "400_Sales Discount", 12) + # ItemRate = self.create_sub_element(ET, InvoiceLineAdd, "Rate", str(disc_amount), 10) + if salesorder['Disc_Amount']!=0: # disc_amount != 0: # disc_amount=format(disc_amount, ".2f") InvoiceLineAdd = self.create_sub_element(ET, InvoiceAdd, "InvoiceLineAdd", "\n ", 10 ) ItemRef = self.create_sub_element(ET, InvoiceLineAdd, "ItemRef", "\n ", 12) ItemFullName = self.create_sub_element(ET, ItemRef, "FullName", "400_Sales Discount", 12) ItemRate = self.create_sub_element(ET, InvoiceLineAdd, "Rate", str(disc_amount), 10) + elif 'other_itemFullName' in salesorder and 'other_qty' in salesorder and 'other_rate' in salesorder: + pass + InvoiceLineAdd = self.create_sub_element(ET, InvoiceAdd, "InvoiceLineAdd", "\n ", 10 ) + ItemRef = self.create_sub_element(ET, InvoiceLineAdd, "ItemRef", "\n ", 12) + ItemFullName = self.create_sub_element(ET, ItemRef, "FullName", salesorder['other_itemFullName'], 12) + Quantity = self.create_sub_element(ET, InvoiceLineAdd, "Quantity", str(salesorder['other_qty']), 12 ) + ItemRate = self.create_sub_element(ET, InvoiceLineAdd, "Rate", str(salesorder['other_rate']), 10) mydata = ET.tostring(root, encoding = "unicode") @@ -205,8 +271,10 @@ class SalesOrderQuery: qbxml_query = qbxml_query + "\n" + mydata # print(f'create_invoiceadd_QBXML->Create_Invoiceadd_QBXML: {qbxml_query}') # print(f"replyfrom qbxml:{self.connect_to_quickbooks(qbxml_query)}") + # print([s for s in qbxml_query.split('\n') if s.strip(' ') != '']) - return qbxml_query + # print(self.pprintXml(qbxml_query)) + return self.pprintXml(qbxml_query) def connect_to_quickbooks(self, qbxml_query): @@ -229,7 +297,7 @@ class SalesOrderQuery: sessionManager.EndSession(ticket) # Close the company file sessionManager.CloseConnection() # Close the connection # print (f'response_string:{response_string}') - return response_string + return self.pprintXml(response_string) def __str__(self, *args) -> str: # return str(self._get_datarow(self.connect_to_quickbooks(self.create_QBXML()))) @@ -258,49 +326,127 @@ class SalesOrderQuery: return False, status_code - def _get_sales_order_header(self, response_string): + def get_saved_refnumber(self, QBXML): #for InvoiceAddRS + + tree = ET.fromstring(QBXML) + objects = {} + GSRQRs = tree.find(".//InvoiceAddRs") + refnumber = tree.find(".//RefNumber").text + print(f"saved refnumber:{refnumber}") + objects['RefNumber'] = refnumber + objects['Customer_FullName']= tree.find(".//CustomerRef/FullName").text + objects['TxnDate'] = tree.find(".//TxnDate").text + objects['BalanceRemaining'] = tree.find(".//BalanceRemaining").text + return objects + + def get_discperpcs(self, ItemFullName, Rate): + discPerPcs = 0 + if self.Customer: + if self.Customer[2]: + try: + pricelist = self._df_price_level.loc[(self._df_price_level['FullName']==ItemFullName) & (self._df_price_level['PriceLevelName']==self.Customer[2])].values.tolist()[0][2] + discPerPcs = Rate-pricelist + # ic(Rate, disc, (Rate - self._df_price_level.loc[(self._df_price_level['FullName']==ItemFullName) & (self._df_price_level['PriceLevelName']==self.SPPriceLevelName)].values.tolist()[0][2])) + if discPerPcs < 0 : + discPerPcs = 0 + print(f"WARNING: Rate is Lower than Pricelist Cust:{self.Customer} ItemName:{ItemFullName} Rate:{Rate} < {pricelist}") + except: + print('Pricelevelname not found') + return None + return discPerPcs + + + def _get_sales_order_header(self, response_string, includefullInvoiced=False): print('_get_sales_order_header') - # print(f'responsestring:{response_string}') + print(f'responsestring sales order header:{self.pprintXml(response_string)}') QBXML = ET.fromstring(response_string) datadict = {} SalesOrderdict = {} _SalesOrderlist = [] SalesOrderRets = QBXML.findall('.//SalesOrderRet') + if self.Customer == None: + custtemp = QBXML.find('.//SalesOrderRet/CustomerRef/FullName') + if custtemp != None: + self.Customer = custtemp.text + self.Customer = self._df_customer.loc[(self._df_customer["FullName"]==self.Customer)].values.tolist()[0] + print(f'Customer:{self.Customer}') # print(SalesOrderRets) for SalesOrderRet in SalesOrderRets: RefNumber = SalesOrderRet.find('RefNumber').text # Memo = SalesOrderRet.find('Memo').text + TxnDate = SalesOrderRet.find('TxnDate').text + TxnNumber = SalesOrderRet.find('TxnNumber').text CustomerFullName = SalesOrderRet.find('CustomerRef/FullName').text TxnID = SalesOrderRet.find('TxnID').text TotalAmount = SalesOrderRet.find('TotalAmount').text IsFullyInvoiced = SalesOrderRet.find('IsFullyInvoiced').text IsManuallyClosed = SalesOrderRet.find('IsManuallyClosed').text + if includefullInvoiced==False: + if IsFullyInvoiced.lower()=='true': + # print(IsFullyInvoiced) + continue # print(CustomerFullName, TxnID, TotalAmount) SalesOrderdict = {'RefNumber':RefNumber, 'CustomerFullName':CustomerFullName, 'TxnID':TxnID, + 'TxnDate':TxnDate, 'TxnNumber':TxnNumber, 'TotalAmount':TotalAmount, 'IsFullyInvoiced':IsFullyInvoiced, 'IsManuallyClosed':IsManuallyClosed, 'SalesOrderLineRet':[]} SalesOrderLineRet = SalesOrderRet.findall('SalesOrderLineRet') - # print(len(SalesOrderLineRet)) + # ic(len(SalesOrderLineRet)) + disc_amount=0 if len(SalesOrderLineRet) > 0: - disc_amount=0 + # disc_amount=0 for SalesOrderLineRet in SalesOrderLineRet: + discPerItem = 0 + discPerPcs = 0 + convertQTY = 1 TxnLineID = SalesOrderLineRet.find('TxnLineID').text - ItemFullName = SalesOrderLineRet.find('ItemRef/FullName').text + ItemFullName = SalesOrderLineRet.find('ItemRef/FullName') + if ItemFullName is None: + print("no itemfullname") + continue #skip this orderline + else: + ItemFullName=ItemFullName.text + # print(ItemFullName) + if 'Sales' in ItemFullName and 'Disc' in ItemFullName: + continue #skip this sales discount line Quantity = SalesOrderLineRet.find('Quantity').text UnitOfMeasure = SalesOrderLineRet.find('UnitOfMeasure').text - Rate = float(SalesOrderLineRet.find('Rate').text) - Amount = float(SalesOrderLineRet.find('Amount').text) + ### modified if UOM has ConvertQTY: '_' or ' of '-> in OverrideUOMSetRef + if '_' in UnitOfMeasure: + convertQTY = int(UnitOfMeasure.split('_')[1]) + OverrideUOMSetRef = SalesOrderLineRet.find('OverrideUOMSetRef/FullName') + if OverrideUOMSetRef != None: + OverrideUOMSetRef = OverrideUOMSetRef.text + if 'of' in OverrideUOMSetRef and UnitOfMeasure.upper() == 'BOX': + convertQTY = int(OverrideUOMSetRef.split('of')[1]) + print(f'OverrideUOMSetRef:{OverrideUOMSetRef}') + ### + + Rate = Decimal(SalesOrderLineRet.find('Rate').text) + Amount = Decimal(SalesOrderLineRet.find('Amount').text) # if self.SPPriceLevelName: - if self.Customer[2]: - # print(Rate, (Rate - self._df_price_level.loc[(self._df_price_level['FullName']==ItemFullName) & (self._df_price_level['PriceLevelName']==self.SPPriceLevelName)].values.tolist()[0][2])) - print(Quantity, Rate, (Rate - self._df_price_level.loc[(self._df_price_level['FullName']==ItemFullName) & (self._df_price_level['PriceLevelName']==self.Customer[2])].values.tolist()[0][2])) - disc_amount += float(Quantity) * (Rate-self._df_price_level.loc[(self._df_price_level['FullName']==ItemFullName) & (self._df_price_level['PriceLevelName']==self.Customer[2])].values.tolist()[0][2]) - # disc_amount+=float(Quantity)*2000 #testing only Invoiced = SalesOrderLineRet.find('Invoiced').text LineIsManuallyClosed = SalesOrderLineRet.find('IsManuallyClosed').text # print(TxnLineID, ItemFullName) - BackOrdered = float(Quantity) - float(Invoiced) - if BackOrdered: + BackOrdered = Decimal(Quantity) - Decimal(Invoiced) + if BackOrdered > 0 and LineIsManuallyClosed.lower() == 'false' : + # ic(self.Customer) + discPerPcs = self.get_discperpcs(ItemFullName, Rate) + if discPerPcs == None: + return False + discPerItem = BackOrdered * discPerPcs + disc_amount += discPerItem + # if self.Customer: + # if self.Customer[2]: + # discPerPcs = Rate-self._df_price_level.loc[(self._df_price_level['FullName']==ItemFullName) & (self._df_price_level['PriceLevelName']==self.Customer[2])].values.tolist()[0][2] + # # ic(Rate, disc, (Rate - self._df_price_level.loc[(self._df_price_level['FullName']==ItemFullName) & (self._df_price_level['PriceLevelName']==self.SPPriceLevelName)].values.tolist()[0][2])) + # if discPerPcs > 0: + # print(Quantity, BackOrdered, Rate, (Rate - self._df_price_level.loc[(self._df_price_level['FullName']==ItemFullName) & (self._df_price_level['PriceLevelName']==self.Customer[2])].values.tolist()[0][2])) + # discPerItem = BackOrdered * discPerPcs + # disc_amount += discPerItem + # # disc_amount += BackOrdered * discPerPcs # (Rate-self._df_price_level.loc[(self._df_price_level['FullName']==ItemFullName) & (self._df_price_level['PriceLevelName']==self.Customer[2])].values.tolist()[0][2]) + # else: + # discPerPcs = 0 SalesOrderLinedict = {'TxnLineID':TxnLineID, 'ItemFullName':ItemFullName, 'Quantity':Quantity, @@ -310,6 +456,9 @@ class SalesOrderQuery: 'BackOrdered':BackOrdered, 'Invoiced':Invoiced, 'LineIsManuallyClosed':LineIsManuallyClosed, + 'discPerItem':discPerItem, # backorder qty * disc per pcs + 'discPerPcs':discPerPcs, + 'convertQTY':convertQTY, } SalesOrderdict['SalesOrderLineRet'].append(SalesOrderLinedict) SalesOrderdict['Disc_Amount']=disc_amount @@ -318,7 +467,8 @@ class SalesOrderQuery: self.SalesOrderList=_SalesOrderlist # print(f'_get_sales_order_header->Salesorderlist: {self.SalesOrderList}') return self.SalesOrderList - + + def addDiscountToInvoiceList(self, _dict:dict): print("addDiscountToInvoiceList") @@ -501,11 +651,12 @@ class SalesOrderQuery: print(f'txnid: {txnlist}', type(txnlist)) txnid = [] for x in txnlist: + # print(x, type(x)) if isinstance(x, list): txnid.append(x[0]) else: txnid.append(x) - break + # break # txnid = [x[0] if isinstance(x, list) else x for x in txnid ] print(txnid) if txnid: @@ -522,7 +673,9 @@ if __name__ == '__main__': # ini=SalesOrderQuery(FullName= '999 HPL', IncludeRetElement = ['TxnID', 'TimeCreated', 'TimeModified','TxnNumber', 'CustomerRef', 'IsManuallyClosed', 'IsFullyInvoiced']) # ini=SalesOrderQuery(FullName= 'YSM Interior', IncludeRetElement = ['TxnID', 'TimeCreated', 'TimeModified','TxnNumber', 'CustomerRef', 'TxnDate', 'RefNumber', 'IsManuallyClosed', 'IsFullyInvoiced','TotalAmount']) - ini=SalesOrderQuery(FullName= 'Abadi Serpong', IncludeRetElement = ['TxnID', 'TimeCreated', 'TimeModified','TxnNumber', 'CustomerRef', 'TxnDate', 'RefNumber', 'IsManuallyClosed', 'IsFullyInvoiced','TotalAmount']) + # ini=SalesOrderQuery(FullName= 'Abadi Serpong', IncludeRetElement = ['TxnID', 'TimeCreated', 'TimeModified','TxnNumber', 'CustomerRef', 'TxnDate', 'RefNumber', 'IsManuallyClosed', 'IsFullyInvoiced','TotalAmount']) + # ini=SalesOrderQuery(RefNumber = 'B23070685', FullName= 'Abadi Serpong', IncludeRetElement = ['TxnID', 'TimeCreated', 'TimeModified','TxnNumber', 'CustomerRef', 'TxnDate', 'RefNumber', 'IsManuallyClosed', 'IsFullyInvoiced','TotalAmount']) + ini=SalesOrderQuery(RefNumber = 'B23070685', IncludeRetElement = ['TxnID', 'TimeCreated', 'TimeModified','TxnNumber', 'CustomerRef', 'TxnDate', 'RefNumber', 'IsManuallyClosed', 'IsFullyInvoiced','TotalAmount']) # iya = ini.create_customerquery_QBXML() #pakai excel saja lebih cepat # print(iya) print(f'createQBXML:{ini.create_QBXML()}') diff --git a/django/Invoice/templates/Invoice/prepare_data.html b/django/Invoice/templates/Invoice/prepare_data.html new file mode 100644 index 0000000..c1eb163 --- /dev/null +++ b/django/Invoice/templates/Invoice/prepare_data.html @@ -0,0 +1,30 @@ +{% extends 'base.html' %} +{% load crispy_forms_tags %} +{% load humanize %} +{% block title %}Prepare Data{% endblock title %} + +{% block body %} +