I am working with the magento api and I have run into a bit of an issue with creating an order. I have been able to get everything up to creating the order to work correctly. The issue that I am seeing is when I call the method to create the order I always get the exception: Credit card number mismatch with credit card type.
I am running Magento ver. 1.6.2.0
I have verified that the card I am testing with works via the magento frontend.
Any help with this is greatly appreciated.
This is the test code that I am using:
<?php
$proxy = new SoapClient('http://localhost/index.php/api/soap/?wsdl');
$sessionId = $proxy->login('shopapi', 'test123');
// Create a quote, get quote identifier
$shoppingCartId = $proxy->call( $sessionId, 'cart.create');
// Set customer, for example guest
$customerAsGuest = array(
"firstname" => "testFirstname",
"lastname" => "testLastName",
"email" => "[email protected]",
//"website_id" => "0",
//"store_id" => "0",
"mode" => "guest"
);
$resultCustomerSet = $proxy->call($sessionId, 'cart_customer.set', array( $shoppingCartId, $customerAsGuest) );
// Set customer addresses, for example guest's addresses
$arrAddresses = array(
array(
"mode" => "shipping",
"firstname" => "testFirstname",
"lastname" => "testLastname",
"company" => "testCompany",
"street" => "testStreet",
"city" => "testCity",
"region" => "CA",
"postcode" => "90049",
"country_id" => "US",
"telephone" => "0123456789",
"fax" => "0123456789",
"is_default_shipping" => 0,
"is_default_billing" => 0
),
array(
"mode" => "billing",
"firstname" => "testFirstname",
"lastname" => "testLastname",
"company" => "testCompany",
"street" => "testStreet",
"city" => "testCity",
"region" => "CA",
"postcode" => "90049",
"country_id" => "US",
"telephone" => "0123456789",
"fax" => "0123456789",
"is_default_shipping" => 0,
"is_default_billing" => 0
)
);
$resultCustomerAddresses = $proxy->call($sessionId, "cart_customer.addresses", array($shoppingCartId, $arrAddresses));
// add products into shopping cart
$arrProducts = array(
array(
"product_id" => "1",
"qty" => 1
)
);
$resultCartProductAdd = $proxy->call($sessionId, "cart_product.add", array($shoppingCartId, $arrProducts));
// get list of products
$shoppingCartProducts = $proxy->call($sessionId, "cart_product.list", array($shoppingCartId));
// set payment method
$paymentMethod = array(
"method" => "authorizenet",
"cc_type" => 'MC',
"cc_number" =>'5555555555554444' ,
"cc_exp_month" => 9,
"cc_exp_year" => 2014,
"cc_cid" => 123
);
$resultPaymentMethod = $proxy->call($sessionId, "cart_payment.method", array($shoppingCartId, $paymentMethod));
// create order
$resultOrderCreation = $proxy->call($sessionId,"cart.order",array($shoppingCartId));
var_dump($resultOrderCreation);
?>
Your call to cart_payment.method is succeeding, according to your post, so the CC number is validating to be a MC card, as expected.
The problem is that Magento, due to PCI concerns, does NOT save the CC number in the database (in most cases).
So, as you are sending payment details, along with CC number and CID, in one request and then creating the order in another, the state is lost and the CC number and CID are blanked out.
When the order is created, the payment data is validated a second time and when that happens, it has an empty CC number with a type of MC, causing the fault you see.
Unfortunately, I do not see a way to make cart.order accept payment data as a work around.
You could write a module to extend the checkout APIs with a new method that does both steps in a single call and that would likely solve the problem.
I ran into this issue as well. My solution was to create a custom SOAP endpoint which handled all of the order creation and submission logic at once without multiple API calls.
Even this way, I was getting card type mismatch exceptions.
The trick was once I set the payment info, collect totals, and save quote, with the getPayment->importData method, it seems to forget the card info. Probably for (not the best way to handle) PCI-DSS compliance.
To solve it, I added another getPayment->importData line after saving the quote, before submitting the order.
This is achieved without changing any of the core files.
See example:
public function customCheckout($checkoutData=false)
{
if(!$checkoutData){
Mage::throwException("No checkout data received.");
}
if(!json_decode($checkoutData)){
Mage::throwException("Bad checkout data received.");
}
$data = json_decode($checkoutData);
$email = '[email protected]';
// get the basic store info to associate with order
$websiteId = Mage::app()->getWebsite()->getId();
$store = Mage::app()->getStore();
// begin checkout with a quote
$quote = Mage::getModel('sales/quote')->setStoreId($store->getId());
// set customer by email
$customer = Mage::getModel('customer/customer')
->setWebsiteId($websiteId)
->loadByEmail($email);
// handle customer not exists by creating a new customer
if($customer->getId() == ''){
$customer = Mage::getModel('customer/customer');
$customer->setWebsiteId($websiteId)
->setStore($store)
->setFirstName("Bob")
->setLastName("Loblaw")
->setEmail($email)
->setPassword('password');
$customer->save();
}
// assign customer to SO quote
$quote->assignCustomer($customer);
// do we want to send a confirmation email to the customer?
// my guess is we would handle that in a separate service.
$quote->setSendConfirmation(0);
// add products to quote
foreach($data->products as $item){
$product = Mage::getModel('catalog/product')->load($item->id);
$quote->addProduct($product,new Varien_Object(array('qty'=>$item->qty)));
}
// set SO billing address
$billingAddress = $quote->getBillingAddress()->addData(array(
'customer_address_id' => '',
'prefix' => '',
'firstname' => $data->customer->firstName,
'middlename' => '',
'lastname' => $data->customer->lastName,
'suffix' => '',
'company' => '',
'street' => array(
'0' => 'street1',
'1' => 'street2'
),
'city'=>'city',
'country_id'=>'US',
'region'=>'WA',
'postcode'=>'98101',
'telephone' => '425-425-4254',
'fax' => '789-789-7897',
'vat_id' => '',
'save_in_address_book' => 0
));
// set SO shipping address, this will probably be the location of sale, on-site
$shippingAddress = $quote->getShippingAddress()->addData(array(
'customer_address_id' => '',
'prefix' => '',
'firstname' => $data->customer->firstName,
'middlename' => 'middle',
'lastname' => $data->customer->lastName,
'suffix' => '',
'company' => '',
'street' => array(
'0' => 'street1',
'1' => 'street2'
),
'city'=>'city',
'country_id'=>'US',
'region'=>'WA',
'postcode'=>'98201',
'telephone' => '425-425-4254',
'fax' => '789-789-7897',
'vat_id' => '',
'save_in_address_book' => 0
));
// set shipping method, if it's sold on site we aren't charging for delivery
$shipMethod='freeshipping_freeshipping';
$shippingAddress->setCollectShippingRates(true)
->collectShippingRates()
->setShippingMethod($shipMethod)
->setPaymentMethod($data->payment->method);
// set payment method
$quote->getPayment()->importData(array(
'method' =>$data->payment->method,
'cc_type' =>$data->payment->type,
'cc_number' =>$data->payment->number,
'cc_exp_year' =>$data->payment->expYear,
'cc_exp_month'=>$data->payment->expMonth,
));
// collect totals, save quote
$quote->collectTotals()->save();
// turn the quote into an order
$service = Mage::getModel('sales/service_quote',$quote);
// set payment method A SECOND TIME!!!!!!!!!!!!!
$quote->getPayment()->importData(array(
'method' =>$data->payment->method,
'cc_type' =>$data->payment->type,
'cc_number' =>$data->payment->number,
'cc_exp_year' =>$data->payment->expYear,
'cc_exp_month'=>$data->payment->expMonth,
));
$service->submitAll();
$increment_id = $service->getOrder()->getRealOrderId();
$quote = $customer = $service = null;
$retval = new stdClass;
$retval->orderId = $increment_id;
return json_encode($retval);
}
I have never done successful API transactions to the payment method code authorizenet
. This only always succeeds via frontend, not sure why.. nor have I had time to investigate why. Although what I have always done instead is to use authorizenet_direct
post instead. My reasoning behind this / how I stumbled upon this is that the same also applies to the Paypal payment methods. API seems to only work with paypal_direct
or paypaluk_direct
. Try it! it should work. At the very least, this works for me.
$paymentMethod = array(
"method" => "authorizenet_directpost",
"cc_type" => 'MC',
"cc_number" =>'5555555555554444' ,
"cc_exp_month" => 9,
"cc_exp_year" => 2014,
"cc_cid" => 123
);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With