intuit / QuickBooks-V3-PHP-SDK

Official PHP SDK for QuickBooks REST API v3.0: https://developer.intuit.com/
Apache License 2.0
246 stars 246 forks source link

Unable to query `RecurringTransaction` #459

Open baaskoen opened 2 years ago

baaskoen commented 2 years ago

I'm on version: ^6.0 and I'm trying to get all RecurringTransaction:

$dataService = (new QuickbooksClient())
    ->getDataService();

$results = $dataService->Query('SELECT * FROM RecurringTransaction');

Then an exception is thrown:

Message: Exception appears in converting Response to XML.
File: v3-php-sdk/src/DataService/DataService.php
Line: 1035

I'm not getting this exception in other queries.

baaskoen commented 2 years ago

This is the content of $responseBody before it throws an exception:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<IntuitResponse xmlns="http://schema.intuit.com/finance/v3" time="2022-09-14T01:17:47.511-07:00">
    <QueryResponse startPosition="1" maxResults="1">
        <RecurringTransaction>
            <Invoice domain="QBO" sparse="false">
                <Id>182</Id>
                <SyncToken>1</SyncToken>
                <MetaData>
                    <CreateTime>2022-09-14T00:46:50-07:00</CreateTime>
                    <LastModifiedByRef>9130354723602346</LastModifiedByRef>
                    <LastUpdatedTime>2022-09-14T00:49:01-07:00</LastUpdatedTime>
                </MetaData>
                <CustomField>
                    <DefinitionId>1</DefinitionId>
                    <Name>Crew #</Name>
                    <Type>StringType</Type>
                </CustomField>
                <CurrencyRef name="United States Dollar">USD</CurrencyRef>
                <Line>
                    <Id>1</Id>
                    <LineNum>1</LineNum>
                    <Description>Doloribus.</Description>
                    <Amount>4.00</Amount>
                    <DetailType>SalesItemLineDetail</DetailType>
                    <SalesItemLineDetail>
                        <ItemRef name="Services">1</ItemRef>
                        <Qty>2</Qty>
                        <ItemAccountRef name="Services">1</ItemAccountRef>
                        <TaxCodeRef>NON</TaxCodeRef>
                        <TaxClassificationRef>EUC-99990201-V1-00020000</TaxClassificationRef>
                    </SalesItemLineDetail>
                </Line>
                <Line>
                    <Id>2</Id>
                    <LineNum>2</LineNum>
                    <Description>Accusantium quasi.</Description>
                    <Amount>6.00</Amount>
                    <DetailType>SalesItemLineDetail</DetailType>
                    <SalesItemLineDetail>
                        <ItemRef name="Services">1</ItemRef>
                        <Qty>2</Qty>
                        <ItemAccountRef name="Services">1</ItemAccountRef>
                        <TaxCodeRef>NON</TaxCodeRef>
                        <TaxClassificationRef>EUC-99990201-V1-00020000</TaxClassificationRef>
                    </SalesItemLineDetail>
                </Line>
                <Line>
                    <Amount>10.00</Amount>
                    <DetailType>SubTotalLineDetail</DetailType>
                    <SubTotalLineDetail/>
                </Line>
                <TxnTaxDetail>
                    <TxnTaxCodeRef>5</TxnTaxCodeRef>
                    <TotalTax>0</TotalTax>
                    <TaxLine>
                        <Amount>0</Amount>
                        <DetailType>TaxLineDetail</DetailType>
                        <TaxLineDetail>
                            <TaxRateRef>9</TaxRateRef>
                            <PercentBased>true</PercentBased>
                            <TaxPercent>0.5</TaxPercent>
                            <NetAmountTaxable>0</NetAmountTaxable>
                        </TaxLineDetail>
                    </TaxLine>
                    <TaxLine>
                        <Amount>0</Amount>
                        <DetailType>TaxLineDetail</DetailType>
                        <TaxLineDetail>
                            <TaxRateRef>6</TaxRateRef>
                            <PercentBased>true</PercentBased>
                            <TaxPercent>6.25</TaxPercent>
                            <NetAmountTaxable>0</NetAmountTaxable>
                        </TaxLineDetail>
                    </TaxLine>
                    <TaxLine>
                        <Amount>0</Amount>
                        <DetailType>TaxLineDetail</DetailType>
                        <TaxLineDetail>
                            <TaxRateRef>8</TaxRateRef>
                            <PercentBased>true</PercentBased>
                            <TaxPercent>1.5</TaxPercent>
                            <NetAmountTaxable>0</NetAmountTaxable>
                        </TaxLineDetail>
                    </TaxLine>
                    <TaxLine>
                        <Amount>0</Amount>
                        <DetailType>TaxLineDetail</DetailType>
                        <TaxLineDetail>
                            <TaxRateRef>7</TaxRateRef>
                            <PercentBased>true</PercentBased>
                            <TaxPercent>1</TaxPercent>
                            <NetAmountTaxable>0</NetAmountTaxable>
                        </TaxLineDetail>
                    </TaxLine>
                </TxnTaxDetail>
                <RecurDataRef>4</RecurDataRef>
                <RecurringInfo>
                    <Name>My company name</Name>
                    <RecurType>Automated</RecurType>
                    <Active>true</Active>
                    <ScheduleInfo>
                        <IntervalType>Daily</IntervalType>
                        <NumInterval>1</NumInterval>
                        <MaxOccurrences>5</MaxOccurrences>
                        <StartDate>2022-09-14</StartDate>
                        <NextDate>2022-09-14</NextDate>
                    </ScheduleInfo>
                </RecurringInfo>
                <CustomerRef name="My company name">65</CustomerRef>
                <CustomerMemo>THIS IS RECURRING</CustomerMemo>
                <FreeFormAddress>false</FreeFormAddress>
                <ShipFromAddr>
                    <Id>130</Id>
                    <Line1>123 Sierra Way</Line1>
                    <Line2>San Pablo, CA 87999 US</Line2>
                </ShipFromAddr>
                <TotalAmt>10.00</TotalAmt>
                <ApplyTaxAfterDiscount>false</ApplyTaxAfterDiscount>
                <PrintStatus>NeedToPrint</PrintStatus>
                <EmailStatus>NotSet</EmailStatus>
                <BillEmail>
                    <Address>email@domain.nl</Address>
                </BillEmail>
                <Balance>10.00</Balance>
                <TaxExemptionRef/>
                <AllowIPNPayment>false</AllowIPNPayment>
                <AllowOnlinePayment>false</AllowOnlinePayment>
                <AllowOnlineCreditCardPayment>false</AllowOnlineCreditCardPayment>
                <AllowOnlineACHPayment>false</AllowOnlineACHPayment>
            </Invoice>
        </RecurringTransaction>
    </QueryResponse>
</IntuitResponse>
fdalcin commented 2 years ago

I'm having the same issue and it appears to be a problem with the IPPRecurringTransaction class, I was debugging to see if I could better understand what was happening and this is what I got

[2022-11-23 19:32:44] local.ERROR: Property QuickBooksOnline\API\Data\IPPRecurringTransaction::$Invoice does not exist.
Class QuickBooksOnline\API\Data\IPPRecurringTransaction {"exception":"[object] (RuntimeException(code: 0): Property QuickBooksOnline\\API\\Data\\IPPRecurringTransaction::$Invoice does not exist. 
Class QuickBooksOnline\\API\\Data\\IPPRecurringTransaction at /app/vendor/quickbooks/v3-php-sdk/src/XSD2PHP/src/com/mikebevz/xsd2php/Bind.php:135)
rberlin01 commented 1 year ago

Bump. Running into the same issue and have confirmed the above reports.

cliffordvickrey commented 1 year ago

The problem is that the XSD, and the code extracted from there, doesn't match what comes back from the API.

My hacky fix:

<?php

// before API calls
if (!class_exists(\QuickBooksOnline\API\Data\IPPRecurringTransaction::class, false)) {
    require_once __DIR__ . '/Polyfill_IPPRecurringTransaction.php';
}

The "polyfill" with a fixed entity:

<?php

// Polyfill_IPPRecurringTransaction.php

namespace QuickBooksOnline\API\Data;

use function get_class;
use function property_exists;

/**
 * @xmlNamespace http://schema.intuit.com/finance/v3
 * @xmlType IntuitEntity
 * @xmlName IPPRecurringTransaction
 * @var IPPRecurringTransaction
 * @xmlDefinition The Recurrence Transaction Object
 */
class IPPRecurringTransaction extends IPPIntuitEntity
{
    /**
     * @xmlType element
     * @xmlName IntuitObject
     * @var com\intuit\schema\finance\v3\IntuitObject
     */
    public $IntuitObject;
    /**
     * @xmlType element
     * @xmlNamespace http://schema.intuit.com/finance/v3
     * @xmlMinOccurs 0
     * @xmlName Bill
     * @var com\intuit\schema\finance\v3\IPPBill
     */
    public $Bill;
    /**
     * @xmlType element
     * @xmlNamespace http://schema.intuit.com/finance/v3
     * @xmlMinOccurs 0
     * @xmlName Purchase
     * @var com\intuit\schema\finance\v3\IPPPurchase
     */
    public $Purchase;
    /**
     * @xmlType element
     * @xmlNamespace http://schema.intuit.com/finance/v3
     * @xmlMinOccurs 0
     * @xmlName CreditMemo
     * @var com\intuit\schema\finance\v3\IPPCreditMemo
     */
    public $CreditMemo;
    /**
     * @xmlType element
     * @xmlNamespace http://schema.intuit.com/finance/v3
     * @xmlMinOccurs 0
     * @xmlName Deposit
     * @var com\intuit\schema\finance\v3\IPPDeposit
     */
    public $Deposit;
    /**
     * @xmlType element
     * @xmlNamespace http://schema.intuit.com/finance/v3
     * @xmlMinOccurs 0
     * @xmlName Estimate
     * @var com\intuit\schema\finance\v3\IPPEstimate
     */
    public $Estimate;
    /**
     * @xmlType element
     * @xmlNamespace http://schema.intuit.com/finance/v3
     * @xmlMinOccurs 0
     * @xmlName Invoice
     * @var com\intuit\schema\finance\v3\IPPInvoice
     */
    public $Invoice;
    /**
     * @xmlType element
     * @xmlNamespace http://schema.intuit.com/finance/v3
     * @xmlMinOccurs 0
     * @xmlName JournalEntry
     * @var com\intuit\schema\finance\v3\IPPJournalEntry
     */
    public $JournalEntry;
    /**
     * @xmlType element
     * @xmlNamespace http://schema.intuit.com/finance/v3
     * @xmlMinOccurs 0
     * @xmlName RefundReceipt
     * @var com\intuit\schema\finance\v3\IPPRefundReceipt
     */
    public $RefundReceipt;
    /**
     * @xmlType element
     * @xmlNamespace http://schema.intuit.com/finance/v3
     * @xmlMinOccurs 0
     * @xmlName SalesReceipt
     * @var com\intuit\schema\finance\v3\IPPSalesReceipt
     */
    public $SalesReceipt;
    /**
     * @xmlType element
     * @xmlNamespace http://schema.intuit.com/finance/v3
     * @xmlMinOccurs 0
     * @xmlName Transfer
     * @var com\intuit\schema\finance\v3\IPPTransfer
     */
    public $Transfer;
    /**
     * @xmlType element
     * @xmlNamespace http://schema.intuit.com/finance/v3
     * @xmlMinOccurs 0
     * @xmlName VendorCredit
     * @var com\intuit\schema\finance\v3\IPPVendorCredit
     */
    public $VendorCredit;
    /**
     * @xmlType element
     * @xmlNamespace http://schema.intuit.com/finance/v3
     * @xmlMinOccurs 0
     * @xmlName PurchaseOrder
     * @var com\intuit\schema\finance\v3\IPPPurchaseOrder
     */
    public $PurchaseOrder;

    /**
     * Initializes this object, optionally with pre-defined property values
     *
     * Initializes this object and it's property members, using the dictionary
     * of key/value pairs passed as an optional argument.
     *
     * @param dictionary $keyValInitializers key/value pairs to be populated into object's properties
     * @param boolean $verbose specifies whether object should echo warnings
     */
    public function __construct($keyValInitializers = array(), $verbose = FALSE)
    {
        foreach ($keyValInitializers as $initPropName => $initPropVal) {
            if (property_exists('IPPRecurringTransaction', $initPropName) || property_exists('QuickBooksOnline\API\Data\IPPRecurringTransaction', $initPropName)) {
                $this->{$initPropName} = $initPropVal;
            } else {
                if ($verbose)
                    echo "Property does not exist ($initPropName) in class (" . get_class($this) . ")";
            }
        }
    }
} // end class IPPRecurringTransaction