I have this credit card adding when a customer first signs up
// CREDIT CARD CODE (STRIPE)
$q_get_user = "select * from users where `id` = '$user_id' ";
$r_get_user = mysqli_query($conn,$q_get_user);
$get_user = mysqli_fetch_assoc($r_get_user);
if(1) {
\Stripe\Stripe::setApiKey("sk_live_9N676756776");
try {
$t = \Stripe\Token::create(
array(
"card" => array(
"name" => $get_user['first_name']." ".$get_user['last_name'],
"number" => $credit_num,
"exp_month" => $credit_month,
"exp_year" => $credit_year,
"cvc" => $credit_ccv
)
)
);
if($t->id != '') {
try {
$c = \Stripe\Customer::create(array(
"description" => "Customer for ".$get_user['email'],
"source" => $t->id)
);
if($c->id != '') {
$stripe_token_response = mysqli_real_escape_string($conn, json_encode($t));
$stripe_token_id = mysqli_real_escape_string($conn, $t->id);
$stripe_customer_response = mysqli_real_escape_string($conn, json_encode($c));
$stripe_customer_id = mysqli_real_escape_string($conn, $c->id);
$stripe_card_id = mysqli_real_escape_string($conn, $c->default_source);
}
} catch (Exception $e) {
//print_r($e->getMessage());
header('Location: /credits?error=cc&message='.urlencode($e->getMessage()));die;
}
}
} catch (Exception $e) {
//print_r($e->getMessage());
header('Location: /credits?error=cc&message='.urlencode($e->getMessage()));die;
}
}
// END - CREDIT CARD CODE (STRIPE)
How can I make it inside of it being for a new customer for it to add to an existing customer? Therefore the customer is adding a new card (they will have more than one)
You are sending card details through the API directly, which is probably not something you want to do. This means that you get the card numbers on your server which has some serious PCI compliance implications. I would strongly advise you to modify your integration so that you always tokenize the card details first by using Stripe.js or Stripe Checkout client-side to send the card details to Stripe directly and get a unique card token (tok_XXX) that you'd then send safely to your server to create the Customer or add as a Card.
You can find a description of the 'card update' process here; the only difference you need is that, instead of doing this to replace the card:
$cu->source = $_POST['stripeToken']; // obtained with Checkout
You want to do this to add a new one:
$customer->sources->create(array("source" => $t->id));
Related
I have a simple form that registers users. The form also uses Stripe to process payments. Stripe's API is super clean but for some reason I can't seem to figure this out. Please tell me if i'm doing something wrong here.
Right now I'm in a test account with Stripe, but every time I register a user in stripe it keeps creating a new plan. I know in my code below I have "Stripe\Plan::create" that's because I don't know how to add a new customer to an existing plan. Is this normal the way I'm doing this currently?
In the screenshot below you will see that it will create a new plan for that customer and assign them to it. Is it possible to just keep adding new customers to an existing plan?
// Include configuration file
require_once 'stripe/config.php';
// Include Stripe PHP library
require_once 'vendor/autoload.php';
$payment_id = $statusMsg = $api_error = '';
$ordStatus = 'error';
// Check whether stripe token is not empty
if(!empty($_POST['stripeToken'])){
// Retrieve stripe token, card and user info from the submitted form data
$token = $_POST['stripeToken'];
$users_email = $_POST['email'];
$first_name = $_POST['first_name'];
$last_name = $_POST['last_name'];
$full_name = $first_name.' '.$last_name;
// Set API key
\Stripe\Stripe::setApiKey(STRIPE_API_KEY);
// Add customer to stripe
$customer = \Stripe\Customer::create(array(
'email' => $users_email,
'name' => $full_name,
'source' => $token
));
// Create a plan
try {
$plan = \Stripe\Plan::create([
'amount' => 3000,
'currency' => 'usd',
'interval' => 'month',
// 'product' => ['name' => 'Standard Plan'],
'product' => 'prod_ktItFVvqgr4edf',
]);
}catch(Exception $e) {
$api_error = $e->getMessage();
}
if(empty($api_error) && $plan){
// Creates a new subscription
try {
$subscription = \Stripe\Subscription::create(array(
"customer" => $customer->id,
"items" => array(
array(
"plan" => $plan->id,
),
),
));
}catch(Exception $e) {
$api_error = $e->getMessage();
}
if(empty($api_error) && $subscription){
// Retrieve subscription data
$subsData = $subscription->jsonSerialize();
// Check whether the subscription activation is successful
if($subsData['status'] == 'active'){
// Subscription info
$subscrID = $subsData['id'];
$custID = $subsData['customer'];
$planID = $subsData['plan']['id'];
$created = date("Y-m-d H:i:s", $subsData['created']);
$status = $subsData['status'];
// Insert into database
// Insert into database
}else{
$statusMsg = "Subscription activation failed!";
}
}else{
$statusMsg = "Subscription creation failed! ".$api_error;
}
}else{
$statusMsg = "Plan creation failed! ".$api_error;
}
}else{
$statusMsg = "Error on form submission, please try again.";
}
To create a subscription with an existing plan, simply pass in that older plan's ID when creating the subscription instead of creating a new plan for each customer. In your // Create a plan block, either retrieve an existing plan and use that to create the subscription or create a new plan if needed. Or better yet, store the plan ID's in your own database for easier retrieval.
It seems I am missing something when trying to handle some errors with Stripe in test mode with PHP.
Payment are successful when I enter a test card number like 4242424242424242 (for VISA) but I have no error and nothing is recorded when I enter a bad card number.
It is like if the button "Pay" was not working although it displays an error message if I use a real correct card number in test mode.
Does someone know what am I doing wrong here ? Thanks.
Here is the PHP code :
// Check whether stripe token is not empty
if(!empty($_POST['stripeToken'])){
// Retrieve stripe token, card and user info from the submitted form data
$token = $_POST['stripeToken'];
$name = $_POST['name'];
$email = $_POST['email'];
$card_number = $_POST['card_number'];
$card_exp_month = $_POST['card_exp_month'];
$card_exp_year = $_POST['card_exp_year'];
$card_cvc = $_POST['card_cvc'];
$itemPrice = $_POST['itemPrice'];
$itemNumber = $_POST['itemNumber'];
$Ticket_number = $_POST['Ticket_number'];
// Include Stripe PHP library
require_once 'stripe-php/init.php';
// Set API key
\Stripe\Stripe::setApiKey(STRIPE_API_KEY);
// Add customer to stripe
$customer = \Stripe\Customer::create(array(
'email' => $email,
'source' => $token
));
// Unique order ID
$orderID = strtoupper(str_replace('.','',uniqid('', true)));
// Convert price to cents
$itemPrice = ($itemPrice*100);
// Charge a credit or a debit card
$charge = \Stripe\Charge::create(array(
'customer' => $customer->id,
'amount' => $itemPrice,
'currency' => $currency,
'description' => $itemName,
'metadata' => array(
'order_id' => $orderID
)
));
// Retrieve charge details
$chargeJson = $charge->jsonSerialize();
// Check whether the charge is successful
if($chargeJson['amount_refunded'] == 0 && empty($chargeJson['failure_code']) && $chargeJson['paid'] == 1 && $chargeJson['captured'] == 1){
// Order details
$transactionID = $chargeJson['balance_transaction'];
$paidAmount = $chargeJson['amount'];
$paidCurrency = $chargeJson['currency'];
$payment_status = $chargeJson['status'];
// Include database connection file
include_once 'dbConnect.php';
$itemPrice = ($itemPrice/100);
$paidAmount = ($paidAmount/100);
// Insert tansaction data into the database
$sql = "INSERT INTO orders(name,email,card_number,card_exp_month,card_exp_year,item_name,item_number,item_price,item_price_currency,paid_amount,paid_amount_currency,txn_id,payment_status,created,modified) VALUES('".$name."','".$email."','".$card_number."','".$card_exp_month."','".$card_exp_year."','".$itemName."','".$itemNumber."','".$itemPrice."','".$currency."','".$paidAmount."','".$paidCurrency."','".$transactionID."','".$payment_status."',NOW(),NOW())";
$insert = $db->query($sql);
$payment_id = $db->insert_id;
// If the order is successful
if($payment_status == 'succeeded'){
$ordStatus = 'success';
$statusMsg = '';
}else{
$statusMsg = "Your Payment has Failed!";
}
}else{
print '<pre>';print_r($chargeJson);
$statusMsg = "Transaction has been failed!";
}
}else{
$statusMsg = "Error on form submission.";
}
?>
Thank you for your answers but in fact it was a dummy mistake : I did not declare an id to display my error. I had to add the following code in my form :
<p id="payment-status" role="alert"></p>
I'm looking to do the following sequence (using the Stripe API) when a customer submits a credit card:
Check if the user has a stripe customer id in their meta
If they don't, create a new customer, save the entered card to that user
If the user already has a customer id, check if the entered card is already one of their saved cards.
If it is, charge that card
If it's not, add the new card to the customer object, and then charge that card.
In my current code, Stripe is returning an invalid_request error upon trying to create the charge. Here's the section of code that relates:
//See if our user already has a customer ID, if not create one
$stripeCustID = get_user_meta($current_user->ID, 'stripeCustID', true);
if (!empty($stripeCustID)) {
$customer = \Stripe\Customer::retrieve($stripeCustID);
} else {
// Create a Customer:
$customer = \Stripe\Customer::create(array(
'email' => $current_user->user_email,
'source' => $token,
));
$stripeCustID = $customer->id;
//Add to user's meta
update_user_meta($current_user->ID, 'stripeCustID', $stripeCustID);
}
//Figure out if the user is using a stored card or a new card by comparing card fingerprints
$tokenData = \Stripe\Token::retrieve($token);
$thisCard = $tokenData['card'];
$custCards = $customer['sources']['data'];
foreach ($custCards as $card) {
if ($card['fingerprint'] == $thisCard['fingerprint']) {
$source = $thisCard['id'];
}
}
//If this card is not an existing one, we'll add it
if ($source == false) {
$newSource = $customer->sources->create(array('source' => $token));
$source=$newSource['id'];
}
// Try to authorize the card
$chargeArgs = array(
'amount' => $cartTotal,
'currency' => 'usd',
'description' => 'TPS Space Rental',
'customer' => $stripeCustID,
'source' => $source,
'capture' => false, //this pre-authorizes the card for 7 days instead of charging it immedietely
);
try {
$charge = \Stripe\Charge::create($chargeArgs);
Any help is appreciated.
The issue turned out to be this section:
if ($card['fingerprint'] == $thisCard['fingerprint']) {
$source = $thisCard['id'];
}
If a fingerprint match is successful, I need to grab the id of the card already in the users's meta, not the matching card that was inputted. So, this works:
if ($card['fingerprint'] == $thisCard['fingerprint']) {
$source = $card['id'];
}
Im using the authorize.net recurring transaction.
What Im trying to do is give the an option to check off a donation if they want it recurring for the next 12 months.
So before the ARB - I want to verify the card but 0.00 isn't a valid amount. so if i made the amount 0.01 - how can I void the transaction after the card is verified?
Also - when a subscription is made I dont get an email from authorize.net telling me a transaction was made like when a regular transaction is processed.
My code:
$authorization = new AuthnetAIM($apilogin, $apitranskey, true);
$authorization->setTransaction($creditcard, $expiration, '0.01');
$authorization->setTransactionType('AUTH_ONLY');
$authorization->process();
if ($authorization->isApproved())
{
$subscription = new AuthnetARB($apilogin, $apitranskey, AuthnetARB::USE_DEVELOPMENT_SERVER);
// Set subscription information
$subscription->setParameter('amount', $amount);
$subscription->setParameter('cardNumber', $creditcard);
$subscription->setParameter('expirationDate', $expiration);
$subscription->setParameter('firstName', $business_firstname);
$subscription->setParameter('lastName', $business_lastname);
$subscription->setParameter('address', $business_address);
$subscription->setParameter('city', $business_city);
$subscription->setParameter('state', $business_state);
$subscription->setParameter('zip', $business_zipcode);
$subscription->setParameter('email', $email);
// Set the billing cycle for every three months
$subscription->setParameter('interval_length', 1);
$subscription->setParameter('startDate', date("Y-m-d", strtotime("+ 1 months")));
// Create the subscription
$subscription->createAccount();
// Check the results of our API call
if ($subscription->isSuccessful())
{
// Get the subscription ID
$subscription_id = $subscription->getSubscriberID();
Send_email();
}
else
{
$transError = 'your subscription was not created';
$hasError = true;
}
}
else if ($authorization->isDeclined())
{
$transError = 'This card is not valid';
$hasError = true;
}
}
catch (AuthnetARBException $e)
{
$transError = 'There was an error processing the transaction. Here is the error message:<br/> ';
echo $e->__toString();
$hasError = true;
}
}
With the new SDK for authorize this would work
$authorize = new AuthorizeNetAIM(self::AUTHNET_LOGIN, self::AUTHNET_TRANSKEY);
$authorize->setFields(array(
'amount' => '0.01',
'card_num' => $cardNumber,
'exp_date' => $expDate
));
$response = $authorize->authorizeOnly();
if ($response->response_code == 1) {
// good card
}else{
// bad card
}
Not only is 0.00 a valid amount, but if you're just trying to verify a credit card is legitimate you are required by Visa and Mastercard to use that amount. A few years ago they stopped allowing pre-auths of any real value to be done for this reason. I think there are fines for merchants who fail to do so.
Having said that, if you're going to take the "charge $.01 and then void the transaction" route, the following code should work:
$transaction_id = $authorization->getTransactionID();
$void = new AuthnetAIM($apilogin, $apitranskey, true);
$void->setTransactionType("VOID");
$void->setParameter('x_trans_id', $transaction_id);
$void->process();
At the end of the purchase, the user has the possibility to change your shipping address. Im trying to update this information, but it dosen't work. This is my code:
$customer = Mage::getModel('customer/session')->getCustomer();
$order = Mage::getSingleton('checkout/session')->getLastOrder();
$postData = Mage::app()->getRequest()->getPost();
$_new_address = array (
'firstname' => $postData['nombre'],
'lastname' => $postData['apellidos'],
'street' => array ('0' => $postData['direccion']),
'city' => $postData['localidad'],
'region_id' => $postData['provincia_id'],
'region' => '',
'postcode' => $postData['codigo_postal'],
'country_id'=> 'ES',
'telephone' => $postData['telefono']
);
$customAddress = Mage::getModel('customer/address');
$customAddress->setData($_new_address)
->setCustomerId($customer->getId())
->setIsDefaultBilling('1')
->setIsDefaultShipping('1')
->setSaveInAddressBook('1');
// Save address
try {
$customAddress->save();
} catch (Exception $e) {
Mage::getSingleton('core/session')->addError($e->getMessage());
header('Location: /');
exit;
}
// Update the order
try {
$order->setShippingAddress($customAddress)->save();
} catch (Exception $e) {
Mage::getSingleton('core/session')->addError($e->getMessage());
header('Location: /');
exit;
}
Can I update an order or is not allowed? Can anyone give me a tip?
My problem was that the Billing address and shipping address in the order, are different than having the user has as default addresses.
At the end the code looks like this:
$order = Mage::getSingleton('checkout/session')->getLastOrder();
$postData = Mage::app()->getRequest()->getPost();
// Try to get shipping and billing address data.
$orderShippingAddress = $order->getShippingAddress()->getId();
$orderShipping = Mage::getModel('sales/order_address')->load($orderShippingAddress);
$orderBillingAddress = $order->getBillingAddress()->getId();
$orderBilling = Mage::getModel('sales/order_address')->load($orderBillingAddress);
// Updating data.
$orderShipping->addData($postData);
$orderBilling->addData($postData);
try {
$orderShipping->implodeStreetAddress()->save();
$orderBilling->implodeStreetAddress()->save();
} catch (Exception $e) {
Mage::logException($e);
Mage::getSingleton('core/session')->addError($e->getMessage());
header('Location: /after/success/envio');
exit;
}
Now, it works. Thanks for your help #R.S
Assuming that you want to update the shipping address for an order, take a look # addressSaveAction() in /app/code/core/Mage/Adminhtml/controllers/Sales/OrderController.php
$order = Mage::getSingleton('checkout/session')->getLastOrder();
//Get shipping address Id
$addressId = $order->getShippingAddress()->getId();
$address = Mage::getModel('sales/order_address')->load($addressId);
$data = $this->getRequest()->getPost();
$address->addData($data);
$address->implodeStreetAddress()->save();
Also i'm not sure if Mage::getSingleton('checkout/session')->getLastOrder() will still contain a valid order id after you submit your form since you will be loading a new page
While functioning correctly both other answers have an excessive address loading. The getShippingAddress already returns instance of sales/order_address. So the procedure can be simplified to following:
$order = Mage::getSingleton('checkout/session')->getLastOrder();
$data = $this->getRequest()->getPost();
$order->getShippingAddress()->addData($data)
->save();
Also implodeStreetAddress method call only required if you use multiline street address.