The paypal module tries to map the billing information that is returned (usually nothing) from Paypal over the billing information entered by the user during the checkout process. I've fond the code that does this in NVP.php model.
/**
* Create billing and shipping addresses basing on response data
* @param array $data
*/
protected function _exportAddressses($data)
{
$address = new Varien_Object();
Varien_Object_Mapper::accumulateByMap($data, $address, $this->_billingAddressMap);
$address->setExportedKeys(array_values($this->_billingAddressMap));
$this->_applyStreetAndRegionWorkarounds($address);
$this->setExportedBillingAddress($address);
// assume there is shipping address if there is at least one field specific to shipping
if (isset($data['SHIPTONAME'])) {
$shippingAddress = clone $address;
Varien_Object_Mapper::accumulateByMap($data, $shippingAddress, $this->_shippingAddressMap);
$this->_applyStreetAndRegionWorkarounds($shippingAddress);
// PayPal doesn't provide detailed shipping name fields, so the name will be overwritten
$shippingAddress->addData(array(
'prefix' => null,
'firstname' => $data['SHIPTONAME'],
'middlename' => null,
'lastname' => null,
'suffix' => null,
));
$this->setExportedShippingAddress($shippingAddress);
}
}
/**
* Adopt specified address object to be compatible with Magento
*
* @param Varien_Object $address
*/
protected function _applyStreetAndRegionWorkarounds(Varien_Object $address)
{
// merge street addresses into 1
if ($address->hasStreet2()) {
$address->setStreet(implode("\n", array($address->getStreet(), $address->getStreet2())));
$address->unsStreet2();
}
// attempt to fetch region_id from directory
if ($address->getCountryId() && $address->getRegion()) {
$regions = Mage::getModel('directory/country')->loadByCode($address->getCountryId())->getRegionCollection()
->addRegionCodeFilter($address->getRegion())
->setPageSize(1)
;
foreach ($regions as $region) {
$address->setRegionId($region->getId());
$address->setExportedKeys(array_merge($address->getExportedKeys(), array('region_id')));
break;
}
}
}
Has anyone had any success modifying this process to get back fuller billing information. We need to be able to send "Paid" invoices to customers who pay with Paypal, so we need to capture this information.
i have hacked a workaround for that problem. It is not the cleanest way but i can save the billing address data in the order after paying with PayPal. I spent 2 days working on it and at the end i coded only a few lines. I marked my workaround with the comment #103.
Override method of class Mage_Paypal_Model_Api_Nvp:
protected function _importAddresses(array $to)
{
// Original Code
//$billingAddress = ($this->getBillingAddress()) ? $this->getBillingAddress() : $this->getAddress();
// Workaround #103
if ($this->getBillingAddress())
{
$billingAddress = $this->getBillingAddress();
}
else
{
$chkout = Mage::getSingleton('checkout/session');
$quote = $chkout->getQuote();
$billingAddress = $quote->getBillingAddress();
$billingAddress->setData($billingAddress->getOrigData());
$session = Mage::getSingleton("core/session", array("name"=>"frontend"));
$session->setData("syn_paypal_original_billing_address", serialize($billingAddress->getOrigData()));
}
$shippingAddress = $this->getAddress();
$to = Varien_Object_Mapper::accumulateByMap($billingAddress, $to, array_flip($this->_billingAddressMap));
if ($regionCode = $this->_lookupRegionCodeFromAddress($billingAddress)) {
$to['STATE'] = $regionCode;
}
if (!$this->getSuppressShipping()) {
$to = Varien_Object_Mapper::accumulateByMap($shippingAddress, $to, array_flip($this->_shippingAddressMap));
if ($regionCode = $this->_lookupRegionCodeFromAddress($shippingAddress)) {
$to['SHIPTOSTATE'] = $regionCode;
}
$this->_importStreetFromAddress($shippingAddress, $to, 'SHIPTOSTREET', 'SHIPTOSTREET2');
$this->_importStreetFromAddress($billingAddress, $to, 'STREET', 'STREET2');
$to['SHIPTONAME'] = $shippingAddress->getName();
}
$this->_applyCountryWorkarounds($to);
return $to;
}
And override method in Mage_Paypal_Model_Express_Checkout:
public function returnFromPaypal($token)
{
$this->_getApi();
$this->_api->setToken($token)
->callGetExpressCheckoutDetails();
// import billing address
$billingAddress = $this->_quote->getBillingAddress();
$exportedBillingAddress = $this->_api->getExportedBillingAddress();
// Workaround #103
$session = Mage::getSingleton("core/session", array("name"=>"frontend"));
$dataOrg = unserialize($session->getData("syn_paypal_original_billing_address"));
if (true === is_object($billingAddress))
{
foreach ($exportedBillingAddress->getExportedKeys() as $key) {
if (array_key_exists($key, $dataOrg))
{
$billingAddress->setData($key, $dataOrg[$key]);
}
}
$this->_quote->setBillingAddress($billingAddress);
}
// import shipping address
$exportedShippingAddress = $this->_api->getExportedShippingAddress();
if (!$this->_quote->getIsVirtual()) {
$shippingAddress = $this->_quote->getShippingAddress();
if ($shippingAddress) {
if ($exportedShippingAddress) {
foreach ($exportedShippingAddress->getExportedKeys() as $key) {
$shippingAddress->setDataUsingMethod($key, $exportedShippingAddress->getData($key));
}
$shippingAddress->setCollectShippingRates(true);
}
// import shipping method
$code = '';
if ($this->_api->getShippingRateCode()) {
if ($code = $this->_matchShippingMethodCode($shippingAddress, $this->_api->getShippingRateCode())) {
// possible bug of double collecting rates :-/
$shippingAddress->setShippingMethod($code)->setCollectShippingRates(true);
}
}
$this->_quote->getPayment()->setAdditionalInformation(self::PAYMENT_INFO_TRANSPORT_SHIPPING_METHOD, $code);
}
}
$this->_ignoreAddressValidation();
// import payment info
$payment = $this->_quote->getPayment();
$payment->setMethod($this->_methodType);
Mage::getSingleton('paypal/info')->importToPayment($this->_api, $payment);
$payment->setAdditionalInformation(self::PAYMENT_INFO_TRANSPORT_PAYER_ID, $this->_api->getPayerId())
->setAdditionalInformation(self::PAYMENT_INFO_TRANSPORT_TOKEN, $token)
;
$this->_quote->collectTotals()->save();
}