mirror of
https://github.com/bcomsugi/dasaproject.git
synced 2026-01-09 15:32:38 +07:00
Merge branch 'master' of https://github.com/bcomsugi/dasaproject
This commit is contained in:
commit
39d788c5f0
@ -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
|
||||
|
||||
@ -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 version="13.0"?>"""
|
||||
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))
|
||||
|
||||
@ -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()}')
|
||||
|
||||
30
django/Invoice/templates/Invoice/prepare_data.html
Normal file
30
django/Invoice/templates/Invoice/prepare_data.html
Normal file
@ -0,0 +1,30 @@
|
||||
{% extends 'base.html' %}
|
||||
{% load crispy_forms_tags %}
|
||||
{% load humanize %}
|
||||
{% block title %}Prepare Data{% endblock title %}
|
||||
|
||||
{% block body %}
|
||||
<div class="container-fluid">
|
||||
<form action="" method="POST" class="card border-info-subtle p-3 mt-2" autocomplete="off" id="form">
|
||||
{% csrf_token %}
|
||||
<button type="submit" class="btn btn-primary mt-2 me-2 ms-2" name="subject" value="Item Inventory">Item Inventory</button>
|
||||
<button type="submit" class="btn btn-primary mt-2 me-2 ms-2" name="subject" value="Customer List">Customer List</button>
|
||||
<div class="container-fluid card border-info p-3 mt-3">
|
||||
{% for so_no in objects %}
|
||||
<div class="form-check form-check-inline">
|
||||
<input class="form-check-input" type="checkbox" id="inlineCheckbox{{forloop.count}}" name="selected_items" value="{{so_no}}">{{so_no}}
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
<button type="submit" class="btn btn-primary mt-2 me-2 ms-2" name="subject" value="Price Level List">Price Level List</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<datalist id='itemname'>
|
||||
{% for customer in customers %}
|
||||
<option value="{{customer|first}}" data-pk="{{customer|first}}" data-desc="{{customer|first}}" data-rate="{{customer|first}}">
|
||||
{% endfor %}
|
||||
</datalist>
|
||||
|
||||
{% endblock body %}
|
||||
@ -4,18 +4,7 @@
|
||||
{% block title %}Invoice{% endblock title %}
|
||||
|
||||
{% block body %}
|
||||
{% comment %} {% if messages %}
|
||||
<div class="alert alert-success" role="alert">
|
||||
{{message}}
|
||||
</div>
|
||||
{% endif %} {% endcomment %}
|
||||
{% if messages %}
|
||||
<ul class="messages">
|
||||
{% for message in messages %}
|
||||
<li{% if message.tags %} class="alert alert-{{ message.tags }}"{% endif %}>{{ message }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
|
||||
|
||||
<div class="container-fluid">
|
||||
<form action="" method="POST" class="card border-info-subtle p-3 mt-2" autocomplete="off" id="form">
|
||||
@ -23,7 +12,7 @@
|
||||
<div class="row">
|
||||
</div>
|
||||
<!-- <input name="customer_fullname" type='text' list='itemname' onchange='changeitem(event)' value='{{customer_name}}' class='textinput form-control'> -->
|
||||
<input name="customerreffullname" type='text' list='itemname' value='{{customer_name}}' id='id_CustomerRefFullName' class='textinput form-control' autofocus>
|
||||
<input name="customerreffullname" type='text' list='itemname' value='{{customer_name}}' id='id_CustomerRefFullName' class='textinput form-control' placeholder="Choose Customer" autofocus>
|
||||
|
||||
<button type="submit" class="btn btn-primary mt-2 me-2 ms-2" id="id_btnsave" onclick="checksubmit(event)">Save</button>
|
||||
<!-- <button type="submit" class="btn btn-primary mt-2 me-2 ms-2" id="id_btnsave" >Save</button> -->
|
||||
|
||||
110
django/Invoice/templates/Invoice/so_details_form.html
Normal file
110
django/Invoice/templates/Invoice/so_details_form.html
Normal file
@ -0,0 +1,110 @@
|
||||
{% extends 'base.html' %}
|
||||
{% block body %}
|
||||
<!-- <form method="POST" action="{{ request.path }}"> -->
|
||||
<div class="container">
|
||||
<form method="POST" action="{% url 'Invoice:save_inv' %}" class="modal-content">
|
||||
{% csrf_token %}
|
||||
<div class="modal-header">
|
||||
<!-- <h1>Choose Items</h1> -->
|
||||
<h2>{{ customer_fullname }}</h2>
|
||||
<div>
|
||||
<h3> <label class="form-check-label">Ref Number</label> <input type="text" name="ref_number" value="">
|
||||
</h3>
|
||||
</div>
|
||||
<div>
|
||||
<h3> <label class="form-check-label">Date</label> <input type="date" name="date" required>
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="mb-3 mt-3">
|
||||
<input type="hidden" name="customer_fullname" value="{{ customer_fullname }}">
|
||||
|
||||
<!-- <input name="customerreffullname" type='text' list='itemname' value='{{customer_name}}' id='id_CustomerRefFullName' class='textinput form-control' autofocus> -->
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">Item</th>
|
||||
<th scope="col">Date</th>
|
||||
<th scope="col">SO Number</th>
|
||||
<th scope="col">Ordered</th>
|
||||
<th scope="col">Prev. Inv</th>
|
||||
<th scope="col">To Invoice</th>
|
||||
<th scope="col">UOM</th>
|
||||
<th scope="col">Rate</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for so_dict in objects %}
|
||||
<!-- {{so_dict}} -->
|
||||
{% for so_line in so_dict.SalesOrderLineRet %}
|
||||
<tr>
|
||||
<td>
|
||||
<input type="hidden" name="RefNumber" value="{{ so_dict.RefNumber }}">
|
||||
<input type="hidden" name="CustomerFullName" value="{{ so_dict.CustomerFullName }}">
|
||||
<input type="hidden" name="TxnID" value="{{ so_dict.TxnID }}">
|
||||
<input type="hidden" name="TxnDate" value="{{ so_dict.TxnDate }}">
|
||||
<input type="hidden" name="TotalAmount" value="{{ so_dict.TotalAmount }}">
|
||||
{% for k, v in so_line.items %}
|
||||
<input type="hidden" name="{{ k }}" value="{{ v }}">
|
||||
{% endfor %}
|
||||
<div class="form-check">
|
||||
<input type="checkbox" name="so_field" value="{{ so_line.TxnLineID }}" id="id_so_field_{{forloop.counter}}" class="form-check-input" checked>
|
||||
<label for="id_so_field_{{ forloop.counter }}" class="form-check-label">{{so_line.ItemFullName}}
|
||||
</label>
|
||||
</div>
|
||||
</td>
|
||||
<td>{{ so_dict.TxnDate }}</td>
|
||||
<td>{{ so_dict.RefNumber }}</td>
|
||||
<td>{% widthratio so_line.Quantity so_line.convertQTY 1 %}</td>
|
||||
<td>{% widthratio so_line.Invoiced so_line.convertQTY 1 %}</td>
|
||||
<td><input type="number" name="backordered" required value="{% widthratio so_line.BackOrdered so_line.convertQTY 1 %}" min="0" max="{% widthratio so_line.BackOrdered so_line.convertQTY 1 %}"> </td>
|
||||
<td>{{ so_line.UOM }}</td>
|
||||
<td><input type="number" name="rate" required value="{% widthratio so_line.Rate 1 so_line.convertQTY %}" min="0" > </td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
<tr>
|
||||
<!-- bisa jadikan for loop jika banyak item lagi -->
|
||||
<td>
|
||||
<input type="hidden" name="other_items" value="peti">
|
||||
<div class="form-check">
|
||||
<input type="checkbox" name="selected_items" value="peti" class="form-check-input peti">
|
||||
<label class="form-check-label">PETI</label>
|
||||
</div>
|
||||
</td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td><input type="number" name="other_qty" required value="1" min="0" max="100"> </td>
|
||||
<td>PETI</td>
|
||||
<td><input type="number" name="other_rate" required value="40000" min="0" max="40000000"> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<input type="hidden" name="other_items" value="expedition">
|
||||
<div class="form-check">
|
||||
<input type="checkbox" name="selected_items" value="expedition" class="form-check-input expedition">
|
||||
<label class="form-check-label">Ekspedisi</label>
|
||||
</div>
|
||||
</td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td><input type="number" name="other_qty" required value="1" min="0" max="1"> </td>
|
||||
<td></td>
|
||||
<td><input type="number" name="other_rate" required value="0" min="0" max="10000000"> </td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="submit" class="btn btn-primary mt-2 me-2 ms-2" id="id_btnsave" >Save to Invoice</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@ -2,10 +2,10 @@
|
||||
{% block body %}
|
||||
<!-- <form method="POST" action="{{ request.path }}"> -->
|
||||
<div class="container">
|
||||
<form method="POST" action="{% url 'Invoice:show_inv' %}" class="modal-content">
|
||||
<form method="POST" action="{% url 'Invoice:choose_inv' %}" class="modal-content">
|
||||
{% csrf_token %}
|
||||
<div class="modal-header">
|
||||
<h1>Choose SO</h1>
|
||||
<h2>Select SO Customer: {{ customer_fullname }}</h2>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="mb-3 mt-3">
|
||||
@ -40,7 +40,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="submit" class="btn btn-primary mt-2 me-2 ms-2" id="id_btnsave" >Save</button>
|
||||
<button type="submit" class="btn btn-primary mt-2 me-2 ms-2" id="id_btnsave" >Choose</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@ -1,13 +1,18 @@
|
||||
from django.urls import path
|
||||
from . import views
|
||||
|
||||
# from icecream import install
|
||||
# install()
|
||||
# from icecream import ic
|
||||
# ic.configureOutput(includeContext=True, )
|
||||
app_name = "Invoice"
|
||||
|
||||
urlpatterns = [
|
||||
# path('', views.home_view ),
|
||||
path('', views.show_customer, name="show_customer" ),
|
||||
path('selectso', views.select_so, name="select_so" ),
|
||||
path('showinv', views.show_inv, name="show_inv" ),
|
||||
path('showinv', views.choose_inv, name="choose_inv" ),
|
||||
path('saveinv', views.save_inv, name="save_inv" ),
|
||||
path('preparedata', views.prepare_data, name="prepare_data" ),
|
||||
|
||||
|
||||
path('', views.index, name="index"),
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
from django.shortcuts import render, get_object_or_404, redirect
|
||||
from django.urls import reverse
|
||||
from django.http import HttpResponse, JsonResponse
|
||||
from django.http import HttpResponse, JsonResponse, HttpResponseRedirect
|
||||
from django.forms import modelformset_factory, inlineformset_factory
|
||||
from django.db import transaction
|
||||
from django.core import serializers
|
||||
@ -14,8 +14,14 @@ from django.contrib import messages
|
||||
import os
|
||||
import pandas as pd
|
||||
from django.conf import settings
|
||||
# from icecream import ic
|
||||
import timeit
|
||||
from decimal import Decimal
|
||||
from datetime import datetime
|
||||
|
||||
def get_SalesOrderQuery(customer_name):
|
||||
# ic.configureOutput(includeContext= True)
|
||||
|
||||
def get_SalesOrderQuery(customer_name, txnid=None):
|
||||
try:
|
||||
print("try")
|
||||
from SO_to_Inv.readSO import SalesOrderQuery
|
||||
@ -23,10 +29,11 @@ def get_SalesOrderQuery(customer_name):
|
||||
except:
|
||||
import sys
|
||||
sys.path.append('.')
|
||||
sys.path.append('..')
|
||||
print("except")
|
||||
print(sys.path)
|
||||
from SO_to_Inv.readSO import SalesOrderQuery
|
||||
|
||||
print("salesorderquery imported")
|
||||
# print(os.getcwd())
|
||||
# parentdir = os.path.dirname(os.getcwd())
|
||||
# print(parentdir)
|
||||
@ -34,13 +41,40 @@ def get_SalesOrderQuery(customer_name):
|
||||
|
||||
basedir = settings.BASE_DIR
|
||||
parentdir = os.path.dirname(basedir)
|
||||
ini=SalesOrderQuery(FullName= customer_name, IncludeRetElement = ['TxnID', 'TimeCreated', 'TimeModified','TxnNumber', 'CustomerRef', 'TxnDate', 'RefNumber', 'IsManuallyClosed', 'IsFullyInvoiced','TotalAmount'], cwd=parentdir)
|
||||
if txnid:
|
||||
ini=SalesOrderQuery(FullName= customer_name, TxnID=txnid, IncludeRetElement = ['TxnID', 'TimeCreated', 'TimeModified','TxnNumber', 'CustomerRef', 'TxnDate', 'RefNumber', 'IsManuallyClosed', 'IsFullyInvoiced','TotalAmount'], cwd=parentdir)
|
||||
pass
|
||||
else:
|
||||
ini=SalesOrderQuery(FullName= customer_name, IncludeRetElement = ['TxnID', 'TimeCreated', 'TimeModified','TxnNumber', 'CustomerRef', 'TxnDate', 'RefNumber', 'IsManuallyClosed', 'IsFullyInvoiced','TotalAmount'], cwd=parentdir)
|
||||
return ini
|
||||
return None
|
||||
|
||||
def get_TransactionQuery(txnid=None, refnumber=None, customername=None, txntypefilter=None, includeret=[ 'TxnID', 'EntityRef', 'TxnDate', 'RefNumber', 'Memo'] ):
|
||||
try:
|
||||
print("try")
|
||||
from qbtransactionquery import TransactionQuery
|
||||
|
||||
except:
|
||||
import sys
|
||||
sys.path.append('.')
|
||||
sys.path.append('..')
|
||||
print("except")
|
||||
print(sys.path)
|
||||
from qbtransactionquery import TransactionQuery
|
||||
print("transactionquery imported")
|
||||
|
||||
basedir = settings.BASE_DIR
|
||||
parentdir = os.path.dirname(basedir)
|
||||
if txnid:
|
||||
ini=TransactionQuery(FullName= customername, RefNumber = refnumber, TxnID=txnid, IncludeRetElement = includeret, cwd=parentdir)
|
||||
else:
|
||||
ini=TransactionQuery(FullName= customername, RefNumber = refnumber, IncludeRetElement =includeret, cwd=parentdir)
|
||||
return ini
|
||||
|
||||
|
||||
def show_customer(request):
|
||||
pass
|
||||
|
||||
print("show_customer")
|
||||
starttime = timeit.default_timer()
|
||||
# thispath = os.getcwd()
|
||||
# print(thispath)
|
||||
basedir = settings.BASE_DIR
|
||||
@ -54,15 +88,110 @@ def show_customer(request):
|
||||
if request.method =="POST":
|
||||
customer_name = request.POST.get("customerreffullname")
|
||||
print(f'customer_name: {customer_name}')
|
||||
context['objects'] = [['abc', 'def', 'ghi', 'jkl']]
|
||||
# context['objects'] = [['abc', 'def', 'ghi', 'jkl']]
|
||||
context['objects'] = []
|
||||
|
||||
print("The time difference is bef show customer :", timeit.default_timer() - starttime)
|
||||
|
||||
if customer_name:
|
||||
ini = get_SalesOrderQuery(customer_name)
|
||||
print("The time difference is mid show customer :", timeit.default_timer() - starttime)
|
||||
if ini:
|
||||
print("after ini show customer")
|
||||
qbxml = ini.create_QBXML()
|
||||
# print(qbxml)
|
||||
print("The time difference is :", timeit.default_timer() - starttime)
|
||||
print("timeeint")
|
||||
response_string = ini.connect_to_quickbooks(qbxml)
|
||||
# print(response_string)
|
||||
open_sales_orders = ini.get_open_so()
|
||||
print(f'open sales orders showcustomer:{open_sales_orders}')
|
||||
ini=None
|
||||
if not open_sales_orders:
|
||||
messages.info(request, f"There is No open SO for {customer_name}")
|
||||
return redirect("Invoice:show_customer")
|
||||
# if open_sales_orders:
|
||||
context['objects'] = open_sales_orders
|
||||
|
||||
|
||||
context['customer_fullname'] = customer_name
|
||||
print("The time difference is :", timeit.default_timer() - starttime)
|
||||
return render(request, "Invoice/so_list_form.html", context)
|
||||
# print(df.values.tolist())
|
||||
print("The time difference is :", timeit.default_timer() - starttime)
|
||||
return render(request, "Invoice/show-customers.html", context)
|
||||
|
||||
|
||||
def select_so(request):
|
||||
pass
|
||||
|
||||
def choose_inv(request):
|
||||
print("choose_inv")
|
||||
starttime = timeit.default_timer()
|
||||
|
||||
context={}
|
||||
if request.method == "POST":
|
||||
print(request.POST)
|
||||
data = dict(request.POST)
|
||||
del data['csrfmiddlewaretoken']
|
||||
del data['customer_fullname']
|
||||
# if 'other_items' in data:
|
||||
# del data['other_items']
|
||||
# del data['other_qty']
|
||||
# del data['other_rate']
|
||||
# del data['selected_items']
|
||||
|
||||
print(f"datadict:{data}")
|
||||
try:
|
||||
df = pd.DataFrame(data)
|
||||
print(df)
|
||||
except:
|
||||
print(Exception)
|
||||
return HttpResponse("DataFrame Error")
|
||||
print(f'json:{df.to_json(orient="records")}')
|
||||
print(df.to_dict("records"))
|
||||
|
||||
if ('so_field' in request.POST) and ('customer_fullname' in request.POST):
|
||||
print(request.POST.getlist('so_field'))
|
||||
open_sales_orders_TxnID = request.POST.getlist('so_field')
|
||||
customer_fullname = request.POST.get('customer_fullname')
|
||||
print(f'Customer_fullname:{customer_fullname} -> request values:{open_sales_orders_TxnID}')
|
||||
### get the SO detail
|
||||
ini=get_SalesOrderQuery(customer_fullname, open_sales_orders_TxnID)
|
||||
# ini=get_SalesOrderQuery(customer_fullname)
|
||||
print("")
|
||||
print("The time difference chooseinv is :", timeit.default_timer() - starttime)
|
||||
print(f'ini::{ini}')
|
||||
print("The time difference chooseinv is :", timeit.default_timer() - starttime)
|
||||
print("before ITU")
|
||||
itu = ini.get_open_sales_order(open_sales_orders_TxnID)
|
||||
# print(itu)
|
||||
print("The time difference after itu is :", timeit.default_timer() - starttime)
|
||||
print(f'get_open_sales_order:{itu}')
|
||||
if itu:
|
||||
context['objects'] = itu
|
||||
context['customer_fullname'] = customer_fullname
|
||||
# print("Invoiceaddqbxml:")
|
||||
# invoiceaddQBXML=ini.create_invoiceadd_QBXML()
|
||||
|
||||
# print(invoiceaddQBXML)
|
||||
# print("")
|
||||
# result=None
|
||||
# print("")
|
||||
# result = ini.connect_to_quickbooks(ini.create_invoiceadd_QBXML())
|
||||
# print("RESULT:")
|
||||
# print(result)
|
||||
print("The time difference finish choose inv is :", timeit.default_timer() - starttime)
|
||||
|
||||
return render(request, "Invoice/so_details_form.html", context)
|
||||
else:
|
||||
messages.warning(request, "Customer PriceLevel or PriceLevelList not found. please prepare data first and check Customer 'Special Customer Custom Field'")
|
||||
elif 'customer_fullname' in request.POST:
|
||||
customer_name = request.POST.get('customer_fullname')
|
||||
ini = get_SalesOrderQuery(customer_name)
|
||||
if ini:
|
||||
print("after ini")
|
||||
qbxml = ini.create_QBXML()
|
||||
print(qbxml)
|
||||
# print(qbxml)
|
||||
response_string = ini.connect_to_quickbooks(qbxml)
|
||||
print(response_string)
|
||||
open_sales_orders = ini.get_open_so()
|
||||
@ -73,39 +202,334 @@ def show_customer(request):
|
||||
|
||||
|
||||
context['customer_fullname'] = customer_name
|
||||
return render(request, "Invoice/so_list_form.html", context)
|
||||
# print(df.values.tolist())
|
||||
|
||||
print("The time difference is :", timeit.default_timer() - starttime)
|
||||
|
||||
|
||||
return render(request, "Invoice/show-customers.html", context)
|
||||
return render( request, "Invoice/so_list_form.html", context)
|
||||
# return HttpResponse('')
|
||||
|
||||
|
||||
def select_so(request):
|
||||
pass
|
||||
def unique(list1):
|
||||
|
||||
# insert the list to the set
|
||||
list_set = set(list1)
|
||||
# convert the set to the list
|
||||
unique_list = (list(list_set))
|
||||
return unique_list
|
||||
|
||||
def show_inv(request):
|
||||
print("show_inv")
|
||||
def check_duplicate_refnumber(refnumber):
|
||||
ini = get_TransactionQuery(refnumber=refnumber, includeret=['TxnID', 'RefNumber'])
|
||||
status, statuscode = ini.status_ok(ini.connect_to_quickbooks(ini.create_QBXML()))
|
||||
print(f'check duplicate refnumber:{status}; {statuscode}')
|
||||
return status ### status=True -> duplicate refnumber
|
||||
|
||||
|
||||
def save_inv(request):
|
||||
print("save_inv")
|
||||
starttime = timeit.default_timer()
|
||||
context={}
|
||||
if request.method == "POST":
|
||||
print(request.POST)
|
||||
# print(request.POST)
|
||||
data = dict(request.POST)
|
||||
del data['csrfmiddlewaretoken']
|
||||
del data['customer_fullname']
|
||||
### get others items into list of dict ###
|
||||
others=[]
|
||||
otherFullName = {'peti': 'PETI', 'expedition':'Sales_Ekspedisi'}
|
||||
ref_number = request.POST.get('ref_number', None)
|
||||
txn_date = request.POST.get('date', None)
|
||||
print(ref_number, txn_date)
|
||||
if len(ref_number)>20:
|
||||
return HttpResponse("RefNumber Invalid. ")
|
||||
elif ref_number.strip()=="":
|
||||
ref_number = None
|
||||
if ref_number and check_duplicate_refnumber(ref_number):
|
||||
messages.warning(request, 'RefNumber already Exist. please choose other RefNumber')
|
||||
return HttpResponseRedirect(request.META.get('HTTP_REFERER', '/'))
|
||||
return HttpResponse('RefNumber already Exist. please choose other RefNumber')
|
||||
if len(txn_date)<6:
|
||||
return HttpResponse("Date is Invalid")
|
||||
del data['ref_number']
|
||||
del data['date']
|
||||
if 'selected_items' in data:
|
||||
for _ in data['selected_items']:
|
||||
if _ in data['other_items']:
|
||||
data_idx = data['other_items'].index(_)
|
||||
print(f'selected item:{_} is in index:{data_idx}')
|
||||
other_qty = int(data['other_qty'][data_idx])
|
||||
other_rate = float(data['other_rate'][data_idx])
|
||||
if other_qty<=0:
|
||||
other_qty = 1
|
||||
if other_rate <= 0:
|
||||
continue
|
||||
temp_ = {'other_item':data['other_items'][data_idx], 'other_itemFullName': otherFullName[data['other_items'][data_idx]], 'other_qty':other_qty, 'other_rate': other_rate}
|
||||
others.append(temp_)
|
||||
del data['selected_items']
|
||||
if 'other_items' in data:
|
||||
del data['other_items']
|
||||
if 'other_qty' in data:
|
||||
del data['other_qty']
|
||||
if 'other_rate' in data:
|
||||
del data['other_rate']
|
||||
print(f'others:{others}')
|
||||
|
||||
print(f"datadict:{data}")
|
||||
required_data = ['RefNumber', 'CustomerFullName', 'TxnID', 'TxnDate', 'TotalAmount', 'TxnLineID', 'ItemFullName',
|
||||
'Quantity', 'UOM', 'Rate', 'Amount', 'Invoiced', 'LineIsManuallyClosed', 'backordered', 'rate', 'convertQTY']
|
||||
if 'so_field' not in data:
|
||||
return HttpResponse("no Selected Items. Please select at least 1 item to be invoiced.")
|
||||
for _ in required_data:
|
||||
if _ not in data:
|
||||
return HttpResponse(f"Required data not returned from the form: {_}")
|
||||
|
||||
### retrieve only the selected so_field ###
|
||||
so_field = data['so_field']
|
||||
del data['so_field']
|
||||
selectedItems = []
|
||||
for _ in so_field:
|
||||
if _ not in data['TxnLineID']:
|
||||
return HttpResponse(f"One of the TxnLineID is not valid: {_}")
|
||||
data_idx = data['TxnLineID'].index(_)
|
||||
try:
|
||||
df = pd.DataFrame(data)
|
||||
print(df)
|
||||
df = df[df['TxnLineID'].isin(so_field)].reset_index()
|
||||
print(df)
|
||||
except:
|
||||
print(Exception)
|
||||
return HttpResponse("DataFrame Error")
|
||||
# print(f'json:{df.to_json(orient="records")}')
|
||||
web_dict = df.to_dict("records")
|
||||
# print(f'web_dict:{web_dict}' )
|
||||
web_dict = sorted(web_dict, key=lambda x: x['TxnID'])
|
||||
# print(f'Sorted web_dict:{web_dict}' )
|
||||
if ('so_field' in request.POST) and ('customer_fullname' in request.POST):
|
||||
# print(request.POST.getlist('so_field'))
|
||||
open_sales_orders = request.POST.getlist('so_field')
|
||||
print(request.POST.getlist('so_field'))
|
||||
# open_sales_orders_TxnID = unique(request.POST.getlist('so_field'))
|
||||
open_sales_orders_TxnID = unique(df['TxnID'].to_list())
|
||||
customer_fullname = request.POST.get('customer_fullname')
|
||||
print(f'Customer_fullname:{customer_fullname} -> request values:{open_sales_orders}')
|
||||
print(f'Customer_fullname:{customer_fullname} -> request values:{open_sales_orders_TxnID}')
|
||||
### get the SO detail
|
||||
ini=get_SalesOrderQuery(customer_fullname)
|
||||
itu = ini.get_open_sales_order(open_sales_orders)
|
||||
print(f'ini::{ini}')
|
||||
print("before ITU")
|
||||
itu = ini.get_open_sales_order(open_sales_orders_TxnID)
|
||||
# print(itu)
|
||||
itu = sorted(itu, key=lambda x: x['TxnID'])
|
||||
print(f'get_open_sales_order:{itu}')
|
||||
if itu:
|
||||
invoiceaddQBXML=ini.create_invoiceadd_QBXML()
|
||||
### do the checking web_dict and openSO ###
|
||||
data_to_save = []
|
||||
dict_ = {}
|
||||
txnids = []
|
||||
disc_amount = 0
|
||||
for web in web_dict:
|
||||
for tu_ in itu:
|
||||
# print(tu_)
|
||||
if web['TxnID'] == tu_['TxnID'] and web['TxnDate'] == tu_['TxnDate'] and web['RefNumber'] == tu_['RefNumber']:
|
||||
if web['TxnID'] not in txnids: # new txn
|
||||
if dict_:
|
||||
dict_['Disc_Amount']=disc_amount
|
||||
data_to_save.append(dict_)
|
||||
dict_ = {'RefNumber': web['RefNumber'], 'CustomerFullName': tu_['CustomerFullName'], 'TxnID': web['TxnID'],
|
||||
'TxnDate': web['TxnDate'], 'TxnNumber': tu_['TxnNumber'],
|
||||
'TotalAmount': '0.00', 'IsFullyInvoiced': tu_['IsFullyInvoiced'], 'IsManuallyClosed': tu_['IsManuallyClosed'],
|
||||
'SalesOrderLineRet': [] }
|
||||
disc_amount = 0
|
||||
txnids.append(web['TxnID'])
|
||||
txnids = unique(txnids) ### not usefull
|
||||
for tu_line_ret in tu_['SalesOrderLineRet']:
|
||||
# print(tu_line_ret)
|
||||
if web['TxnLineID']==tu_line_ret['TxnLineID'] and web['ItemFullName']==tu_line_ret['ItemFullName']:
|
||||
### modified back the rate and backordered using convertQTY ###
|
||||
convertQTY = int(tu_line_ret['convertQTY'])
|
||||
webbackordered = Decimal(web['backordered']) * convertQTY
|
||||
webrate = Decimal(web['rate']) / convertQTY
|
||||
###
|
||||
if 0 < webbackordered <= Decimal(tu_line_ret['BackOrdered']):
|
||||
# print('put in list')
|
||||
discPerPcs=0
|
||||
discPerItem=0
|
||||
if webrate == Decimal(tu_line_ret['Rate']):
|
||||
discPerPcs = ini.get_discperpcs(web['ItemFullName'], webrate)
|
||||
elif webrate < Decimal(tu_line_ret['Rate']):
|
||||
discPerPcs = Decimal(tu_line_ret['Rate']) - webrate
|
||||
discPerItem = webbackordered * discPerPcs
|
||||
disc_amount += discPerItem
|
||||
|
||||
SalesOrderLinedict = {'TxnLineID':web['TxnLineID'],
|
||||
'ItemFullName':tu_line_ret['ItemFullName'],
|
||||
'Quantity':tu_line_ret['Quantity'],
|
||||
'UOM':tu_line_ret['UOM'],
|
||||
'Rate':webrate,
|
||||
'Amount':Decimal(tu_line_ret['Amount']),
|
||||
'BackOrdered':webbackordered,
|
||||
'Invoiced':tu_line_ret['Invoiced'],
|
||||
'LineIsManuallyClosed':tu_line_ret['LineIsManuallyClosed'],
|
||||
'discPerItem':discPerItem, # backorder qty * disc per pcs
|
||||
'discPerPcs':discPerPcs,
|
||||
'convertQTY':tu_line_ret['convertQTY']
|
||||
}
|
||||
# print(f'salesorderlineddict:{SalesOrderLinedict}')
|
||||
_salesorderlineret = dict_['SalesOrderLineRet']
|
||||
_salesorderlineret.append(SalesOrderLinedict)
|
||||
dict_['SalesOrderLineRet'] = _salesorderlineret
|
||||
|
||||
break
|
||||
break
|
||||
print(f'last:{dict_}')
|
||||
print(f'datatosaveonly:{data_to_save}')
|
||||
if not data_to_save:
|
||||
dict_['Disc_Amount']=disc_amount
|
||||
data_to_save.append(dict_)
|
||||
elif dict_ != data_to_save[-1]: #append the last dict_
|
||||
dict_['Disc_Amount']=disc_amount
|
||||
data_to_save.append(dict_)
|
||||
print('save the last dict')
|
||||
else:
|
||||
print('last data to save == dict')
|
||||
for _ in others:
|
||||
data_to_save.append(_)
|
||||
|
||||
dict_to_save = {'customer_fullname': customer_fullname, 'ref_number':ref_number, 'txn_date':txn_date, 'data':data_to_save }
|
||||
print(f'Final List:{dict_to_save}')
|
||||
print("")
|
||||
# print(itu)
|
||||
context['objects'] = itu
|
||||
context['customer_fullname'] = customer_fullname
|
||||
# print(context['objects'])
|
||||
print("Invoiceaddqbxml:")
|
||||
invoiceaddQBXML=ini.create_invoiceadd_QBXML(dict_to_save)
|
||||
|
||||
print(invoiceaddQBXML)
|
||||
result=None
|
||||
result = ini.connect_to_quickbooks(invoiceaddQBXML)
|
||||
print("RESULT:")
|
||||
print(result)
|
||||
rst, status_msg = ini.status_ok(result)
|
||||
if rst:
|
||||
saved_inv = ini.get_saved_refnumber(result)
|
||||
print(saved_inv)
|
||||
# context['messages']=[{"alert":"info", "message": "invoice Is Good"}]
|
||||
balance_remaining = "{:,}".format(float(saved_inv['BalanceRemaining']))
|
||||
date_format = '%Y-%m-%d'
|
||||
date_obj = datetime.strptime(saved_inv['TxnDate'], date_format).strftime('%d %b %Y')
|
||||
messages.success(request, f"Customer : {saved_inv['Customer_FullName']}<br>Invoice No : {saved_inv['RefNumber']}   Date : {date_obj}<br>Invoice Amount : Rp. {balance_remaining}<br> Is SAVED with link to SO No. : {unique(df['RefNumber'].to_list())}<br>it takes {round(timeit.default_timer() - starttime, 4)} secs")
|
||||
|
||||
# messages.info(request, 'Invoice Has Been SAVED2')
|
||||
else:
|
||||
messages.warning(request, f"Error saving SO No. {unique(df['RefNumber'].to_list())}<br>Status: {status_msg}")
|
||||
print("The time difference finish Save Inv is :", timeit.default_timer() - starttime)
|
||||
|
||||
return redirect('Invoice:show_customer')
|
||||
return render(request, "Invoice/show-customers.html", context)
|
||||
return render(request, "Invoice/so_details_form.html", context)
|
||||
else:
|
||||
return HttpResponse(f"You cannot Save, because There Is No Open Sales Order for Customer: {customer_fullname}")
|
||||
elif 'customer_fullname' in request.POST:
|
||||
customer_name = request.POST.get('customer_fullname')
|
||||
ini = get_SalesOrderQuery(customer_name)
|
||||
if ini:
|
||||
print("after ini")
|
||||
qbxml = ini.create_QBXML()
|
||||
# print(qbxml)
|
||||
response_string = ini.connect_to_quickbooks(qbxml)
|
||||
print(response_string)
|
||||
open_sales_orders = ini.get_open_so()
|
||||
print(f'open sales orders:{open_sales_orders}')
|
||||
ini=None
|
||||
if open_sales_orders:
|
||||
context['objects'] = open_sales_orders
|
||||
|
||||
|
||||
context['customer_fullname'] = customer_name
|
||||
|
||||
return render( request, "Invoice/so_list_form.html", context)
|
||||
# return HttpResponse('')
|
||||
|
||||
|
||||
def prepare_data(request):
|
||||
starttime = timeit.default_timer()
|
||||
import sys
|
||||
sys.path.append('.')
|
||||
sys.path.append('..')
|
||||
|
||||
context = {}
|
||||
FullName = ""
|
||||
if request.method=='POST':
|
||||
print(request.POST)
|
||||
subject = request.POST.get("subject", None)
|
||||
print(subject, type(subject))
|
||||
if subject and isinstance(subject, str):
|
||||
ret=False
|
||||
# import sys
|
||||
# sys.path.append('.')
|
||||
# sys.path.append('..')
|
||||
if subject.upper() == "ITEM INVENTORY":
|
||||
# try:
|
||||
print("try iteminventory import")
|
||||
from ItemInventoryQuery import ItemInventoryQuery
|
||||
|
||||
ini= ItemInventoryQuery( OwnerID ="0")
|
||||
itu = ini.connect_to_quickbooks(ini.create_QBXML())
|
||||
ret, msg = ini.status_ok(itu)
|
||||
if ret:
|
||||
print("YEAH")
|
||||
df = pd.DataFrame.from_dict(ini.get_data(itu))
|
||||
print(df)
|
||||
df.to_excel('ItemInventory\ItemInventory_FromQB.xlsx', index=False)
|
||||
modtime = datetime.fromtimestamp(os.path.getmtime('ItemInventory\ItemInventory_FromQB.xlsx'))
|
||||
print(f"modified Time:{modtime}")
|
||||
# print(ini.status_ok(itu))
|
||||
else:
|
||||
messages.warning(request, f"Saving {subject} NOT success: {msg}")
|
||||
|
||||
elif subject.upper() == "CUSTOMER LIST":
|
||||
# try:
|
||||
print("try customerlist import")
|
||||
from SO_to_Inv.CustomerQuery import CustomerQuery
|
||||
|
||||
ini=CustomerQuery()
|
||||
itu = ini.create_customerquery_QBXML()
|
||||
# print(f'itu:{itu}')
|
||||
print(f'get customer pricelevel list:{ini.get_customer_pricelevel_list(itu)}')
|
||||
ret=True
|
||||
elif subject.upper() == "PRICE LEVEL LIST":
|
||||
# try:
|
||||
print("try pricelevelquery import")
|
||||
from SO_to_Inv.PriceLevelQuery import PriceLevelQuery
|
||||
|
||||
FullName = ['t 202202', 'M 202202', 'b 202202', 'sp 202202']
|
||||
FullName = request.POST.getlist("selected_items", FullName)
|
||||
# print(f'fullname:{FullName}')
|
||||
ini = PriceLevelQuery(FullName = FullName, )
|
||||
itu = ini.connect_to_quickbooks(ini.create_QBXML())
|
||||
ret, msg = ini.get_pricelevel()
|
||||
ini= None
|
||||
itu = None
|
||||
if ret:
|
||||
print(f'Success Save Price Level : {FullName}')
|
||||
|
||||
else:
|
||||
messages.warning(request, f"Saving Not Success. status: {msg}")
|
||||
print(f"Saving Not Success. status: {msg}")
|
||||
if ret:
|
||||
# messages.info(request, "<p> You are <em>pretty</em><br> smart</p>")
|
||||
messages.info(request, f"{subject} has been updated Successfully in {round(timeit.default_timer() - starttime, 4)} seconds. {FullName}")
|
||||
|
||||
else:
|
||||
messages.error(request, "not valid choice. Please choose again")
|
||||
# else:
|
||||
from SO_to_Inv.PriceLevelQuery import PriceLevelQuery
|
||||
ini = PriceLevelQuery(IncludeRetElement = ['Name'])
|
||||
|
||||
price_level_list = ini.name_list()
|
||||
# print(price_level_list)
|
||||
context['objects']=price_level_list
|
||||
|
||||
print("The time difference is :", timeit.default_timer() - starttime)
|
||||
return render(request, "Invoice/prepare_data.html", context=context)
|
||||
|
||||
|
||||
def index(request):
|
||||
print("index Inv")
|
||||
context = {}
|
||||
|
||||
@ -2,6 +2,9 @@
|
||||
"""Django's command-line utility for administrative tasks."""
|
||||
import os
|
||||
import sys
|
||||
# from icecream import install
|
||||
# install()
|
||||
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
@ -1,15 +1,16 @@
|
||||
<!DOCTYPE html>
|
||||
{% load static %}
|
||||
{% load tz %}
|
||||
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
{% comment %} <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-KK94CHFLLe+nY2dmCWGMq91rCGa5gtU4mk92HdvYe+M/SXH301p5ILy+dN9+nJOZ" crossorigin="anonymous">
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ENjdO4Dr2bkBIFxQpeoTz1HIcje39Wm4jDKdf19U8gI4ddQ3GYNS7NTKfAdVQSZe" crossorigin="anonymous"></script> {% endcomment %}
|
||||
<link href= {% static 'bootstrap.min.css' %} rel="stylesheet" crossorigin="anonymous">
|
||||
<script src= {% static 'bootstrap.bundle.min.js' %} ></script>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-KK94CHFLLe+nY2dmCWGMq91rCGa5gtU4mk92HdvYe+M/SXH301p5ILy+dN9+nJOZ" crossorigin="anonymous">
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ENjdO4Dr2bkBIFxQpeoTz1HIcje39Wm4jDKdf19U8gI4ddQ3GYNS7NTKfAdVQSZe" crossorigin="anonymous"></script>
|
||||
<!-- <link href= {% static 'bootstrap.min.css' %} rel="stylesheet" crossorigin="anonymous">
|
||||
<script src= {% static 'bootstrap.bundle.min.js' %} ></script> -->
|
||||
<script src="https://unpkg.com/htmx.org@1.9.6"></script>
|
||||
<style type="text/css">
|
||||
|
||||
@ -47,9 +48,9 @@
|
||||
{% block head %}{% endblock %}
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar navbar-expand-lg bg-light">
|
||||
<nav class="navbar navbar-expand-lg border-bottom bg-body-tertiary" data-bs-theme='light' >
|
||||
<div class="container-fluid">
|
||||
<a class="navbar-brand" href="#">DBW</a>
|
||||
<a class="navbar-brand" href="{% url 'Invoice:show_customer' %}">DBW</a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarScroll" aria-controls="navbarScroll" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
@ -71,20 +72,44 @@
|
||||
<li><a class="dropdown-item" href="{% url 'Invoice:index' %}">Invoice List</a></li>
|
||||
|
||||
<li><hr class="dropdown-divider"></li>
|
||||
<li><a class="dropdown-item" href="#">Something else here</a></li>
|
||||
<li><a class="dropdown-item" href="{% url 'Invoice:prepare_data' %}">Prepare Data</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link disabled">Link</a>
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
SO to Inv
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a class="dropdown-item" href="{% url 'Invoice:show_customer' %}">SO to Inv</a></li>
|
||||
<li><a class="dropdown-item" href="{% url 'Invoice:prepare_data' %}">Prepare Data</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<!-- <li class="nav-item">
|
||||
<a class="nav-link disabled">Link</a>
|
||||
</li> -->
|
||||
</ul>
|
||||
<div>{% block search_nav %}{% endblock search_nav %}
|
||||
<div>{% block search_nav %}<form class="d-flex" role="search">
|
||||
<input class="form-control me-2" type="search" placeholder="Search" aria-label="Search">
|
||||
<button class="btn btn-outline-success" type="submit">Search</button>
|
||||
</form>
|
||||
{% endblock search_nav %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
{% block body %}{% endblock body %}
|
||||
|
||||
{% if messages %}
|
||||
{% for message in messages %}
|
||||
<div class="alert alert-{{ message.tags }} alert-dismissible fade show" role="alert">
|
||||
{{message | safe}}
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
<div>
|
||||
{% block body %}{% endblock body %}
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Modal -->
|
||||
|
||||
12
main.py
12
main.py
@ -1,7 +1,11 @@
|
||||
from fastapi.responses import HTMLResponse
|
||||
from fastapi.templating import Jinja2Templates
|
||||
from fastapi import FastAPI, Request, UploadFile, Body
|
||||
|
||||
# from icecream import install
|
||||
# import icecream
|
||||
# install()
|
||||
# from icecream import ic
|
||||
# ic.configureOutput(includeContext=True, )
|
||||
import json
|
||||
from iteminventorydasa import QBStock
|
||||
import datetime
|
||||
@ -13,7 +17,7 @@ import pdfexcel4DNwithxlrd
|
||||
from ItemInventoryQuery import ItemInventoryQuery
|
||||
from SO_to_Inv import readSO
|
||||
import os
|
||||
from icecream import ic
|
||||
|
||||
import pprint
|
||||
|
||||
# app = FastAPI()
|
||||
@ -56,6 +60,7 @@ async def renew_iteminventory():
|
||||
@app.post("/upload-file/")
|
||||
async def create_upload_file(uploaded_file: UploadFile):
|
||||
base_file_location = f"DN_Excel_files"
|
||||
status = "ERROR"
|
||||
if uploaded_file.filename.endswith(".xls") and uploaded_file.filename.startswith("TCO-DN"):
|
||||
folder_yearmonth = uploaded_file.filename.split('-')
|
||||
if len(folder_yearmonth)>3:
|
||||
@ -123,7 +128,7 @@ async def create_upload_file(uploaded_file: UploadFile):
|
||||
|
||||
|
||||
return [{"info": f"file '{uploaded_file.filename}' saved at '{file_location}'", "status": status, "msg": msg}]
|
||||
return {"info": f"file '{uploaded_file.filename}' is not Excel(.xls) file or it is not Delivery Note(TCO-DN)file. please upload the correct file", "status": status}
|
||||
return {"info": f"file '{uploaded_file.filename}' is not Excel(.xls) file or Filename is not start with 'TCO-DN'. Please upload the correct file", "status": status}
|
||||
|
||||
@app.post('/getopenso')
|
||||
async def getopenso(request: Request, CustomerName: str = Body(...)):
|
||||
@ -134,6 +139,7 @@ async def getopenso(request: Request, CustomerName: str = Body(...)):
|
||||
FullName = CustomerName['CustomerName']
|
||||
print(FullName)
|
||||
ini=readSO.SalesOrderQuery(FullName= FullName, IncludeRetElement = ['TxnID', 'TimeCreated', 'TimeModified','TxnNumber', 'CustomerRef', 'TxnDate', 'RefNumber', 'IsManuallyClosed', 'IsFullyInvoiced','TotalAmount'])
|
||||
print("selesai salesorder")
|
||||
open_sales_orders = ini.get_open_so()
|
||||
print(f'return opensalesorder:{open_sales_orders}')
|
||||
return open_sales_orders
|
||||
|
||||
@ -84,9 +84,25 @@ def read_DN_excel(filename):
|
||||
|
||||
# DNRefNum = rawdata[1][3].strip().split("-")[1][-1] + "".join(rawdata[1][3].strip().split("-")[-2:])
|
||||
# TxnDate = rawdata[2][3].strip().split(" ")[-1]
|
||||
DNRefNum = wb.sheets()[0].cell(1, 3).value.strip().split("-")[1][-1] + "".join(wb.sheets()[0].cell(1, 3).value.strip().split("-")[-2:])
|
||||
_y=1
|
||||
_x=0
|
||||
for col in range(1,wb.sheets()[0].ncols):
|
||||
|
||||
col_value = wb.sheets()[0].col_values(col)
|
||||
print("col=",col, col_value[1])
|
||||
if "TCO-DN" in col_value[1]:
|
||||
_x=col
|
||||
if _x == 0 :
|
||||
return False, "Cannot find TCO-DN cell"
|
||||
|
||||
|
||||
# if "TCO-DN" in wb.sheets()[0].cell(_y, _x).value.strip():
|
||||
|
||||
|
||||
print(wb.sheets()[0].cell(_y, _x).value.strip())
|
||||
DNRefNum = wb.sheets()[0].cell(_y, _x).value.strip().split("-")[1][-1] + "".join(wb.sheets()[0].cell(_y, _x).value.strip().split("-")[-2:])
|
||||
# print(DNRefNum)
|
||||
TxnDate = wb.sheets()[0].cell(2, 3).value.strip().split(" ")[-1]
|
||||
TxnDate = wb.sheets()[0].cell(_y+1, _x).value.strip().split(" ")[-1]
|
||||
Memo = DNRefNum
|
||||
print(f'pdfexcel4DNwithxlrd.py->DNRefNum:{DNRefNum}, TxnDate:{TxnDate}')
|
||||
DeliveryNotedict={'DNRefNum':DNRefNum, 'TxnDate':TxnDate, 'Memo': Memo}
|
||||
@ -108,7 +124,19 @@ def read_DN_excel(filename):
|
||||
if not None and row[0]=="Item No" :
|
||||
if firstpage:
|
||||
# print('firstpage')
|
||||
data.append(row)
|
||||
if len(row)==5:
|
||||
data.append(row)
|
||||
elif len(row)>5:
|
||||
temp_ =[]
|
||||
for _ in row:
|
||||
if _ != None:
|
||||
temp_.append(_)
|
||||
if len(row)==5:
|
||||
data.append(temp_)
|
||||
else:
|
||||
print("HEADER ERROR!!!")
|
||||
data.append(['Item No', 'Description', 'QuantityUOM', 'No.SO', 'LPN No.'])
|
||||
|
||||
boldataline=True
|
||||
firstpage=False
|
||||
# continue
|
||||
@ -130,7 +158,8 @@ def read_DN_excel(filename):
|
||||
movetonextpage=True
|
||||
continue
|
||||
elif row[3] is not None:
|
||||
if row[3].startswith('Hormat'):
|
||||
# if row[3].startswith('Hormat'):
|
||||
if 'Hormat Kami,' in row:
|
||||
# print('hormatkami found')
|
||||
boldataline=False
|
||||
movetonextpage=True
|
||||
@ -140,7 +169,8 @@ def read_DN_excel(filename):
|
||||
else:
|
||||
data.append(row)
|
||||
elif row[3] is not None:
|
||||
if row[3].startswith('Hormat'):
|
||||
# if row[3].startswith('Hormat'):
|
||||
if 'Hormat Kami,' in row:
|
||||
boldataline=False
|
||||
movetonextpage=True
|
||||
# continue
|
||||
@ -149,28 +179,67 @@ def read_DN_excel(filename):
|
||||
else:
|
||||
data.append(row)
|
||||
|
||||
# print (f'data: {data}')
|
||||
print (f'data: {data}')
|
||||
|
||||
for idx, x in enumerate(data):
|
||||
if x[0].upper() == "ET-06/A1.": ### Change the source from "ET-06/A1." to "ET-06/A1.BOX_100" and replace the UOM from "BOX_100" to "BOX"
|
||||
x[0] = "ET-06/A1.BOX_100"
|
||||
x[2] = x[2].replace("BOX_100", "BOX")
|
||||
for colidx, col in enumerate(x): ### change the empty cell into None
|
||||
if col == "":
|
||||
data[idx][colidx]=None
|
||||
|
||||
# for idx, x in enumerate(data):
|
||||
# print(idx, x)
|
||||
|
||||
coly=0
|
||||
lenList = 0
|
||||
xylist=[]
|
||||
for idx, x in enumerate(data):
|
||||
print(idx, x)
|
||||
xylist=[]
|
||||
if len(x)>5 and (idx % 2)==1 :
|
||||
print(idx,x)
|
||||
lenList = len(x)
|
||||
for idy, y in enumerate(x):
|
||||
if y == None:
|
||||
coly=idy
|
||||
|
||||
else:
|
||||
xylist.append(y)
|
||||
if len(xylist)==5:
|
||||
data[idx]=xylist
|
||||
elif len(x)>5 and (idx % 2)==0 and coly==0:
|
||||
pass
|
||||
print("Different page, seconde line have different column width (6)")
|
||||
boloddcolumn=True
|
||||
for _ in x[:len(x)-2]:
|
||||
print(_)
|
||||
if _ != None:
|
||||
boloddcolumn=False
|
||||
print(boloddcolumn)
|
||||
if boloddcolumn:
|
||||
del x[0]
|
||||
print(x)
|
||||
|
||||
elif coly != 0 and lenList == len(x):
|
||||
for idy, y in enumerate(x):
|
||||
if idy!=coly:
|
||||
xylist.append(y)
|
||||
data[idx]=xylist
|
||||
coly=0
|
||||
lenList = 0
|
||||
print(idx, data[idx])
|
||||
|
||||
print(f'len data={len(data)}')
|
||||
|
||||
for idx, x in enumerate(data):
|
||||
# print(idx, x)
|
||||
if x[0] !=None and x[0].upper() == "ET-06/A1.": ### Change the source from "ET-06/A1." to "ET-06/A1.BOX_100" and replace the UOM from "BOX_100" to "BOX"
|
||||
print(idx, x)
|
||||
x[0] = "ET-06/A1.BOX_100"
|
||||
x[2] = x[2].replace("BOX_100", "BOX")
|
||||
print(idx, x)
|
||||
|
||||
newdata=[]
|
||||
|
||||
templist=[]
|
||||
for idx, dt in enumerate(data):
|
||||
if dt[0] != 'Item No':
|
||||
# print(idx,'not item')
|
||||
# print(idx,'not item', dt)
|
||||
if dt[0] is None:
|
||||
if dt[1]:
|
||||
templist[1]+=" " + dt[1]
|
||||
@ -191,33 +260,35 @@ def read_DN_excel(filename):
|
||||
templist=dt
|
||||
# print(templist)
|
||||
|
||||
# for idx, x in enumerate(newdata):
|
||||
# print(idx, x)
|
||||
# print(f'len newdata={len(newdata)}')
|
||||
for idx, x in enumerate(newdata):
|
||||
pass
|
||||
print(idx, x)
|
||||
print(f'len newdata={len(newdata)}')
|
||||
|
||||
|
||||
df=pd.DataFrame(newdata, columns=['Item No', 'Description', 'Quantity', 'No.SO/Ext.Doc.No.', 'LPN No.', 'UOM', 'Ext.Doc.No.'])#, columns=data[0]+"UOM")
|
||||
df=pd.DataFrame(newdata, columns=['Item No', 'Description', 'Quantity', 'No.SO', 'LPN No.', 'UOM', 'Ext.Doc.No'])#, columns=data[0]+"UOM")
|
||||
# print(df)
|
||||
# df=df.groupby(['No.SO/Ext.Doc.No.','Item No', 'UOM'])['Quantity'].sum().reset_index().sort_values(by=['Item No', 'No.SO/Ext.Doc.No.'])#.sort_values(by=['No.SO/Ext.Doc.No.'])
|
||||
df=df.groupby(['Ext.Doc.No.', 'No.SO/Ext.Doc.No.','Item No', 'UOM'])['Quantity'].sum().reset_index().sort_values(by=['Ext.Doc.No.','No.SO/Ext.Doc.No.', 'Item No'])
|
||||
# df=df.groupby(['No.SO','Item No', 'UOM'])['Quantity'].sum().reset_index().sort_values(by=['Item No', 'No.SO'])#.sort_values(by=['No.SO'])
|
||||
df=df.groupby(['Ext.Doc.No', 'No.SO','Item No', 'UOM'])['Quantity'].sum().reset_index().sort_values(by=['Ext.Doc.No','No.SO', 'Item No'])
|
||||
df['NameFromTaco']=df['Item No']
|
||||
# print(df)
|
||||
# df['FullName'] = inteminvdf.loc[df['Item No'],'FullName']
|
||||
df=df.merge(inteminvdf, how="left")
|
||||
|
||||
print(df['FullName'].isnull())
|
||||
print(df['FullName'])
|
||||
# print(df)
|
||||
if df['FullName'].isnull().sum() > 0:
|
||||
|
||||
print("Cannot Find Item FullName")
|
||||
listitemNoFullName = df.loc[df['FullName'].isnull()].values.tolist()
|
||||
df=df.reindex(columns=['Ext.Doc.No.', 'No.SO/Ext.Doc.No.', 'Item No', 'FullName', 'Quantity', 'UOM'])
|
||||
print(df)
|
||||
print(listitemNoFullName)
|
||||
df=df.reindex(columns=['Ext.Doc.No', 'No.SO', 'Item No', 'FullName', 'Quantity', 'UOM'])
|
||||
# print(df)
|
||||
# print(listitemNoFullName)
|
||||
# print(listitemNoFullName)
|
||||
return False, listitemNoFullName
|
||||
else:
|
||||
df=df.groupby(['Ext.Doc.No.', 'No.SO/Ext.Doc.No.','Item No', 'UOM', 'FullName'])['Quantity'].sum().reset_index().sort_values(by=['Ext.Doc.No.','No.SO/Ext.Doc.No.', 'Item No'])
|
||||
df=df.reindex(columns=['Ext.Doc.No.', 'No.SO/Ext.Doc.No.', 'Item No', 'FullName', 'Quantity', 'UOM'])
|
||||
df=df.groupby(['Ext.Doc.No', 'No.SO','Item No', 'UOM', 'FullName'])['Quantity'].sum().reset_index().sort_values(by=['Ext.Doc.No','No.SO', 'Item No'])
|
||||
df=df.reindex(columns=['Ext.Doc.No', 'No.SO', 'Item No', 'FullName', 'Quantity', 'UOM'])
|
||||
# print(df)
|
||||
lst = df.to_dict('records')
|
||||
# print(lst)
|
||||
@ -232,5 +303,8 @@ if __name__=="__main__":
|
||||
# read_DN_excel(filename)
|
||||
# filename = "DN_Excel_files\TCO-DNPR-2305-00305.xls"
|
||||
# read_DN_excel(filename)
|
||||
filename = "DN_Excel_files\TCO-DNPG-2307-01407.xls"
|
||||
read_DN_excel(filename)
|
||||
# filename = "DN_Excel_files\TCO-DNPG-2307-01407.xls"
|
||||
filename = "DN_Excel_files\TCO-DNPG-2310-00337.xls"
|
||||
status, retdict = read_DN_excel(filename)
|
||||
print(status)
|
||||
print(retdict)
|
||||
File diff suppressed because one or more lines are too long
@ -58,7 +58,7 @@ class SalesOrderQuery:
|
||||
qbxml_query = """<?xml version="1.0" encoding="utf-8"?>\n"""
|
||||
qbxml_query = qbxml_query + """<?qbxml version="13.0"?>"""
|
||||
qbxml_query = qbxml_query + "\n" + mydata
|
||||
|
||||
print(qbxml_query)
|
||||
return qbxml_query
|
||||
|
||||
def connect_to_quickbooks(self, qbxml_query):
|
||||
@ -83,7 +83,7 @@ class SalesOrderQuery:
|
||||
|
||||
def __str__(self, *args) -> str:
|
||||
# return str(self._get_datarow(self.connect_to_quickbooks(self.create_QBXML())))
|
||||
# print("__str__")
|
||||
print("__str__")
|
||||
return str(self.get_datarow())
|
||||
# return "hello"
|
||||
|
||||
|
||||
@ -6,13 +6,18 @@ import datetime
|
||||
import pandas as pd
|
||||
import xml.dom.minidom
|
||||
from lxml import etree
|
||||
|
||||
from tools import pprintXml
|
||||
import timeit
|
||||
class TransactionQuery:
|
||||
def __init__(self, **kwargs) -> None:
|
||||
# print(f'kwargs:{kwargs}')
|
||||
# print(args)
|
||||
# self.TransactionTypeFilter = kwargs['TransactionTypeFilter'] if 'TransactionTypeFilter' in kwargs else 'SalesOrder'
|
||||
self.TxnTypeFilter = kwargs['TxnTypeFilter'] if 'TxnTypeFilter' in kwargs else 'SalesOrder'
|
||||
self.EntityTypeFilter = kwargs['EntityTypeFilter'] if 'EntityTypeFilter' in kwargs else None
|
||||
self.RefNumber = kwargs['RefNumber'] if 'RefNumber' in kwargs else None
|
||||
|
||||
self.FullName = kwargs['FullName'] if 'FullName' in kwargs else None
|
||||
self.TxnTypeFilter = kwargs['TxnTypeFilter'] if 'TxnTypeFilter' in kwargs else None
|
||||
# self.TransactionPaidStatusFilter = kwargs['TransactionPaidStatusFilter'] if 'TransactionPaidStatusFilter' in kwargs else 'Open'
|
||||
self.TransactionPaidStatusFilter = kwargs['TransactionPaidStatusFilter'] if 'TransactionPaidStatusFilter' in kwargs else 'Open'
|
||||
self.TransactionDetailLevelFilter = kwargs['TransactionDetailLevelFilter'] if 'TransactionDetailLevelFilter' in kwargs else None
|
||||
@ -26,7 +31,7 @@ class TransactionQuery:
|
||||
self.FromTxnDate = self.validate_date(kwargs['FromTxnDate']) if 'FromTxnDate' in kwargs else None
|
||||
self.ToTxnDate = self.validate_date(kwargs['ToTxnDate']) if 'ToTxnDate' 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.DateMacro, self.ReportPeriod, self.FromTxnDate, self.ToTxnDate)
|
||||
|
||||
def create_sub_element(self, ET, parentNode, thisNode, text="\n", whiteSpace = 0, attrib =None):
|
||||
@ -53,6 +58,13 @@ class TransactionQuery:
|
||||
QBXMLMsgsRq.text = "\n "
|
||||
# TransactionQueryRq = self.create_sub_element(ET, QBXMLMsgsRq, "TransactionQueryRq","\n", attrib={"metaData":"MetaDataAndResponseData", "iteratorID":"UUIDTYPE" })
|
||||
TransactionQueryRq = self.create_sub_element(ET, QBXMLMsgsRq, "TransactionQueryRq","\n")
|
||||
if self.RefNumber:
|
||||
if isinstance(self.RefNumber, list):
|
||||
for _ in self.RefNumber:
|
||||
RefNumber = self.create_sub_element(ET, TransactionQueryRq, "RefNumber", _)
|
||||
else:
|
||||
RefNumber = self.create_sub_element(ET, TransactionQueryRq, "RefNumber", self.RefNumber)
|
||||
|
||||
if self.DateMacro:
|
||||
TransactionDateRangeFilter = self.create_sub_element(ET, TransactionQueryRq, "TransactionDateRangeFilter","\n")
|
||||
# ReportPeriod = self.create_sub_element(ET, TransactionQueryRq, "TransactionDateRangeFilter", "\n ",)
|
||||
@ -65,7 +77,12 @@ class TransactionQuery:
|
||||
if type(self.ToTxnDate) is datetime.date:
|
||||
ToTxnDate = self.create_sub_element(ET, TransactionDateRangeFilter, "ToTxnDate", self.ToTxnDate.strftime('%Y-%m-%d'))
|
||||
|
||||
|
||||
if self.EntityTypeFilter or self.FullName:
|
||||
TransactionEntityFilter = self.create_sub_element(ET, TransactionQueryRq, "TransactionEntityFilter","\n")
|
||||
if self.EntityTypeFilter:
|
||||
EntityTypeFilter = self.create_sub_element(ET, TransactionEntityFilter, "EntityTypeFilter", self.EntityTypeFilter, )
|
||||
if self.FullName:
|
||||
FullName = self.create_sub_element(ET, TransactionEntityFilter, "FullName", self.FullName,)
|
||||
# TransactionQueryRq = self.create_sub_element(ET, QBXMLMsgsRq, "TransactionQueryRq","\n " )
|
||||
if self.TxnTypeFilter:
|
||||
TransactionTypeFilter = self.create_sub_element(ET, TransactionQueryRq, 'TransactionTypeFilter', "\n")
|
||||
@ -78,13 +95,13 @@ class TransactionQuery:
|
||||
IncludeRetElement = self.create_sub_element(ET, TransactionQueryRq, 'IncludeRetElement', ire)
|
||||
mydata = ET.tostring(root, encoding="unicode")
|
||||
# mydata = ET.tostring(root, encoding = "unicode")
|
||||
print(mydata)
|
||||
# print(mydata)
|
||||
qbxml_query = """<?xml version="1.0" encoding="utf-8"?>\n"""
|
||||
qbxml_query = qbxml_query + """<?qbxml version="13.0"?>"""
|
||||
qbxml_query = qbxml_query + "\n" + mydata
|
||||
# def to_string():
|
||||
# qbxml_query=str(qbxml_query)
|
||||
return qbxml_query
|
||||
return pprintXml(qbxml_query)
|
||||
|
||||
def connect_to_quickbooks(self, qbxml_query):
|
||||
# Connect to Quickbooks
|
||||
@ -95,7 +112,8 @@ class TransactionQuery:
|
||||
# print(enumfodnc.qbFileOpenDoNotCare)
|
||||
sessionManager = win32com.client.Dispatch("QBXMLRP2.RequestProcessor")
|
||||
sessionManager.OpenConnection('', 'DASA2')
|
||||
ticket = sessionManager.BeginSession("z:\\DBW Bogor.qbw", 2)
|
||||
# ticket = sessionManager.BeginSession("z:\\DBW Bogor.qbw", 2)
|
||||
ticket = sessionManager.BeginSession("", 2)
|
||||
|
||||
# Send query and receive response
|
||||
response_string = sessionManager.ProcessRequest(ticket, qbxml_query)
|
||||
@ -103,8 +121,9 @@ class TransactionQuery:
|
||||
# Disconnect from Quickbooks
|
||||
sessionManager.EndSession(ticket) # Close the company file
|
||||
sessionManager.CloseConnection() # Close the connection
|
||||
# print (response_string)
|
||||
return response_string
|
||||
# print(f"response: {response_string}")
|
||||
# print (pprintXml(response_string))
|
||||
return pprintXml(response_string)
|
||||
|
||||
def __str__(self, *args) -> str:
|
||||
# return str(self._get_datarow(self.connect_to_quickbooks(self.create_QBXML())))
|
||||
@ -123,7 +142,12 @@ class TransactionQuery:
|
||||
return self._get_total(self.connect_to_quickbooks(self.create_QBXML()))
|
||||
|
||||
def status_ok(self, QBXML):
|
||||
GSRQRs=QBXML.find('.//TransactionQueryRs')
|
||||
print(QBXML)
|
||||
tree = ET.fromstring(QBXML)
|
||||
|
||||
GSRQRs=tree.find('.//TransactionQueryRs')
|
||||
print(f"GSRQRs:{GSRQRs}")
|
||||
|
||||
status_code = GSRQRs.attrib #.get('statusCode')
|
||||
# print(GSRQRs.attrib)
|
||||
# print(GSRQRs.attrib['statusCode'])
|
||||
@ -252,14 +276,26 @@ class TransactionQuery:
|
||||
# raise ValueError("Incorrect data format, should be YYYY-MM-DD")
|
||||
print('### Transaction ###')
|
||||
if __name__ == '__main__':
|
||||
starttime = timeit.default_timer()
|
||||
|
||||
# ini=TransactionQuery(DateMacro='ThisMonth')
|
||||
# ini=TransactionQuery()
|
||||
# temp = xml.dom.minidom.parseString(ini.create_QBXML())
|
||||
# print(temp.toprettyxml())
|
||||
print("hello")
|
||||
|
||||
# ini=TransactionQuery(FromTxnDate='2023-01-11', ToTxnDate='2023-01-12', TransactionPaidStatusFilter='Closed', TransactionDetailLevelFilter='All')
|
||||
ini=TransactionQuery(FromTxnDate='2023-01-11', ToTxnDate='2023-01-12', TransactionPaidStatusFilter='Closed', TransactionDetailLevelFilter=None,
|
||||
IncludeRetElement=['EntityRef', 'TxnDate', 'Amount', 'Memo'])
|
||||
# ini=TransactionQuery(FromTxnDate='2023-01-11', ToTxnDate='2023-01-12', TransactionPaidStatusFilter='Closed', TransactionDetailLevelFilter=None,
|
||||
# IncludeRetElement=['EntityRef', 'TxnDate', 'Amount', 'Memo'])
|
||||
ini=TransactionQuery( TransactionPaidStatusFilter='Open', TransactionDetailLevelFilter=None,
|
||||
# FullName='Abadi Serpong',
|
||||
# EntityTypeFilter='Customer',
|
||||
# RefNumber = ['24010005', '24010001', '24010002'],
|
||||
RefNumber = ['24010002'],
|
||||
TxnTypeFilter = None,
|
||||
# IncludeRetElement=['EntityRef', 'TxnDate', 'Amount', 'Memo', 'RefNumber', 'TxnID', 'TimeCreated', 'TimeModified'])
|
||||
|
||||
IncludeRetElement=[ 'TxnID', 'EntityRef', 'TxnDate', 'RefNumber', 'Memo'])
|
||||
# ini=TransactionQuery(TransactionTypeFilter='SalesByItemSummary')
|
||||
# ini=TransactionQuery(TransactionTypeFilter='SalesByRepSummary')
|
||||
# ini=TransactionQuery(TransactionTypeFilter='PurchaseByVendorSummary')
|
||||
@ -268,7 +304,8 @@ if __name__ == '__main__':
|
||||
# ini=TransactionQuery(TransactionTypeFilter='InventoryStockStatusByItem')
|
||||
print(type(ini.create_QBXML()))
|
||||
print(ini.create_QBXML())
|
||||
print(f'print ini:{ini}')
|
||||
print(f"ini result connect:{ini.connect_to_quickbooks(ini.create_QBXML())}")
|
||||
# print(f'print ini:{ini}')
|
||||
# print(type(ini.get_datarow()))
|
||||
# print(ini.get_total())
|
||||
# print(f'ini.getdatarow:{ini.get_datarow()}')
|
||||
@ -283,4 +320,6 @@ if __name__ == '__main__':
|
||||
# print(df.loc[df['TotalSales']>0])
|
||||
# print(df.tail(10))
|
||||
# print(headers)
|
||||
# print(list(df.keys().values))
|
||||
# print(list(df.keys().values))
|
||||
|
||||
print("The time difference is :", timeit.default_timer() - starttime)
|
||||
1
records
Normal file
1
records
Normal file
@ -0,0 +1 @@
|
||||
{"itemfullname":{"0":"TACO:G_D:TH-017D","1":"TEDG:S122:EDG-009-1\/22","2":"TIERO:AF:TI-Q-9002-AF"},"txnlineid":{"0":"1786D7-1689047665","1":"178970-1689047665","2":"1796BD-1689144572"},"so_field":{"0":"1786D5-1689047665, 1786D7-1689047665","1":"1786D5-1689047665, 178970-1689047665","2":"1796BB-1689144572, 1796BD-1689144572"},"backordered":{"0":"11","1":"1.0","2":"8.0"},"rate":{"0":"179500.0","1":"380000.0","2":"1080000.0"}}
|
||||
13
tools.py
13
tools.py
@ -7,5 +7,18 @@ def get_alpha_numeric(text:str):
|
||||
result += x
|
||||
return result
|
||||
|
||||
|
||||
def pprintXml(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
|
||||
|
||||
if __name__ == "__main__":
|
||||
print(get_alpha_numeric('TH-201/88. aa, BH'))
|
||||
Loading…
Reference in New Issue
Block a user