update exim

This commit is contained in:
bcomsugi 2025-02-21 06:08:34 +07:00
parent 89982de5b0
commit c8c7816f01

238
exim.py
View File

@ -6,6 +6,8 @@ from QBClass.QBClasses import InvoiceQuery, SalesOrderQuery
import time import time
import json import json
import pandas as pd import pandas as pd
import numpy as np
import datetime
print('succes Loading modules') print('succes Loading modules')
@ -26,7 +28,7 @@ def timer(func):
@timer @timer
def get_all_so_from_invoice(MaxReturned=None, FromTxnDate=None, ToTxnDate=None): def get_all_so_from_invoice( FromTxnDate=None, ToTxnDate=None, MaxReturned=None,):
print(MaxReturned, FromTxnDate, ToTxnDate) print(MaxReturned, FromTxnDate, ToTxnDate)
start = time.time() start = time.time()
print('Get Invoice Query List. Processing..... wait for at minute(1 month=90secs)') print('Get Invoice Query List. Processing..... wait for at minute(1 month=90secs)')
@ -160,6 +162,7 @@ def process():
@timer @timer
def process_data(iq_list, so_dict): def process_data(iq_list, so_dict):
print('process_data')
# iq = InvoiceQuery(MaxReturned= 20, IncludeLinkedTxns='true', IncludeLineItems='true', debug=False) # iq = InvoiceQuery(MaxReturned= 20, IncludeLinkedTxns='true', IncludeLineItems='true', debug=False)
# iq = InvoiceQuery(TxnDateRangeFilter_FromTxnDate='2024-02-01', TxnDateRangeFilter_ToTxnDate='2024-02-29', IncludeLinkedTxns='true', IncludeLineItems='true') # iq = InvoiceQuery(TxnDateRangeFilter_FromTxnDate='2024-02-01', TxnDateRangeFilter_ToTxnDate='2024-02-29', IncludeLinkedTxns='true', IncludeLineItems='true')
# pprint(iq_list, sort_dicts=False) # pprint(iq_list, sort_dicts=False)
@ -214,81 +217,81 @@ def process_data(iq_list, so_dict):
soNotInOneInv.append(sodt['RefNumber']) soNotInOneInv.append(sodt['RefNumber'])
if float(linkedtxn['Amount'])<0: if float(linkedtxn['Amount'])<0:
if sodt['TotalAmount']!=linkedtxn['Amount'][1:]: # if sodt['TotalAmount']!=linkedtxn['Amount'][1:]:
if is_soLinkedToOneInvoice: #maybe the SO is manually closed, check it item by item, find which item is not in invoice # pass
if sodt['IsManuallyClosed'] == 'true': # if is_soLinkedToOneInvoice: #maybe the SO is manually closed, check it item by item, find which item is not in invoice
pass # if sodt['IsManuallyClosed'] == 'true':
print(f"{sodt['TxnID'] = } {sodt['RefNumber'] = }") # pass
manuallyClosedSO.append(sodt['RefNumber']) # print(f"{sodt['TxnID'] = } {sodt['RefNumber'] = }")
else: # manuallyClosedSO.append(sodt['RefNumber'])
print('SO TotalAmount<>Amount in Invoice. not Manually closed and not fully Invoiced') # else:
pprint(f'{linkedtxn = }', sort_dicts=False) # print('SO TotalAmount<>Amount in Invoice. not Manually closed and not fully Invoiced')
print(f"{sodt['TxnID'] = } {sodt['RefNumber'] = }") # pprint(f'{linkedtxn = }', sort_dicts=False)
print(sodt) # print(f"{sodt['TxnID'] = } {sodt['RefNumber'] = }")
openSO.append(sodt['RefNumber']) # print(sodt)
else: # openSO.append(sodt['RefNumber'])
pass # this SO is fully invoiced, starting process to export the details # else:
try: pass # this SO is fully invoiced, starting process to export the details
if not isinstance(sodt['SalesOrderLineRet'],list): try:
sodt['SalesOrderLineRet'] = [sodt['SalesOrderLineRet']] if not isinstance(sodt['SalesOrderLineRet'],list):
if not isinstance(txn['InvoiceLineRet'],list): sodt['SalesOrderLineRet'] = [sodt['SalesOrderLineRet']]
txn['InvoiceLineRet'] = [txn['InvoiceLineRet']] if not isinstance(txn['InvoiceLineRet'],list):
for so_line in sodt['SalesOrderLineRet']: txn['InvoiceLineRet'] = [txn['InvoiceLineRet']]
checklist = ['ItemRef', ] for so_line in sodt['SalesOrderLineRet']:
if len([ i for i in checklist if i in so_line])==0: checklist = ['ItemRef', ]
continue if len([ i for i in checklist if i in so_line])==0:
soitemref_fullname = so_line.get('ItemRef',{}).get('FullName') continue
soquantity:str = so_line.get('Quantity') soitemref_fullname = so_line.get('ItemRef',{}).get('FullName')
# print(f'{soquantity = }') soquantity:str = so_line.get('Quantity')
sounitofmeasure = so_line.get('UnitOfMeasure') # print(f'{soquantity = }')
# sooverrideuomsetref_fullname = so_line['OverrideUOMSetRef']['FullName'] sounitofmeasure = so_line.get('UnitOfMeasure')
sorate = so_line.get('Rate') # sooverrideuomsetref_fullname = so_line['OverrideUOMSetRef']['FullName']
soamount = so_line.get('Amount') sorate = so_line.get('Rate')
soinvoiced = so_line.get('Invoiced') soamount = so_line.get('Amount')
soismanuallyclosed = so_line['IsManuallyClosed'] soinvoiced = so_line.get('Invoiced')
soother2 = so_line.get('Other2') soismanuallyclosed = so_line['IsManuallyClosed']
soother2 = so_line.get('Other2')
#check compare to the invoicelineret #check compare to the invoicelineret
for inv_line in txn['InvoiceLineRet']: #loop start from top in order for inv_line in txn['InvoiceLineRet']: #loop start from top in order
is_inv_so_line_ok = True is_inv_so_line_ok = True
if 'soline' not in inv_line: #this line has no so link yet if 'soline' not in inv_line: #this line has no so link yet
if inv_line['ItemRef']['FullName'] != soitemref_fullname: if inv_line.get('ItemRef',{}).get('FullName') != soitemref_fullname:
continue continue
if inv_line.get('UnitOfMeasure') != sounitofmeasure: if inv_line.get('UnitOfMeasure') != sounitofmeasure:
print(f"{inv_line['ItemRef']['FullName'] = } {inv_line['UnitOfMeasure']=} != {sounitofmeasure=}") print(f"{inv_line['ItemRef']['FullName'] = } {inv_line['UnitOfMeasure']=} != {sounitofmeasure=}")
is_inv_so_line_ok = False
#do convertion????
# continue
if soinvoiced and inv_line.get('Quantity',0)!=soinvoiced: #compre with the invoiced
print(f"{inv_line['ItemRef']['FullName'] = } {inv_line['Quantity']=} != {soquantity=}")
is_inv_so_line_ok = False
if sorate:
if float(inv_line.get('Rate',0))!=float(sorate):
print(f"{inv_line['ItemRef']['FullName'] = } {inv_line['Rate']=} <> {sorate=} ; {float(inv_line.get('Rate',0)) = } {float(sorate) = }")
is_inv_so_line_ok = False is_inv_so_line_ok = False
#do convertion???? # if soamount:
# continue # if float(inv_line.get('Amount',0))!=float(soamount):
if soinvoiced and inv_line.get('Quantity',0)!=soinvoiced: #compre with the invoiced # print(f"{txn['RefNumber']} {inv_line['ItemRef']['FullName'] = } {inv_line['Amount']=} != {soamount=}")
print(f"{inv_line['ItemRef']['FullName'] = } {inv_line['Quantity']=} != {soquantity=}") # is_inv_so_line_ok = False
is_inv_so_line_ok = False if not is_inv_so_line_ok:
if sorate: print(f"{inv_line['ItemRef']['FullName'] = } Some detail not equal")
if float(inv_line.get('Rate',0))!=float(sorate): continue
print(f"{inv_line['ItemRef']['FullName'] = } {inv_line['Rate']=} <> {sorate=} ; {float(inv_line.get('Rate',0)) = } {float(sorate) = }") #add to the spesific invoiceline
is_inv_so_line_ok = False inv_line['soline']= {'RefNumber':sodt['RefNumber'],
# if inv_line['Amount']!=soamount or float(inv_line['Amount'])!=float(soamount): 'TxnDate':sodt['TxnDate'],
if soamount: 'ItemRef_FullName':soitemref_fullname,
if float(inv_line.get('Amount',0))!=float(soamount): 'Quantity':soquantity,
print(f"{inv_line['ItemRef']['FullName'] = } {inv_line['Amount']=} != {soamount=}") 'UnitOfMeasure':sounitofmeasure,
is_inv_so_line_ok = False 'Rate':sorate,
if not is_inv_so_line_ok: 'Amount':soamount,
print(f"{inv_line['ItemRef']['FullName'] = } Some detail not equal") 'Invoiced':soinvoiced,
continue 'IsManuallyClosed':soismanuallyclosed,
#add to the spesific invoiceline 'Other2':soother2}
inv_line['soline']= {'RefNumber':sodt['RefNumber'], break
'TxnDate':sodt['TxnDate'], except Exception as e:
'ItemRef_FullName':soitemref_fullname, print(f"SO {sodt['RefNumber'] = } {txn['RefNumber'] = }")
'Quantity':soquantity, print(f'ERROR: {e}')
'UnitOfMeasure':sounitofmeasure,
'Rate':sorate,
'Amount':soamount,
'Invoiced':soinvoiced,
'IsManuallyClosed':soismanuallyclosed,
'Other2':soother2}
break
except Exception as e:
print(f"SO {sodt['RefNumber'] = } {txn['RefNumber'] = }")
print(f'ERROR: {e}')
else: else:
print('Linkedtxn amount is positif(should be negatif') print('Linkedtxn amount is positif(should be negatif')
except Exception as e: except Exception as e:
@ -329,9 +332,7 @@ def checking_iqwith_so(iq_list):
continue continue
if 'ItemRef' not in inv_line: if 'ItemRef' not in inv_line:
inv_line_no_itemref.append({'RefNumber':txn['RefNumber'], inv_line_no_itemref.append({'RefNumber':txn['RefNumber'],
'idx':idx, 'idx':idx,})
'ItemRef_FullName':inv_line['ItemRef']['FullName'],
'Amount':inv_line['Amount']})
continue continue
if '400_Sales' not in inv_line['ItemRef']['FullName']: if '400_Sales' not in inv_line['ItemRef']['FullName']:
inv_line_no_soline.append({'RefNumber':txn['RefNumber'], inv_line_no_soline.append({'RefNumber':txn['RefNumber'],
@ -364,7 +365,7 @@ def writeToFile(iq_list=None, so_dict=None, filename = "", suffix="", indent=2):
so_dict_json = json.dumps(so_dict) so_dict_json = json.dumps(so_dict)
else: else:
so_dict_json = json.dumps(so_dict, indent=indent) so_dict_json = json.dumps(so_dict, indent=indent)
with open(f"{filename}{suffix}.json", "w") as outfile: with open(f"{filename}_so_dict{suffix}.json", "w") as outfile:
outfile.write(so_dict_json) outfile.write(so_dict_json)
return True return True
except Exception as e: except Exception as e:
@ -380,24 +381,71 @@ def readJsonFromFile(filename):
print(e) print(e)
return [] return []
# print(timeit.repeat(process, repeat=1))
# process()
invqueryfilename = 'exim\Data\iq' def get_last_date_of_month(stryearmonth:str):
# iq_list, so_dict = get_all_so_from_invoice(MaxReturned=20) # Get Last date of Month
### Reading from QB and write to a file depends on txndate # Using replace() + timedelta()
# iq_list, so_dict = get_all_so_from_invoice(FromTxnDate="2024-08-01", ToTxnDate="2024-08-31")
# writeToFile(iq_list, so_dict)
### reading from existing file the iq_list and so_dict jsonfile # initializing date
test_date = datetime.datetime.fromisoformat(stryearmonth)
# test_date = datetime.datetime(2018, 6, 4)
# printing original date
print("The original date is : " + str(test_date))
# getting next month
# using replace to get to last day + offset
# to reach next month
nxt_mnth = test_date.replace(day=28) + datetime.timedelta(days=4)
# subtracting the days from next month date to
# get last date of current Month
res = nxt_mnth - datetime.timedelta(days=nxt_mnth.day)
# printing result
datesplit = stryearmonth.split('-')
print("Last date of month : " + str(res.day), f"{datesplit[0]}-{datesplit[1]}-{str(res.day)}")
iq_list = readJsonFromFile(f"{invqueryfilename}.json") return f"{datesplit[0]}-{datesplit[1]}-{str(res.day)}"
so_dict = readJsonFromFile(f"{invqueryfilename}_so_dict.json")
print(f'{len(iq_list) = } {len(so_dict) = }')
iq_list = process_data(iq_list, so_dict)
suffix = '_withsoindent2'
writeToFile(iq_list, filename=f'{invqueryfilename}', suffix=suffix, indent=2)
iq_list = readJsonFromFile(f'{invqueryfilename}{suffix}.json')
print(len(iq_list))
print(f'Seems {invqueryfilename}{suffix}.json is {checking_iqwith_so(iq_list)}') #checking the iq_list. is it good to import to new QB?
def main(fromtxndate, totxndate, maxreturned:int=None):
# print(timeit.repeat(process, repeat=1))
# process()
invqueryfilename = f'exim\Data\{fromtxndate}iq'
# if maxreturned:
# iq_list, so_dict = get_all_so_from_invoice(MaxReturned=maxreturned)
# else:
# try:
# _fromdate = datetime.datetime.fromisoformat(fromtxndate)
# _todate = datetime.datetime.fromisoformat(totxndate)
# except Exception as e:
# print('date format should be yyyy-mm-dd example: "2024-03-09"')
# return False
# ## Reading from QB and write to a file depends on txndate
# iq_list, so_dict = get_all_so_from_invoice(FromTxnDate=fromtxndate, ToTxnDate=totxndate)
# writeToFile(iq_list, so_dict, filename=invqueryfilename)
### reading from existing file the iq_list and so_dict jsonfile
iq_list = readJsonFromFile(f"{invqueryfilename}.json")
so_dict = readJsonFromFile(f"{invqueryfilename}_so_dict.json")
print(f'{len(iq_list) = } {len(so_dict) = }')
iq_list = process_data(iq_list, so_dict)
suffix = '_withsoindent2'
writeToFile(iq_list, filename=f'{invqueryfilename}', suffix=suffix, indent=2)
iq_list = readJsonFromFile(f'{invqueryfilename}{suffix}.json')
print(len(iq_list))
print(f'Seems {invqueryfilename}{suffix}.json is {checking_iqwith_so(iq_list)}') #checking the iq_list. is it good to import to new QB?
if __name__=='__main__':
# print(np.arange('2021-02', '2021-03', dtype='datetime64[D]'))
fromtxndate = '2022-08-01'
totxndate = get_last_date_of_month(fromtxndate)
_fromdate = datetime.datetime.fromisoformat(fromtxndate)
print(fromtxndate)
main(fromtxndate, totxndate)