Skip to content

Commit

Permalink
QBO: Fetch customers by DisplayName rather than CompanyName
Browse files Browse the repository at this point in the history
We were fetching by `CompanyName` and then filtering with `pluck_customer_id_by_currency()`, because QBO doesn't allow filtering by `currencyRef`. A simpler way to achieve that is by filtering on `DisplayName`, since `create_customer()` includes the currency there.

Its nice to simplify the code like this, but the main reason for this change was to fix a problem where a WCEU invoice for WPML couldn't be approved. `get_customer()` returned id `4` when it should have returned id `3878`. `4` was created manually with the `USD` currency, and doesn't have the currency in the `DisplayName` like the code expects. When that customer was passed to `pluck_customer_id_by_currency()`, it returned `false` because it was looking for a company with the `EUR` currency. So then `probably_get_customer_id()` tried to create a `EUR` customer, but that failed because one already exists with that `DisplayName`.

There's about 70 of those manually created customers that are missing the currency in the `DisplayName`, so this will have the side-effect of creating an extra customer for them. There's no tangible problem with having multiple customers with the same currency for the same company, though; we already have a lot of them because `wcb_sponsor` posts are created with slightly different names -- e.g. "WooCommerce" and "WooCommerce LLC".

I didn't manually fix the `DisplayName` for the older customers because it would have taken too long to be worth it.

https://europe.wordcamp.org/2023/wp-admin/post.php?post=5117&action=edit
https://app.qbo.intuit.com/app/customerdetail?nameId=4
https://app.qbo.intuit.com/app/customerdetail?nameId=3878
https://help.developer.intuit.com/s/article/6240-Duplicate-Name-Exists-Error
https://help.developer.intuit.com/s/question/0D5G000004Dk7XKKAZ/how-to-query-with-currencyref-condition-in-customerqb-online
  • Loading branch information
iandunn committed Jan 27, 2023
1 parent 61493e1 commit af80fa3
Showing 1 changed file with 19 additions and 25 deletions.
44 changes: 19 additions & 25 deletions public_html/wp-content/plugins/wordcamp-qbo/wordcamp-qbo.php
Original file line number Diff line number Diff line change
Expand Up @@ -769,7 +769,7 @@ protected static function probably_get_customer_id( $sponsor, $currency_code ) {
* @return int|false|WP_Error A customer ID as integer, if one was found; false if no match was found; a WP_Error if an error occurred.
*/
protected static function get_customer( $customer_name, $currency_code ) {
$qbo_request = self::build_qbo_get_customer_request( $customer_name );
$qbo_request = self::build_qbo_get_customer_request( $customer_name, $currency_code );

if ( is_wp_error( $qbo_request ) ) {
return $qbo_request;
Expand All @@ -786,7 +786,7 @@ protected static function get_customer( $customer_name, $currency_code ) {
$body = json_decode( wp_remote_retrieve_body( $response ), true );

if ( isset( $body['QueryResponse']['Customer'][0]['Id'] ) ) {
$result = self::pluck_customer_id_by_currency( $body['QueryResponse']['Customer'], $currency_code );
$result = absint( $body['QueryResponse']['Customer'][0]['Id'] );
} elseif ( isset( $body['QueryResponse'] ) && 0 === count( $body['QueryResponse'] ) ) {
$result = false;
} else {
Expand All @@ -804,10 +804,11 @@ protected static function get_customer( $customer_name, $currency_code ) {
*
* @return array|WP_Error
*/
protected static function build_qbo_get_customer_request( $customer_name ) {
protected static function build_qbo_get_customer_request( $customer_name, $currency_code ) {
global $wpdb;

$customer_name = sanitize_text_field( $customer_name );
$customer_name = str_replace( ':', '-', $customer_name );

self::load_options();
$oauth_header = self::qbo_client()->get_oauth_header();
Expand All @@ -820,9 +821,14 @@ protected static function build_qbo_get_customer_request( $customer_name ) {
);

$request_url_query = array(
// QBO uses a custom query language based on (generic) SQL, but $wpdb->prepare still works in this context.
// @link https://developer.intuit.com/app/developer/qbo/docs/learn/explore-the-quickbooks-online-api/data-queries
'query' => $wpdb->prepare(
"SELECT * FROM Customer WHERE CompanyName = '%s'",
str_replace( ':', '-', $customer_name )
// We can't filter by `CurrencyRef`, but `create_customer()` includes it the DisplayName, so we
// can use that instead.
// @link https://help.developer.intuit.com/s/question/0D5G000004Dk7XKKAZ/how-to-query-with-currencyref-condition-in-customerqb-online
"SELECT * FROM Customer WHERE DisplayName = '%s'",
self::get_company_display_name( $customer_name, $currency_code )
),
);

Expand All @@ -834,7 +840,7 @@ protected static function build_qbo_get_customer_request( $customer_name ) {
),
);

$request_url_query = array_map( 'rawurlencode', $request_url_query ); // has to be done after get_oauth_header(), or oauth_signature won't be generated correctly
$request_url_query = array_map( 'rawurlencode', $request_url_query ); // Has to be done after get_oauth_header(), or oauth_signature won't be generated correctly.
$request_url = add_query_arg( $request_url_query, $request_url );

return array(
Expand All @@ -844,27 +850,15 @@ protected static function build_qbo_get_customer_request( $customer_name ) {
}

/**
* Pluck a Customer out of an array based on their currency
* Get the DisplayName for a company.
*
* QuickBook's API doesn't allow you to filter query results based on a CurrencyRef, so we have to do it
* manually.
* This should be used when creating and fetching Customers, to ensure they have consistent names. The currency
* is necessary because a Customer in QBO can only have one currency (I think).
*
* @param array $customers
* @param string $currency_code
*
* @return int|false A customer ID on success, or false on failure
* @link https://developer.intuit.com/app/developer/qbo/docs/api/accounting/all-entities/customer#the-customer-object
*/
protected static function pluck_customer_id_by_currency( $customers, $currency_code ) {
$customer_id = false;

foreach ( $customers as $customer ) {
if ( $customer['CurrencyRef']['value'] === $currency_code ) {
$customer_id = absint( $customer['Id'] );
break;
}
}

return $customer_id;
public static function get_company_display_name( string $customer_name, string $currency_code ) : string {
return sprintf( '%s - %s', $customer_name, $currency_code );
}

/**
Expand Down Expand Up @@ -944,7 +938,7 @@ protected static function build_qbo_create_customer_request( $sponsor, $currency
'GivenName' => $sponsor['first-name'],
'FamilyName' => $sponsor['last-name'],
'CompanyName' => $sponsor['company-name'],
'DisplayName' => sprintf( '%s - %s', $sponsor['company-name'], $currency_code ),
'DisplayName' => self::get_company_display_name( $sponsor['company-name'], $currency_code ),
'PrintOnCheckName' => $sponsor['company-name'],

'PrimaryPhone' => array(
Expand Down

0 comments on commit af80fa3

Please sign in to comment.