Skip to content

Add support to account id, payment type etc. #62

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 9 additions & 5 deletions CRM/Civiquickbooks/Contact.php
Original file line number Diff line number Diff line change
Expand Up @@ -576,11 +576,15 @@ protected function getQBOContacts($start_date_string) {
* to be an Organisation otherwise.
*/
protected function getQBOContactByName($name, $givenName = NULL) {
$query = (
empty($givenName)
? sprintf("SELECT * FROM Customer WHERE FullyQualifiedName = '%s'", addslashes($name))
: sprintf("SELECT * FROM Customer WHERE FamilyName = '%s' AND GivenName = '%s'", addslashes($name), addslashes($givenName))
);
$givenName = trim($givenName);
$inputParam = ['1' => [$name, 'String']];
$query = 'SELECT * FROM Customer WHERE FullyQualifiedName = %1';
if (!empty($givenName)) {
$inputParam['2'] = [$givenName, 'String'];
$query = 'SELECT * FROM Customer WHERE FamilyName = %1 AND GivenName = %2';
}
// Switch to CiviCRM to handle the single quote present in the contact name.
$query = CRM_Core_DAO::composeQuery($query, $inputParam);

try {
$dataService = CRM_Quickbooks_APIHelper::getAccountingDataServiceObject();
Expand Down
94 changes: 77 additions & 17 deletions CRM/Civiquickbooks/Invoice.php
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,12 @@ public function push($params = [], $limit = PHP_INT_MAX) {
}

if ($accountsInvoice->Id) {
// Get invoice SyncToken to avoid Stale object error:
// You and XXXX were working on this at the same time. XXX
// finished before you did, so your work was not saved.
$invoiceExiting = $this->getInvoiceFromQBO($record);
$accountsInvoice->SyncToken = $invoiceExiting->SyncToken;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have always been a little apprehensive about doing this in the push function, however on balance of things I guess if an important change had been made, it would have been pulled in during the InvoicePull call already anyway.
Approved

$result = $dataService->Update($accountsInvoice);

if ($last_error = $dataService->getLastError()) {
Expand Down Expand Up @@ -224,27 +230,51 @@ public static function pushPayments($contribution_id, $account_invoice) {

$dataService = CRM_Quickbooks_APIHelper::getAccountingDataServiceObject();
$result = [];

$quickbooksAccountId = civicrm_api3('Setting', 'getvalue', [
'name' => "quickbooks_account_id",
'group' => 'civiquickbooks',
]);
$paymentInstrument = CRM_Contribute_BAO_Contribution::buildOptions('payment_instrument_id', 'create');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think buildOptions is deprecated, this could be an API call?

foreach ($payments['values'] as $payment) {
$txnDate = $payment['trxn_date'];
$total = sprintf('%.5f', $payment['total_amount']);
$QBOPayment = \QuickBooksOnline\API\Facades\Payment::create(
[
'TotalAmt' => $total,
'CustomerRef' => $account_invoice->CustomerRef,
'CurrencyRef' => $account_invoice->CurrencyRef,
'TxnDate' => $txnDate,
'Line' => [
'Amount' => $total,
'LinkedTxn' => [
[
'TxnType' => 'Invoice',
'TxnId' => $account_invoice->Id,
],
$paymentInput = [
'TotalAmt' => $total,
'CustomerRef' => $account_invoice->CustomerRef,
'CurrencyRef' => $account_invoice->CurrencyRef,
'TxnDate' => $txnDate,
'Line' => [
'Amount' => $total,
'LinkedTxn' => [
[
'TxnType' => 'Invoice',
'TxnId' => $account_invoice->Id,
],
],
]
);
],
];
// check payment instrument present on record
if (!empty($payment['payment_instrument_id'])) {
$paymentMethodId = self::getPaymentMethod($paymentInstrument[$payment['payment_instrument_id']]);
if (!empty($paymentMethodId)) {
$paymentInput['PaymentMethodRef'] = ['value' => $paymentMethodId];
}
}

// set Account ID
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My understanding is that on the Quickbooks side, each product or service should have an Income account set, and we should defer where the payments go to this.

Is there a particular reason for having a setting for one particular income account that overrides this behaviour? It doesn't sound like the correct approach

if ($quickbooksAccountId) {
$paymentInput['DepositToAccountRef'] = ['value' => $quickbooksAccountId];
}

// set Transaction ID
if (!empty($payment['trxn_id'])) {
$paymentInput['PaymentRefNum'] = $payment['trxn_id'];
}
else if (!empty($payment['check_number'])) {
$paymentInput['PaymentRefNum'] = $payment['check_number'];
}

$QBOPayment = \QuickBooksOnline\API\Facades\Payment::create($paymentInput);
$result[] = $dataService->Add($QBOPayment);
}

Expand Down Expand Up @@ -628,7 +658,10 @@ protected function mapToAccounts($db_contribution, $accountsID, $SyncToken, $qb_
}

$lineTotal = $line_item['line_total'];

// Do not sync line items with zero quantity.
if (empty($line_item['qty'])) {
continue;
}
$tmp = [
'Id' => $i . '',
'LineNum' => $i,
Expand All @@ -641,6 +674,9 @@ protected function mapToAccounts($db_contribution, $accountsID, $SyncToken, $qb_
],
'UnitPrice' => $lineTotal / $line_item['qty'] * 1.00,
'Qty' => $line_item['qty'] * 1,
'TaxCodeRef' => [
'value' => $line_item_tax_ref,
],
],
];

Expand Down Expand Up @@ -853,6 +889,28 @@ public static function getQBOTaxCode($name) {
return $codes[$name];
}

/**
* get Payment Method for syncing
* @param $name
*/
public static function getPaymentMethod($name) {
$name = strtolower($name);
$paymentMethods =& \Civi::$statics[__CLASS__][__FUNCTION__];
if (!isset($paymentMethods[$name])) {
$query = 'SELECT * From PaymentMethod';
$dataService = CRM_Quickbooks_APIHelper::getAccountingDataServiceObject();
$result = $dataService->Query($query);
if (empty($result)) {
return;
}
foreach ($result as $paymentMethodObject) {
$paymentMethods[strtolower($paymentMethodObject->Name)] = $paymentMethodObject->Id;
}
}

return $paymentMethods[$name];
}

/**
* Map fields for a cancelled contribution to be updated to QuickBooks.
*
Expand Down Expand Up @@ -945,7 +1003,9 @@ protected function generateTaxDetails($line_items) {
* @throws \CiviCRM_API3_Exception
*/
protected function findPushContributions($params, $limit) {
// quickbook does not accept negative amount.
$accountInvoices = AccountInvoice::get()
->addJoin('Contribution AS contribution', 'INNER', ['contribution.total_amount', '>=', 0])
->addWhere('plugin', '=', $this->plugin)
->addWhere('connector_id', '=', 0)
->addWhere('accounts_status_id:name', 'NOT IN', ['completed'])
Expand Down
28 changes: 28 additions & 0 deletions CRM/Quickbooks/APIHelper.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
<?php

use QuickBooksOnline\API\Core\HttpClients\FaultHandler;
use CRM_Civiquickbooks_ExtensionUtil as E;

require E::path('vendor/autoload.php');

class CRM_Quickbooks_APIHelper {

Expand Down Expand Up @@ -317,4 +320,29 @@ public static function parseErrorResponse($error_response) {

return $error_message;
}

/**
* Function to get Accounts name and id.
* @return array
*/
public static function accountsName() {
if (!CRM_Quickbooks_APIHelper::isAuthorized()) {
return [];
}
// Get the accounts name and id from QuickBooks.
try {
$query = "SELECT * From Account where AccountType = 'Bank' AND Classification = 'Asset'";
$dataService = CRM_Quickbooks_APIHelper::getAccountingDataServiceObject();
$result = $dataService->Query($query);
$accountNames = [];
foreach ($result as $accountNameObject) {
$accountNames[$accountNameObject->Id] = $accountNameObject->Name;
}

return $accountNames;
}
catch (Exception $e) {
return [];
}
}
}
2 changes: 1 addition & 1 deletion managed/navigation.mgd.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
'url' => 'civicrm/admin/setting/quickbooks',
'icon' => NULL,
'permission' => [
'administer CiviCRM system',
'administer CiviCRM',
],
'permission_operator' => 'AND',
'parent_id.name' => 'Accounts_System',
Expand Down
22 changes: 22 additions & 0 deletions settings/civiquickbooks.setting.php
Original file line number Diff line number Diff line change
Expand Up @@ -310,4 +310,26 @@
],
'settings_pages' => ['quickbooks' => ['weight' => 1]],
],
'quickbooks_account_id' => [
'group_name' => E::ts('QuickBooks Online Settings'),
'group' => 'civiquickbooks',
'name' => 'quickbooks_account_id',
'type' => 'String',
'add' => '5.13',
'is_domain' => 1,
'is_contact' => 0,
'description' => 'QuickBook Payment Account ID',
'title' => 'QuickBook Account ID',
'help_text' => 'QuickBook Account ID',
'html_type' => 'Select',
'default' => '',
'quick_form_type' => 'Select',
'html_attributes' => [
'class' => 'crm-select2',
],
'pseudoconstant' => [
'callback' => 'CRM_Quickbooks_APIHelper::accountsName',
],
'settings_pages' => ['quickbooks' => ['weight' => 1]],
],
];
2 changes: 1 addition & 1 deletion xml/Menu/civiquickbooks.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
<path>civicrm/admin/setting/quickbooks</path>
<page_callback>CRM_Civiquickbooks_Form_Settings</page_callback>
<title>QuickBooks Online Settings</title>
<access_arguments>access CiviCRM</access_arguments>
<access_arguments>administer CiviCRM</access_arguments>
</item>
<item>
<path>civicrm/ajax/civiquickbooks/sync/contact/errors</path>
Expand Down