mirror of
https://github.com/bcomsugi/dasaproject.git
synced 2026-01-10 05:52:38 +07:00
Merge branch 'master' of https://github.com/bcomsugi/dasaproject
This commit is contained in:
commit
cf7293c912
3
.gitignore
vendored
3
.gitignore
vendored
@ -169,4 +169,5 @@ QBbackup/
|
|||||||
.xlsx
|
.xlsx
|
||||||
.pdf
|
.pdf
|
||||||
QBbackup/
|
QBbackup/
|
||||||
test_folder_source_DeliveryNote/
|
test_folder_source_DeliveryNote/
|
||||||
|
Exim/Data
|
||||||
@ -1,6 +1,6 @@
|
|||||||
cd "C:\Sources\dasaproject\"
|
cd "C:\Sources\dasaproject\"
|
||||||
echo already cd
|
echo already cd
|
||||||
cmd /k "cd /d C:\Sources\dasaproject\env\Scripts\ & activate & cd /d C:\Sources\dasaproject\ & uvicorn main:app --host 0.0.0.0 --port 9997
|
cmd /k "cd /d C:\Sources\dasaproject\env\Scripts\ & activate & cd /d C:\Sources\dasaproject\ & uvicorn main:app --host 0.0.0.0 --port 9999
|
||||||
echo workon env
|
echo workon env
|
||||||
echo pause
|
echo pause
|
||||||
echo get to env
|
echo get to env
|
||||||
0
Exim/__init__.py
Normal file
0
Exim/__init__.py
Normal file
454
InvoiceAdd.xml
Normal file
454
InvoiceAdd.xml
Normal 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>
|
||||||
2611
QBClass/QBClasses.py
2611
QBClass/QBClasses.py
File diff suppressed because it is too large
Load Diff
@ -8,508 +8,513 @@ from .utils import cleanIncludeRetElements
|
|||||||
import json
|
import json
|
||||||
|
|
||||||
def timing(f):
|
def timing(f):
|
||||||
# @wraps(f)
|
# @wraps(f)
|
||||||
def wrap(*args, **kw):
|
def wrap(*args, **kw):
|
||||||
ts = time()
|
ts = time()
|
||||||
result = f(*args, **kw)
|
result = f(*args, **kw)
|
||||||
te = time()
|
te = time()
|
||||||
print('func:%r args:[%r, %r] took: %2.6f sec' % \
|
print('func:%r args:[%r, %r] took: %2.6f sec' % \
|
||||||
(f.__name__, args, kw, te-ts))
|
(f.__name__, args, kw, te-ts))
|
||||||
return result
|
return result
|
||||||
return wrap
|
return wrap
|
||||||
|
|
||||||
|
|
||||||
class baseQBQuery:
|
class baseQBQuery:
|
||||||
def __init__(self, *args, **kwargs, ) -> None:
|
def __init__(self, *args, **kwargs, ) -> None:
|
||||||
# print(f'{kwargs = }')
|
# print(f'{kwargs = }')
|
||||||
# print(f'{args = }')
|
print(f'{args = }')
|
||||||
self.QBXML = None
|
self.QBXML = None
|
||||||
self.QBDict = {}
|
self.QBDict = {}
|
||||||
self.response_string = None
|
self.response_string = None
|
||||||
self.Rs = None
|
self.Rs = None
|
||||||
self.varDict = {}
|
self.varDict = {}
|
||||||
### start ### variable to be replace with other class init value
|
### start ### variable to be replace with other class init value
|
||||||
self.onError = "continueOnError"
|
self.onError = "continueOnError"
|
||||||
# self.cleanIncludeRetElements = None
|
# self.cleanIncludeRetElements = None
|
||||||
self.includeRetElements_allowed = None
|
self.includeRetElements_allowed = None
|
||||||
self.retName = None
|
self.retName = None
|
||||||
self.defaultFilterKey = None
|
self.defaultFilterKey = None
|
||||||
self.class_debug = False
|
self.class_debug = False
|
||||||
### end ### variable to be replace with other class init value
|
### end ### variable to be replace with other class init value
|
||||||
self.listOfDict = self.ListOfDict(None, self.varDict, self.retName, False)
|
self.listOfDict = self.ListOfDict(None, self.varDict, self.retName, False)
|
||||||
self.requestID = None
|
self.requestID = None
|
||||||
self.statusCode = -1
|
self.statusCode = -1
|
||||||
self.statusMessage = ""
|
self.statusMessage = ""
|
||||||
self.statusSeverity = ""
|
self.statusSeverity = ""
|
||||||
self.statusOk = False
|
self.statusOk = False
|
||||||
if self.__class__.__name__=="baseQBQuery":
|
if self.class_debug:
|
||||||
print("baseqbquey same with classname")
|
if self.__class__.__name__=="baseQBQuery":
|
||||||
else:
|
print("baseqbquey same with classname")
|
||||||
print("accessed from child class")
|
else:
|
||||||
print("basequery is accessed from ", self.__class__.__name__ + "Rq")
|
print("accessed from child class")
|
||||||
|
|
||||||
|
print("basequery is accessed from ", self.__class__.__name__ + "Rq")
|
||||||
|
|
||||||
# @timing
|
# @timing
|
||||||
def create_QBXML(self):
|
def create_QBXML(self):
|
||||||
version = "13.0"
|
version = "13.0"
|
||||||
dataDict = { ### Header for qmxml with version attribute
|
dataDict = { ### Header for qmxml with version attribute
|
||||||
"?qbxml": {
|
"?qbxml": {
|
||||||
"@version": version,
|
"@version": version,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
# dataDict["?qbxml"]["QBXML"] = {"QBXMLMsgsRq": { ### Simple Example ###
|
# dataDict["?qbxml"]["QBXML"] = {"QBXMLMsgsRq": { ### Simple Example ###
|
||||||
# "@onError": "continueOnError",
|
# "@onError": "continueOnError",
|
||||||
# "GeneralSummaryReportQueryRq": {
|
# "GeneralSummaryReportQueryRq": {
|
||||||
# "GeneralSummaryReportType": self.GeneralSummaryReportType,
|
# "GeneralSummaryReportType": self.GeneralSummaryReportType,
|
||||||
# }
|
# }
|
||||||
# }
|
# }
|
||||||
# }
|
# }
|
||||||
|
|
||||||
# dataDict["?qbxml"]["QBXML"] = {"QBXMLMsgsRq": { ### Example with multiple FullName Item ###
|
# dataDict["?qbxml"]["QBXML"] = {"QBXMLMsgsRq": { ### Example with multiple FullName Item ###
|
||||||
# "@onError": "continueOnError",
|
# "@onError": "continueOnError",
|
||||||
# "ItemInventoryQueryRq": {
|
# "ItemInventoryQueryRq": {
|
||||||
# "FullName": ["TACO:AA:TH-003AA",
|
# "FullName": ["TACO:AA:TH-003AA",
|
||||||
# "TACO:AA:TH-010AA"]
|
# "TACO:AA:TH-010AA"]
|
||||||
# },
|
# },
|
||||||
# }
|
# }
|
||||||
# }
|
# }
|
||||||
firstKey = str(list(self.QBDict.keys())[0])
|
firstKey = str(list(self.QBDict.keys())[0])
|
||||||
dataDict["?qbxml"]["QBXML"] = {"QBXMLMsgsRq": { ### Example with multiple FullName Item ###
|
print(f'{firstKey = } {self.QBDict}')
|
||||||
"@onError": self.onError,
|
dataDict["?qbxml"]["QBXML"] = {"QBXMLMsgsRq": { ### Example with multiple FullName Item ###
|
||||||
firstKey: self.QBDict[firstKey]}}
|
"@onError": self.onError,
|
||||||
# print(f'{dataDict = }')
|
firstKey: self.QBDict[firstKey]}}
|
||||||
|
# print(f'{dataDict = }')
|
||||||
# # QBXML = '<?qbxml version="13.0"?>' + xmltodict.unparse(dataDict, pretty=True)
|
# # QBXML = '<?qbxml version="13.0"?>' + xmltodict.unparse(dataDict, pretty=True)
|
||||||
self.QBXML = xmltodict.unparse(dataDict, pretty=True).replace("</?qbxml>", "").replace(f'version="{version}"', f'version="{version}"?')
|
self.QBXML = xmltodict.unparse(dataDict, pretty=True).replace("</?qbxml>", "").replace(f'version="{version}"', f'version="{version}"?')
|
||||||
print(self.QBXML, type(self.QBXML))
|
if self.class_debug:
|
||||||
return self.QBXML
|
print(self.QBXML, type(self.QBXML))
|
||||||
|
return self.QBXML
|
||||||
|
|
||||||
# @timing
|
# @timing
|
||||||
def connect_to_quickbooks(self, qbxml_query=None):
|
def connect_to_quickbooks(self, qbxml_query=None):
|
||||||
# Connect to Quickbooks
|
# Connect to Quickbooks
|
||||||
sessionManager = win32com.client.Dispatch("QBXMLRP2.RequestProcessor")
|
sessionManager = win32com.client.Dispatch("QBXMLRP2.RequestProcessor")
|
||||||
sessionManager.OpenConnection('', 'DASA2')
|
sessionManager.OpenConnection('', 'DASA2')
|
||||||
# ticket = sessionManager.BeginSession("z:\\DBW Bogor.qbw", 2)
|
# ticket = sessionManager.BeginSession("z:\\DBW Bogor.qbw", 2)
|
||||||
ticket = sessionManager.BeginSession("", 2)
|
ticket = sessionManager.BeginSession("", 2)
|
||||||
|
|
||||||
# Send query and receive response
|
# Send query and receive response
|
||||||
self.response_string = sessionManager.ProcessRequest(ticket, self.QBXML)
|
self.response_string = sessionManager.ProcessRequest(ticket, self.QBXML)
|
||||||
|
|
||||||
# Disconnect from Quickbooks
|
# Disconnect from Quickbooks
|
||||||
sessionManager.EndSession(ticket) # Close the company file
|
sessionManager.EndSession(ticket) # Close the company file
|
||||||
sessionManager.CloseConnection() # Close the connection
|
sessionManager.CloseConnection() # Close the connection
|
||||||
|
|
||||||
# Beautify response_string
|
# Beautify response_string
|
||||||
# print(f'{self.response_string = }')
|
# print(f'{self.response_string = }')
|
||||||
xml = minidom.parseString(self.response_string.replace("\n", ""))
|
xml = minidom.parseString(self.response_string.replace("\n", ""))
|
||||||
self.response_string = xml.toprettyxml()
|
self.response_string = xml.toprettyxml()
|
||||||
# print(f'{self.response_string = }')
|
# print(f'{self.response_string = }')
|
||||||
|
|
||||||
self.statusOk = self.isDataOK()
|
self.statusOk = self.isDataOK()
|
||||||
return self.statusOk
|
return self.statusOk
|
||||||
return self.response_string
|
return self.response_string
|
||||||
|
|
||||||
def isDataOK(self):
|
def isDataOK(self):
|
||||||
# print("isdataok")
|
# print("isdataok")
|
||||||
# QBXML = ET.fromstring(self.response_string)
|
# QBXML = ET.fromstring(self.response_string)
|
||||||
# print(xmltodict.parse(self.response_string))
|
# print(xmltodict.parse(self.response_string))
|
||||||
self.varDict = xmltodict.parse(self.response_string)
|
self.varDict = xmltodict.parse(self.response_string)
|
||||||
if self.class_debug:
|
if self.class_debug:
|
||||||
pprint.pprint("isDataOK", self.varDict)
|
print("isDataOK", self.varDict)
|
||||||
self.listOfDict.varDict = self.varDict
|
self.listOfDict.varDict = self.varDict
|
||||||
self.listOfDict.filterKey = ["@requestID"]
|
self.listOfDict.filterKey = ["@requestID"]
|
||||||
self.requestID = self.listOfDict.firstValue().get('@requestID',None)
|
self.requestID = self.listOfDict.firstValue().get('@requestID',None)
|
||||||
self.listOfDict.filterKey = ["@statusCode"]
|
self.listOfDict.filterKey = ["@statusCode"]
|
||||||
self.statusCode = self.listOfDict.firstValue().get('@statusCode',None)
|
self.statusCode = self.listOfDict.firstValue().get('@statusCode',None)
|
||||||
self.listOfDict.filterKey = ["@statusMessage"]
|
self.listOfDict.filterKey = ["@statusMessage"]
|
||||||
self.statusMessage = self.listOfDict.firstValue().get('@statusMessage',None)
|
self.statusMessage = self.listOfDict.firstValue().get('@statusMessage',None)
|
||||||
self.listOfDict.filterKey = ["@statusSeverity"]
|
self.listOfDict.filterKey = ["@statusSeverity"]
|
||||||
self.statusSeverity = self.listOfDict.firstValue().get('@statusSeverity')
|
self.statusSeverity = self.listOfDict.firstValue().get('@statusSeverity')
|
||||||
self.listOfDict.filterKey = [self.retName]
|
self.listOfDict.filterKey = [self.retName]
|
||||||
if self.class_debug:
|
if self.class_debug:
|
||||||
print(f'isDataOK -> {self.listOfDict.firstValue() = }')
|
print(f'isDataOK -> {self.listOfDict.firstValue() = }')
|
||||||
if self.listOfDict.firstValue().get(self.retName,None)==None:
|
if self.listOfDict.firstValue().get(self.retName,None)==None:
|
||||||
return False
|
return False
|
||||||
|
if self.class_debug:
|
||||||
print(f'{self.statusCode = }, {self.statusMessage = }, {self.statusSeverity = }')
|
print(f'{self.statusCode = }, {self.statusMessage = }, {self.statusSeverity = }')
|
||||||
varDict = self.varDict['QBXML']['QBXMLMsgsRs'][self.__class__.__name__+"Rs"]
|
varDict = self.varDict['QBXML']['QBXMLMsgsRs'][self.__class__.__name__+"Rs"]
|
||||||
return True
|
return True
|
||||||
# isStatusOK=None
|
# isStatusOK=None
|
||||||
|
|
||||||
# for _ in self.findKeyInDict("FullName", ): ###berhasil
|
# for _ in self.findKeyInDict("FullName", ): ###berhasil
|
||||||
# print(f'{_ = }')
|
# print(f'{_ = }')
|
||||||
# for _ in self.gen_dict_extract("@statusMessage", self.varDict):
|
# for _ in self.gen_dict_extract("@statusMessage", self.varDict):
|
||||||
# print(_)
|
# print(_)
|
||||||
# if 'Status OK'.lower()==_.lower():
|
# if 'Status OK'.lower()==_.lower():
|
||||||
# print(_)
|
# print(_)
|
||||||
# isStatusOK = True
|
# isStatusOK = True
|
||||||
# break
|
# break
|
||||||
# else:
|
# else:
|
||||||
# isStatusOK=False
|
# isStatusOK=False
|
||||||
|
|
||||||
# if self.ListOfDict.find_firstListOfDict("@statusMessage")['@statusMessage'].lower()=="status OK".lower():
|
# if self.ListOfDict.find_firstListOfDict("@statusMessage")['@statusMessage'].lower()=="status OK".lower():
|
||||||
# # print(f'{self.retName = }')
|
# # print(f'{self.retName = }')
|
||||||
# self.Rs = self.find_firstListOfDict(self.retName)[self.retName]
|
# self.Rs = self.find_firstListOfDict(self.retName)[self.retName]
|
||||||
# # self.Rs=self.returnRet(self.varDict)
|
# # self.Rs=self.returnRet(self.varDict)
|
||||||
# # # print(self.findKeyInDict("FullName", )) ###test
|
# # # print(self.findKeyInDict("FullName", )) ###test
|
||||||
# # print(self.findKeyInDict("FullName", self.findKeyInDict("QBXMLMsgsRs1", ))) ###test
|
# # print(self.findKeyInDict("FullName", self.findKeyInDict("QBXMLMsgsRs1", ))) ###test
|
||||||
# # # print(self.findKeyInDict("@statusMessage", )) ###test
|
# # # print(self.findKeyInDict("@statusMessage", )) ###test
|
||||||
# # for _ in self.findKeyInDict("QBXMLMsgsRs",): ###trial blm berhasil
|
# # for _ in self.findKeyInDict("QBXMLMsgsRs",): ###trial blm berhasil
|
||||||
# # print(f'2{_ = }')
|
# # print(f'2{_ = }')
|
||||||
# # print(f'{self.Rs = }')
|
# # print(f'{self.Rs = }')
|
||||||
# # print(type(self.Rs))
|
# # print(type(self.Rs))
|
||||||
# # print(self.find_firstListOfDict("FullName")['FullName'])
|
# # print(self.find_firstListOfDict("FullName")['FullName'])
|
||||||
# # print(self.find_firstListOfDict("FullName"))
|
# # print(self.find_firstListOfDict("FullName"))
|
||||||
# # print(self.find_allListOfDict("FullName"))
|
# # print(self.find_allListOfDict("FullName"))
|
||||||
|
|
||||||
def returnRet(self, varDict:dict = None):
|
def returnRet(self, varDict:dict = None):
|
||||||
if varDict== None:
|
if varDict== None:
|
||||||
varDict=self.varDict
|
varDict=self.varDict
|
||||||
# pprint.pprint(self.varDict)
|
# pprint.pprint(self.varDict)
|
||||||
|
|
||||||
# print(f'{varDict = }')
|
# print(f'{varDict = }')
|
||||||
varDict = varDict['QBXML']['QBXMLMsgsRs'][self.__class__.__name__+"Rs"]
|
varDict = varDict['QBXML']['QBXMLMsgsRs'][self.__class__.__name__+"Rs"]
|
||||||
# print(f'{varDict = }')
|
# print(f'{varDict = }')
|
||||||
|
|
||||||
for idx, key in enumerate(varDict):
|
for idx, key in enumerate(varDict):
|
||||||
# print(idx, key, len(varDict))
|
# print(idx, key, len(varDict))
|
||||||
if self.retName in key:
|
if self.retName in key:
|
||||||
return varDict[key]
|
return varDict[key]
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def runCheck(self):
|
def runCheck(self):
|
||||||
# print("runCheck")
|
# print("runCheck")
|
||||||
if self.varDict:
|
if self.varDict:
|
||||||
return True
|
return True
|
||||||
if self.response_string:
|
if self.response_string:
|
||||||
return True
|
return True
|
||||||
if self.Rs:
|
if self.Rs:
|
||||||
return True
|
return True
|
||||||
if self.QBDict:
|
if self.QBDict:
|
||||||
self.create_QBXML()
|
print('runcheck', self.QBDict)
|
||||||
if self.connect_to_quickbooks():
|
self.create_QBXML()
|
||||||
return True
|
if self.connect_to_quickbooks():
|
||||||
return False
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
self.all()
|
self.all()
|
||||||
# print(f'{self.returnRet() = }')
|
# print(f'{self.returnRet() = }')
|
||||||
return self.response_string
|
return self.response_string
|
||||||
|
|
||||||
def count(self) -> int:
|
def count(self) -> int:
|
||||||
# objs = self.filter(self.defaultFilterKey).all()
|
# objs = self.filter(self.defaultFilterKey).all()
|
||||||
# print(f"{objs = }", type(objs))
|
# print(f"{objs = }", type(objs))
|
||||||
return len(self.filter(self.defaultFilterKey).all())
|
return len(self.filter(self.defaultFilterKey).all())
|
||||||
|
|
||||||
|
|
||||||
def filter(self, key=None):
|
def filter(self, key=None):
|
||||||
print(f'{key = }')
|
print(f'{key = }')
|
||||||
# print(f'{self.statusOk = }')
|
# print(f'{self.statusOk = }')
|
||||||
if not self.runCheck():
|
if not self.runCheck():
|
||||||
print("not runcheck")
|
print("not runcheck")
|
||||||
return self.ListOfDict(["abc"], self.varDict, self.retName, self.includeRetElements_allowed, self.statusOk)
|
return self.ListOfDict(["abc"], self.varDict, self.retName, self.includeRetElements_allowed, self.statusOk)
|
||||||
return []
|
return []
|
||||||
if isinstance(key, str):
|
if isinstance(key, str):
|
||||||
key = [key]
|
key = [key]
|
||||||
elif isinstance(key, list):
|
elif isinstance(key, list):
|
||||||
pass
|
pass
|
||||||
elif isinstance(key, dict):
|
elif isinstance(key, dict):
|
||||||
key = [x for x,y in key.items()]
|
key = [x for x,y in key.items()]
|
||||||
elif key is None:
|
elif key is None:
|
||||||
# print(f"key is none. {self.retName = }")
|
# print(f"key is none. {self.retName = }")
|
||||||
return self.ListOfDict(self.retName, self.varDict, self.retName, self.includeRetElements_allowed, self.statusOk)#.firstValue()#[self.retName]
|
return self.ListOfDict(self.retName, self.varDict, self.retName, self.includeRetElements_allowed, self.statusOk)#.firstValue()#[self.retName]
|
||||||
else:
|
else:
|
||||||
return []
|
return []
|
||||||
key = cleanIncludeRetElements(self.includeRetElements_allowed, key)
|
key = cleanIncludeRetElements(self.includeRetElements_allowed, key)
|
||||||
# print(f'f {key = }')
|
# print(f'f {key = }')
|
||||||
if key:
|
if key:
|
||||||
return self.ListOfDict(key, self.varDict, self.retName, self.includeRetElements_allowed, self.statusOk)
|
return self.ListOfDict(key, self.varDict, self.retName, self.includeRetElements_allowed, self.statusOk)
|
||||||
else:
|
else:
|
||||||
return self.ListOfDict(["abc"], self.varDict, self.retName, self.includeRetElements_allowed, self.statusOk)
|
return self.ListOfDict(["abc"], self.varDict, self.retName, self.includeRetElements_allowed, self.statusOk)
|
||||||
### dont use this way, better returning class because the value if you assign to variable, the valu will be the last filterKey inputed
|
### dont use this way, better returning class because the value if you assign to variable, the valu will be the last filterKey inputed
|
||||||
### if return class, every filterKey is an object, different from other filterKey
|
### if return class, every filterKey is an object, different from other filterKey
|
||||||
self.listOfDict.varDict = self.varDict
|
self.listOfDict.varDict = self.varDict
|
||||||
self.listOfDict.filterKey = key
|
self.listOfDict.filterKey = key
|
||||||
return self.listOfDict
|
return self.listOfDict
|
||||||
###
|
###
|
||||||
|
|
||||||
def all(self) -> dict:
|
def all(self) -> dict:
|
||||||
if not self.runCheck():
|
if not self.runCheck():
|
||||||
return None
|
return None
|
||||||
# return self.ListOfDict(None, self.varDict, self.retName).firstValue()
|
# return self.ListOfDict(None, self.varDict, self.retName).firstValue()
|
||||||
temp = self.ListOfDict(None, self.varDict, self.retName, self.includeRetElements_allowed, self.statusOk).firstValue()
|
temp = self.ListOfDict(None, self.varDict, self.retName, self.includeRetElements_allowed, self.statusOk).firstValue()
|
||||||
if temp:
|
if temp:
|
||||||
temp = temp[self.retName]
|
temp = temp[self.retName]
|
||||||
else:
|
else:
|
||||||
return {'status':"Error", 'statusCode': self.statusCode, 'statusMessage':self.statusMessage, 'statusSeverity': self.statusSeverity}
|
return {'status':"Error", 'statusCode': self.statusCode, 'statusMessage':self.statusMessage, 'statusSeverity': self.statusSeverity}
|
||||||
if self.requestID:
|
if self.requestID:
|
||||||
temp['requestID']=self.requestID
|
temp['requestID']=self.requestID
|
||||||
# print(f'{temp = }')
|
# print(f'{temp = }')
|
||||||
return temp
|
return temp
|
||||||
# return self.ListOfDict(None, self.varDict, self.retName, self.includeRetElements_allowed, self.statusOk).firstValue()[self.retName]
|
# return self.ListOfDict(None, self.varDict, self.retName, self.includeRetElements_allowed, self.statusOk).firstValue()[self.retName]
|
||||||
### dont use this way
|
### dont use this way
|
||||||
self.listOfDict.varDict = self.varDict
|
self.listOfDict.varDict = self.varDict
|
||||||
self.listOfDict.filterKey = self.retName
|
self.listOfDict.filterKey = self.retName
|
||||||
return self.listOfDict
|
return self.listOfDict
|
||||||
###
|
###
|
||||||
|
|
||||||
def to_json(self) -> str:
|
def to_json(self) -> str:
|
||||||
return json.dumps(self.all())
|
return json.dumps(self.all())
|
||||||
|
|
||||||
|
|
||||||
class ListOfDict:
|
|
||||||
def __init__(self, key, var, retName, includeRetElements_allowed:list ,statusOk:bool = True) -> None:
|
|
||||||
# print(f'{key =}, {var =}')
|
|
||||||
# self.first = self.find_firstListOfDict(key)
|
|
||||||
if key:
|
|
||||||
if isinstance(key, str):
|
|
||||||
self.filterKey = [key]
|
|
||||||
else:
|
|
||||||
self.filterKey = key
|
|
||||||
else:
|
|
||||||
self.filterKey = [retName]
|
|
||||||
# print(f"{self.filterKey = }")
|
|
||||||
self.varDict = var
|
|
||||||
self.statusOk = statusOk
|
|
||||||
self._includeRetElements_allowed = includeRetElements_allowed
|
|
||||||
# print("listofDict")
|
|
||||||
|
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
|
||||||
return str(self.all())
|
|
||||||
|
|
||||||
# def filter(self, filterKey):
|
|
||||||
# self.filterKey=filterKey
|
|
||||||
|
|
||||||
|
|
||||||
def getValuesOf(self, key:str=None, var:dict=None, dataRetList:list=None) :
|
|
||||||
if key==None:
|
|
||||||
key = self.filterKey
|
|
||||||
elif isinstance(key, str):
|
|
||||||
key=[key]
|
|
||||||
elif isinstance(key, list):
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
raise TypeError(f'{key=} should be string not {type(key)}')
|
|
||||||
print(key)
|
|
||||||
key = cleanIncludeRetElements(self._includeRetElements_allowed, key)
|
|
||||||
print(key)
|
|
||||||
if len(key)==0:
|
|
||||||
key = self.filterKey
|
|
||||||
else:
|
|
||||||
key = key
|
|
||||||
# print(f'getvaluesof {key = }')
|
|
||||||
# for xdct in self.findKeyInDict(var, dataRetList):
|
|
||||||
# print(f'{xdct = }', type(xdct), self.filterKey[0], key)
|
|
||||||
lstresult = []
|
|
||||||
for x in self.findKeyInDict(var, dataRetList):
|
|
||||||
templstresult = []
|
|
||||||
for y in key:
|
|
||||||
templstresult.append(x.get(y, ""))
|
|
||||||
lstresult.append(templstresult)
|
|
||||||
print(f'{lstresult[-1] =}')
|
|
||||||
return lstresult
|
|
||||||
_lst = [x[key] for x in self.findKeyInDict(var, dataRetList)]
|
|
||||||
# print(_dct)
|
|
||||||
return _lst
|
|
||||||
|
|
||||||
def all(self, var:dict=None, dataRetList:list=None) -> list:
|
|
||||||
# print(f'{self.statusOk = }')
|
|
||||||
if not self.statusOk:
|
|
||||||
return []
|
|
||||||
_lst = [x for x in self.findKeyInDict(var, dataRetList)]
|
|
||||||
# _lst = [x[self.filterKey] for x in self.findKeyInDict(var, dataRetList)]
|
|
||||||
# if _lst:
|
|
||||||
return _lst
|
|
||||||
# else:
|
|
||||||
# return []
|
|
||||||
|
|
||||||
def allOnlyValue(self, var:dict=None, dataRetList:list=None):
|
|
||||||
if not self.statusOk:
|
|
||||||
return []
|
|
||||||
_lst = [x for x in self.findKeyInDict(var, dataRetList)]
|
|
||||||
return _lst
|
|
||||||
|
|
||||||
def first(self, var:dict=None, dataRetList:list=None) -> dict:
|
|
||||||
if not self.statusOk:
|
|
||||||
return {}
|
|
||||||
return next(self.findKeyInDict( var, dataRetList), {})
|
|
||||||
|
|
||||||
def firstValue(self, var:dict=None, dataRetList:list=None) ->dict:
|
|
||||||
if not self.statusOk:
|
|
||||||
print("firstValue statusOk is False")
|
|
||||||
return {}
|
|
||||||
# return self.first(var, dataRetList)[self.filterKey]
|
|
||||||
_val=self.first(var, dataRetList)
|
|
||||||
# print(f'{_val = }')
|
|
||||||
if _val:
|
|
||||||
# return _val[self.filterKey]
|
|
||||||
return _val
|
|
||||||
else:
|
|
||||||
return {}
|
|
||||||
|
|
||||||
def last(self, var:dict=None, dataRetList:list=None) -> dict:
|
|
||||||
if not self.statusOk:
|
|
||||||
return {}
|
|
||||||
# *_, last = self.findKeyInDict( var, dataRetList)
|
|
||||||
_val= self.all(var, dataRetList)
|
|
||||||
if _val:return _val[-1]
|
|
||||||
else: return {}
|
|
||||||
|
|
||||||
def lastValue(self, var:dict=None, dataRetList:list=None) -> dict:
|
|
||||||
if not self.statusOk:
|
|
||||||
return {}
|
|
||||||
_val=self.last(var, dataRetList)
|
|
||||||
# print(f"lastValue {_val =}")
|
|
||||||
if _val:
|
|
||||||
# return _val[self.filterKey]
|
|
||||||
return _val
|
|
||||||
else:
|
|
||||||
return {}
|
|
||||||
|
|
||||||
def count(self, var:dict=None, dataRetList:list=None) -> int:
|
|
||||||
if not self.statusOk:
|
|
||||||
return 0
|
|
||||||
# print(len(self.all()))
|
|
||||||
return len(self.all())
|
|
||||||
|
|
||||||
# def findKeyInDict(self, var:dict=None, dataRetList:list=None, ):
|
|
||||||
# # print("genfinekeys")
|
|
||||||
# if var==None:
|
|
||||||
# var=self.varDict
|
|
||||||
# # print(f"{var = }")
|
|
||||||
# if dataRetList is None:
|
|
||||||
# dataRetList = []
|
|
||||||
# if isinstance(var, list):
|
|
||||||
# # print("list var")
|
|
||||||
# for _ in var:
|
|
||||||
# yield from self.findKeyInDict( _, )
|
|
||||||
# elif isinstance(var, dict):
|
|
||||||
# # print("dict var")
|
|
||||||
# if self.filterKey in var:
|
|
||||||
# dataRetList.append({self.filterKey: var[self.filterKey]})
|
|
||||||
# print(f"{dataRetList = }")
|
|
||||||
# yield {self.filterKey: var[self.filterKey]}
|
|
||||||
# else:
|
|
||||||
# # print(f'dict else var={var}')
|
|
||||||
# for _ in var:
|
|
||||||
# # print(_)
|
|
||||||
# yield from self.findKeyInDict(var[_], )
|
|
||||||
# return dataRetList
|
|
||||||
|
|
||||||
def findKeyInDict(self, var:dict=None, dataRetList:list=None, ):
|
|
||||||
# print("genfinekeys")
|
|
||||||
if var==None:
|
|
||||||
var=self.varDict
|
|
||||||
# print(f"{var = }")
|
|
||||||
if dataRetList is None:
|
|
||||||
dataRetList = []
|
|
||||||
if isinstance(var, list):
|
|
||||||
# print("list var")
|
|
||||||
for _ in var:
|
|
||||||
yield from self.findKeyInDict( _, )
|
|
||||||
elif isinstance(var, dict):
|
|
||||||
# print("dict var")
|
|
||||||
found = False
|
|
||||||
tempDct = {}
|
|
||||||
for fKey in self.filterKey:
|
|
||||||
# if self.filterKey in var:
|
|
||||||
if fKey in var:
|
|
||||||
found = True
|
|
||||||
tempDct[fKey]=var[fKey]
|
|
||||||
# print(f'{tempDct = }')
|
|
||||||
if found:
|
|
||||||
# dataRetList.append({self.filterKey: var[self.filterKey]})
|
|
||||||
dataRetList.append(tempDct)
|
|
||||||
# print(f"{dataRetList = }")
|
|
||||||
yield tempDct #{self.filterKey: var[self.filterKey]}
|
|
||||||
else:
|
|
||||||
# print(f'dict else var={var}')
|
|
||||||
for _ in var:
|
|
||||||
# print(_)
|
|
||||||
yield from self.findKeyInDict(var[_], )
|
|
||||||
return dataRetList
|
|
||||||
|
|
||||||
|
|
||||||
# def find_allListOfDict(self, key, var:dict=None, dataRetList:list=None):
|
|
||||||
# return [x for x in self.findKeyInDict(key, var, dataRetList)]
|
|
||||||
|
|
||||||
# def find_firstListOfDictValue(self, key, var:dict=None, dataRetList:list=None):
|
|
||||||
# return self.find_firstListOfDict(key, var, dataRetList)[key]
|
|
||||||
|
|
||||||
# def find_firstListOfDict(self, key, var:dict=None, dataRetList:list=None):
|
|
||||||
# return next(self.findKeyInDict(key, var, dataRetList), None)
|
|
||||||
|
|
||||||
# def findKeyInDict(self, key, var:dict=None, dataRetList:list=None, ):
|
|
||||||
# # print("genfinekeys")
|
|
||||||
# if var==None:
|
|
||||||
# var=self.varDict
|
|
||||||
# # print(f"{var = }")
|
|
||||||
# if dataRetList is None:
|
|
||||||
# dataRetList = []
|
|
||||||
# if isinstance(var, list):
|
|
||||||
# # print("list var")
|
|
||||||
# for _ in var:
|
|
||||||
# yield from self.findKeyInDict(key, _, )
|
|
||||||
# elif isinstance(var, dict):
|
|
||||||
# # print("dict var")
|
|
||||||
# if key in var:
|
|
||||||
# dataRetList.append({key: var[key]})
|
|
||||||
# # print(f"{dataRetList = }")
|
|
||||||
# yield {key: var[key]}
|
|
||||||
# else:
|
|
||||||
# # print(f'dict else var={var}')
|
|
||||||
# for _ in var:
|
|
||||||
# # print(_)
|
|
||||||
# yield from self.findKeyInDict(key, var[_], )
|
|
||||||
# return dataRetList
|
|
||||||
|
|
||||||
|
|
||||||
#### dont delete.
|
|
||||||
### Example of extracting dictionary value by key
|
|
||||||
def gen_dict_extract(self, key, var:dict=None): ### Utils
|
|
||||||
if var==None:
|
|
||||||
var=self.response_string
|
|
||||||
# print("var")
|
|
||||||
if hasattr(var,'items'): # hasattr(var,'items') for python 3, hasattr(var,'iteritems') for python 2
|
|
||||||
# print("hassattr")
|
|
||||||
for k, v in var.items(): # var.items() for python 3, var.iteritems() for python 2
|
|
||||||
# print(k,v)
|
|
||||||
if k == key:
|
|
||||||
yield v
|
|
||||||
if isinstance(v, dict):
|
|
||||||
for result in self.gen_dict_extract(key, v):
|
|
||||||
yield result
|
|
||||||
elif isinstance(v, list):
|
|
||||||
for d in v:
|
|
||||||
for result in self.gen_dict_extract(key, d):
|
|
||||||
yield result
|
|
||||||
|
|
||||||
def __str__(self, *args, **kwargs) -> str:
|
|
||||||
# return str(self._get_datarow(self.connect_to_quickbooks(self.create_QBXML())))
|
|
||||||
# print("__str__")
|
|
||||||
return str(self.all())
|
|
||||||
return self.__class__.__name__
|
|
||||||
return str(self.get_datarow())
|
|
||||||
|
|
||||||
|
|
||||||
# def get_datarow(self, *args):
|
|
||||||
# return self._get_datarow(self.connect_to_quickbooks(self.create_QBXML()))
|
|
||||||
|
|
||||||
# def get_dict(self, *args):
|
|
||||||
# return pd.DataFrame(self._get_datarow(self.connect_to_quickbooks(self.create_QBXML())))
|
|
||||||
|
|
||||||
def status_ok(self, QBXML):
|
class ListOfDict:
|
||||||
GSRQRs=QBXML.find('.//GeneralSummaryReportQueryRs')
|
def __init__(self, key, var, retName, includeRetElements_allowed:list ,statusOk:bool = True) -> None:
|
||||||
status_code = GSRQRs.attrib #.get('statusCode')
|
# print(f'{key =}, {var =}')
|
||||||
# print(GSRQRs.attrib)
|
# self.first = self.find_firstListOfDict(key)
|
||||||
# print(GSRQRs.attrib['statusCode'])
|
if key:
|
||||||
status=GSRQRs.attrib.get('statusMessage')
|
if isinstance(key, str):
|
||||||
|
self.filterKey = [key]
|
||||||
print(f'status={status}')
|
else:
|
||||||
if 'OK' in status:
|
self.filterKey = key
|
||||||
return True, status_code
|
else:
|
||||||
else:
|
self.filterKey = [retName]
|
||||||
return False, status_code
|
# print(f"{self.filterKey = }")
|
||||||
|
self.varDict = var
|
||||||
|
self.statusOk = statusOk
|
||||||
|
self._includeRetElements_allowed = includeRetElements_allowed
|
||||||
|
# print("listofDict")
|
||||||
|
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return str(self.all())
|
||||||
|
|
||||||
|
# def filter(self, filterKey):
|
||||||
|
# self.filterKey=filterKey
|
||||||
|
|
||||||
|
|
||||||
|
def getValuesOf(self, key:str=None, var:dict=None, dataRetList:list=None) :
|
||||||
|
if key==None:
|
||||||
|
key = self.filterKey
|
||||||
|
elif isinstance(key, str):
|
||||||
|
key=[key]
|
||||||
|
elif isinstance(key, list):
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
raise TypeError(f'{key=} should be string not {type(key)}')
|
||||||
|
print(key)
|
||||||
|
key = cleanIncludeRetElements(self._includeRetElements_allowed, key)
|
||||||
|
print(key)
|
||||||
|
if len(key)==0:
|
||||||
|
key = self.filterKey
|
||||||
|
else:
|
||||||
|
key = key
|
||||||
|
# print(f'getvaluesof {key = }')
|
||||||
|
# for xdct in self.findKeyInDict(var, dataRetList):
|
||||||
|
# print(f'{xdct = }', type(xdct), self.filterKey[0], key)
|
||||||
|
lstresult = []
|
||||||
|
for x in self.findKeyInDict(var, dataRetList):
|
||||||
|
templstresult = []
|
||||||
|
for y in key:
|
||||||
|
templstresult.append(x.get(y, ""))
|
||||||
|
lstresult.append(templstresult)
|
||||||
|
print(f'{lstresult[-1] =}')
|
||||||
|
return lstresult
|
||||||
|
_lst = [x[key] for x in self.findKeyInDict(var, dataRetList)]
|
||||||
|
# print(_dct)
|
||||||
|
return _lst
|
||||||
|
|
||||||
|
def all(self, var:dict=None, dataRetList:list=None) -> list:
|
||||||
|
# print(f'{self.statusOk = }')
|
||||||
|
if not self.statusOk:
|
||||||
|
return []
|
||||||
|
_lst = [x for x in self.findKeyInDict(var, dataRetList)]
|
||||||
|
# _lst = [x[self.filterKey] for x in self.findKeyInDict(var, dataRetList)]
|
||||||
|
# if _lst:
|
||||||
|
return _lst
|
||||||
|
# else:
|
||||||
|
# return []
|
||||||
|
|
||||||
|
def allOnlyValue(self, var:dict=None, dataRetList:list=None):
|
||||||
|
if not self.statusOk:
|
||||||
|
return []
|
||||||
|
_lst = [x for x in self.findKeyInDict(var, dataRetList)]
|
||||||
|
return _lst
|
||||||
|
|
||||||
|
def first(self, var:dict=None, dataRetList:list=None) -> dict:
|
||||||
|
if not self.statusOk:
|
||||||
|
return {}
|
||||||
|
return next(self.findKeyInDict( var, dataRetList), {})
|
||||||
|
|
||||||
|
def firstValue(self, var:dict=None, dataRetList:list=None) ->dict:
|
||||||
|
if not self.statusOk:
|
||||||
|
print("firstValue statusOk is False")
|
||||||
|
return {}
|
||||||
|
# return self.first(var, dataRetList)[self.filterKey]
|
||||||
|
_val=self.first(var, dataRetList)
|
||||||
|
# print(f'{_val = }')
|
||||||
|
if _val:
|
||||||
|
# return _val[self.filterKey]
|
||||||
|
return _val
|
||||||
|
else:
|
||||||
|
return {}
|
||||||
|
|
||||||
|
def last(self, var:dict=None, dataRetList:list=None) -> dict:
|
||||||
|
if not self.statusOk:
|
||||||
|
return {}
|
||||||
|
# *_, last = self.findKeyInDict( var, dataRetList)
|
||||||
|
_val= self.all(var, dataRetList)
|
||||||
|
if _val:return _val[-1]
|
||||||
|
else: return {}
|
||||||
|
|
||||||
|
def lastValue(self, var:dict=None, dataRetList:list=None) -> dict:
|
||||||
|
if not self.statusOk:
|
||||||
|
return {}
|
||||||
|
_val=self.last(var, dataRetList)
|
||||||
|
# print(f"lastValue {_val =}")
|
||||||
|
if _val:
|
||||||
|
# return _val[self.filterKey]
|
||||||
|
return _val
|
||||||
|
else:
|
||||||
|
return {}
|
||||||
|
|
||||||
|
def count(self, var:dict=None, dataRetList:list=None) -> int:
|
||||||
|
if not self.statusOk:
|
||||||
|
return 0
|
||||||
|
# print(len(self.all()))
|
||||||
|
return len(self.all())
|
||||||
|
|
||||||
|
# def findKeyInDict(self, var:dict=None, dataRetList:list=None, ):
|
||||||
|
# # print("genfinekeys")
|
||||||
|
# if var==None:
|
||||||
|
# var=self.varDict
|
||||||
|
# # print(f"{var = }")
|
||||||
|
# if dataRetList is None:
|
||||||
|
# dataRetList = []
|
||||||
|
# if isinstance(var, list):
|
||||||
|
# # print("list var")
|
||||||
|
# for _ in var:
|
||||||
|
# yield from self.findKeyInDict( _, )
|
||||||
|
# elif isinstance(var, dict):
|
||||||
|
# # print("dict var")
|
||||||
|
# if self.filterKey in var:
|
||||||
|
# dataRetList.append({self.filterKey: var[self.filterKey]})
|
||||||
|
# print(f"{dataRetList = }")
|
||||||
|
# yield {self.filterKey: var[self.filterKey]}
|
||||||
|
# else:
|
||||||
|
# # print(f'dict else var={var}')
|
||||||
|
# for _ in var:
|
||||||
|
# # print(_)
|
||||||
|
# yield from self.findKeyInDict(var[_], )
|
||||||
|
# return dataRetList
|
||||||
|
|
||||||
|
def findKeyInDict(self, var:dict=None, dataRetList:list=None, ):
|
||||||
|
# print("genfinekeys")
|
||||||
|
if var==None:
|
||||||
|
var=self.varDict
|
||||||
|
# print(f"{var = }")
|
||||||
|
if dataRetList is None:
|
||||||
|
dataRetList = []
|
||||||
|
if isinstance(var, list):
|
||||||
|
# print("list var")
|
||||||
|
for _ in var:
|
||||||
|
yield from self.findKeyInDict( _, )
|
||||||
|
elif isinstance(var, dict):
|
||||||
|
# print("dict var")
|
||||||
|
found = False
|
||||||
|
tempDct = {}
|
||||||
|
for fKey in self.filterKey:
|
||||||
|
# if self.filterKey in var:
|
||||||
|
if fKey in var:
|
||||||
|
found = True
|
||||||
|
tempDct[fKey]=var[fKey]
|
||||||
|
# print(f'{tempDct = }')
|
||||||
|
if found:
|
||||||
|
# dataRetList.append({self.filterKey: var[self.filterKey]})
|
||||||
|
dataRetList.append(tempDct)
|
||||||
|
# print(f"{dataRetList = }")
|
||||||
|
yield tempDct #{self.filterKey: var[self.filterKey]}
|
||||||
|
else:
|
||||||
|
# print(f'dict else var={var}')
|
||||||
|
for _ in var:
|
||||||
|
# print(_)
|
||||||
|
yield from self.findKeyInDict(var[_], )
|
||||||
|
return dataRetList
|
||||||
|
|
||||||
|
|
||||||
|
# def find_allListOfDict(self, key, var:dict=None, dataRetList:list=None):
|
||||||
|
# return [x for x in self.findKeyInDict(key, var, dataRetList)]
|
||||||
|
|
||||||
|
# def find_firstListOfDictValue(self, key, var:dict=None, dataRetList:list=None):
|
||||||
|
# return self.find_firstListOfDict(key, var, dataRetList)[key]
|
||||||
|
|
||||||
|
# def find_firstListOfDict(self, key, var:dict=None, dataRetList:list=None):
|
||||||
|
# return next(self.findKeyInDict(key, var, dataRetList), None)
|
||||||
|
|
||||||
|
# def findKeyInDict(self, key, var:dict=None, dataRetList:list=None, ):
|
||||||
|
# # print("genfinekeys")
|
||||||
|
# if var==None:
|
||||||
|
# var=self.varDict
|
||||||
|
# # print(f"{var = }")
|
||||||
|
# if dataRetList is None:
|
||||||
|
# dataRetList = []
|
||||||
|
# if isinstance(var, list):
|
||||||
|
# # print("list var")
|
||||||
|
# for _ in var:
|
||||||
|
# yield from self.findKeyInDict(key, _, )
|
||||||
|
# elif isinstance(var, dict):
|
||||||
|
# # print("dict var")
|
||||||
|
# if key in var:
|
||||||
|
# dataRetList.append({key: var[key]})
|
||||||
|
# # print(f"{dataRetList = }")
|
||||||
|
# yield {key: var[key]}
|
||||||
|
# else:
|
||||||
|
# # print(f'dict else var={var}')
|
||||||
|
# for _ in var:
|
||||||
|
# # print(_)
|
||||||
|
# yield from self.findKeyInDict(key, var[_], )
|
||||||
|
# return dataRetList
|
||||||
|
|
||||||
|
|
||||||
|
#### dont delete.
|
||||||
|
### Example of extracting dictionary value by key
|
||||||
|
def gen_dict_extract(self, key, var:dict=None): ### Utils
|
||||||
|
if var==None:
|
||||||
|
var=self.response_string
|
||||||
|
# print("var")
|
||||||
|
if hasattr(var,'items'): # hasattr(var,'items') for python 3, hasattr(var,'iteritems') for python 2
|
||||||
|
# print("hassattr")
|
||||||
|
for k, v in var.items(): # var.items() for python 3, var.iteritems() for python 2
|
||||||
|
# print(k,v)
|
||||||
|
if k == key:
|
||||||
|
yield v
|
||||||
|
if isinstance(v, dict):
|
||||||
|
for result in self.gen_dict_extract(key, v):
|
||||||
|
yield result
|
||||||
|
elif isinstance(v, list):
|
||||||
|
for d in v:
|
||||||
|
for result in self.gen_dict_extract(key, d):
|
||||||
|
yield result
|
||||||
|
|
||||||
|
def __str__(self, *args, **kwargs) -> str:
|
||||||
|
# return str(self._get_datarow(self.connect_to_quickbooks(self.create_QBXML())))
|
||||||
|
# print("__str__")
|
||||||
|
return str(self.all())
|
||||||
|
return self.__class__.__name__
|
||||||
|
return str(self.get_datarow())
|
||||||
|
|
||||||
|
|
||||||
|
# def get_datarow(self, *args):
|
||||||
|
# return self._get_datarow(self.connect_to_quickbooks(self.create_QBXML()))
|
||||||
|
|
||||||
|
# def get_dict(self, *args):
|
||||||
|
# return pd.DataFrame(self._get_datarow(self.connect_to_quickbooks(self.create_QBXML())))
|
||||||
|
|
||||||
|
def status_ok(self, QBXML):
|
||||||
|
GSRQRs=QBXML.find('.//GeneralSummaryReportQueryRs')
|
||||||
|
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__':
|
if __name__ == '__main__':
|
||||||
pass
|
pass
|
||||||
568
exim.py
Normal file
568
exim.py
Normal file
@ -0,0 +1,568 @@
|
|||||||
|
# from . import QBClasses
|
||||||
|
from pprint import pprint
|
||||||
|
# from QBClass.QBClasses import InvoiceQuery, SalesOrderQuery
|
||||||
|
from QBClass.QBClasses import InvoiceQuery, SalesOrderQuery
|
||||||
|
# import timeit
|
||||||
|
import time
|
||||||
|
import json
|
||||||
|
import pandas as pd
|
||||||
|
import numpy as np
|
||||||
|
import datetime
|
||||||
|
|
||||||
|
print('succes Loading modules')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def timer(func):
|
||||||
|
def wrapper(*args, **kwargs):
|
||||||
|
nonlocal total
|
||||||
|
start = time.time()
|
||||||
|
result = func(*args, **kwargs)
|
||||||
|
duration = time.time() - start
|
||||||
|
total += duration
|
||||||
|
print(f"Execution time: {duration} Total: {total}")
|
||||||
|
return result
|
||||||
|
|
||||||
|
total = 0
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
|
@timer
|
||||||
|
def get_all_so_from_invoice( FromTxnDate=None, ToTxnDate=None, MaxReturned=None,):
|
||||||
|
print(MaxReturned, FromTxnDate, ToTxnDate)
|
||||||
|
start = time.time()
|
||||||
|
print('Get Invoice Query List. Processing..... wait for at minute(1 month=90secs)')
|
||||||
|
if MaxReturned:
|
||||||
|
iq = InvoiceQuery(MaxReturned= MaxReturned, IncludeLinkedTxns='true', IncludeLineItems='true', debug=False)
|
||||||
|
elif FromTxnDate and ToTxnDate:
|
||||||
|
print('here')
|
||||||
|
iq = InvoiceQuery(TxnDateRangeFilter_FromTxnDate=FromTxnDate, TxnDateRangeFilter_ToTxnDate=ToTxnDate, IncludeLinkedTxns='true', IncludeLineItems='true', debug=False)
|
||||||
|
else:
|
||||||
|
iq = InvoiceQuery(TxnDateRangeFilter_FromTxnDate='2021-01-01', TxnDateRangeFilter_ToTxnDate='2021-03-30', IncludeLinkedTxns='true', IncludeLineItems='true', debug=False)
|
||||||
|
# pprint(iq.all(), sort_dicts=False)
|
||||||
|
# print(iq.all())
|
||||||
|
print(f"Execution time InvoiceQuery: {time.time()-start} {len(iq.all()) = }")
|
||||||
|
so_list = []
|
||||||
|
iq_list = []
|
||||||
|
dup_so_list = []
|
||||||
|
for idx, txn in enumerate(iq.all()):
|
||||||
|
# iq_list.append(txn)
|
||||||
|
# print(f"{idx = } {txn['RefNumber'] = } {txn['TxnDate'] = } {txn['Subtotal'] = } ")
|
||||||
|
if 'LinkedTxn' in txn:
|
||||||
|
# pprint(txn['LinkedTxn'], sort_dicts=False)
|
||||||
|
if not isinstance(txn['LinkedTxn'], list): #if there is no receive payment and only 1 linked traction, need to change to a list. RECORD it
|
||||||
|
txn_linkedTxn = [txn['LinkedTxn']]
|
||||||
|
else:
|
||||||
|
txn_linkedTxn = txn['LinkedTxn']
|
||||||
|
for linkedtxn in txn_linkedTxn:
|
||||||
|
if linkedtxn['TxnType']=='SalesOrder':
|
||||||
|
if linkedtxn['RefNumber'] not in so_list:
|
||||||
|
so_list.append(linkedtxn['RefNumber'])
|
||||||
|
else:
|
||||||
|
dup_so_list.append(linkedtxn['RefNumber'])
|
||||||
|
|
||||||
|
print(f'{dup_so_list = }')
|
||||||
|
print()
|
||||||
|
so_dict = {}
|
||||||
|
print(f"Execution time before SO: {time.time()-start}")
|
||||||
|
print('Get Sales Order Query List. Processing..... wait for at minute(1 month=130 secs)')
|
||||||
|
so = SalesOrderQuery(RefNumber = so_list, IncludeLinkedTxns='true', IncludeLineItems='true', debug=False)
|
||||||
|
duplicateSO = []
|
||||||
|
soWithNoLinkedTxn = []
|
||||||
|
print(f"Execution time SalesOrderQuery: {time.time()-start}")
|
||||||
|
for idx, txn in enumerate(so.all()):
|
||||||
|
if 'LinkedTxn' in txn:
|
||||||
|
if txn['RefNumber'] not in so_dict:
|
||||||
|
so_dict[txn['RefNumber']] = txn
|
||||||
|
else:
|
||||||
|
duplicateSO.append(txn['RefNumber'])
|
||||||
|
else:
|
||||||
|
soWithNoLinkedTxn.append(txn)
|
||||||
|
# pprint(so.all(), sort_dicts=False)
|
||||||
|
res = next(iter(so_dict))
|
||||||
|
# print(f'{so_dict[res] = }')
|
||||||
|
# pprint(so_dict[res])
|
||||||
|
print(f'{soWithNoLinkedTxn = }')
|
||||||
|
print(f'{len(iq.all()) = } {len(so.all()) = } {len(so_list) = } {len(dup_so_list) = } {len(so_dict) = }')
|
||||||
|
print(f'{duplicateSO = }')
|
||||||
|
print()
|
||||||
|
### start processing like below module ###
|
||||||
|
pass
|
||||||
|
return iq.all(), so_dict
|
||||||
|
|
||||||
|
|
||||||
|
@timer
|
||||||
|
def process():
|
||||||
|
iq = InvoiceQuery(MaxReturned= 20, IncludeLinkedTxns='true', IncludeLineItems='true', debug=False)
|
||||||
|
# iq = InvoiceQuery(TxnDateRangeFilter_FromTxnDate='2024-02-01', TxnDateRangeFilter_ToTxnDate='2024-02-29', IncludeLinkedTxns='true', IncludeLineItems='true')
|
||||||
|
pprint(iq.all(), sort_dicts=False)
|
||||||
|
# print(iq.all())
|
||||||
|
nolinkInv = []
|
||||||
|
soNotInOneInv = []
|
||||||
|
for idx, txn in enumerate(iq.all()):
|
||||||
|
print(f"{idx = } {txn['RefNumber'] = } {txn['TxnDate'] = } {txn['Subtotal'] = } ")
|
||||||
|
# print(f"{txn['Subtotal'] = }")
|
||||||
|
if 'LinkedTxn' in txn:
|
||||||
|
# pprint(txn['LinkedTxn'], sort_dicts=False)
|
||||||
|
|
||||||
|
if not isinstance(txn['LinkedTxn'], list): #if there is no receive payment and only 1 linked traction, need to change to a list. RECORD it
|
||||||
|
txn_linkedTxn = [txn['LinkedTxn']]
|
||||||
|
else:
|
||||||
|
txn_linkedTxn = txn['LinkedTxn']
|
||||||
|
|
||||||
|
for linkedtxn in txn_linkedTxn:
|
||||||
|
try:
|
||||||
|
if linkedtxn['TxnType']=='SalesOrder':
|
||||||
|
so = SalesOrderQuery(RefNumber = linkedtxn['RefNumber'], IncludeLinkedTxns='true', debug=False)
|
||||||
|
is_soLinkedToOneInvoice = False
|
||||||
|
if 'LinkedTxn' in so.all():
|
||||||
|
if not isinstance(so.all()['LinkedTxn'], list):
|
||||||
|
# print(so.all())
|
||||||
|
so_linkedTxn = [so.all()['LinkedTxn']] #make a list
|
||||||
|
else:
|
||||||
|
so_linkedTxn = so.all()['LinkedTxn'] #just copy, already list
|
||||||
|
# print(so.all())
|
||||||
|
for solinkedtxn in so_linkedTxn:
|
||||||
|
# print(len(so_linkedTxn))
|
||||||
|
if solinkedtxn['TxnType']=='Invoice' and len(so_linkedTxn)==1:
|
||||||
|
# print(so.all()['RefNumber'], 'the only one SO')
|
||||||
|
is_soLinkedToOneInvoice=True
|
||||||
|
# pass
|
||||||
|
else:
|
||||||
|
is_soLinkedToOneInvoice=False
|
||||||
|
print(so.all()['RefNumber'], 'NOT the only One, this SO have other Invoice number') #make append to a list
|
||||||
|
soNotInOneInv.append(so.all()['RefNumber'])
|
||||||
|
|
||||||
|
if float(linkedtxn['Amount'])<0:
|
||||||
|
if so.all()['TotalAmount']!=linkedtxn['Amount'][1:]:
|
||||||
|
if is_soLinkedToOneInvoice: #maybe the SO is manually closed, check it item by item, find which item is not in invoice
|
||||||
|
if so.all()['IsManuallyClosed'] == 'true':
|
||||||
|
pass
|
||||||
|
print(f"{so.all()['TxnID'] = } {so.all()['RefNumber'] = }")
|
||||||
|
else:
|
||||||
|
print('SO TotalAmount<>Amount in Invoice. not Manually closed and not fully Invoiced')
|
||||||
|
pprint(f'{linkedtxn = }', sort_dicts=False)
|
||||||
|
print(f"{so.all()['TxnID'] = } {so.all()['RefNumber'] = }")
|
||||||
|
print(so.all())
|
||||||
|
else:
|
||||||
|
pass # this SO is fully invoiced, starting process to export the details
|
||||||
|
else:
|
||||||
|
print('Linkedtxn amount is positif(should be negatif')
|
||||||
|
except Exception as e:
|
||||||
|
print('ERROR')
|
||||||
|
pprint(linkedtxn, sort_dicts=False)
|
||||||
|
print(f"{so.all()['TxnID'] = }")
|
||||||
|
print(so.all())
|
||||||
|
print(e)
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
nolinkInv.append(txn)
|
||||||
|
print(f'{len(nolinkInv) = }')
|
||||||
|
|
||||||
|
|
||||||
|
@timer
|
||||||
|
def process_data(iq_list, so_dict):
|
||||||
|
print('process_data')
|
||||||
|
# iq = InvoiceQuery(MaxReturned= 20, IncludeLinkedTxns='true', IncludeLineItems='true', debug=False)
|
||||||
|
# iq = InvoiceQuery(TxnDateRangeFilter_FromTxnDate='2024-02-01', TxnDateRangeFilter_ToTxnDate='2024-02-29', IncludeLinkedTxns='true', IncludeLineItems='true')
|
||||||
|
# pprint(iq_list, sort_dicts=False)
|
||||||
|
# print(iq_list)
|
||||||
|
nolinkInv = []
|
||||||
|
soNotInOneInv = []
|
||||||
|
manuallyClosedSO = []
|
||||||
|
openSO = []
|
||||||
|
fullyInvoicedSO = []
|
||||||
|
so_list = [x for x in so_dict]
|
||||||
|
print(f'{len(so_list) = }')
|
||||||
|
result_iq_list = []
|
||||||
|
for idx, txn in enumerate(iq_list):
|
||||||
|
# print(f"{idx = } {txn['RefNumber'] = } {txn['TxnDate'] = } {txn['Subtotal'] = } ")
|
||||||
|
# print(f"{txn['Subtotal'] = }")
|
||||||
|
|
||||||
|
if 'LinkedTxn' in txn:
|
||||||
|
# pprint(txn['LinkedTxn'], sort_dicts=False)
|
||||||
|
if not isinstance(txn['LinkedTxn'], list): #if there is no receive payment and only 1 linked traction, need to change to a list. RECORD it
|
||||||
|
txn_linkedTxn = [txn['LinkedTxn']]
|
||||||
|
else:
|
||||||
|
txn_linkedTxn = txn['LinkedTxn']
|
||||||
|
|
||||||
|
for linkedtxn in txn_linkedTxn:
|
||||||
|
# try:
|
||||||
|
if linkedtxn['TxnType']=='SalesOrder':
|
||||||
|
try:
|
||||||
|
# so_list.remove(linkedtxn['RefNumber'])
|
||||||
|
# so = SalesOrderQuery(RefNumber = linkedtxn['RefNumber'], IncludeLinkedTxns='true', debug=False)
|
||||||
|
sodt = so_dict[linkedtxn['RefNumber']]
|
||||||
|
is_soLinkedToOneInvoice = False
|
||||||
|
if sodt['IsManuallyClosed']=='true':
|
||||||
|
manuallyClosedSO.append(sodt['RefNumber'])
|
||||||
|
if sodt['IsFullyInvoiced']=='true':
|
||||||
|
fullyInvoicedSO.append(sodt['RefNumber'])
|
||||||
|
if 'LinkedTxn' in sodt:
|
||||||
|
if not isinstance(sodt['LinkedTxn'], list):
|
||||||
|
# print(sodt)
|
||||||
|
so_linkedTxn = [sodt['LinkedTxn']] #make a list
|
||||||
|
else:
|
||||||
|
so_linkedTxn = sodt['LinkedTxn'] #just copy, already list
|
||||||
|
# print(sodt)
|
||||||
|
for solinkedtxn in so_linkedTxn:
|
||||||
|
# print(len(so_linkedTxn))
|
||||||
|
if solinkedtxn['TxnType']=='Invoice' and len(so_linkedTxn)==1:
|
||||||
|
# print(sodt['RefNumber'], 'the only one SO')
|
||||||
|
is_soLinkedToOneInvoice=True
|
||||||
|
# pass
|
||||||
|
else:
|
||||||
|
is_soLinkedToOneInvoice=False
|
||||||
|
print(sodt['RefNumber'], 'NOT the only One, this SO have other Invoice number') #make append to a list
|
||||||
|
soNotInOneInv.append(sodt['RefNumber'])
|
||||||
|
|
||||||
|
if float(linkedtxn['Amount'])<0:
|
||||||
|
# if sodt['TotalAmount']!=linkedtxn['Amount'][1:]:
|
||||||
|
# pass
|
||||||
|
# if is_soLinkedToOneInvoice: #maybe the SO is manually closed, check it item by item, find which item is not in invoice
|
||||||
|
# if sodt['IsManuallyClosed'] == 'true':
|
||||||
|
# pass
|
||||||
|
# print(f"{sodt['TxnID'] = } {sodt['RefNumber'] = }")
|
||||||
|
# manuallyClosedSO.append(sodt['RefNumber'])
|
||||||
|
# else:
|
||||||
|
# print('SO TotalAmount<>Amount in Invoice. not Manually closed and not fully Invoiced')
|
||||||
|
# pprint(f'{linkedtxn = }', sort_dicts=False)
|
||||||
|
# print(f"{sodt['TxnID'] = } {sodt['RefNumber'] = }")
|
||||||
|
# print(sodt)
|
||||||
|
# openSO.append(sodt['RefNumber'])
|
||||||
|
# else:
|
||||||
|
pass # this SO is fully invoiced, starting process to export the details
|
||||||
|
try:
|
||||||
|
if not isinstance(sodt['SalesOrderLineRet'],list):
|
||||||
|
sodt['SalesOrderLineRet'] = [sodt['SalesOrderLineRet']]
|
||||||
|
if not isinstance(txn['InvoiceLineRet'],list):
|
||||||
|
txn['InvoiceLineRet'] = [txn['InvoiceLineRet']]
|
||||||
|
for so_line in sodt['SalesOrderLineRet']:
|
||||||
|
checklist = ['ItemRef', ]
|
||||||
|
if len([ i for i in checklist if i in so_line])==0:
|
||||||
|
continue
|
||||||
|
sotxnlineid = so_line['TxnLineID']
|
||||||
|
soitemref_fullname = so_line.get('ItemRef',{}).get('FullName')
|
||||||
|
soquantity:str = so_line.get('Quantity')
|
||||||
|
# print(f'{soquantity = }')
|
||||||
|
sounitofmeasure = so_line.get('UnitOfMeasure')
|
||||||
|
# sooverrideuomsetref_fullname = so_line['OverrideUOMSetRef']['FullName']
|
||||||
|
sorate = so_line.get('Rate')
|
||||||
|
soamount = so_line.get('Amount')
|
||||||
|
soinvoiced = so_line.get('Invoiced')
|
||||||
|
soismanuallyclosed = so_line['IsManuallyClosed']
|
||||||
|
soother2 = so_line.get('Other2')
|
||||||
|
|
||||||
|
#check compare to the invoicelineret
|
||||||
|
for inv_line in txn['InvoiceLineRet']: #loop start from top in order
|
||||||
|
is_inv_so_line_ok = True
|
||||||
|
if 'soline' not in inv_line: #this line has no so link yet
|
||||||
|
if inv_line.get('ItemRef',{}).get('FullName') != soitemref_fullname:
|
||||||
|
continue
|
||||||
|
if inv_line.get('UnitOfMeasure') != sounitofmeasure:
|
||||||
|
print(f"{inv_line['ItemRef']['FullName'] = } {inv_line['UnitOfMeasure']=} != {sounitofmeasure=}")
|
||||||
|
is_inv_so_line_ok = False
|
||||||
|
#do convertion????
|
||||||
|
# continue
|
||||||
|
if soinvoiced and inv_line.get('Quantity',0)!=soinvoiced: #compre with the invoiced
|
||||||
|
print(f"{inv_line['ItemRef']['FullName'] = } {inv_line['Quantity']=} != {soquantity=}")
|
||||||
|
is_inv_so_line_ok = False
|
||||||
|
if sorate:
|
||||||
|
if float(inv_line.get('Rate',0))!=float(sorate):
|
||||||
|
print(f"{inv_line['ItemRef']['FullName'] = } {inv_line['Rate']=} <> {sorate=} ; {float(inv_line.get('Rate',0)) = } {float(sorate) = }")
|
||||||
|
is_inv_so_line_ok = False
|
||||||
|
# if soamount:
|
||||||
|
# if float(inv_line.get('Amount',0))!=float(soamount):
|
||||||
|
# print(f"{txn['RefNumber']} {inv_line['ItemRef']['FullName'] = } {inv_line['Amount']=} != {soamount=}")
|
||||||
|
# is_inv_so_line_ok = False
|
||||||
|
if not is_inv_so_line_ok:
|
||||||
|
print(f"{inv_line['ItemRef']['FullName'] = } Some detail not equal")
|
||||||
|
continue
|
||||||
|
#add to the spesific invoiceline
|
||||||
|
inv_line['soline']= {'TxnID':sodt['TxnID'],
|
||||||
|
'RefNumber':sodt['RefNumber'],
|
||||||
|
'TxnDate':sodt['TxnDate'],
|
||||||
|
'TxnLineID': sotxnlineid,
|
||||||
|
'ItemRef_FullName':soitemref_fullname,
|
||||||
|
'Quantity':soquantity,
|
||||||
|
'UnitOfMeasure':sounitofmeasure,
|
||||||
|
'Rate':sorate,
|
||||||
|
'Amount':soamount,
|
||||||
|
'Invoiced':soinvoiced,
|
||||||
|
'IsManuallyClosed':soismanuallyclosed,
|
||||||
|
'Other2':soother2}
|
||||||
|
break
|
||||||
|
except Exception as e:
|
||||||
|
print(f"SO {sodt['RefNumber'] = } {txn['RefNumber'] = }")
|
||||||
|
print(f'ERROR: {e}')
|
||||||
|
else:
|
||||||
|
print('Linkedtxn amount is positif(should be negatif')
|
||||||
|
except Exception as e:
|
||||||
|
# print('ERROR')
|
||||||
|
# pprint(linkedtxn, sort_dicts=False)
|
||||||
|
# print(f"{sodt['TxnID'] = }")
|
||||||
|
print(f"{sodt['RefNumber'] = } {txn['RefNumber'] = }")
|
||||||
|
print(f'ERROR: {e}')
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
nolinkInv.append(txn)
|
||||||
|
# c =next(iter(iq_list))
|
||||||
|
# print('TEST RESULT:')
|
||||||
|
# pprint(c, sort_dicts=False)
|
||||||
|
print(f'{len(nolinkInv) = }\n{nolinkInv = }\n{soNotInOneInv = }\n{manuallyClosedSO = }\n{openSO = }\n{len(fullyInvoicedSO) = }')
|
||||||
|
c = [item for item in so_list if item not in fullyInvoicedSO]
|
||||||
|
print(f'not fuuly invoice, leftover SO: {c}')
|
||||||
|
return iq_list
|
||||||
|
|
||||||
|
|
||||||
|
def checking_iqwith_so(iq_list):
|
||||||
|
if not iq_list:
|
||||||
|
return False
|
||||||
|
if not isinstance(iq_list,list):
|
||||||
|
iq_list = [iq_list]
|
||||||
|
inv_nolineret = []
|
||||||
|
inv_line_no_soline = []
|
||||||
|
inv_line_no_itemref = []
|
||||||
|
for txn in iq_list:
|
||||||
|
if 'InvoiceLineRet' not in txn:
|
||||||
|
print(f"{txn['RefNumber'] = } doesnt have InvoiceLineRet")
|
||||||
|
inv_nolineret.append(txn['RefNumber'])
|
||||||
|
continue
|
||||||
|
# if 'LinkedTxn'
|
||||||
|
if not isinstance(txn['InvoiceLineRet'], list):
|
||||||
|
txn['InvoiceLineRet'] = [txn['InvoiceLineRet']]
|
||||||
|
for idx, inv_line in enumerate(txn['InvoiceLineRet']):
|
||||||
|
if 'ItemRef' not in inv_line:
|
||||||
|
inv_line_no_itemref.append({'RefNumber':txn['RefNumber'],
|
||||||
|
'idx':idx,})
|
||||||
|
continue
|
||||||
|
if 'soline' in inv_line:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if '400_Sales' not in inv_line['ItemRef']['FullName'] and 'Sales Promo Discount' not in inv_line['ItemRef']['FullName']:
|
||||||
|
inv_line_no_soline.append({'RefNumber':txn['RefNumber'],
|
||||||
|
'idx':idx,
|
||||||
|
'ItemRef_FullName':inv_line['ItemRef']['FullName'],
|
||||||
|
'Amount':inv_line['Amount']})
|
||||||
|
print(f'{inv_line_no_soline = }')
|
||||||
|
print(f'{inv_line_no_itemref = }')
|
||||||
|
print(f'{inv_nolineret = }')
|
||||||
|
if inv_line_no_soline or inv_line_no_itemref or inv_nolineret:
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def make_invoiceadd_dict(iq_list):
|
||||||
|
print('make_invoiceadd_dict')
|
||||||
|
# status = checking_iqwith_so(iq_list)
|
||||||
|
# print(status)
|
||||||
|
# if not status:
|
||||||
|
# return False
|
||||||
|
inv_nolineret = []
|
||||||
|
inv_line_no_soline = []
|
||||||
|
inv_line_no_itemref = []
|
||||||
|
invoiceaddlist = []
|
||||||
|
for inv_line in iq_list:
|
||||||
|
# if 'InvoiceLineRet' not in txn:
|
||||||
|
# print(f"{txn['RefNumber'] = } doesnt have InvoiceLineRet")
|
||||||
|
# inv_nolineret.append(txn['RefNumber'])
|
||||||
|
# continue
|
||||||
|
# if not isinstance(txn['InvoiceLineRet'], list):
|
||||||
|
# txn['InvoiceLineRet'] = [txn['InvoiceLineRet']]
|
||||||
|
# for idx, inv_line in enumerate(txn['InvoiceLineRet']):
|
||||||
|
invadddict = {}
|
||||||
|
# pprint(inv_line, sort_dicts=False)
|
||||||
|
invadddict['CustomerRef_FullName'] = inv_line['CustomerRef']['FullName']
|
||||||
|
invadddict['ARAccountRef_FullName']= inv_line['ARAccountRef']['FullName']
|
||||||
|
invadddict['TemplateRef_FullName'] = inv_line['TemplateRef']['FullName']
|
||||||
|
invadddict['TxnDate'] = inv_line['TxnDate']
|
||||||
|
invadddict['RefNumber'] = inv_line['RefNumber']
|
||||||
|
invadddict['BillAddress_Addr1'] = inv_line['BillAddress'].get('Addr1')
|
||||||
|
invadddict['BillAddress_Addr2'] = inv_line['BillAddress'].get('Addr2')
|
||||||
|
invadddict['BillAddress_Addr3'] = inv_line['BillAddress'].get('Addr3')
|
||||||
|
invadddict['BillAddress_Addr4'] = inv_line['BillAddress'].get('Addr4')
|
||||||
|
invadddict['BillAddress_Addr5'] = inv_line['BillAddress'].get('Addr5')
|
||||||
|
invadddict['BillAddress_City'] = inv_line['BillAddress'].get('City')
|
||||||
|
invadddict['BillAddress_State'] = inv_line['BillAddress'].get('State')
|
||||||
|
invadddict['BillAddress_PostalCode'] = inv_line['BillAddress'].get('PostalCode')
|
||||||
|
invadddict['BillAddress_Country'] = inv_line['BillAddress'].get('Country')
|
||||||
|
invadddict['BillAddress_Note'] = inv_line['BillAddress'].get('Note')
|
||||||
|
if 'ShipAddress' in inv_line:
|
||||||
|
invadddict['ShipAddress_Addr1'] = inv_line['ShipAddress'].get('Addr1')
|
||||||
|
invadddict['ShipAddress_Addr2'] = inv_line['ShipAddress'].get('Addr2')
|
||||||
|
invadddict['ShipAddress_Addr3'] = inv_line['ShipAddress'].get('Addr3')
|
||||||
|
invadddict['ShipAddress_Addr4'] = inv_line['ShipAddress'].get('Addr4')
|
||||||
|
invadddict['ShipAddress_Addr5'] = inv_line['ShipAddress'].get('Addr5')
|
||||||
|
invadddict['ShipAddress_City'] = inv_line['ShipAddress'].get('City')
|
||||||
|
invadddict['ShipAddress_State'] = inv_line['ShipAddress'].get('State')
|
||||||
|
invadddict['ShipAddress_PostalCode'] = inv_line['ShipAddress'].get('PostalCode')
|
||||||
|
invadddict['ShipAddress_Country'] = inv_line['ShipAddress'].get('Country')
|
||||||
|
invadddict['ShipAddress_Note'] = inv_line['ShipAddress'].get('Note')
|
||||||
|
if inv_line.get('PONumber'):
|
||||||
|
invadddict['PONumber'] = inv_line.get('PONumber')
|
||||||
|
invadddict['TermsRef_FullName'] = inv_line['TermsRef']['FullName']
|
||||||
|
invadddict['DueDate'] = inv_line['DueDate']
|
||||||
|
if 'SalesRepRef' in inv_line:
|
||||||
|
invadddict['SalesRepRef_FullName'] = inv_line['SalesRepRef']['FullName']
|
||||||
|
invadddict['ShipDate'] = inv_line['ShipDate']
|
||||||
|
if inv_line.get('Memo'):
|
||||||
|
invadddict['Memo'] = inv_line['Memo']
|
||||||
|
invadddict['IsToBePrinted'] = "false"
|
||||||
|
invadddict['IsToBeEmailed'] = "false"
|
||||||
|
if 'Other' in inv_line :
|
||||||
|
invadddict['Other'] = inv_line['Other']
|
||||||
|
|
||||||
|
#InvoiceLineAdd BEGIN
|
||||||
|
invoicelineadd_list = []
|
||||||
|
txnid_list = []
|
||||||
|
if not isinstance(inv_line['InvoiceLineRet'], list):
|
||||||
|
inv_line['InvoiceLineRet'] = [inv_line['InvoiceLineRet']]
|
||||||
|
|
||||||
|
for idx, invlineret in enumerate(inv_line['InvoiceLineRet']):
|
||||||
|
print(f'{invlineret = }')
|
||||||
|
if 'ItemRef' not in invlineret:
|
||||||
|
inv_line_no_itemref.append({'RefNumber':inv_line['RefNumber'],
|
||||||
|
'idx':idx,})
|
||||||
|
continue
|
||||||
|
invlineadd={}
|
||||||
|
if 'soline' not in invlineret:
|
||||||
|
invlineadd['ItemRef_FullName'] = invlineret['ItemRef']['FullName']
|
||||||
|
# invlineadd['Desc'] = invlineret['Desc']
|
||||||
|
if 'Quantity' in invlineret:
|
||||||
|
invlineadd['Quantity'] = invlineret['Quantity']
|
||||||
|
if 'UnitOfMeasure' in invlineret:
|
||||||
|
invlineadd['UnitOfMeasure'] = invlineret['UnitOfMeasure']
|
||||||
|
invlineadd['Rate'] = invlineret['Rate']
|
||||||
|
invlineadd['Amount'] = invlineret['Amount']
|
||||||
|
if 'Other1' in invlineret:
|
||||||
|
invlineadd['Other1'] = invlineret['Other1']
|
||||||
|
if 'Other2' in invlineret:
|
||||||
|
invlineadd['Other2'] = invlineret['Other2']
|
||||||
|
# print(f"{invlineadd = } {invlineret['ItemRef']['FullName']=}")
|
||||||
|
### WARNING, check with the real TxnID in new QB. Replace the soline TxnID and TxnLineID with New QB SalesOrder
|
||||||
|
if 'soline' in invlineret: ### WARNING, check with the real TxnID in new QB
|
||||||
|
invlineadd['LinkToTxn_TxnID'] = invlineret['soline']['TxnID']
|
||||||
|
invlineadd['LinkToTxn_TxnLineID'] = invlineret['soline']['TxnLineID']
|
||||||
|
txnid_list.append(invlineret['soline']['TxnID'])
|
||||||
|
invoicelineadd_list.append(invlineadd)
|
||||||
|
# print(invlineadd)
|
||||||
|
# print(invoicelineadd_list)
|
||||||
|
txnid = list(set(txnid_list))
|
||||||
|
# if txnid:
|
||||||
|
# invadddict['LinkToTxnID']=txnid
|
||||||
|
invadddict['InvoiceLineAdd'] = invoicelineadd_list
|
||||||
|
invoiceaddlist.append(invadddict)
|
||||||
|
|
||||||
|
pprint(invadddict, sort_dicts=False)
|
||||||
|
for x in invoiceaddlist:
|
||||||
|
if '10671' in x['RefNumber']:
|
||||||
|
pprint(x, sort_dicts=False)
|
||||||
|
break
|
||||||
|
# for y in x['InvoiceLineAdd']:
|
||||||
|
# if '10671' in y['ItemRef_FullName']:
|
||||||
|
# pprint(x, sort_dicts=False)
|
||||||
|
# break
|
||||||
|
print(f'{len(invoiceaddlist) = }')
|
||||||
|
|
||||||
|
def writeToFile(iq_list=None, so_dict=None, filename = "", suffix="", indent=2):
|
||||||
|
if not filename:
|
||||||
|
return False
|
||||||
|
try:
|
||||||
|
if iq_list:
|
||||||
|
if indent==None:
|
||||||
|
iq_list_json = json.dumps(iq_list)
|
||||||
|
else:
|
||||||
|
iq_list_json = json.dumps(iq_list, indent=indent)
|
||||||
|
with open(f"{filename}{suffix}.json", "w") as outfile:
|
||||||
|
outfile.write(iq_list_json)
|
||||||
|
if so_dict:
|
||||||
|
if indent==None:
|
||||||
|
so_dict_json = json.dumps(so_dict)
|
||||||
|
else:
|
||||||
|
so_dict_json = json.dumps(so_dict, indent=indent)
|
||||||
|
with open(f"{filename}_so_dict{suffix}.json", "w") as outfile:
|
||||||
|
outfile.write(so_dict_json)
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
print(e)
|
||||||
|
return False
|
||||||
|
|
||||||
|
def readJsonFromFile(filename):
|
||||||
|
try:
|
||||||
|
with open(filename, "r") as infile:
|
||||||
|
_list = json.load(infile)
|
||||||
|
return _list
|
||||||
|
except Exception as e:
|
||||||
|
print(e)
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
def get_last_date_of_month(stryearmonth:str):
|
||||||
|
# Get Last date of Month
|
||||||
|
# Using replace() + timedelta()
|
||||||
|
|
||||||
|
# initializing date
|
||||||
|
test_date = datetime.datetime.fromisoformat(stryearmonth)
|
||||||
|
# test_date = datetime.datetime(2018, 6, 4)
|
||||||
|
|
||||||
|
# printing original date
|
||||||
|
print("The original date is : " + str(test_date))
|
||||||
|
|
||||||
|
# getting next month
|
||||||
|
# using replace to get to last day + offset
|
||||||
|
# to reach next month
|
||||||
|
nxt_mnth = test_date.replace(day=28) + datetime.timedelta(days=4)
|
||||||
|
|
||||||
|
# subtracting the days from next month date to
|
||||||
|
# get last date of current Month
|
||||||
|
res = nxt_mnth - datetime.timedelta(days=nxt_mnth.day)
|
||||||
|
|
||||||
|
# printing result
|
||||||
|
datesplit = stryearmonth.split('-')
|
||||||
|
print("Last date of month : " + str(res.day), f"{datesplit[0]}-{datesplit[1]}-{str(res.day)}")
|
||||||
|
|
||||||
|
return f"{datesplit[0]}-{datesplit[1]}-{str(res.day)}"
|
||||||
|
|
||||||
|
def main(fromtxndate, totxndate, maxreturned:int=None):
|
||||||
|
# print(timeit.repeat(process, repeat=1))
|
||||||
|
# process()
|
||||||
|
|
||||||
|
invqueryfilename = f'exim\Data\{fromtxndate}iq'
|
||||||
|
# if maxreturned:
|
||||||
|
# iq_list, so_dict = get_all_so_from_invoice(MaxReturned=maxreturned)
|
||||||
|
|
||||||
|
# else:
|
||||||
|
# try:
|
||||||
|
# _fromdate = datetime.datetime.fromisoformat(fromtxndate)
|
||||||
|
# _todate = datetime.datetime.fromisoformat(totxndate)
|
||||||
|
# except Exception as e:
|
||||||
|
# print('date format should be yyyy-mm-dd example: "2024-03-09"')
|
||||||
|
# return False
|
||||||
|
|
||||||
|
# ## Reading from QB and write to a file depends on txndate
|
||||||
|
# iq_list, so_dict = get_all_so_from_invoice(FromTxnDate=fromtxndate, ToTxnDate=totxndate)
|
||||||
|
# writeToFile(iq_list, so_dict, filename=invqueryfilename)
|
||||||
|
|
||||||
|
### reading from existing file the iq_list and so_dict jsonfile
|
||||||
|
|
||||||
|
iq_list = readJsonFromFile(f"{invqueryfilename}.json")
|
||||||
|
so_dict = readJsonFromFile(f"{invqueryfilename}_so_dict.json")
|
||||||
|
print(f'{len(iq_list) = } {len(so_dict) = }')
|
||||||
|
iq_list = process_data(iq_list, so_dict)
|
||||||
|
suffix = '_withsoindent2'
|
||||||
|
writeToFile(iq_list, filename=f'{invqueryfilename}', suffix=suffix, indent=2)
|
||||||
|
iq_list = readJsonFromFile(f'{invqueryfilename}{suffix}.json')
|
||||||
|
print(len(iq_list))
|
||||||
|
print(f'Seems {invqueryfilename}{suffix}.json is {checking_iqwith_so(iq_list)}') #checking the iq_list. is it good to import to new QB?
|
||||||
|
|
||||||
|
make_invoiceadd_dict(iq_list)
|
||||||
|
|
||||||
|
if __name__=='__main__':
|
||||||
|
# print(np.arange('2021-02', '2021-03', dtype='datetime64[D]'))
|
||||||
|
fromtxndate = '2022-08-01'
|
||||||
|
totxndate = get_last_date_of_month(fromtxndate)
|
||||||
|
_fromdate = datetime.datetime.fromisoformat(fromtxndate)
|
||||||
|
|
||||||
|
print(fromtxndate)
|
||||||
|
main(fromtxndate, totxndate)
|
||||||
137
exim_testimport.py
Normal file
137
exim_testimport.py
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
dt2 = [{'CustomerRef_FullName': 'JM Abadi',
|
||||||
|
'ARAccountRef_FullName': 'Accounts Receivable',
|
||||||
|
'TemplateRef_FullName': 'DBW Invoice (11%)',
|
||||||
|
'TxnDate': '2022-08-26',
|
||||||
|
'RefNumber': '10671',
|
||||||
|
'BillAddress_Addr1': 'JM Abadi',
|
||||||
|
'BillAddress_Addr2': 'Jl. Raya Ps. Minggu No. 75',
|
||||||
|
'BillAddress_Addr3': None,
|
||||||
|
'BillAddress_Addr4': None,
|
||||||
|
'BillAddress_Addr5': None,
|
||||||
|
'BillAddress_City': None,
|
||||||
|
'BillAddress_State': None,
|
||||||
|
'BillAddress_PostalCode': None,
|
||||||
|
'BillAddress_Country': None,
|
||||||
|
'BillAddress_Note': None,
|
||||||
|
'ShipAddress_Addr1': 'JM Abadi',
|
||||||
|
'ShipAddress_Addr2': 'Jl. Raya Ps. Minggu No. 75',
|
||||||
|
'ShipAddress_Addr3': None,
|
||||||
|
'ShipAddress_Addr4': None,
|
||||||
|
'ShipAddress_Addr5': None,
|
||||||
|
'ShipAddress_City': None,
|
||||||
|
'ShipAddress_State': None,
|
||||||
|
'ShipAddress_PostalCode': None,
|
||||||
|
'ShipAddress_Country': None,
|
||||||
|
'ShipAddress_Note': None,
|
||||||
|
'TermsRef_FullName': '30 Hari',
|
||||||
|
'DueDate': '2022-09-25',
|
||||||
|
'SalesRepRef_FullName': 'W',
|
||||||
|
'ShipDate': '2022-08-26',
|
||||||
|
'IsToBePrinted': 'false',
|
||||||
|
'IsToBeEmailed': 'false',
|
||||||
|
'InvoiceLineAdd': [{'Quantity': '12',
|
||||||
|
'UnitOfMeasure': 'Box',
|
||||||
|
'Rate': '35000',
|
||||||
|
'Amount': '420000.00',
|
||||||
|
'LinkToTxn_TxnID': 'A289A-1661495309',
|
||||||
|
'LinkToTxn_TxnLineID': 'A289C-1661495309'},
|
||||||
|
{'Quantity': '6',
|
||||||
|
'UnitOfMeasure': 'Box',
|
||||||
|
'Rate': '122500',
|
||||||
|
'Amount': '735000.00',
|
||||||
|
'LinkToTxn_TxnID': 'A289A-1661495309',
|
||||||
|
'LinkToTxn_TxnLineID': 'A289D-1661495309'}]},
|
||||||
|
{'CustomerRef_FullName': 'JM Abadi',
|
||||||
|
'ARAccountRef_FullName': 'Accounts Receivable',
|
||||||
|
'TemplateRef_FullName': 'DBW Invoice (11%)',
|
||||||
|
'TxnDate': '2022-08-26',
|
||||||
|
'RefNumber': '10671',
|
||||||
|
'BillAddress_Addr1': 'JM Abadi',
|
||||||
|
'BillAddress_Addr2': 'Jl. Raya Ps. Minggu No. 75',
|
||||||
|
'BillAddress_Addr3': None,
|
||||||
|
'BillAddress_Addr4': None,
|
||||||
|
'BillAddress_Addr5': None,
|
||||||
|
'BillAddress_City': None,
|
||||||
|
'BillAddress_State': None,
|
||||||
|
'BillAddress_PostalCode': None,
|
||||||
|
'BillAddress_Country': None,
|
||||||
|
'BillAddress_Note': None,
|
||||||
|
'ShipAddress_Addr1': 'JM Abadi',
|
||||||
|
'ShipAddress_Addr2': 'Jl. Raya Ps. Minggu No. 75',
|
||||||
|
'ShipAddress_Addr3': None,
|
||||||
|
'ShipAddress_Addr4': None,
|
||||||
|
'ShipAddress_Addr5': None,
|
||||||
|
'ShipAddress_City': None,
|
||||||
|
'ShipAddress_State': None,
|
||||||
|
'ShipAddress_PostalCode': None,
|
||||||
|
'ShipAddress_Country': None,
|
||||||
|
'ShipAddress_Note': None,
|
||||||
|
'TermsRef_FullName': '30 Hari',
|
||||||
|
'DueDate': '2022-09-25',
|
||||||
|
'SalesRepRef_FullName': 'W',
|
||||||
|
'ShipDate': '2022-08-26',
|
||||||
|
'IsToBePrinted': 'false',
|
||||||
|
'IsToBeEmailed': 'false',
|
||||||
|
'InvoiceLineAdd': [{'Quantity': '12',
|
||||||
|
'UnitOfMeasure': 'Box',
|
||||||
|
'Rate': '35000',
|
||||||
|
'Amount': '420000.00',
|
||||||
|
'LinkToTxn_TxnID': 'A289A-1661495309',
|
||||||
|
'LinkToTxn_TxnLineID': 'A289C-1661495309'},
|
||||||
|
{'Quantity': '6',
|
||||||
|
'UnitOfMeasure': 'Box',
|
||||||
|
'Rate': '122500',
|
||||||
|
'Amount': '735000.00',
|
||||||
|
'LinkToTxn_TxnID': 'A289A-1661495309',
|
||||||
|
'LinkToTxn_TxnLineID': 'A289D-1661495309'}]}]
|
||||||
|
# print(dt)
|
||||||
|
|
||||||
|
dt = {'CustomerRef_FullName': 'JM Abadi',
|
||||||
|
'ARAccountRef_FullName': 'Accounts Receivable',
|
||||||
|
'TemplateRef_FullName': 'DBW Invoice (11%)',
|
||||||
|
'TxnDate': '2022-08-26',
|
||||||
|
'RefNumber': '10671',
|
||||||
|
'BillAddress_Addr1': 'JM Abadi',
|
||||||
|
'BillAddress_Addr2': 'Jl. Raya Ps. Minggu No. 75',
|
||||||
|
'BillAddress_Addr3': None,
|
||||||
|
'BillAddress_Addr4': None,
|
||||||
|
'BillAddress_Addr5': None,
|
||||||
|
'BillAddress_City': None,
|
||||||
|
'BillAddress_State': None,
|
||||||
|
'BillAddress_PostalCode': None,
|
||||||
|
'BillAddress_Country': None,
|
||||||
|
'BillAddress_Note': None,
|
||||||
|
'ShipAddress_Addr1': 'JM Abadi',
|
||||||
|
'ShipAddress_Addr2': 'Jl. Raya Ps. Minggu No. 75',
|
||||||
|
'ShipAddress_Addr3': None,
|
||||||
|
'ShipAddress_Addr4': None,
|
||||||
|
'ShipAddress_Addr5': None,
|
||||||
|
'ShipAddress_City': None,
|
||||||
|
'ShipAddress_State': None,
|
||||||
|
'ShipAddress_PostalCode': None,
|
||||||
|
'ShipAddress_Country': None,
|
||||||
|
'ShipAddress_Note': None,
|
||||||
|
'TermsRef_FullName': '30 Hari',
|
||||||
|
'DueDate': '2022-09-25',
|
||||||
|
'SalesRepRef_FullName': 'W',
|
||||||
|
'ShipDate': '2022-08-26',
|
||||||
|
'IsToBePrinted': 'false',
|
||||||
|
'IsToBeEmailed': 'false',
|
||||||
|
'InvoiceLineAdd': [{'Quantity': '12',
|
||||||
|
'UnitOfMeasure': 'Box',
|
||||||
|
'Rate': '35000',
|
||||||
|
'Amount': '420000.00',
|
||||||
|
'LinkToTxn_TxnID': 'A289A-1661495309',
|
||||||
|
'LinkToTxn_TxnLineID': 'A289C-1661495309'},
|
||||||
|
{'Quantity': '6',
|
||||||
|
'UnitOfMeasure': 'Box',
|
||||||
|
'Rate': '122500',
|
||||||
|
'Amount': '735000.00',
|
||||||
|
'LinkToTxn_TxnID': 'A289A-1661495309',
|
||||||
|
'LinkToTxn_TxnLineID': 'A289D-1661495309'}]}
|
||||||
|
from QBClass.QBClasses import InvoiceAdd
|
||||||
|
|
||||||
|
# IA = InvoiceAdd(**dt, debug=True)
|
||||||
|
IA = InvoiceAdd(*dt2, debug=True) #a list
|
||||||
|
print(IA.all())
|
||||||
|
|
||||||
7
main.py
7
main.py
@ -265,7 +265,10 @@ async def get_generalsalesreport(request: Request):
|
|||||||
getdict = json.loads(getdict)
|
getdict = json.loads(getdict)
|
||||||
except:
|
except:
|
||||||
print('error get_gsr()')
|
print('error get_gsr()')
|
||||||
return {'message':'error getting GeneralSalesReport'}
|
if not getdict:
|
||||||
|
getdict = {'ReportDateMacro' : 'ThisYear'}
|
||||||
|
else:
|
||||||
|
return {'message':'error getting GeneralSalesReport'}
|
||||||
print(f'get_gsr 1-> {type(getdict)}, {getdict}')
|
print(f'get_gsr 1-> {type(getdict)}, {getdict}')
|
||||||
ReportDateMacro = getdict['ReportDateMacro'] if 'ReportDateMacro' in getdict else None
|
ReportDateMacro = getdict['ReportDateMacro'] if 'ReportDateMacro' in getdict else None
|
||||||
FromReportDate = getdict['FromReportDate'] if 'FromReportDate' in getdict else None
|
FromReportDate = getdict['FromReportDate'] if 'FromReportDate' in getdict else None
|
||||||
@ -274,7 +277,7 @@ async def get_generalsalesreport(request: Request):
|
|||||||
responseRt = GSRQ(GeneralSummaryReportType='SalesByCustomerSummary', ReportDateMacro=ReportDateMacro, FromReportDate=FromReportDate, ToReportDate=ToReportDate)
|
responseRt = GSRQ(GeneralSummaryReportType='SalesByCustomerSummary', ReportDateMacro=ReportDateMacro, FromReportDate=FromReportDate, ToReportDate=ToReportDate)
|
||||||
# print(f'get_gsr 2-> {type(responseRt)}, {responseRt}')
|
# print(f'get_gsr 2-> {type(responseRt)}, {responseRt}')
|
||||||
datas1=responseRt.get_datarow()
|
datas1=responseRt.get_datarow()
|
||||||
# print(f'get_gsr 3-> {type(datas1)}, {datas1}')
|
print(f'get_gsr 3-> {type(datas1)}, {datas1}')
|
||||||
print(f'{datetime.datetime.now()} get_gsr 4 finish -> {type(getdict)}, {getdict}')
|
print(f'{datetime.datetime.now()} get_gsr 4 finish -> {type(getdict)}, {getdict}')
|
||||||
print("")
|
print("")
|
||||||
|
|
||||||
|
|||||||
128
test from mike.py
Normal file
128
test from mike.py
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
import win32com.client
|
||||||
|
import xml.etree.ElementTree as ET
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# **🔹 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")
|
||||||
|
|
||||||
|
# Print hasil dalam format dictionary
|
||||||
|
print("Sales Orders:", sales_orders)
|
||||||
|
|
||||||
|
finally:
|
||||||
|
qb.close_connection()
|
||||||
Loading…
Reference in New Issue
Block a user