/[drupal]/contributions/modules/uc_qb/uc_qb.module
ViewVC logotype

Diff of /contributions/modules/uc_qb/uc_qb.module

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph | View Patch Patch

revision 1.1, Thu Aug 21 11:55:30 2008 UTC revision 1.1.2.1, Thu Aug 21 11:55:30 2008 UTC
# Line 0  Line 1 
1    <?php
2    // $Id: $
3    
4    /*
5     * @TODO:
6     *
7     * 1. Advanced/separated error system (using QBWC interactive error handling)
8     * 2. Import product data from QuickBooks
9     * 3. **Important** Update customer email addresses in QuickBooks when the user changes them
10     */
11    
12    /**
13     *  Implementation of hook_menu()
14     */
15    function uc_qb_menu($may_cache = false) {
16      $items = array();
17    
18      if ($may_cache) {
19            $items[] = array(
20          'path' => 'admin/store/settings/qb',
21          'title' => t('QB import/export'),
22          'description' => t('Import/Export store data to QuickBooks using Web Connector'),
23          'callback' => 'drupal_get_form',
24          'callback arguments' => array('uc_qb_settings'),
25          'access' => user_access('administer quickbooks import/export'),
26          'type' => MENU_NORMAL_ITEM,
27        );
28        // TODO: Write help page that also can display the latest errors
29        $items[] = array(
30          'path' => 'admin/store/settings/qb/help',
31          'title' => t('QuickBooks Import/Export Help'),
32          'description' => t('Detailed information for importing and exporting to QuickBooks using the Web Connector.'),
33          'callback' => 'uc_qb_admin_help',
34          'access' => user_access('administer quickbooks import/export'),
35          'type' => MENU_CALLBACK,
36        );
37      }
38    
39      return $items;
40    }
41    
42    /**
43     * Menu callback for settings related to QB import
44     */
45    function uc_qb_settings() {
46            $form = array();
47    
48      $form['uc_qb_start_order'] = array(
49        '#type' => 'textfield',
50        '#title' => t('Order # to start imports from'),
51        '#description' => t('Enter the order number of the order to start imports from. That order and all orders after will get included in the QB import process.'),
52        '#default_value' => variable_get('uc_qb_start_order', 0),
53      );
54      $form['uc_qb_failed_orders_email'] = array(
55        '#type' => 'textfield',
56        '#title' => t('Contact e-mail'),
57        '#description' => t('Enter the email address that will receive notifications of failed order exports'),
58        '#default_value' => variable_get('uc_qb_failed_orders_email', '')
59      );
60    
61      return system_settings_form($form);
62    }
63    
64    /**
65     * Implementation of hook_perm().
66     */
67    function uc_qb_perm() {
68      return array('administer quickbooks import/export');
69    }
70    
71    /**
72     * Implementation of hook_qbwc_authenticate()
73     */
74    function uc_qb_qbwc_authenticate($ticket, $user) {
75              // Make sure this is defined and set to an array to avoid errors
76      if (!is_array($_SESSION['qb_orders'])) {
77        $_SESSION['qb_orders'] = array();
78      }
79    
80      // Only deal with orders for now. Everything required to make a valid order in quickbooks will
81      // be exported, but nothing else (won't export customers/products without either of those being part of a purchase)
82      $last_export = variable_get('uc_qb_last_export', 0);
83    
84      // Get a list of orders needing exported
85      $result = db_query('SELECT DISTINCT(uop.order_id), uc.uid, uc.modified, uc.order_total, uc.primary_email, uc.order_status, uc.data as order_data, u.name, u.data as user_data FROM {uc_orders} uc INNER JOIN {users} u ON uc.uid = u.uid LEFT JOIN {uc_order_products} uop ON uc.order_id = uop.order_id WHERE uc.modified > "%d" AND order_status IN ("completed", "payment_received") AND uop.nid IS NOT NULL AND uc.order_id >= "%d" ORDER BY uc.modified ASC', $last_export, variable_get('uc_qb_start_order', 0));
86    
87      $_SESSION['qb_orders_count'] = db_num_rows($result);
88      $_SESSION['qb_orders_done'] = 0;
89    
90      while ($item = db_fetch_object($result)) {
91        $item->user_data = $item->uid ? unserialize($item->user_data) : array();
92        $item->order_data = unserialize($item->order_data);
93    
94        if ($item->order_data['QBProcessed']) {
95          // This item has already been processed
96          $_SESSION['qb_orders_count']--;
97          continue;
98        }
99    
100        // Save the orders in the session so we don't have to run the query again
101        $_SESSION['qb_orders'][$item->order_id] = $item;
102      }
103    
104      // Return true if orders need processing signaling we have work for QB
105      if (!empty($_SESSION['qb_orders'])) {
106            return true;
107      }
108    }
109    
110    /**
111     * Implementation of hook_qbwc_response()
112     *
113     * @Description: Receive queries for QB data and set appropriate session variables for use in hook_qbwc_request()
114     */
115    function uc_qb_qbwc_response($response, $hresult, $message, $saved) {
116      $done = &$_SESSION['qb_orders_done'];
117      $new = array();
118      // Go through the responses, dealing with each in turn
119      foreach((array)$response as $element) {
120        $requestId = $element->getAttribute('requestID');
121        $returnCnt = $element->getAttribute('retCount');
122        $statusCode = $element->getAttribute('statusCode');
123        $statusMessage = $element->getAttribute('statusMessage');
124    
125        if ($statusCode > 0) {
126            watchdog('uc_qb', t('QB responded to a request with error #%code (%message)', array('%code' => $statusCode, '%message' => $statusMessage)), WATCHDOG_ERROR);
127        }
128        if ($statusCode == 3231) {
129          // This element was not processed, so skip it
130            continue;
131        }
132    
133        switch($element->tagName) {
134          // Check if the checked shipping method is available or not, and if not queries it to be created
135          case 'ShipMethodAddRs':
136            if (!isset($saved[$requestId])) {
137              $error = true;
138              break;
139            }
140    
141            if ($statusCode == 0) {
142                    $_SESSION['qb_shipping_methods'][$saved[$requestId]['method']] = true;
143            }
144            else {
145                    $error = true;
146              break;
147            }
148          break;
149            case 'ShipMethodQueryRs':
150            if (!isset($saved[$requestId])) {
151              $error = true;
152              break;
153            }
154    
155            if ($returnCnt > 0) {
156                    $_SESSION['qb_shipping_methods'][$saved[$requestId]['method']] = true;
157            }
158            else {
159                    $new[] = array(
160                'name' => 'ShipMethodAddRq',
161                'request' => array('ShipMethodAdd' => array(
162                  'Name' => $saved[$requestId]['method'],
163                  'IsActive' => 'true'
164                )),
165                'data' => $saved[$requestId]
166              );
167            }
168          break;
169          case 'ItemServiceAddRs':
170            if (!isset($saved[$requestId])) {
171              $error = true;
172              break;
173            }
174    
175            if ($statusCode == 0) {
176                    $_SESSION['qb_services'][$saved[$requestId]] = true;
177            }
178            else {
179                    $error = true;
180              break;
181            }
182          break;
183          // Check if the SHIPPING service is available and create if necessary
184          case 'ItemServiceQueryRs':
185            if (!isset($saved[$requestId])) {
186              $error = true;
187              break;
188            }
189    
190            if ($returnCnt > 0) {
191              $_SESSION['qb_services'][$saved[$requestId]] = true;
192            }
193            else {
194              $new[] = array(
195                'name' => 'ItemServiceAddRq',
196                'request' => array('ItemServiceAdd' => array(
197                  'Name' => $saved[$requestId],
198                  'IsActive' => 'true',
199                  'SalesOrPurchase' => array(
200                    'Price' => '0.0',
201                    'AccountRef' => array(
202                      'FullName' => variable_get('uc_qb_service_account_'. $saved[$requestId], variable_get('uc_qb_service_account', 'Merchandise Sales'))
203                    )
204                  )
205                )),
206                'data' => $saved[$requestId]
207              );
208            }
209          break;
210          case 'PaymentMethodAddRs':
211            if (!isset($saved[$requestId])) {
212              $error = true;
213              break;
214            }
215    
216            // Check if the checked payment method is available or not, and if not queries it to be created
217            if ($statusCode == 0) {
218              $_SESSION['qb_payment_methods'][$saved[$requestId]] = true;
219            }
220            else {
221              $error = true;
222              break;
223            }
224          break;
225          case 'PaymentMethodQueryRs':
226            if (!isset($saved[$requestId])) {
227              $error = true;
228              break;
229            }
230    
231          // Check if the checked payment method is available or not, and if not queries it to be created
232            if ($returnCnt > 0) {
233              $_SESSION['qb_payment_methods'][$saved[$requestId]] = true;
234            }
235            else {
236              $new[] = array(
237                'name' => 'PaymentMethodAddRq',
238                'request' => array('PaymentMethodAdd' => array(
239                  'Name' => $saved[$requestId],
240                  'IsActive' => 'true'
241                )),
242                'data' => $saved[$requestId]
243              );
244            }
245          break;
246          // Check if the checked tax name is available or not, and if not queries it to be created
247          case 'ItemSalesTaxQueryRs':
248            if (!isset($saved[$requestId])) {
249              $error = true;
250              break;
251            }
252    
253            if ($returnCnt > 0) {
254              $_SESSION['qb_tax_types'][$saved[$requestId]->type] = true;
255            }
256            else {
257              $new[] = array(
258                'name' => 'ItemSalesTaxAddRq',
259                'request' => array('ItemSalesTaxAdd' => array(
260                  'Name' => $saved[$requestId]->type,
261                  'IsActive' => 'true'
262                ))
263              );
264            }
265          break;
266          // Check if the checked customers are available or not, and if not queries them to be created
267          case 'CustomerQueryRs':
268          case 'CustomerAddRs':
269            if (!isset($saved[$requestId])) {
270              $error = true;
271              break;
272            }
273    
274            $data = &$_SESSION['qb_orders'][$saved[$requestId]->order_id];
275            $data->qb_user_id_pending = false;
276            if ($statusCode == 0 && $user_id = $element->getElementsByTagName('ListID')->item(0)->nodeValue) {
277              $data->qb_user_id = $user_id;
278              if ($data->uid) {
279                $data->user_data['QBListID'] = $user_id;
280                db_query('UPDATE {users} SET data = "%s" WHERE uid = "%d"', serialize($data->user_data), $data->uid);
281              }
282              else {
283                $data->order_data['QBListID'] = $user_id;
284                db_query('UPDATE {uc_orders} SET data = "%s" WHERE order_id = "%d"', serialize($data->order_data), $data->order_id);
285              }
286            }
287            // If this is an anonymous user and already exists, get the ListID for it, any other situation should not happen and is an error
288            else if ($data->uid == 0 && $statusCode == 3100) {
289                    $new[] = array(
290                  'name' => 'CustomerQueryRq',
291                  'request' => array(
292                    'FullName' => $data->primary_email,
293                    'IncludeRetElement' => 'ListID'
294                  ),
295                  'data' => $saved[$requestId]
296                );
297            }
298            else {
299              // This should never happen. If it does, make a log entry for this order saying that it failed to get exported
300              watchdog('uc_qb', t('Order #%order_id (and possibly others from this user) failed to get exported to QB because the user failed to get exported with status code #%code (%message).', array('%code' => $statusCode, '%order_id' => $data->order_id, '%message' => $statusMessage)), WATCHDOG_ERROR);
301            }
302          break;
303          // Response to adding a receipt
304          case 'SalesReceiptAddRs':
305            $error = true;
306            $data = &$_SESSION['qb_orders'][$saved[$requestId]->order_id];
307            $data->order_data['QBProcessed'] =  true;
308            $total = $element->getElementsByTagName('TotalAmount')->item(0)->nodeValue;
309            if ($statusCode == 0 && round($total, 2) == round($data->order_total, 2)) {
310              db_query('UPDATE {uc_orders} SET data = "%s" WHERE order_id = "%d"', serialize($data->order_data), $data->order_id);
311              variable_set('uc_qb_last_export', $data->modified);
312              $done++;
313            }
314            // The amount recorded in QB does not match the right amount for some reason
315            else if ($statusCode == 0) {
316              $_SESSION['qb_failed_orders'][] = $saved[$requestId];
317              watchdog('uc_qb', t('Order #%order exported successfully, but the sales receipt total did not match the correct total', array('%order' => $saved[$requestId]->order_id, '%code' => $statusCode, '%message' => $statusMessage)), WATCHDOG_ERROR);
318    
319              // Make the receipt pending so that it does not get processed fully before somebody takes a look at it
320              $new[] = array(
321                'name' => 'SalesReceiptModRq',
322                'request' => array(
323                  'TxnID' => $element->getElementsByTagName('TxnID')->item(0)->nodeValue,
324                  'EditSequence' => $element->getElementsByTagName('EditSequence')->item(0)->nodeValue,
325                  'IsPending' => 'true'
326                ),
327                'data' => $saved[$requestId]
328              );
329            }
330            else {
331                    $_SESSION['qb_failed_orders'][] = $saved[$requestId];
332              $_SESSION['qb_orders_count']--;
333              watchdog('uc_qb', t('Failed to export the order #%order with error code %code (%message) to QB', array('%order' => $saved[$requestId]->order_id, '%code' => $statusCode, '%message' => $statusMessage)), WATCHDOG_ERROR);
334            }
335          break;
336          case 'SalesReceiptModRs':
337            //Successfully changed the receipt to pending. Mark this as done.
338            if ($statusCode == 0) {
339                    $_SESSION['qb_orders_count']--;
340            }
341            else {
342              watchdog('uc_qb', t('Failed to change the ', array('%order' => $saved[$requestId]->order_id, '%code' => $statusCode, '%message' => $statusMessage)), WATCHDOG_ERROR);
343            }
344          break;
345          // Response to a product search query
346          case 'ItemInventoryQueryRs':
347            $product = $saved[$requestId];
348            if ($returnCnt > 0) {
349              $model = $element->getElementsByTagName('Name')->item(0)->nodeValue;
350              $id = $element->getElementsByTagName('ListID')->item(0)->nodeValue;
351              $price = $element->getElementsByTagName('SalesPrice')->item(0)->nodeValue;
352              $edit = $element->getElementsByTagName('EditSequence')->item(0)->nodeValue;
353    
354              // Make sure all orders ordering this product get the product data
355              foreach((array)$_SESSION['QBProducts'][$model]->order_id as $order_id) {
356                $_SESSION['qb_orders'][$order_id]->order_data['QBProducts'][$model] = array(
357                  'id' => $id,
358                  'model' => $model,
359                  'price' => $price,
360                  'edit' => $edit
361                );
362              }
363            }
364            // Create the product if it was not there
365            else {
366                    $new[] = array(
367                'name' => 'ItemInventoryAddRq',
368                'request' => array(
369                  'ItemInventoryAdd' => array(
370                    'Name' => $product->model,
371                    'IsActive' => 'true',
372                    'SalesDesc' => $product->title,
373                    'SalesPrice' => $product->sell_price,
374                    'IncomeAccountRef' => array(
375                      'FullName' => variable_get('uc_qb_income_account', 'Merchandise Sales')
376                    ),
377                    'PurchaseCost' => "0.0",
378                    'COGSAccountRef' => array(
379                      'FullName' => variable_get('uc_qb_cogs_account', 'Merchant Account Fees')
380                    ),
381                    'AssetAccountRef' => array(
382                      'FullName' => variable_get('uc_qb_asset_account', 'Inventory Asset')
383                    ),
384                    'ReorderPoint' => '',
385                    'QuantityOnHand' => '',
386                    'TotalValue' => '',
387                    'InventoryDate' => date('Y-m-d', time()),
388                  ),
389                  'IncludeRetElement' => array('ListID', 'Name', 'SalesPrice', 'EditSequence')
390                ),
391              );
392            }
393          break;
394          // Save created inventory data
395          case 'ItemInventoryAddRs':
396            if ($statusCode == 0) {
397              $model = $element->getElementsByTagName('Name')->item(0)->nodeValue;
398              $id = $element->getElementsByTagName('ListID')->item(0)->nodeValue;
399              $price = $element->getElementsByTagName('SalesPrice')->item(0)->nodeValue;
400              $edit = $element->getElementsByTagName('EditSequence')->item(0)->nodeValue;
401    
402              // Make sure all orders ordering this product get the product data
403              foreach((array)$_SESSION['QBProducts'][$model]->order_id as $order_id) {
404                $_SESSION['qb_orders'][$order_id]->order_data['QBProducts'][$model] = array(
405                  'id' => $id,
406                  'model' => $model,
407                  'price' => $price,
408                  'edit' => $edit
409                );
410              }
411            }
412            else {
413                    // Failed to add the product
414              watchdog('uc_qb', t('Failed to export the product %product in order #%order with error code %code (%message) to QB', array('%product' => $saved[$requestId]->title, '%order' => $saved[$requestId]->order_id, '%code' => $statusCode, '%message' => $statusMessage)), WATCHDOG_ERROR);
415            }
416          break;
417          case 'ItemInventoryModRs':
418            if ($statusCode == 0) {
419              $model = $element->getElementsByTagName('Name')->item(0)->nodeValue;
420              $id = $element->getElementsByTagName('ListID')->item(0)->nodeValue;
421              $price = $element->getElementsByTagName('SalesPrice')->item(0)->nodeValue;
422              $edit = $element->getElementsByTagName('EditSequence')->item(0)->nodeValue;
423    
424              // Make sure all orders ordering this product get the product data
425              foreach((array)$_SESSION['QBProducts'][$model]->order_id as $order_id) {
426                $_SESSION['qb_orders'][$order_id]->order_data['QBProducts'][$model] = array(
427                  'id' => $id,
428                  'model' => $model,
429                  'price' => $price,
430                  'edit' => $edit
431                );
432              }
433            }
434            else {
435              // Failed to add the product
436              watchdog('uc_qb', t('Failed to change the product price of %product in order #%order with error code %code (%message) to QB', array('%product' => $saved[$requestId]->title, '%order' => $saved[$requestId]->order_id, '%code' => $statusCode, '%message' => $statusMessage)), WATCHDOG_ERROR);
437            }
438          break;
439          case 'AccountQueryRs':
440            if (!isset($saved[$requestId])) {
441              $error = true;
442              break;
443            }
444    
445            if ($returnCnt == 0) {
446              $new[] = array(
447                'name' => 'AccountAddRq',
448                'request' => array('AccountAdd' => array(
449                  'Name' => $saved[$requestId]['name'],
450                  'AccountType' => $saved[$requestId]['type'],
451                )),
452                'data' => $saved[$requestId]
453              );
454            }
455          break;
456          case 'AccountAddRs':
457            if ($statusCode != 0) {
458              $error = true;
459              break;
460            }
461          break;
462          case 'PreferencesQueryRs':
463            // Check that inventory and taxes are turned on
464            $taxes = $element->getElementsByTagName('SalesTaxPreferences');
465            $inventory = $element->getElementsByTagName('IsUsingInventory');
466            if ($taxes->length == 0) {
467                    // Taxes are not turned on. Will fail
468              watchdog('uc_qb', t('Failed to start QB export as taxes are not turned on in the company preferences.'), WATCHDOG_ERROR);
469              $error = true;
470              break;
471            }
472            if (!($inventory = $inventory->item(0)) || $inventory->nodeValue == 'false') {
473                    // Taxes are not turned on. Will fail
474              watchdog('uc_qb', t('Failed to start QB export as inventory is not turned on in the company preferences.'), WATCHDOG_ERROR);
475              $error = true;
476              break;
477            }
478          break;
479        }
480      }
481    
482      // Stop processing on errors
483      if ($error) {
484        return -1;
485      }
486    
487      if (!empty($new)) {
488            $_SESSION['qb_pending_requests'][] = $new;
489      }
490    
491      if ($_SESSION['qb_orders_count'] == 0) {
492            return 100;
493      }
494    
495            return ($done / $_SESSION['qb_orders_count']) * 100;
496    }
497    
498    /**
499     * Implementation of hook_qbwc_request()
500     *
501     * @Description: Send requests for data from quickbooks (existing customers/orders)
502     *    or requests for additions into Quickbooks
503     */
504    function uc_qb_qbwc_request() {
505      // Check if we have any pending requests to make as a response to QB returned data
506      if (!empty($_SESSION['qb_pending_requests'])) {
507            return array_shift($_SESSION['qb_pending_requests']);
508      }
509    
510      // Get a list of orders needing exported
511      if (!isset($_SESSION['qb_started_processing'])) {
512        $_SESSION['qb_started_processing'] = true;
513        $checked_users = $products  = array();
514    
515        // Checks for accounts/settings to exist that need to happen on first connect
516        if (count($_SESSION['qb_orders'])) {
517          // Check that certain required service accounts exist
518          $services[] = array('name' => variable_get('uc_qb_income_account', 'Merchandise Sales'), 'type' => 'Income');
519          $services[] = array('name' => variable_get('uc_qb_cogs_account', 'Merchant Account Fees'), 'type' => 'CostOfGoodsSold');
520          $services[] = array('name' => variable_get('uc_qb_asset_account', 'Inventory Asset'), 'type' => 'OtherCurrentAsset');
521          foreach($services as $service) {
522           $check[] = array(
523              'name' => 'AccountQueryRq',
524              'request' => array(
525                'FullName' => $service['name'],
526                '_metaData' => 'MetaDataOnly'
527              ),
528              'data' => $service
529            );
530          }
531    
532          $check[] = array(
533            'name' => 'PreferencesQueryRq',
534            'request' => array('IncludeRetElement' => array('SalesTaxPreferences', 'PurchasesAndVendorsPreferences')),
535          );
536        }
537    
538        $_SESSION['QBProducts'] = array();
539        $products = &$_SESSION['QBProducts'];
540        foreach($_SESSION['qb_orders'] as &$copy) {
541          // Check that all of the products exist in QB and if not create them
542            $product_result = db_query('SELECT uop.nid, uop.title, uop.model, uop.order_id, up.sell_price FROM {uc_order_products} uop INNER JOIN {uc_products} up ON uop.nid = up.nid WHERE uop.order_id = "%d"', $copy->order_id);
543          while ($product = db_fetch_object($product_result)) {
544            if (!array_key_exists($product->model, $products)) {
545              $product->order_id = array($product->order_id);
546              $check[] = array(
547                'name' => 'ItemInventoryQueryRq',
548                'request' => array(
549                  'FullName' => $product->model,
550                  'IncludeRetElement' => array('ListID', 'Name', 'SalesPrice', 'EditSequence'),
551                  '_metaData' => 'MetaDataAndResponseData'
552                ),
553                'data' => $product
554              );
555              $products[$product->model] = $product;
556            }
557            else {
558                    $products[$product->model]->order_id[] = $product->order_id;
559            }
560          }
561    
562          // Check that all the customers exist in QB and if not create them
563          if (!array_key_exists($copy->uid ? $copy->uid : $copy->primary_email, $checked_users)) {
564            if (isset($copy->user_data['QBListID'])) {
565              $copy->qb_user_id = $copy->user_data['QBListID'];
566            }
567            else if (isset($copy->order_data['QBListID'])) {
568              $copy->qb_user_id = $copy->order_data['QBListID'];
569            }
570            else if (!$copy->primary_email) {
571                    watchdog('uc_qb', t('Order #%order could not be exported to QB because anonymous user did not provide an email address.', array('%order' => $copy->order_id)), WATCHDOG_ERROR);
572            }
573            else {
574              $check[] = array(
575                'name' => 'CustomerAddRq',
576                'request' => array('CustomerAdd' => array(
577                  'Name' => $copy->uid ? $copy->name : $copy->primary_email,
578                  'IsActive' => 'true',
579                  'Email' => $copy->primary_email,
580                  'Notes' => $copy->uid ? url('user/'. $copy->uid, null, null, true) : ' '
581                )),
582                'data' => $copy
583              );
584              $copy->qb_user_id_pending = true;
585            }
586    
587            $checked_users[$copy->uid ? $copy->uid : $copy->primary_email] = true;
588          }
589        }
590      }
591      else if (empty($_SESSION['qb_orders'])) {
592            return;
593      }
594    
595      $requests = array();
596      $first = true;
597      foreach($_SESSION['qb_orders'] as &$item) {
598        if ($item->order_data['QBProcessed']) {
599          // This order was already processed
600            continue;
601        }
602    
603        $receipt = array();
604    
605        $order = uc_order_load($item->order_id);
606    
607        // Is there a better way to get at the customer message?
608        $message = db_result(db_query('SELECT message FROM {uc_order_comments} WHERE order_id = "%d" AND order_status = "pending" AND message != "-" LIMIT 1', $order->order_id));
609        $billing_country = uc_get_country_data(array('country_id' => $order->billing_country));
610        $shipping_country = uc_get_country_data(array('country_id' => $order->delivery_country));
611    
612        // Check if shipping/payment methods are available. If not send a request for those instead
613        if ($order->quote['method'] && !array_key_exists($order->quote['method'], (array)$_SESSION['qb_shipping_methods'])) {
614          $check[] = array(
615            'name' => 'ShipMethodQueryRq',
616            'request' => array(
617              'FullName' => $order->quote['method'],
618              '_metaData' => 'MetaDataOnly'
619            ),
620            'data' => $order->quote
621          );
622        }
623    
624        // If payment methods are enabled, ensure that we have mapped values from UC -> QB
625        if (isset($order->payment_method) && !array_key_exists($order->payment_method, (array)$_SESSION['qb_payment_methods'])) {
626          $check[] = array(
627            'name' => 'PaymentMethodQueryRq',
628            'request' => array(
629              'FullName' => $order->payment_method,
630              '_metaData' => 'MetaDataOnly'
631            ),
632            'data' => $order->payment_method
633          );
634        }
635    
636        // Make various checks on line items
637        foreach((array)$order->line_items as $line) {
638          $line = (object)$line;
639          if (_line_item_data($line->type, 'calculated') != TRUE) {
640            continue;
641          }
642    
643          if (!array_key_exists($line->type, (array)$_SESSION['qb_services'])) {
644            $check[] = array(
645              'name' => 'ItemServiceQueryRq',
646              'request' => array(
647                'FullName' => $line->type,
648                '_metaData' => 'MetaDataOnly'
649              ),
650              'data' => $line->type
651            );
652          }
653        }
654    
655        if (!$item->qb_user_id_pending && !$item->qb_user_id) {
656            // This should never happen. If it does, make a log entry for this order saying that it failed to get exported
657          $item->order_data['QBProcessed'] = true;
658          $_SESSION['qb_orders_count']--;
659          $_SESSION['qb_failed_orders'][] = $item;
660          watchdog('uc_qb', t('Order #%order_id failed to get exported to QB because the user did not exist in (failed to create properly) inside QB.', array('%order_id' => $item->order_id)), WATCHDOG_ERROR);
661          continue;
662        }
663    
664        // If any check items were marked, send them all at once
665        if (!empty($check)) {
666            return $check;
667        }
668    
669        // Set the available info to get imported into QB
670        $receipt['CustomerRef']['ListID'] = $item->qb_user_id;
671        $receipt['TxnDate'] = date('Y-m-d', $order->created);
672        $receipt['RefNumber'] = $order->order_id;
673        $addcount = 1;
674        $receipt['BillAddress'] = array();
675        if ($order->billing_company) {
676          $receipt['BillAddress']['Addr'. $addcount++] = $order->billing_company;
677        }
678        $receipt['BillAddress'] += array(
679          'Addr'. $addcount++ => $order->billing_first_name . ' ' . $order->billing_last_name,
680          'Addr'. $addcount++ => $order->billing_street1,
681          'Addr'. $addcount => $order->billing_street2,
682          'City' => $order->billing_city,
683          'State' => uc_get_zone_code($order->billing_zone),
684          'PostalCode' => $order->billing_postal_code,
685          'Country' => $billing_country[0]['country_iso_code_2']
686        );
687        $addcount = 1;
688        $receipt['ShipAddress'] = array();
689        if ($order->delivery_company) {
690          $receipt['ShipAddress']['Addr'. $addcount] = $order->delivery_company;
691        }
692        $receipt['ShipAddress'] += array(
693          'Addr'. $addcount++ => $order->delivery_first_name .' '. $order->delivery_last_name,
694          'Addr'. $addcount++ => $order->delivery_street1,
695          'Addr'. $addcount => $order->delivery_street2,
696          'City' => $order->delivery_city,
697          'State' => uc_get_zone_code($order->delivery_zone),
698          'PostalCode' => $order->delivery_postal_code,
699          'Country' => $shipping_country[0]['country_iso_code_2']
700        );
701        $receipt['IsPending'] = 'false';
702        if ($order->payment_method) {
703            $receipt['PaymentMethodRef']['FullName'] = $order->payment_method;
704        }
705        if ($order->quote['method']) {
706            $receipt['ShipMethodRef']['FullName'] = $order->quote['method'];
707        }
708        $receipt['Memo'] = substr($message, 0, 101);
709        $receipt['DepositToAccountRef']['FullName'] = variable_get('uc_qb1_income_account', 'Undeposited Funds');
710        //$receipt['Other'] = 'CC:'. $order->payment_details['cc_number'] . ' UserID:'. $order->uid;
711    
712        $added_products = false;
713        $total = 0;
714        if (is_array($order->products) && count($order->products) > 0) {
715          $lineItems = &$receipt['SalesReceiptLineAdd'];
716    
717          foreach ($order->products as $product) {
718            if (!$item->order_data['QBProducts'][$product->model]) {
719              // The product was not created/set properly in QB
720              $added_products = false;
721              break;
722            }
723    
724            $description = $product->title .' x'. $product->qty;
725            if (is_array($product->data['attributes'])) {
726              $description .= ', ';
727              $start = true;
728              foreach ($product->data['attributes'] as $key => $value) {
729                if ($start) {
730                  $start = false;
731                }
732                else {
733                  $description .= ', ';
734                }
735                $description .= $key .': '. $value;
736              }
737            }
738    
739            if ($item->order_data['QBProducts'][$product->model]['price'] != $product->price) {
740              // TODO: Change the price in QB of the product if it had been changed for this product
741                    $requests[] = array(
742    
743              );
744            }
745    
746            $product_line = array();
747            $product_line['ItemRef']['ListID'] = $item->order_data['QBProducts'][$product->model]['id'];
748            $product_line['Desc'] = substr($description, 0, 4000);
749            $product_line['Quantity'] = $product->qty;
750            $product_line['Rate'] = uc_currency_format($product->price, FALSE, FALSE, '.');
751            $product_line['SalesTaxCodeRef']['FullName'] = 'NON';
752    
753            $added_products = true;
754            $total += $product->qty * $product->price;
755            $lineItems[] = $product_line;
756          }
757    
758          if (!$added_products) {
759            // Make sure to keep total orders to be processed up to date
760            $item->order_data['QBProcessed'] = true;
761            $_SESSION['qb_orders_count']--;
762            $_SESSION['qb_failed_orders'][] = $item;
763            watchdog('uc_qb', t('Failed to export order #%order because some or all of the purchased products could not be created/found in QB.', array('%order' => $item->order_id)), WATCHDOG_ERROR);
764            continue;
765          }
766        }
767        else {
768          // Make sure to keep total orders to be processed up to date
769          $item->order_data['QBProcessed'] = true;
770          $_SESSION['qb_orders_count']--;
771          $_SESSION['qb_failed_orders'][] = $item;
772            watchdog('uc_qb', t('Failed to export order #%order because no products were purchased.', array('%order' => $item->order_id)), WATCHDOG_ERROR);
773          continue;
774        }
775    
776        // Add the line items so the total will match up properly
777        foreach((array)$order->line_items as $line) {
778          // Only look at calculated line items
779          if (_line_item_data($line['type'], 'calculated') != TRUE) {
780            continue;
781          }
782          $lineItems = &$receipt['SalesReceiptLineAdd'];
783    
784          $line_item = array();
785          $line_item['ItemRef']['FullName'] = $line['type'];
786          $line_item['Desc'] = $line['title'];
787          $line_item['Amount'] = uc_currency_format($line['amount'], FALSE, FALSE, '.');
788          $line_item['SalesTaxCodeRef']['FullName'] = 'NON';
789    
790          $total += $line['amount'];
791          $lineItems[] = $line_item;
792        }
793    
794        // Add any customer messages as a blank line item
795        if ($message && variable_get('uc_qb_include_messages', true)) {
796          // Add two blank lines in front
797          $receipt['SalesReceiptLineAdd'][] = array('Desc' => ' ');
798          $receipt['SalesReceiptLineAdd'][] = array('Desc' => ' ');
799            $receipt['SalesReceiptLineAdd'][] = array(
800            'Desc' => substr($message, 0, 4000)
801          );
802        }
803    
804        // Only add items if we are calculating the total properly
805        if (round($total, 2) == round($order->order_total, 2)) {
806            $requests[] = array(
807            'name' => 'SalesReceiptAddRq',
808            'request' => array(
809              'SalesReceiptAdd' => $receipt,
810              'IncludeRetElement' => array('RefNumber', 'TotalAmount', 'TxnID', 'EditSequence')),
811            'data' => $item
812          );
813        }
814        else {
815            $item->order_data['QBProcessed'] = true;
816          $_SESSION['qb_orders_count']--;
817          $_SESSION['qb_failed_orders'][] = $item;
818          watchdog('uc_qb', t('Failed to export order #%order the calculated total meant for QB did not match the order total.', array('%order' => $item->order_id)), WATCHDOG_ERROR);
819          continue;
820        }
821    
822        $first = false;
823      }
824    
825      return $requests;
826    }
827    
828    /**
829     * Implementation of hook qbwc_close()
830     *
831     * Send email alerts on failed orders
832     */
833    function uc_qb_qbwc_close($ticket) {
834            if (!empty($_SESSION['qb_failed_orders']) && ($mail = variable_get('uc_qb_failed_orders_email', ''))) {
835        foreach($_SESSION['qb_failed_orders'] as $order) {
836            $orders[] = t('#%order (@link)', array('%order' => $order->order_id, '@link' => url('fleurville/admin/store/orders/'. $order->order_id, null, null, true)));
837        }
838    
839        $output = t('There were errors exporting the following orders to QB via Web Connector: ') . "\n\n";
840        $output .= implode("\n", $orders) . "\n\n";
841        $output .= t('To find more details about the errors, view the error logs at %url and filter by "uc_qb"', array('%url' => url('admin/logs/watchdog', null, null, true)));
842    
843                    drupal_mail('uc_qb_failed_exports', $mail, t('Errors exporting orders to QB'), $output, uc_store_email_from());
844            }
845    }

Legend:
Removed from v.1.1  
changed lines
  Added in v.1.1.2.1

  ViewVC Help
Powered by ViewVC 1.1.2