Would it be possible to integrate this module into the page where an admin creates an order for a customer?

At the moment, a customer's saved addresses are not available to select in the drop down menu here. (Only the addresses from previous orders are available.)

And if an admin enters a new address for a customer here, it is not saved into their address list.

Comments

freixas’s picture

I tried to integrate the uc_addresses code into Ubercart without affecting how the uc_orders module works.

uc_addresses gets its address from one place and uc_order gets its addresses from previous orders. On the checkout page, I redirected the "address book" button so that it gets addresses from uc_addresses instead of uc_orders. That's about as much as I've interfered with the uc_orders module.

Creating a new order for a customer is similar to the checkout page, so it would be reasonable to add the same hooks there. I suspect the changes would be more complicated, but I haven't investigated this. One concern would be anything that affects an existing system to which uc_addresses is added. I don't want the admin to go to the orders and find that there are no longer any addresses associated with them (because the addresses are coming from uc_addresses and no addresses have been entered yet).

Delivering a patch, of course, increases the odds that this enhancement will be added. At this point, it is not high on my list.

c0mputerking’s picture

Hello all i have installed the invoice feature of Ubercart and it works quite nicely. I have also installed the uc_addresses module and it does not work as i expected.

Mostly i am using Ubercart as an invoicing system and would like to login as administrator and create invoices for any user or even invoices for customers that do not necessarily have a user account. I read somewhere about ubercart saving addresses somewhere, but cannot seem to find how to make that happen.

So far the only way to have the addresses auto populate is by logging in as the specific user and creating the invoice from their account. This is unpractical and i do not know all my users passwords.

I tried entering the addresses as the admin but it does not seem to save them anywhere.

As the admin user I can create an order and it asks me to create a new customer or select an existing customer. Also the new order customer fields at the bottom of the page are blanked out. If i select create a new customer it has me input an email, but no address. Later after i create an order for this new customer including entering a billing address the address does not get saved to the users data or anywhere that i can find for that matter.

If i select use an existing customer i have to do a search which is bit annoying but i can live with it. However when i select a customer one that already has an address in their user account no address appears on the order.

Please someone help me get this sorted.

c0mputerking’s picture

Sorry about the duplicate! I guess what you are saying is that uc_addresses does not work with orders only with checkout? and that it is not high on your priority list is there anything i could do to change that? Is there any sort of work around? as it seems that when a customer creates an order in there own account the address field is populated just not when the admin does it. Just curious but none of the address i enter as an admin get saved either I wish i could go to the user panel select a user and create an order that had addresses filled in.

freixas’s picture

Assigned: Unassigned » freixas
Status: Active » Closed (won't fix)

Hi, c0mputerking,

Regarding the question about raising the priority: paid work always has priority! If you're interested, all my contact information is on my Web site at www.tigerheron.com.

Is there a work-around? I don't know of any.

When you create an order (as admin), where do the addresses come from? They come from prior orders.

If a customer places an order, the address goes into the user's profile, but it is also part of the order, so it is available to the admin. If the user has never placed an order, there are no addresses for the order system to find. If you enter an address as admin, the address is stored with the order, but not added to the user's profile. The order system also has no concept of a "default" address.

As for having to log in to each user's account to enter addresses, keep in mind that, as admin and with the permissions set properly, you can edit anyone's address information without having to log in as the user. Just go to their profile and edit away! This won't help the order system, though—again, it only looks at orders placed.

Sorry for the confusion.

Tommy Kaneko’s picture

Version: 5.x-2.1 » 6.x-1.0

I also had this problem. I have made a hack, and I am happy to share.

I hacked the function uc_get_addresses() in ubercart's uc_store.module file, to include the following piece of code at the end of the function:

  <?php
// TK: check to see if there are any addresses with the uc_addresses module if the list is empty
  if (empty($addresses) && module_exists('uc_addresses')) {
  	 $uc_addresses = _uc_addresses_db_get_address($uid);
	 if ($uc_addresses == FALSE) {
	   return NULL;
	 }
	 foreach ($uc_addresses as $key => $address) {
		foreach ($address as $field => $value) {
			$addresses[$key][$field] = $value;
		}
	 }
  }
?>

Below is the copy of the whole edited function, so you know where to put the above code:

<?php
/**
 * Load a customer's previously given addresses.
 */
function uc_get_addresses($uid, $type = 'billing') {
  if ($uid == 0) {
    return NULL;
  }

  if ($type == 'delivery') {
    $type = 'delivery';
  }
  else {
    $type = 'billing';
  }

  switch ($GLOBALS['db_type']) {
    case 'mysqli':
    case 'mysql':
      $result = db_query("SELECT DISTINCT ". $type ."_first_name AS first_name, "
                   . $type ."_last_name AS last_name, ". $type ."_phone AS phone, "
                   . $type ."_company AS company, ". $type ."_street1 AS street1, "
                   . $type ."_street2 AS street2, ". $type ."_city AS city, "
                   . $type ."_zone AS zone, ". $type ."_postal_code AS postal_code, "
                   . $type ."_country AS country FROM {uc_orders} WHERE uid = %d "
                   ."AND order_status IN ". uc_order_status_list('general', TRUE)
                   ." ORDER BY created DESC", $uid);
      break;
    case 'pgsql':
      // In pgsql, ORDER BY requires the field being sorted by to be in the SELECT list.
      // But if we have the 'created' column in the SELECT list, the DISTINCT is
      // rather useless. So for pgsql we will just sort addresses alphabetically.
      $result = db_query("SELECT DISTINCT ". $type ."_first_name AS first_name, "
                   . $type ."_last_name AS last_name, ". $type ."_phone AS phone, "
                   . $type ."_company AS company, ". $type ."_street1 AS street1, "
                   . $type ."_street2 AS street2, ". $type ."_city AS city, "
                   . $type ."_zone AS zone, ". $type ."_postal_code AS postal_code, "
                   . $type ."_country AS country FROM {uc_orders} WHERE uid = %d "
                   ."AND order_status IN ". uc_order_status_list('general', TRUE)
                   ." ORDER BY ". $type ."_street1 DESC", $uid);
      break;
  }

  $addresses = array();
  while ($address = db_fetch_array($result)) {
    if (!empty($address['street1']) || !empty($address['postal_code'])) {
      $addresses[] = $address;
    }
  }
  
  // TK: check to see if there are any addresses with the uc_addresses module if the list is empty
  if (empty($addresses) && module_exists('uc_addresses')) {
  	 $uc_addresses = _uc_addresses_db_get_address($uid);
	 if ($uc_addresses == FALSE) {
	   return NULL;
	 }
	 foreach ($uc_addresses as $key => $address) {
		foreach ($address as $field => $value) {
			$addresses[$key][$field] = $value;
		}
	 }
  }
  
  return $addresses;
}
?>

You'll need PHP 5, or it won't work. Note that I have Drupal 6 installed too - things may have changed since D5. Remember to test the code - it may screw up your system!

checker’s picture

Hi Tommy Kaneko!
I tried your patch and it seems to work - very nice!

Maybe we can patch uc_store.module with a hook that can be implemented by uc_addresses

rubenlouis’s picture

Tommy Kaneko post above solved things for me as well. All I had to do was paste in that extra bit of code my uc_store.module file (in the uc_store folder for those looking). Many thanks.

duzers’s picture

after hours of searching I was just about to give up and than I found Tommys masterpiece, did the trick for me straight a way, what a great feeling. Thanks a lot Tommy

TechNikh’s picture

subscribing..
Though it's not recommended to hack ubercart I guess I have no other option. I will apply the patch and keep looking for better option.
Thanks for the Patch Tommy Kaneko.

kasalla’s picture

You don´t actually need to patch the module. If you have your own module, you can use hook_form_alter.


function mymodule_form_alter(&$form, &$form_state, $form_id){
    if($form_id == 'uc_order_address_book_form'){
        
        $uid = $form_state['post']['uid']; 
        $type = $form_state['post']['type']; 
        $func = $form_state['post']['func']; 
        

         $select = mymodule_select_address($uid, $type, $func);

          if ($uid == 0) {
            $form['desc'] = array('#value' => '<br />'. t('You must select a customer before address<br />information is available.<br />') .'<br />');
          }
          elseif (is_null($select)) {
            $form['desc'] = array('#value' => '<br />'. t('No addresses found for customer.') .'<br />');
          }
          else {
            $form['addresses'] = mymodule_select_address($uid, $type, $func, t('Select an address from uc_addresses'));
            $form['addresses']['#prefix'] = '<div style="float: left; margin-right: 1em;">';
            $form['addresses']['#suffix'] = '</div>';
          }

          $form['close'] = array(
            '#type' => 'button',
            '#value' => t('Close'),
            '#attributes' => array('onclick' => "return close_address_select('#". $type ."_address_select');"),
          );
            
    }   
}

function mymodule_select_address($uid, $type = 'billing', $onchange = '', $title = NULL, $icon_suffix = FALSE){
  $addresses = mymodule_get_addresses($uid, $type);

  if (!is_array($addresses) || count($addresses) == 0) {
    return NULL;
  }

  $options = array('0' => t('Select one...'));
  foreach ($addresses as $key => $address) {
    $option = $address['street1'];
    // Check if the address is a duplicate (i.e. same address, but sent to different person)
    if ((isset($addresses[$key - 1]) && $option == $addresses[$key - 1]['street1']) ||
        (isset($addresses[$key + 1]) && $option == $addresses[$key + 1]['street1'])) {
      $option .= ' - ' . $address['first_name'] . ' ' . $address['last_name'];
    }
    $options[drupal_to_js($address)] = check_plain($option);
  }

  $select = array(
    '#type' => 'select',
    '#title' => is_null($title) ? t('Address book') : $title,
    '#options' => $options,
    '#attributes' => array('onchange' => $onchange),
    '#suffix' => $icon_suffix ? uc_store_get_icon('file:address_book', FALSE, 'address-book-icon') : NULL,
  );

  return $select;    
}

/**
 * Load a customer's previously given addresses.
 */
function mymodule_get_addresses($uid, $type = 'billing') {
  if ($uid == 0) {
    return NULL;
  }

  if ($type == 'delivery') {
    $type = 'delivery';
  }
  else {
    $type = 'billing';
  }

  switch ($GLOBALS['db_type']) {
    case 'mysqli':
    case 'mysql':
      $result = db_query("SELECT DISTINCT ". $type ."_first_name AS first_name, "
                   . $type ."_last_name AS last_name, ". $type ."_phone AS phone, "
                   . $type ."_company AS company, ". $type ."_street1 AS street1, "
                   . $type ."_street2 AS street2, ". $type ."_city AS city, "
                   . $type ."_zone AS zone, ". $type ."_postal_code AS postal_code, "
                   . $type ."_country AS country FROM {uc_orders} WHERE uid = %d "
                   ."AND order_status IN ". uc_order_status_list('general', TRUE)
                   ." ORDER BY created DESC", $uid);
      break;
    case 'pgsql':
      // In pgsql, ORDER BY requires the field being sorted by to be in the SELECT list.
      // But if we have the 'created' column in the SELECT list, the DISTINCT is
      // rather useless. So for pgsql we will just sort addresses alphabetically.
      $result = db_query("SELECT DISTINCT ". $type ."_first_name AS first_name, "
                   . $type ."_last_name AS last_name, ". $type ."_phone AS phone, "
                   . $type ."_company AS company, ". $type ."_street1 AS street1, "
                   . $type ."_street2 AS street2, ". $type ."_city AS city, "
                   . $type ."_zone AS zone, ". $type ."_postal_code AS postal_code, "
                   . $type ."_country AS country FROM {uc_orders} WHERE uid = %d "
                   ."AND order_status IN ". uc_order_status_list('general', TRUE)
                   ." ORDER BY ". $type ."_street1 DESC", $uid);
      break;
  }

  $addresses = array();
  while ($address = db_fetch_array($result)) {
    if (!empty($address['street1']) || !empty($address['postal_code'])) {
      $addresses[] = $address;
    }
  }
  
  // TK: check to see if there are any addresses with the uc_addresses module if the list is empty
  if (empty($addresses) && module_exists('uc_addresses')) {
       $uc_addresses = _uc_addresses_db_get_address($uid);
     if ($uc_addresses == FALSE) {
       return NULL;
     }
     foreach ($uc_addresses as $key => $address) {
        foreach ($address as $field => $value) {
            $addresses[$key][$field] = $value;
        }
     }
  }

  return $addresses;
}
kasalla’s picture

Another little change: I want the shipping address to come from uc_addresses aswell.

Orig:

// TK: check to see if there are any addresses with the uc_addresses module if the list is empty
  if (empty($addresses) && module_exists('uc_addresses')) {
       $uc_addresses = _uc_addresses_db_get_address($uid);
     if ($uc_addresses == FALSE) {
       return NULL;
     }
     foreach ($uc_addresses as $key => $address) {
        foreach ($address as $field => $value) {
            $addresses[$key][$field] = $value;
        }
     }
  }

To:

// TK: check to see if there are any addresses with the uc_addresses module if the list is empty
  if (module_exists('uc_addresses')) {
       $uc_addresses = _uc_addresses_db_get_address($uid);
     if ($uc_addresses == FALSE) {
       return NULL;
     }
     foreach ($uc_addresses as $key => $address) {
        foreach ($address as $field => $value) {
            $addresses[$key][$field] = $value;
        }
     }
  }
kirtimansharma’s picture

@ anstosser: Could you please elaborate on how to use your code. If we have to make a module, please mention a step by step process as php mortals like me are not very good with codes and especially not good with codes without instructions to implement it. Thank you so much.

kirtimansharma’s picture

Ok what I did was that I created an .info file just like in any other module and necessary for drupal to recognize a module with the name mymodule.info (got the hint for this name from the code posted by anstosser above)

name = My Module
description = Address Tweet.
dependencies[] = uc_addresses
package = "Ubercart - extra"
core = 6.x
version = "6.x-1.1"

and pasted the code above by anstosser into a notepad file and renamed it mymodule.module

copied both the files into a folder named mymodule and uploaded and enabled it the way we enable any other module.

Good work anstosser, it works!

I liked the separate module approach though as updating the uc_addresses module in the future will erase the patch and may make the patch useless.

I m concerned about any security holes in the code. As this is not a module monitored by Drupal security team which have a better perspective about different scenarios which can become a potential security risk factor. Any help on this would be useful. And anstosser, why dont you make a module out of it and post it on Drupal projects.

MegaChriz’s picture

Version: 6.x-1.0 » 6.x-2.x-dev
Assigned: freixas » MegaChriz
Status: Closed (won't fix) » Needs work

I plan to fix this for the 6.x-2.x version. Thanks for all the code posted! I'll see what I can use of it and adapt it for 6.x-2.x version.

MegaChriz’s picture

Component: Code » Order
MegaChriz’s picture

For the 6.x-2.x version addresses can now be selected from the address book (if you have Ubercart 2.6 installed), but not from other sources yet. It should be possible to select addresses from other sources (such as previous orders) when there are no addresses in the address book. I'm still working on this issue and thinking about what's the best way to implement that.

MegaChriz’s picture

Status: Needs work » Needs review

In the 6.x-2.x-dev version from October 31 addresses can now come from other sources too. Let me know if this feature works as expected/desired.

Michael-IDA’s picture

tag.

This in D7?

I was looking for something else, but this is very useful,
Sam

MegaChriz’s picture

@Sam-Inet
Yes, this functionality (selectable addresses coming from other sources) also appears in the D7 version. It's only untested and I'm not sure yet if it works as requested here. To let the customer choose an address not coming from the address book at checkout or to let the administrator choose an address not coming from the address book when editing the order, implement hook_uc_addresses_select_addresses() in your module. You can provide an array of straight address arrays or an array of UcAddressesAddress instances.

TechNikh’s picture

#10 & #11 worked for my 1.x version

Thanks @anstosser
Awesome work!

MegaChriz’s picture

Status: Needs review » Closed (fixed)

This was fixed a long time ago.

jvieille’s picture

This does not work for me.
I can select the addresses, but they are not saved.
Or maybe I am doing something wrong.
This problem is also reported on D7 were I put a note, so not reopening for now
http://drupal.org/node/1424038

MegaChriz’s picture

This issue is about selecting addresses from the address book with a fallback to addresses from previous orders if the customer has no addresses. Optionally, other modules can provide other addresses by implementing the hook hook_uc_addresses_select_addresses().

By the sounds of it, your issue is different: addresses are not saved with the order. If this is the case, then I'd suggest to open a new issue. If possible, please provide the exact steps to reproduce the issue, preferably on an install with a minimal amount of modules enabled (only Ubercart Addresses + dependencies).

jvieille’s picture

I have opened a new issue here
http://drupal.org/node/1917666

Thanks for your insightful and responsive support of this great module.

jvieille’s picture

Issue summary: View changes

Sorry to reopen this issue for support purpose - I think it is better to handle this here..
In my case, addresses given or modified in admin orders are not saved. They correctly are with user orders.
Is this feature implemented?
If yes, where addresses are saved? It seems to be in uc_addresses_uc_checkout_complete(), but this hook is not invoked when submitting/saving an admin order. Forcing its execution in the form submit function does not help (no info in $SESSION)

Thanks for help