This commit is contained in:
bcomsugi 2023-09-27 15:49:36 +07:00
commit 5854568f28
144 changed files with 12916 additions and 0 deletions

171
.gitignore vendored Normal file
View File

@ -0,0 +1,171 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
*.pot
*.pyc
__pycache__/
local_settings.py
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock
# pdm
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
#pdm.lock
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
# in version control.
# https://pdm.fming.dev/#use-with-ide
.pdm.toml
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/
# PyCharm
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/
DN_Excel_files/
ItemInventory/
QBbackup/
.xlsx
.pdf
QBbackup/
test_folder_source_DeliveryNote/

9
DASAServer.bat Normal file
View File

@ -0,0 +1,9 @@
cd "C:\Sources\dasaproject win7\"
echo already cd
cmd /k "cd /d C:\Sources\dasaproject win7\env\Scripts\ & activate & cd /d C:\Sources\dasaproject win7\ & uvicorn main:app --host 0.0.0.0 --port 9999
echo workon env
echo pause
echo get to env
echo cd "C:\Users\MSi\Documents\Python Project\DBW\Web scrapping"
echo uvicorn main:app --reload
echo start app

Binary file not shown.

5
FASTApiItemReceipt.bat Normal file
View File

@ -0,0 +1,5 @@
cd "C:\Sources\dasaproject win7\"
echo already cd
cmd /k "cd /d C:\Sources\dasaproject win7\env\Scripts\ & activate & cd /d C:\Sources\dasaproject win7\ & uvicorn main:app --host 0.0.0.0 --port 8888
echo uvicorn main:app --reload
echo start app

146
GeneralSummaryReport.xml Normal file
View File

@ -0,0 +1,146 @@
<?xml version="1.0" encoding="utf-8"?>
<?qbxml version="16.0"?>
<QBXML>
<QBXMLMsgsRq onError="stopOnError">
<GeneralSummaryReportQueryRq>
<!-- GeneralSummaryReportType may have one of the following values: BalanceSheetByClass, BalanceSheetPrevYearComp, BalanceSheetStandard, BalanceSheetSummary, CustomerBalanceSummary, ExpenseByVendorSummary, IncomeByCustomerSummary, InventoryStockStatusByItem, InventoryStockStatusByVendor, IncomeTaxSummary, InventoryValuationSummary, InventoryValuationSummaryBySite, LotNumberInStockBySite, PhysicalInventoryWorksheet, ProfitAndLossByClass, ProfitAndLossByJob, ProfitAndLossPrevYearComp, ProfitAndLossStandard, ProfitAndLossYTDComp, PurchaseByItemSummary, PurchaseByVendorSummary, SalesByCustomerSummary, SalesByItemSummary, SalesByRepSummary, SalesTaxLiability, SalesTaxRevenueSummary, SerialNumberInStockBySite, TrialBalance, VendorBalanceSummary -->
<GeneralSummaryReportType >ENUMTYPE</GeneralSummaryReportType> <!-- required -->
<DisplayReport >BOOLTYPE</DisplayReport> <!-- optional -->
<!-- BEGIN OR -->
<ReportPeriod> <!-- optional -->
<FromReportDate >DATETYPE</FromReportDate> <!-- optional -->
<ToReportDate >DATETYPE</ToReportDate> <!-- optional -->
</ReportPeriod>
<!-- OR -->
<!-- ReportDateMacro may have one of the following values: All, Today, ThisWeek, ThisWeekToDate, ThisMonth, ThisMonthToDate, ThisQuarter, ThisQuarterToDate, ThisYear, ThisYearToDate, Yesterday, LastWeek, LastWeekToDate, LastMonth, LastMonthToDate, LastQuarter, LastQuarterToDate, LastYear, LastYearToDate, NextWeek, NextFourWeeks, NextMonth, NextQuarter, NextYear -->
<ReportDateMacro >ENUMTYPE</ReportDateMacro> <!-- optional -->
<!-- END OR -->
<ReportAccountFilter> <!-- optional -->
<!-- BEGIN OR -->
<!-- AccountTypeFilter may have one of the following values: AccountsPayable, AccountsReceivable, AllowedFor1099, APAndSalesTax, APOrCreditCard, ARAndAP, Asset, BalanceSheet, Bank, BankAndARAndAPAndUF, BankAndUF, CostOfSales, CreditCard, CurrentAsset, CurrentAssetAndExpense, CurrentLiability, Equity, EquityAndIncomeAndExpense, ExpenseAndOtherExpense, FixedAsset, IncomeAndExpense, IncomeAndOtherIncome, Liability, LiabilityAndEquity, LongTermLiability, NonPosting, OrdinaryExpense, OrdinaryIncome, OrdinaryIncomeAndCOGS, OrdinaryIncomeAndExpense, OtherAsset, OtherCurrentAsset, OtherCurrentLiability, OtherExpense, OtherIncome, OtherIncomeOrExpense -->
<AccountTypeFilter >ENUMTYPE</AccountTypeFilter> <!-- optional -->
<!-- OR -->
<ListID >IDTYPE</ListID> <!-- optional, may repeat -->
<!-- OR -->
<FullName >STRTYPE</FullName> <!-- optional, may repeat -->
<!-- OR -->
<ListIDWithChildren >IDTYPE</ListIDWithChildren> <!-- optional -->
<!-- OR -->
<FullNameWithChildren >STRTYPE</FullNameWithChildren> <!-- optional -->
<!-- END OR -->
</ReportAccountFilter>
<ReportEntityFilter> <!-- optional -->
<!-- BEGIN OR -->
<!-- EntityTypeFilter may have one of the following values: Customer, Employee, OtherName, Vendor -->
<EntityTypeFilter >ENUMTYPE</EntityTypeFilter> <!-- optional -->
<!-- OR -->
<ListID >IDTYPE</ListID> <!-- optional, may repeat -->
<!-- OR -->
<FullName >STRTYPE</FullName> <!-- optional, may repeat -->
<!-- OR -->
<ListIDWithChildren >IDTYPE</ListIDWithChildren> <!-- optional -->
<!-- OR -->
<FullNameWithChildren >STRTYPE</FullNameWithChildren> <!-- optional -->
<!-- END OR -->
</ReportEntityFilter>
<ReportItemFilter> <!-- optional -->
<!-- BEGIN OR -->
<!-- ItemTypeFilter may have one of the following values: AllExceptFixedAsset, Assembly, Discount, FixedAsset, Inventory, InventoryAndAssembly, NonInventory, OtherCharge, Payment, Sales, SalesTax, Service -->
<ItemTypeFilter >ENUMTYPE</ItemTypeFilter> <!-- optional -->
<!-- OR -->
<ListID >IDTYPE</ListID> <!-- optional, may repeat -->
<!-- OR -->
<FullName >STRTYPE</FullName> <!-- optional, may repeat -->
<!-- OR -->
<ListIDWithChildren >IDTYPE</ListIDWithChildren> <!-- optional -->
<!-- OR -->
<FullNameWithChildren >STRTYPE</FullNameWithChildren> <!-- optional -->
<!-- END OR -->
</ReportItemFilter>
<ReportClassFilter> <!-- optional -->
<!-- BEGIN OR -->
<ListID >IDTYPE</ListID> <!-- optional, may repeat -->
<!-- OR -->
<FullName >STRTYPE</FullName> <!-- optional, may repeat -->
<!-- OR -->
<ListIDWithChildren >IDTYPE</ListIDWithChildren> <!-- optional -->
<!-- OR -->
<FullNameWithChildren >STRTYPE</FullNameWithChildren> <!-- optional -->
<!-- END OR -->
</ReportClassFilter>
<ReportTxnTypeFilter> <!-- optional -->
<!-- TxnTypeFilter may have one of the following values: All, ARRefundCreditCard, Bill, BillPaymentCheck, BillPaymentCreditCard, BuildAssembly, Charge, Check, CreditCardCharge, CreditCardCredit, CreditMemo, Deposit, Estimate, InventoryAdjustment, Invoice, ItemReceipt, JournalEntry, LiabilityAdjustment, Paycheck, PayrollLiabilityCheck, PurchaseOrder, ReceivePayment, SalesOrder, SalesReceipt, SalesTaxPaymentCheck, Transfer, VendorCredit, YTDAdjustment -->
<TxnTypeFilter >ENUMTYPE</TxnTypeFilter> <!-- required, may repeat -->
</ReportTxnTypeFilter>
<!-- BEGIN OR -->
<ReportModifiedDateRangeFilter> <!-- optional -->
<FromReportModifiedDate >DATETYPE</FromReportModifiedDate> <!-- optional -->
<ToReportModifiedDate >DATETYPE</ToReportModifiedDate> <!-- optional -->
</ReportModifiedDateRangeFilter>
<!-- OR -->
<!-- ReportModifiedDateRangeMacro may have one of the following values: All, Today, ThisWeek, ThisWeekToDate, ThisMonth, ThisMonthToDate, ThisQuarter, ThisQuarterToDate, ThisYear, ThisYearToDate, Yesterday, LastWeek, LastWeekToDate, LastMonth, LastMonthToDate, LastQuarter, LastQuarterToDate, LastYear, LastYearToDate, NextWeek, NextFourWeeks, NextMonth, NextQuarter, NextYear -->
<ReportModifiedDateRangeMacro >ENUMTYPE</ReportModifiedDateRangeMacro> <!-- optional -->
<!-- END OR -->
<!-- ReportDetailLevelFilter may have one of the following values: All [DEFAULT], AllExceptSummary, SummaryOnly -->
<ReportDetailLevelFilter >ENUMTYPE</ReportDetailLevelFilter> <!-- optional -->
<!-- ReportPostingStatusFilter may have one of the following values: Either, NonPosting, Posting -->
<ReportPostingStatusFilter >ENUMTYPE</ReportPostingStatusFilter> <!-- optional -->
<!-- SummarizeColumnsBy may have one of the following values: Account, BalanceSheet, Class, Customer, CustomerType, Day, Employee, FourWeek, HalfMonth, IncomeStatement, ItemDetail, ItemType, Month, Payee, PaymentMethod, PayrollItemDetail, PayrollYtdDetail, Quarter, SalesRep, SalesTaxCode, ShipMethod, Terms, TotalOnly, TwoWeek, Vendor, VendorType, Week, Year -->
<SummarizeColumnsBy >ENUMTYPE</SummarizeColumnsBy> <!-- optional -->
<IncludeSubcolumns >BOOLTYPE</IncludeSubcolumns> <!-- optional -->
<!-- ReportCalendar may have one of the following values: CalendarYear, FiscalYear, TaxYear -->
<ReportCalendar >ENUMTYPE</ReportCalendar> <!-- optional -->
<!-- ReturnRows may have one of the following values: ActiveOnly, NonZero, All -->
<ReturnRows >ENUMTYPE</ReturnRows> <!-- optional -->
<!-- ReturnColumns may have one of the following values: ActiveOnly, NonZero, All -->
<ReturnColumns >ENUMTYPE</ReturnColumns> <!-- optional -->
<!-- ReportBasis may have one of the following values: Accrual, Cash, None [DEFAULT] -->
<ReportBasis >ENUMTYPE</ReportBasis> <!-- optional -->
</GeneralSummaryReportQueryRq>
<GeneralSummaryReportQueryRs statusCode="INTTYPE" statusSeverity="STRTYPE" statusMessage="STRTYPE">
<ReportRet> <!-- optional -->
<ReportTitle >STRTYPE</ReportTitle> <!-- required -->
<ReportSubtitle >STRTYPE</ReportSubtitle> <!-- required -->
<!-- ReportBasis may have one of the following values: Accrual, Cash, None [DEFAULT] -->
<ReportBasis >ENUMTYPE</ReportBasis> <!-- optional -->
<NumRows >INTTYPE</NumRows> <!-- required -->
<NumColumns >INTTYPE</NumColumns> <!-- required -->
<NumColTitleRows >INTTYPE</NumColTitleRows> <!-- required -->
<ColDesc colID="INTTYPE" dataType="ENUMTYPE"> <!-- required, may repeat -->
<ColTitle titleRow="INTTYPE" value="STRTYPE"> <!-- required, may repeat -->
</ColTitle>
<!-- ColType may have one of the following values: Account, Addr1, Addr2, Addr3, Addr4, Addr5, Aging, Amount, AmountDifference, AverageCost, BilledDate, BillingStatus, Blank, CalculatedAmount, Class, ClearedStatus, CostPrice, CreateDate, Credit, CustomField, Date, Debit, DeliveryDate, DueDate, Duration, EarliestReceiptDate, EstimateActive, FOB, IncomeSubjectToTax, Invoiced, IsAdjustment, Item, ItemDesc, ItemVendor, Label, LastModifiedBy, LatestOrPriorState, Memo, ModifiedTime, Name, NameAccountNumber, NameAddress, NameCity, NameContact, NameEmail, NameFax, NamePhone, NameState, NameZip, OpenBalance, OriginalAmount, PaidAmount, PaidStatus, PaidThroughDate, PaymentMethod, PayrollItem, Percent, PercentChange, PercentOfTotalRetail, PercentOfTotalValue, PhysicalCount, PONumber, PrintStatus, ProgressAmount, ProgressPercent, Quantity, QuantityAvailable, QuantityOnHand, QuantityOnOrder, QuantityOnPendingBuild, QuantityOnSalesOrder, ReceivedQuantity, RefNumber, ReorderPoint, RetailValueOnHand, RunningBalance, SalesPerWeek, SalesRep, SalesTaxCode, ShipDate, ShipMethod, ShipToAddr1, ShipToAddr2, ShipToAddr3, ShipToAddr4, ShipToAddr5, SONumber, SourceName, SplitAccount, SSNOrTaxID, SuggestedReorder, TaxLine, TaxTableVersion, Terms, Total, TxnID, TxnNumber, TxnType, UnitPrice, UserEdit, ValueOnHand, WageBase, WageBaseTips -->
<ColType >ENUMTYPE</ColType> <!-- required -->
</ColDesc>
<ReportData> <!-- optional -->
<!-- BEGIN OR -->
<DataRow> <!-- optional -->
<RowData rowType="ENUMTYPE" value="STRTYPE"> <!-- optional -->
</RowData>
<ColData colID="INTTYPE" value="STRTYPE" dataType="ENUMTYPE"> <!-- optional, may repeat -->
</ColData>
</DataRow>
<!-- OR -->
<TextRow rowNumber="INTTYPE" value="STRTYPE"> <!-- optional -->
</TextRow>
<!-- OR -->
<SubtotalRow> <!-- optional -->
<RowData rowType="ENUMTYPE" value="STRTYPE"> <!-- optional -->
</RowData>
<ColData colID="INTTYPE" value="STRTYPE" dataType="ENUMTYPE"> <!-- optional, may repeat -->
</ColData>
</SubtotalRow>
<!-- OR -->
<TotalRow> <!-- optional -->
<RowData rowType="ENUMTYPE" value="STRTYPE"> <!-- optional -->
</RowData>
<ColData colID="INTTYPE" value="STRTYPE" dataType="ENUMTYPE"> <!-- optional, may repeat -->
</ColData>
</TotalRow>
<!-- END OR -->
</ReportData>
</ReportRet>
</GeneralSummaryReportQueryRs>
</QBXMLMsgsRq>
</QBXML>

BIN
ItemInventory140723.xlsx Normal file

Binary file not shown.

199
ItemInventoryQuery.py Normal file
View File

@ -0,0 +1,199 @@
import xml.etree.ElementTree as ET
import win32com.client
import pandas as pd
from datetime import date, datetime
import timeit
import os
class ItemInventoryQuery:
def __init__(self, *args, **kwargs) -> None:
# print(f'kwargs:{kwargs}')
# print(args)
self.filename=None
if len(args)>0:
self.filename = args[0]
# print(f'args:{args}')
# print(self.filename)
self.IncludeRetElement = kwargs['IncludeRetElement'] if 'IncludeRetElement' in kwargs else None
if not isinstance(self.IncludeRetElement, list):
self.IncludeRetElement = [self.IncludeRetElement]
self.OwnerID = kwargs['OwnerID'] if 'OwnerID' in kwargs else "0"
self.MaxReturned = kwargs['MaxReturned'] if 'MaxReturned' in kwargs else None
if isinstance(self.MaxReturned, int):
self.MaxReturned = str(self.MaxReturned)
self.NameRangeFilter = kwargs['NameRangeFilter'] if 'NameRangeFilter' in kwargs else []
self.DN = kwargs['DN'] if 'DN' in kwargs else {}
self.TxnDateRangeFilter = kwargs['TxnDateRangeFilter'] if 'TxnDateRangeFilter' in kwargs else None
self.DateMacro = None
if 'DateMacro' in kwargs:
if kwargs['DateMacro'] in ['All', 'Today', 'ThisWeek', 'ThisWeekToDate', 'ThisMonth', 'ThisMonthToDate', 'ThisQuarter', 'ThisQuarterToDate', 'ThisYear', 'ThisYearToDate', 'Yesterday', 'LastWeek', 'LastWeekToDate', 'LastMonth', 'LastMonthToDate', 'LastQuarter', 'LastQuarterToDate', 'LastYear', 'LastYearToDate', 'NextWeek', 'NextFourWeeks', 'NextMonth', 'NextQuarter', 'NextYear']:
self.DateMacro = kwargs['DateMacro']
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.TxnDateRangeFilter, self.FromTxnDate, self.ToTxnDate)
def create_sub_element(self, ET, parentNode, thisNode, text="\n", whiteSpace = 0, attrib =None):
if type(attrib) is not dict:
attrib = {}
ele = ET.SubElement(parentNode, thisNode)
for x in attrib:
ele.set(x, attrib[x])
ele.text = text
tail = "\n"
for x in range(whiteSpace):
tail = tail + " "
ele.tail = tail
return ele
def create_QBXML(self):
root = ET.Element("QBXML")
root.tail = "\n"
root.text = "\n "
QBXMLMsgsRq = ET.SubElement(root, "QBXMLMsgsRq")
# QBXMLMsgsRq.set("onError", "continueOnError")
QBXMLMsgsRq.set("onError", "stopOnError")
QBXMLMsgsRq.tail = "\n"
QBXMLMsgsRq.text = "\n "
ItemInventoryQueryRq = self.create_sub_element(ET, QBXMLMsgsRq, "ItemInventoryQueryRq","\n " )
if self.MaxReturned is not None:
MaxReturned = self.create_sub_element(ET, ItemInventoryQueryRq, "MaxReturned", self.MaxReturned, 4)
if len(self.NameRangeFilter)==2:
print(self.NameRangeFilter)
NameRangeFilter = self.create_sub_element(ET, ItemInventoryQueryRq, "NameRangeFilter", "\n ")
FromName = self.create_sub_element(ET, NameRangeFilter, "FromName", self.NameRangeFilter[0])
ToName = self.create_sub_element(ET, NameRangeFilter, "ToName", self.NameRangeFilter[1])
if self.IncludeRetElement:
for x in self.IncludeRetElement:
IncludeRetElement = self.create_sub_element(ET, ItemInventoryQueryRq, "IncludeRetElement", x, 4)
# print(self.OwnerID)
if self.OwnerID is not None:
OwnerID = self.create_sub_element(ET, ItemInventoryQueryRq, "OwnerID", self.OwnerID, 4)
mydata = ET.tostring(root, encoding = "unicode")
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(f'create_QBXML->qbxml_query: {qbxml_query}')
return qbxml_query
def connect_to_quickbooks(self, qbxml_query):
# Connect to Quickbooks
# sessionManager = win32com.client.Dispatch("QBXMLRP2.RequestProcessor")
# sessionManager.OpenConnection('', 'DASA')
# enumfodnc= win32com.client.Dispatch('QBXMLRP2.RequestProcessor')
# print(enumfodnc)
# print(enumfodnc.qbFileOpenDoNotCare)
sessionManager = win32com.client.Dispatch("QBXMLRP2.RequestProcessor")
sessionManager.OpenConnection('', 'DASA2')
# ticket = sessionManager.BeginSession("z:\\DBW Bogor.qbw", 2)
ticket = sessionManager.BeginSession("", 2)
# Send query and receive response
response_string = sessionManager.ProcessRequest(ticket, qbxml_query)
# Disconnect from Quickbooks
sessionManager.EndSession(ticket) # Close the company file
sessionManager.CloseConnection() # Close the connection
# print (f'response_string: {response_string}')
return response_string
def status_ok(self, QBXML): #for ItemInventoryQueryRs
tree = ET.fromstring(QBXML)
GSRQRs = tree.find(".//ItemInventoryQueryRs")
# print(f"GSRQRs:{GSRQRs}")
status_code = GSRQRs.attrib #.get('statusCode')
# print(GSRQRs.attrib)
# print(GSRQRs.attrib['statusCode'])
status=GSRQRs.attrib.get('statusMessage')
print(f'ItemInventoryQuery->status={status}')
# print('OK' in status)
if 'OK' in status:
return True, status_code
else:
return False, status_code
def get_data(self, response_string):
tree = ET.fromstring(response_string)
data = tree.findall(".//ItemInventoryRet")
NameFromTaco = []
FullName = []
# print(f'get_data->response_string:{response_string}')
# print(data)
for dt in data:
# print(dt.find('FullName').text, )
for dtextret in dt.findall('DataExtRet'):
if dtextret.findtext('DataExtName')=='NameFromTaco':
FullName.append(dt.find('FullName').text.strip())
NameFromTaco.append(dtextret.findtext('DataExtValue').strip())
# print(f"{dt.find('FullName').text}->{dtextret.find('DataExtName').text} : {dtextret.findtext('DataExtValue')}")
# print()
if len(FullName)>0 and len(NameFromTaco)>0 and len(FullName) == len(NameFromTaco):
# print(f'ItemInventoryQuery->exact len:{len(FullName)}')
return {'FullName': FullName, 'NameFromTaco': NameFromTaco}
else:
print(f'ItemInventoryQuery->Not Exact Len:Fullname={len(FullName)}; NameFromTaco={len(NameFromTaco)}')
return {}
def to_excel(self, filename:str=''):
start = timeit.default_timer()
# print(f'to_excel filename:{self.filename}')
if filename == '':
print("filename is none")
if self.filename != None:
print("self.filename not none")
filename = self.filename
else:
return False, 'Please fill excel filename.'
# print(filename, type(filename))
if not filename.endswith('.xlsx'):
return False, 'filename has to be excel file(.xlsx)'
# print(self.create_QBXML())
response_string = self.connect_to_quickbooks(self.create_QBXML())
ret, msg = self.status_ok(response_string)
if ret:
df = pd.DataFrame.from_dict(self.get_data(response_string))
print(df)
if len(df)>0:
df.to_excel(filename, index=False)
modtime = datetime.fromtimestamp(os.path.getmtime(filename))
print(f"modified Time:{modtime}")
else:
False, 'There is no data(df==0)'
else:
return False, msg
print("The difference of time is :", timeit.default_timer() - start)
return True, f"It takes {format(timeit.default_timer() - start, '.2f')} seconds to update {filename}"
start = timeit.default_timer()
if __name__ == "__main__":
# ini= ItemInventoryQuery(IncludeRetElement='FullName', OwnerID = "0")
for x in range(0, 1):
# 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))
# ini.to_excel('ItemInventory\ItemInventory_FromQB.xlsx')
itu = ini.connect_to_quickbooks(ini.create_QBXML())
# print(itu)
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}")
break
# print(ini.status_ok(itu))
# print(ini.create_QBXML())
print("The difference of time is :",
timeit.default_timer() - start)

114
ItemIventoryQuery.xml Normal file
View File

@ -0,0 +1,114 @@
<?xml version="1.0" encoding="utf-8"?>
<?qbxml version="16.0"?>
<QBXML>
<QBXMLMsgsRq onError="stopOnError">
<ItemInventoryQueryRq metaData="ENUMTYPE" iterator="ENUMTYPE" iteratorID="UUIDTYPE">
<!-- BEGIN OR -->
<ListID >IDTYPE</ListID> <!-- optional, may repeat -->
<!-- OR -->
<FullName >STRTYPE</FullName> <!-- optional, may repeat -->
<!-- OR -->
<MaxReturned >INTTYPE</MaxReturned> <!-- optional -->
<!-- ActiveStatus may have one of the following values: ActiveOnly [DEFAULT], InactiveOnly, All -->
<ActiveStatus >ENUMTYPE</ActiveStatus> <!-- optional -->
<FromModifiedDate >DATETIMETYPE</FromModifiedDate> <!-- optional -->
<ToModifiedDate >DATETIMETYPE</ToModifiedDate> <!-- optional -->
<!-- BEGIN OR -->
<NameFilter> <!-- optional -->
<!-- MatchCriterion may have one of the following values: StartsWith, Contains, EndsWith -->
<MatchCriterion >ENUMTYPE</MatchCriterion> <!-- required -->
<Name >STRTYPE</Name> <!-- required -->
</NameFilter>
<!-- OR -->
<NameRangeFilter> <!-- optional -->
<FromName >STRTYPE</FromName> <!-- optional -->
<ToName >STRTYPE</ToName> <!-- optional -->
</NameRangeFilter>
<!-- END OR -->
<ClassFilter> <!-- optional -->
<!-- BEGIN OR -->
<ListID >IDTYPE</ListID> <!-- optional, may repeat -->
<!-- OR -->
<FullName >STRTYPE</FullName> <!-- optional, may repeat -->
<!-- OR -->
<ListIDWithChildren >IDTYPE</ListIDWithChildren> <!-- optional -->
<!-- OR -->
<FullNameWithChildren >STRTYPE</FullNameWithChildren> <!-- optional -->
<!-- END OR -->
</ClassFilter>
<!-- END OR -->
<IncludeRetElement >STRTYPE</IncludeRetElement> <!-- optional, may repeat -->
<OwnerID >GUIDTYPE</OwnerID> <!-- optional, may repeat -->
</ItemInventoryQueryRq>
<ItemInventoryQueryRs statusCode="INTTYPE" statusSeverity="STRTYPE" statusMessage="STRTYPE" retCount="INTTYPE" iteratorRemainingCount="INTTYPE" iteratorID="UUIDTYPE">
<ItemInventoryRet> <!-- optional, may repeat -->
<ListID >IDTYPE</ListID> <!-- required -->
<TimeCreated >DATETIMETYPE</TimeCreated> <!-- required -->
<TimeModified >DATETIMETYPE</TimeModified> <!-- required -->
<EditSequence >STRTYPE</EditSequence> <!-- required -->
<Name >STRTYPE</Name> <!-- required -->
<FullName >STRTYPE</FullName> <!-- required -->
<BarCodeValue >STRTYPE</BarCodeValue> <!-- optional -->
<IsActive >BOOLTYPE</IsActive> <!-- optional -->
<ClassRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</ClassRef>
<ParentRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</ParentRef>
<Sublevel >INTTYPE</Sublevel> <!-- required -->
<ManufacturerPartNumber >STRTYPE</ManufacturerPartNumber> <!-- optional -->
<UnitOfMeasureSetRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</UnitOfMeasureSetRef>
<IsTaxIncluded >BOOLTYPE</IsTaxIncluded> <!-- optional -->
<SalesTaxCodeRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</SalesTaxCodeRef>
<SalesDesc >STRTYPE</SalesDesc> <!-- optional -->
<SalesPrice >PRICETYPE</SalesPrice> <!-- optional -->
<IncomeAccountRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</IncomeAccountRef>
<PurchaseDesc >STRTYPE</PurchaseDesc> <!-- optional -->
<PurchaseCost >PRICETYPE</PurchaseCost> <!-- optional -->
<PurchaseTaxCodeRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</PurchaseTaxCodeRef>
<COGSAccountRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</COGSAccountRef>
<PrefVendorRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</PrefVendorRef>
<AssetAccountRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</AssetAccountRef>
<ReorderPoint >QUANTYPE</ReorderPoint> <!-- optional -->
<Max >QUANTYPE</Max> <!-- optional -->
<QuantityOnHand >QUANTYPE</QuantityOnHand> <!-- optional -->
<AverageCost >PRICETYPE</AverageCost> <!-- optional -->
<QuantityOnOrder >QUANTYPE</QuantityOnOrder> <!-- optional -->
<QuantityOnSalesOrder >QUANTYPE</QuantityOnSalesOrder> <!-- optional -->
<ExternalGUID >GUIDTYPE</ExternalGUID> <!-- optional -->
<DataExtRet> <!-- optional, may repeat -->
<OwnerID >GUIDTYPE</OwnerID> <!-- optional -->
<DataExtName >STRTYPE</DataExtName> <!-- required -->
<!-- DataExtType may have one of the following values: AMTTYPE, DATETIMETYPE, INTTYPE, PERCENTTYPE, PRICETYPE, QUANTYPE, STR1024TYPE, STR255TYPE -->
<DataExtType >ENUMTYPE</DataExtType> <!-- required -->
<DataExtValue >STRTYPE</DataExtValue> <!-- required -->
</DataExtRet>
</ItemInventoryRet>
</ItemInventoryQueryRs>
</QBXMLMsgsRq>
</QBXML>

5
ItemReceipt.ini Normal file
View File

@ -0,0 +1,5 @@
[Section 1]
key1 = myval1
key2 = value2
#item_inventory_path = ItemInventory\ItemInventory140723.xlsx

272
ItemReceiptXml.xml Normal file
View File

@ -0,0 +1,272 @@
<?xml version="1.0" encoding="utf-8"?>
<?qbxml version="16.0"?>
<QBXML>
<QBXMLMsgsRq onError="stopOnError">
<ItemReceiptAddRq>
<ItemReceiptAdd defMacro="MACROTYPE"> <!-- required -->
<VendorRef> <!-- required -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</VendorRef>
<TxnDate >DATETYPE</TxnDate> <!-- optional -->
<RefNumber >STRTYPE</RefNumber> <!-- optional -->
<Memo >STRTYPE</Memo> <!-- optional -->
<ExternalGUID >GUIDTYPE</ExternalGUID> <!-- optional -->
<LinkToTxnID >IDTYPE</LinkToTxnID> <!-- optional, may repeat -->
<ItemLineAdd> <!-- optional -->
<ItemRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</ItemRef>
<Desc >STRTYPE</Desc> <!-- optional -->
<Quantity >QUANTYPE</Quantity> <!-- optional -->
<UnitOfMeasure >STRTYPE</UnitOfMeasure> <!-- optional -->
<Cost >PRICETYPE</Cost> <!-- optional -->
<Amount >AMTTYPE</Amount> <!-- optional -->
<LinkToTxn> <!-- optional -->
<TxnID >IDTYPE</TxnID> <!-- required -->
<TxnLineID >IDTYPE</TxnLineID> <!-- required -->
</LinkToTxn>
</ItemLineAdd>
</ItemReceiptAdd>
<IncludeRetElement >STRTYPE</IncludeRetElement> <!-- optional, may repeat -->
</ItemReceiptAddRq>
<ItemReceiptAddRs statusCode="INTTYPE" statusSeverity="STRTYPE" statusMessage="STRTYPE">
<ItemReceiptRet> <!-- optional -->
<TxnID >IDTYPE</TxnID> <!-- required -->
<TimeCreated >DATETIMETYPE</TimeCreated> <!-- required -->
<TimeModified >DATETIMETYPE</TimeModified> <!-- required -->
<EditSequence >STRTYPE</EditSequence> <!-- required -->
<TxnNumber >INTTYPE</TxnNumber> <!-- optional -->
<VendorRef> <!-- required -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</VendorRef>
<!-- BEGIN OR -->
<APAccountRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</APAccountRef>
<!-- OR -->
<LiabilityAccountRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</LiabilityAccountRef>
<!-- END OR -->
<TxnDate >DATETYPE</TxnDate> <!-- required -->
<TotalAmount >AMTTYPE</TotalAmount> <!-- required -->
<CurrencyRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</CurrencyRef>
<ExchangeRate >FLOATTYPE</ExchangeRate> <!-- optional -->
<TotalAmountInHomeCurrency >AMTTYPE</TotalAmountInHomeCurrency> <!-- optional -->
<RefNumber >STRTYPE</RefNumber> <!-- optional -->
<Memo >STRTYPE</Memo> <!-- optional -->
<IsTaxIncluded >BOOLTYPE</IsTaxIncluded> <!-- optional -->
<SalesTaxCodeRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</SalesTaxCodeRef>
<ExternalGUID >GUIDTYPE</ExternalGUID> <!-- optional -->
<LinkedTxn> <!-- optional, may repeat -->
<TxnID >IDTYPE</TxnID> <!-- required -->
<!-- TxnType may have one of the following values: ARRefundCreditCard, Bill, BillPaymentCheck, BillPaymentCreditCard, BuildAssembly, Charge, Check, CreditCardCharge, CreditCardCredit, CreditMemo, Deposit, Estimate, InventoryAdjustment, Invoice, ItemReceipt, JournalEntry, LiabilityAdjustment, Paycheck, PayrollLiabilityCheck, PurchaseOrder, ReceivePayment, SalesOrder, SalesReceipt, SalesTaxPaymentCheck, Transfer, VendorCredit, YTDAdjustment -->
<TxnType >ENUMTYPE</TxnType> <!-- required -->
<TxnDate >DATETYPE</TxnDate> <!-- required -->
<RefNumber >STRTYPE</RefNumber> <!-- optional -->
<!-- LinkType may have one of the following values: AMTTYPE, QUANTYPE -->
<LinkType >ENUMTYPE</LinkType> <!-- optional -->
<Amount >AMTTYPE</Amount> <!-- required -->
</LinkedTxn>
<ExpenseLineRet> <!-- optional, may repeat -->
<TxnLineID >IDTYPE</TxnLineID> <!-- required -->
<AccountRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</AccountRef>
<Amount >AMTTYPE</Amount> <!-- optional -->
<Memo >STRTYPE</Memo> <!-- optional -->
<CustomerRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</CustomerRef>
<ClassRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</ClassRef>
<SalesTaxCodeRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</SalesTaxCodeRef>
<!-- BillableStatus may have one of the following values: Billable, NotBillable, HasBeenBilled -->
<BillableStatus >ENUMTYPE</BillableStatus> <!-- optional -->
<SalesRepRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</SalesRepRef>
<DataExtRet> <!-- optional, may repeat -->
<OwnerID >GUIDTYPE</OwnerID> <!-- optional -->
<DataExtName >STRTYPE</DataExtName> <!-- required -->
<!-- DataExtType may have one of the following values: AMTTYPE, DATETIMETYPE, INTTYPE, PERCENTTYPE, PRICETYPE, QUANTYPE, STR1024TYPE, STR255TYPE -->
<DataExtType >ENUMTYPE</DataExtType> <!-- required -->
<DataExtValue >STRTYPE</DataExtValue> <!-- required -->
</DataExtRet>
</ExpenseLineRet>
<!-- BEGIN OR -->
<ItemLineRet> <!-- optional -->
<TxnLineID >IDTYPE</TxnLineID> <!-- required -->
<ItemRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</ItemRef>
<InventorySiteRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</InventorySiteRef>
<InventorySiteLocationRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</InventorySiteLocationRef>
<!-- BEGIN OR -->
<SerialNumber >STRTYPE</SerialNumber> <!-- optional -->
<!-- OR -->
<LotNumber >STRTYPE</LotNumber> <!-- optional -->
<!-- END OR -->
<ExpirationDateForSerialLotNumber >STRTYPE</ExpirationDateForSerialLotNumber> <!-- optional -->
<Desc >STRTYPE</Desc> <!-- optional -->
<Quantity >QUANTYPE</Quantity> <!-- optional -->
<UnitOfMeasure >STRTYPE</UnitOfMeasure> <!-- optional -->
<OverrideUOMSetRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</OverrideUOMSetRef>
<Cost >PRICETYPE</Cost> <!-- optional -->
<Amount >AMTTYPE</Amount> <!-- optional -->
<CustomerRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</CustomerRef>
<ClassRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</ClassRef>
<SalesTaxCodeRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</SalesTaxCodeRef>
<!-- BillableStatus may have one of the following values: Billable, NotBillable, HasBeenBilled -->
<BillableStatus >ENUMTYPE</BillableStatus> <!-- optional -->
<SalesRepRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</SalesRepRef>
<DataExtRet> <!-- optional, may repeat -->
<OwnerID >GUIDTYPE</OwnerID> <!-- optional -->
<DataExtName >STRTYPE</DataExtName> <!-- required -->
<!-- DataExtType may have one of the following values: AMTTYPE, DATETIMETYPE, INTTYPE, PERCENTTYPE, PRICETYPE, QUANTYPE, STR1024TYPE, STR255TYPE -->
<DataExtType >ENUMTYPE</DataExtType> <!-- required -->
<DataExtValue >STRTYPE</DataExtValue> <!-- required -->
</DataExtRet>
</ItemLineRet>
<!-- OR -->
<ItemGroupLineRet> <!-- optional -->
<TxnLineID >IDTYPE</TxnLineID> <!-- required -->
<ItemGroupRef> <!-- required -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</ItemGroupRef>
<Desc >STRTYPE</Desc> <!-- optional -->
<Quantity >QUANTYPE</Quantity> <!-- optional -->
<UnitOfMeasure >STRTYPE</UnitOfMeasure> <!-- optional -->
<OverrideUOMSetRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</OverrideUOMSetRef>
<TotalAmount >AMTTYPE</TotalAmount> <!-- required -->
<ItemLineRet> <!-- optional, may repeat -->
<TxnLineID >IDTYPE</TxnLineID> <!-- required -->
<ItemRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</ItemRef>
<InventorySiteRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</InventorySiteRef>
<InventorySiteLocationRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</InventorySiteLocationRef>
<!-- BEGIN OR -->
<SerialNumber >STRTYPE</SerialNumber> <!-- optional -->
<!-- OR -->
<LotNumber >STRTYPE</LotNumber> <!-- optional -->
<!-- END OR -->
<ExpirationDateForSerialLotNumber >STRTYPE</ExpirationDateForSerialLotNumber> <!-- optional -->
<Desc >STRTYPE</Desc> <!-- optional -->
<Quantity >QUANTYPE</Quantity> <!-- optional -->
<UnitOfMeasure >STRTYPE</UnitOfMeasure> <!-- optional -->
<OverrideUOMSetRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</OverrideUOMSetRef>
<Cost >PRICETYPE</Cost> <!-- optional -->
<Amount >AMTTYPE</Amount> <!-- optional -->
<CustomerRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</CustomerRef>
<ClassRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</ClassRef>
<SalesTaxCodeRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</SalesTaxCodeRef>
<!-- BillableStatus may have one of the following values: Billable, NotBillable, HasBeenBilled -->
<BillableStatus >ENUMTYPE</BillableStatus> <!-- optional -->
<SalesRepRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</SalesRepRef>
<DataExtRet> <!-- optional, may repeat -->
<OwnerID >GUIDTYPE</OwnerID> <!-- optional -->
<DataExtName >STRTYPE</DataExtName> <!-- required -->
<!-- DataExtType may have one of the following values: AMTTYPE, DATETIMETYPE, INTTYPE, PERCENTTYPE, PRICETYPE, QUANTYPE, STR1024TYPE, STR255TYPE -->
<DataExtType >ENUMTYPE</DataExtType> <!-- required -->
<DataExtValue >STRTYPE</DataExtValue> <!-- required -->
</DataExtRet>
</ItemLineRet>
<DataExt> <!-- optional, may repeat -->
<OwnerID >GUIDTYPE</OwnerID> <!-- required -->
<DataExtName >STRTYPE</DataExtName> <!-- required -->
<DataExtValue >STRTYPE</DataExtValue> <!-- required -->
</DataExt>
</ItemGroupLineRet>
<!-- END OR -->
<DataExtRet> <!-- optional, may repeat -->
<OwnerID >GUIDTYPE</OwnerID> <!-- optional -->
<DataExtName >STRTYPE</DataExtName> <!-- required -->
<!-- DataExtType may have one of the following values: AMTTYPE, DATETIMETYPE, INTTYPE, PERCENTTYPE, PRICETYPE, QUANTYPE, STR1024TYPE, STR255TYPE -->
<DataExtType >ENUMTYPE</DataExtType> <!-- required -->
<DataExtValue >STRTYPE</DataExtValue> <!-- required -->
</DataExtRet>
</ItemReceiptRet>
<ErrorRecovery> <!-- optional -->
<!-- BEGIN OR -->
<ListID >IDTYPE</ListID> <!-- optional -->
<!-- OR -->
<OwnerID >GUIDTYPE</OwnerID> <!-- optional -->
<!-- OR -->
<TxnID >IDTYPE</TxnID> <!-- optional -->
<!-- END OR -->
<TxnNumber >INTTYPE</TxnNumber> <!-- optional -->
<EditSequence >STRTYPE</EditSequence> <!-- optional -->
<ExternalGUID >GUIDTYPE</ExternalGUID> <!-- optional -->
</ErrorRecovery>
</ItemReceiptAddRs>
</QBXMLMsgsRq>
</QBXML>

146
PriceLevelQuery.py Normal file
View File

@ -0,0 +1,146 @@
#!usr/bin/python
import win32com.client
import xml.etree.ElementTree as ET
import json
import xmltodict
# Connect to Quickbooks
sessionManager = win32com.client.Dispatch("QBXMLRP2.RequestProcessor")
sessionManager.OpenConnection('', 'Test qbXML Request')
ticket = sessionManager.BeginSession("C:\Quickbooks Bogor\qb test\distrindo bakti wutama.qbw", 0)
# Send query and receive response
qbxml_query = """
<?qbxml version="13.0"?>
<QBXML>
<QBXMLMsgsRq onError="stopOnError">
<ItemInventoryQueryRq metaData="MetaDataAndResponseData">
<NameFilter>
<MatchCriterion>Contains</MatchCriterion>
<Name>TS-I502</Name>
</NameFilter>
<IncludeRetElement>QuantityOnHand</IncludeRetElement>
</ItemInventoryQueryRq>
</QBXMLMsgsRq>
</QBXML>
"""
qbxml_query = """
<?qbxml version="13.0"?>
<QBXML>
<QBXMLMsgsRq onError="stopOnError">
<PriceLevelQueryRq metaData="MetaDataAndResponseData">
<FullName>A</FullName>
<FullName>B</FullName>
</PriceLevelQueryRq>
</QBXMLMsgsRq>
</QBXML>
"""
qbxml_query = """<?qbxml version="13.0"?>
<QBXML><QBXMLMsgsRq onError="stopOnError"><PriceLevelQueryRq metaData="MetaDataAndResponseData"><FullName>A</FullName><FullName>B</FullName></PriceLevelQueryRq></QBXMLMsgsRq></QBXML>"""
qbxml_query1 = """
<?qbxml version="13.0"?>
<QBXML>
<QBXMLMsgsRq onError="stopOnError">
<ItemInventoryQueryRq metaData="MetaDataAndResponseData">
<IncludeRetElement>QuantityOnHand</IncludeRetElement>
<IncludeRetElement>QuantityOnOrder</IncludeRetElement>
<IncludeRetElement>QuantityOnSalesOrder</IncludeRetElement>
<IncludeRetElement>FullName</IncludeRetElement>
<IncludeRetElement>Name</IncludeRetElement>
</ItemInventoryQueryRq>
</QBXMLMsgsRq>
</QBXML>
"""
root = ET.Element("QBXML")
root.tail = "\n "
root.text = "\n "
QBXMLMsgsRq = ET.SubElement(root, "QBXMLMsgsRq")
QBXMLMsgsRq.set("onError", "stopOnError")
QBXMLMsgsRq.tail = "\n"
QBXMLMsgsRq.text = "\n "
PriceLevelQueryRq = ET.SubElement(QBXMLMsgsRq, "PriceLevelQueryRq")
#PriceLevelQueryRq.set("metaData", "MetaDataAndResponseData")
PriceLevelQueryRq.set("metaData", "NoMetaData")
PriceLevelQueryRq.tail = "\n "
PriceLevelQueryRq.text = "\n "
FullName = ET.SubElement(PriceLevelQueryRq, "FullName")
FullName.text = "A"
FullName.tail = "\n "
FullName = ET.SubElement(PriceLevelQueryRq, "FullName")
FullName.text = "C"
FullName.tail = "\n "
#mydata = ET.tostring(root, encoding = "unicode", method = "xml")
mydata = ET.tostring(root, encoding = "unicode")
#mydata = ET.tostring(root).decode()
print (mydata,type(mydata))
qbxml_query1 = """<?xml version="1.0" encoding="utf-8"?>"""
qbxml_query1 = qbxml_query1 + """<?qbxml version="11.0"?>"""
qbxml_query1 = qbxml_query1 + "\n" + mydata
print("")
print(qbxml_query1, type(qbxml_query1))
print("")
#print(qbxml_query, type(qbxml_query))
tree = ET.ElementTree(root)
print("test",tree)
#response_string = sessionManager.ProcessRequest(ticket, qbxml_query1)
# Disconnect from Quickbooks
sessionManager.EndSession(ticket) # Close the company file
sessionManager.CloseConnection() # Close the connection
#print (response_string)
# Parse the response into an Element Tree and peel away the layers of response
#QBXML = xml.etree.ElementTree.fromstring(response_string)
QBXML = ET.fromstring(response_string)
print("")
#print(QBXML)
#print(QBXML)
datadict=xmltodict.parse(response_string)
#print(datadict)
jsondata=json.dumps(datadict)
#print(jsondata)
ddict=json.loads(jsondata)
#print(ddict)
QBXMLMsgsRs = QBXML.find('QBXMLMsgsRs')
#InventoryAdjustmentQueryRs = QBXMLMsgsRs.getiterator("InventoryAdjustmentRet")
#InventoryAdjustmentQueryRs = QBXMLMsgsRs.iter("ItemInventoryRet")
PriceLevelQueryRs = QBXMLMsgsRs.iter("PriceLevelRet")
#print (PriceLevelQueryRs)
PriceLevelRet = ddict["QBXML"]["QBXMLMsgsRs"]["PriceLevelQueryRs"]["PriceLevelRet"]
#print (priceLevelPerItemRet)
for priceLevelPerItemRetList in PriceLevelRet:
#print(priceLevelPerItemRetList)
#priceLevelPerItemRet = priceLevelPerItemRet["PriceLevelPerItemRet"]
for PriceLevelPerItemRet in priceLevelPerItemRetList["PriceLevelPerItemRet"]:
pass
print(priceLevelPerItemRetList["Name"],PriceLevelPerItemRet["ItemRef"]["FullName"], PriceLevelPerItemRet["CustomPrice"])
# for PriceLevelRet in PriceLevelQueryRs:
# print(PriceLevelRet)
# # try:
# PLT = PriceLevelRet.find('PriceLevelType').text
# IsActive = PriceLevelRet.find('IsActive').text
# #txnid = PriceLevelRet.find('ListID').text
# name = PriceLevelRet.find('Name').text
# PriceLevelPerItemRet = PriceLevelRet.iter("PriceLevelPerItemRet")
# for ItemRef in PriceLevelPerItemRet:
# print(ItemRef)
# FullName = ItemRef.find('FullName').text
# CustomPrice = PriceLevelRet.find('CustomPrice').text
# print(FullName, name, PLT, CustomPrice)
# # except AttributeError:
# # print("attrib err")
# # except:
# # print("err")

147
PriceLevelQueryv2.py Normal file
View File

@ -0,0 +1,147 @@
#!usr/bin/python
import win32com.client
import xml.etree.ElementTree as ET
import json
import xmltodict
# Connect to Quickbooks
sessionManager = win32com.client.Dispatch("QBXMLRP2.RequestProcessor")
sessionManager.OpenConnection('', 'Test qbXML Request')
#ticket = sessionManager.BeginSession("C:\Quickbooks Bogor\qb test\distrindo bakti wutama.qbw", 0)
ticket = sessionManager.BeginSession("", 0)
# Send query and receive response
qbxml_query = """
<?qbxml version="13.0"?>
<QBXML>
<QBXMLMsgsRq onError="stopOnError">
<ItemInventoryQueryRq metaData="MetaDataAndResponseData">
<NameFilter>
<MatchCriterion>Contains</MatchCriterion>
<Name>TS-I502</Name>
</NameFilter>
<IncludeRetElement>QuantityOnHand</IncludeRetElement>
</ItemInventoryQueryRq>
</QBXMLMsgsRq>
</QBXML>
"""
qbxml_query = """
<?qbxml version="13.0"?>
<QBXML>
<QBXMLMsgsRq onError="stopOnError">
<PriceLevelQueryRq metaData="MetaDataAndResponseData">
<FullName>A</FullName>
<FullName>B</FullName>
</PriceLevelQueryRq>
</QBXMLMsgsRq>
</QBXML>
"""
qbxml_query = """<?qbxml version="13.0"?>
<QBXML><QBXMLMsgsRq onError="stopOnError"><PriceLevelQueryRq metaData="MetaDataAndResponseData"><FullName>A</FullName><FullName>B</FullName></PriceLevelQueryRq></QBXMLMsgsRq></QBXML>"""
qbxml_query1 = """
<?qbxml version="13.0"?>
<QBXML>
<QBXMLMsgsRq onError="stopOnError">
<ItemInventoryQueryRq metaData="MetaDataAndResponseData">
<IncludeRetElement>QuantityOnHand</IncludeRetElement>
<IncludeRetElement>QuantityOnOrder</IncludeRetElement>
<IncludeRetElement>QuantityOnSalesOrder</IncludeRetElement>
<IncludeRetElement>FullName</IncludeRetElement>
<IncludeRetElement>Name</IncludeRetElement>
</ItemInventoryQueryRq>
</QBXMLMsgsRq>
</QBXML>
"""
root = ET.Element("QBXML")
root.tail = "\n "
root.text = "\n "
QBXMLMsgsRq = ET.SubElement(root, "QBXMLMsgsRq")
QBXMLMsgsRq.set("onError", "stopOnError")
QBXMLMsgsRq.tail = "\n"
QBXMLMsgsRq.text = "\n "
PriceLevelQueryRq = ET.SubElement(QBXMLMsgsRq, "PriceLevelQueryRq")
#PriceLevelQueryRq.set("metaData", "MetaDataAndResponseData")
PriceLevelQueryRq.set("metaData", "NoMetaData")
PriceLevelQueryRq.tail = "\n "
PriceLevelQueryRq.text = "\n "
FullName = ET.SubElement(PriceLevelQueryRq, "FullName")
FullName.text = "A"
FullName.tail = "\n "
FullName = ET.SubElement(PriceLevelQueryRq, "FullName")
FullName.text = "C"
FullName.tail = "\n "
#mydata = ET.tostring(root, encoding = "unicode", method = "xml")
mydata = ET.tostring(root, encoding = "unicode")
#mydata = ET.tostring(root).decode()
print (mydata,type(mydata))
qbxml_query1 = """<?xml version="1.0" encoding="utf-8"?>"""
qbxml_query1 = qbxml_query1 + """<?qbxml version="11.0"?>"""
qbxml_query1 = qbxml_query1 + "\n" + mydata
print("")
print(qbxml_query1, type(qbxml_query1))
print("")
#print(qbxml_query, type(qbxml_query))
tree = ET.ElementTree(root)
print("test",tree)
response_string = sessionManager.ProcessRequest(ticket, qbxml_query1)
# Disconnect from Quickbooks
sessionManager.EndSession(ticket) # Close the company file
sessionManager.CloseConnection() # Close the connection
print (response_string)
# Parse the response into an Element Tree and peel away the layers of response
#QBXML = xml.etree.ElementTree.fromstring(response_string)
QBXML = ET.fromstring(response_string)
print("")
#print(QBXML)
#print(QBXML)
datadict=xmltodict.parse(response_string)
#print(datadict)
jsondata=json.dumps(datadict)
#print(jsondata)
ddict=json.loads(jsondata)
#print(ddict)
QBXMLMsgsRs = QBXML.find('QBXMLMsgsRs')
#InventoryAdjustmentQueryRs = QBXMLMsgsRs.getiterator("InventoryAdjustmentRet")
#InventoryAdjustmentQueryRs = QBXMLMsgsRs.iter("ItemInventoryRet")
PriceLevelQueryRs = QBXMLMsgsRs.iter("PriceLevelRet")
#print (PriceLevelQueryRs)
PriceLevelRet = ddict["QBXML"]["QBXMLMsgsRs"]["PriceLevelQueryRs"]["PriceLevelRet"]
#print (priceLevelPerItemRet)
for priceLevelPerItemRetList in PriceLevelRet:
#print(priceLevelPerItemRetList)
#priceLevelPerItemRet = priceLevelPerItemRet["PriceLevelPerItemRet"]
for PriceLevelPerItemRet in priceLevelPerItemRetList["PriceLevelPerItemRet"]:
pass
print(priceLevelPerItemRetList["Name"],PriceLevelPerItemRet["ItemRef"]["FullName"], PriceLevelPerItemRet["CustomPrice"])
# for PriceLevelRet in PriceLevelQueryRs:
# print(PriceLevelRet)
# # try:
# PLT = PriceLevelRet.find('PriceLevelType').text
# IsActive = PriceLevelRet.find('IsActive').text
# #txnid = PriceLevelRet.find('ListID').text
# name = PriceLevelRet.find('Name').text
# PriceLevelPerItemRet = PriceLevelRet.iter("PriceLevelPerItemRet")
# for ItemRef in PriceLevelPerItemRet:
# print(ItemRef)
# FullName = ItemRef.find('FullName').text
# CustomPrice = PriceLevelRet.find('CustomPrice').text
# print(FullName, name, PLT, CustomPrice)
# # except AttributeError:
# # print("attrib err")
# # except:
# # print("err")

144
SO_to_Inv/CustomerQuery.py Normal file
View File

@ -0,0 +1,144 @@
import xml.etree.ElementTree as ET
import win32com.client
import xmltodict
import pprint
import datetime
import pandas as pd
from datetime import date
import timeit
import os
class CustomerQuery:
def __init__(self, **kwargs) -> None:
# print(f'kwargs:{kwargs}')
# print(args)
self.CustomerPriceLevelNames = []
self.SPPriceLevelNames = []
self.CustomerFullNames = []
self.item_inventory_path = "ItemInventory"
self._filename = "CustomerList.xlsx"
# self._df_customer = pd.read_excel(os.path.join(os.getcwd(), self.item_inventory_path, self._filename), usecols=['FullName', 'PriceLevelName', 'Special Cust'],)
# print(self._df_customer)
# print(type(self._df_customer.loc[(self._df_customer['FullName']=="ECO:0:ECO-002") & (self._df_customer['PriceLevelName']=="T 202202")].values.tolist()[0][2]))
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 else None
def get_customer_pricelevel_list(self, response_string):
QBXML = ET.fromstring(response_string)
CustomerRets = QBXML.findall('.//CustomerRet')
# print(f'CustomerRets:{CustomerRets}')
for CustomerRet in CustomerRets:
CustomerFullName = None
PriceLevelName = None
SP_PriceLevelName = None
CustomerFullName = CustomerRet.find('FullName').text
PriceLevelName = CustomerRet.find('.//PriceLevelRef')
if PriceLevelName:
PriceLevelName = PriceLevelName.find("FullName").text
# print(f'PriceLevelName:{PriceLevelName}')
DataExtRets = CustomerRet.findall('.//DataExtRet')
SP_PriceLevelName = None
if len(DataExtRets)>0:
for DataExtRet in DataExtRets:
DataExtName = DataExtRet.find('DataExtName').text
DataExtValue = DataExtRet.find('DataExtValue').text
if DataExtName.lower() == 'special cust'.lower():
SP_PriceLevelName = DataExtValue.upper()
break
self.CustomerPriceLevelNames.append(PriceLevelName)
self.SPPriceLevelNames.append(SP_PriceLevelName)
self.CustomerFullNames.append(CustomerFullName)
# print(self.CustomerFullNames, self.CustomerPriceLevelNames, self.SPPriceLevelNames)
Customer = {}
Customer['FullName']=self.CustomerFullNames
Customer['PriceLevelName']=self.CustomerPriceLevelNames
Customer['SPName']= self.SPPriceLevelNames
# print(Customer)
_df = pd.DataFrame.from_dict(Customer)
print(_df)
_df.to_excel(os.path.join(os.getcwd(), self.item_inventory_path, self._filename), index=False)
return PriceLevelName, SP_PriceLevelName
def create_customerquery_QBXML(self ):
root = ET.Element("QBXML")
root.tail = "\n"
root.text = "\n "
QBXMLMsgsRq = ET.SubElement(root, "QBXMLMsgsRq")
# QBXMLMsgsRq.set("onError", "continueOnError")
QBXMLMsgsRq.set("onError", "stopOnError")
QBXMLMsgsRq.tail = "\n"
QBXMLMsgsRq.text = "\n "
CustomerQueryRq = self.create_sub_element(ET, QBXMLMsgsRq, "CustomerQueryRq","\n " )
# FullName = self.create_sub_element(ET, CustomerQueryRq, "FullName", self.FullName, 6)
IncludeRetElement = ['FullName', 'PriceLevelRef', 'DataExtRet']
for x in IncludeRetElement:
IncludeRetElement = self.create_sub_element(ET, CustomerQueryRq, "IncludeRetElement", x, 4)
OwnerID = self.create_sub_element(ET, CustomerQueryRq, "OwnerID", "0", 6)
mydata = ET.tostring(root, encoding = "unicode")
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(f'create_customer_QBXML->qbxml_query: {qbxml_query}')
response_string=self.connect_to_quickbooks(qbxml_query)
return response_string
def create_sub_element(self, ET, parentNode, thisNode, text="\n", whiteSpace = 0, attrib =None):
if type(attrib) is not dict:
attrib = {}
ele = ET.SubElement(parentNode, thisNode)
for x in attrib:
ele.set(x, attrib[x])
ele.text = text
tail = "\n"
for x in range(whiteSpace):
tail = tail + " "
ele.tail = tail
return ele
def connect_to_quickbooks(self, qbxml_query):
# Connect to Quickbooks
sessionManager = win32com.client.Dispatch("QBXMLRP2.RequestProcessor")
sessionManager.OpenConnection('', 'DASA2')
# ticket = sessionManager.BeginSession("z:\\DBW Bogor.qbw", 2)
ticket = sessionManager.BeginSession("", 2)
# Send query and receive response
response_string = sessionManager.ProcessRequest(ticket, qbxml_query)
# Disconnect from Quickbooks
sessionManager.EndSession(ticket) # Close the company file
sessionManager.CloseConnection() # Close the connection
# print (f'response_string:{response_string}')
return response_string
def status_ok(self, QBXML): #for CustomerRs
tree = ET.fromstring(QBXML)
GSRQRs = tree.find(".//CustomerRs")
# print(f"GSRQRs:{GSRQRs}")
status_code = GSRQRs.attrib #.get('statusCode')
# print(GSRQRs.attrib)
# print(GSRQRs.attrib['statusCode'])
status=GSRQRs.attrib.get('statusMessage')
print(f'status={status}')
if 'OK' in status:
return True, status_code
else:
return False, status_code
if __name__ == '__main__':
starttime = timeit.default_timer()
# ini=SalesOrderQuery(FullName= '999 HPL', IncludeRetElement = ['TxnID', 'TimeCreated', 'TimeModified','TxnNumber', 'CustomerRef', 'IsManuallyClosed', 'IsFullyInvoiced'])
ini=CustomerQuery()
iya = ini.create_customerquery_QBXML()
# print(iya)
ini.get_customer_pricelevel_list(iya)
print("The time difference is :", timeit.default_timer() - starttime)

454
SO_to_Inv/InvoiceAdd.xml Normal file
View File

@ -0,0 +1,454 @@
<?xml version="1.0" encoding="utf-8"?>
<?qbxml version="16.0"?>
<QBXML>
<QBXMLMsgsRq onError="stopOnError">
<InvoiceAddRq>
<InvoiceAdd defMacro="MACROTYPE"> <!-- required -->
<CustomerRef> <!-- required -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</CustomerRef>
<ClassRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</ClassRef>
<ARAccountRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</ARAccountRef>
<TemplateRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</TemplateRef>
<TxnDate >DATETYPE</TxnDate> <!-- optional -->
<RefNumber >STRTYPE</RefNumber> <!-- optional -->
<BillAddress> <!-- optional -->
<Addr1 >STRTYPE</Addr1> <!-- optional -->
<Addr2 >STRTYPE</Addr2> <!-- optional -->
<Addr3 >STRTYPE</Addr3> <!-- optional -->
<Addr4 >STRTYPE</Addr4> <!-- optional -->
<Addr5 >STRTYPE</Addr5> <!-- optional -->
<City >STRTYPE</City> <!-- optional -->
<State >STRTYPE</State> <!-- optional -->
<PostalCode >STRTYPE</PostalCode> <!-- optional -->
<Country >STRTYPE</Country> <!-- optional -->
<Note >STRTYPE</Note> <!-- optional -->
</BillAddress>
<ShipAddress> <!-- optional -->
<Addr1 >STRTYPE</Addr1> <!-- optional -->
<Addr2 >STRTYPE</Addr2> <!-- optional -->
<Addr3 >STRTYPE</Addr3> <!-- optional -->
<Addr4 >STRTYPE</Addr4> <!-- optional -->
<Addr5 >STRTYPE</Addr5> <!-- optional -->
<City >STRTYPE</City> <!-- optional -->
<State >STRTYPE</State> <!-- optional -->
<PostalCode >STRTYPE</PostalCode> <!-- optional -->
<Country >STRTYPE</Country> <!-- optional -->
<Note >STRTYPE</Note> <!-- optional -->
</ShipAddress>
<IsPending >BOOLTYPE</IsPending> <!-- optional -->
<IsFinanceCharge >BOOLTYPE</IsFinanceCharge> <!-- optional -->
<PONumber >STRTYPE</PONumber> <!-- optional -->
<TermsRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</TermsRef>
<DueDate >DATETYPE</DueDate> <!-- optional -->
<SalesRepRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</SalesRepRef>
<FOB >STRTYPE</FOB> <!-- optional -->
<ShipDate >DATETYPE</ShipDate> <!-- optional -->
<ShipMethodRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</ShipMethodRef>
<ItemSalesTaxRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</ItemSalesTaxRef>
<Memo >STRTYPE</Memo> <!-- optional -->
<CustomerMsgRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</CustomerMsgRef>
<IsToBePrinted >BOOLTYPE</IsToBePrinted> <!-- optional -->
<IsToBeEmailed >BOOLTYPE</IsToBeEmailed> <!-- optional -->
<IsTaxIncluded >BOOLTYPE</IsTaxIncluded> <!-- optional -->
<CustomerSalesTaxCodeRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</CustomerSalesTaxCodeRef>
<Other >STRTYPE</Other> <!-- optional -->
<ExchangeRate >FLOATTYPE</ExchangeRate> <!-- optional -->
<ExternalGUID >GUIDTYPE</ExternalGUID> <!-- optional -->
<LinkToTxnID >IDTYPE</LinkToTxnID> <!-- optional, may repeat -->
<SetCredit> <!-- optional, may repeat -->
<CreditTxnID useMacro="MACROTYPE">IDTYPE</CreditTxnID> <!-- required -->
<AppliedAmount >AMTTYPE</AppliedAmount> <!-- required -->
<Override >BOOLTYPE</Override> <!-- optional -->
</SetCredit>
<!-- BEGIN OR -->
<InvoiceLineAdd defMacro="MACROTYPE"> <!-- optional -->
<ItemRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</ItemRef>
<Desc >STRTYPE</Desc> <!-- optional -->
<Quantity >QUANTYPE</Quantity> <!-- optional -->
<UnitOfMeasure >STRTYPE</UnitOfMeasure> <!-- optional -->
<!-- BEGIN OR -->
<Rate >PRICETYPE</Rate> <!-- optional -->
<!-- OR -->
<RatePercent >PERCENTTYPE</RatePercent> <!-- optional -->
<!-- OR -->
<PriceLevelRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</PriceLevelRef>
<!-- END OR -->
<ClassRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</ClassRef>
<Amount >AMTTYPE</Amount> <!-- optional -->
<!-- OptionForPriceRuleConflict may have one of the following values: Zero, BasePrice -->
<OptionForPriceRuleConflict >ENUMTYPE</OptionForPriceRuleConflict> <!-- optional -->
<InventorySiteRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</InventorySiteRef>
<InventorySiteLocationRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</InventorySiteLocationRef>
<!-- BEGIN OR -->
<SerialNumber >STRTYPE</SerialNumber> <!-- optional -->
<!-- OR -->
<LotNumber >STRTYPE</LotNumber> <!-- optional -->
<!-- END OR -->
<ServiceDate >DATETYPE</ServiceDate> <!-- optional -->
<SalesTaxCodeRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</SalesTaxCodeRef>
<OverrideItemAccountRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</OverrideItemAccountRef>
<Other1 >STRTYPE</Other1> <!-- optional -->
<Other2 >STRTYPE</Other2> <!-- optional -->
<LinkToTxn> <!-- optional -->
<TxnID >IDTYPE</TxnID> <!-- required -->
<TxnLineID >IDTYPE</TxnLineID> <!-- required -->
</LinkToTxn>
<DataExt> <!-- optional, may repeat -->
<OwnerID >GUIDTYPE</OwnerID> <!-- required -->
<DataExtName >STRTYPE</DataExtName> <!-- required -->
<DataExtValue >STRTYPE</DataExtValue> <!-- required -->
</DataExt>
</InvoiceLineAdd>
<!-- OR -->
<InvoiceLineGroupAdd> <!-- optional -->
<ItemGroupRef> <!-- required -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</ItemGroupRef>
<Quantity >QUANTYPE</Quantity> <!-- optional -->
<UnitOfMeasure >STRTYPE</UnitOfMeasure> <!-- optional -->
<InventorySiteRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</InventorySiteRef>
<InventorySiteLocationRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</InventorySiteLocationRef>
<DataExt> <!-- optional, may repeat -->
<OwnerID >GUIDTYPE</OwnerID> <!-- required -->
<DataExtName >STRTYPE</DataExtName> <!-- required -->
<DataExtValue >STRTYPE</DataExtValue> <!-- required -->
</DataExt>
</InvoiceLineGroupAdd>
<!-- END OR -->
</InvoiceAdd>
<IncludeRetElement >STRTYPE</IncludeRetElement> <!-- optional, may repeat -->
</InvoiceAddRq>
<InvoiceAddRs statusCode="INTTYPE" statusSeverity="STRTYPE" statusMessage="STRTYPE">
<InvoiceRet> <!-- optional -->
<TxnID >IDTYPE</TxnID> <!-- required -->
<TimeCreated >DATETIMETYPE</TimeCreated> <!-- required -->
<TimeModified >DATETIMETYPE</TimeModified> <!-- required -->
<EditSequence >STRTYPE</EditSequence> <!-- required -->
<TxnNumber >INTTYPE</TxnNumber> <!-- optional -->
<CustomerRef> <!-- required -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</CustomerRef>
<ClassRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</ClassRef>
<ARAccountRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</ARAccountRef>
<TemplateRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</TemplateRef>
<TxnDate >DATETYPE</TxnDate> <!-- required -->
<RefNumber >STRTYPE</RefNumber> <!-- optional -->
<BillAddress> <!-- optional -->
<Addr1 >STRTYPE</Addr1> <!-- optional -->
<Addr2 >STRTYPE</Addr2> <!-- optional -->
<Addr3 >STRTYPE</Addr3> <!-- optional -->
<Addr4 >STRTYPE</Addr4> <!-- optional -->
<Addr5 >STRTYPE</Addr5> <!-- optional -->
<City >STRTYPE</City> <!-- optional -->
<State >STRTYPE</State> <!-- optional -->
<PostalCode >STRTYPE</PostalCode> <!-- optional -->
<Country >STRTYPE</Country> <!-- optional -->
<Note >STRTYPE</Note> <!-- optional -->
</BillAddress>
<BillAddressBlock> <!-- optional -->
<Addr1 >STRTYPE</Addr1> <!-- optional -->
<Addr2 >STRTYPE</Addr2> <!-- optional -->
<Addr3 >STRTYPE</Addr3> <!-- optional -->
<Addr4 >STRTYPE</Addr4> <!-- optional -->
<Addr5 >STRTYPE</Addr5> <!-- optional -->
</BillAddressBlock>
<ShipAddress> <!-- optional -->
<Addr1 >STRTYPE</Addr1> <!-- optional -->
<Addr2 >STRTYPE</Addr2> <!-- optional -->
<Addr3 >STRTYPE</Addr3> <!-- optional -->
<Addr4 >STRTYPE</Addr4> <!-- optional -->
<Addr5 >STRTYPE</Addr5> <!-- optional -->
<City >STRTYPE</City> <!-- optional -->
<State >STRTYPE</State> <!-- optional -->
<PostalCode >STRTYPE</PostalCode> <!-- optional -->
<Country >STRTYPE</Country> <!-- optional -->
<Note >STRTYPE</Note> <!-- optional -->
</ShipAddress>
<ShipAddressBlock> <!-- optional -->
<Addr1 >STRTYPE</Addr1> <!-- optional -->
<Addr2 >STRTYPE</Addr2> <!-- optional -->
<Addr3 >STRTYPE</Addr3> <!-- optional -->
<Addr4 >STRTYPE</Addr4> <!-- optional -->
<Addr5 >STRTYPE</Addr5> <!-- optional -->
</ShipAddressBlock>
<IsPending >BOOLTYPE</IsPending> <!-- optional -->
<IsFinanceCharge >BOOLTYPE</IsFinanceCharge> <!-- optional -->
<PONumber >STRTYPE</PONumber> <!-- optional -->
<TermsRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</TermsRef>
<DueDate >DATETYPE</DueDate> <!-- optional -->
<SalesRepRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</SalesRepRef>
<FOB >STRTYPE</FOB> <!-- optional -->
<ShipDate >DATETYPE</ShipDate> <!-- optional -->
<ShipMethodRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</ShipMethodRef>
<Subtotal >AMTTYPE</Subtotal> <!-- optional -->
<ItemSalesTaxRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</ItemSalesTaxRef>
<SalesTaxPercentage >PERCENTTYPE</SalesTaxPercentage> <!-- optional -->
<SalesTaxTotal >AMTTYPE</SalesTaxTotal> <!-- optional -->
<AppliedAmount >AMTTYPE</AppliedAmount> <!-- optional -->
<BalanceRemaining >AMTTYPE</BalanceRemaining> <!-- optional -->
<CurrencyRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</CurrencyRef>
<ExchangeRate >FLOATTYPE</ExchangeRate> <!-- optional -->
<BalanceRemainingInHomeCurrency >AMTTYPE</BalanceRemainingInHomeCurrency> <!-- optional -->
<Memo >STRTYPE</Memo> <!-- optional -->
<IsPaid >BOOLTYPE</IsPaid> <!-- optional -->
<CustomerMsgRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</CustomerMsgRef>
<IsToBePrinted >BOOLTYPE</IsToBePrinted> <!-- optional -->
<IsToBeEmailed >BOOLTYPE</IsToBeEmailed> <!-- optional -->
<IsTaxIncluded >BOOLTYPE</IsTaxIncluded> <!-- optional -->
<CustomerSalesTaxCodeRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</CustomerSalesTaxCodeRef>
<SuggestedDiscountAmount >AMTTYPE</SuggestedDiscountAmount> <!-- optional -->
<SuggestedDiscountDate >DATETYPE</SuggestedDiscountDate> <!-- optional -->
<Other >STRTYPE</Other> <!-- optional -->
<ExternalGUID >GUIDTYPE</ExternalGUID> <!-- optional -->
<LinkedTxn> <!-- optional, may repeat -->
<TxnID >IDTYPE</TxnID> <!-- required -->
<!-- TxnType may have one of the following values: ARRefundCreditCard, Bill, BillPaymentCheck, BillPaymentCreditCard, BuildAssembly, Charge, Check, CreditCardCharge, CreditCardCredit, CreditMemo, Deposit, Estimate, InventoryAdjustment, Invoice, ItemReceipt, JournalEntry, LiabilityAdjustment, Paycheck, PayrollLiabilityCheck, PurchaseOrder, ReceivePayment, SalesOrder, SalesReceipt, SalesTaxPaymentCheck, Transfer, VendorCredit, YTDAdjustment -->
<TxnType >ENUMTYPE</TxnType> <!-- required -->
<TxnDate >DATETYPE</TxnDate> <!-- required -->
<RefNumber >STRTYPE</RefNumber> <!-- optional -->
<!-- LinkType may have one of the following values: AMTTYPE, QUANTYPE -->
<LinkType >ENUMTYPE</LinkType> <!-- optional -->
<Amount >AMTTYPE</Amount> <!-- required -->
</LinkedTxn>
<!-- BEGIN OR -->
<InvoiceLineRet> <!-- optional -->
<TxnLineID >IDTYPE</TxnLineID> <!-- required -->
<ItemRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</ItemRef>
<Desc >STRTYPE</Desc> <!-- optional -->
<Quantity >QUANTYPE</Quantity> <!-- optional -->
<UnitOfMeasure >STRTYPE</UnitOfMeasure> <!-- optional -->
<OverrideUOMSetRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</OverrideUOMSetRef>
<!-- BEGIN OR -->
<Rate >PRICETYPE</Rate> <!-- optional -->
<!-- OR -->
<RatePercent >PERCENTTYPE</RatePercent> <!-- optional -->
<!-- END OR -->
<ClassRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</ClassRef>
<Amount >AMTTYPE</Amount> <!-- optional -->
<InventorySiteRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</InventorySiteRef>
<InventorySiteLocationRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</InventorySiteLocationRef>
<!-- BEGIN OR -->
<SerialNumber >STRTYPE</SerialNumber> <!-- optional -->
<!-- OR -->
<LotNumber >STRTYPE</LotNumber> <!-- optional -->
<!-- END OR -->
<ExpirationDateForSerialLotNumber>STRTYPE</ExpirationDateForSerialLotNumber>
<ServiceDate >DATETYPE</ServiceDate> <!-- optional -->
<SalesTaxCodeRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</SalesTaxCodeRef>
<Other1 >STRTYPE</Other1> <!-- optional -->
<Other2 >STRTYPE</Other2> <!-- optional -->
<DataExtRet> <!-- optional, may repeat -->
<OwnerID >GUIDTYPE</OwnerID> <!-- optional -->
<DataExtName >STRTYPE</DataExtName> <!-- required -->
<!-- DataExtType may have one of the following values: AMTTYPE, DATETIMETYPE, INTTYPE, PERCENTTYPE, PRICETYPE, QUANTYPE, STR1024TYPE, STR255TYPE -->
<DataExtType >ENUMTYPE</DataExtType> <!-- required -->
<DataExtValue >STRTYPE</DataExtValue> <!-- required -->
</DataExtRet>
</InvoiceLineRet>
<!-- OR -->
<InvoiceLineGroupRet> <!-- optional -->
<TxnLineID >IDTYPE</TxnLineID> <!-- required -->
<ItemGroupRef> <!-- required -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</ItemGroupRef>
<Desc >STRTYPE</Desc> <!-- optional -->
<Quantity >QUANTYPE</Quantity> <!-- optional -->
<UnitOfMeasure >STRTYPE</UnitOfMeasure> <!-- optional -->
<OverrideUOMSetRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</OverrideUOMSetRef>
<IsPrintItemsInGroup >BOOLTYPE</IsPrintItemsInGroup> <!-- required -->
<TotalAmount >AMTTYPE</TotalAmount> <!-- required -->
<InvoiceLineRet> <!-- optional, may repeat -->
<TxnLineID >IDTYPE</TxnLineID> <!-- required -->
<ItemRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</ItemRef>
<Desc >STRTYPE</Desc> <!-- optional -->
<Quantity >QUANTYPE</Quantity> <!-- optional -->
<UnitOfMeasure >STRTYPE</UnitOfMeasure> <!-- optional -->
<OverrideUOMSetRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</OverrideUOMSetRef>
<!-- BEGIN OR -->
<Rate >PRICETYPE</Rate> <!-- optional -->
<!-- OR -->
<RatePercent >PERCENTTYPE</RatePercent> <!-- optional -->
<!-- END OR -->
<ClassRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</ClassRef>
<Amount >AMTTYPE</Amount> <!-- optional -->
<InventorySiteRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</InventorySiteRef>
<InventorySiteLocationRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</InventorySiteLocationRef>
<!-- BEGIN OR -->
<SerialNumber >STRTYPE</SerialNumber> <!-- optional -->
<!-- OR -->
<LotNumber >STRTYPE</LotNumber> <!-- optional -->
<!-- END OR -->
<ExpirationDateForSerialLotNumber>STRTYPE</ExpirationDateForSerialLotNumber>
<ServiceDate >DATETYPE</ServiceDate> <!-- optional -->
<SalesTaxCodeRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</SalesTaxCodeRef>
<Other1 >STRTYPE</Other1> <!-- optional -->
<Other2 >STRTYPE</Other2> <!-- optional -->
<DataExtRet> <!-- optional, may repeat -->
<OwnerID >GUIDTYPE</OwnerID> <!-- optional -->
<DataExtName >STRTYPE</DataExtName> <!-- required -->
<!-- DataExtType may have one of the following values: AMTTYPE, DATETIMETYPE, INTTYPE, PERCENTTYPE, PRICETYPE, QUANTYPE, STR1024TYPE, STR255TYPE -->
<DataExtType >ENUMTYPE</DataExtType> <!-- required -->
<DataExtValue >STRTYPE</DataExtValue> <!-- required -->
</DataExtRet>
</InvoiceLineRet>
<DataExtRet> <!-- optional, may repeat -->
<OwnerID >GUIDTYPE</OwnerID> <!-- optional -->
<DataExtName >STRTYPE</DataExtName> <!-- required -->
<!-- DataExtType may have one of the following values: AMTTYPE, DATETIMETYPE, INTTYPE, PERCENTTYPE, PRICETYPE, QUANTYPE, STR1024TYPE, STR255TYPE -->
<DataExtType >ENUMTYPE</DataExtType> <!-- required -->
<DataExtValue >STRTYPE</DataExtValue> <!-- required -->
</DataExtRet>
</InvoiceLineGroupRet>
<!-- END OR -->
<DataExtRet> <!-- optional, may repeat -->
<OwnerID >GUIDTYPE</OwnerID> <!-- optional -->
<DataExtName >STRTYPE</DataExtName> <!-- required -->
<!-- DataExtType may have one of the following values: AMTTYPE, DATETIMETYPE, INTTYPE, PERCENTTYPE, PRICETYPE, QUANTYPE, STR1024TYPE, STR255TYPE -->
<DataExtType >ENUMTYPE</DataExtType> <!-- required -->
<DataExtValue >STRTYPE</DataExtValue> <!-- required -->
</DataExtRet>
</InvoiceRet>
<ErrorRecovery> <!-- optional -->
<!-- BEGIN OR -->
<ListID >IDTYPE</ListID> <!-- optional -->
<!-- OR -->
<OwnerID >GUIDTYPE</OwnerID> <!-- optional -->
<!-- OR -->
<TxnID >IDTYPE</TxnID> <!-- optional -->
<!-- END OR -->
<TxnNumber >INTTYPE</TxnNumber> <!-- optional -->
<EditSequence >STRTYPE</EditSequence> <!-- optional -->
<ExternalGUID >GUIDTYPE</ExternalGUID> <!-- optional -->
</ErrorRecovery>
</InvoiceAddRs>
</QBXMLMsgsRq>
</QBXML>

587
SO_to_Inv/InvoiceQuery.py Normal file
View File

@ -0,0 +1,587 @@
import xml.etree.ElementTree as ET
import win32com.client
import xmltodict
import pprint
import datetime
import pandas as pd
from datetime import date
import timeit
import os
class InvoiceQuery:
def __init__(self, **kwargs) -> None:
# print(f'kwargs:{kwargs}')
# print(args)
# self.InvoiceList=[]
self.PriceLevelName = None
self.SPPriceLevelName = None
self.item_inventory_path = "ItemInventory"
self.price_level_filename = "PriceLevel.xlsx"
self._df_price_level = pd.read_excel(os.path.join(os.getcwd(), 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]))
self.FullName = kwargs['FullName'] if 'FullName' in kwargs else None
self.CustomerPriceLevelName_filename = "CustomerList.xlsx"
self._df_customer = pd.read_excel(os.path.join(os.getcwd(), 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.DN = kwargs['DN'] if 'DN' in kwargs else {}
self.Reuse = kwargs['Reuse'] if 'Reuse' in kwargs else None
self.InvoiceList= kwargs['InvoiceList'] if 'InvoiceList' in kwargs else []
self.InvoiceList = None
self.InvoiceType = kwargs['InvoiceType'] if 'InvoiceType' in kwargs else 'SalesByCustomerSummary'
self.IncludeLineItems = kwargs['IncludeLineItems'] if 'IncludeLineItems' in kwargs else 'true'
self.IncludeRetElement = kwargs['IncludeRetElement'] if 'IncludeRetElement' in kwargs else []
self.TxnDateRangeFilter = kwargs['TxnDateRangeFilter'] if 'TxnDateRangeFilter' in kwargs else None
self.DateMacro = None
self.MaxReturned = kwargs['MaxReturned'] if 'MaxReturned' in kwargs else '1'
if 'DateMacro' in kwargs:
if kwargs['DateMacro'] in ['All', 'Today', 'ThisWeek', 'ThisWeekToDate', 'ThisMonth', 'ThisMonthToDate', 'ThisQuarter', 'ThisQuarterToDate', 'ThisYear', 'ThisYearToDate', 'Yesterday', 'LastWeek', 'LastWeekToDate', 'LastMonth', 'LastMonthToDate', 'LastQuarter', 'LastQuarterToDate', 'LastYear', 'LastYearToDate', 'NextWeek', 'NextFourWeeks', 'NextMonth', 'NextQuarter', 'NextYear']:
self.DateMacro = kwargs['DateMacro']
today = datetime.date.today()
deltatoday = today - datetime.timedelta(days = 74)
print(today, deltatoday)
self.FromTxnDate = self.validate_date(kwargs['FromTxnDate']) if 'FromTxnDate' in kwargs else deltatoday
self.ToTxnDate = self.validate_date(kwargs['ToTxnDate']) if 'ToTxnDate' in kwargs else today
self.ReportEntityFilter = kwargs['ReportEntityFilter'] if 'ReportEntityFilter' in kwargs else None
# print(self.DateMacro, self.TxnDateRangeFilter, self.FromTxnDate, self.ToTxnDate)
# 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.get_sales_order_header()
def create_sub_element(self, ET, parentNode, thisNode, text="\n", whiteSpace = 0, attrib =None):
if type(attrib) is not dict:
attrib = {}
ele = ET.SubElement(parentNode, thisNode)
for x in attrib:
ele.set(x, attrib[x])
ele.text = text
tail = "\n"
for x in range(whiteSpace):
tail = tail + " "
ele.tail = tail
return ele
def create_QBXML(self):
root = ET.Element("QBXML")
root.tail = "\n"
root.text = "\n "
QBXMLMsgsRq = ET.SubElement(root, "QBXMLMsgsRq")
# QBXMLMsgsRq.set("onError", "continueOnError")
QBXMLMsgsRq.set("onError", "stopOnError")
QBXMLMsgsRq.tail = "\n"
QBXMLMsgsRq.text = "\n "
InvoiceQueryRq = self.create_sub_element(ET, QBXMLMsgsRq, "InvoiceQueryRq","\n " )
# InvoiceType = self.create_sub_element(ET, InvoiceQueryRq, 'InvoiceType', self.InvoiceType)
# if self.FullName:
# EntityFilter = self.create_sub_element(ET, InvoiceQueryRq, 'EntityFilter', "\n ")
# FullName = self.create_sub_element(ET, EntityFilter, "FullName", self.FullName, 6)
# if self.MaxReturned:
# MaxReturned = self.create_sub_element(ET, InvoiceQueryRq, 'MaxReturned', self.MaxReturned, 6)
if self.DateMacro:
TxnDateRangeFilter = self.create_sub_element(ET, InvoiceQueryRq, "TxnDateRangeFilter", "\n ",)
InvoiceType = self.create_sub_element(ET, TxnDateRangeFilter, "DateMacro", self.DateMacro)
# InvoiceType = self.create_sub_element(ET, InvoiceQueryRq, "DateMacro", self.DateMacro)
elif type(self.FromTxnDate) is datetime.date or type(self.ToTxnDate) is datetime.date:
TxnDateRangeFilter = self.create_sub_element(ET, InvoiceQueryRq, "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, InvoiceQueryRq, "IncludeLineItems", self.IncludeLineItems, 4)
if len(self.IncludeRetElement)>0:
for x in self.IncludeRetElement:
IncludeRetElement = self.create_sub_element(ET, InvoiceQueryRq, "IncludeRetElement", x, 4)
mydata = ET.tostring(root, encoding = "unicode")
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(f'create_QBXML->qbxml_query: {qbxml_query}')
return qbxml_query
def get_customer_pricelevel(self, response_string):
QBXML = ET.fromstring(response_string)
PriceLevelName = QBXML.find('.//PriceLevelRef')
if PriceLevelName:
PriceLevelName = PriceLevelName.find("FullName").text
print(f'PriceLevelName:{PriceLevelName}')
DataExtRets = QBXML.findall('.//DataExtRet')
SP_PriceLevelName = None
if len(DataExtRets)>0:
for DataExtRet in DataExtRets:
DataExtName = DataExtRet.find('DataExtName').text
DataExtValue = DataExtRet.find('DataExtValue').text
if DataExtName.lower() == 'special cust'.lower():
SP_PriceLevelName = DataExtValue.upper()
break
self.PriceLevelName = PriceLevelName
self.SPPriceLevelName = SP_PriceLevelName
return PriceLevelName, SP_PriceLevelName
def create_customerquery_QBXML(self ):
root = ET.Element("QBXML")
root.tail = "\n"
root.text = "\n "
QBXMLMsgsRq = ET.SubElement(root, "QBXMLMsgsRq")
# QBXMLMsgsRq.set("onError", "continueOnError")
QBXMLMsgsRq.set("onError", "stopOnError")
QBXMLMsgsRq.tail = "\n"
QBXMLMsgsRq.text = "\n "
CustomerQueryRq = self.create_sub_element(ET, QBXMLMsgsRq, "CustomerQueryRq","\n " )
# InvoiceType = self.create_sub_element(ET, CustomerQueryRq, 'InvoiceType', self.InvoiceType)
FullName = self.create_sub_element(ET, CustomerQueryRq, "FullName", self.FullName, 6)
IncludeRetElement = ['FullName', 'PriceLevelRef', 'DataExtRet']
for x in IncludeRetElement:
IncludeRetElement = self.create_sub_element(ET, CustomerQueryRq, "IncludeRetElement", x, 4)
OwnerID = self.create_sub_element(ET, CustomerQueryRq, "OwnerID", "0", 6)
mydata = ET.tostring(root, encoding = "unicode")
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(f'create_customer_QBXML->qbxml_query: {qbxml_query}')
response_string=self.connect_to_quickbooks(qbxml_query)
return self.get_customer_pricelevel(response_string)
return response_string
def create_invoiceadd_QBXML(self):
print('create_ionvoiceadd_QBXML')
root = ET.Element("QBXML")
root.tail = "\n"
root.text = "\n "
QBXMLMsgsRq = ET.SubElement(root, "QBXMLMsgsRq")
QBXMLMsgsRq.set("onError", "stopOnError")
QBXMLMsgsRq.tail = "\n"
QBXMLMsgsRq.text = "\n "
InvoiceAddRq = self.create_sub_element(ET, QBXMLMsgsRq, "InvoiceAddRq", "\n ",2 )
InvoiceAdd = self.create_sub_element(ET, InvoiceAddRq, "InvoiceAdd", "\n ",4 )
CustomerRef = self.create_sub_element(ET, InvoiceAdd, "CustomerRef", "\n ",8 )
FullName = self.create_sub_element(ET, CustomerRef, "FullName", self.InvoiceList[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 )
# Memo = self.create_sub_element(ET, InvoiceAdd, "Memo", self.DN['Memo'], 10 )
disc_amount = 0
for soidx, salesorder in enumerate(self.InvoiceList):
SOTxnId = salesorder['TxnID']
disc_amount+=int(salesorder['Disc_Amount'])
print(f'create_invoiceadd_QBXML->SOTxnId: {SOTxnId}')
for itemline in salesorder['InvoiceLineRet']:
# 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.InvoiceList)-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)
mydata = ET.tostring(root, encoding = "unicode")
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(f'create_invoiceadd_QBXML->Create_Invoiceadd_QBXML: {qbxml_query}')
# print(f"replyfrom qbxml:{self.connect_to_quickbooks(qbxml_query)}")
return qbxml_query
def connect_to_quickbooks(self, qbxml_query):
# Connect to Quickbooks
# sessionManager = win32com.client.Dispatch("QBXMLRP2.RequestProcessor")
# sessionManager.OpenConnection('', 'DASA')
# enumfodnc= win32com.client.Dispatch('QBXMLRP2.RequestProcessor')
# print(enumfodnc)
# print(enumfodnc.qbFileOpenDoNotCare)
sessionManager = win32com.client.Dispatch("QBXMLRP2.RequestProcessor")
sessionManager.OpenConnection('', 'DASA2')
# ticket = sessionManager.BeginSession("z:\\DBW Bogor.qbw", 2)
ticket = sessionManager.BeginSession("", 2)
# Send query and receive response
response_string = sessionManager.ProcessRequest(ticket, qbxml_query)
# Disconnect from Quickbooks
sessionManager.EndSession(ticket) # Close the company file
sessionManager.CloseConnection() # Close the connection
# print (f'response_string:{response_string}')
return response_string
def __str__(self, *args) -> str:
# return str(self._get_datarow(self.connect_to_quickbooks(self.create_QBXML())))
# print("__str__")
return str(self.get_sales_order_header())
# return "hello"
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)
GSRQRs = tree.find(".//InvoiceQueryRs")
# print(f"GSRQRs:{GSRQRs}")
status_code = GSRQRs.attrib #.get('statusCode')
# print(GSRQRs.attrib)
# print(GSRQRs.attrib['statusCode'])
status=GSRQRs.attrib.get('statusMessage')
print(f'status={status}')
if 'OK' in status:
return True, status_code
else:
return False, status_code
def _get_sales_order_header(self, response_string):
print('_get_sales_order_header')
# print(f'responsestring:{response_string}')
QBXML = ET.fromstring(response_string)
datadict = {}
Invoicedict = {}
_Invoicelist = []
InvoiceRets = QBXML.findall('.//InvoiceRet')
# print(InvoiceRets)
for InvoiceRet in InvoiceRets:
RefNumber = InvoiceRet.find('RefNumber').text
# Memo = InvoiceRet.find('Memo').text
CustomerFullName = InvoiceRet.find('CustomerRef/FullName').text
TxnID = InvoiceRet.find('TxnID').text
TotalAmount = InvoiceRet.find('TotalAmount').text
IsFullyInvoiced = InvoiceRet.find('IsFullyInvoiced').text
IsManuallyClosed = InvoiceRet.find('IsManuallyClosed').text
# print(CustomerFullName, TxnID, TotalAmount)
Invoicedict = {'RefNumber':RefNumber, 'CustomerFullName':CustomerFullName, 'TxnID':TxnID,
'TotalAmount':TotalAmount, 'IsFullyInvoiced':IsFullyInvoiced, 'IsManuallyClosed':IsManuallyClosed, 'InvoiceLineRet':[]}
InvoiceLineRet = InvoiceRet.findall('InvoiceLineRet')
# print(len(InvoiceLineRet))
if len(InvoiceLineRet) > 0:
disc_amount=0
for InvoiceLineRet in InvoiceLineRet:
TxnLineID = InvoiceLineRet.find('TxnLineID').text
ItemFullName = InvoiceLineRet.find('ItemRef/FullName').text
Quantity = InvoiceLineRet.find('Quantity').text
UnitOfMeasure = InvoiceLineRet.find('UnitOfMeasure').text
Rate = float(InvoiceLineRet.find('Rate').text)
Amount = float(InvoiceLineRet.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 = InvoiceLineRet.find('Invoiced').text
LineIsManuallyClosed = InvoiceLineRet.find('IsManuallyClosed').text
# print(TxnLineID, ItemFullName)
BackOrdered = float(Quantity) - float(Invoiced)
if BackOrdered:
InvoiceLinedict = {'TxnLineID':TxnLineID,
'ItemFullName':ItemFullName,
'Quantity':Quantity,
'UOM':UnitOfMeasure,
'Rate':Rate,
'Amount':Amount,
'BackOrdered':BackOrdered,
'Invoiced':Invoiced,
'LineIsManuallyClosed':LineIsManuallyClosed,
}
Invoicedict['InvoiceLineRet'].append(InvoiceLinedict)
Invoicedict['Disc_Amount']=disc_amount
_Invoicelist.append(Invoicedict)
# print(_Invoicelist)
self.InvoiceList=_Invoicelist
# print(f'_get_sales_order_header->Salesorderlist: {self.InvoiceList}')
return self.InvoiceList
def addDiscountToInvoiceList(self, _dict:dict):
print("addDiscountToInvoiceList")
def addDNQtyToInvoiceList(self, _dict:dict):
_bolfoundrefnum=False
_bol_dictisadded=False
Error_msg = None
for poidx, _po in enumerate(self.InvoiceList):
if _po['RefNumber']==_dict['RefNum']:
_bolfoundrefnum=True
if len(_po['InvoiceLineRet'])>0:
for polineidx, _poline in enumerate(_po['InvoiceLineRet']):
pass
if _poline['ItemFullName']==_dict['FullName']:
if _poline['UOM'].upper()==_dict['UOM'].upper():
# first do UOM in _dict convert treatment
QuantityIn_dict = _dict['Quantity']
if _dict['UOM'].upper().startswith('ROLL_'):
print(f"addDNQtyToInvoiceList->DNqty:{_dict['Quantity']}, Roll_:{_dict['UOM'].split('_')[1]}")
QuantityIn_dict = _dict['Quantity'] * int(_dict['UOM'].split("_")[1])
pass
elif _dict['UOM'].upper() == 'BOX' and _dict['Item No'].upper() == "CUTTER":
print("addDNQtyToInvoiceList->cutter")
elif _dict['UOM'].upper() == 'BOX' and (_dict['Item No'].upper().startswith("EB-") or _dict['Item No'].upper().startswith("TA-")):
print("addDNQtyToInvoiceList->LEM")
if _dict['Item No'].split("-")[1].endswith("1006"):
QuantityIn_dict = QuantityIn_dict * 12
elif _dict['Item No'].split("-")[1].endswith("1025"):
QuantityIn_dict = QuantityIn_dict * 6
elif _dict['Item No'].split("-")[1].endswith("1100"):
pass
print("1100 lem")
elif _dict['UOM'].upper() == 'BOX' and (_dict['Item No'].upper().startswith("TL-") or _dict['Item No'].upper().startswith("TFL-")):
print("addDNQtyToInvoiceList->Lock")
QuantityIn_dict = QuantityIn_dict * 20
elif _dict['UOM'].upper() == 'BOX' and _dict['Item No'].upper() == "EDG-TRIMMER":
QuantityIn_dict = QuantityIn_dict * 12 #coz box of 12
if _poline['BackOrdered']>=QuantityIn_dict:
self.InvoiceList[poidx]['InvoiceLineRet'][polineidx]['DNQuantity']=float(QuantityIn_dict)
_bol_dictisadded = True
else:
print(f"{_poline['ItemFullName']} BackOrdered < Qty in DN {_poline['BackOrdered']}<{QuantityIn_dict}")
Error_msg = f"BackOrdered < Qty in DN {_poline['BackOrdered']}<{QuantityIn_dict}"
else:
# print(f"UOM different {_poline['UOM']} <> {_dict['UOM']}")
Error_msg = f"UOM different {_poline['UOM']} <> {_dict['UOM']}"
else:
# print("errorpoline <>DN")
Error_msg = f"poline[ItemFullName] <> DN[FullName]; {_poline['ItemFullName']} <> {_dict['FullName']}, maybe there are 2 same namefromtaco in QB"
else:
pass
# print(f"this refnum {_dict['RefNum']} have no QB PO Return Line")
Error_msg = f"this refnum {_dict['RefNum']} have no QB PO Return Line"
# print (_bol_dictisadded, Error_msg)
return _bol_dictisadded, Error_msg
def prepareInvoice(self, df:pd.DataFrame = None):
# print(df)
_bolAllDNareOk = True
_notindflist=[]
_yescounter = 0
_nocounter = 0
if df is not None:
_dflist = df.to_dict('records')
# print(_dflist)
# else:
# _dflist = self.dfDN.to_dict('records')
# print(self.dfDN)
# print(f'_dflist:{_dflist}')
for idx, xdf in enumerate(_dflist):
_boladdDN, _Errormsg = self.addDNQtyToInvoiceList(xdf)
# print(f'prepareInvoice->_Errormsg:{_Errormsg}')
if _boladdDN:
_dflist[idx]['ADDED']=True
elif _Errormsg:
_dflist[idx]['ERROR']=_Errormsg
for xdf in (_dflist):
if 'ADDED' not in xdf:
# print (f"prepareInvoice->not added: {xdf['Item No']}")
print (f"prepareInvoice->not added: {xdf}")
_notindflist.append(xdf)
_nocounter+=1
_bolAllDNareOk = False
else:
print (f"ADDED: {xdf['Item No']}")
print(f'{len(_dflist) - _nocounter} of {len(_dflist)} are added')
return _bolAllDNareOk, _notindflist
def validate_date(self, date_text):
if date_text is None:
return None
try:
return datetime.datetime.strptime(date_text, '%Y-%m-%d').date()
except ValueError:
return None
# raise ValueError("Incorrect data format, should be YYYY-MM-DD")
def get_ext_doc_no_list(self, dndict=None):
if dndict:
dnlist = dndict['lines']
else:
dnlist = self.DN
df = pd.DataFrame(dnlist)
# print(df)
df['RefNum']= df['No.SO/Ext.Doc.No.'].apply(lambda x: "L"+ x.split("L-")[1])
# print(df)
ext_doc_no=df['RefNum'].unique().tolist()
if len(ext_doc_no)>0:
return df, ext_doc_no
else:
return df, None
def get_last_refnumber(self, response_string=None):
if not response_string:
response_string = self.connect_to_quickbooks(self.create_QBXML())
status, status_msg = self.status_ok(response_string)
if not status:
return None
QBXML = ET.fromstring(response_string)
_OpenInvoicelist = []
InvoiceRets = QBXML.findall('.//RefNumber')
print(f'InvoiceRets count:{len(InvoiceRets)}')
refnumbers = []
for InvoiceRet in InvoiceRets:
print(InvoiceRet, InvoiceRet.text)
refnumbers.append(InvoiceRet.text)
# IsFullyInvoiced = InvoiceRet.find('IsFullyInvoiced').text
# IsManuallyClosed = InvoiceRet.find('IsManuallyClosed').text
# if IsFullyInvoiced=='false' and IsManuallyClosed=='false':
# txndate = InvoiceRet.find('TxnDate').text
# totalamount = InvoiceRet.find('TotalAmount').text
# refnumber = InvoiceRet.find('RefNumber').text
# _OpenInvoicelist.append([InvoiceRet.find('TxnID').text, txndate, totalamount, refnumber, ])
# # _OpenInvoicelist.append(InvoiceRet.find('TxnID').text)
# # RefNumber = InvoiceRet.find('RefNumber').text
# # Memo = InvoiceRet.find('Memo').text
# # CustomerFullName = InvoiceRet.find('CustomerRef/FullName').text
# # TxnID = InvoiceRet.find('TxnID').text
# # TotalAmount = InvoiceRet.find('TotalAmount').text
# # IsFullyReceived = InvoiceRet.find('IsFullyReceived').text
# # IsManuallyClosed = InvoiceRet.find('IsManuallyClosed').text
print(refnumbers)
refnumbers.sort()
return refnumbers[-1]
def get_open_so(self, response_string=None):
if not response_string:
response_string = self.connect_to_quickbooks(self.create_QBXML())
QBXML = ET.fromstring(response_string)
_OpenInvoicelist = []
InvoiceRets = QBXML.findall('.//InvoiceRet')
# print(f'InvoiceRets count:{len(InvoiceRets)}')
for InvoiceRet in InvoiceRets:
IsFullyInvoiced = InvoiceRet.find('IsFullyInvoiced').text
IsManuallyClosed = InvoiceRet.find('IsManuallyClosed').text
if IsFullyInvoiced=='false' and IsManuallyClosed=='false':
txndate = InvoiceRet.find('TxnDate').text
totalamount = InvoiceRet.find('TotalAmount').text
refnumber = InvoiceRet.find('RefNumber').text
_OpenInvoicelist.append([InvoiceRet.find('TxnID').text, txndate, totalamount, refnumber, ])
# _OpenInvoicelist.append(InvoiceRet.find('TxnID').text)
# RefNumber = InvoiceRet.find('RefNumber').text
# Memo = InvoiceRet.find('Memo').text
# CustomerFullName = InvoiceRet.find('CustomerRef/FullName').text
# TxnID = InvoiceRet.find('TxnID').text
# TotalAmount = InvoiceRet.find('TotalAmount').text
# IsFullyReceived = InvoiceRet.find('IsFullyReceived').text
# IsManuallyClosed = InvoiceRet.find('IsManuallyClosed').text
# print(_OpenInvoicelist)
return _OpenInvoicelist
def create_open_sales_order_qbxml(self, txnid:list, IncludeLineItems=True):
root = ET.Element("QBXML")
root.tail = "\n"
root.text = "\n "
QBXMLMsgsRq = ET.SubElement(root, "QBXMLMsgsRq")
# QBXMLMsgsRq.set("onError", "continueOnError")
QBXMLMsgsRq.set("onError", "stopOnError")
QBXMLMsgsRq.tail = "\n"
QBXMLMsgsRq.text = "\n "
InvoiceQueryRq = self.create_sub_element(ET, QBXMLMsgsRq, "InvoiceQueryRq","\n " )
if len(txnid)>0:
for x in txnid:
TxnID = self.create_sub_element(ET, InvoiceQueryRq, "TxnID", x, 6 )
else:
return None
if IncludeLineItems:
IncludeLineItems = self.create_sub_element(ET, InvoiceQueryRq, "IncludeLineItems", 'true', 4)
# if len(self.IncludeRetElement)>0:
# for x in self.IncludeRetElement:
# IncludeRetElement = self.create_sub_element(ET, InvoiceQueryRq, "IncludeRetElement", x, 4)
mydata = ET.tostring(root, encoding = "unicode")
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(f'create_open_sale_order_qbxml->qbxml_query: {qbxml_query}')
return qbxml_query
def get_open_sales_order(self, txnlist:list):
print(f'txnid: {txnlist}', type(txnlist))
txnid = []
for x in txnlist:
if isinstance(x, list):
txnid.append(x[0])
else:
txnid.append(x)
break
# txnid = [x[0] if isinstance(x, list) else x for x in txnid ]
print(txnid)
if txnid:
# print(self.connect_to_quickbooks(self.create_open_sales_order_qbxml(txnid)))
return self._get_sales_order_header(self.connect_to_quickbooks(self.create_open_sales_order_qbxml(txnid)))
else:
print("There is No Open Invoice Order")
return None
return None
print('### InvoiceQuery ###')
if __name__ == '__main__':
starttime = timeit.default_timer()
# ini=InvoiceQuery(FullName= '999 HPL', IncludeRetElement = ['TxnID', 'TimeCreated', 'TimeModified','TxnNumber', 'CustomerRef', 'IsManuallyClosed', 'IsFullyInvoiced'])
# ini=InvoiceQuery(FullName= 'YSM Interior', IncludeRetElement = ['TxnID', 'TimeCreated', 'TimeModified','TxnNumber', 'CustomerRef', 'TxnDate', 'RefNumber', 'IsManuallyClosed', 'IsFullyInvoiced','TotalAmount'])
ini=InvoiceQuery(FullName= 'Abadi Serpong', IncludeRetElement = 'RefNumber', ])
# iya = ini.create_customerquery_QBXML() #pakai excel saja lebih cepat
# print(iya)
print(f'createQBXML:{ini.create_QBXML()}')
response_string = ini.connect_to_quickbooks(ini.create_QBXML())
print(f'response_string:{response_string}')
# response_string = None
last_refnumber = ini.get_last_refnumber(response_string)
print(f'open sales orders:{last_refnumber};type:{type(last_refnumber)}')
# print('23a'+1)
# if open_sales_orders:
# itu = ini.get_open_sales_order(open_sales_orders)
# # print(itu)
# print(f'get_open_sales_order:{itu}')
# if itu:
# print(ini.create_invoiceadd_QBXML())
# # ini.connect_to_quickbooks(ini.create_invoiceadd_QBXML())
print("The time difference is :", timeit.default_timer() - starttime)

View File

@ -0,0 +1,444 @@
import xml.etree.ElementTree as ET
import win32com.client
import xmltodict
import pprint
import datetime
import pandas as pd
from datetime import date
import timeit
class PriceLevelQuery:
def __init__(self, **kwargs) -> None:
# print(f'kwargs:{kwargs}')
# print(args)
# self.SalesOrderList=[]
self.IncludeLineItems = kwargs['IncludeLineItems'] if 'IncludeLineItems' in kwargs else 'true'
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 []
self.NameFilter = kwargs['NameFilter'] if 'NameFilter' in kwargs else None
self.ItemRef = kwargs['ItemRef'] if 'ItemRef' in kwargs else None
def create_sub_element(self, ET, parentNode, thisNode, text="\n", whiteSpace = 0, attrib =None):
if type(attrib) is not dict:
attrib = {}
ele = ET.SubElement(parentNode, thisNode)
for x in attrib:
ele.set(x, attrib[x])
ele.text = text
tail = "\n"
for x in range(whiteSpace):
tail = tail + " "
ele.tail = tail
return ele
def create_QBXML(self):
root = ET.Element("QBXML")
root.tail = "\n"
root.text = "\n "
QBXMLMsgsRq = ET.SubElement(root, "QBXMLMsgsRq")
# QBXMLMsgsRq.set("onError", "continueOnError")
QBXMLMsgsRq.set("onError", "stopOnError")
QBXMLMsgsRq.tail = "\n"
QBXMLMsgsRq.text = "\n "
PriceLevelQueryRq = self.create_sub_element(ET, QBXMLMsgsRq, "PriceLevelQueryRq","\n " )
if len(self.FullName)>0:
for x in self.FullName:
FullName = self.create_sub_element(ET, PriceLevelQueryRq, "FullName", x, 6)
if self.NameFilter:
NameFilter = self.create_sub_element(ET, PriceLevelQueryRq, "NameFilter","\n ", 6)
MatchCriterion = self.create_sub_element(ET, NameFilter, "MatchCriterion", "StartsWith")
Name = self.create_sub_element(ET, NameFilter, "Name", self.NameFilter)
if self.ItemRef:
ItemRef = self.create_sub_element(ET, PriceLevelQueryRq, "ItemRef", "\n ")
ItemRefFullName = self.create_sub_element(ET, ItemRef, "FullName", self.ItemRef)
if len(self.IncludeRetElement)>0:
for x in self.IncludeRetElement:
IncludeRetElement = self.create_sub_element(ET, PriceLevelQueryRq, "IncludeRetElement", x, 4)
mydata = ET.tostring(root, encoding = "unicode")
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(f'create_QBXML->qbxml_query: {qbxml_query}')
return qbxml_query
def create_invoiceadd_QBXML(self):
root = ET.Element("QBXML")
root.tail = "\n"
root.text = "\n "
QBXMLMsgsRq = ET.SubElement(root, "QBXMLMsgsRq")
QBXMLMsgsRq.set("onError", "stopOnError")
QBXMLMsgsRq.tail = "\n"
QBXMLMsgsRq.text = "\n "
InvoiceAddRq = self.create_sub_element(ET, QBXMLMsgsRq, "InvoiceAddRq", "\n ",2 )
InvoiceAdd = self.create_sub_element(ET, InvoiceAddRq, "InvoiceAdd", "\n ",4 )
CustomerRef = self.create_sub_element(ET, InvoiceAdd, "CustomerRef", "\n ",8 )
FullName = self.create_sub_element(ET, CustomerRef, "FullName", self.SalesOrderList[1]['CustomerFullName'], 8 )
TemplateRef = self.create_sub_element(ET, InvoiceAdd, "TemplateRef", "\n ", 8 )
tempFullName = 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 )
# 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")}')
# 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)
mydata = ET.tostring(root, encoding = "unicode")
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(f'create_invoiceadd_QBXML->Create_Invoiceadd_QBXML: {qbxml_query}')
# print(f"replyfrom qbxml:{self.connect_to_quickbooks(qbxml_query)}")
return qbxml_query
def connect_to_quickbooks(self, qbxml_query):
# Connect to Quickbooks
# sessionManager = win32com.client.Dispatch("QBXMLRP2.RequestProcessor")
# sessionManager.OpenConnection('', 'DASA')
# enumfodnc= win32com.client.Dispatch('QBXMLRP2.RequestProcessor')
# print(enumfodnc)
# print(enumfodnc.qbFileOpenDoNotCare)
sessionManager = win32com.client.Dispatch("QBXMLRP2.RequestProcessor")
sessionManager.OpenConnection('', 'DASA2')
# ticket = sessionManager.BeginSession("z:\\DBW Bogor.qbw", 2)
ticket = sessionManager.BeginSession("", 2)
# Send query and receive response
response_string = sessionManager.ProcessRequest(ticket, qbxml_query)
# Disconnect from Quickbooks
sessionManager.EndSession(ticket) # Close the company file
sessionManager.CloseConnection() # Close the connection
# print (f'response_string:{response_string}')
return response_string
def __str__(self, *args) -> str:
# return str(self._get_datarow(self.connect_to_quickbooks(self.create_QBXML())))
# print("__str__")
return str(self.get_sales_order_header())
# return "hello"
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)
GSRQRs = tree.find(".//PriceLevelQueryRs")
# print(f"GSRQRs:{GSRQRs}")
status_code = GSRQRs.attrib #.get('statusCode')
# print(GSRQRs.attrib)
# print(GSRQRs.attrib['statusCode'])
status=GSRQRs.attrib.get('statusMessage')
print(f'status={status}')
if 'OK' in status:
return True, status_code
else:
return False, status_code
def _get_sales_order_header(self, response_string):
print('_get_sales_order_header')
# print(f'responsestring:{response_string}')
QBXML = ET.fromstring(response_string)
datadict = {}
SalesOrderdict = {}
_SalesOrderlist = []
SalesOrderRets = QBXML.findall('.//SalesOrderRet')
# print(SalesOrderRets)
for SalesOrderRet in SalesOrderRets:
RefNumber = SalesOrderRet.find('RefNumber').text
# Memo = SalesOrderRet.find('Memo').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
# print(CustomerFullName, TxnID, TotalAmount)
SalesOrderdict = {'RefNumber':RefNumber, 'CustomerFullName':CustomerFullName, 'TxnID':TxnID,
'TotalAmount':TotalAmount, 'IsFullyInvoiced':IsFullyInvoiced, 'IsManuallyClosed':IsManuallyClosed, 'SalesOrderLineRet':[]}
SalesOrderLineRet = SalesOrderRet.findall('SalesOrderLineRet')
# print(len(SalesOrderLineRet))
if len(SalesOrderLineRet) > 0:
disc_amount=0
for SalesOrderLineRet in SalesOrderLineRet:
TxnLineID = SalesOrderLineRet.find('TxnLineID').text
ItemFullName = SalesOrderLineRet.find('ItemRef/FullName').text
Quantity = SalesOrderLineRet.find('Quantity').text
UnitOfMeasure = SalesOrderLineRet.find('UnitOfMeasure').text
Rate = float(SalesOrderLineRet.find('Rate').text)
Amount = float(SalesOrderLineRet.find('Amount').text)
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:
SalesOrderLinedict = {'TxnLineID':TxnLineID,
'ItemFullName':ItemFullName,
'Quantity':Quantity,
'UOM':UnitOfMeasure,
'Rate':Rate,
'Amount':Amount,
'BackOrdered':BackOrdered,
'Invoiced':Invoiced,
'LineIsManuallyClosed':LineIsManuallyClosed,
}
SalesOrderdict['SalesOrderLineRet'].append(SalesOrderLinedict)
SalesOrderdict['Disc_Amount']=disc_amount
_SalesOrderlist.append(SalesOrderdict)
# print(_SalesOrderlist)
self.SalesOrderList=_SalesOrderlist
# print(f'_get_sales_order_header->Salesorderlist: {self.SalesOrderList}')
return self.SalesOrderList
def addDiscountToInvoiceList(self, _dict:dict):
print("addDiscountToInvoiceList")
def addDNQtyToSalesOrderList(self, _dict:dict):
_bolfoundrefnum=False
_bol_dictisadded=False
Error_msg = None
for poidx, _po in enumerate(self.SalesOrderList):
if _po['RefNumber']==_dict['RefNum']:
_bolfoundrefnum=True
if len(_po['SalesOrderLineRet'])>0:
for polineidx, _poline in enumerate(_po['SalesOrderLineRet']):
pass
if _poline['ItemFullName']==_dict['FullName']:
if _poline['UOM'].upper()==_dict['UOM'].upper():
# first do UOM in _dict convert treatment
QuantityIn_dict = _dict['Quantity']
if _dict['UOM'].upper().startswith('ROLL_'):
print(f"addDNQtyToSalesOrderList->DNqty:{_dict['Quantity']}, Roll_:{_dict['UOM'].split('_')[1]}")
QuantityIn_dict = _dict['Quantity'] * int(_dict['UOM'].split("_")[1])
pass
elif _dict['UOM'].upper() == 'BOX' and _dict['Item No'].upper() == "CUTTER":
print("addDNQtyToSalesOrderList->cutter")
elif _dict['UOM'].upper() == 'BOX' and (_dict['Item No'].upper().startswith("EB-") or _dict['Item No'].upper().startswith("TA-")):
print("addDNQtyToSalesOrderList->LEM")
if _dict['Item No'].split("-")[1].endswith("1006"):
QuantityIn_dict = QuantityIn_dict * 12
elif _dict['Item No'].split("-")[1].endswith("1025"):
QuantityIn_dict = QuantityIn_dict * 6
elif _dict['Item No'].split("-")[1].endswith("1100"):
pass
print("1100 lem")
elif _dict['UOM'].upper() == 'BOX' and (_dict['Item No'].upper().startswith("TL-") or _dict['Item No'].upper().startswith("TFL-")):
print("addDNQtyToSalesOrderList->Lock")
QuantityIn_dict = QuantityIn_dict * 20
elif _dict['UOM'].upper() == 'BOX' and _dict['Item No'].upper() == "EDG-TRIMMER":
QuantityIn_dict = QuantityIn_dict * 12 #coz box of 12
if _poline['BackOrdered']>=QuantityIn_dict:
self.SalesOrderList[poidx]['SalesOrderLineRet'][polineidx]['DNQuantity']=float(QuantityIn_dict)
_bol_dictisadded = True
else:
print(f"{_poline['ItemFullName']} BackOrdered < Qty in DN {_poline['BackOrdered']}<{QuantityIn_dict}")
Error_msg = f"BackOrdered < Qty in DN {_poline['BackOrdered']}<{QuantityIn_dict}"
else:
# print(f"UOM different {_poline['UOM']} <> {_dict['UOM']}")
Error_msg = f"UOM different {_poline['UOM']} <> {_dict['UOM']}"
else:
# print("errorpoline <>DN")
Error_msg = f"poline[ItemFullName] <> DN[FullName]; {_poline['ItemFullName']} <> {_dict['FullName']}, maybe there are 2 same namefromtaco in QB"
else:
pass
# print(f"this refnum {_dict['RefNum']} have no QB PO Return Line")
Error_msg = f"this refnum {_dict['RefNum']} have no QB PO Return Line"
# print (_bol_dictisadded, Error_msg)
return _bol_dictisadded, Error_msg
def prepareInvoice(self, df:pd.DataFrame = None):
# print(df)
_bolAllDNareOk = True
_notindflist=[]
_yescounter = 0
_nocounter = 0
if df is not None:
_dflist = df.to_dict('records')
# print(_dflist)
else:
_dflist = self.dfDN.to_dict('records')
# print(self.dfDN)
# print(f'_dflist:{_dflist}')
for idx, xdf in enumerate(_dflist):
_boladdDN, _Errormsg = self.addDNQtyToSalesOrderList(xdf)
# print(f'prepareInvoice->_Errormsg:{_Errormsg}')
if _boladdDN:
_dflist[idx]['ADDED']=True
elif _Errormsg:
_dflist[idx]['ERROR']=_Errormsg
for xdf in (_dflist):
if 'ADDED' not in xdf:
# print (f"prepareInvoice->not added: {xdf['Item No']}")
print (f"prepareInvoice->not added: {xdf}")
_notindflist.append(xdf)
_nocounter+=1
_bolAllDNareOk = False
else:
print (f"ADDED: {xdf['Item No']}")
print(f'{len(_dflist) - _nocounter} of {len(_dflist)} are added')
return _bolAllDNareOk, _notindflist
def validate_date(self, date_text):
if date_text is None:
return None
try:
return datetime.datetime.strptime(date_text, '%Y-%m-%d').date()
except ValueError:
return None
# raise ValueError("Incorrect data format, should be YYYY-MM-DD")
def get_ext_doc_no_list(self, dndict=None):
if dndict:
dnlist = dndict['lines']
else:
dnlist = self.DN
df = pd.DataFrame(dnlist)
# print(df)
df['RefNum']= df['No.SO/Ext.Doc.No.'].apply(lambda x: "L"+ x.split("L-")[1])
# print(df)
ext_doc_no=df['RefNum'].unique().tolist()
if len(ext_doc_no)>0:
return df, ext_doc_no
else:
return df, None
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)
if statusok:
QBXML = ET.fromstring(response_string)
PriceLevellist = {}
fullnamelist = []
custompricelist =[]
PriceLevelRets = QBXML.findall('.//PriceLevelRet')
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
print(f'pricelevelname:{PriceLevelName}')
for PriceLevelPerItemRet in PriceLevelPerItemRets:
FullName = PriceLevelPerItemRet.find('.//FullName').text
fullnamelist.append(FullName)
CustomPrice = PriceLevelPerItemRet.find('CustomPrice').text
custompricelist.append(CustomPrice)
PriceLevelNamelist.append(PriceLevelName)
zip(fullnamelist, custompricelist)
PriceLevellist['PriceLevelName'] = PriceLevelNamelist
PriceLevellist['FullName']= fullnamelist
PriceLevellist['CustomPrice']= custompricelist
PriceLeveldf = pd.DataFrame.from_dict(PriceLevellist)
PriceLeveldf.sort_values(by=['PriceLevelName', 'FullName'], inplace=True)
PriceLeveldf=PriceLeveldf.reset_index(drop=True)
print(PriceLeveldf)
PriceLeveldf.to_excel('ItemInventory\PriceLevel.xlsx', sheet_name=PriceLevelName, index=False )
# print(PriceLevellist)
return PriceLevellist
else:
return None
def create_open_sales_order_qbxml(self, txnid:list, IncludeLineItems=True):
root = ET.Element("QBXML")
root.tail = "\n"
root.text = "\n "
QBXMLMsgsRq = ET.SubElement(root, "QBXMLMsgsRq")
# QBXMLMsgsRq.set("onError", "continueOnError")
QBXMLMsgsRq.set("onError", "stopOnError")
QBXMLMsgsRq.tail = "\n"
QBXMLMsgsRq.text = "\n "
SalesOrderQueryRq = self.create_sub_element(ET, QBXMLMsgsRq, "SalesOrderQueryRq","\n " )
if len(txnid)>0:
for x in txnid:
TxnID = self.create_sub_element(ET, SalesOrderQueryRq, "TxnID", x, 6 )
else:
return None
if IncludeLineItems:
IncludeLineItems = self.create_sub_element(ET, SalesOrderQueryRq, "IncludeLineItems", 'true', 4)
# if len(self.IncludeRetElement)>0:
# for x in self.IncludeRetElement:
# IncludeRetElement = self.create_sub_element(ET, SalesOrderQueryRq, "IncludeRetElement", x, 4)
mydata = ET.tostring(root, encoding = "unicode")
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(f'create_QBXML->qbxml_query: {qbxml_query}')
return qbxml_query
def get_open_sales_order(self, txnid:list):
print(f'txnid: {txnid}', type(txnid))
txnid = [x[0] if isinstance(x, list) else x for x in txnid ]
if txnid:
# print(self.connect_to_quickbooks(self.create_open_sales_order_qbxml(txnid)))
return self._get_sales_order_header(self.connect_to_quickbooks(self.create_open_sales_order_qbxml(txnid)))
else:
print("There is No Open Sales Order")
return None
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'], )
# 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(f'pricelevel:{pricelevel}')
# print(ini.get_open_sales_order(open_sales_orders))
# print(ini.create_invoiceadd_QBXML())
# ini.connect_to_quickbooks(ini.create_invoiceadd_QBXML())
print("The time difference is :", timeit.default_timer() - starttime)

View File

@ -0,0 +1,336 @@
<?xml version="1.0" encoding="utf-8"?>
<?qbxml version="16.0"?>
<QBXML>
<QBXMLMsgsRq onError="stopOnError">
<SalesOrderQueryRq metaData="ENUMTYPE" iterator="ENUMTYPE" iteratorID="UUIDTYPE">
<!-- BEGIN OR -->
<TxnID >IDTYPE</TxnID> <!-- optional, may repeat -->
<!-- OR -->
<RefNumber >STRTYPE</RefNumber> <!-- optional, may repeat -->
<!-- OR -->
<RefNumberCaseSensitive >STRTYPE</RefNumberCaseSensitive> <!-- optional, may repeat -->
<!-- OR -->
<MaxReturned >INTTYPE</MaxReturned> <!-- optional -->
<!-- BEGIN OR -->
<ModifiedDateRangeFilter> <!-- optional -->
<FromModifiedDate >DATETIMETYPE</FromModifiedDate> <!-- optional -->
<ToModifiedDate >DATETIMETYPE</ToModifiedDate> <!-- optional -->
</ModifiedDateRangeFilter>
<!-- OR -->
<TxnDateRangeFilter> <!-- optional -->
<!-- BEGIN OR -->
<FromTxnDate >DATETYPE</FromTxnDate> <!-- optional -->
<ToTxnDate >DATETYPE</ToTxnDate> <!-- optional -->
<!-- OR -->
<!-- DateMacro may have one of the following values: All, Today, ThisWeek, ThisWeekToDate, ThisMonth, ThisMonthToDate, ThisCalendarQuarter, ThisCalendarQuarterToDate, ThisFiscalQuarter, ThisFiscalQuarterToDate, ThisCalendarYear, ThisCalendarYearToDate, ThisFiscalYear, ThisFiscalYearToDate, Yesterday, LastWeek, LastWeekToDate, LastMonth, LastMonthToDate, LastCalendarQuarter, LastCalendarQuarterToDate, LastFiscalQuarter, LastFiscalQuarterToDate, LastCalendarYear, LastCalendarYearToDate, LastFiscalYear, LastFiscalYearToDate, NextWeek, NextFourWeeks, NextMonth, NextCalendarQuarter, NextCalendarYear, NextFiscalQuarter, NextFiscalYear -->
<DateMacro >ENUMTYPE</DateMacro> <!-- optional -->
<!-- END OR -->
</TxnDateRangeFilter>
<!-- END OR -->
<EntityFilter> <!-- optional -->
<!-- BEGIN OR -->
<ListID >IDTYPE</ListID> <!-- optional, may repeat -->
<!-- OR -->
<FullName >STRTYPE</FullName> <!-- optional, may repeat -->
<!-- OR -->
<ListIDWithChildren >IDTYPE</ListIDWithChildren> <!-- optional -->
<!-- OR -->
<FullNameWithChildren >STRTYPE</FullNameWithChildren> <!-- optional -->
<!-- END OR -->
</EntityFilter>
<!-- BEGIN OR -->
<RefNumberFilter> <!-- optional -->
<!-- MatchCriterion may have one of the following values: StartsWith, Contains, EndsWith -->
<MatchCriterion >ENUMTYPE</MatchCriterion> <!-- required -->
<RefNumber >STRTYPE</RefNumber> <!-- required -->
</RefNumberFilter>
<!-- OR -->
<RefNumberRangeFilter> <!-- optional -->
<FromRefNumber >STRTYPE</FromRefNumber> <!-- optional -->
<ToRefNumber >STRTYPE</ToRefNumber> <!-- optional -->
</RefNumberRangeFilter>
<!-- END OR -->
<CurrencyFilter> <!-- optional -->
<!-- BEGIN OR -->
<ListID >IDTYPE</ListID> <!-- optional, may repeat -->
<!-- OR -->
<FullName >STRTYPE</FullName> <!-- optional, may repeat -->
<!-- END OR -->
</CurrencyFilter>
<!-- END OR -->
<IncludeLineItems >BOOLTYPE</IncludeLineItems> <!-- optional -->
<IncludeLinkedTxns >BOOLTYPE</IncludeLinkedTxns> <!-- optional -->
<IncludeRetElement >STRTYPE</IncludeRetElement> <!-- optional, may repeat -->
<OwnerID >GUIDTYPE</OwnerID> <!-- optional, may repeat -->
</SalesOrderQueryRq>
<SalesOrderQueryRs statusCode="INTTYPE" statusSeverity="STRTYPE" statusMessage="STRTYPE" retCount="INTTYPE" iteratorRemainingCount="INTTYPE" iteratorID="UUIDTYPE">
<SalesOrderRet> <!-- optional, may repeat -->
<TxnID >IDTYPE</TxnID> <!-- required -->
<TimeCreated >DATETIMETYPE</TimeCreated> <!-- required -->
<TimeModified >DATETIMETYPE</TimeModified> <!-- required -->
<EditSequence >STRTYPE</EditSequence> <!-- required -->
<TxnNumber >INTTYPE</TxnNumber> <!-- optional -->
<CustomerRef> <!-- required -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</CustomerRef>
<ClassRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</ClassRef>
<TemplateRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</TemplateRef>
<TxnDate >DATETYPE</TxnDate> <!-- required -->
<RefNumber >STRTYPE</RefNumber> <!-- optional -->
<BillAddress> <!-- optional -->
<Addr1 >STRTYPE</Addr1> <!-- optional -->
<Addr2 >STRTYPE</Addr2> <!-- optional -->
<Addr3 >STRTYPE</Addr3> <!-- optional -->
<Addr4 >STRTYPE</Addr4> <!-- optional -->
<Addr5 >STRTYPE</Addr5> <!-- optional -->
<City >STRTYPE</City> <!-- optional -->
<State >STRTYPE</State> <!-- optional -->
<PostalCode >STRTYPE</PostalCode> <!-- optional -->
<Country >STRTYPE</Country> <!-- optional -->
<Note >STRTYPE</Note> <!-- optional -->
</BillAddress>
<BillAddressBlock> <!-- optional -->
<Addr1 >STRTYPE</Addr1> <!-- optional -->
<Addr2 >STRTYPE</Addr2> <!-- optional -->
<Addr3 >STRTYPE</Addr3> <!-- optional -->
<Addr4 >STRTYPE</Addr4> <!-- optional -->
<Addr5 >STRTYPE</Addr5> <!-- optional -->
</BillAddressBlock>
<ShipAddress> <!-- optional -->
<Addr1 >STRTYPE</Addr1> <!-- optional -->
<Addr2 >STRTYPE</Addr2> <!-- optional -->
<Addr3 >STRTYPE</Addr3> <!-- optional -->
<Addr4 >STRTYPE</Addr4> <!-- optional -->
<Addr5 >STRTYPE</Addr5> <!-- optional -->
<City >STRTYPE</City> <!-- optional -->
<State >STRTYPE</State> <!-- optional -->
<PostalCode >STRTYPE</PostalCode> <!-- optional -->
<Country >STRTYPE</Country> <!-- optional -->
<Note >STRTYPE</Note> <!-- optional -->
</ShipAddress>
<ShipAddressBlock> <!-- optional -->
<Addr1 >STRTYPE</Addr1> <!-- optional -->
<Addr2 >STRTYPE</Addr2> <!-- optional -->
<Addr3 >STRTYPE</Addr3> <!-- optional -->
<Addr4 >STRTYPE</Addr4> <!-- optional -->
<Addr5 >STRTYPE</Addr5> <!-- optional -->
</ShipAddressBlock>
<PONumber >STRTYPE</PONumber> <!-- optional -->
<TermsRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</TermsRef>
<DueDate >DATETYPE</DueDate> <!-- optional -->
<SalesRepRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</SalesRepRef>
<FOB >STRTYPE</FOB> <!-- optional -->
<ShipDate >DATETYPE</ShipDate> <!-- optional -->
<ShipMethodRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</ShipMethodRef>
<Subtotal >AMTTYPE</Subtotal> <!-- optional -->
<ItemSalesTaxRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</ItemSalesTaxRef>
<SalesTaxPercentage >PERCENTTYPE</SalesTaxPercentage> <!-- optional -->
<SalesTaxTotal >AMTTYPE</SalesTaxTotal> <!-- optional -->
<TotalAmount >AMTTYPE</TotalAmount> <!-- optional -->
<CurrencyRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</CurrencyRef>
<ExchangeRate >FLOATTYPE</ExchangeRate> <!-- optional -->
<TotalAmountInHomeCurrency >AMTTYPE</TotalAmountInHomeCurrency> <!-- optional -->
<IsManuallyClosed >BOOLTYPE</IsManuallyClosed> <!-- optional -->
<IsFullyInvoiced >BOOLTYPE</IsFullyInvoiced> <!-- optional -->
<Memo >STRTYPE</Memo> <!-- optional -->
<CustomerMsgRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</CustomerMsgRef>
<IsToBePrinted >BOOLTYPE</IsToBePrinted> <!-- optional -->
<IsToBeEmailed >BOOLTYPE</IsToBeEmailed> <!-- optional -->
<IsTaxIncluded >BOOLTYPE</IsTaxIncluded> <!-- optional -->
<CustomerSalesTaxCodeRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</CustomerSalesTaxCodeRef>
<Other >STRTYPE</Other> <!-- optional -->
<ExternalGUID >GUIDTYPE</ExternalGUID> <!-- optional -->
<LinkedTxn> <!-- optional, may repeat -->
<TxnID >IDTYPE</TxnID> <!-- required -->
<!-- TxnType may have one of the following values: ARRefundCreditCard, Bill, BillPaymentCheck, BillPaymentCreditCard, BuildAssembly, Charge, Check, CreditCardCharge, CreditCardCredit, CreditMemo, Deposit, Estimate, InventoryAdjustment, Invoice, ItemReceipt, JournalEntry, LiabilityAdjustment, Paycheck, PayrollLiabilityCheck, PurchaseOrder, ReceivePayment, SalesOrder, SalesReceipt, SalesTaxPaymentCheck, Transfer, VendorCredit, YTDAdjustment -->
<TxnType >ENUMTYPE</TxnType> <!-- required -->
<TxnDate >DATETYPE</TxnDate> <!-- required -->
<RefNumber >STRTYPE</RefNumber> <!-- optional -->
<!-- LinkType may have one of the following values: AMTTYPE, QUANTYPE -->
<LinkType >ENUMTYPE</LinkType> <!-- optional -->
<Amount >AMTTYPE</Amount> <!-- required -->
</LinkedTxn>
<!-- BEGIN OR -->
<SalesOrderLineRet> <!-- optional -->
<TxnLineID >IDTYPE</TxnLineID> <!-- required -->
<ItemRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</ItemRef>
<Desc >STRTYPE</Desc> <!-- optional -->
<Quantity >QUANTYPE</Quantity> <!-- optional -->
<UnitOfMeasure >STRTYPE</UnitOfMeasure> <!-- optional -->
<OverrideUOMSetRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</OverrideUOMSetRef>
<!-- BEGIN OR -->
<Rate >PRICETYPE</Rate> <!-- optional -->
<!-- OR -->
<RatePercent >PERCENTTYPE</RatePercent> <!-- optional -->
<!-- END OR -->
<ClassRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</ClassRef>
<Amount >AMTTYPE</Amount> <!-- optional -->
<InventorySiteRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</InventorySiteRef>
<InventorySiteLocationRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</InventorySiteLocationRef>
<!-- BEGIN OR -->
<SerialNumber >STRTYPE</SerialNumber> <!-- optional -->
<!-- OR -->
<LotNumber >STRTYPE</LotNumber> <!-- optional -->
<!-- END OR -->
<ExpirationDateForSerialLotNumber>STRTYPE</ExpirationDateForSerialLotNumber> <!-- optional -->
<SalesTaxCodeRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</SalesTaxCodeRef>
<Invoiced >QUANTYPE</Invoiced> <!-- optional -->
<IsManuallyClosed >BOOLTYPE</IsManuallyClosed> <!-- optional -->
<Other1 >STRTYPE</Other1> <!-- optional -->
<Other2 >STRTYPE</Other2> <!-- optional -->
<DataExtRet> <!-- optional, may repeat -->
<OwnerID >GUIDTYPE</OwnerID> <!-- optional -->
<DataExtName >STRTYPE</DataExtName> <!-- required -->
<!-- DataExtType may have one of the following values: AMTTYPE, DATETIMETYPE, INTTYPE, PERCENTTYPE, PRICETYPE, QUANTYPE, STR1024TYPE, STR255TYPE -->
<DataExtType >ENUMTYPE</DataExtType> <!-- required -->
<DataExtValue >STRTYPE</DataExtValue> <!-- required -->
</DataExtRet>
</SalesOrderLineRet>
<!-- OR -->
<SalesOrderLineGroupRet> <!-- optional -->
<TxnLineID >IDTYPE</TxnLineID> <!-- required -->
<ItemGroupRef> <!-- required -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</ItemGroupRef>
<Desc >STRTYPE</Desc> <!-- optional -->
<Quantity >QUANTYPE</Quantity> <!-- optional -->
<UnitOfMeasure >STRTYPE</UnitOfMeasure> <!-- optional -->
<OverrideUOMSetRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</OverrideUOMSetRef>
<IsPrintItemsInGroup >BOOLTYPE</IsPrintItemsInGroup> <!-- required -->
<TotalAmount >AMTTYPE</TotalAmount> <!-- required -->
<SalesOrderLineRet> <!-- optional, may repeat -->
<TxnLineID >IDTYPE</TxnLineID> <!-- required -->
<ItemRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</ItemRef>
<Desc >STRTYPE</Desc> <!-- optional -->
<Quantity >QUANTYPE</Quantity> <!-- optional -->
<UnitOfMeasure >STRTYPE</UnitOfMeasure> <!-- optional -->
<OverrideUOMSetRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</OverrideUOMSetRef>
<!-- BEGIN OR -->
<Rate >PRICETYPE</Rate> <!-- optional -->
<!-- OR -->
<RatePercent >PERCENTTYPE</RatePercent> <!-- optional -->
<!-- END OR -->
<ClassRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</ClassRef>
<Amount >AMTTYPE</Amount> <!-- optional -->
<InventorySiteRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</InventorySiteRef>
<InventorySiteLocationRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</InventorySiteLocationRef>
<!-- BEGIN OR -->
<SerialNumber >STRTYPE</SerialNumber> <!-- optional -->
<!-- OR -->
<LotNumber >STRTYPE</LotNumber> <!-- optional -->
<!-- END OR -->
<ExpirationDateForSerialLotNumber>STRTYPE</ExpirationDateForSerialLotNumber> <!-- optional -->
<SalesTaxCodeRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</SalesTaxCodeRef>
<Invoiced >QUANTYPE</Invoiced> <!-- optional -->
<IsManuallyClosed >BOOLTYPE</IsManuallyClosed> <!-- optional -->
<Other1 >STRTYPE</Other1> <!-- optional -->
<Other2 >STRTYPE</Other2> <!-- optional -->
<DataExtRet> <!-- optional, may repeat -->
<OwnerID >GUIDTYPE</OwnerID> <!-- optional -->
<DataExtName >STRTYPE</DataExtName> <!-- required -->
<!-- DataExtType may have one of the following values: AMTTYPE, DATETIMETYPE, INTTYPE, PERCENTTYPE, PRICETYPE, QUANTYPE, STR1024TYPE, STR255TYPE -->
<DataExtType >ENUMTYPE</DataExtType> <!-- required -->
<DataExtValue >STRTYPE</DataExtValue> <!-- required -->
</DataExtRet>
</SalesOrderLineRet>
<DataExtRet> <!-- optional, may repeat -->
<OwnerID >GUIDTYPE</OwnerID> <!-- optional -->
<DataExtName >STRTYPE</DataExtName> <!-- required -->
<!-- DataExtType may have one of the following values: AMTTYPE, DATETIMETYPE, INTTYPE, PERCENTTYPE, PRICETYPE, QUANTYPE, STR1024TYPE, STR255TYPE -->
<DataExtType >ENUMTYPE</DataExtType> <!-- required -->
<DataExtValue >STRTYPE</DataExtValue> <!-- required -->
</DataExtRet>
</SalesOrderLineGroupRet>
<!-- END OR -->
<DataExtRet> <!-- optional, may repeat -->
<OwnerID >GUIDTYPE</OwnerID> <!-- optional -->
<DataExtName >STRTYPE</DataExtName> <!-- required -->
<!-- DataExtType may have one of the following values: AMTTYPE, DATETIMETYPE, INTTYPE, PERCENTTYPE, PRICETYPE, QUANTYPE, STR1024TYPE, STR255TYPE -->
<DataExtType >ENUMTYPE</DataExtType> <!-- required -->
<DataExtValue >STRTYPE</DataExtValue> <!-- required -->
</DataExtRet>
<FulfillmentStatus>ENUMTYPE</FulfillmentStatus> <!-- optional -->
<ShippingDetails> <!-- optional -->
<ShippingDetailsLineRet> <!-- optional -->
<TrackingID>IDTYPE</TrackingID> <!-- optional -->
<CarrierName>STRTYPE</CarrierName> <!-- optional -->
<ShippingMethod>STRTYPE</ShippingMethod> <!-- optional -->
<ShippingCharges>AMTTYPE</ShippingCharges> <!-- optional -->
</ShippingDetailsLineRet>
</ShippingDetails>
<SOChannel>ENUMTYPE</SOChannel> <!-- optional -->
<StoreName>STRTYPE</StoreName> <!-- optional -->
<StoreType>STRTYPE</StoreType> <!-- optional -->
</SalesOrderRet>
</SalesOrderQueryRs>
</QBXMLMsgsRq>
</QBXML>

0
SO_to_Inv/__init__.py Normal file
View File

417
SO_to_Inv/invoiceadd.py Normal file
View File

@ -0,0 +1,417 @@
import xml.etree.ElementTree as ET
import win32com.client
import xmltodict
import pprint
import datetime
import pandas as pd
from datetime import date
import timeit
class SalesOrderQuery:
def __init__(self, **kwargs) -> None:
# print(f'kwargs:{kwargs}')
# print(args)
# self.SalesOrderList=[]
self.DN = kwargs['DN'] if 'DN' in kwargs else {}
self.Reuse = kwargs['Reuse'] if 'Reuse' in kwargs else None
self.SalesOrderList= kwargs['SalesOrderList'] if 'SalesOrderList' in kwargs else []
self.SalesOrderType = kwargs['SalesOrderType'] if 'SalesOrderType' in kwargs else 'SalesByCustomerSummary'
self.IncludeLineItems = kwargs['IncludeLineItems'] if 'IncludeLineItems' in kwargs else 'true'
self.IncludeRetElement = kwargs['IncludeRetElement'] if 'IncludeRetElement' in kwargs else []
self.TxnDateRangeFilter = kwargs['TxnDateRangeFilter'] if 'TxnDateRangeFilter' in kwargs else None
self.DateMacro = None
if 'DateMacro' in kwargs:
if kwargs['DateMacro'] in ['All', 'Today', 'ThisWeek', 'ThisWeekToDate', 'ThisMonth', 'ThisMonthToDate', 'ThisQuarter', 'ThisQuarterToDate', 'ThisYear', 'ThisYearToDate', 'Yesterday', 'LastWeek', 'LastWeekToDate', 'LastMonth', 'LastMonthToDate', 'LastQuarter', 'LastQuarterToDate', 'LastYear', 'LastYearToDate', 'NextWeek', 'NextFourWeeks', 'NextMonth', 'NextQuarter', 'NextYear']:
self.DateMacro = kwargs['DateMacro']
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.TxnDateRangeFilter, self.FromTxnDate, self.ToTxnDate)
# 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.get_sales_order_header()
def create_sub_element(self, ET, parentNode, thisNode, text="\n", whiteSpace = 0, attrib =None):
if type(attrib) is not dict:
attrib = {}
ele = ET.SubElement(parentNode, thisNode)
for x in attrib:
ele.set(x, attrib[x])
ele.text = text
tail = "\n"
for x in range(whiteSpace):
tail = tail + " "
ele.tail = tail
return ele
def create_QBXML(self):
root = ET.Element("QBXML")
root.tail = "\n"
root.text = "\n "
QBXMLMsgsRq = ET.SubElement(root, "QBXMLMsgsRq")
# QBXMLMsgsRq.set("onError", "continueOnError")
QBXMLMsgsRq.set("onError", "stopOnError")
QBXMLMsgsRq.tail = "\n"
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)
# print(f'refnumber:{self.RefNumber}')
# if self.RefNumber:
# for rn in self.RefNumber:
# RefNumber = self.create_sub_element(ET, SalesOrderQueryRq, "RefNumber", f'{rn}', 4)
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)
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:
for x in self.IncludeRetElement:
IncludeRetElement = self.create_sub_element(ET, SalesOrderQueryRq, "IncludeRetElement", x, 4)
mydata = ET.tostring(root, encoding = "unicode")
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(f'create_QBXML->qbxml_query: {qbxml_query}')
return qbxml_query
def create_invoiceadd_QBXML(self):
root = ET.Element("QBXML")
root.tail = "\n"
root.text = "\n "
QBXMLMsgsRq = ET.SubElement(root, "QBXMLMsgsRq")
QBXMLMsgsRq.set("onError", "stopOnError")
QBXMLMsgsRq.tail = "\n"
QBXMLMsgsRq.text = "\n "
InvoiceAddRq = self.create_sub_element(ET, QBXMLMsgsRq, "InvoiceAddRq", "\n ",2 )
InvoiceAdd = self.create_sub_element(ET, InvoiceAddRq, "InvoiceAdd", "\n ",4 )
CustomerRef = self.create_sub_element(ET, InvoiceAdd, "CustomerRef", "\n ",8 )
FullName = self.create_sub_element(ET, CustomerRef, "FullName", "TACO", 8 )
today = str(date.today())
TxnDate = self.create_sub_element(ET, InvoiceAdd, "TxnDate", self.DN['TxnDate'], 8 )
RefNumber = self.create_sub_element(ET, InvoiceAdd, "RefNumber", self.DN['DNRefNum'], 8 )
Memo = self.create_sub_element(ET, InvoiceAdd, "Memo", self.DN['Memo'], 10 )
for salesorder in self.SalesOrderList:
POTxnId = salesorder['TxnID']
print(f'create_invoiceadd_QBXML->POTxnID: {POTxnId}')
for itemline in salesorder['SalesOrderLineRet']:
if 'DNQuantity' in itemline:
ItemLineAdd = self.create_sub_element(ET, InvoiceAdd, "ItemLineAdd", "\n ", 10 )
Quantity = self.create_sub_element(ET, ItemLineAdd, "Quantity", str(itemline['DNQuantity'] ), 12 )
UnitOfMeasure = self.create_sub_element(ET, ItemLineAdd, "UnitOfMeasure", str(itemline['UOM']), 12 )
LinkToTxn = self.create_sub_element(ET, ItemLineAdd, "LinkToTxn", "\n ",10 )
TxnID = self.create_sub_element(ET, LinkToTxn, "TxnID", POTxnId,14 )
TxnLineID = self.create_sub_element(ET, LinkToTxn, "TxnLineID", itemline['TxnLineID'],12 )
mydata = ET.tostring(root, encoding = "unicode")
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(f'create_invoiceadd_QBXML->Create_Invoiceadd_QBXML: {qbxml_query}')
# print(f"replyfrom qbxml:{self.connect_to_quickbooks(qbxml_query)}")
return qbxml_query
def connect_to_quickbooks(self, qbxml_query):
# Connect to Quickbooks
# sessionManager = win32com.client.Dispatch("QBXMLRP2.RequestProcessor")
# sessionManager.OpenConnection('', 'DASA')
# enumfodnc= win32com.client.Dispatch('QBXMLRP2.RequestProcessor')
# print(enumfodnc)
# print(enumfodnc.qbFileOpenDoNotCare)
sessionManager = win32com.client.Dispatch("QBXMLRP2.RequestProcessor")
sessionManager.OpenConnection('', 'DASA2')
# ticket = sessionManager.BeginSession("z:\\DBW Bogor.qbw", 2)
ticket = sessionManager.BeginSession("", 2)
# Send query and receive response
response_string = sessionManager.ProcessRequest(ticket, qbxml_query)
# Disconnect from Quickbooks
sessionManager.EndSession(ticket) # Close the company file
sessionManager.CloseConnection() # Close the connection
print (response_string)
return response_string
def __str__(self, *args) -> str:
# return str(self._get_datarow(self.connect_to_quickbooks(self.create_QBXML())))
# print("__str__")
return str(self.get_sales_order_header())
# return "hello"
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)
GSRQRs = tree.find(".//InvoiceAddRs")
# print(f"GSRQRs:{GSRQRs}")
status_code = GSRQRs.attrib #.get('statusCode')
# print(GSRQRs.attrib)
# print(GSRQRs.attrib['statusCode'])
status=GSRQRs.attrib.get('statusMessage')
print(f'status={status}')
if 'OK' in status:
return True, status_code
else:
return False, status_code
def _get_sales_order_header(self, response_string):
print('_get_sales_order_header')
# print(f'responsestring:{response_string}')
QBXML = ET.fromstring(response_string)
datadict = {}
SalesOrderdict = {}
_SalesOrderlist = []
SalesOrderRets = QBXML.findall('.//SalesOrderRet')
print(SalesOrderRets)
for SalesOrderRet in SalesOrderRets:
RefNumber = SalesOrderRet.find('RefNumber').text
# Memo = SalesOrderRet.find('Memo').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
# print(CustomerFullName, TxnID, TotalAmount)
SalesOrderdict = {'RefNumber':RefNumber, 'CustomerFullName':CustomerFullName, 'TxnID':TxnID,
'TotalAmount':TotalAmount, 'IsFullyInvoiced':IsFullyInvoiced, 'IsManuallyClosed':IsManuallyClosed, 'SalesOrderLineRet':[]}
SalesOrderLineRet = SalesOrderRet.findall('SalesOrderLineRet')
# print(len(SalesOrderLineRet))
if len(SalesOrderLineRet) > 0:
for SalesOrderLineRet in SalesOrderLineRet:
pass
TxnLineID = SalesOrderLineRet.find('TxnLineID').text
ItemFullName = SalesOrderLineRet.find('ItemRef/FullName').text
Quantity = SalesOrderLineRet.find('Quantity').text
UnitOfMeasure = SalesOrderLineRet.find('UnitOfMeasure').text
Rate = float(SalesOrderLineRet.find('Rate').text)
Amount = float(SalesOrderLineRet.find('Amount').text)
Invoiced = SalesOrderLineRet.find('Invoiced').text
# IsBilled = SalesOrderLineRet.find('IsBilled').text
LineIsManuallyClosed = SalesOrderLineRet.find('IsManuallyClosed').text
# print(TxnLineID, ItemFullName)
BackOrdered = float(Quantity) - float(Invoiced)
if BackOrdered:
SalesOrderLinedict = {'TxnLineID':TxnLineID,
'ItemFullName':ItemFullName,
'Quantity':Quantity,
'UOM':UnitOfMeasure,
'Rate':Rate,
'Amount':Amount,
'BackOrdered':BackOrdered,
'Invoiced':Invoiced,
# 'IsBilled':IsBilled,
'LineIsManuallyClosed':LineIsManuallyClosed,
}
SalesOrderdict['SalesOrderLineRet'].append(SalesOrderLinedict)
_SalesOrderlist.append(SalesOrderdict)
# print(_SalesOrderlist)
self.SalesOrderList=_SalesOrderlist
print(f'_get_sales_order_header->Salesorderlist: {self.SalesOrderList}')
# return SalesOrderlist
def addDNQtyToSalesOrderList(self, _dict:dict):
_bolfoundrefnum=False
_bol_dictisadded=False
Error_msg = None
for poidx, _po in enumerate(self.SalesOrderList):
if _po['RefNumber']==_dict['RefNum']:
_bolfoundrefnum=True
if len(_po['SalesOrderLineRet'])>0:
for polineidx, _poline in enumerate(_po['SalesOrderLineRet']):
pass
if _poline['ItemFullName']==_dict['FullName']:
if _poline['UOM'].upper()==_dict['UOM'].upper():
# first do UOM in _dict convert treatment
QuantityIn_dict = _dict['Quantity']
if _dict['UOM'].upper().startswith('ROLL_'):
print(f"addDNQtyToSalesOrderList->DNqty:{_dict['Quantity']}, Roll_:{_dict['UOM'].split('_')[1]}")
QuantityIn_dict = _dict['Quantity'] * int(_dict['UOM'].split("_")[1])
pass
elif _dict['UOM'].upper() == 'BOX' and _dict['Item No'].upper() == "CUTTER":
print("addDNQtyToSalesOrderList->cutter")
elif _dict['UOM'].upper() == 'BOX' and (_dict['Item No'].upper().startswith("EB-") or _dict['Item No'].upper().startswith("TA-")):
print("addDNQtyToSalesOrderList->LEM")
if _dict['Item No'].split("-")[1].endswith("1006"):
QuantityIn_dict = QuantityIn_dict * 12
elif _dict['Item No'].split("-")[1].endswith("1025"):
QuantityIn_dict = QuantityIn_dict * 6
elif _dict['Item No'].split("-")[1].endswith("1100"):
pass
print("1100 lem")
elif _dict['UOM'].upper() == 'BOX' and (_dict['Item No'].upper().startswith("TL-") or _dict['Item No'].upper().startswith("TFL-")):
print("addDNQtyToSalesOrderList->Lock")
QuantityIn_dict = QuantityIn_dict * 20
elif _dict['UOM'].upper() == 'BOX' and _dict['Item No'].upper() == "EDG-TRIMMER":
QuantityIn_dict = QuantityIn_dict * 12 #coz box of 12
if _poline['BackOrdered']>=QuantityIn_dict:
self.SalesOrderList[poidx]['SalesOrderLineRet'][polineidx]['DNQuantity']=float(QuantityIn_dict)
_bol_dictisadded = True
else:
print(f"{_poline['ItemFullName']} BackOrdered < Qty in DN {_poline['BackOrdered']}<{QuantityIn_dict}")
Error_msg = f"BackOrdered < Qty in DN {_poline['BackOrdered']}<{QuantityIn_dict}"
else:
# print(f"UOM different {_poline['UOM']} <> {_dict['UOM']}")
Error_msg = f"UOM different {_poline['UOM']} <> {_dict['UOM']}"
else:
# print("errorpoline <>DN")
Error_msg = f"poline[ItemFullName] <> DN[FullName]; {_poline['ItemFullName']} <> {_dict['FullName']}, maybe there are 2 same namefromtaco in QB"
else:
pass
# print(f"this refnum {_dict['RefNum']} have no QB PO Return Line")
Error_msg = f"this refnum {_dict['RefNum']} have no QB PO Return Line"
# print (_bol_dictisadded, Error_msg)
return _bol_dictisadded, Error_msg
def prepareInvoice(self, df:pd.DataFrame = None):
# print(df)
_bolAllDNareOk = True
_notindflist=[]
_yescounter = 0
_nocounter = 0
if df is not None:
_dflist = df.to_dict('records')
# print(_dflist)
else:
_dflist = self.dfDN.to_dict('records')
# print(self.dfDN)
# print(f'_dflist:{_dflist}')
for idx, xdf in enumerate(_dflist):
_boladdDN, _Errormsg = self.addDNQtyToSalesOrderList(xdf)
# print(f'prepareInvoice->_Errormsg:{_Errormsg}')
if _boladdDN:
_dflist[idx]['ADDED']=True
elif _Errormsg:
_dflist[idx]['ERROR']=_Errormsg
for xdf in (_dflist):
if 'ADDED' not in xdf:
# print (f"prepareInvoice->not added: {xdf['Item No']}")
print (f"prepareInvoice->not added: {xdf}")
_notindflist.append(xdf)
_nocounter+=1
_bolAllDNareOk = False
else:
print (f"ADDED: {xdf['Item No']}")
print(f'{len(_dflist) - _nocounter} of {len(_dflist)} are added')
return _bolAllDNareOk, _notindflist
def validate_date(self, date_text):
if date_text is None:
return None
try:
return datetime.datetime.strptime(date_text, '%Y-%m-%d').date()
except ValueError:
return None
# raise ValueError("Incorrect data format, should be YYYY-MM-DD")
def get_ext_doc_no_list(self, dndict=None):
if dndict:
dnlist = dndict['lines']
else:
dnlist = self.DN
df = pd.DataFrame(dnlist)
# print(df)
df['RefNum']= df['No.SO/Ext.Doc.No.'].apply(lambda x: "L"+ x.split("L-")[1])
# print(df)
ext_doc_no=df['RefNum'].unique().tolist()
if len(ext_doc_no)>0:
return df, ext_doc_no
else:
return df, None
def get_open_so(self, response_string):
QBXML = ET.fromstring(response_string)
_OpenSalesOrderlist = []
SalesOrderRets = QBXML.findall('.//SalesOrderRet')
# print(f'SalesOrderRets count:{len(SalesOrderRets)}')
for SalesOrderRet in SalesOrderRets:
IsFullyInvoiced = SalesOrderRet.find('IsFullyInvoiced').text
IsManuallyClosed = SalesOrderRet.find('IsManuallyClosed').text
if IsFullyInvoiced=='false' and IsManuallyClosed=='false':
_OpenSalesOrderlist.append(SalesOrderRet.find('TxnID').text)
# RefNumber = SalesOrderRet.find('RefNumber').text
# Memo = SalesOrderRet.find('Memo').text
# CustomerFullName = SalesOrderRet.find('CustomerRef/FullName').text
# TxnID = SalesOrderRet.find('TxnID').text
# TotalAmount = SalesOrderRet.find('TotalAmount').text
# IsFullyReceived = SalesOrderRet.find('IsFullyReceived').text
# IsManuallyClosed = SalesOrderRet.find('IsManuallyClosed').text
# print(_OpenSalesOrderlist)
return _OpenSalesOrderlist
def create_open_sales_order_qbxml(self, txnid:list, IncludeLineItems=True):
root = ET.Element("QBXML")
root.tail = "\n"
root.text = "\n "
QBXMLMsgsRq = ET.SubElement(root, "QBXMLMsgsRq")
# QBXMLMsgsRq.set("onError", "continueOnError")
QBXMLMsgsRq.set("onError", "stopOnError")
QBXMLMsgsRq.tail = "\n"
QBXMLMsgsRq.text = "\n "
SalesOrderQueryRq = self.create_sub_element(ET, QBXMLMsgsRq, "SalesOrderQueryRq","\n " )
if len(txnid)>0:
for x in txnid:
TxnID = self.create_sub_element(ET, SalesOrderQueryRq, "TxnID", x, 6 )
else:
return None
if IncludeLineItems:
IncludeLineItems = self.create_sub_element(ET, SalesOrderQueryRq, "IncludeLineItems", 'true', 4)
# if len(self.IncludeRetElement)>0:
# for x in self.IncludeRetElement:
# IncludeRetElement = self.create_sub_element(ET, SalesOrderQueryRq, "IncludeRetElement", x, 4)
mydata = ET.tostring(root, encoding = "unicode")
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(f'create_QBXML->qbxml_query: {qbxml_query}')
return qbxml_query
def get_open_sales_order(self, txnid:list):
print(txnid, type(txnid))
print(self.connect_to_quickbooks(self.create_open_sales_order_qbxml(txnid)))
self._get_sales_order_header(self.connect_to_quickbooks(self.create_open_sales_order_qbxml(txnid)))
print('### SalesOrder ###')
if __name__ == '__main__':
starttime = timeit.default_timer()
ini=SalesOrderQuery(FullName= '999 HPL', IncludeRetElement = ['TxnID', 'TimeCreated', 'TimeModified','TxnNumber', 'CustomerRef', 'IsManuallyClosed', 'IsFullyInvoiced'])
print(ini.create_QBXML())
response_string = ini.connect_to_quickbooks(ini.create_QBXML())
open_sales_orders = ini.get_open_so(response_string)
print(open_sales_orders)
print(ini.get_open_sales_order(open_sales_orders))
print("The time difference is :", timeit.default_timer() - starttime)

544
SO_to_Inv/readSO.py Normal file
View File

@ -0,0 +1,544 @@
import xml.etree.ElementTree as ET
import win32com.client
import xmltodict
import pprint
import datetime
import pandas as pd
from datetime import date
import timeit
import os
class SalesOrderQuery:
def __init__(self, **kwargs) -> None:
# print(f'kwargs:{kwargs}')
# print(args)
# self.SalesOrderList=[]
self.PriceLevelName = None
self.SPPriceLevelName = None
self.cwd = kwargs['cwd'] if 'cwd' in kwargs else os.getcwd()
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]))
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.DN = kwargs['DN'] if 'DN' in kwargs else {}
self.Reuse = kwargs['Reuse'] if 'Reuse' in kwargs else None
self.SalesOrderList= kwargs['SalesOrderList'] if 'SalesOrderList' in kwargs else []
self.InvoiceList = None
self.SalesOrderType = kwargs['SalesOrderType'] if 'SalesOrderType' in kwargs else 'SalesByCustomerSummary'
self.IncludeLineItems = kwargs['IncludeLineItems'] if 'IncludeLineItems' in kwargs else 'true'
self.IncludeRetElement = kwargs['IncludeRetElement'] if 'IncludeRetElement' in kwargs else []
self.TxnDateRangeFilter = kwargs['TxnDateRangeFilter'] if 'TxnDateRangeFilter' in kwargs else None
self.DateMacro = None
if 'DateMacro' in kwargs:
if kwargs['DateMacro'] in ['All', 'Today', 'ThisWeek', 'ThisWeekToDate', 'ThisMonth', 'ThisMonthToDate', 'ThisQuarter', 'ThisQuarterToDate', 'ThisYear', 'ThisYearToDate', 'Yesterday', 'LastWeek', 'LastWeekToDate', 'LastMonth', 'LastMonthToDate', 'LastQuarter', 'LastQuarterToDate', 'LastYear', 'LastYearToDate', 'NextWeek', 'NextFourWeeks', 'NextMonth', 'NextQuarter', 'NextYear']:
self.DateMacro = kwargs['DateMacro']
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
# print(self.DateMacro, self.TxnDateRangeFilter, self.FromTxnDate, self.ToTxnDate)
# 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.get_sales_order_header()
def create_sub_element(self, ET, parentNode, thisNode, text="\n", whiteSpace = 0, attrib =None):
if type(attrib) is not dict:
attrib = {}
ele = ET.SubElement(parentNode, thisNode)
for x in attrib:
ele.set(x, attrib[x])
ele.text = text
tail = "\n"
for x in range(whiteSpace):
tail = tail + " "
ele.tail = tail
return ele
def create_QBXML(self):
root = ET.Element("QBXML")
root.tail = "\n"
root.text = "\n "
QBXMLMsgsRq = ET.SubElement(root, "QBXMLMsgsRq")
# QBXMLMsgsRq.set("onError", "continueOnError")
QBXMLMsgsRq.set("onError", "stopOnError")
QBXMLMsgsRq.tail = "\n"
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)
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:
for x in self.IncludeRetElement:
IncludeRetElement = self.create_sub_element(ET, SalesOrderQueryRq, "IncludeRetElement", x, 4)
mydata = ET.tostring(root, encoding = "unicode")
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(f'create_QBXML->qbxml_query: {qbxml_query}')
return qbxml_query
def get_customer_pricelevel(self, response_string):
QBXML = ET.fromstring(response_string)
PriceLevelName = QBXML.find('.//PriceLevelRef')
if PriceLevelName:
PriceLevelName = PriceLevelName.find("FullName").text
print(f'PriceLevelName:{PriceLevelName}')
DataExtRets = QBXML.findall('.//DataExtRet')
SP_PriceLevelName = None
if len(DataExtRets)>0:
for DataExtRet in DataExtRets:
DataExtName = DataExtRet.find('DataExtName').text
DataExtValue = DataExtRet.find('DataExtValue').text
if DataExtName.lower() == 'special cust'.lower():
SP_PriceLevelName = DataExtValue.upper()
break
self.PriceLevelName = PriceLevelName
self.SPPriceLevelName = SP_PriceLevelName
return PriceLevelName, SP_PriceLevelName
def create_customerquery_QBXML(self ):
root = ET.Element("QBXML")
root.tail = "\n"
root.text = "\n "
QBXMLMsgsRq = ET.SubElement(root, "QBXMLMsgsRq")
# QBXMLMsgsRq.set("onError", "continueOnError")
QBXMLMsgsRq.set("onError", "stopOnError")
QBXMLMsgsRq.tail = "\n"
QBXMLMsgsRq.text = "\n "
CustomerQueryRq = self.create_sub_element(ET, QBXMLMsgsRq, "CustomerQueryRq","\n " )
# SalesOrderType = self.create_sub_element(ET, CustomerQueryRq, 'SalesOrderType', self.SalesOrderType)
FullName = self.create_sub_element(ET, CustomerQueryRq, "FullName", self.FullName, 6)
IncludeRetElement = ['FullName', 'PriceLevelRef', 'DataExtRet']
for x in IncludeRetElement:
IncludeRetElement = self.create_sub_element(ET, CustomerQueryRq, "IncludeRetElement", x, 4)
OwnerID = self.create_sub_element(ET, CustomerQueryRq, "OwnerID", "0", 6)
mydata = ET.tostring(root, encoding = "unicode")
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(f'create_customer_QBXML->qbxml_query: {qbxml_query}')
response_string=self.connect_to_quickbooks(qbxml_query)
return self.get_customer_pricelevel(response_string)
return response_string
def create_invoiceadd_QBXML(self):
print('create_ionvoiceadd_QBXML')
root = ET.Element("QBXML")
root.tail = "\n"
root.text = "\n "
QBXMLMsgsRq = ET.SubElement(root, "QBXMLMsgsRq")
QBXMLMsgsRq.set("onError", "stopOnError")
QBXMLMsgsRq.tail = "\n"
QBXMLMsgsRq.text = "\n "
InvoiceAddRq = self.create_sub_element(ET, QBXMLMsgsRq, "InvoiceAddRq", "\n ",2 )
InvoiceAdd = self.create_sub_element(ET, InvoiceAddRq, "InvoiceAdd", "\n ",4 )
CustomerRef = self.create_sub_element(ET, InvoiceAdd, "CustomerRef", "\n ",8 )
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 )
# 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=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)
mydata = ET.tostring(root, encoding = "unicode")
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(f'create_invoiceadd_QBXML->Create_Invoiceadd_QBXML: {qbxml_query}')
# print(f"replyfrom qbxml:{self.connect_to_quickbooks(qbxml_query)}")
return qbxml_query
def connect_to_quickbooks(self, qbxml_query):
# Connect to Quickbooks
# sessionManager = win32com.client.Dispatch("QBXMLRP2.RequestProcessor")
# sessionManager.OpenConnection('', 'DASA')
# enumfodnc= win32com.client.Dispatch('QBXMLRP2.RequestProcessor')
# print(enumfodnc)
# print(enumfodnc.qbFileOpenDoNotCare)
sessionManager = win32com.client.Dispatch("QBXMLRP2.RequestProcessor")
sessionManager.OpenConnection('', 'DASA2')
# ticket = sessionManager.BeginSession("z:\\DBW Bogor.qbw", 2)
ticket = sessionManager.BeginSession("", 2)
# Send query and receive response
response_string = sessionManager.ProcessRequest(ticket, qbxml_query)
# Disconnect from Quickbooks
sessionManager.EndSession(ticket) # Close the company file
sessionManager.CloseConnection() # Close the connection
# print (f'response_string:{response_string}')
return response_string
def __str__(self, *args) -> str:
# return str(self._get_datarow(self.connect_to_quickbooks(self.create_QBXML())))
# print("__str__")
return str(self.get_sales_order_header())
# return "hello"
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)
GSRQRs = tree.find(".//InvoiceAddRs")
# print(f"GSRQRs:{GSRQRs}")
status_code = GSRQRs.attrib #.get('statusCode')
# print(GSRQRs.attrib)
# print(GSRQRs.attrib['statusCode'])
status=GSRQRs.attrib.get('statusMessage')
print(f'status={status}')
if 'OK' in status:
return True, status_code
else:
return False, status_code
def _get_sales_order_header(self, response_string):
print('_get_sales_order_header')
# print(f'responsestring:{response_string}')
QBXML = ET.fromstring(response_string)
datadict = {}
SalesOrderdict = {}
_SalesOrderlist = []
SalesOrderRets = QBXML.findall('.//SalesOrderRet')
# print(SalesOrderRets)
for SalesOrderRet in SalesOrderRets:
RefNumber = SalesOrderRet.find('RefNumber').text
# Memo = SalesOrderRet.find('Memo').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
# print(CustomerFullName, TxnID, TotalAmount)
SalesOrderdict = {'RefNumber':RefNumber, 'CustomerFullName':CustomerFullName, 'TxnID':TxnID,
'TotalAmount':TotalAmount, 'IsFullyInvoiced':IsFullyInvoiced, 'IsManuallyClosed':IsManuallyClosed, 'SalesOrderLineRet':[]}
SalesOrderLineRet = SalesOrderRet.findall('SalesOrderLineRet')
# print(len(SalesOrderLineRet))
if len(SalesOrderLineRet) > 0:
disc_amount=0
for SalesOrderLineRet in SalesOrderLineRet:
TxnLineID = SalesOrderLineRet.find('TxnLineID').text
ItemFullName = SalesOrderLineRet.find('ItemRef/FullName').text
Quantity = SalesOrderLineRet.find('Quantity').text
UnitOfMeasure = SalesOrderLineRet.find('UnitOfMeasure').text
Rate = float(SalesOrderLineRet.find('Rate').text)
Amount = float(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:
SalesOrderLinedict = {'TxnLineID':TxnLineID,
'ItemFullName':ItemFullName,
'Quantity':Quantity,
'UOM':UnitOfMeasure,
'Rate':Rate,
'Amount':Amount,
'BackOrdered':BackOrdered,
'Invoiced':Invoiced,
'LineIsManuallyClosed':LineIsManuallyClosed,
}
SalesOrderdict['SalesOrderLineRet'].append(SalesOrderLinedict)
SalesOrderdict['Disc_Amount']=disc_amount
_SalesOrderlist.append(SalesOrderdict)
# print(_SalesOrderlist)
self.SalesOrderList=_SalesOrderlist
# print(f'_get_sales_order_header->Salesorderlist: {self.SalesOrderList}')
return self.SalesOrderList
def addDiscountToInvoiceList(self, _dict:dict):
print("addDiscountToInvoiceList")
def addDNQtyToSalesOrderList(self, _dict:dict):
_bolfoundrefnum=False
_bol_dictisadded=False
Error_msg = None
for poidx, _po in enumerate(self.SalesOrderList):
if _po['RefNumber']==_dict['RefNum']:
_bolfoundrefnum=True
if len(_po['SalesOrderLineRet'])>0:
for polineidx, _poline in enumerate(_po['SalesOrderLineRet']):
pass
if _poline['ItemFullName']==_dict['FullName']:
if _poline['UOM'].upper()==_dict['UOM'].upper():
# first do UOM in _dict convert treatment
QuantityIn_dict = _dict['Quantity']
if _dict['UOM'].upper().startswith('ROLL_'):
print(f"addDNQtyToSalesOrderList->DNqty:{_dict['Quantity']}, Roll_:{_dict['UOM'].split('_')[1]}")
QuantityIn_dict = _dict['Quantity'] * int(_dict['UOM'].split("_")[1])
pass
elif _dict['UOM'].upper() == 'BOX' and _dict['Item No'].upper() == "CUTTER":
print("addDNQtyToSalesOrderList->cutter")
elif _dict['UOM'].upper() == 'BOX' and (_dict['Item No'].upper().startswith("EB-") or _dict['Item No'].upper().startswith("TA-")):
print("addDNQtyToSalesOrderList->LEM")
if _dict['Item No'].split("-")[1].endswith("1006"):
QuantityIn_dict = QuantityIn_dict * 12
elif _dict['Item No'].split("-")[1].endswith("1025"):
QuantityIn_dict = QuantityIn_dict * 6
elif _dict['Item No'].split("-")[1].endswith("1100"):
pass
print("1100 lem")
elif _dict['UOM'].upper() == 'BOX' and (_dict['Item No'].upper().startswith("TL-") or _dict['Item No'].upper().startswith("TFL-")):
print("addDNQtyToSalesOrderList->Lock")
QuantityIn_dict = QuantityIn_dict * 20
elif _dict['UOM'].upper() == 'BOX' and _dict['Item No'].upper() == "EDG-TRIMMER":
QuantityIn_dict = QuantityIn_dict * 12 #coz box of 12
if _poline['BackOrdered']>=QuantityIn_dict:
self.SalesOrderList[poidx]['SalesOrderLineRet'][polineidx]['DNQuantity']=float(QuantityIn_dict)
_bol_dictisadded = True
else:
print(f"{_poline['ItemFullName']} BackOrdered < Qty in DN {_poline['BackOrdered']}<{QuantityIn_dict}")
Error_msg = f"BackOrdered < Qty in DN {_poline['BackOrdered']}<{QuantityIn_dict}"
else:
# print(f"UOM different {_poline['UOM']} <> {_dict['UOM']}")
Error_msg = f"UOM different {_poline['UOM']} <> {_dict['UOM']}"
else:
# print("errorpoline <>DN")
Error_msg = f"poline[ItemFullName] <> DN[FullName]; {_poline['ItemFullName']} <> {_dict['FullName']}, maybe there are 2 same namefromtaco in QB"
else:
pass
# print(f"this refnum {_dict['RefNum']} have no QB PO Return Line")
Error_msg = f"this refnum {_dict['RefNum']} have no QB PO Return Line"
# print (_bol_dictisadded, Error_msg)
return _bol_dictisadded, Error_msg
def prepareInvoice(self, df:pd.DataFrame = None):
# print(df)
_bolAllDNareOk = True
_notindflist=[]
_yescounter = 0
_nocounter = 0
if df is not None:
_dflist = df.to_dict('records')
# print(_dflist)
# else:
# _dflist = self.dfDN.to_dict('records')
# print(self.dfDN)
# print(f'_dflist:{_dflist}')
for idx, xdf in enumerate(_dflist):
_boladdDN, _Errormsg = self.addDNQtyToSalesOrderList(xdf)
# print(f'prepareInvoice->_Errormsg:{_Errormsg}')
if _boladdDN:
_dflist[idx]['ADDED']=True
elif _Errormsg:
_dflist[idx]['ERROR']=_Errormsg
for xdf in (_dflist):
if 'ADDED' not in xdf:
# print (f"prepareInvoice->not added: {xdf['Item No']}")
print (f"prepareInvoice->not added: {xdf}")
_notindflist.append(xdf)
_nocounter+=1
_bolAllDNareOk = False
else:
print (f"ADDED: {xdf['Item No']}")
print(f'{len(_dflist) - _nocounter} of {len(_dflist)} are added')
return _bolAllDNareOk, _notindflist
def validate_date(self, date_text):
if date_text is None:
return None
try:
return datetime.datetime.strptime(date_text, '%Y-%m-%d').date()
except ValueError:
return None
# raise ValueError("Incorrect data format, should be YYYY-MM-DD")
def get_ext_doc_no_list(self, dndict=None):
if dndict:
dnlist = dndict['lines']
else:
dnlist = self.DN
df = pd.DataFrame(dnlist)
# print(df)
df['RefNum']= df['No.SO/Ext.Doc.No.'].apply(lambda x: "L"+ x.split("L-")[1])
# print(df)
ext_doc_no=df['RefNum'].unique().tolist()
if len(ext_doc_no)>0:
return df, ext_doc_no
else:
return df, None
def get_open_so(self, response_string=None):
if not response_string:
response_string = self.connect_to_quickbooks(self.create_QBXML())
QBXML = ET.fromstring(response_string)
_OpenSalesOrderlist = []
SalesOrderRets = QBXML.findall('.//SalesOrderRet')
# print(f'SalesOrderRets count:{len(SalesOrderRets)}')
for SalesOrderRet in SalesOrderRets:
IsFullyInvoiced = SalesOrderRet.find('IsFullyInvoiced').text
IsManuallyClosed = SalesOrderRet.find('IsManuallyClosed').text
if IsFullyInvoiced=='false' and IsManuallyClosed=='false':
txndate = SalesOrderRet.find('TxnDate').text
totalamount = SalesOrderRet.find('TotalAmount').text
refnumber = SalesOrderRet.find('RefNumber').text
_OpenSalesOrderlist.append([SalesOrderRet.find('TxnID').text, txndate, totalamount, refnumber, ])
# _OpenSalesOrderlist.append(SalesOrderRet.find('TxnID').text)
# RefNumber = SalesOrderRet.find('RefNumber').text
# Memo = SalesOrderRet.find('Memo').text
# CustomerFullName = SalesOrderRet.find('CustomerRef/FullName').text
# TxnID = SalesOrderRet.find('TxnID').text
# TotalAmount = SalesOrderRet.find('TotalAmount').text
# IsFullyReceived = SalesOrderRet.find('IsFullyReceived').text
# IsManuallyClosed = SalesOrderRet.find('IsManuallyClosed').text
# print(_OpenSalesOrderlist)
return _OpenSalesOrderlist
def create_open_sales_order_qbxml(self, txnid:list, IncludeLineItems=True):
root = ET.Element("QBXML")
root.tail = "\n"
root.text = "\n "
QBXMLMsgsRq = ET.SubElement(root, "QBXMLMsgsRq")
# QBXMLMsgsRq.set("onError", "continueOnError")
QBXMLMsgsRq.set("onError", "stopOnError")
QBXMLMsgsRq.tail = "\n"
QBXMLMsgsRq.text = "\n "
SalesOrderQueryRq = self.create_sub_element(ET, QBXMLMsgsRq, "SalesOrderQueryRq","\n " )
if len(txnid)>0:
for x in txnid:
TxnID = self.create_sub_element(ET, SalesOrderQueryRq, "TxnID", x, 6 )
else:
return None
if IncludeLineItems:
IncludeLineItems = self.create_sub_element(ET, SalesOrderQueryRq, "IncludeLineItems", 'true', 4)
# if len(self.IncludeRetElement)>0:
# for x in self.IncludeRetElement:
# IncludeRetElement = self.create_sub_element(ET, SalesOrderQueryRq, "IncludeRetElement", x, 4)
mydata = ET.tostring(root, encoding = "unicode")
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(f'create_open_sale_order_qbxml->qbxml_query: {qbxml_query}')
return qbxml_query
def get_open_sales_order(self, txnlist:list):
print(f'txnid: {txnlist}', type(txnlist))
txnid = []
for x in txnlist:
if isinstance(x, list):
txnid.append(x[0])
else:
txnid.append(x)
break
# txnid = [x[0] if isinstance(x, list) else x for x in txnid ]
print(txnid)
if txnid:
# print(self.connect_to_quickbooks(self.create_open_sales_order_qbxml(txnid)))
return self._get_sales_order_header(self.connect_to_quickbooks(self.create_open_sales_order_qbxml(txnid)))
else:
print("There is No Open Sales Order")
return None
return None
print('### SalesOrder ###')
if __name__ == '__main__':
starttime = timeit.default_timer()
# 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'])
# iya = ini.create_customerquery_QBXML() #pakai excel saja lebih cepat
# print(iya)
print(f'createQBXML:{ini.create_QBXML()}')
response_string = ini.connect_to_quickbooks(ini.create_QBXML())
# print(f'response_string:{response_string}')
response_string = None
open_sales_orders = ini.get_open_so()
print(f'open sales orders:{open_sales_orders}')
if open_sales_orders:
itu = ini.get_open_sales_order(open_sales_orders)
# print(itu)
print(f'get_open_sales_order:{itu}')
if itu:
print(ini.create_invoiceadd_QBXML())
# ini.connect_to_quickbooks(ini.create_invoiceadd_QBXML())
print("The time difference is :", timeit.default_timer() - starttime)

336
SalesOrderQuery.xml Normal file
View File

@ -0,0 +1,336 @@
<?xml version="1.0" encoding="utf-8"?>
<?qbxml version="16.0"?>
<QBXML>
<QBXMLMsgsRq onError="stopOnError">
<SalesOrderQueryRq metaData="ENUMTYPE" iterator="ENUMTYPE" iteratorID="UUIDTYPE">
<!-- BEGIN OR -->
<TxnID >IDTYPE</TxnID> <!-- optional, may repeat -->
<!-- OR -->
<RefNumber >STRTYPE</RefNumber> <!-- optional, may repeat -->
<!-- OR -->
<RefNumberCaseSensitive >STRTYPE</RefNumberCaseSensitive> <!-- optional, may repeat -->
<!-- OR -->
<MaxReturned >INTTYPE</MaxReturned> <!-- optional -->
<!-- BEGIN OR -->
<ModifiedDateRangeFilter> <!-- optional -->
<FromModifiedDate >DATETIMETYPE</FromModifiedDate> <!-- optional -->
<ToModifiedDate >DATETIMETYPE</ToModifiedDate> <!-- optional -->
</ModifiedDateRangeFilter>
<!-- OR -->
<TxnDateRangeFilter> <!-- optional -->
<!-- BEGIN OR -->
<FromTxnDate >DATETYPE</FromTxnDate> <!-- optional -->
<ToTxnDate >DATETYPE</ToTxnDate> <!-- optional -->
<!-- OR -->
<!-- DateMacro may have one of the following values: All, Today, ThisWeek, ThisWeekToDate, ThisMonth, ThisMonthToDate, ThisCalendarQuarter, ThisCalendarQuarterToDate, ThisFiscalQuarter, ThisFiscalQuarterToDate, ThisCalendarYear, ThisCalendarYearToDate, ThisFiscalYear, ThisFiscalYearToDate, Yesterday, LastWeek, LastWeekToDate, LastMonth, LastMonthToDate, LastCalendarQuarter, LastCalendarQuarterToDate, LastFiscalQuarter, LastFiscalQuarterToDate, LastCalendarYear, LastCalendarYearToDate, LastFiscalYear, LastFiscalYearToDate, NextWeek, NextFourWeeks, NextMonth, NextCalendarQuarter, NextCalendarYear, NextFiscalQuarter, NextFiscalYear -->
<DateMacro >ENUMTYPE</DateMacro> <!-- optional -->
<!-- END OR -->
</TxnDateRangeFilter>
<!-- END OR -->
<EntityFilter> <!-- optional -->
<!-- BEGIN OR -->
<ListID >IDTYPE</ListID> <!-- optional, may repeat -->
<!-- OR -->
<FullName >STRTYPE</FullName> <!-- optional, may repeat -->
<!-- OR -->
<ListIDWithChildren >IDTYPE</ListIDWithChildren> <!-- optional -->
<!-- OR -->
<FullNameWithChildren >STRTYPE</FullNameWithChildren> <!-- optional -->
<!-- END OR -->
</EntityFilter>
<!-- BEGIN OR -->
<RefNumberFilter> <!-- optional -->
<!-- MatchCriterion may have one of the following values: StartsWith, Contains, EndsWith -->
<MatchCriterion >ENUMTYPE</MatchCriterion> <!-- required -->
<RefNumber >STRTYPE</RefNumber> <!-- required -->
</RefNumberFilter>
<!-- OR -->
<RefNumberRangeFilter> <!-- optional -->
<FromRefNumber >STRTYPE</FromRefNumber> <!-- optional -->
<ToRefNumber >STRTYPE</ToRefNumber> <!-- optional -->
</RefNumberRangeFilter>
<!-- END OR -->
<CurrencyFilter> <!-- optional -->
<!-- BEGIN OR -->
<ListID >IDTYPE</ListID> <!-- optional, may repeat -->
<!-- OR -->
<FullName >STRTYPE</FullName> <!-- optional, may repeat -->
<!-- END OR -->
</CurrencyFilter>
<!-- END OR -->
<IncludeLineItems >BOOLTYPE</IncludeLineItems> <!-- optional -->
<IncludeLinkedTxns >BOOLTYPE</IncludeLinkedTxns> <!-- optional -->
<IncludeRetElement >STRTYPE</IncludeRetElement> <!-- optional, may repeat -->
<OwnerID >GUIDTYPE</OwnerID> <!-- optional, may repeat -->
</SalesOrderQueryRq>
<SalesOrderQueryRs statusCode="INTTYPE" statusSeverity="STRTYPE" statusMessage="STRTYPE" retCount="INTTYPE" iteratorRemainingCount="INTTYPE" iteratorID="UUIDTYPE">
<SalesOrderRet> <!-- optional, may repeat -->
<TxnID >IDTYPE</TxnID> <!-- required -->
<TimeCreated >DATETIMETYPE</TimeCreated> <!-- required -->
<TimeModified >DATETIMETYPE</TimeModified> <!-- required -->
<EditSequence >STRTYPE</EditSequence> <!-- required -->
<TxnNumber >INTTYPE</TxnNumber> <!-- optional -->
<CustomerRef> <!-- required -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</CustomerRef>
<ClassRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</ClassRef>
<TemplateRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</TemplateRef>
<TxnDate >DATETYPE</TxnDate> <!-- required -->
<RefNumber >STRTYPE</RefNumber> <!-- optional -->
<BillAddress> <!-- optional -->
<Addr1 >STRTYPE</Addr1> <!-- optional -->
<Addr2 >STRTYPE</Addr2> <!-- optional -->
<Addr3 >STRTYPE</Addr3> <!-- optional -->
<Addr4 >STRTYPE</Addr4> <!-- optional -->
<Addr5 >STRTYPE</Addr5> <!-- optional -->
<City >STRTYPE</City> <!-- optional -->
<State >STRTYPE</State> <!-- optional -->
<PostalCode >STRTYPE</PostalCode> <!-- optional -->
<Country >STRTYPE</Country> <!-- optional -->
<Note >STRTYPE</Note> <!-- optional -->
</BillAddress>
<BillAddressBlock> <!-- optional -->
<Addr1 >STRTYPE</Addr1> <!-- optional -->
<Addr2 >STRTYPE</Addr2> <!-- optional -->
<Addr3 >STRTYPE</Addr3> <!-- optional -->
<Addr4 >STRTYPE</Addr4> <!-- optional -->
<Addr5 >STRTYPE</Addr5> <!-- optional -->
</BillAddressBlock>
<ShipAddress> <!-- optional -->
<Addr1 >STRTYPE</Addr1> <!-- optional -->
<Addr2 >STRTYPE</Addr2> <!-- optional -->
<Addr3 >STRTYPE</Addr3> <!-- optional -->
<Addr4 >STRTYPE</Addr4> <!-- optional -->
<Addr5 >STRTYPE</Addr5> <!-- optional -->
<City >STRTYPE</City> <!-- optional -->
<State >STRTYPE</State> <!-- optional -->
<PostalCode >STRTYPE</PostalCode> <!-- optional -->
<Country >STRTYPE</Country> <!-- optional -->
<Note >STRTYPE</Note> <!-- optional -->
</ShipAddress>
<ShipAddressBlock> <!-- optional -->
<Addr1 >STRTYPE</Addr1> <!-- optional -->
<Addr2 >STRTYPE</Addr2> <!-- optional -->
<Addr3 >STRTYPE</Addr3> <!-- optional -->
<Addr4 >STRTYPE</Addr4> <!-- optional -->
<Addr5 >STRTYPE</Addr5> <!-- optional -->
</ShipAddressBlock>
<PONumber >STRTYPE</PONumber> <!-- optional -->
<TermsRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</TermsRef>
<DueDate >DATETYPE</DueDate> <!-- optional -->
<SalesRepRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</SalesRepRef>
<FOB >STRTYPE</FOB> <!-- optional -->
<ShipDate >DATETYPE</ShipDate> <!-- optional -->
<ShipMethodRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</ShipMethodRef>
<Subtotal >AMTTYPE</Subtotal> <!-- optional -->
<ItemSalesTaxRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</ItemSalesTaxRef>
<SalesTaxPercentage >PERCENTTYPE</SalesTaxPercentage> <!-- optional -->
<SalesTaxTotal >AMTTYPE</SalesTaxTotal> <!-- optional -->
<TotalAmount >AMTTYPE</TotalAmount> <!-- optional -->
<CurrencyRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</CurrencyRef>
<ExchangeRate >FLOATTYPE</ExchangeRate> <!-- optional -->
<TotalAmountInHomeCurrency >AMTTYPE</TotalAmountInHomeCurrency> <!-- optional -->
<IsManuallyClosed >BOOLTYPE</IsManuallyClosed> <!-- optional -->
<IsFullyInvoiced >BOOLTYPE</IsFullyInvoiced> <!-- optional -->
<Memo >STRTYPE</Memo> <!-- optional -->
<CustomerMsgRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</CustomerMsgRef>
<IsToBePrinted >BOOLTYPE</IsToBePrinted> <!-- optional -->
<IsToBeEmailed >BOOLTYPE</IsToBeEmailed> <!-- optional -->
<IsTaxIncluded >BOOLTYPE</IsTaxIncluded> <!-- optional -->
<CustomerSalesTaxCodeRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</CustomerSalesTaxCodeRef>
<Other >STRTYPE</Other> <!-- optional -->
<ExternalGUID >GUIDTYPE</ExternalGUID> <!-- optional -->
<LinkedTxn> <!-- optional, may repeat -->
<TxnID >IDTYPE</TxnID> <!-- required -->
<!-- TxnType may have one of the following values: ARRefundCreditCard, Bill, BillPaymentCheck, BillPaymentCreditCard, BuildAssembly, Charge, Check, CreditCardCharge, CreditCardCredit, CreditMemo, Deposit, Estimate, InventoryAdjustment, Invoice, ItemReceipt, JournalEntry, LiabilityAdjustment, Paycheck, PayrollLiabilityCheck, PurchaseOrder, ReceivePayment, SalesOrder, SalesReceipt, SalesTaxPaymentCheck, Transfer, VendorCredit, YTDAdjustment -->
<TxnType >ENUMTYPE</TxnType> <!-- required -->
<TxnDate >DATETYPE</TxnDate> <!-- required -->
<RefNumber >STRTYPE</RefNumber> <!-- optional -->
<!-- LinkType may have one of the following values: AMTTYPE, QUANTYPE -->
<LinkType >ENUMTYPE</LinkType> <!-- optional -->
<Amount >AMTTYPE</Amount> <!-- required -->
</LinkedTxn>
<!-- BEGIN OR -->
<SalesOrderLineRet> <!-- optional -->
<TxnLineID >IDTYPE</TxnLineID> <!-- required -->
<ItemRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</ItemRef>
<Desc >STRTYPE</Desc> <!-- optional -->
<Quantity >QUANTYPE</Quantity> <!-- optional -->
<UnitOfMeasure >STRTYPE</UnitOfMeasure> <!-- optional -->
<OverrideUOMSetRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</OverrideUOMSetRef>
<!-- BEGIN OR -->
<Rate >PRICETYPE</Rate> <!-- optional -->
<!-- OR -->
<RatePercent >PERCENTTYPE</RatePercent> <!-- optional -->
<!-- END OR -->
<ClassRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</ClassRef>
<Amount >AMTTYPE</Amount> <!-- optional -->
<InventorySiteRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</InventorySiteRef>
<InventorySiteLocationRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</InventorySiteLocationRef>
<!-- BEGIN OR -->
<SerialNumber >STRTYPE</SerialNumber> <!-- optional -->
<!-- OR -->
<LotNumber >STRTYPE</LotNumber> <!-- optional -->
<!-- END OR -->
<ExpirationDateForSerialLotNumber>STRTYPE</ExpirationDateForSerialLotNumber> <!-- optional -->
<SalesTaxCodeRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</SalesTaxCodeRef>
<Invoiced >QUANTYPE</Invoiced> <!-- optional -->
<IsManuallyClosed >BOOLTYPE</IsManuallyClosed> <!-- optional -->
<Other1 >STRTYPE</Other1> <!-- optional -->
<Other2 >STRTYPE</Other2> <!-- optional -->
<DataExtRet> <!-- optional, may repeat -->
<OwnerID >GUIDTYPE</OwnerID> <!-- optional -->
<DataExtName >STRTYPE</DataExtName> <!-- required -->
<!-- DataExtType may have one of the following values: AMTTYPE, DATETIMETYPE, INTTYPE, PERCENTTYPE, PRICETYPE, QUANTYPE, STR1024TYPE, STR255TYPE -->
<DataExtType >ENUMTYPE</DataExtType> <!-- required -->
<DataExtValue >STRTYPE</DataExtValue> <!-- required -->
</DataExtRet>
</SalesOrderLineRet>
<!-- OR -->
<SalesOrderLineGroupRet> <!-- optional -->
<TxnLineID >IDTYPE</TxnLineID> <!-- required -->
<ItemGroupRef> <!-- required -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</ItemGroupRef>
<Desc >STRTYPE</Desc> <!-- optional -->
<Quantity >QUANTYPE</Quantity> <!-- optional -->
<UnitOfMeasure >STRTYPE</UnitOfMeasure> <!-- optional -->
<OverrideUOMSetRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</OverrideUOMSetRef>
<IsPrintItemsInGroup >BOOLTYPE</IsPrintItemsInGroup> <!-- required -->
<TotalAmount >AMTTYPE</TotalAmount> <!-- required -->
<SalesOrderLineRet> <!-- optional, may repeat -->
<TxnLineID >IDTYPE</TxnLineID> <!-- required -->
<ItemRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</ItemRef>
<Desc >STRTYPE</Desc> <!-- optional -->
<Quantity >QUANTYPE</Quantity> <!-- optional -->
<UnitOfMeasure >STRTYPE</UnitOfMeasure> <!-- optional -->
<OverrideUOMSetRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</OverrideUOMSetRef>
<!-- BEGIN OR -->
<Rate >PRICETYPE</Rate> <!-- optional -->
<!-- OR -->
<RatePercent >PERCENTTYPE</RatePercent> <!-- optional -->
<!-- END OR -->
<ClassRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</ClassRef>
<Amount >AMTTYPE</Amount> <!-- optional -->
<InventorySiteRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</InventorySiteRef>
<InventorySiteLocationRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</InventorySiteLocationRef>
<!-- BEGIN OR -->
<SerialNumber >STRTYPE</SerialNumber> <!-- optional -->
<!-- OR -->
<LotNumber >STRTYPE</LotNumber> <!-- optional -->
<!-- END OR -->
<ExpirationDateForSerialLotNumber>STRTYPE</ExpirationDateForSerialLotNumber> <!-- optional -->
<SalesTaxCodeRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</SalesTaxCodeRef>
<Invoiced >QUANTYPE</Invoiced> <!-- optional -->
<IsManuallyClosed >BOOLTYPE</IsManuallyClosed> <!-- optional -->
<Other1 >STRTYPE</Other1> <!-- optional -->
<Other2 >STRTYPE</Other2> <!-- optional -->
<DataExtRet> <!-- optional, may repeat -->
<OwnerID >GUIDTYPE</OwnerID> <!-- optional -->
<DataExtName >STRTYPE</DataExtName> <!-- required -->
<!-- DataExtType may have one of the following values: AMTTYPE, DATETIMETYPE, INTTYPE, PERCENTTYPE, PRICETYPE, QUANTYPE, STR1024TYPE, STR255TYPE -->
<DataExtType >ENUMTYPE</DataExtType> <!-- required -->
<DataExtValue >STRTYPE</DataExtValue> <!-- required -->
</DataExtRet>
</SalesOrderLineRet>
<DataExtRet> <!-- optional, may repeat -->
<OwnerID >GUIDTYPE</OwnerID> <!-- optional -->
<DataExtName >STRTYPE</DataExtName> <!-- required -->
<!-- DataExtType may have one of the following values: AMTTYPE, DATETIMETYPE, INTTYPE, PERCENTTYPE, PRICETYPE, QUANTYPE, STR1024TYPE, STR255TYPE -->
<DataExtType >ENUMTYPE</DataExtType> <!-- required -->
<DataExtValue >STRTYPE</DataExtValue> <!-- required -->
</DataExtRet>
</SalesOrderLineGroupRet>
<!-- END OR -->
<DataExtRet> <!-- optional, may repeat -->
<OwnerID >GUIDTYPE</OwnerID> <!-- optional -->
<DataExtName >STRTYPE</DataExtName> <!-- required -->
<!-- DataExtType may have one of the following values: AMTTYPE, DATETIMETYPE, INTTYPE, PERCENTTYPE, PRICETYPE, QUANTYPE, STR1024TYPE, STR255TYPE -->
<DataExtType >ENUMTYPE</DataExtType> <!-- required -->
<DataExtValue >STRTYPE</DataExtValue> <!-- required -->
</DataExtRet>
<FulfillmentStatus>ENUMTYPE</FulfillmentStatus> <!-- optional -->
<ShippingDetails> <!-- optional -->
<ShippingDetailsLineRet> <!-- optional -->
<TrackingID>IDTYPE</TrackingID> <!-- optional -->
<CarrierName>STRTYPE</CarrierName> <!-- optional -->
<ShippingMethod>STRTYPE</ShippingMethod> <!-- optional -->
<ShippingCharges>AMTTYPE</ShippingCharges> <!-- optional -->
</ShippingDetailsLineRet>
</ShippingDetails>
<SOChannel>ENUMTYPE</SOChannel> <!-- optional -->
<StoreName>STRTYPE</StoreName> <!-- optional -->
<StoreType>STRTYPE</StoreType> <!-- optional -->
</SalesOrderRet>
</SalesOrderQueryRs>
</QBXMLMsgsRq>
</QBXML>

147
TransactionQuery.xml Normal file
View File

@ -0,0 +1,147 @@
<?xml version="1.0" encoding="utf-8"?>
<?qbxml version="16.0"?>
<QBXML>
<QBXMLMsgsRq onError="stopOnError">
<TransactionQueryRq metaData="ENUMTYPE" iterator="ENUMTYPE" iteratorID="UUIDTYPE">
<!-- BEGIN OR -->
<TxnID >IDTYPE</TxnID> <!-- optional, may repeat -->
<!-- OR -->
<MaxReturned >INTTYPE</MaxReturned> <!-- optional -->
<!-- BEGIN OR -->
<RefNumber >STRTYPE</RefNumber> <!-- optional, may repeat -->
<!-- OR -->
<RefNumberCaseSensitive >STRTYPE</RefNumberCaseSensitive> <!-- optional, may repeat -->
<!-- OR -->
<RefNumberFilter> <!-- optional -->
<!-- MatchCriterion may have one of the following values: StartsWith, Contains, EndsWith -->
<MatchCriterion >ENUMTYPE</MatchCriterion> <!-- required -->
<RefNumber >STRTYPE</RefNumber> <!-- required -->
</RefNumberFilter>
<!-- OR -->
<RefNumberRangeFilter> <!-- optional -->
<FromRefNumber >STRTYPE</FromRefNumber> <!-- optional -->
<ToRefNumber >STRTYPE</ToRefNumber> <!-- optional -->
</RefNumberRangeFilter>
<!-- END OR -->
<TransactionModifiedDateRangeFilter> <!-- optional -->
<!-- BEGIN OR -->
<FromModifiedDate >DATETIMETYPE</FromModifiedDate> <!-- optional -->
<ToModifiedDate >DATETIMETYPE</ToModifiedDate> <!-- optional -->
<!-- OR -->
<!-- DateMacro may have one of the following values: All, Today, ThisWeek, ThisWeekToDate, ThisMonth, ThisMonthToDate, ThisCalendarQuarter, ThisCalendarQuarterToDate, ThisFiscalQuarter, ThisFiscalQuarterToDate, ThisCalendarYear, ThisCalendarYearToDate, ThisFiscalYear, ThisFiscalYearToDate, Yesterday, LastWeek, LastWeekToDate, LastMonth, LastMonthToDate, LastCalendarQuarter, LastCalendarQuarterToDate, LastFiscalQuarter, LastFiscalQuarterToDate, LastCalendarYear, LastCalendarYearToDate, LastFiscalYear, LastFiscalYearToDate, NextWeek, NextFourWeeks, NextMonth, NextCalendarQuarter, NextCalendarYear, NextFiscalQuarter, NextFiscalYear -->
<DateMacro >ENUMTYPE</DateMacro> <!-- optional -->
<!-- END OR -->
</TransactionModifiedDateRangeFilter>
<TransactionDateRangeFilter> <!-- optional -->
<!-- BEGIN OR -->
<FromTxnDate >DATETYPE</FromTxnDate> <!-- optional -->
<ToTxnDate >DATETYPE</ToTxnDate> <!-- optional -->
<!-- OR -->
<!-- DateMacro may have one of the following values: All, Today, ThisWeek, ThisWeekToDate, ThisMonth, ThisMonthToDate, ThisCalendarQuarter, ThisCalendarQuarterToDate, ThisFiscalQuarter, ThisFiscalQuarterToDate, ThisCalendarYear, ThisCalendarYearToDate, ThisFiscalYear, ThisFiscalYearToDate, Yesterday, LastWeek, LastWeekToDate, LastMonth, LastMonthToDate, LastCalendarQuarter, LastCalendarQuarterToDate, LastFiscalQuarter, LastFiscalQuarterToDate, LastCalendarYear, LastCalendarYearToDate, LastFiscalYear, LastFiscalYearToDate, NextWeek, NextFourWeeks, NextMonth, NextCalendarQuarter, NextCalendarYear, NextFiscalQuarter, NextFiscalYear -->
<DateMacro >ENUMTYPE</DateMacro> <!-- optional -->
<!-- END OR -->
</TransactionDateRangeFilter>
<TransactionEntityFilter> <!-- optional -->
<!-- BEGIN OR -->
<!-- EntityTypeFilter may have one of the following values: Customer, Employee, OtherName, Vendor -->
<EntityTypeFilter >ENUMTYPE</EntityTypeFilter> <!-- optional -->
<!-- OR -->
<ListID >IDTYPE</ListID> <!-- optional, may repeat -->
<!-- OR -->
<FullName >STRTYPE</FullName> <!-- optional, may repeat -->
<!-- OR -->
<ListIDWithChildren >IDTYPE</ListIDWithChildren> <!-- optional -->
<!-- OR -->
<FullNameWithChildren >STRTYPE</FullNameWithChildren> <!-- optional -->
<!-- END OR -->
</TransactionEntityFilter>
<TransactionAccountFilter> <!-- optional -->
<!-- BEGIN OR -->
<!-- AccountTypeFilter may have one of the following values: AccountsPayable, AccountsReceivable, AllowedFor1099, APAndSalesTax, APOrCreditCard, ARAndAP, Asset, BalanceSheet, Bank, BankAndARAndAPAndUF, BankAndUF, CostOfSales, CreditCard, CurrentAsset, CurrentAssetAndExpense, CurrentLiability, Equity, EquityAndIncomeAndExpense, ExpenseAndOtherExpense, FixedAsset, IncomeAndExpense, IncomeAndOtherIncome, Liability, LiabilityAndEquity, LongTermLiability, NonPosting, OrdinaryExpense, OrdinaryIncome, OrdinaryIncomeAndCOGS, OrdinaryIncomeAndExpense, OtherAsset, OtherCurrentAsset, OtherCurrentLiability, OtherExpense, OtherIncome, OtherIncomeOrExpense -->
<AccountTypeFilter >ENUMTYPE</AccountTypeFilter> <!-- optional -->
<!-- OR -->
<ListID >IDTYPE</ListID> <!-- optional, may repeat -->
<!-- OR -->
<FullName >STRTYPE</FullName> <!-- optional, may repeat -->
<!-- OR -->
<ListIDWithChildren >IDTYPE</ListIDWithChildren> <!-- optional -->
<!-- OR -->
<FullNameWithChildren >STRTYPE</FullNameWithChildren> <!-- optional -->
<!-- END OR -->
</TransactionAccountFilter>
<TransactionItemFilter> <!-- optional -->
<!-- BEGIN OR -->
<!-- ItemTypeFilter may have one of the following values: AllExceptFixedAsset, Assembly, Discount, FixedAsset, Inventory, InventoryAndAssembly, NonInventory, OtherCharge, Payment, Sales, SalesTax, Service -->
<ItemTypeFilter >ENUMTYPE</ItemTypeFilter> <!-- optional -->
<!-- OR -->
<ListID >IDTYPE</ListID> <!-- optional, may repeat -->
<!-- OR -->
<FullName >STRTYPE</FullName> <!-- optional, may repeat -->
<!-- OR -->
<ListIDWithChildren >IDTYPE</ListIDWithChildren> <!-- optional -->
<!-- OR -->
<FullNameWithChildren >STRTYPE</FullNameWithChildren> <!-- optional -->
<!-- END OR -->
</TransactionItemFilter>
<TransactionClassFilter> <!-- optional -->
<!-- BEGIN OR -->
<ListID >IDTYPE</ListID> <!-- optional, may repeat -->
<!-- OR -->
<FullName >STRTYPE</FullName> <!-- optional, may repeat -->
<!-- OR -->
<ListIDWithChildren >IDTYPE</ListIDWithChildren> <!-- optional -->
<!-- OR -->
<FullNameWithChildren >STRTYPE</FullNameWithChildren> <!-- optional -->
<!-- END OR -->
</TransactionClassFilter>
<TransactionTypeFilter> <!-- optional -->
<!-- TxnTypeFilter may have one of the following values: All, ARRefundCreditCard, Bill, BillPaymentCheck, BillPaymentCreditCard, BuildAssembly, Charge, Check, CreditCardCharge, CreditCardCredit, CreditMemo, Deposit, Estimate, InventoryAdjustment, Invoice, ItemReceipt, JournalEntry, LiabilityAdjustment, Paycheck, PayrollLiabilityCheck, PurchaseOrder, ReceivePayment, SalesOrder, SalesReceipt, SalesTaxPaymentCheck, Transfer, VendorCredit, YTDAdjustment -->
<TxnTypeFilter >ENUMTYPE</TxnTypeFilter> <!-- required, may repeat -->
</TransactionTypeFilter>
<!-- TransactionDetailLevelFilter may have one of the following values: All, SummaryOnly [DEFAULT], AllExceptSummary -->
<TransactionDetailLevelFilter >ENUMTYPE</TransactionDetailLevelFilter> <!-- optional -->
<!-- TransactionPostingStatusFilter may have one of the following values: Either [DEFAULT], NonPosting, Posting -->
<TransactionPostingStatusFilter >ENUMTYPE</TransactionPostingStatusFilter> <!-- optional -->
<!-- TransactionPaidStatusFilter may have one of the following values: Either [DEFAULT], Closed, Open -->
<TransactionPaidStatusFilter >ENUMTYPE</TransactionPaidStatusFilter> <!-- optional -->
<CurrencyFilter> <!-- optional -->
<!-- BEGIN OR -->
<ListID >IDTYPE</ListID> <!-- optional, may repeat -->
<!-- OR -->
<FullName >STRTYPE</FullName> <!-- optional, may repeat -->
<!-- END OR -->
</CurrencyFilter>
<!-- END OR -->
<IncludeRetElement >STRTYPE</IncludeRetElement> <!-- optional, may repeat -->
</TransactionQueryRq>
<TransactionQueryRs statusCode="INTTYPE" statusSeverity="STRTYPE" statusMessage="STRTYPE" retCount="INTTYPE" iteratorRemainingCount="INTTYPE" iteratorID="UUIDTYPE">
<TransactionRet> <!-- optional, may repeat -->
<!-- TxnType may have one of the following values: ARRefundCreditCard, Bill, BillPaymentCheck, BillPaymentCreditCard, BuildAssembly, Charge, Check, CreditCardCharge, CreditCardCredit, CreditMemo, Deposit, Estimate, InventoryAdjustment, Invoice, ItemReceipt, JournalEntry, LiabilityAdjustment, Paycheck, PayrollLiabilityCheck, PurchaseOrder, ReceivePayment, SalesOrder, SalesReceipt, SalesTaxPaymentCheck, Transfer, VendorCredit, YTDAdjustment -->
<TxnType >ENUMTYPE</TxnType> <!-- optional -->
<TxnID >IDTYPE</TxnID> <!-- optional -->
<TxnLineID >IDTYPE</TxnLineID> <!-- optional -->
<TimeCreated >DATETIMETYPE</TimeCreated> <!-- optional -->
<TimeModified >DATETIMETYPE</TimeModified> <!-- optional -->
<EntityRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</EntityRef>
<AccountRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</AccountRef>
<TxnDate >DATETYPE</TxnDate> <!-- optional -->
<RefNumber >STRTYPE</RefNumber> <!-- optional -->
<Amount >AMTTYPE</Amount> <!-- optional -->
<CurrencyRef> <!-- optional -->
<ListID >IDTYPE</ListID> <!-- optional -->
<FullName >STRTYPE</FullName> <!-- optional -->
</CurrencyRef>
<ExchangeRate >FLOATTYPE</ExchangeRate> <!-- optional -->
<AmountInHomeCurrency >AMTTYPE</AmountInHomeCurrency> <!-- optional -->
<Memo >STRTYPE</Memo> <!-- optional -->
</TransactionRet>
</TransactionQueryRs>
</QBXMLMsgsRq>
</QBXML>

BIN
database.db Normal file

Binary file not shown.

166
django/.gitignore vendored Normal file
View File

@ -0,0 +1,166 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock
# pdm
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
#pdm.lock
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
# in version control.
# https://pdm.fming.dev/#use-with-ide
.pdm.toml
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/
# PyCharm
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/
#excel files
*.xlsx
*.xls
ItemInventory/

View File

4
django/Customer/admin.py Normal file
View File

@ -0,0 +1,4 @@
from django.contrib import admin
from .models import Customer
admin.site.register(Customer)

6
django/Customer/apps.py Normal file
View File

@ -0,0 +1,6 @@
from django.apps import AppConfig
class CustomerConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'Customer'

7
django/Customer/forms.py Normal file
View File

@ -0,0 +1,7 @@
from django.forms import ModelForm
from .models import Customer
class CustomerForm(ModelForm):
class Meta:
model = Customer
fields = "__all__"

View File

@ -0,0 +1,69 @@
# Generated by Django 4.2 on 2023-05-02 10:31
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='Customer',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('TimeCreated', models.DateTimeField(auto_created=True)),
('CustomerName', models.CharField(max_length=80)),
('CustomerFullName', models.CharField(max_length=160)),
('CustomerIsActive', models.BooleanField(default=True)),
('Sublevel', models.PositiveSmallIntegerField(default=0)),
('CompanyName', models.CharField(max_length=80)),
('Salutation', models.CharField(max_length=5)),
('FirstName', models.CharField(max_length=80)),
('MiddleName', models.CharField(blank=True, max_length=80, null=True)),
('LastName', models.CharField(blank=True, max_length=80, null=True)),
('BillAddr1', models.CharField(max_length=80)),
('BillAddr2', models.CharField(blank=True, max_length=80, null=True)),
('BillAddr3', models.CharField(blank=True, max_length=80, null=True)),
('BillAddr4', models.CharField(blank=True, max_length=80, null=True)),
('BillAddr5', models.CharField(blank=True, max_length=80, null=True)),
('BillCity', models.CharField(blank=True, max_length=80, null=True)),
('BillState', models.CharField(blank=True, max_length=80, null=True)),
('BillPostalCode', models.CharField(blank=True, max_length=80, null=True)),
('BillCountry', models.CharField(default='Indonesia', max_length=80)),
('BillNote', models.CharField(blank=True, max_length=80, null=True)),
('ShipAddr1', models.CharField(blank=True, max_length=80, null=True)),
('ShipAddr2', models.CharField(blank=True, max_length=80, null=True)),
('ShipAddr3', models.CharField(blank=True, max_length=80, null=True)),
('ShipAddr4', models.CharField(blank=True, max_length=80, null=True)),
('ShipAddr5', models.CharField(blank=True, max_length=80, null=True)),
('ShipCity', models.CharField(blank=True, max_length=80, null=True)),
('ShipState', models.CharField(blank=True, max_length=80, null=True)),
('ShipPostalCode', models.CharField(blank=True, max_length=80, null=True)),
('ShipCountry', models.CharField(blank=True, max_length=80, null=True)),
('ShipNote', models.CharField(blank=True, max_length=200, null=True)),
('Phone', models.CharField(blank=True, max_length=80, null=True)),
('Contact', models.CharField(max_length=80)),
('Notes', models.CharField(blank=True, max_length=200, null=True)),
('AltPhone', models.CharField(blank=True, max_length=25, null=True)),
('Fax', models.CharField(blank=True, max_length=25, null=True)),
('Email', models.CharField(blank=True, max_length=50, null=True)),
('AltContact', models.CharField(blank=True, max_length=50, null=True)),
('CreditLimit', models.DecimalField(blank=True, decimal_places=2, max_digits=12, null=True)),
('NPWP', models.CharField(max_length=20)),
('KTP', models.CharField(max_length=16)),
('DMS_Cust_Name', models.CharField(max_length=80)),
('DMS_Cust_Code', models.CharField(max_length=80)),
('Special_Cust', models.BooleanField(default=False)),
('EFaktur_Name', models.CharField(max_length=80)),
('Efaktur_Address', models.CharField(max_length=80)),
('Coordinates', models.CharField(blank=True, max_length=50, null=True)),
('TimeModified', models.DateTimeField(auto_now=True)),
('Parent', models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, to='Customer.customer')),
],
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 4.2 on 2023-05-02 10:47
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('Customer', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='customer',
name='TimeCreated',
field=models.DateTimeField(auto_now_add=True),
),
]

View File

@ -0,0 +1,19 @@
# Generated by Django 4.2 on 2023-05-02 10:51
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('Customer', '0002_alter_customer_timecreated'),
]
operations = [
migrations.AlterField(
model_name='customer',
name='Parent',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='Customer.customer'),
),
]

View File

@ -0,0 +1,20 @@
# Generated by Django 4.2 on 2023-05-08 06:06
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('Item', '0008_alter_pricelevelitem_pl'),
('Customer', '0003_alter_customer_parent'),
]
operations = [
migrations.AddField(
model_name='customer',
name='PriceLevelRefFullName',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='PriceList', to='Item.pricelevel'),
),
]

View File

@ -0,0 +1,48 @@
# Generated by Django 4.2 on 2023-05-13 18:32
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('Customer', '0004_customer_pricelevelreffullname'),
]
operations = [
migrations.AlterField(
model_name='customer',
name='Coordinates',
field=models.CharField(blank=True, max_length=30, null=True),
),
migrations.AlterField(
model_name='customer',
name='DMS_Cust_Code',
field=models.CharField(blank=True, max_length=80, null=True),
),
migrations.AlterField(
model_name='customer',
name='DMS_Cust_Name',
field=models.CharField(blank=True, max_length=80, null=True),
),
migrations.AlterField(
model_name='customer',
name='EFaktur_Name',
field=models.CharField(blank=True, max_length=80, null=True),
),
migrations.AlterField(
model_name='customer',
name='Efaktur_Address',
field=models.CharField(blank=True, max_length=80, null=True),
),
migrations.AlterField(
model_name='customer',
name='KTP',
field=models.CharField(blank=True, max_length=16, null=True),
),
migrations.AlterField(
model_name='customer',
name='NPWP',
field=models.CharField(blank=True, max_length=20, null=True),
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 4.2 on 2023-05-19 15:33
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('Customer', '0005_alter_customer_coordinates_and_more'),
]
operations = [
migrations.AlterField(
model_name='customer',
name='Salutation',
field=models.CharField(choices=[('Mr', 'Mr.'), ('Mrs', 'Mrs.')], max_length=4),
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 4.2 on 2023-08-31 10:31
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('Customer', '0006_alter_customer_salutation'),
]
operations = [
migrations.AlterField(
model_name='customer',
name='CustomerFullName',
field=models.CharField(max_length=160, unique=True),
),
]

View File

97
django/Customer/models.py Normal file
View File

@ -0,0 +1,97 @@
from django.db import models
from django.urls import reverse
from Item.models import PriceLevel
class Customer(models.Model):
MR = 'Mr'
MRS = 'Mrs'
SALUTATION_CHOICE = [
(MR, 'Mr.'),
(MRS, 'Mrs.'),
]
CustomerName = models.CharField(max_length=80)
CustomerFullName = models.CharField(max_length=160, unique=True)
CustomerIsActive = models.BooleanField(default=True)
Parent = models.ForeignKey("Customer", on_delete=models.DO_NOTHING, blank=True, null=True)
Sublevel = models.PositiveSmallIntegerField(default=0)
CompanyName = models.CharField(max_length=80)
Salutation = models.CharField(max_length=4, choices=SALUTATION_CHOICE)
FirstName = models.CharField(max_length=80)
MiddleName = models.CharField(max_length=80, blank=True, null=True)
LastName = models.CharField(max_length=80, blank=True, null=True)
BillAddr1 = models.CharField(max_length=80)
BillAddr2 = models.CharField(max_length=80, blank=True, null=True)
BillAddr3 = models.CharField(max_length=80, blank=True, null=True)
BillAddr4 = models.CharField(max_length=80, blank=True, null=True)
BillAddr5 = models.CharField(max_length=80, blank=True, null=True)
BillCity = models.CharField(max_length=80, blank=True, null=True)
BillState = models.CharField(max_length=80, blank=True, null=True)
BillPostalCode = models.CharField(max_length=80, blank=True, null=True)
BillCountry = models.CharField(max_length=80, default="Indonesia")
BillNote = models.CharField(max_length=80, blank=True, null=True)
ShipAddr1 = models.CharField(max_length=80, blank=True, null=True)
ShipAddr2 = models.CharField(max_length=80, blank=True, null=True)
ShipAddr3 = models.CharField(max_length=80, blank=True, null=True)
ShipAddr4 = models.CharField(max_length=80, blank=True, null=True)
ShipAddr5 = models.CharField(max_length=80, blank=True, null=True)
ShipCity = models.CharField(max_length=80, blank=True, null=True)
ShipState = models.CharField(max_length=80, blank=True, null=True)
ShipPostalCode = models.CharField(max_length=80, blank=True, null=True)
ShipCountry = models.CharField(max_length=80, blank=True, null=True)
ShipNote = models.CharField(max_length=200, blank=True, null=True)
Phone = models.CharField(max_length=80, blank=True, null=True)
Contact = models.CharField(max_length=80)
# CustomerTypeRefFullName
# TermsRefFullName
# SalesRepRefFullName
# Balance
# TotalBalance
# SalesTaxCodeRefFullName
# ItemSalesTaxRefFullName
# CreditCardNo
# ExpirationMonth
# ExpirationYear
# NameOnCard
# CreditCardAddress
# CreditCardPostalCode
# JobStatus
# JobStartDate
# JobProjectedEndDate
# JobEndDate
# JobTypeRefFullName
Notes = models.CharField(max_length=200, blank=True, null=True)
PriceLevelRefFullName = models.ForeignKey("Item.PriceLevel", related_name="PriceList", on_delete=models.SET_NULL, blank=True, null=True)
# CurrencyRefFullName
AltPhone = models.CharField(max_length=25, blank=True, null=True)
Fax = models.CharField(max_length=25, blank=True, null=True)
Email = models.CharField(max_length=50, blank=True, null=True)
AltContact = models.CharField(max_length=50, blank=True, null=True)
# ResaleNumber
# AccountNumber
CreditLimit = models.DecimalField(max_digits=12, decimal_places=2, blank=True, null=True)
# PreferredPaymentMethodRefFullName
NPWP = models.CharField(max_length=20, blank=True, null=True)
KTP = models.CharField(max_length=16, blank=True, null=True)
DMS_Cust_Name = models.CharField(max_length=80, blank=True, null=True)
DMS_Cust_Code = models.CharField(max_length=80, blank=True, null=True)
Special_Cust = models.BooleanField(default=False)
EFaktur_Name = models.CharField(max_length=80, blank=True, null=True)
Efaktur_Address = models.CharField(max_length=80, blank=True, null=True)
Coordinates = models.CharField(max_length=30, blank=True, null=True)
TimeCreated = models.DateTimeField(auto_now_add=True)
TimeModified = models.DateTimeField(auto_now=True)
def __str__(self):
return f"{self.CustomerName}; {self.PriceLevelRefFullName}"
def get_field_name(obj):
# return [(f.name, f.value_to_string(obj)) for f in obj._meta.fields] #get value convert it to string
return [(f.verbose_name, f.name, f.value_from_object(obj)) for f in obj._meta.fields]
def get_absolute_url(self):
return reverse('Customer:edit_customer', args=[str(self.id)])

View File

@ -0,0 +1,12 @@
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% block title %}{{title}}{% endblock title %}
{% block body %}
<form method="POST" action="">
{% csrf_token %}
{{form|crispy}}
{% comment %} {{form.CustomerName|as_crispy_field}} {% endcomment %}
<button type="submit">submit</button>
</form>
{% endblock body %}

View File

@ -0,0 +1,62 @@
{% extends 'base.html' %}
{% block title %}test obj{% endblock title %}
{% block search_nav %}<form class="d-flex" role="search" action="" method="GET">
<input onfocusout="focusout(this)" id="source" list="itemname" class="form-control me-2" type="search" placeholder="Search" aria-label="Search" name="q">
<button class="btn btn-outline-success" type="submit">Search</button>
</form>
{% endblock search_nav %}
{% block body %}
{% comment %} {{objects}} {% endcomment %}
{{objects.count}}
<datalist id="itemname">
{% for obj in objects %}
{% comment %} {{obj.0}} {% endcomment %}
{% if obj.itempricelevel__Price %}
<option value="{{obj.FullName}}" data-price="{{obj.itempricelevel__Price}}"></option>
{% else %}
<option value="{{obj.FullName}}" data-price="{{obj.SalesPrice}}"></option>
{% endif %}
{% endfor %}
</datalist>
{% comment %} {% for obj in objects %}
{{obj}}
{% endfor %} {% endcomment %}
<div>
<input id="priceid" class="form-control me-2" value = "0">
</div>
<div id="result">
test
</div>
<script>
const source = document.getElementById('source');
const result = document.getElementById('result');
const itemname = document.getElementById('itemname');
function focusout(e){
let Text = document.querySelector('option[value="' + e.value + '"]');
if (Text){
console.log(e.value);
console.log(Text.getAttribute('data-price'));
document.getElementById('priceid').value = Text.getAttribute('data-price');
}
else {
console.log("element not exist");
document.getElementById('priceid').value = 0;
}
}
const inputHandler = function(e) {
console.log(e.target.Text);
result.innerHTML = e.target.value;
}
source.addEventListener('input', inputHandler);
source.addEventListener('propertychange', inputHandler);
</script>
{% endblock body %}

View File

@ -0,0 +1 @@
{% include 'Item/table_index.html' with title="Customer Page" %}

3
django/Customer/tests.py Normal file
View File

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

9
django/Customer/urls.py Normal file
View File

@ -0,0 +1,9 @@
from django.urls import path, include
from .views import index, edit_customer, add_customer, delete_customer
app_name = "Customer"
urlpatterns = [
path('', index, name="index" ),
path('edit/<int:pk>', edit_customer, name="edit_customer" ),
path('add/', add_customer, name="add_customer" ),
path('delete/<int:pk>', delete_customer, name="delete_customer" ),
]

77
django/Customer/views.py Normal file
View File

@ -0,0 +1,77 @@
from django.shortcuts import render, redirect, get_object_or_404
from django.urls import reverse
from .models import Customer
from django.db.models import Q
from django.core.paginator import Paginator
# from Item.models import Item, PriceLevel, PriceLevelItem
from .forms import CustomerForm
# def index(request):
# context={}
# qs1 = Item.objects.filter(itempricelevel__PL__Name='B2020',).prefetch_related("itempricelevel").values('FullName','SalesPrice', 'itempricelevel__Price')
# qs2 = Item.objects.exclude(itempricelevel__PL__Name='B2020').prefetch_related("itempricelevel").values( "FullName", "SalesPrice", "AlwaysNull")
# print(qs2)
# qs = qs1.union(qs2)
# print(type(qs))
# print(qs)
# context['objects'] = qs
# return render(request, "Customer/index.html", context=context)
def index(request):
context={}
search = request.GET.get("q")
customers=Customer.objects.all().order_by('CustomerFullName')
print(customers)
if search:
customer = Customer.objects.order_by('CustomerFullName').filter(Q(CustomerName__icontains=search) | Q(CustomerFullName__icontains=search))
else:
customer = Customer.objects.order_by('CustomerFullName')
paginator = Paginator(customer, 25) # Show 25 contacts per page.
page_number = request.GET.get("page")
page_obj = paginator.get_page(page_number)
# heads = [f.name for f in Customer._meta.get_fields()]
# print(heads)
print(customer)
print(page_obj[0].CustomerName)
context['objects'] = page_obj
context['customers'] = customers
context['addurl'] = reverse('Customer:add_customer')
return render(request, "Customer/index.html", context=context)
def edit_customer(request, pk):
print("edit customer")
print(pk)
print(request)
customer = get_object_or_404(Customer, pk=pk)
form = CustomerForm( request.POST or None, instance=customer)
if request.method == "GET":
print("GET")
if customer:
# form = CustomerForm(instance=customer)
return render(request, "Customer/addedit.html", {"objects": [customer,], "form":form})
elif request.method == "POST":
print("POST")
# form = CustomerForm(request.POST, instance=customer)
if form.is_valid():
print("form is valid")
customer=form.save()
# return redirect(reverse('Customer:edit_customer', kwargs={"pk":pk}))
return render(request, "Customer/index.html", {"objects": [customer]})
else:
print("not valid form")
return render(request, "Customer/addedit.html", {"objects": [customer,], "form":form})
def add_customer(request):
print("add customer")
form = CustomerForm(request.POST or None)
if request.POST:
# print(form["CustomerName"].value())
if form.is_valid():
# print(form.cleaned_data["CustomerName"])
form.save()
return redirect(reverse("Customer:index"))
# print(form["CustomerName"].value())
return render(request, "Customer/addedit.html", {"form":form})
def delete_customer(request, pk):
print("delete customer")

View File

16
django/Inventory/asgi.py Normal file
View File

@ -0,0 +1,16 @@
"""
ASGI config for Inventory project.
It exposes the ASGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/4.2/howto/deployment/asgi/
"""
import os
from django.core.asgi import get_asgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'Inventory.settings')
application = get_asgi_application()

View File

@ -0,0 +1,143 @@
"""
Django settings for Inventory project.
Generated by 'django-admin startproject' using Django 4.2.
For more information on this file, see
https://docs.djangoproject.com/en/4.2/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/4.2/ref/settings/
"""
from pathlib import Path
import os
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'django-insecure-u(al(30azswvgyf($b)cz-%h$8hl@o&i9glc9iv)!ikopl1!s-'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'debug_toolbar',
"crispy_forms",
"crispy_bootstrap5",
"crispy_bootstrap4",
'Item',
'SalesOrder',
'Invoice',
'Customer',
'django.contrib.humanize',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'debug_toolbar.middleware.DebugToolbarMiddleware',
]
ROOT_URLCONF = 'Inventory.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [BASE_DIR / 'templates'],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
WSGI_APPLICATION = 'Inventory.wsgi.application'
# Database
# https://docs.djangoproject.com/en/4.2/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
# Password validation
# https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
# Internationalization
# https://docs.djangoproject.com/en/4.2/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'Asia/Jakarta'
USE_I18N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/4.2/howto/static-files/
STATIC_URL = 'static/'
# Default primary key field type
# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
INTERNAL_IPS = [
'127.0.0.1',
]
CRISPY_ALLOWED_TEMPLATE_PACKS = "bootstrap5"
CRISPY_TEMPLATE_PACK = "bootstrap5"

33
django/Inventory/urls.py Normal file
View File

@ -0,0 +1,33 @@
"""
URL configuration for Inventory project.
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/4.2/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path, include
from django.conf import settings
urlpatterns = [
path('admin/', admin.site.urls),
# path('', include("SalesOrder.urls")),
path('customer/', include("Customer.urls")),
path('item/', include("Item.urls")),
path('so/', include("SalesOrder.urls")),
path('inv/', include("Invoice.urls")),
]
if settings.DEBUG:
import debug_toolbar
urlpatterns += path('__debug__/', include(debug_toolbar.urls)),

16
django/Inventory/wsgi.py Normal file
View File

@ -0,0 +1,16 @@
"""
WSGI config for Inventory project.
It exposes the WSGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/4.2/howto/deployment/wsgi/
"""
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'Inventory.settings')
application = get_wsgi_application()

View File

3
django/Invoice/admin.py Normal file
View File

@ -0,0 +1,3 @@
from django.contrib import admin
# Register your models here.

6
django/Invoice/apps.py Normal file
View File

@ -0,0 +1,6 @@
from django.apps import AppConfig
class InvoiceConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'Invoice'

54
django/Invoice/forms.py Normal file
View File

@ -0,0 +1,54 @@
from django.forms import ModelForm
from django import forms
from .models import Invoice, InvoiceItemLine
from crispy_forms.helper import FormHelper
class InvoiceForm(ModelForm):
class Meta:
model = Invoice
fields = "__all__"
widgets = {
'TxnDate' : forms.DateInput(attrs={'type':"date"}),
'BillAddr1' : forms.Textarea(attrs={'rows':7, 'style':'height:180px'}),
'ShipAddr1' : forms.Textarea(attrs={'rows':7, 'style':'height:180px'}),
'TotalAmount' : forms.TextInput(attrs={'class':'text-end hidden', 'onkeypress':'return event.preventDefault()'})
}
def __init__(self, *args, **kwargs):
super(InvoiceForm, self).__init__(*args, **kwargs)
self.helper = FormHelper(self)
# self.helper.form_show_labels = False
self.fields['TotalAmount'].label = False
self.fields['TotalAmount'].field_class = ''
class InvoiceItemLineForm(ModelForm):
class Meta:
model = InvoiceItemLine
fields = ('ItemRefFullName', 'Desc', 'Quantity', 'UnitOfMeasure', 'Rate', 'Amount', 'Invoiced', 'LineIsManuallyClosed')
# fields = "__all__"
widgets = {
# 'ItemRefFullName' : forms.Select(choices=[('1', '1')]),
'ItemRefFullName' : forms.NumberInput(attrs={'class':'hidden itemreffullname'}),
'Desc' : forms.TextInput(attrs={'class':'desc'}),
'Quantity' : forms.TextInput(attrs={'class':'quantity','onkeypress':'numberOnly(event)'}), #'onkeypress':'return (event.charCode >= 48 && event.charCode <= 57) || event.charCode == 46'}),
'UnitOfMeasure' : forms.Select(attrs={'class':'unitofmeasure'}),
'Rate' : forms.TextInput(attrs={'class':'rate text-end', 'onkeypress':'numberOnly(event)'}),
'Amount' : forms.TextInput(attrs={'class':'amount text-end', 'onkeypress':'numberOnly(event)', 'onchange':'amountchanged(event)'}),
}
def __init__(self, *args, **kwargs):
super(InvoiceItemLineForm, self).__init__(*args, **kwargs)
self.helper = FormHelper(self)
self.helper.form_show_labels = False
# self.helper.form_class = "abc"
# self.helper.field_class = "xyz"
DEMO_CHOICES =(
("1", "Naveen"),
("2", "Pranav"),
("3", "Isha"),
("4", "Saloni"),
)
class GeeksForm(forms.Form):
geeks_field = forms.MultipleChoiceField(widget=forms.CheckboxSelectMultiple, choices = DEMO_CHOICES)

View File

@ -0,0 +1,83 @@
# Generated by Django 4.2 on 2023-08-31 10:31
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
('Customer', '0007_alter_customer_customerfullname'),
('Item', '0010_alter_pricelevelitem_price'),
]
operations = [
migrations.CreateModel(
name='Invoice',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('TxnDate', models.DateField()),
('RefNumber', models.CharField(max_length=30, verbose_name='S.O. No.')),
('BillAddr1', models.CharField(max_length=80, verbose_name='Name/Address')),
('BillAddr2', models.CharField(blank=True, max_length=80, null=True)),
('BillAddr3', models.CharField(blank=True, max_length=80, null=True)),
('BillAddr4', models.CharField(blank=True, max_length=80, null=True)),
('BillAddr5', models.CharField(blank=True, max_length=80, null=True)),
('BillCity', models.CharField(blank=True, max_length=80, null=True)),
('BillState', models.CharField(blank=True, max_length=80, null=True)),
('BillPostalCode', models.CharField(blank=True, max_length=80, null=True)),
('BillCountry', models.CharField(blank=True, default='Indonesia', max_length=80, null=True)),
('BillNote', models.CharField(blank=True, max_length=80, null=True)),
('ShipAddr1', models.CharField(blank=True, max_length=80, null=True, verbose_name='Ship To')),
('ShipAddr2', models.CharField(blank=True, max_length=80, null=True)),
('ShipAddr3', models.CharField(blank=True, max_length=80, null=True)),
('ShipAddr4', models.CharField(blank=True, max_length=80, null=True)),
('ShipAddr5', models.CharField(blank=True, max_length=80, null=True)),
('ShipCity', models.CharField(blank=True, max_length=80, null=True)),
('ShipState', models.CharField(blank=True, max_length=80, null=True)),
('ShipPostalCode', models.CharField(blank=True, max_length=80, null=True)),
('ShipCountry', models.CharField(blank=True, max_length=80, null=True)),
('ShipNote', models.CharField(blank=True, max_length=200, null=True)),
('PONumber', models.CharField(blank=True, max_length=30, null=True, verbose_name='PO. No.')),
('TermsRefFullName', models.CharField(blank=True, max_length=10, null=True, verbose_name='Terms')),
('SalesRepRefFullName', models.CharField(blank=True, max_length=10, null=True, verbose_name='REP')),
('ShipDate', models.DateTimeField(blank=True, null=True)),
('DueDate', models.DateField(blank=True, null=True)),
('TotalAmount', models.DecimalField(blank=True, decimal_places=2, max_digits=14, null=True)),
('CustomerMsgRefFullName', models.CharField(blank=True, max_length=120, null=True)),
('IsToBePrinted', models.BooleanField(default=False)),
('IsToBeEmailed', models.BooleanField(default=False)),
('IsManuallyClosed', models.BooleanField(default=False)),
('IsFullyInvoiced', models.BooleanField(default=False)),
('Memo', models.CharField(blank=True, max_length=120, null=True)),
('NPWP', models.CharField(blank=True, max_length=20, null=True)),
('KTP', models.CharField(blank=True, max_length=16, null=True)),
('DMS_Cust_Name', models.CharField(blank=True, max_length=80, null=True)),
('DMS_Cust_Code', models.CharField(blank=True, max_length=80, null=True)),
('Special_Cust', models.BooleanField(default=False)),
('EFaktur_Name', models.CharField(blank=True, max_length=80, null=True)),
('Efaktur_Address', models.CharField(blank=True, max_length=80, null=True)),
('Coordinates', models.CharField(blank=True, max_length=30, null=True)),
('TimeCreated', models.DateTimeField(auto_now_add=True)),
('TimeModified', models.DateTimeField(auto_now=True)),
('CustomerRefFullName', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='Customer.customer')),
],
),
migrations.CreateModel(
name='InvoiceItemLine',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('Desc', models.CharField(blank=True, max_length=80, null=True)),
('Quantity', models.DecimalField(blank=True, decimal_places=2, max_digits=6, null=True)),
('Rate', models.DecimalField(blank=True, decimal_places=2, max_digits=11, null=True)),
('Amount', models.DecimalField(blank=True, decimal_places=2, max_digits=14, null=True)),
('Invoiced', models.DecimalField(blank=True, decimal_places=2, max_digits=6, null=True)),
('LineIsManuallyClosed', models.BooleanField(blank=True, default=False, null=True)),
('Invoice', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='Invoice.invoice')),
('ItemRefFullName', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='Item.item')),
('UnitOfMeasure', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='Item.uom', verbose_name='UOM')),
],
),
]

View File

135
django/Invoice/models.py Normal file
View File

@ -0,0 +1,135 @@
from django.db import models
from django.urls import reverse
from Item.models import Item, UOM
from Customer.models import Customer
class Invoice(models.Model):
CustomerRefFullName = models.ForeignKey(Customer, on_delete=models.PROTECT)
# TxnNumber
# ClassRefFullName
# TemplateRefFullName
TxnDate = models.DateField()
RefNumber = models.CharField(max_length=30, verbose_name="S.O. No.")
BillAddr1 = models.CharField(max_length=80, verbose_name="Name/Address")
BillAddr2 = models.CharField(max_length=80, blank=True, null=True)
BillAddr3 = models.CharField(max_length=80, blank=True, null=True)
BillAddr4 = models.CharField(max_length=80, blank=True, null=True)
BillAddr5 = models.CharField(max_length=80, blank=True, null=True)
BillCity = models.CharField(max_length=80, blank=True, null=True)
BillState = models.CharField(max_length=80, blank=True, null=True)
BillPostalCode = models.CharField(max_length=80, blank=True, null=True)
BillCountry = models.CharField(max_length=80, default="Indonesia", blank=True, null=True)
BillNote = models.CharField(max_length=80, blank=True, null=True)
# Addr1 =
# Addr2
# Addr3
ShipAddr1 = models.CharField(max_length=80, verbose_name="Ship To", blank=True, null=True)
ShipAddr2 = models.CharField(max_length=80, blank=True, null=True)
ShipAddr3 = models.CharField(max_length=80, blank=True, null=True)
ShipAddr4 = models.CharField(max_length=80, blank=True, null=True)
ShipAddr5 = models.CharField(max_length=80, blank=True, null=True)
ShipCity = models.CharField(max_length=80, blank=True, null=True)
ShipState = models.CharField(max_length=80, blank=True, null=True)
ShipPostalCode = models.CharField(max_length=80, blank=True, null=True)
ShipCountry = models.CharField(max_length=80, blank=True, null=True)
ShipNote = models.CharField(max_length=200, blank=True, null=True)
# ShipAddr1
# ShipAddr2
# ShipAddr3
# ShipAddr4
# ShipCity
# ShipState
# ShipPostalCode
# ShipCountry
# City
# State
# PostalCode
# Country_Note
PONumber = models.CharField(max_length=30, verbose_name="PO. No.", blank=True, null=True)
TermsRefFullName = models.CharField(max_length=10, verbose_name="Terms", blank=True, null=True)
SalesRepRefFullName = models.CharField(max_length=10, verbose_name="REP", blank=True, null=True)
ShipDate = models.DateTimeField(blank=True, null=True)
# ShipMethodRefFullName =
DueDate = models.DateField(blank=True, null=True)
# Subtotal = models.DecimalField(max_digits=14, decimal_places=2, blank=True, null=True)
# ItemSalesTaxRefFullName
# SalesTaxPercentage
# SalesTaxTotal
# CurrencyRefFullName
TotalAmount = models.DecimalField(max_digits=14, decimal_places=2, blank=True, null=True )
# ExchangeRate
# TotalAmountInHomeCurrency
CustomerMsgRefFullName = models.CharField(max_length=120, blank=True, null=True)
IsToBePrinted = models.BooleanField(default=False)
IsToBeEmailed = models.BooleanField(default=False)
# CustomerSalesTaxCodeRefFullName
# Other
# FOB
IsManuallyClosed = models.BooleanField(default=False)
IsFullyInvoiced = models.BooleanField(default=False)
Memo = models.CharField(max_length=120, blank=True, null=True)
# LinkedTxnID
# TxnLineID = models.ForeignKey(InvoiceItemLine, ondelete=models.DO_NOTHING)
NPWP = models.CharField(max_length=20, blank=True, null=True)
KTP = models.CharField(max_length=16, blank=True, null=True)
DMS_Cust_Name = models.CharField(max_length=80, blank=True, null=True)
DMS_Cust_Code = models.CharField(max_length=80, blank=True, null=True)
Special_Cust = models.BooleanField(default=False)
EFaktur_Name = models.CharField(max_length=80, blank=True, null=True)
Efaktur_Address = models.CharField(max_length=80, blank=True, null=True)
Coordinates = models.CharField(max_length=30, blank=True, null=True)
TimeCreated = models.DateTimeField(auto_now_add=True)
TimeModified = models.DateTimeField(auto_now=True)
def __str__(self):
return self.RefNumber
def get_field_name(obj):
# return [(f.name, f.value_to_string(obj)) for f in obj._meta.fields] #get value convert it to string
return [(f.verbose_name, f.name, f.value_from_object(obj)) for f in obj._meta.fields]
def get_absolute_url(self):
return reverse('Invoice:edit_so', args=[str(self.id)])
def save(self, *args, **kwargs):
super().save(*args, **kwargs)
class InvoiceItemLine(models.Model):
Invoice = models.ForeignKey(Invoice, on_delete=models.PROTECT)
ItemRefFullName = models.ForeignKey(Item, on_delete=models.PROTECT)
Desc = models.CharField(max_length=80, blank=True, null=True)
Quantity = models.DecimalField(max_digits=6, decimal_places=2, blank=True, null=True)
UnitOfMeasure = models.ForeignKey(UOM, verbose_name="UOM", on_delete=models.DO_NOTHING, blank=True, null=True)
# OverrideUOMFullName
Rate = models.DecimalField(max_digits=11, decimal_places=2, blank=True, null=True)
Amount = models.DecimalField(max_digits=14, decimal_places=2, blank=True, null=True)
# InventorySiteRefFullName
# SerialNumber
# LotNumber
# SalesTaxCodeRefFullName
# Other1
# Other2
Invoiced = models.DecimalField(max_digits=6, decimal_places=2, blank=True, null=True) #how many qty that has invoiced
LineIsManuallyClosed = models.BooleanField(default=False, blank=True, null=True)
# LineClass
# GroupTxnLineID
# GroupItemFullName
# GroupDesc
# GroupQuantity
# IsPrintItemsInGroup
# RatePercent
# GroupLineTxnLineID
# GroupLineItemFullName
# GroupLineDesc
# GroupLineQuantity
# GroupLineUOM
# GroupLineOverrideUOM
# GroupLineRate
# GroupLineAmount
# GroupLineServiceDate
# GroupLineSalesTaxCodeFullName

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,525 @@
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% load humanize %}
{% 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">
{% csrf_token %}
<div class="row">
<div class="col-6">{{form.CustomerRefFullName|as_crispy_field}}</div>
</div>
<div class="row">
<div class="col-sm">{{form.BillAddr1|as_crispy_field}}</div>
<div class="col">
<div class="row">
<div class="col-sm">{{form.TxnDate|as_crispy_field}}</div>
<div class="col">{{form.RefNumber|as_crispy_field}}</div>
</div>
<div class="row">
<div class="col">{{form.PONumber|as_crispy_field}}</div>
</div>
<div class="row">
<div class="col">{{form.SalesRepRefFullName|as_crispy_field}}</div>
</div>
</div>
<div class="col">{{form.ShipAddr1|as_crispy_field}}</div>
</div>
{{form.TotalAmount}}
{% comment %} <div >{{form.IsToBePrinted.as_hidden}}</div>
<div >{{form.IsToBeEmailed.as_hidden}}</div>
<div >{{form.IsManuallyClosed.as_hidden}}</div> {% endcomment %}
<div >{{form.KTP.as_hidden}}</div>
<div >{{form.NPWP.as_hidden}}</div>
<div >{{form.DMS_Cust_Name.as_hidden}}</div>
<div >{{form.DMS_Cust_Code.as_hidden}}</div>
<div >{{form.Special_Cust.as_hidden}}</div>
<div >{{form.EFaktur_Name.as_hidden}}</div>
<div >{{form.Efaktur_Address.as_hidden}}</div>
<div class="col">{{form.Coordinates.as_hidden}}</div>
<hr style="border: 1px solid #007bff">
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
{% if formset %}
{{ formset.management_form }}
<div class="row">
<div class="col-2 text-center mb-1">ItemRefFullName*</div>
<div class="col-3 text-center">Description</div>
<div class="col-1 text-center">Qty</div>
<div class="col-1 text-center">UOM</div>
<div class="col-2 text-center">Rate</div>
<div class="col">
<div class='row'>
<div class='col-10 text-end'>
Amount</div>
<div class='col text-end'>Del</div>
</div>
</div>
<div id='itemline-form-list'>
{% comment %} {% for form in formset %} {% endcomment %}
{% for qs, form in qsformset %}
<div class='itemline-form'>
{{form.id}}
{% comment %} {{form.ItemRefFullName.field}} {% endcomment %}
<div class="row parentrow">
<div class="col-2">
<div id='div_id_form-{{forloop.counter0}}-inputitem' class='mb-1'>
{% comment %} <label for="id_form-{{forloop.counter0}}-inputitem" class="form-label requiredField"> ItemRefFullName<span class="asteriskField">*</span>
</label> {% endcomment %}
<div></div>
<input type='text' list='itemname' onchange='changeitem(event)' value='{{qs.ItemRefFullName}}' class='textinput form-control inputitem'
id='id_form-{{forloop.counter0}}-inputitem'>
</div>
</div>
<div class="col hidden">{{form.ItemRefFullName|as_crispy_field}}</div>
<div class="col-3" onchange='descchanged(event)'>{{form.Desc|as_crispy_field}}</div>
<div class="col-1" onchange='qtychanged(event)'>{{form.Quantity|as_crispy_field}}</div>
<div class="col-1">{{form.UnitOfMeasure|as_crispy_field}}</div>
<div class="col-2" onchange='ratechanged(event)'>{{form.Rate|as_crispy_field}}</div>
<div class="col">
<div class="row">
<div class='col text-end' onchange='amountchanged(event)'>{{form.Amount|as_crispy_field}}</div>
<div class="col-1 mt-1" onchange='deletechanged(event)' onclick='return confirm("Are you sure DELETE this Item Line?")'>{{form.DELETE|as_crispy_field}}</div>
</div>
</div>
{{form.Invoiced.as_hidden}}
{{form.LineIsManuallyClosed.as_hidden}}
</div>
</div>
{% endfor %}
</div>
<br>
{% endif %}
<div class="row justify-content-between ">
<div class="col-5 mt-3">
<button type="button" class="btn btn-primary me-2" id='add-more'>+ More ItemLine</button>
<button type="submit" class="btn btn-primary me-2 ms-2" id="id_btnsave" onclick="checksubmit(event)">Save</button>
<button type="button" class="btn btn-primary me-2 ms-2" onclick="revert()" id="id_btnrevert">Revert</button>
{% comment %} <div class="col-4"> {% endcomment %}
</div>
<div class='col text-end mt-3 fs-5 fw-bold'>
Total Amount Rp.
</div>
<div id='div_id_TotalAmount' class='col col-md-4 mb-1 mt-2 text-end mt-3 me-4 fs-5 fw-bold'>{{form.TotalAmount.value|intcomma}}
{% comment %} <input type='text' name='TotalAmount' value="{{form.Amount.value|intcomma}}" class='hidden text-end fs-5 form-control' id='id_TotalAmount' readonly> {% endcomment %}
</div>
{% comment %} <div class='col-1'></div> {% endcomment %}
</div>
</div>
</form>
<div id='empty-form' class='hidden'>
<div class="row parentrow">
<div class="col-2">
<div id='div_id_form-__prefix__-inputitem' class='mb-1'>
{% comment %} <label for="id_form-__prefix__-inputitem" class="form-label requiredField"> ItemRefFullName<span class="asteriskField">*</span>
</label> {% endcomment %}
<input type='text' list='itemname' onchange='changeitem(event)' value='{{qs.ItemRefFullName}}' class='textinput form-control'
id='id_form-__prefix__-inputitem'>
</div>
</div>
<div class="col hidden">{{formset.empty_form.ItemRefFullName|as_crispy_field}}</div>
<div class="col-3">{{formset.empty_form.Desc|as_crispy_field}}</div>
<div class="col-1" onchange='qtychanged(event)'>{{formset.empty_form.Quantity|as_crispy_field}}</div>
<div class="col-1">{{formset.empty_form.UnitOfMeasure|as_crispy_field}}</div>
<div class="col-2" onchange='ratechanged(event)'>{{formset.empty_form.Rate|as_crispy_field}}</div>
{% comment %} <div class="col" onchange='amountchanged(event)'>{{formset.empty_form.Amount|as_crispy_field}}</div> {% endcomment %}
{% comment %} <div class="col">{{formset.empty_form.DELETE|as_crispy_field}}</div> {% endcomment %}
<div class="col">
<div class="row">
<div class='col text-end' onchange='amountchanged(event)'>{{formset.empty_form.Amount|as_crispy_field}}</div>
<div class="col-1 mt-1" onchange='deletechanged(event)'>{{formset.empty_form.DELETE|as_crispy_field}}</div>
</div>
</div>
{{formset.empty_form.Invoiced.as_hidden}}
{{formset.empty_form.LineIsManuallyClosed.as_hidden}}
</div>
</div>
</div>
<datalist id='itemname'>
{% for item in itemdatalist %}
<option value="{{item.FullName}}" data-pk="{{item.id}}" data-desc="{{item.SalesDesc}}" data-rate="{{item.SalesPrice}}">
{% endfor %}
</datalist>
<script>
document.getElementById('id_CustomerRefFullName').addEventListener('focusout', function() {
console.log(this.value);
if (this.value == '') {
return};
let str='';
let url="{% url 'Invoice:getpricelist' %}"+this.value
console.log(url)
fetch(url)
.then((response) => {
return response.json();
})
.then((data) => {
//console.log(data);
data=JSON.parse(data);
let dt=JSON.parse(data['itemdatalist']);
console.log(dt)
console.log(dt.length)
for (let k=0;k<dt.length;k++){
//console.log(dt[k]);
//console.log("dt[k]")
if (dt[k].itempricelevel__Price) {
str+='<option value="' + dt[k].FullName + '" data-pk="' + dt[k].id + '" data-desc="' + dt[k].SalesDesc + '" data-rate="' + dt[k].itempricelevel__Price + '">';
} else {
str+='<option value="' + dt[k].FullName + '" data-pk="' + dt[k].id + '" data-desc="' + dt[k].SalesDesc + '" data-rate="' + dt[k].SalesPrice + '">';
}
}
//console.log(str);
dt=JSON.parse(data['obj']);
console.log(dt)
console.log(dt.length)
document.getElementById('itemname').innerHTML = str;
str='';
for (let k=0;k<dt.length;k++){
console.log(dt[0].pk);
console.log(dt[0].fields.BillAddr1);
str= dt[0].fields.BillAddr1;
if (dt[0].fields.BillAddr2) {str+="\n"+dt[0].fields.BillAddr2}
if (dt[0].fields.BillAddr3) {str+="\n"+dt[0].fields.BillAddr3}
if (dt[0].fields.BillAddr4) {str+="\n"+dt[0].fields.BillAddr4}
if (dt[0].fields.BillAddr5) {str+="\n"+dt[0].fields.BillAddr5}
document.getElementById('id_BillAddr1').value = str
str=dt[0].fields.ShipAddr1;
if (dt[0].fields.ShipAddr2) {str+="\n"+dt[0].fields.ShipAddr2}
if (dt[0].fields.ShipAddr3) {str+="\n"+dt[0].fields.ShipAddr3}
if (dt[0].fields.ShipAddr4) {str+="\n"+dt[0].fields.ShipAddr4}
if (dt[0].fields.ShipAddr5) {str+="\n"+dt[0].fields.ShipAddr5}
document.getElementById('id_ShipAddr1').value = str;
//document.getElementById('id_ShipAddr1').value = dt[0].fields.ShipAddr1;
}
});
console.log(str)
//for (let i=0;i<12;i++){
// str+= '<option value="' + i + '">';
//}
//document.getElementById('itemname').innerHTML = str;
});
function customerChanged(e){
console.log(e)
}
</script>
<script>
function number_format( number, decimals, dec_point, thousands_sep ) {
// http://kevin.vanzonneveld.net
// + original by: Jonas Raoni Soares Silva (http://www.jsfromhell.com)
// + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
// + bugfix by: Michael White (http://crestidg.com)
// + bugfix by: Benjamin Lupton
// + bugfix by: Allan Jensen (http://www.winternet.no)
// + revised by: Jonas Raoni Soares Silva (http://www.jsfromhell.com)
// * example 1: number_format(1234.5678, 2, '.', '');
// * returns 1: 1234.57
var n = number, c = isNaN(decimals = Math.abs(decimals)) ? 2 : decimals;
var d = dec_point == undefined ? "," : dec_point;
var t = thousands_sep == undefined ? "." : thousands_sep, s = n < 0 ? "-" : "";
var i = parseInt(n = Math.abs(+n || 0).toFixed(c)) + "", j = (j = i.length) > 3 ? j % 3 : 0;
return s + (j ? i.substr(0, j) + t : "") + i.substr(j).replace(/(\d{3})(?=\d)/g, "$1" + t) + (c ? d + Math.abs(n - i).toFixed(c).slice(2) : "");
}
</script>
<script>
var totalAmount = 0;
var boloktosave = 0;
function revert(){
document.getElementById("form").reset();
findTotalAmount()
}
function numberOnly(event){
//console.log(event.cancelable);
if ((event.charCode >= 48 && event.charCode <= 57) || event.charCode==46) {
//console.log("true");
return true;
} else {
//console.log("false");
event.preventDefault();
return false;
}
}
function checksubmit(e){
console.log('boloktosave:' + boloktosave);
if (boloktosave==0) {
console.log("prevented")
e.preventDefault();
return false;
}
const customerreffullname = document.getElementById('id_CustomerRefFullName');
if (!customerreffullname.value){
console.log('customer is empty');
e.preventDefault();
return false
}
const inputitem = document.getElementsByClassName('inputitem');
for (let i=0; i<inputitem.length;i++) {
if (!inputitem[i].value){
console.log(getElementByElEventClass(inputitem[i], "checkboxinput").checked)
if (getElementByElEventClass(inputitem[i], "checkboxinput").checked==true) {
continue;
};
//console.log()
console.log("ItemRefFullName cannot be empty");
alert('ItemRefFullName cannot be empty');
console.log(i);
console.log(inputitem[i]);
inputitem[i].focus();
e.preventDefault();
return false
}
}
console.log("submitted")
}
function changeitem(e) {
console.log(e.cancelable);
const inputValue=e.target.value;
console.log("inputval="+inputValue);
const dtlist = document.getElementById('itemname');
const selectedOption = dtlist.querySelector('option[value="' + inputValue + '"]');
console.log(selectedOption)
if (!selectedOption && e.target.value!="") {
console.log("cannot find item")
//e.preventDefault;
boloktosave=0;
e.target.focus();
e.target.onblur= function() {
setTimeout(function() {
e.target.focus();
}, 0);
};
return false;
}
if (e.target.value=="" || !e.target.value){
boloktosave=0;
return false;
}
e.target.onblur="";
boloktosave=1;
const datasetPK = selectedOption.dataset.pk;
const datasetDesc = selectedOption.dataset.desc;
const datasetRate = selectedOption.dataset.rate;
console.log(datasetPK, datasetDesc, datasetRate);
const targetELParent = e.target.parentElement.parentElement.parentElement;
console.log(targetELParent);
//const targetELParent = e.target.parentElement.parentElement;
//const targetELItemRef = targetELParent.nextElementSibling.children[0].children[1];
const targetELItemRef = targetELParent.getElementsByClassName('itemreffullname')[0];
console.log(targetELItemRef);
targetELItemRef.value = datasetPK;
//const targetELDesc = targetELParent.nextElementSibling.nextElementSibling.children[0].children[1];
const targetELDesc = getElementByElEventClass(e, "desc");
//const targetELDesc = targetELParent.getElementsByClassName('desc')[0];
console.log(targetELDesc);
targetELDesc.value = datasetDesc;
//const targetELRate = targetELParent.nextElementSibling.nextElementSibling.nextElementSibling.nextElementSibling.nextElementSibling.children[0].children[1];
const targetELRate = getElementByElEventClass(e, "rate");
//const targetELRate = targetELParent.getElementsByClassName('rate')[0];
console.log(targetELRate);
targetELRate.value = parseFloat(datasetRate).toFixed(2);
//const targetELAmount = targetELParent.nextElementSibling.nextElementSibling.nextElementSibling.nextElementSibling.nextElementSibling.nextElementSibling.children[0].children[1];
const targetELAmount = getElementByElEventClass(e, "amount");
//const targetELAmount = targetELParent.getElementsByClassName('amount')[0];
//const qty = targetELParent.nextElementSibling.nextElementSibling.nextElementSibling.children[0].children[1].value;
const qtyEL = getElementByElEventClass(e, "quantity");
//const qtyEL = targetELParent.getElementsByClassName('quantity')[0];
console.log(qtyEL.value);
if (!qtyEL.value){
qtyEL.value=1;
}
targetELAmount.value=(qtyEL.value*parseFloat(datasetRate)).toFixed(2)
findTotalAmount();
}
function findTotalAmount() {
let arr=document.getElementsByClassName('amount');
let tot=0;
for(let i=0;i<arr.length;i++){
if(parseFloat(arr[i].value)) {
tot += parseFloat(arr[i].value);
}
}
console.log(tot);
const totalamountEL=document.getElementById('id_TotalAmount');
const dividtotalamountEL = document.getElementById('div_id_TotalAmount');
const totFormated = number_format(tot,"2",".",",");
console.log(totFormated);
console.log(dividtotalamountEL)
dividtotalamountEL.innerHTML = totFormated;
console.log(dividtotalamountEL.innerHTML)
totalamountEL.value=tot;
}
function descchanged(e) {
boloktosave=1;
}
function qtychanged(e) {
console.log(e);
let qty=e.target.value;
console.log(qty);
if (!qty) {
qty=1;
e.target.value=qty;
} else if (qty<0) {
qty=0;
e.target.value=qty;
}
const rate=getElementByElEventClass(e, "rate").value;
//const rate=e.target.parentElement.parentElement.nextElementSibling.nextElementSibling.children[0].children[1].value;
console.log(rate * qty);
let amountValue=rate*qty;
const amount=getElementByElEventClass(e, "amount")
//let amount=e.target.parentElement.parentElement.nextElementSibling.nextElementSibling.nextElementSibling.children[0].children[1];
console.log(amount);
amount.value=amountValue.toFixed(2);
findTotalAmount();
boloktosave=1;
}
function ratechanged(e) {
console.log(e);
let rate=e.target.value;
console.log(rate);
if (!rate){
rate=0;
e.target.value=0;
} else if(rate<0){
rate=0;
e.target.value=0;
}
const qty=getElementByElEventClass(e, "quantity").value;
//const qty=e.target.parentElement.parentElement.previousElementSibling.previousElementSibling.children[0].children[1].value;
console.log("qty"+qty);
let amountValue=rate*qty;
console.log(amountValue);
const amount=getElementByElEventClass(e,"amount");
//const amount=e.target.parentElement.parentElement.nextElementSibling.children[0].children[1];
console.log(amount);
amount.value=amountValue.toFixed(2);
console.log(amount.value);
findTotalAmount();
boloktosave=1;
}
function amountchanged(e) {
console.log(e);
let amount=e.target.value;
if (!amount){
amount=0;
e.target.value=0;
} else if(amount<0){
amount=0;
e.target.value=0;
alert("Amount cannot be a negative value.")
}
const qty=getElementByElEventClass(e, "quantity");
console.log(qty.value);
if (qty.value){
const rateEL=getElementByElEventClass(e, "rate")
if (qty.value>0){
rateEL.value=(amount/qty.value).toFixed(2)
} else {
qty.value=(amount/rateEL.value).toFixed(2)
}
findTotalAmount();
boloktosave=1;
}
}
function getElementByElEventClass(e, classname){
let parent;
console.log("eventclaaaaaaasss");
console.log("eventclass",e,classname)
if (e.target){
parent = e.target.parentElement;
}
else {
parent = e.parentElement;
}
console.log(parent);
console.log(e, classname);
while (!parent.classList.contains('parentrow')){
parent = parent.parentElement;
}
console.log(parent);
//const parent=e.target.parentElement.parentElement.parentElement;
console.log(parent);
const el=parent.getElementsByClassName(classname)[0];
console.log(el);
return el;
}
function deletechanged(e){
console.log("DELETEEEEE")
boloktosave=1;
findTotalAmount();
}
</script>
<script>
document.addEventListener('click', (event)=>{
if (event.target.id == 'add-more') {
console.log("addmore clicked")
add_new_form(event);
}
})
function add_new_form(e) {
if (e) {
e.preventDefault();
}
const totalNewForms = document.getElementById('id_invoiceitemline_set-TOTAL_FORMS'); //'id_invoiceitemline_set-TOTAL_FORMS' 'id_form-TOTAL_FORMS'
const curItemLineForms = document.getElementsByClassName('itemline-form');
const curFormCount = curItemLineForms.length;
console.log('curformcount=' + curFormCount);
const formCopyTarget = document.getElementById('itemline-form-list');
const copyEmptyFormEl = document.getElementById('empty-form').cloneNode(true);
copyEmptyFormEl.setAttribute('class', 'itemline-form');
copyEmptyFormEl.setAttribute('id', `form-${curFormCount}`);
const regex = new RegExp('__prefix__', 'g');
copyEmptyFormEl.innerHTML = copyEmptyFormEl.innerHTML.replace(regex, curFormCount);
totalNewForms.setAttribute('value', curFormCount + 1);
formCopyTarget.append(copyEmptyFormEl);
}
</script>
{% endblock body %}

View File

@ -0,0 +1,8 @@
{% extends 'base.html'%}
{% block body %}
<form method="POST">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit">
</form>
{% endblock %}

View File

@ -0,0 +1 @@
{% include 'Item/table_index.html' with title="Invoice Order Index" %}

View File

@ -0,0 +1,406 @@
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% load humanize %}
{% 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">
{% csrf_token %}
<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>
<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> -->
</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>
<!--
<script>
document.getElementById('id_CustomerRefFullName').addEventListener('focusout', function() {
console.log(this.value);
if (this.value == '') {
return};
let str='';
let url="{% url 'Invoice:getpricelist' %}"+this.value
console.log(url)
fetch(url)
.then((response) => {
return response.json();
})
.then((data) => {
//console.log(data);
data=JSON.parse(data);
let dt=JSON.parse(data['itemdatalist']);
console.log(dt)
console.log(dt.length)
for (let k=0;k<dt.length;k++){
//console.log(dt[k]);
//console.log("dt[k]")
if (dt[k].itempricelevel__Price) {
str+='<option value="' + dt[k].FullName + '" data-pk="' + dt[k].id + '" data-desc="' + dt[k].SalesDesc + '" data-rate="' + dt[k].itempricelevel__Price + '">';
} else {
str+='<option value="' + dt[k].FullName + '" data-pk="' + dt[k].id + '" data-desc="' + dt[k].SalesDesc + '" data-rate="' + dt[k].SalesPrice + '">';
}
}
//console.log(str);
dt=JSON.parse(data['obj']);
console.log(dt)
console.log(dt.length)
document.getElementById('itemname').innerHTML = str;
str='';
for (let k=0;k<dt.length;k++){
console.log(dt[0].pk);
console.log(dt[0].fields.BillAddr1);
str= dt[0].fields.BillAddr1;
if (dt[0].fields.BillAddr2) {str+="\n"+dt[0].fields.BillAddr2}
if (dt[0].fields.BillAddr3) {str+="\n"+dt[0].fields.BillAddr3}
if (dt[0].fields.BillAddr4) {str+="\n"+dt[0].fields.BillAddr4}
if (dt[0].fields.BillAddr5) {str+="\n"+dt[0].fields.BillAddr5}
document.getElementById('id_BillAddr1').value = str
str=dt[0].fields.ShipAddr1;
if (dt[0].fields.ShipAddr2) {str+="\n"+dt[0].fields.ShipAddr2}
if (dt[0].fields.ShipAddr3) {str+="\n"+dt[0].fields.ShipAddr3}
if (dt[0].fields.ShipAddr4) {str+="\n"+dt[0].fields.ShipAddr4}
if (dt[0].fields.ShipAddr5) {str+="\n"+dt[0].fields.ShipAddr5}
document.getElementById('id_ShipAddr1').value = str;
//document.getElementById('id_ShipAddr1').value = dt[0].fields.ShipAddr1;
}
});
console.log(str)
//for (let i=0;i<12;i++){
// str+= '<option value="' + i + '">';
//}
//document.getElementById('itemname').innerHTML = str;
});
function customerChanged(e){
console.log(e)
}
</script> -->
<script>
function number_format( number, decimals, dec_point, thousands_sep ) {
// http://kevin.vanzonneveld.net
// + original by: Jonas Raoni Soares Silva (http://www.jsfromhell.com)
// + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
// + bugfix by: Michael White (http://crestidg.com)
// + bugfix by: Benjamin Lupton
// + bugfix by: Allan Jensen (http://www.winternet.no)
// + revised by: Jonas Raoni Soares Silva (http://www.jsfromhell.com)
// * example 1: number_format(1234.5678, 2, '.', '');
// * returns 1: 1234.57
var n = number, c = isNaN(decimals = Math.abs(decimals)) ? 2 : decimals;
var d = dec_point == undefined ? "," : dec_point;
var t = thousands_sep == undefined ? "." : thousands_sep, s = n < 0 ? "-" : "";
var i = parseInt(n = Math.abs(+n || 0).toFixed(c)) + "", j = (j = i.length) > 3 ? j % 3 : 0;
return s + (j ? i.substr(0, j) + t : "") + i.substr(j).replace(/(\d{3})(?=\d)/g, "$1" + t) + (c ? d + Math.abs(n - i).toFixed(c).slice(2) : "");
}
</script>
<script>
var totalAmount = 0;
var boloktosave = 0;
function revert(){
document.getElementById("form").reset();
findTotalAmount()
}
function numberOnly(event){
//console.log(event.cancelable);
if ((event.charCode >= 48 && event.charCode <= 57) || event.charCode==46) {
//console.log("true");
return true;
} else {
//console.log("false");
event.preventDefault();
return false;
}
}
function checksubmit(e){
console.log('boloktosave:' + boloktosave);
// if (boloktosave==0) {
// console.log("prevented")
// e.preventDefault();
// return false;
// }
const customerreffullname = document.getElementById('id_CustomerRefFullName');
if (!customerreffullname.value){
console.log('customer is empty');
e.preventDefault();
return false
}
const inputitem = document.getElementsByClassName('inputitem');
const inputValue=document.getElementById('id_CustomerRefFullName').value;
const dtlist = document.getElementById('itemname');
console.log(inputValue)
const selectedOption = dtlist.querySelector('option[value="' + inputValue + '"]');
console.log("selected option:")
console.log(selectedOption);
if (!selectedOption) {
console.log("not correct custname")
e.preventDefault();
return false
}
// for (let i=0; i<inputitem.length;i++) {
// if (!inputitem[i].value){
// console.log(getElementByElEventClass(inputitem[i], "checkboxinput").checked)
// if (getElementByElEventClass(inputitem[i], "checkboxinput").checked==true) {
// continue;
// };
// //console.log()
// console.log("ItemRefFullName cannot be empty");
// alert('ItemRefFullName cannot be empty');
// console.log(i);
// console.log(inputitem[i]);
// inputitem[i].focus();
// e.preventDefault();
// return false
// }
// }
console.log("submitted")
}
function changeitem(e) {
console.log(e.cancelable);
const inputValue=e.target.value;
console.log("inputval="+inputValue);
const dtlist = document.getElementById('itemname');
const selectedOption = dtlist.querySelector('option[value="' + inputValue + '"]');
console.log(selectedOption)
if (!selectedOption && e.target.value!="") {
console.log("cannot find item")
//e.preventDefault;
boloktosave=0;
e.target.focus();
e.target.onblur= function() {
setTimeout(function() {
e.target.focus();
}, 0);
};
return false;
}
if (e.target.value=="" || !e.target.value){
boloktosave=0;
return false;
}
e.target.onblur="";
boloktosave=1;
const datasetPK = selectedOption.dataset.pk;
const datasetDesc = selectedOption.dataset.desc;
const datasetRate = selectedOption.dataset.rate;
console.log(datasetPK, datasetDesc, datasetRate);
const targetELParent = e.target.parentElement.parentElement.parentElement;
console.log(targetELParent);
//const targetELParent = e.target.parentElement.parentElement;
//const targetELItemRef = targetELParent.nextElementSibling.children[0].children[1];
const targetELItemRef = targetELParent.getElementsByClassName('itemreffullname')[0];
console.log(targetELItemRef);
targetELItemRef.value = datasetPK;
//const targetELDesc = targetELParent.nextElementSibling.nextElementSibling.children[0].children[1];
const targetELDesc = getElementByElEventClass(e, "desc");
//const targetELDesc = targetELParent.getElementsByClassName('desc')[0];
console.log(targetELDesc);
targetELDesc.value = datasetDesc;
//const targetELRate = targetELParent.nextElementSibling.nextElementSibling.nextElementSibling.nextElementSibling.nextElementSibling.children[0].children[1];
const targetELRate = getElementByElEventClass(e, "rate");
//const targetELRate = targetELParent.getElementsByClassName('rate')[0];
console.log(targetELRate);
targetELRate.value = parseFloat(datasetRate).toFixed(2);
//const targetELAmount = targetELParent.nextElementSibling.nextElementSibling.nextElementSibling.nextElementSibling.nextElementSibling.nextElementSibling.children[0].children[1];
const targetELAmount = getElementByElEventClass(e, "amount");
//const targetELAmount = targetELParent.getElementsByClassName('amount')[0];
//const qty = targetELParent.nextElementSibling.nextElementSibling.nextElementSibling.children[0].children[1].value;
const qtyEL = getElementByElEventClass(e, "quantity");
//const qtyEL = targetELParent.getElementsByClassName('quantity')[0];
console.log(qtyEL.value);
if (!qtyEL.value){
qtyEL.value=1;
}
targetELAmount.value=(qtyEL.value*parseFloat(datasetRate)).toFixed(2)
findTotalAmount();
}
function findTotalAmount() {
let arr=document.getElementsByClassName('amount');
let tot=0;
for(let i=0;i<arr.length;i++){
if(parseFloat(arr[i].value)) {
tot += parseFloat(arr[i].value);
}
}
console.log(tot);
const totalamountEL=document.getElementById('id_TotalAmount');
const dividtotalamountEL = document.getElementById('div_id_TotalAmount');
const totFormated = number_format(tot,"2",".",",");
console.log(totFormated);
console.log(dividtotalamountEL)
dividtotalamountEL.innerHTML = totFormated;
console.log(dividtotalamountEL.innerHTML)
totalamountEL.value=tot;
}
function descchanged(e) {
boloktosave=1;
}
function qtychanged(e) {
console.log(e);
let qty=e.target.value;
console.log(qty);
if (!qty) {
qty=1;
e.target.value=qty;
} else if (qty<0) {
qty=0;
e.target.value=qty;
}
const rate=getElementByElEventClass(e, "rate").value;
//const rate=e.target.parentElement.parentElement.nextElementSibling.nextElementSibling.children[0].children[1].value;
console.log(rate * qty);
let amountValue=rate*qty;
const amount=getElementByElEventClass(e, "amount")
//let amount=e.target.parentElement.parentElement.nextElementSibling.nextElementSibling.nextElementSibling.children[0].children[1];
console.log(amount);
amount.value=amountValue.toFixed(2);
findTotalAmount();
boloktosave=1;
}
function ratechanged(e) {
console.log(e);
let rate=e.target.value;
console.log(rate);
if (!rate){
rate=0;
e.target.value=0;
} else if(rate<0){
rate=0;
e.target.value=0;
}
const qty=getElementByElEventClass(e, "quantity").value;
//const qty=e.target.parentElement.parentElement.previousElementSibling.previousElementSibling.children[0].children[1].value;
console.log("qty"+qty);
let amountValue=rate*qty;
console.log(amountValue);
const amount=getElementByElEventClass(e,"amount");
//const amount=e.target.parentElement.parentElement.nextElementSibling.children[0].children[1];
console.log(amount);
amount.value=amountValue.toFixed(2);
console.log(amount.value);
findTotalAmount();
boloktosave=1;
}
function amountchanged(e) {
console.log(e);
let amount=e.target.value;
if (!amount){
amount=0;
e.target.value=0;
} else if(amount<0){
amount=0;
e.target.value=0;
alert("Amount cannot be a negative value.")
}
const qty=getElementByElEventClass(e, "quantity");
console.log(qty.value);
if (qty.value){
const rateEL=getElementByElEventClass(e, "rate")
if (qty.value>0){
rateEL.value=(amount/qty.value).toFixed(2)
} else {
qty.value=(amount/rateEL.value).toFixed(2)
}
findTotalAmount();
boloktosave=1;
}
}
function getElementByElEventClass(e, classname){
let parent;
console.log("eventclaaaaaaasss");
console.log("eventclass",e,classname)
if (e.target){
parent = e.target.parentElement;
}
else {
parent = e.parentElement;
}
console.log(parent);
console.log(e, classname);
while (!parent.classList.contains('parentrow')){
parent = parent.parentElement;
}
console.log(parent);
//const parent=e.target.parentElement.parentElement.parentElement;
console.log(parent);
const el=parent.getElementsByClassName(classname)[0];
console.log(el);
return el;
}
function deletechanged(e){
console.log("DELETEEEEE")
boloktosave=1;
findTotalAmount();
}
</script>
<script>
document.addEventListener('click', (event)=>{
if (event.target.id == 'add-more') {
console.log("addmore clicked")
add_new_form(event);
}
})
function add_new_form(e) {
if (e) {
e.preventDefault();
}
const totalNewForms = document.getElementById('id_invoiceitemline_set-TOTAL_FORMS'); //'id_invoiceitemline_set-TOTAL_FORMS' 'id_form-TOTAL_FORMS'
const curItemLineForms = document.getElementsByClassName('itemline-form');
const curFormCount = curItemLineForms.length;
console.log('curformcount=' + curFormCount);
const formCopyTarget = document.getElementById('itemline-form-list');
const copyEmptyFormEl = document.getElementById('empty-form').cloneNode(true);
copyEmptyFormEl.setAttribute('class', 'itemline-form');
copyEmptyFormEl.setAttribute('id', `form-${curFormCount}`);
const regex = new RegExp('__prefix__', 'g');
copyEmptyFormEl.innerHTML = copyEmptyFormEl.innerHTML.replace(regex, curFormCount);
totalNewForms.setAttribute('value', curFormCount + 1);
formCopyTarget.append(copyEmptyFormEl);
}
</script>
{% endblock body %}

View File

@ -0,0 +1,47 @@
{% extends 'base.html' %}
{% block body %}
<!-- <form method="POST" action="{{ request.path }}"> -->
<div class="container">
<form method="POST" action="{% url 'Invoice:show_inv' %}" class="modal-content">
{% csrf_token %}
<div class="modal-header">
<h1>Choose SO</h1>
</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">Date</th>
<th scope="col">Amount</th>
<th scope="col">SO Number</th>
<!-- <th scope="col">Handle</th> -->
</tr>
</thead>
<tbody>
{% for so_no in objects %}
<tr>
<td>
<div class="form-check">
<input type="checkbox" name="so_field" value="{{ so_no.0 }}" id="id_so_field_{{forloop.counter}}" class="form-check-input">
<label for="id_so_field_{{ forloop.counter }}" class="form-check-label">{{ so_no.1 }}
</label>
</div>
</td>
<td>{{ so_no.2 }}</td>
<td>{{ so_no.3 }}</td>
</tr>
{% endfor %}
</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</button>
</div>
</form>
</div>
{% endblock %}

View File

@ -0,0 +1,105 @@
{% comment %} {{form.CustomerRefFullName.errors}}
{% if form.non_field_errors %}
<ul>
{% for error in form.non_field_errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
{% for hidden_field in form.hidden_fields %}
{% if hidden_field.errors %}
<ul>
{% for error in hidden_field.errors %}
<li>(Hidden field {{ hidden_field.name }}) {{ error }}</li>
{% endfor %}
</ul>
{% endif %}
{{ hidden_field }}
{% endfor %}
<table border="1">
{% for field in form.visible_fields %}
<tr>
<th>{{ field.label_tag }}</th>
<td>
{% if field.errors %}
<ul>
{% for error in field.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
{{ field }}
{% if field.help_text %}
<br />{{ field.help_text }}
{% endif %}
</td>
</tr>
{% endfor %}
</table> {% endcomment %}
{% comment %} <div class="container-fluid">
<div class="row">
<div class="col-9">
<div class="row">
<div class="col-9">
I'm the first element in the nested grid
</div>
<div class="col-3">
I'm the second element in the nested grid
</div>
</div>
</div>
<div class="col-3">
I'm the second element in the first grid
</div>
<div class="col-9">
I'm the third element in the first grid
</div>
</div>
</div>
<div class="container">
<div class="row">
<div class="col-6">{{form.CustomerRefFullName|as_crispy_field}}</div>
<div class="row">
<div class="col">{{form.BillAddr1|as_crispy_field}}</div>
<div class="col">
<div class="row">
<div class="col">{{form.TxnDate|as_crispy_field}}</div>
<div class="col">{{form.RefNumber|as_crispy_field}}</div>
</div>
<div class="row">
<div class="col-5l">{{form.CustomerRefFullName|as_crispy_field}}</div>
<div class="col-4">{{form.BillAddr3|as_crispy_field}}</div>
<div class="col">{{form.RefNumber|as_crispy_field}}</div>
</div>
</div>
<div class="col">Outer row 1, column 3 - spans two rows (column 2 has two rows)</div>
</div>
</div>
<div class="container">
<div class="row">
<div class="col">{{form.BillAddr1|as_crispy_field}}</div>
<div class="col">
<div class="row">
<div class="col">{{form.CustomerRefFullName|as_crispy_field}}</div>
<div class="col">{{form.CustomerRefFullName|as_crispy_field}}</div>
</div>
<div class="row">
<div class="col">{{form.CustomerRefFullName|as_crispy_field}}</div>
<div class="col">{{form.CustomerRefFullName|as_crispy_field}}</div>
<div class="col">{{form.CustomerRefFullName|as_crispy_field}}</div>
</div>
</div>
<div class="col">Outer row 1, column 3 - spans two rows (column 2 has two rows)</div>
</div>
</div>
{% endcomment %}

3
django/Invoice/tests.py Normal file
View File

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

19
django/Invoice/urls.py Normal file
View File

@ -0,0 +1,19 @@
from django.urls import path
from . import views
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('', views.index, name="index"),
path('add', views.add_so, name="add_so"),
path('edit/<int:pk>', views.add_so, name="edit_so"),
path('delete/<int:pk>', views.delete_so, name="delete_so"),
path('getpricelist/<int:pk>', views.getpricelist_so, name="getpricelist_so"),
path('getpricelist/', views.getpricelist_so, name="getpricelist"),
]

300
django/Invoice/views.py Normal file
View File

@ -0,0 +1,300 @@
from django.shortcuts import render, get_object_or_404, redirect
from django.urls import reverse
from django.http import HttpResponse, JsonResponse
from django.forms import modelformset_factory, inlineformset_factory
from django.db import transaction
from django.core import serializers
from .models import Invoice, InvoiceItemLine
from Item.models import Item, PriceLevel, PriceLevelItem
from Customer.models import Customer
from .forms import InvoiceForm, InvoiceItemLineForm, GeeksForm
import json
from django.core.serializers.json import DjangoJSONEncoder
from django.contrib import messages
import os
import pandas as pd
def show_customer(request):
pass
thispath = os.getcwd()
print(thispath)
parent = os.path.dirname(thispath)
print(parent)
customers_file = os.path.join(parent, "ItemInventory", "CustomerList.xlsx")
df = pd.read_excel(customers_file, usecols=["FullName"])
context={"customers": df.values.tolist()}
if request.method =="POST":
import sys
sys.path.append('..')
from SO_to_Inv.readSO import SalesOrderQuery
print(os.getcwd())
parentdir = os.path.dirname(os.getcwd())
print(parentdir)
customer_name = request.POST.get("customerreffullname")
print(f'customer_name: {customer_name}')
context['objects'] = ['abc', 'def', 'ghi', 'jkl']
if customer_name:
ini=SalesOrderQuery(FullName= customer_name, IncludeRetElement = ['TxnID', 'TimeCreated', 'TimeModified','TxnNumber', 'CustomerRef', 'TxnDate', 'RefNumber', 'IsManuallyClosed', 'IsFullyInvoiced','TotalAmount'], cwd=parentdir)
print("after ini")
# qbxml = ini.create_QBXML()
# print(qbxml)
response_string = ini.connect_to_quickbooks(ini.create_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)
# print(df.values.tolist())
return render(request, "Invoice/show-customers.html", context)
def select_so(request):
pass
def show_inv(request):
print("show_inv")
context={}
if request.method == "POST":
print(request.POST)
if ('so_field' in request.POST) and ('customer_fullname' in request.POST):
# print(request.POST.getlist('so_field'))
multivals = request.POST.getlist('so_field')
customer_fullname = request.POST.get('customer_fullname')
print(f'Customer_fullname:{customer_fullname} -> request values:{multivals}')
return render( request, "Invoice/so_list_form.html", context)
# return HttpResponse('')
def index(request):
print("index Inv")
context = {}
context['objects'] = Invoice.objects.order_by('-TimeCreated')
context['addurl'] = reverse('Invoice:add_so')
return render(request, "Invoice/index_invoice.html", context=context)
DEMO_CHOICES2 =(
("10", "Naveen"),
("20", "Pranav"),
("30", "Isha"),
("40", "Saloni"),
("50", "Sg"),
)
def home_view(request):
if request.method == "POST":
print(request.POST)
if 'geeks_field' in request.POST:
print(request.POST.getlist('geeks_field'))
multivals = request.POST.getlist('geeks_field')
print(multivals)
form = GeeksForm(request.POST)
if form.is_valid():
print('good')
demochc = ()
for i in range(2,6):
demochc += ((i, str(i)))
context = {}
print (demochc)
form = GeeksForm()
# form.fields['geeks_field'].choices = demochc
context['form'] = form
return render( request, "Invoice/home.html", context)
def add_so(request, pk=None):
print("add INV")
context = {}
obj=None
plname = None
if pk:
obj = get_object_or_404(Invoice.objects.select_related(), pk=pk)
# obj = get_object_or_404(Invoice, pk=pk)
plname = obj.CustomerRefFullName.PriceLevelRefFullName.Name
# print(f"{obj.CustomerRefFullName.PriceLevelRefFullName.Name}")
form = InvoiceForm(request.POST or None, instance=obj)
# InvoiceItemLineFormset = modelformset_factory(InvoiceItemLine, form=InvoiceItemLineForm, extra=0) #cannot use extra >0 because the formset is zip with the qs below
InvoiceItemLineFormset = inlineformset_factory(Invoice, InvoiceItemLine, form=InvoiceItemLineForm, extra=0) #cannot use extra >0 because the formset is zip with the qs below
# InvoiceItemLineFormset = modelformset_factory(InvoiceItemLine, fields = ('ItemRefFullName', 'Desc', 'Quantity', 'UnitOfMeasure', 'Rate', 'Amount', 'Invoiced', 'LineIsManuallyClosed',), extra=1)
# InvoiceItemLineFormset = modelformset_factory(InvoiceItemLine, fields = ('ItemRefFullName', 'Desc', 'Quantity', 'UnitOfMeasure', 'Rate', 'Amount', 'Invoiced', 'LineIsManuallyClosed',), extra=1)
qs=None
formset = InvoiceItemLineFormset(request.POST or None)
if pk:
print("got ID")
qs = obj.invoiceitemline_set.all().order_by('id').select_related('ItemRefFullName')
# formset = InvoiceItemLineFormset(request.POST or None, queryset=qs)
formset = InvoiceItemLineFormset(request.POST or None, instance=obj)
print(request.POST)
# print(formset)
# print(len(formset))
# print(f"queryset={qs}")
# print(f"queryset={qs[0].ItemRefFullName}")
# qsItemList = list(x.ItemRefFullName for x in qs)
# print(qsItemList)
print(f'plname:{plname}')
qsIn = Item.objects.filter(itempricelevel__PL__Name=plname).prefetch_related("itempricelevel").values('id', 'FullName','SalesDesc', 'SalesPrice', 'itempricelevel__Price')
qsEx = Item.objects.exclude(itempricelevel__PL__Name=plname).prefetch_related("itempricelevel").values( "id", "FullName", "SalesDesc", "SalesPrice", "AlwaysNull")
# print(qsIn)
# print("qsEx")
# print(qsEx)
context['itemdatalist'] = qsIn.union(qsEx)
context['object'] = obj
context['qsformset'] = None
if pk:
context['qsformset'] = list(zip(qs, formset))
if request.method == "POST":
with transaction.atomic():
if form.is_valid():
# print(form.cleaned_data)
# with transaction.atomic():
# print(formset)
if formset.is_valid():
for delform in formset.deleted_forms:
pass
totalamount=form.cleaned_data['TotalAmount']
print(totalamount, type(totalamount))
totalamountChildren=0
for fm in formset:
# print(fm)
print(fm['DELETE'].value())
if not fm['DELETE'].value() and 'Amount' in fm.cleaned_data:
# print(fm.cleaned_data['Amount'])
amount=fm.cleaned_data['Amount']
# print(amount)
print(fm['DELETE'].value())
totalamountChildren+=amount
print(totalamountChildren)
if totalamount==totalamountChildren:
print("correct total amount")
else:
print(f"not correct total amount:{totalamount} supposed={totalamountChildren}")
# form.cleaned_data['TotalAmount'] = totalamountChildren
parentobj = form.save(commit=False)
parentobj.TotalAmount = totalamountChildren
parentobj.save()
# print(parentobj)
print("formset valid")
instances = formset.save(commit=False)
for obj in formset.deleted_objects:
print("deelted object")
print(obj)
obj.delete()
for instance in instances:
# print(instance.ItemRefFullName)
# print(instance.pk)
# print(parentobj.id)
instance.Invoice = parentobj
instance.save()
context['message'] = "All Data Saved"
print("all formset saved")
print(parentobj.pk, type(parentobj.pk))
print(reverse('Invoice:edit_so', args=[parentobj.pk]))
messages.success(request, "All Data is Saved")
return redirect(reverse('Invoice:edit_so', args=[parentobj.pk]))
else:
print("formset error")
print(formset.errors)
else:
print("form error")
print(form.errors)
context['form'] = form
context['formset'] = formset
return render(request, "Invoice/create-update.html", context=context)
# def add_so(request):
# print("create SO")
# context = {}
# # obj = get_object_or_404(Invoice, pk=id)
# obj=None
# form = InvoiceForm(request.POST or None, )
# InvoiceItemLineFormset = modelformset_factory(InvoiceItemLine, form=InvoiceItemLineForm, extra=1)
# # qs = obj.invoiceitemline_set.all()
# qs=None
# formset = InvoiceItemLineFormset(request.POST or None, )
# context['form'] = form
# context['formset'] = formset
# context['object'] = obj
# if all([form.is_valid(), formset.is_valid()]):
# print(form.cleaned_data)
# for form in formset:
# print(form.clean_data)
# context['message'] = "All Data saved"
# return render(request, "Invoice/create-update.html", context=context)
def getpricelist_so(request, pk=None):
print(f"getpricelist INV; pk={pk}")
context = {}
obj=None
plname = None
if pk:
# obj = get_object_or_404(Invoice.objects.select_related(), pk=pk)
obj = get_object_or_404(Customer.objects.select_related(), pk=pk)
plname = obj.PriceLevelRefFullName.Name
# print(f"{obj.CustomerRefFullName.PriceLevelRefFullName.Name}")
# form = InvoiceForm(request.POST or None, instance=obj)
# InvoiceItemLineFormset = inlineformset_factory(Invoice, InvoiceItemLine, form=InvoiceItemLineForm, extra=0) #cannot use extra >0 because the formset is zip with the qs below
print(obj)
qs=None
# formset = InvoiceItemLineFormset(request.POST or None)
# if pk:
# print("got ID")
# qs = obj.invoiceitemline_set.all().order_by('id').select_related('ItemRefFullName')
# # formset = InvoiceItemLineFormset(request.POST or None, queryset=qs)
# formset = InvoiceItemLineFormset(request.POST or None, instance=obj)
print(request.GET)
# print(len(formset))
# print(f"queryset={qs}")
# print(f"queryset={qs[0].ItemRefFullName}")
# qsItemList = list(x.ItemRefFullName for x in qs)
# print(qsItemList)
print(f'plname1:{plname}')
qsIn = Item.objects.filter(itempricelevel__PL__Name=plname).prefetch_related("itempricelevel").values('id', 'FullName','SalesDesc', 'SalesPrice', 'itempricelevel__Price')
qsEx = Item.objects.exclude(itempricelevel__PL__Name=plname).prefetch_related("itempricelevel").values( "id", "FullName", "SalesDesc", "SalesPrice", "AlwaysNull")
context['itemdatalist'] = qsIn.union(qsEx)
serialized_q = json.dumps(list( context['itemdatalist']), cls=DjangoJSONEncoder)
# p=json.loads(serialized_q)
print(f'serialized_q:{serialized_q}')
serialized_obj = serializers.serialize('json', [ obj, ])
context['obj'] = serialized_obj
context['itemdatalist'] = serialized_q
# serialized_q = serialized_q + serialized_obj
# print(serialized_obj)
data = json.dumps(context, indent=4, sort_keys=True, default=str)
# print(data)
# print(serialized_q)
return JsonResponse(data, safe=False)
def edit_so(request):
print("Edit SO")
context = {}
obj = get_object_or_404(Invoice, pk=id)
form = InvoiceForm(request.POST or None, instance=obj)
InvoiceItemLineFormset = modelformset_factory(InvoiceItemLine, form=InvoiceItemLineForm, extra=1)
qs = obj.invoiceitemline_set.all()
formset = InvoiceItemLineFormset(request.POST or None, isinstance=qs)
context['form'] = form
context['formset'] = formset
context['object'] = obj
if all([form.is_valid(), formset.is_valid()]):
print(form.cleaned_data)
for form in formset:
print(form.clean_data)
context['message'] = "All Data saved"
return render(request, "Invoice/create-update.html", context=context)
def delete_so(request):
pass

0
django/Item/__init__.py Normal file
View File

19
django/Item/admin.py Normal file
View File

@ -0,0 +1,19 @@
from django.contrib import admin
from .models import UOM, Item, PriceLevel, PriceLevelItem
class ItemAdmin(admin.ModelAdmin):
list_filter = ("ItemType",)
admin.site.register(UOM)
admin.site.register(Item, ItemAdmin)
class PriceLevelPriceLevelItemInline(admin.TabularInline):
model = PriceLevelItem
readonly_fields = ('id',)
extra = 1
# admin.site.register(PriceLevel)
admin.site.register(PriceLevelItem)
@admin.register(PriceLevel)
class PriceLevelAdmin(admin.ModelAdmin):
inlines = [PriceLevelPriceLevelItemInline]

6
django/Item/apps.py Normal file
View File

@ -0,0 +1,6 @@
from django.apps import AppConfig
class ItemConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'Item'

44
django/Item/forms.py Normal file
View File

@ -0,0 +1,44 @@
from django.forms import ModelForm, Select
from django import forms
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Layout, Submit, Row, Column, Field
from .models import Item, PriceLevel
class ItemForm(ModelForm):
class Meta:
model = Item
fields = "__all__"
widgets = {
'SalesDesc':forms.Textarea(attrs={'rows':4}),
'PurchaseDesc':forms.Textarea(attrs={'rows':4}),
}
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.layout = Layout(
# Column('ItemType', css_class='form-group col-md-6 mb-0'),
Row(
Column('Name', css_class='form-group col-md-4 mb-0'),
Column('Parent', css_class='form-group col-md-4 mb-0'),
Column('ManufacturerPartNumber', css_class='form-group col-md-4 mb-0'),
css_class='form-row'
),
Field('UnitOfMeasureSetRefFullName', css_class='form-input col-md-4 mb-0'),
# 'address_2',
Row(
# Card
Column('SalesDesc', css_class='form-group col-md-6 mb-0'),
Column('state', css_class='form-group col-md-4 mb-0'),
Column('zip_code', css_class='form-group col-md-2 mb-0'),
css_class='form-row'
),
'check_me_out',
Submit('submit', 'Sign in')
)
class PriceLevelForm(ModelForm):
class Meta:
model = PriceLevel
fields = "__all__"

View File

@ -0,0 +1,103 @@
from django.core.management.base import BaseCommand, CommandError
from Item.models import Item
import pandas as pd
import numbers as np
class Command(BaseCommand):
help = "Closes the specified poll for voting"
def handle(self, *args, **options):
print("fill Items command")
# return
# if request.method == 'POST' and request.FILES['myfile']:
# myfile = request.FILES['myfile']
# fs = FileSystemStorage()
filename = "Item/management/commands/Iteminventory20230417.xls"
# filename = "Item/management/commands/Book2.xlsx"
# filename = fs.save(myfile.name, myfile)
# uploaded_file_url = fs.url(filename)
empexceldata = pd.read_excel(filename, converters={'ReorderPoint':int}, )
dbframe = empexceldata.replace("NaN", "")
dbframe = dbframe.fillna("")
print(dbframe['PurchaseCost'])
dbframe['PurchaseCost'] = dbframe['PurchaseCost'].apply(pd.to_numeric, downcast='float', errors='coerce')
dbframe['AverageCost'] = dbframe['AverageCost'].apply(pd.to_numeric, downcast='float', errors='coerce')
# dbframe['Reorderpoint'] = dbframe['ReorderPoint'].apply(pd.to_numeric, downcast='float', errors='coerce')
# dbframe['ReorderPoint'] = dbframe['ReorderPoint'].astype(int)
print (dbframe)
dbframe['PurchaseCost'] = dbframe['PurchaseCost'].fillna(0)
dbframe['AverageCost'] = dbframe['AverageCost'].fillna(0)
print(dbframe['PurchaseCost'])
# print(dbframe['NameFromTaco'])
# print(dbframe['ReorderPoint'])
print(dbframe['QuantityOnHand'])
print (dbframe.dtypes)
icount=0
for db in dbframe.itertuples():
obj, created = Item.objects.get_or_create(FullName=db.FullName)
print(obj.FullName, obj.pk)
# if created:
obj.ItemType=1
obj.Name=db.Name
# obj.FullName=db.FullName
# obj.# BarCodeValue=db.# BarCodeValue
obj.SalesDesc=db.SalesDesc
# obj.# SalesPrice=db.# SalesPrice
obj.PurchaseDesc=db.PurchaseDesc
obj.Sublevel=db.Sublevel
obj.ManufacturerPartNumber=db.ManufacturerPartNumber
obj.PurchaseCost=db.PurchaseCost
# obj.ReorderPoint=db.ReorderPoint
obj.QuantityOnHand=db.QuantityOnHand
obj.AverageCost=db.AverageCost
obj.QuantityOnOrder=db.QuantityOnOrder
obj.QuantityOnSalesOrder=db.QuantityOnSalesOrder
# obj.# UnitOfMeasureSetRefFullName=db.# UnitOfMeasureSetRefFullName
obj.ParentRefFullName=db.ParentRefFullName
# obj.# SalesTaxCodeRefFullName=db.# SalesTaxCodeRefFullName
obj.IncomeAccountRefFullName=db.IncomeAccountRefFullName
obj.COGSAccountRefFullName=db.COGSAccountRefFullName
obj.PrefVendorRefFullName=db.PrefVendorRefFullName
obj.AssetAccountRefFullName=db.AssetAccountRefFullName
obj.IsActive=db.IsActive
obj.NameFromTaco=db.NameFromTaco
obj.CATEGORY=db.CATEGORY
obj.Type=db.Type
# obj = Item.objects.create(Name = db.Name,
# FullName = db.FullName,
# # BarCodeValue = db.# BarCodeValue,
# SalesDesc = db.SalesDesc,
# # SalesPrice = db.# SalesPrice,
# PurchaseDesc = db.PurchaseDesc,
# Sublevel = db.Sublevel,
# ManufacturerPartNumber = db.ManufacturerPartNumber,
# PurchaseCost = db.PurchaseCost,
# # ReorderPoint = db.ReorderPoint,
# QuantityOnHand = db.QuantityOnHand,
# AverageCost = db.AverageCost,
# QuantityOnOrder = db.QuantityOnOrder,
# QuantityOnSalesOrder = db.QuantityOnSalesOrder,
# # UnitOfMeasureSetRefFullName = db.# UnitOfMeasureSetRefFullName,
# ParentRefFullName = db.ParentRefFullName,
# # SalesTaxCodeRefFullName = db.# SalesTaxCodeRefFullName,
# IncomeAccountRefFullName = db.IncomeAccountRefFullName,
# COGSAccountRefFullName = db.COGSAccountRefFullName,
# PrefVendorRefFullName = db.PrefVendorRefFullName,
# AssetAccountRefFullName = db.AssetAccountRefFullName,
# IsActive = db.IsActive,
# NameFromTaco = db.NameFromTaco,
# CATEGORY = db.CATEGORY,
# Type = db.Type,
# )
obj.save()
icount+=1
print(f"{icount} Records updated/added")
# return render(request, 'Import_excel_db.html', {
# 'uploaded_file_url': uploaded_file_url
# })
# return render(request, 'Import_excel_db.html',{})

View File

@ -0,0 +1,60 @@
# Generated by Django 4.2 on 2023-05-02 15:17
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='UOM',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('Name', models.CharField(max_length=80)),
('Abbreviation', models.CharField(max_length=12)),
('Number_of', models.DecimalField(decimal_places=3, max_digits=12)),
('Parent', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='parent', to='Item.uom')),
('Purchases', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='purchases', to='Item.uom')),
('Sales', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='sales', to='Item.uom')),
],
),
migrations.CreateModel(
name='Item',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('ItemType', models.CharField(choices=[('3', 'SERVICE'), ('1', 'INVENTORY PART'), ('2', 'NON INVENTORY'), ('4', 'OTHER CHARGES'), ('5', 'SUB TOTAL'), ('6', 'GROUP'), ('7', 'DISCOUNT'), ('8', 'PAYMENT')], default='3', max_length=1)),
('Name', models.CharField(max_length=80)),
('FullName', models.CharField(blank=True, max_length=80, null=True, unique=True)),
('SalesDesc', models.CharField(blank=True, max_length=80, null=True)),
('SalesPrice', models.DecimalField(decimal_places=2, default=0, max_digits=10)),
('PurchaseDesc', models.CharField(blank=True, max_length=80, null=True)),
('Sublevel', models.PositiveSmallIntegerField(default=0)),
('ManufacturerPartNumber', models.CharField(blank=True, max_length=80, null=True)),
('PurchaseCost', models.DecimalField(decimal_places=2, default=0, max_digits=10)),
('ReorderPoint', models.DecimalField(blank=True, decimal_places=2, max_digits=10, null=True)),
('QuantityOnHand', models.DecimalField(blank=True, decimal_places=2, max_digits=10, null=True)),
('AverageCost', models.DecimalField(blank=True, decimal_places=2, max_digits=10, null=True)),
('QuantityOnOrder', models.DecimalField(blank=True, decimal_places=2, max_digits=10, null=True)),
('QuantityOnSalesOrder', models.DecimalField(blank=True, decimal_places=2, max_digits=10, null=True)),
('ParentRefFullName', models.CharField(max_length=80)),
('IncomeAccountRefFullName', models.CharField(default='Sales', max_length=80)),
('COGSAccountRefFullName', models.CharField(default='COGS', max_length=80)),
('PrefVendorRefFullName', models.CharField(default='TACO', max_length=80)),
('AssetAccountRefFullName', models.CharField(default='Inventory Asset', max_length=80)),
('IsActive', models.BooleanField(default=True)),
('NameFromTaco', models.CharField(blank=True, max_length=60, null=True)),
('CATEGORY', models.CharField(blank=True, max_length=60, null=True)),
('Type', models.CharField(blank=True, max_length=60, null=True)),
('TimeCreated', models.DateTimeField(auto_now_add=True)),
('TimeModified', models.DateTimeField(auto_now=True)),
('Parent', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='Item.item')),
('UnitOfMeasureSetRefFullName', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='Item.uom')),
],
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 4.2 on 2023-05-02 15:55
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('Item', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='item',
name='ParentRefFullName',
field=models.CharField(blank=True, max_length=80, null=True),
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 4.2 on 2023-05-03 13:13
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('Item', '0002_alter_item_parentreffullname'),
]
operations = [
migrations.AlterField(
model_name='uom',
name='Number_of',
field=models.DecimalField(blank=True, decimal_places=3, max_digits=12, null=True),
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 4.2 on 2023-05-03 13:15
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('Item', '0003_alter_uom_number_of'),
]
operations = [
migrations.AlterField(
model_name='uom',
name='Name',
field=models.CharField(blank=True, max_length=80, null=True),
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 4.2 on 2023-05-04 16:10
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('Item', '0004_alter_uom_name'),
]
operations = [
migrations.AlterField(
model_name='item',
name='ItemType',
field=models.CharField(choices=[('3', 'SERVICE'), ('1', 'INVENTORY PART'), ('2', 'NON INVENTORY'), ('4', 'OTHER CHARGES'), ('5', 'SUB TOTAL'), ('6', 'GROUP'), ('7', 'DISCOUNT'), ('8', 'PAYMENT')], max_length=1),
),
]

View File

@ -0,0 +1,19 @@
# Generated by Django 4.2 on 2023-05-04 20:53
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('Item', '0005_alter_item_itemtype'),
]
operations = [
migrations.AlterField(
model_name='item',
name='UnitOfMeasureSetRefFullName',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='Item.uom', verbose_name='UOM'),
),
]

View File

@ -0,0 +1,35 @@
# Generated by Django 4.2 on 2023-05-08 05:20
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('Item', '0006_alter_item_unitofmeasuresetreffullname'),
]
operations = [
migrations.CreateModel(
name='PriceLevel',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('Name', models.CharField(max_length=50)),
('Desc', models.CharField(blank=True, max_length=180, null=True, verbose_name='Description')),
('TimeCreated', models.DateTimeField(auto_now_add=True)),
('TimeModified', models.DateTimeField(auto_now=True)),
],
),
migrations.CreateModel(
name='PriceLevelItem',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('Price', models.DecimalField(decimal_places=2, max_digits=12)),
('TimeCreated', models.DateTimeField(auto_now_add=True)),
('TimeModified', models.DateTimeField(auto_now=True)),
('IPL', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='itempricelevel', to='Item.item')),
('PL', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='pricelevel', to='Item.pricelevel')),
],
),
]

View File

@ -0,0 +1,19 @@
# Generated by Django 4.2 on 2023-05-08 05:22
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('Item', '0007_pricelevel_pricelevelitem'),
]
operations = [
migrations.AlterField(
model_name='pricelevelitem',
name='PL',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='pricelevel', to='Item.pricelevel'),
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 4.2 on 2023-05-08 22:11
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('Item', '0008_alter_pricelevelitem_pl'),
]
operations = [
migrations.AddField(
model_name='item',
name='AlwaysNull',
field=models.CharField(blank=True, editable=False, max_length=1, null=True),
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 4.2 on 2023-05-10 20:16
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('Item', '0009_item_alwaysnull'),
]
operations = [
migrations.AlterField(
model_name='pricelevelitem',
name='Price',
field=models.DecimalField(decimal_places=2, max_digits=12, null=True),
),
]

View File

140
django/Item/models.py Normal file
View File

@ -0,0 +1,140 @@
from django.db import models
from django.db import IntegrityError
from django.core.exceptions import ValidationError
from django.urls import reverse
class PriceLevel(models.Model):
Name = models.CharField(max_length=50)
Desc = models.CharField(max_length=180, verbose_name="Description", blank=True, null=True)
TimeCreated = models.DateTimeField(auto_now_add=True)
TimeModified = models.DateTimeField(auto_now=True)
def __str__(self):
return f"{self.pk}; {self.Name}"
def get_field_name(obj):
# return [(f.name, f.value_to_string(obj)) for f in obj._meta.fields] #get value convert it to string
return [(f.verbose_name, f.name, f.value_from_object(obj)) for f in obj._meta.fields]
def get_absolute_url(self):
return reverse('Item:edit_pricelevel', args=[str(self.id)])
class PriceLevelItem(models.Model):
PL = models.ForeignKey("PriceLevel", related_name="pricelevel", on_delete=models.CASCADE)
IPL = models.ForeignKey("Item", related_name="itempricelevel", on_delete=models.CASCADE)
Price = models.DecimalField(max_digits=12, decimal_places=2, null=True)
TimeCreated = models.DateTimeField(auto_now_add=True)
TimeModified = models.DateTimeField(auto_now=True)
#class meta pl ipl unique together
def __str__(self):
return f"{self.PL.Name}; {self.IPL.FullName}; {self.Price}"
class UOM(models.Model):
Name = models.CharField(max_length=80, blank=True, null=True)
Abbreviation = models.CharField(max_length=12)
Number_of = models.DecimalField(max_digits=12, decimal_places=3, blank=True, null=True)
Parent = models.ForeignKey("UOM", related_name="parent", on_delete=models.DO_NOTHING, blank=True, null=True)
Purchases = models.ForeignKey("UOM", related_name="purchases", on_delete=models.DO_NOTHING, blank=True, null=True)
Sales = models.ForeignKey("UOM", related_name="sales", on_delete=models.DO_NOTHING, blank=True, null=True)
def __str__(self):
return self.Abbreviation
class Item(models.Model):
ITEMINVENTORY = "1"
NONINVENTORY = "2"
SERVICE = "3"
OTHERCHARGES = "4"
SUBTOTAL = "5"
GROUP = "6"
DISCOUNT = "7"
PAYMENT = "8"
ITEM_TYPE_CHOICES = [
(SERVICE, "SERVICE"),
(ITEMINVENTORY, "INVENTORY PART"),
(NONINVENTORY, "NON INVENTORY"),
(OTHERCHARGES, "OTHER CHARGES"),
(SUBTOTAL, "SUB TOTAL"),
(GROUP, "GROUP"),
(DISCOUNT, "DISCOUNT"),
(PAYMENT, "PAYMENT"),
]
ItemType = models.CharField(max_length=1, choices=ITEM_TYPE_CHOICES)
Name = models.CharField(max_length=80)
Parent = models.ForeignKey("Item", on_delete=models.DO_NOTHING, blank=True, null=True)
FullName = models.CharField(max_length=80, blank=True, null=True, unique=True)
# BarCodeValue = models.CharField(max_length=80)
SalesDesc = models.CharField(max_length=80, blank=True, null=True)
SalesPrice = models.DecimalField(max_digits=10, decimal_places=2, default=0)
PurchaseDesc = models.CharField(max_length=80, blank=True, null=True)
Sublevel = models.PositiveSmallIntegerField(default = 0)
ManufacturerPartNumber = models.CharField(max_length=80, blank=True, null=True)
PurchaseCost = models.DecimalField(max_digits=10, decimal_places=2, default=0)
ReorderPoint = models.DecimalField(max_digits=10, decimal_places=2, blank=True, null=True)
QuantityOnHand = models.DecimalField(max_digits=10, decimal_places=2, blank=True, null=True)
AverageCost = models.DecimalField(max_digits=10, decimal_places=2, blank=True, null=True)
QuantityOnOrder = models.DecimalField(max_digits=10, decimal_places=2, blank=True, null=True)
QuantityOnSalesOrder = models.DecimalField(max_digits=10, decimal_places=2, blank=True, null=True)
UnitOfMeasureSetRefFullName = models.ForeignKey(UOM, verbose_name="UOM", on_delete=models.DO_NOTHING, blank=True, null=True)
ParentRefFullName = models.CharField(max_length=80, blank=True, null=True)
# SalesTaxCodeRefFullName
IncomeAccountRefFullName= models.CharField(max_length=80, default="Sales")
COGSAccountRefFullName = models.CharField(max_length=80, default="COGS")
PrefVendorRefFullName = models.CharField(max_length=80, default="TACO")
AssetAccountRefFullName = models.CharField(max_length=80, default="Inventory Asset")
IsActive = models.BooleanField(default=True)
NameFromTaco = models.CharField(max_length=60, blank=True, null=True)
CATEGORY = models.CharField(max_length=60, blank=True, null=True)
Type = models.CharField(max_length=60, blank=True, null=True)
AlwaysNull = models.CharField(max_length=1, blank=True, null=True, editable=False)
TimeCreated = models.DateTimeField(auto_now_add=True)
TimeModified = models.DateTimeField(auto_now=True)
# class Meta:
# ordering = ["FullName"]
def get_field_name(obj):
# return [(f.name, f.value_to_string(obj)) for f in obj._meta.fields] #get value convert it to string
return [(f.verbose_name, f.name, f.value_from_object(obj)) for f in obj._meta.fields]
def save(self, *args, **kwargs):
try:
self.FullName = self.Name
print(f"self.FullName={self.FullName}; self.parentreffullname={self.ParentRefFullName}; self.pk={self.pk}")
if self.ParentRefFullName:
print("masuk")
parent = Item.objects.filter(FullName__iexact=self.ParentRefFullName)[0]
print(f"parent.fullname:{parent.FullName}")
if parent:
print(parent.FullName)
self.Parent=parent
print(f"self.Parent={self.Parent}")
if self.Parent:
print(f"self.Parent={self.Parent}")
if self.Parent.FullName:
self.FullName = f"{self.Parent.FullName}:{self.Name}" #no need to do upper()
else:
self.FullName = f"{self.Parent.Name}:{self.Name}"
print(self.Parent.Name, self.Parent.FullName, self.FullName)
item = Item.objects.filter(FullName__iexact=self.FullName)
if item and not self.pk: #check for unique constrain
raise ValidationError("Item FullName should be Unique") #TODO again later
# return
print("raise validationerror itemfullname should unique")
print(f"{self.IsActive}; {self.PurchaseCost}; {self.ReorderPoint}")
super(Item, self).save(*args, **kwargs)
except IntegrityError:
print("integrity error")
except ValidationError:
print("valid error")
def __str__(self) -> str:
if self.FullName:
return f"{self.FullName}"
else:
return self.Name
def get_absolute_url(self): # // ---> new function
return reverse('Item:edit_item', args=[str(self.id)])

View File

@ -0,0 +1,101 @@
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% block title %}{{title}}{% endblock title %}
{% block body %}
<form method="POST">
{% csrf_token %}
{% comment %} {% crispy form %} {% endcomment %}
{% comment %} {{form|crispy}} {% endcomment %}
<div class='container mt-3'>
<div class='row ms-0'>
<div class='card col-6 mb-2'>
<div class='row form-row ms-0 me-0'>
<div class='form-input col-4 col-md-4 mb-0'>{{form.ItemType|as_crispy_field}}</div>
</div>
</div>
<div class='col-4 col-offset-2'>
<div class='form-input col-4 col-md-4 mb-0 mt-3 ms-5'>{{form.IsActive|as_crispy_field}}</div>
</div>
</div>
<div class='card mb-2'>
<div class='row form-row ms-0 me-0'>
<div class='form-group col-md-4 mb-0'> {{form.Name|as_crispy_field}}</div>
<div class='form-group col-md-4 mb-0'> {{form.Parent|as_crispy_field}}</div>
<div class='form-group col-md-4 mb-0'> {{form.ManufacturerPartNumber|as_crispy_field}}</div>
</div>
</div>
<div class='card col-6 mb-2'>
<div class='row form-row ms-0 me-0'>
<div class='form-input col-4 col-md-4 mb-0'>{{form.UnitOfMeasureSetRefFullName|as_crispy_field}}</div>
</div>
</div>
<div class='card-group mb-2'>
<div class='card '>
<div class='row form-row ms-0 me-0'>
<div class'form-group col-md-4 mb-0'>{{form.PurchaseDesc|as_crispy_field}}</div>
<div class'form-group col-md-4 mb-0'>{{form.PurchaseCost|as_crispy_field}}</div>
<div class'form-group col-md-4 mb-0'>{{form.COGSAccountRefFullName|as_crispy_field}}</div>
<div class'form-group col-md-4 mb-0'>{{form.PrefVendorRefFullName|as_crispy_field}}</div>
</div>
</div>
<div class='card'>
<div class='row form-row ms-0 me-0'>
<div class'form-group col-md-4 mb-0'>{{form.SalesDesc|as_crispy_field}}</div>
<div class'form-group col-md-4 mb-0'>{{form.SalesPrice|as_crispy_field}}</div>
<div></div>
<div class'form-group col-md-4 mb-0'>{{form.IncomeAccountRefFullName|as_crispy_field}}</div>
</div>
</div>
</div>
<div class='card mb-2'>
<div class='row form-row ms-0 me-0'>
<div class='form-group col-md-2 mb-0'> {{form.IncomeAccountRefFullName|as_crispy_field}}</div>
<div class='form-group col-md mb-0'> {{form.ReorderPoint|as_crispy_field}}</div>
<div class='form-group col-md mb-0'> {{form.ReorderPoint|as_crispy_field}}</div>
<div class='form-group col-md mb-0'> {{form.QuantityOnHand|as_crispy_field}}</div>
<div class='form-group col-md mb-0'> {{form.AverageCost|as_crispy_field}}</div>
<div class='form-group col-md mb-0'> {{form.QuantityOnOrder|as_crispy_field}}</div>
<div class='form-group col-md mb-0'> {{form.QuantityOnSalesOrder|as_crispy_field}}</div>
</div>
</div>
<button type="submit" class='btn btn-primary mb-3'>submit</button>
<!-- Button trigger modal -->
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#staticBackdrop">
Launch static backdrop modal
</button>
<!-- Modal -->
<div class="modal fade" id="staticBackdrop" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1" aria-labelledby="staticBackdropLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="staticBackdropLabel">Modal title</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div class='row'>
<div class='col-8'>
<div class='form-group col mb-0'> {{form.NameFromTaco|as_crispy_field}}</div>
<div class='form-group col mb-0'> {{form.CATEGORY|as_crispy_field}}</div>
<div class='form-group col mb-0'> {{form.Type|as_crispy_field}}</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary">Understood</button>
</div>
</div>
</div>
</div>
</div>
</form>
{% endblock body %}

View File

@ -0,0 +1,173 @@
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% block title %}Price Level{% endblock title %}
{% block search_nav %}
<form class="d-flex" role="search" action="" method="GET">
<input autocomplete=off id="search" list="itemname" class="form-control me-2" type="search" placeholder="Search" aria-label="Search" name="q">
<button class="btn btn-outline-success" type="submit" onclick="search_btn(event)">Search</button>
</form>
<datalist id="itemname">
{% with objects as items %}
{% for item in items %}
{% comment %} {{item.FullName}} {% endcomment %}
<option value="{{item.FullName}}">{{item.FullName}}</option>
{% endfor %}
{% endwith %}
{% endblock search_nav %}
{% block body %}
<form method="POST" onkeydown="return event.key != 'Enter';">
{% csrf_token %}
{{form|crispy}}
<div class="table-responsive">
<table id="tableId" class="table-sm table-scroll table-bordered border-info table-hover table-striped resizable">
<thead><tr>
<th>FullName</th>
<th>SalesPrice</th>
<th>Price</th>
</tr></thead>
<tbody>
{% for obj in objects %}
<tr>
<td><input type="text" disabled="True" style='width:275px' value="{{obj.FullName}}"></td>
<td><input type="text" disabled="True" value={{obj.SalesPrice}}></td>
<td><input autocomplete=off class="pricelist" type="text" onfocusout="focusout(this)" data-changed data-fullname="{{obj.FullName}}"
{% if obj.itempricelevel__Price %}
data-ori={{obj.itempricelevel__Price}} value={{obj.itempricelevel__Price}}
{% else %}
data-ori=""
{% endif %}>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<button type="submit" onclick="clicksubmit(event)">submit</button>
</form>
<script>
function search_btn(e) {
e.preventDefault();
console.log("search button clicked");
let searchval = document.getElementById('search');
//const searchele=document.querySelector('option[value="' + e.target.value + '"]');
var searchele=document.querySelector('input[data-fullname="' + searchval.value + '"]')
var searcheleparent=document.querySelector('input[data-fullname="' + searchval.value + '"]').parentNode.parentNode;
var prevSibling=searcheleparent.previousElementSibling;
if (prevSibling) {
prevSibling.scrollIntoView();
}
searchele.select();
}
</script>
<script>
const pk = {{pk}};
const datajson={};
const plist = document.getElementsByClassName('pricelist');
//console.log(plist.length);
//console.log(pk);
const idname = document.getElementById('id_Name');
const iddesc = document.getElementById('id_Desc');
//console.log(idname);
function focusout(e){
console.log("data-changed="+ e.getAttribute('data-changed')+";");
if ((parseFloat(e.value).toFixed(2)!=e.getAttribute('data-ori') && e.value != "") ) {
//if (e.getAttribute('data-ori')) {
if (e.dataset.ori!=""){
e.setAttribute('data-changed', "2"); // 2 => EDIT
console.log("edit " + e.getAttribute('data-fullname') + ";" + e.getAttribute('data-ori') + "!= "+e.value);
console.log("data-changed="+ e.getAttribute('data-changed')+";");
}
else {
//e.setAttribute('data-changed', "1"); // thesame thing with below syntax
e.dataset.changed = 1; // 1=> ADD NEW
console.log("add " + e.getAttribute('data-fullname') + ";" + e.getAttribute('data-ori') + "!= "+e.value);
}
} else if ((e.value == null || e.value == "") && e.dataset.ori!=""){
console.log("dtchange");
e.setAttribute('data-changed', "2"); // 2 => EDIT
console.log("edit " + e.getAttribute('data-fullname') + ";" + e.getAttribute('data-ori') + "!= "+e.value);
} else if (e.dataset.changed) {
e.dataset.changed = undefined;
e.removeAttribute('data-changed');
console.log(e.getAttribute('data-fullname') + " back to ori " );
}
console.log("data-changed="+ e.getAttribute('data-changed')+";");
}
function clicksubmit(e){
e.preventDefault();
//console.log(pk);
//console.log(e);
let dt = [];
for (let i = 0; i < plist.length; i++) {
let inputprice = plist[i].value;
let dtchange = plist[i].dataset.changed;
let dtfullname = plist[i].dataset.fullname;
if (dtchange) {
let dttemp = {
FullName : dtfullname,
dtchange : dtchange,
price : parseFloat(parseFloat(inputprice).toFixed(2)),
pk : pk
};
//console.log(dttemp);
dt.push(dttemp);
}
}
console.log(dt);
const datajson = JSON.stringify(dt);
console.log(datajson);
sendform(datajson, idname.value, iddesc.value);
console.log("data sent");
}
function sendform(data, name, desc) {
fetch('', {
method: 'POST',
headers: {
'X-CSRFToken': csrftoken,
'Content-Type': 'application/x-www-form-urlencoded',
},
body: new URLSearchParams({
'data': data,
'pk' : pk,
'Name' : name,
'Desc' : desc,
}),
redirect: "follow", // follow, manual, error
})
.then(response => {
if (response.redirected) {
window.location.replace(response.url);
// creates the second request, and change the content
return;
};
})
}
function getCookie(name) {
let cookieValue = null;
if (document.cookie && document.cookie !== '') {
const cookies = document.cookie.split(';');
for (let i = 0; i < cookies.length; i++) {
const cookie = cookies[i].trim();
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
const csrftoken = getCookie('csrftoken');
console.log(csrftoken);
</script>
{% endblock body %}

View File

@ -0,0 +1 @@
{% include "Item/table_index.html" with title="Item Index" %}

View File

@ -0,0 +1 @@
{% include 'Item/table_index.html' with title="Price Level Index" %}

View File

@ -0,0 +1,221 @@
{% extends 'base.html' %}
{% load tz %}
{% block title %}
{{title}}
{% endblock title %}
{% block search_nav %}
<form class="d-flex" role="search" action="" method="GET">
<input autocomplete=off onfocusout="focusout(this)" id="search" list="itemname" class="form-control me-2" type="search" placeholder="Search" aria-label="Search" name="q">
<button class="btn btn-outline-success" type="submit">Search</button>
</form>
<datalist id="itemname">
{% for item in items %}
{{item.FullName}}
<option value="{{item.FullName}}"><a href="{{item.get_absolute_url}}">{{item.FullName}}; {{item.SalesDesc}}; {{item.SalesPrice}}</a></option>"
{% endfor %}
</datalist>
{% endblock search_nav %}
{% block body %}
<div class="container">
<div>
<a href="{{addurl}}" class="btn btn-primary mt-2">Add New</a>
</div>
<div class="table-responsive mt-2">
<table id="tableId" class=" table table-sm table-scroll table-bordered border-info table-hover table-striped resizable">
<thead><tr>
{% for verbose_name, key, val in objects.0.get_field_name %}
<th>{{verbose_name}}</th>
{% endfor %}
<th></th>
</tr></thead>
<tbody>
{% for object in objects %}
<tr>
{% for vn, key, val in object.get_field_name %}
{% if forloop.first %}
{% comment %} <td><a href="{% url 'edit_item' object.pk %}">{{object.Name|safe}}</a></td> {% endcomment %}
<td><a href="{{ object.get_absolute_url }}">
{% if object.Name %}
{{object.Name|safe}}
{% elif object.CustomerName %}
{{object.CustomerName}}
{% elif object.RefNumber %}
{{object.RefNumber}}
{% endif %}
</a></td>
{% else %}
{% if key == "TimeModified" or key == "TimeCreated" %}
<td>{{val|localtime}}</td>
{% elif key == "ItemType" %}
<td>{{object.get_ItemType_display}}</td>
{% else %}
<td>{{val}}</td>
{% endif %}
{% endif %}
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% if objects.paginator.num_pages > 1 %}
<div class = "d-flex justify-content-center aligns-items-center">
<div class="pagination ">
<span class="step-links">
{% if objects.has_previous %}
<a href="?page=1{% if request.GET.q %}&q={{ request.GET.q }}{% endif %}">&laquo; first</a>
<a href="?page={{ objects.previous_page_number }}{% if request.GET.q %}&q={{ request.GET.q }}{% endif %}">previous</a>
{% endif %}
<span class="current">
Page {{ objects.number }} of {{ objects.paginator.num_pages }}.
</span>
{% if objects.has_next %}
<a href="?page={{ objects.next_page_number }}{% if request.GET.q %}&q={{ request.GET.q }}{% endif %}">next</a>
<a href="?page={{ objects.paginator.num_pages }}{% if request.GET.q %}&q={{ request.GET.q }}{% endif %}">last &raquo;</a>
{% endif %}
</span>
</div>
</div>
{% endif %}
<div id="result">
test
</div>
<script>
const search = document.getElementById('search');
const result = document.getElementById('result');
const itemname = document.getElementById('itemname');
function focusout(e){
let Text = document.querySelector('option[value="' + e.value + '"]');
if (Text){
console.log(e.value)
console.log(Text.text)
}
else {
console.log("element not exist")
}
}
const inputHandler = function(e) {
console.log(e.target.Text)
result.innerHTML = e.target.value;
}
search.addEventListener('input', inputHandler);
search.addEventListener('propertychange', inputHandler);
</script>
<script>
//script to rezise columns TABLE
//var tables = document.getElementsByClassName('flexiCol');
var tables = document.getElementsByClassName('resizable');
for (var i = 0; i < tables.length; i++) {
//console.log(tables[i]);
resizableGrid(tables[i]);
}
function resizableGrid(table) {
var row = table.getElementsByTagName('tr')[0],
cols = row ? row.children : undefined;
if (!cols) return;
table.style.overflow = 'hidden';
var tableHeight = table.offsetHeight;
for (var i = 0; i < cols.length; i++) {
var div = createDiv(tableHeight);
cols[i].appendChild(div);
cols[i].style.position = 'relative';
setListeners(div);
}
function setListeners(div) {
var pageX, curCol, nxtCol, curColWidth, nxtColWidth, tableWidth;
div.addEventListener('mousedown', function(e) {
tableWidth = document.getElementById('tableId').offsetWidth;
curCol = e.target.parentElement;
nxtCol = curCol.nextElementSibling;
pageX = e.pageX;
var padding = paddingDiff(curCol);
curColWidth = curCol.offsetWidth - padding;
// if (nxtCol)
//nxtColWidth = nxtCol.offsetWidth - padding;
});
div.addEventListener('mouseover', function(e) {
e.target.style.borderRight = '2px solid #0000ff';
})
div.addEventListener('mouseout', function(e) {
e.target.style.borderRight = '';
})
document.addEventListener('mousemove', function(e) {
if (curCol) {
var diffX = e.pageX - pageX;
// if (nxtCol)
//nxtCol.style.width = (nxtColWidth - (diffX)) + 'px';
curCol.style.width = (curColWidth + diffX) + 'px';
console.log(curCol.style.width)
console.log(tableWidth)
document.getElementById('tableId').style.width = tableWidth + diffX + "px"
}
});
document.addEventListener('mouseup', function(e) {
curCol = undefined;
nxtCol = undefined;
pageX = undefined;
nxtColWidth = undefined;
curColWidth = undefined
});
}
function createDiv(height) {
var div = document.createElement('div');
div.style.top = 0;
div.style.right = 0;
div.style.width = '5px';
div.style.position = 'absolute';
div.style.cursor = 'col-resize';
div.style.userSelect = 'none';
div.style.height = height + 'px';
return div;
}
function paddingDiff(col) {
if (getStyleVal(col, 'box-sizing') == 'border-box') {
return 0;
}
var padLeft = getStyleVal(col, 'padding-left');
var padRight = getStyleVal(col, 'padding-right');
return (parseInt(padLeft) + parseInt(padRight));
}
function getStyleVal(elm, css) {
return (window.getComputedStyle(elm, null).getPropertyValue(css))
}
};
</script>
{% endblock body %}

3
django/Item/tests.py Normal file
View File

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

14
django/Item/urls.py Normal file
View File

@ -0,0 +1,14 @@
from django.urls import path, include
from .views import index, add_item, edit_item, delete_item, edit_pricelevel, add_pricelevel, index_pricelevel
app_name = "Item"
urlpatterns = [
path('', index, name="index"),
path('add', add_item, name="add_item"),
path('edit/<int:pk>', edit_item, name="edit_item"),
path('delete/<int:pk>', delete_item, name="delete_item"),
path('pricelevel/', index_pricelevel, name="index_pricelevel"),
path('editpricelevel/<int:id>', add_pricelevel, name="edit_pricelevel"),
path('addpricelevel/', add_pricelevel, name="add_pricelevel"),
]

170
django/Item/views.py Normal file
View File

@ -0,0 +1,170 @@
from django.shortcuts import render, redirect, get_object_or_404
from django.http import HttpResponse
from django.urls import reverse
from django.db import transaction
from django.core.paginator import Paginator
from django.db.models import Q
from .models import Item, UOM
from .forms import ItemForm, PriceLevelForm
from django.db.models import Q
from Item.models import Item, PriceLevel, PriceLevelItem
import json
def index_pricelevel(request):
context={}
context['objects']=PriceLevel.objects.order_by('Name')
context['addurl'] = reverse('Item:add_pricelevel')
# print(context['objects'])
return render(request, "Item/index_pricelevel.html", context=context)
def add_pricelevel(request, id=None):
context={}
# print(f"idroot={id}")
pricelevel1 = None
plname=None
context['pk'] = 'null'
if id:
print(f"edit id={id}")
pricelevel1=get_object_or_404(PriceLevel, pk=id)
plname= pricelevel1.Name
print(plname)
context['pk'] = pricelevel1.pk
else:
print("add new")
form = PriceLevelForm(request.POST or None, instance=pricelevel1)
qs1 = Item.objects.filter(itempricelevel__PL__Name=plname).prefetch_related("itempricelevel").values('FullName','SalesPrice', 'itempricelevel__Price')
qs2 = Item.objects.exclude(itempricelevel__PL__Name=plname).prefetch_related("itempricelevel").values( "FullName", "SalesPrice", "AlwaysNull")
# print(qs2)
qs = qs1.union(qs2)
# print(type(qs))
# print(qs)
context['objects'] = qs
context['form'] = form
if request.POST:
datas = request.POST.get('data')
pk = request.POST.get('pk')
print(pk)
with transaction.atomic():
if form.is_valid():
print(form.cleaned_data["Name"])
pricelevel = form.save()
print("form pricelevel saved")
# return redirect(reverse("index"))
else:
print("form not valid")
return render(request, "Item/addedit_pricelevel.html", context=context)
# pricelevel = get_object_or_404(PriceLevel, pk=pk)
# print(f"pk={pk}; object={pricelevel}")
# print(type(datas))
# print(datas)
datas = json.loads(datas)
# print(type(datas))
# print(datas)
# print(form["Name"].value())
blAllSaved = True
if len(datas)>0:
print("more than 0")
for data in datas:
print(type(data))
print(data)
# print(data['FullName'])
if data['dtchange']=="1" or data['dtchange']=="2":
## add new pricelevelitem
print("dtchange 1,2")
item = get_object_or_404(Item, FullName = f"{data['FullName']}")
print(f"object=={item}")
pricelevelitem, created = PriceLevelItem.objects.get_or_create(PL=pricelevel, IPL=item, defaults={'Price':data['price']})
print(f"created={created}")
print(f"object=={pricelevelitem}")
if not created:
pricelevelitem.Price = data['price']
pricelevelitem.save()
print(f"object=={pricelevelitem}")
else:
blAllSaved=False
print("dtchange is NOT 1 or 2")
if blAllSaved:
return redirect(reverse('Item:index_pricelevel'))
else:
return redirect(reverse('Item:edit_pricelevel', pricelevel.pk ))
else:
return redirect(reverse('Item:index_pricelevel'))
return render(request, "Item/addedit_pricelevel.html", context=context)
def edit_pricelevel(request, pk):
context={}
qs1 = Item.objects.filter(itempricelevel__PL__Name='B2020',).prefetch_related("itempricelevel").values('FullName','SalesPrice', 'itempricelevel__Price')
qs2 = Item.objects.exclude(itempricelevel__PL__Name='B2020').prefetch_related("itempricelevel").values( "FullName", "SalesPrice", "AlwaysNull")
# print(qs2)
qs = qs1.union(qs2)
# print(type(qs))
# print(qs)
context['objects'] = qs
return render(request, "Item/addedit_pricelevel.html", context=context)
def index(request):
context={}
search = request.GET.get("q")
items=Item.objects.all().order_by('FullName')
if search:
item = Item.objects.order_by('FullName').filter(Q(Name__icontains=search) | Q(FullName__icontains=search))
else:
item = Item.objects.order_by('FullName')
paginator = Paginator(item, 25) # Show 25 contacts per page.
page_number = request.GET.get("page")
page_obj = paginator.get_page(page_number)
# heads = [f.name for f in Item._meta.get_fields()]
# print(heads)
context['objects'] = page_obj
context['items'] = items
context['addurl'] = reverse('Item:add_item')
return render(request, "Item/index.html", context=context)
def add_item(request):
form = ItemForm(request.POST or None)
if request.POST:
print(form["Name"].value())
if form.is_valid():
print(form.cleaned_data["Name"])
form.save()
return redirect(reverse("Item:index"))
print(form["Name"].value())
return render(request, "Item/addedit_item.html", {"form":form})
def delete_item(request, pk):
item = get_object_or_404(Item, pk=pk)
item.delete()
return HttpResponse(f"{pk} is deleted")
def edit_item(request, pk):
print(pk)
print(request)
item = get_object_or_404(Item, pk=pk)
form = ItemForm( request.POST or None, instance=item)
if request.method == "GET":
print("GET")
if item:
# form = ItemForm(instance=item)
return render(request, "Item/addedit_item.html", {"objects": [item,], "form":form})
elif request.method == "POST":
print("POST")
# form = ItemForm(request.POST, instance=item)
if form.is_valid():
print("form is valid")
item=form.save()
# return redirect(reverse('Item:edit_item', kwargs={"pk":pk}))
return render(request, "Item/index.html", {"objects": [item]})
else:
print("not valid form")
return render(request, "Item/addedit_item.html", {"objects": [item,], "form":form})

View File

View File

@ -0,0 +1,6 @@
from django.contrib import admin
from .models import SalesOrder, SalesOrderItemLine
admin.site.register(SalesOrder)
admin.site.register(SalesOrderItemLine)

View File

@ -0,0 +1,6 @@
from django.apps import AppConfig
class SalesorderConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'SalesOrder'

View File

@ -0,0 +1,43 @@
from django.forms import ModelForm
from django import forms
from .models import SalesOrder, SalesOrderItemLine
from crispy_forms.helper import FormHelper
class SalesOrderForm(ModelForm):
class Meta:
model = SalesOrder
fields = "__all__"
widgets = {
'TxnDate' : forms.DateInput(attrs={'type':"date"}),
'BillAddr1' : forms.Textarea(attrs={'rows':7, 'style':'height:180px'}),
'ShipAddr1' : forms.Textarea(attrs={'rows':7, 'style':'height:180px'}),
'TotalAmount' : forms.TextInput(attrs={'class':'text-end hidden', 'onkeypress':'return event.preventDefault()'})
}
def __init__(self, *args, **kwargs):
super(SalesOrderForm, self).__init__(*args, **kwargs)
self.helper = FormHelper(self)
# self.helper.form_show_labels = False
self.fields['TotalAmount'].label = False
self.fields['TotalAmount'].field_class = ''
class SalesOrderItemLineForm(ModelForm):
class Meta:
model = SalesOrderItemLine
fields = ('ItemRefFullName', 'Desc', 'Quantity', 'UnitOfMeasure', 'Rate', 'Amount', 'Invoiced', 'LineIsManuallyClosed')
# fields = "__all__"
widgets = {
# 'ItemRefFullName' : forms.Select(choices=[('1', '1')]),
'ItemRefFullName' : forms.NumberInput(attrs={'class':'hidden itemreffullname'}),
'Desc' : forms.TextInput(attrs={'class':'desc'}),
'Quantity' : forms.TextInput(attrs={'class':'quantity','onkeypress':'numberOnly(event)'}), #'onkeypress':'return (event.charCode >= 48 && event.charCode <= 57) || event.charCode == 46'}),
'UnitOfMeasure' : forms.Select(attrs={'class':'unitofmeasure'}),
'Rate' : forms.TextInput(attrs={'class':'rate text-end', 'onkeypress':'numberOnly(event)'}),
'Amount' : forms.TextInput(attrs={'class':'amount text-end', 'onkeypress':'numberOnly(event)', 'onchange':'amountchanged(event)'}),
}
def __init__(self, *args, **kwargs):
super(SalesOrderItemLineForm, self).__init__(*args, **kwargs)
self.helper = FormHelper(self)
self.helper.form_show_labels = False
# self.helper.form_class = "abc"
# self.helper.field_class = "xyz"

View File

@ -0,0 +1,82 @@
# Generated by Django 4.2 on 2023-05-13 18:32
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
('Item', '0010_alter_pricelevelitem_price'),
('Customer', '0005_alter_customer_coordinates_and_more'),
]
operations = [
migrations.CreateModel(
name='SalesOrder',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('TxnDate', models.DateTimeField()),
('RefNumber', models.CharField(max_length=30)),
('BillAddr1', models.CharField(max_length=80)),
('BillAddr2', models.CharField(blank=True, max_length=80, null=True)),
('BillAddr3', models.CharField(blank=True, max_length=80, null=True)),
('BillAddr4', models.CharField(blank=True, max_length=80, null=True)),
('BillAddr5', models.CharField(blank=True, max_length=80, null=True)),
('BillCity', models.CharField(blank=True, max_length=80, null=True)),
('BillState', models.CharField(blank=True, max_length=80, null=True)),
('BillPostalCode', models.CharField(blank=True, max_length=80, null=True)),
('BillCountry', models.CharField(default='Indonesia', max_length=80)),
('BillNote', models.CharField(blank=True, max_length=80, null=True)),
('ShipAddr1', models.CharField(blank=True, max_length=80, null=True)),
('ShipAddr2', models.CharField(blank=True, max_length=80, null=True)),
('ShipAddr3', models.CharField(blank=True, max_length=80, null=True)),
('ShipAddr4', models.CharField(blank=True, max_length=80, null=True)),
('ShipAddr5', models.CharField(blank=True, max_length=80, null=True)),
('ShipCity', models.CharField(blank=True, max_length=80, null=True)),
('ShipState', models.CharField(blank=True, max_length=80, null=True)),
('ShipPostalCode', models.CharField(blank=True, max_length=80, null=True)),
('ShipCountry', models.CharField(blank=True, max_length=80, null=True)),
('ShipNote', models.CharField(blank=True, max_length=200, null=True)),
('PONumber', models.CharField(blank=True, max_length=30, null=True)),
('ShipDate', models.DateTimeField(blank=True, null=True)),
('DueDate', models.DateField(blank=True, null=True)),
('Subtotal', models.DecimalField(decimal_places=2, max_digits=14)),
('TotalAmount', models.DecimalField(decimal_places=2, max_digits=14)),
('CustomerMsgRefFullName', models.CharField(blank=True, max_length=120, null=True)),
('IsToBePrinted', models.BooleanField(default=False)),
('IsToBeEmailed', models.BooleanField(default=False)),
('IsManuallyClosed', models.BooleanField(default=False)),
('IsFullyInvoiced', models.BooleanField(default=False)),
('Memo', models.CharField(blank=True, max_length=120, null=True)),
('NPWP', models.CharField(blank=True, max_length=20, null=True)),
('KTP', models.CharField(blank=True, max_length=16, null=True)),
('DMS_Cust_Name', models.CharField(blank=True, max_length=80, null=True)),
('DMS_Cust_Code', models.CharField(blank=True, max_length=80, null=True)),
('Special_Cust', models.BooleanField(default=False)),
('EFaktur_Name', models.CharField(blank=True, max_length=80, null=True)),
('Efaktur_Address', models.CharField(blank=True, max_length=80, null=True)),
('Coordinates', models.CharField(blank=True, max_length=30, null=True)),
('TimeCreated', models.DateTimeField(auto_now_add=True)),
('TimeModified', models.DateTimeField(auto_now=True)),
('CustomerRefFullName', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='Customer.customer')),
],
),
migrations.CreateModel(
name='SalesOrderItemLine',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('Desc', models.CharField(blank=True, max_length=80, null=True)),
('Quantity', models.DecimalField(blank=True, decimal_places=2, max_digits=6, null=True)),
('Rate', models.DecimalField(blank=True, decimal_places=2, max_digits=11, null=True)),
('Amount', models.DecimalField(blank=True, decimal_places=2, max_digits=14, null=True)),
('Invoiced', models.DecimalField(blank=True, decimal_places=2, max_digits=6, null=True)),
('LineIsManuallyClosed', models.BooleanField(default=False)),
('CustomerRefFullName', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='SalesOrder.salesorder')),
('ItemRefFullName', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='Item.item')),
('UnitOfMeasure', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='Item.uom', verbose_name='UOM')),
],
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 4.2 on 2023-05-14 18:27
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('SalesOrder', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='salesorder',
name='TxnDate',
field=models.DateField(),
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 4.2 on 2023-05-14 19:34
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('SalesOrder', '0002_alter_salesorder_txndate'),
]
operations = [
migrations.RenameField(
model_name='salesorderitemline',
old_name='CustomerRefFullName',
new_name='SalesOrder',
),
]

View File

@ -0,0 +1,23 @@
# Generated by Django 4.2 on 2023-05-15 08:05
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('SalesOrder', '0003_rename_customerreffullname_salesorderitemline_salesorder'),
]
operations = [
migrations.AddField(
model_name='salesorder',
name='SalesRepRefFullName',
field=models.CharField(blank=True, max_length=10, null=True),
),
migrations.AddField(
model_name='salesorder',
name='TermsRefFullName',
field=models.CharField(blank=True, max_length=10, null=True),
),
]

Some files were not shown because too many files have changed in this diff Show More