JoJo
JoJo

Reputation: 161

Omnipay with SagePay Server not accepting billingCountry

I'm getting the following error when trying to use SagePay Server (from printing out the response):

["data":protected]=>array(3) {
["VPSProtocol"]=>
string(4) "2.23"
["Status"]=>
string(7) "INVALID"
["StatusDetail"]=>
string(107) "The data in the BillingCountry field you supplied is an invalid length. Must be an ISO 3166-1 country code."

}

but I am passing the value "GB" as the billingCountry which is correct (SagePay expects billingCountry to be alphabetical and a max of 2 characters)

 ["card"]=>
    object(Omnipay\Common\CreditCard)#46 (1) {
      ["parameters":protected]=>
      object(Symfony\Component\HttpFoundation\ParameterBag)#48 (1) {
        ["parameters":protected]=>
        array(11) {
          ["email"]=>
          string(17) "[email protected]"
          ["billingFirstName"]=>
          string(3) "Joe"
          ["shippingFirstName"]=>
          string(3) "Joe"
          ["billingLastName"]=>
          string(6) "Bloggs"
          ["shippingLastName"]=>
          string(6) "Bloggs"
          ["billingAddress1"]=>
          string(9) "Address 1"
          ["billingAddress2"]=>
          string(9) "Address 2"
          ["billingCity"]=>
          string(4) "City"
          ["billingPostcode"]=>
          string(7) "AB1 1BA"
          ["billingCountry"]=>
          string(2) "GB"
          ["billingPhone"]=>
          string(13) "01234 567 890"
        }
      }

And this is my code:

$response = $this->gateway->Purchase(array(
        'description'=> 'Online order',
        'currency'=> 'GBP',
        'transactionId'=> mt_rand(99, 9999),
        'transactionReference' => 'test order',
        'amount'=> '1.00',
        'returnUrl' => 'http://www.test.com/returnURL/',
        'cancelUrl' => 'http://www.test.com/cancelURL/',
        'card' => array(
            'email' =>  '[email protected]',
            'clientIp' => '123.123.123.123',
            'firstName' => 'Joe',
            'LastName' => 'Bloggs',
            'billingAddress1' => 'Address 1',
            'billingAddress2' => 'Address 2',
            'billingCity' => 'City',
            'billingPostcode' => 'AB1 1BA',
            'billingCountry' => 'GB',
            'billingPhone' => '01234 567 890'
        )))->send();

I can't work it out as it all looks correct. I think I'm going slightly mad! Am I missing the totally obvious?

Updated 28.07.2014: I have been trying various things including sending the data in different formats:

   $formInputData = array(
            'firstName' => 'Joe',
            'lastName' => 'Bloggs',
            'billingAddress1' => '88',
            'billingAddress2' => 'Address 2',
            'billingCity' => 'City',
            'billingPostcode' => '412',
            'billingCountry' => 'GB',
            'billingPhone' => '01234 567 890',
            'email' =>  '[email protected]',
            'clientIp' => '123.123.123.123'
        );


     $card = new CreditCard($formInputData);

     $transactionID = mt_rand(99, 9999);

     $response = $this->gateway->purchase(['amount' => '1.00', 'returnUrl' => 'http://www.example.com/return/', 'transactionId'=> $transactionID, 'description'=> 'Online order', 'transactionReference' => 'test order', 'currency'=> 'GBP', 'card' => $card])->send();

and it doesn't make any difference.

I have also tried sending the same data (but with the addition of test credit card details in the card parameter) to both SagePay Direct and CardSave.

With SagePay Direct I get "The BillingCountry field is missing from the POST".

With CardSave the transaction goes through successfully but I notice that the country field has "N/A" when I look at the transaction history in my CardSave.

Upvotes: 2

Views: 1169

Answers (5)

mickburkejnr
mickburkejnr

Reputation: 3690

Since this bug has been fixed, I have also encountered the error. However the bug spoken about above has now been fixed.

In my case the problem stemmed from using "DeliveryXXXX" instead of "ShippingXXXX". Once I changed all instances of Delivery to Shipping I stopped receiving the error.

Upvotes: 0

drmonkeyninja
drmonkeyninja

Reputation: 8540

The current release of omnipay/sagepay is incorrectly setting the US state for non-US billing addresses.

If the address is outside the US it passes NULL for the state which SagePay rejects. Unfortunately SagePay's error messages often refer to a neighbouring field rather than the actual error. So it is complaining about the BillingCountry not being set when it actually means the state's not been set.

There is a fix in the Git repository for this bug, but it isn't in the main releases so Composer misses it.

In the meantime you can just manually set the state to be an empty string $data['card']['state'] = ''.

Upvotes: 1

JoJo
JoJo

Reputation: 161

To respond to Jason's comments/answers, Omnipay handles multiple payment gateways and so converts fields passed to the correct field names as expected by the particular gateway. In the case of SagePay this is:

protected function getBaseAuthorizeData()
{
    $this->validate('amount', 'card', 'transactionId');
    $card = $this->getCard();

    $data = $this->getBaseData();
    $data['Description'] = $this->getDescription();
    $data['Amount'] = $this->getAmount();
    $data['Currency'] = $this->getCurrency();
    $data['VendorTxCode'] = $this->getTransactionId();
    $data['ClientIPAddress'] = $this->getClientIp();
    $data['ApplyAVSCV2'] = $this->getApplyAVSCV2() ?: 0;
    $data['Apply3DSecure'] = $this->getApply3DSecure() ?: 0;

    // billing details
    $data['BillingFirstnames'] = $card->getFirstName();
    $data['BillingSurname'] = $card->getLastName();
    $data['BillingAddress1'] = $card->getBillingAddress1();
    $data['BillingAddress2'] = $card->getBillingAddress2();
    $data['BillingCity'] = $card->getBillingCity();
    $data['BillingPostCode'] = $card->getBillingPostcode();
    $data['BillingState'] = $card->getBillingCountry() === 'US' ? $card->getBillingState() : null;
    $data['BillingCountry'] = $card->getBillingCountry();
    $data['BillingPhone'] = $card->getBillingPhone();

    // shipping details
    $data['DeliveryFirstnames'] = $card->getFirstName();
    $data['DeliverySurname'] = $card->getLastName();
    $data['DeliveryAddress1'] = $card->getShippingAddress1();
    $data['DeliveryAddress2'] = $card->getShippingAddress2();
    $data['DeliveryCity'] = $card->getShippingCity();
    $data['DeliveryPostCode'] = $card->getShippingPostcode();
    $data['DeliveryState'] = $card->getShippingCountry() === 'US' ? $card->getShippingState() : null;
    $data['DeliveryCountry'] = $card->getShippingCountry();
    $data['DeliveryPhone'] = $card->getShippingPhone();
    $data['CustomerEMail'] = $card->getEmail();

    return $data;
}

Upvotes: 0

Jason
Jason

Reputation: 4772

The firstName and lastName fields - they should be:

  • BillingFirstNames (yes, plural)
  • BillingSurname

The properties for all the fields are summarised in a gateway package I write last year:

https://github.com/academe/SagePay/blob/master/src/Academe/SagePay/Metadata/Transaction.php

This includes the field names, lengths, mandatory status, allowed characters, and which transaction types the fields are used in. These details are difficult to extract from the documentation, and many are not documented at all, and have been found through trial-and-error.

Edit: this is probably a silly answer if Omnipay translates the field names, so feel free to ignore it. My head was in SagePay and not Omnipay.

Upvotes: 0

user1112560
user1112560

Reputation: 185

Could this be a case-sensitivity issue? Does changing it to "BillingCountry" make any difference?

Upvotes: 0

Related Questions