mirror of
https://github.com/bcomsugi/dasaproject.git
synced 2026-01-08 18:42:37 +07:00
202 lines
7.7 KiB
Python
202 lines
7.7 KiB
Python
import win32com.client
|
|
import xml.etree.ElementTree as ET
|
|
from QBClass.QBClasses import GeneralSummaryReportQuery
|
|
import pprint
|
|
|
|
class QuickBooksSDK:
|
|
def __init__(self):
|
|
""" Initialize QBSDK Request Processor """
|
|
self.qb = win32com.client.Dispatch("QBXMLRP2.RequestProcessor")
|
|
# self.session_id = None
|
|
# def open_connection(self):
|
|
# """ Open connection to QuickBooks """
|
|
# self.qb.OpenConnection("", "My Python App")
|
|
# self.qb.BeginSession("", 2) # 2 = Use current QuickBooks session
|
|
|
|
# def close_connection(self):
|
|
# """ Close connection to QuickBooks """
|
|
# self.qb.EndSession()
|
|
# self.qb.CloseConnection()
|
|
|
|
def open_connection(self):
|
|
""" Open connection to QuickBooks """
|
|
self.qb = win32com.client.Dispatch("QBXMLRP2.RequestProcessor")
|
|
self.qb.OpenConnection("", "My QuickBooks App")
|
|
self.session_id = self.qb.BeginSession("", 2) # 2 = Open in "No UI" mode
|
|
print("Connection to QuickBooks established.", self.session_id)
|
|
|
|
def close_connection(self):
|
|
""" Close QuickBooks session and connection """
|
|
if self.session_id:
|
|
|
|
self.qb.EndSession(self.session_id)
|
|
self.qb.CloseConnection()
|
|
print("Connection to QuickBooks closed.")
|
|
|
|
|
|
# def send_request(self, qbxml: str) -> str:
|
|
# """ Send qbXML request and return response """
|
|
# print("Sending XML Request to QuickBooks:\n", qbxml) # Debugging print
|
|
# response = self.qb.ProcessRequest(qbxml)
|
|
# return response
|
|
def send_request(self, qbxml: str) -> str:
|
|
""" Send QBXML request to QuickBooks and return response """
|
|
try:
|
|
print("\n🔷 SENDING REQUEST TO QUICKBOOKS:")
|
|
print(qbxml) # Print the exact request
|
|
print(self.session_id)
|
|
response = self.qb.ProcessRequest(self.session_id, qbxml)
|
|
|
|
print("\n✅ RESPONSE RECEIVED FROM QUICKBOOKS:")
|
|
print(response if response else "No response received!")
|
|
|
|
return response
|
|
except Exception as e:
|
|
print("\n❌ ERROR Processing Request:", str(e))
|
|
return ""
|
|
|
|
|
|
|
|
def parse_sales_order_response(self, xml_response: str):
|
|
""" Parse SalesOrderQueryRs XML response into a Python dictionary """
|
|
print(f'{xml_response = }')
|
|
root = ET.fromstring(xml_response)
|
|
sales_orders = []
|
|
|
|
for order in root.findall(".//SalesOrderRet"):
|
|
order_data = {
|
|
"TxnID": order.findtext("TxnID", ""),
|
|
"TxnDate": order.findtext("TxnDate", ""),
|
|
"CustomerRef": order.findtext("CustomerRef/FullName", ""),
|
|
"TotalAmount": order.findtext("TotalAmount", ""),
|
|
"LineItems": []
|
|
}
|
|
|
|
for line in order.findall(".//SalesOrderLineRet"):
|
|
line_item = {
|
|
"ItemRef": line.findtext("ItemRef/FullName", ""),
|
|
"Quantity": line.findtext("Quantity", ""),
|
|
"Rate": line.findtext("Rate", ""),
|
|
"Amount": line.findtext("Amount", "")
|
|
}
|
|
order_data["LineItems"].append(line_item)
|
|
|
|
sales_orders.append(order_data)
|
|
|
|
return sales_orders
|
|
|
|
def get_sales_orders(self, from_date: str, to_date: str) -> str:
|
|
""" Fetch sales orders from QuickBooks within date range """
|
|
qbxml = f"""
|
|
<?xml version="1.0" encoding="utf-8"?>
|
|
<?qbxml version="13.0"?>
|
|
<QBXML>
|
|
|
|
<QBXMLMsgsRq onError="stopOnError">
|
|
<SalesOrderQueryRq requestID="1">
|
|
<TxnDateRangeFilter>
|
|
<FromTxnDate>2024-01-01</FromTxnDate>
|
|
<ToTxnDate>2024-01-05</ToTxnDate>
|
|
</TxnDateRangeFilter>
|
|
<IncludeLineItems>1</IncludeLineItems>
|
|
</SalesOrderQueryRq>
|
|
</QBXMLMsgsRq>
|
|
</QBXML>
|
|
"""
|
|
qbxml = qbxml.strip()
|
|
print("\n🔍 CHECKING QBXML FORMAT BEFORE SENDING:")
|
|
print(qbxml) # Print request before sending
|
|
|
|
response = self.send_request(qbxml)
|
|
return response
|
|
|
|
def get_keep_sales_orders(self, from_date: str, to_date: str) -> str:
|
|
""" Fetch sales orders from QuickBooks within date range """
|
|
qbxml = f"""
|
|
<?xml version="1.0" encoding="utf-8"?>
|
|
<?qbxml version="13.0"?>
|
|
<QBXML>
|
|
<QBXMLMsgsRq onError="stopOnError">
|
|
<CustomDetailReportQueryRq requestID="1">
|
|
<CustomDetailReportType>CustomTxnDetail</CustomDetailReportType>
|
|
<DisplayReport>true</DisplayReport>
|
|
<ReportDateMacro>All</ReportDateMacro>
|
|
|
|
<ReportEntityFilter>
|
|
<FullName>KEEP</FullName>
|
|
</ReportEntityFilter>
|
|
<ReportItemFilter>
|
|
<FullName>TACO:W:TH-001AA</FullName>
|
|
<FullName>TACO:W:TH-002AA</FullName>
|
|
<FullName>TACO:AA:TH-003AA</FullName>
|
|
<FullName>TACO:AA:TH-010AA</FullName>
|
|
</ReportItemFilter>
|
|
<ReportTxnTypeFilter>
|
|
<TxnTypeFilter>SalesOrder</TxnTypeFilter>
|
|
</ReportTxnTypeFilter>
|
|
<ReportPostingStatusFilter>NonPosting</ReportPostingStatusFilter>
|
|
<SummarizeRowsBy>TotalOnly</SummarizeRowsBy> <!-- required -->
|
|
<!-- IncludeColumn may have one of the following values: Account, Aging, Amount, AmountDifference, AverageCost, BilledDate, BillingStatus, CalculatedAmount,
|
|
Class, ClearedStatus, CostPrice, Credit, Currency, Date, Debit, DeliveryDate, DueDate, EstimateActive, ExchangeRate, FOB, IncomeSubjectToTax, Invoiced, Item, ItemDesc,
|
|
LastModifiedBy, LatestOrPriorState, Memo, ModifiedTime, Name, NameAccountNumber, NameAddress, NameCity, NameContact, NameEmail, NameFax, NamePhone, NameState, NameZip,
|
|
OpenBalance, OriginalAmount, PaidAmount, PaidStatus, PaidThroughDate, PaymentMethod, PayrollItem, PONumber, PrintStatus, ProgressAmount, ProgressPercent, Quantity,
|
|
QuantityAvailable, QuantityOnHand, QuantityOnSalesOrder, ReceivedQuantity, RefNumber, RunningBalance, SalesRep, SalesTaxCode, SerialOrLotNumber, ShipDate, ShipMethod,
|
|
SourceName, SplitAccount, SSNOrTaxID, TaxLine, TaxTableVersion, Terms, TxnID, TxnNumber, TxnType, UnitPrice, UserEdit, ValueOnHand, WageBase, WageBaseTips -->
|
|
<IncludeColumn>Amount</IncludeColumn>
|
|
<IncludeColumn>Item</IncludeColumn>
|
|
<IncludeColumn>Date</IncludeColumn>
|
|
<IncludeColumn>Memo</IncludeColumn>
|
|
<IncludeColumn>Quantity</IncludeColumn>
|
|
<IncludeColumn>RefNumber</IncludeColumn>
|
|
<IncludeColumn>Name</IncludeColumn>
|
|
<IncludeColumn>NameAddress</IncludeColumn>
|
|
<IncludeColumn>SourceName</IncludeColumn>
|
|
<IncludeColumn>TxnNumber</IncludeColumn>
|
|
<IncludeColumn>TxnType</IncludeColumn>
|
|
<IncludeColumn>ReceivedQuantity</IncludeColumn>
|
|
<IncludeColumn>PaidStatus</IncludeColumn>
|
|
<IncludeColumn>Invoiced</IncludeColumn>
|
|
<IncludeColumn>LatestOrPriorState</IncludeColumn>
|
|
|
|
</CustomDetailReportQueryRq>
|
|
</QBXMLMsgsRq>
|
|
</QBXML>
|
|
"""
|
|
# pprint.pprint(qbxml, sort_dicts=False)
|
|
qbxml = qbxml.strip()
|
|
print("\n🔍 CHECKING QBXML FORMAT BEFORE SENDING:")
|
|
print(qbxml) # Print request before sending
|
|
|
|
response = self.send_request(qbxml)
|
|
return response
|
|
|
|
|
|
|
|
|
|
|
|
# **🔹 Main Execution**
|
|
if __name__ == "__main__":
|
|
qb = QuickBooksSDK()
|
|
|
|
try:
|
|
qb.open_connection()
|
|
|
|
# Query sales orders from January 1, 2024 to January 5, 2024
|
|
# sales_orders = qb.get_sales_orders("2024-01-01", "2024-01-05")
|
|
sales_orders = qb.get_keep_sales_orders("2024-01-01", "2024-01-05")
|
|
|
|
# Print hasil dalam format dictionary
|
|
# print("Sales Orders:", sales_orders)
|
|
|
|
finally:
|
|
qb.close_connection()
|
|
|
|
|
|
# g= GeneralSummaryReportQuery(debug=False, GeneralSummaryReportType="InventoryStockStatusByItem", ReportItemFilter_FullName=['ECO:0:ECO-009', 'TACF:HNDL:TP-H04/MR','ECO:0:ECO-007', 'ECO:0:ECO-006'])
|
|
# print(g, type(g))
|
|
# print(type(g.all()))
|
|
# print(g.all())
|
|
# print(g.response_string)
|
|
# print(g.filter("reportdata").all())
|
|
# print(g.all())
|
|
# print(f'{g.filter("datarow").getItemInventory_Report() = }') |