Error sharing customer stripe and create charges with php - php

I'm sorry for my english.
I'm try to create a charge with a connected account in stripe using standalone account. I'm connecting my accounts using this article in stripe: Sample OAuth Applications. I have 3 accounts: A) Main account. In this account are the clients of our app. Account B and account C are other accounts connected to account A (I see this two accounts connect in the settings of account A. That tells me that two account is already connected, right?). All user's app is in account A and we want share to account B and C, that's our target.
When the accounts has been connected we save in our DB the acces_token and refresh token. The docs of shared customers says that we need create a token with the customer_id and the account_id in order to create a token with the credit card info of customer but when we execute the code it returns an error:
The provided key 'sk_test_********************uJ3l' does not have access to account 'acct_--------------' (or that account does not exist). Application access may have been revoked.
We have test a several combinations of variables pass to api and the result always returns an error.
What are doing wrong in this case. Can you help us???
This is the code that we using: All the comments has been the another test that we try:
public function createtransaction($customer_id, $paymentDesc, $destinationAccount) {
$errors = array();
try {
$secret_key = $this->get_secret_key();
\Stripe\Stripe::setApiKey($secret_key);
// THIS ONLY FOR TESTING PURPOSE. WE WANT SEE IF CAN ACCESS TO CONNECTED ACCOUNT
// Fetching an account just needs the ID as a parameter
// WHIT ACCESS_TOKEN WORKS THE RETRIEVE METHOD
// $account = \Stripe\Account::retrieve('access_token_from_db');
// WHIT ACCOUNT_ID DOES NOT. RETURNS AN ERROR
// $account = \Stripe\Account::retrieve('acct_***********');
// echo "<pre>------";
// print_r($account);
// echo "-----</pre>";
// HERE ONLY WE CAN TEST IF WE CAN CREATE A CUSTOMER. THIS IS ONLY TO CHECK IF THE ACCOUNT IS CONNECTED. THE CUSTOMER ALREADY EXISTS IN MAIN ACCOUNT
// Recommended: sending API key with every request
// \Stripe\Customer::create(
// array("description" => "example#stripe.com"),
// array("api_key" => 'sk_test_***************') // account's access token from the Connect flow
// SAME. WITH stripe_account DOES NOT WORK. WHIT api_key PARAM WORKS WELL
// );
// THE DOCS SAYS WE NEED CREATE A TOEKN WITH customer AND stripe_account, BUT IT RETURNS AN ERROR OF PERMISSION
// Create a Token from the existing customer on the platform's account
// $token = \Stripe\Token::create(
// array("customer" => $customer_id),
// array("stripe_account" => 'acct_********************') // id of the connected account
// );
// echo "<pre>------";
// print_r($token);
// echo "-----</pre>";
// ONE COMBINATION. DOES NOT WORK
// var_dump($customer_id, $paymentDesc, $destinationAccount);
// $charge = \Stripe\Charge::create(array(
// "amount" => $paymentDesc['total'] * 100,
// "currency" => "usd",
// "source" => $token,
// "description" => $paymentDesc['description'],
// 'destination' => $destinationAccount
// ));
//
//
// IT WORKS IN THE MAIN ACCOUNT BUT IT IS NOT OUR GOAL, BUT WE CAN TRANSFER THE MONEY TO ANOTHER CONNECTED ACCOUNT
// $charge = \Stripe\Charge::create(array(
// 'amount' => $paymentDesc['total'] * 100,
// 'currency' => 'usd',
// 'customer' => $customer_id,
// "description" => $paymentDesc['description']
// ));
// ANOTHER COMBINATION. DOES NOT WORK
/*$charge = \Stripe\Charge::create(array(
'amount' => $paymentDesc['total'] * 100,
'currency' => 'usd',
"description" => $paymentDesc['description'],
'customer' => $customer_id
), array('stripe_account' => 'acct_************'));*/
// ANOTHER COMBINATION. DOES NOT WORK
/*$charge = \Stripe\Charge::create(array(
'amount' => $paymentDesc['total'] * 100,
'currency' => 'usd',
"description" => $paymentDesc['description'],
'customer' => $customer_id
), array('api_key' => 'ACCESS_TOKEN_IN_DB'));
echo "<pre>------";
print_r($charge);
echo "-----</pre>";
return array('charge' => $charge);*/
} catch(Stripe_CardError $e) {
$errors = array('error' => false, 'message' => 'Card was declined.', 'e' => $e);
} catch (Stripe_InvalidRequestError $e) {
$errors = array('error' => false, 'message' => 'Invalid parameters were supplied to Stripe\'s API', 'e' => $e);
} catch (Stripe_AuthenticationError $e) {
$errors = array('error' => false, 'message' => 'Authentication with Stripe\'s API failed!', 'e' => $e);
} catch (Stripe_ApiConnectionError $e) {
$errors = array('error' => false, 'message' => 'Network communication with Stripe failed', 'e' => $e);
} catch (Stripe_Error $e) {
$errors = array('error' => false, 'message' => 'Stripe error. Something wrong just happened!', 'e' => $e);
} catch (Exception $e) {
$errors = array('error' => false, 'message' => 'An error has ocurred getting info customer.', 'e' => $e);
}
return $errors;
}

You don't need to save the access_token and refresh_token, only the stripe_user_id containing the connected account id is required to work with Connect.
You can use your platform's secret API key for all the requests and just pass the connected account id to the Stripe-account header as shown in the shared customers documentation. More generally this header can be added to almost every API request to have it directed at a connected account:
https://stripe.com/docs/connect/authentication#authentication-via-the-stripe-account-header
In your case you'd do:
// Create a Token from the existing customer on the platform's account
$sharedToken = \Stripe\Token::create(
array("customer" => CUSTOMER_ID, "card" => CARD_ID),
array("stripe_account" => CONNECTED_STRIPE_ACCOUNT_ID) // id of the connected account
);
$sharedCustomer = \Stripe\Customer::create(array(
"description" => "Customer for noah.robinson#example.com",
"source" => $sharedToken),
array("stripe_account" => CONNECTED_STRIPE_ACCOUNT_ID)
);
You can then create a charge from this shared customer in the same way:
\Stripe\Charge::create(array(
"amount" => 2000,
"currency" => "usd",
"customer" => $sharedCustomer),
array("stripe_account" => CONNECTED_STRIPE_ACCOUNT_ID)
);

Related

Stripe - Same Payment Intent Using Manual Confirmation

I am trying to migrate my payment flow from the charges API to payment intents.
The stripe migration docs indicate in step 2 you need to create the payment intent on the server https://stripe.com/docs/payments/payment-intents/quickstart#creating-with-manual-confirmation
If the payment fails and user attempt another payment then I'd be creating multiple payment intents for the same order.
Is there a way that I can reuse the same payment intent if let's say I created the payment intent as soon as the amount is known and then stored the payment intent for that order in a database table using the manual confirmation method?
So something like this:
// create intent
$intent = \Stripe\PaymentIntent::create([
'amount' => 1099,
'currency' => 'usd',
'confirmation_method' => 'manual',
],[
'idempotency_key' => $orderId,
]);
// Update orders table with payment intent id and set order status to unpaid
Then when user makes payment:
# vendor using composer
require_once('vendor/autoload.php');
\Stripe\Stripe::setApiKey(getenv('STRIPE_SECRET_KEY'));
header('Content-Type: application/json');
# retrieve json from POST body
$json_str = file_get_contents('php://input');
$json_obj = json_decode($json_str);
#$intent = null;
$order = // get from database
$intent = \Stripe\PaymentIntent::retrieve($order->payment_intent_id);
try {
if (isset($json_obj->payment_method_id)) {
# Create the PaymentIntent
#$intent = \Stripe\PaymentIntent::create([
# 'payment_method' => $json_obj->payment_method_id,
# 'amount' => 1099,
# 'currency' => 'usd',
# 'confirmation_method' => 'manual',
# 'confirm' => true,
#]);
# Instead of creating a new payment intent we update the previously saved PaymentIntent
\Stripe\PaymentIntent::update($intent->id,
[
'payment_method' => $json_obj->payment_method_id,
'confirm' => true,
]
);
}
if (isset($json_obj->payment_intent_id)) {
$intent = \Stripe\PaymentIntent::retrieve(
$json_obj->payment_intent_id
);
$intent->confirm();
}
generatePaymentResponse($intent);
} catch (\Stripe\Error\Base $e) {
# Display error on client
echo json_encode([
'error' => $e->getMessage()
]);
}
function generatePaymentResponse($intent) {
# Note that if your API version is before 2019-02-11, 'requires_action'
# appears as 'requires_source_action'.
if ($intent->status == 'requires_action' &&
$intent->next_action->type == 'use_stripe_sdk') {
# Tell the client to handle the action
echo json_encode([
'requires_action' => true,
'payment_intent_client_secret' => $intent->client_secret
]);
} else if ($intent->status == 'succeeded') {
# The payment didn’t need any additional actions and completed!
# Handle post-payment fulfillment
echo json_encode([
"success" => true
]);
} else {
# Invalid status
http_response_code(500);
echo json_encode(['error' => 'Invalid PaymentIntent status']);
}
}
Any tips and advice appreciated.

Is there a way to pass the metadata from Subscription API to Charge API?

I have two functions namely charge and subscription, when a successful charge
happens I insert some metadata there look below:
Same for the subscription function:
Then I have a separate file which I will not post here because it only calls to the Charge list API to get all the successful charges to check all the metadatas in there, however I noticed that once I created a subscription via API it's only available there the metadata1 and metadata2.
When I view on the charge created by the subscription nothing was attached to its metadata. How can I attach the metadatas from the subscription to the charge that corresponds to it?
<?php
require_once('stripe-php-master/init.php');
require 'apiKeys.php';
$data = $_REQUEST['data'];
if(isset($data['stripeToken'])){
create_customer($data);
}else{
printResponse($data,"No Token");
}
//Create Customer
function create_customer($data){
try{
\Stripe\Stripe::setApiKey(SK_TEST_KEY);
$customer = \Stripe\Customer::create(array(
"description" => 'Widget Create Customer',
"source" => $data['stripeToken'],
"email" => $data['stripeEmail']
));
$data['customerID'] = $customer->id;
//create_charge($data);
create_subscription($data);
}catch(Exception $e){
echo $e->getMessage();
exit;
}
}//create_customer
//Create charge
function create_charge($data){
try{
\Stripe\Stripe::setApiKey(SK_TEST_KEY);
$settings = [
'currency' => 'aud',
'amount'=>5500,
'description' => 'Widget Payment for ' .$data['widget_name'],
'customer' => $data['customerID'],
'metadata'=>["metadata1" => $data['metadata1'],"metadata2" => $data['metadata2']]
];
// Get the payment token ID submitted by the form:
$charge = \Stripe\Charge::create($settings);
printResponse($data, $charge->status);
}catch(Exception $e){
printResponse($data,$e->getMessage());
exit;
}
}//create_charge
//Create subscription
function create_subscription($data){
try{
\Stripe\Stripe::setApiKey(SK_TEST_KEY);
$settings = [
'customer' => $data['customerID'],
'metadata'=>["metadata1" => $data['metadata1'],"metadata2" => $data['metadata2']],
'items' => [
[
'plan' => $data['widget_class']
]
]
];
$subscription = \Stripe\Subscription::create($settings);
printResponse($data,$subscription->status);
}catch(Exception $e){
printResponse($data,$e->getMessage());
exit;
}
}
function printResponse($data,$status){
//CREATE Response JSON
print_r(json_encode([
'customer_name'=> $data['customer_name'],
'metadata1' => $data['metadata1'],
'metadata2'=> $data['metadata2'],
'payment_status'=>$status
]));
}
?>
I just want the when someone subscribes the charge from the subscription event has the metadata1 and metadata2 attached to it.

Wepay integration

I'm trying to create a simple checkout page with wepay and my checkout code (taken from the SDK sample) works great for the owner (me) when I'm signed in, but when logged in as a different user who hasn't created the account (under theirs?) it says the account is invalid or does not belong to the user.
So how are new logged in users supposed to pay to the account (mine), in other words make payments?
Here is the code for reference. The account_id doesn't work for new logged in users because they haven't created it.
$wepay = new WePay($_SESSION['wepay_access_token']);
$checkout = $wepay->request('checkout/create', array(
'account_id' => 501999810,
'amount' => 1.00,
'currency'=> 'USD',
'short_description'=> 'Selling 42 Pens',
'type'=> 'goods'
));
Maybe I have something completely off, but that account_id is where I want to receive payments?
Any help would be appreciated!
Once you register the user, you have to create an actual merchant account by calling /account/create.
Once you have the user's access token, you can call /account/create with the user's access token and the relevant info to actually attach an account to the user. The /account/create call will return an account_id. That account_id is the one you use in the /checkout/create call.
So until you create an account via /account/create the user cannot accept payments.
$productData['data']['seller_data']['wepay_access_token']="STAGE_ea6cd2dffa3dfa23bd4817f210936fadada9fa91e906f353e15813c6cf920fb8";
$productData['data']['seller_data'}['wepay_account_id']="287443494";
$wepay = new WePay($productData['data']['seller_data']['wepay_access_token']);
$checkOutData = array(
//"account_id" => 12345678,
"account_id" => $productData['data']['seller_data'}['wepay_account_id'],
"amount" => 500,
"type" => "goods",
"currency" => "USD",
"short_description" => "Purchase made at test site",
"long_description" => "The charges made in this payment are of the order placed in test",
"delivery_type" => "point_of_sale",
"fee" => array(
"app_fee" => 15,
//'fee_payer' => 'payer_from_app'
'fee_payer' => 'payee_from_app'
),
//"auto_release"=>false,
"payment_method" => array(
"type" => "credit_card",
"credit_card" => array(
"id" => 2178689241,
"auto_capture" => false
)
)
);
try {
$checkoutResult = $wepay->request('checkout/create', $checkOutData);
} catch (Exception $e) {
$data['status'] = '0';
$data['message'] = 'We could not complete checkout!';
return $this->SetOutput();
}
You can get seller access token and account id using
$user_id=20;
$access_token="STAGE_ea6cd2dffa3dfa23bd4817f210936fadada9fa91e906f353e15813c6cf920fb8":
$userName="test user";
$description="sell products";
try {
$wepay = new WePay($access_token);
if (empty($userName)) {
try {
$uresponse = $wepay->request('/user');
$userName = $uresponse->user_name;
} catch (WePayException $e) {
$uresponse['status'] = '0';
$uresponse['message'] = $e->getMessage();
return $uresponse;
}
}
$response = $wepay->request('account/create/', array(
'name' => $userName,
'description' => $description,
'reference_id' => '"' . $user_id . '"'
));
} catch (WePayException $e) {
$response['status'] = '0';
$response['message'] = $e->getMessage();
return $response;
}

Laravel Cashier: Invalid Request, No such customer

I am trying to implement what mentioned here but getting error:
Array ([type] => invalid_request_error [message] => No such customer: 92 [param] => customer)
I am using Laravel Cashier:
$user = User::find($current_user_id);
if ($user->charge(100, [
'customer' => 92,
'source' => $token,
'description' => "Testing Payment Deduction for Brief"
])
) {
print "Awesome";
} else {
print "it failed";
}
Using this code to create customer fails as it trie to create a record in users table which does not need as I already have a user created:
$customer = $user->create(array(
'email' => 'customer#example.com',
'card' => $token
));
How can I send my existing customer ID and email to Stripe?
This issues erupts only due to one reason and that is token generated by following function.
Stripe.card.createToken($form, stripeResponseHandler)
in stripeResponseHandler(status, response)
response.id is the token value. so please use this token to create subscription or whatever... Thanks

Does the creditCard function exist in Omnipay PayPal Express? Or only in PayPal Pro?

This question is maybe similar to THIS and THIS but I'm not entirely sure.
I've made a shopping cart that sends the product details and quantity/total amount to Paypal on checking out. I'm using Laravel 4 and the Omnipay Paypal plugin (Paypal_Express). I can send product details fine using the 'setItems' function and am now looking to pre-populate the credit card field on the Paypal summary page with my User's details.
I have seen in other SO threads such as THIS that other people use the creditCard function to pass details to the Paypal summary credit card info page.
My question: 1) Do you need to be using Paypal_Pro for the creditCard function to worK?
I get this error when I try (call_user_func_array() expects parameter 1 to be a valid callback, class 'Omnipay\Common\GatewayFactory' does not have a method 'creditCard').
I don't want to enter all the credit card details - Just speed the process up by entering the User's Name, Adress etc...
Also I tried changing to Paypal_Pro and it didn't work. (same error as above) I changed config plus gateways in my payment controller.
2)How do you change PayPal_Express to PayPay_Pro?
My code:
public function postPayment() {
$cart = Session::get('cart');
$allProducts = [];
foreach($cart->aContents as $productID=>$quantity){
$product = Product::find($productID);
// get the product id
// load the product from the id
// store data in the allProduct array
$allProducts[] = array('name' => $product->name, 'quantity' => $quantity, 'price'=> $product->price);
}
$cardInput = array(
'first_name' => Input::get('first_name'),
'last_name' => Input::get('last_name'),
'address1' => Input::get('address1'),
'city' => Input::get('city'),
'zip' => Input::get('zip'),
'email' => Input::get('email')
);
$card = Omnipay::creditCard($cardInput);
$params = array(
'cancelUrl' => \URL::to('cancel_order'),
'returnUrl' => \URL::to('payment_success'),
'amount' => Input::get('price'),
'currency' => Input::get('currency'),
'card' => $card,
);
Session::put('params', $params);
Session::save();
$gateway = Omnipay::create('PayPal_Express');
$gateway->setUsername('tjmusicmanagement-facilitator_api1.gmail.com');
$gateway->setPassword('K2LWQVP2L8472BPY');
$gateway->setSignature('AwTOuAJWzCkdc5PldYeiz.l3iy5UAwOucYW6EFLLA9zUQqXaWyEGbebq');
$gateway->setTestMode(true);
$gateway->setLogoImageUrl(URL::to('images/logoSmall.png'));
$response = $gateway->purchase($params)->setItems($allProducts)->send();
if ($response->isSuccessful()) {
// payment was successful: update database
print_r($response);
} elseif ($response->isRedirect()) {
// redirect to offsite payment gateway
$response->redirect();
} else {
// payment failed: display message to customer
echo $response->getMessage();
}
}
And also the ignited\laravel-omnipay\config.php is unchanged (though I did try changing the driver)
return array(
// The default gateway to use
'default' => 'paypal',
// Add in each gateway here
'gateways' => array(
'paypal' => array(
'driver' => 'PayPal_Express',
'options' => array(
'solutionType' => '',
'landingPage' => '',
'headerImageUrl' => ''
)
)
)
);
Thanks for your tinme!!
EDIT: Here is my getSuccessPayment function where I can hopefully get the users paypal details (just name and address etc) from paypal. But how and where do I specify this?
public function getSuccessPayment()
{
$gateway = Omnipay::create('PayPal_Express');
$gateway->setUsername('lillyloverofwar-facilitator_api1.gmail.com');
$gateway->setPassword('U6LM3SG2MNCA3QE2');
$gateway->setSignature('AJVP9tUtdotIeVt82RpcG7n9ld-tAdCG1Ramb1u8yZECHhSpiXc0BO04');
$gateway->setTestMode(true);
$params = Session::get('params');
$response = $gateway->completePurchase($params)->send();
$paypalResponse = $response->getData(); // this is the raw response object
if(isset($paypalResponse['PAYMENTINFO_0_ACK']) && $paypalResponse['PAYMENTINFO_0_ACK'] === 'Success') {
// return View::make('successfulPayment')->with($params);
// Session::flush();
// Response
// print_r($paypalResponse);
} else {
//Failed transaction
}
// FLUSHING SESSION HERE GETS AN ERROR
// Session::flush();
return View::make('successfulPayment');
}
1) I get this error when I try (call_user_func_array() expects parameter 1 to be a valid callback, class 'Omnipay\Common\GatewayFactory' does not have a method 'creditCard').
You can't use credit cards on the PayPal Express gateway, only on Pro or REST. I recommend that you use the REST gateway not the Pro gateway (REST supersedes Pro and has more features).
I don't want to enter all the credit card details - Just speed the process up by entering the User's Name, Adress etc...
There is no need to do that if you are using PayPal Express anyway, because PayPal will provide you the necessary details after the user has gone through the PayPal login process and authorized the transaction.
Also I tried changing to Paypal_Pro and it didn't work. (same error as above) I changed config plus gateways in my payment controller.
2)How do you change PayPal_Express to PayPay_Pro?
I suggest you have a look at my fork of the omnipay-paypal gateway, https://github.com/delatbabel/omnipay-paypal -- on the accept-paypal-payments branch there are additional commits (sent as a PR to the main repository but not merged yet) with additional features such as using the REST gateway for either Credit Card or PayPal purchases, and additional API documentation including code examples on how to use the REST gateway.
Here is the code example for using the Rest gateway for a purchase transaction with a credit card:
// Create a gateway for the PayPal RestGateway
// (routes to GatewayFactory::create)
$gateway = Omnipay::create('RestGateway');
// Initialise the gateway
$gateway->initialize(array(
'clientId' => 'MyPayPalClientId',
'secret' => 'MyPayPalSecret',
'testMode' => true, // Or false when you are ready for live transactions
));
// Create a credit card object
// DO NOT USE THESE CARD VALUES -- substitute your own
// see the documentation in the class header.
$card = new CreditCard(array(
'firstName' => 'Example',
'lastName' => 'User',
'number' => '4111111111111111',
'expiryMonth' => '01',
'expiryYear' => '2020',
'cvv' => '123',
'billingAddress1' => '1 Scrubby Creek Road',
'billingCountry' => 'AU',
'billingCity' => 'Scrubby Creek',
'billingPostcode' => '4999',
'billingState' => 'QLD',
));
// Do a purchase transaction on the gateway
$transaction = $gateway->purchase(array(
'amount' => '10.00',
'currency' => 'AUD',
'description' => 'This is a test purchase transaction.',
'card' => $card,
));
$response = $transaction->send();
if ($response->isSuccessful()) {
echo "Purchase transaction was successful!\n";
$sale_id = $response->getTransactionReference();
echo "Transaction reference = " . $sale_id . "\n";
}

Categories