Laravel stripe (customers and invoice) - laravel

I created customer and product in stripe.
I create paymentIntent, invoiceItems and invoice for this customer. How i can connect invoice and payment?
My controller:
//check user in stripe
$stripeCustomer = $this->stripe->customers->search([
'query' => "email:'$user->email'",
]);
if (isset($stripeCustomer['data']) && !count($stripeCustomer['data']) ) {
//create new user
$stripeCustomer = $this->stripe->customers->create([
'email' => $user->email,
'name' => $user->name
]);
$stripeCustomerId = $stripeCustomer->id ?: 0;
} else {
$stripeCustomerId = $stripeCustomer['data'][0]->id;
}
$invoiceItems = $this->stripe->invoiceItems->create([
'customer' => $stripeCustomerId,
'price' => $product ? $product->stripe_price_id : null,
]);
//create draft invoice
$invoice = $this->stripe->invoices->create([
'customer' => $stripeCustomerId,
]);
//create payment
$paymentIntent = $this->stripe->paymentIntents->create([
'customer' => $stripeCustomerId,
'amount' => $invoiceItems->amount,
'currency' => Payment::CURRENCY_EUR,
'payment_method_types' => ['card']
]);
$clientSecret = $paymentIntent->client_secret;
After submitting form (number card, etc...) I am confirmPayment in view:
const { error } = await stripe.confirmPayment({
elements,
confirmParams: {
// Make sure to change this to your payment completion page
return_url: "{{route('payment-success'), [ 'token' => $token ])}}",
},
});
My paymentSuccess method:
public function paymentSuccess($token)
{
$data = json_decode(base64_decode($token));
//$data->paymentId
// maybe here i must pay invoice for my paymentId???
}

Invoices can be paid in two ways
Stripe automatically creates and then attempts to collect payment on
invoices for customers on subscriptions according to your
subscriptions settings. However, if you’d like to attempt payment on
an invoice out of the normal collection schedule or for some other
reason, you can do so as follows.
$this->stripe->invoices->finalizeInvoice(
$invoice->id,
[]
);
$this->stripe->invoices->pay(
$invoice->id,
[]
);
OR
You can manually send an invoice through email to your customer to
pay. You can do so as follow
$this->stripe->invoices->finalizeInvoice(
$invoice->id,
[]
);
$this->stripe->invoices->sendInvoice(
$invoice->id,
[]
);

Related

Not getting data for authenticated user from database in Laravel for setting stripe

I've been trying to get the saved customer id for stripe from database but with no luck.
It works everywhere else, I could get it and save it again if I wanted, but whenever I try to use it in payment intent to automatically renew a subscription, it gives me this error: Trying to get property 'stripecustomerid' of non-object.
this is the bit of the stripe code for recurring charge where the error happens:
public function renew($subscription)
{
\Stripe\Stripe::setApiKey('sk_test_XXXXXXXX');
header('Content-Type: application/json');
try {
$json_str = file_get_contents('php://input');
$json_obj = json_decode($json_str);
$user = \Auth::user();
$payment_methods = \Stripe\PaymentMethod::all([
'customer' => $user->stripecustomerid,
'type' => 'card'
]);
$payment_intent = \Stripe\PaymentIntent::create([
'amount' => $subscription->plan->stripePrice(),
'currency' => 'usd',
'customer' => $user->stripecustomerid,
'payment_method' => $payment_methods->data[0]->id,
'off_session' => true,
'confirm' => true,
]);
echo json_encode([
'paymentIntent' => $payment_intent,
]);
}
catch (\Exception $e) {
http_response_code(500);
echo json_encode(['error' => $e->getMessage()]);
}
}
and stripecustomerid is the name of the column where I saved the customer id.
I can print it in another function, and it works when I use GET, but it just doesn't work when the subscription tries to renew.

Stripe & Laravel how to upgrade or downgrade session subscription?

I have some issues using the Laravel Cashier for creating subscriptions.
First, from my backend I am creating a Package, which calls the following two Strip functions:
public function createStripeProduct(array $data)
{
$product = $this->stripe->products->create([
'name' => $data['title']." ".appName(),
]);
return $product->id;
}
public function createStripePrice(array $data)
{
$price = $this->stripe->prices->create([
'unit_amount' => $data['price'] * $this->multiple,
'currency' => $this->currency,
'recurring' => ['interval' => 'month'],
'product' => $data['stripe_prod_id'],
]);
return $price->id;
}
Then in my Controller, I am creating the session:
public function create(Request $request)
{
$key = config('services.stripe.secret');
$stripe = new Stripe\StripeClient($key);
$stripeCustomer = $user->createOrGetStripeCustomer();
$checkout_session = $stripe->checkout->sessions->create([
'customer' => $stripeCustomer['id'],
'success_url' => route('frontend.user.account'),
'cancel_url' => route('frontend.user.account'),
'payment_method_types' => ['card'],
'line_items' => [
[
'price' => $request->stripe_price_id,
'quantity' => 1,
],
],
'mode' => 'subscription',
'allow_promotion_codes' => true,
]);
return $checkout_session['id'];
}
Everything is working so far, but with the implementation, I can subscribe one use multiple times to the same or to a different Package.
How can I prevent this from happening and also how to implement a future upgrade/downgrade of the Package?
To answer your two questions:
1) I can subscribe one use multiple times to the same or to a different Package. How can I prevent this from happening
Your code is fetching a Stripe Customer object in createOrGetStripeCustomer(). You can list all Subscriptions on the Customer with https://stripe.com/docs/api/subscriptions/list#list_subscriptions-customer and then check if you want to create an additional CheckoutSession Subscription on that Customer.
2) how to implement a future upgrade/downgrade of the Package?
You would use the code snippets here: https://stripe.com/docs/billing/subscriptions/upgrade-downgrade#changing where you update the Subscription's SubscriptionItem with a new Price ID.
$sub = \Stripe\Subscription::update('sub_123', [
'cancel_at_period_end' => false,
'proration_behavior' => 'create_prorations',
'items' => [
[
'id' => $subscription->items->data[0]->id,
'price' => 'price_456', // the new Price to update to
],
],
]);

Save One-to-Many Relationship in Laravel 6

I have two Table that Transfer and Product that link One-to-Many Relationship. I'm to create relationship between Transfer and Product like Pics Below.
that get Selected Dropdown Product when Click Search.... and When Click Create save relationship Product into Transfers..
My Transfer Model
public function products()
{
return $this->hasMany(\App\Product::class);
}
My Product Model
public function transfer()
{
return $this->belongsTo(\App\Transfer::class);
}
in TransferController
public function store(Request $request)
{
$request->validate([
'from_location' => 'required',
'to_location' => 'required',
'status' => 'required',
'description' => 'nullable',
'shipping_charge' => 'nullable',
]);
$transfer = new Transfer();
$transfer->branch_id = auth()->user()->id;
$transfer->from_location = $request->input('from_location');
$transfer->to_location = $request->input('to_location');
$transfer->status = $request->input('status');
$transfer->shipping_charge = $request->input('shipping_charge');
$transfer->save();
// $products = new Product();
// $products->name = $request->input('')
return response()->json(['created' => true]);
}
I think its a dummy question, but i stuck 3 days with it. I'll appreciate of all Ur help...
You need to post the product_ids to backend that you selected,
and just update the relationship:
...
$transfer->shipping_charge = $request->input('shipping_charge');
$transfer->save();
Product::whereIn('id', $product_ids)->update(['transfer_id' => $transfer->id]);
If your products are all new, you can use saveMany:
$products = array(
new Product(['name' =>'product1', ...]),
new Product(['name' => 'product2', ...])
);
...
$transfer->save();
$transfer->products()->saveMany($products);

One time fee and recurring after with Stripe and Laravel Cashier

I am trying to charge a one time fee + first month subscription fee in stripe but I can't figure out how to do it since they change their interface.
After the initial fee + first month subscription fee, it should roll on a monthly basis.
Ideally I am looking to do this with Laravel Cashier.
Any ideas and examples will be welcome.
Here is how to charge a subscription or a one time pay in stripe:
public function index()
{
if (!request()->wantsJson()) {
abort(404);
}
$plan = request()->get('plan');
$stripeToken = request()->get('stripeToken');
$user = User::findOrFail(request()->get('userId'));
if (is_null($user) || is_null($plan) || is_null($stripeToken)) {
return response()->json(403);
}
if ($plan === self::PREMIUM) {
$user->newSubscription('main', self::PREMIUM_ID)->create($stripeToken);
}
if ($plan === self::EXTENDED) {
$transaction = $user->charge(999, ['currency' => 'usd', 'source' => $stripeToken]);
$payment = new Payment([
'payment_id' => $transaction->id,
'payment_status' => $transaction->paid,
'amount' => $transaction->amount,
]);
$user->payments()->save($payment);
}
return response()->json(200);
}
$user->newSubscription('main', 'plan_xxxxxxxxxxxxxx')->create($request->stripeToken);
$customer = Customer::retrieve($parent_account->stripe_id);
$charge = Charge::create(array(
'customer' => $customer->id,
'amount' => $amount,
'currency' => 'gbp',
'description' => 'Joining Fee',
));

How to send 'description' of products to Paypal express (omnipay)?

I have setup a checkout system with Ominpay and Paypal express and it worked fine in test mode so I just went 'live' with it. Unfortunately I didn't check whether all the information was sent to paypal after checkout. It seems only the amount and currency are getting sent and not the description/name of the products. This means the seller doesn't know what got sold!
N.B: Everything gets sent to the Paypal checkout page fine. But after payment is made the product names don't show up on the seller's paypal page - only the quantity and price do.
How can I get the product names to show up on the seller's paypal account? It will be an array because multiple products will be sold.
If it helps here's the site: http://threemarchhares.sukeates.com/
I'm using Laravel 4. My payments controller:
public function postPayment() {
$cart = Session::get('cart');
$allProducts = [];
foreach($cart->aContents as $productID=>$quantity){
$product = Product::find($productID);
$allProducts[] = array('name' => $product->name, 'quantity' => $quantity, 'price'=> $product->price);
}
$params = array(
'cancelUrl' => \URL::to('cancel_order'),
'returnUrl' => \URL::to('payment_success'),
'amount' => Input::get('price'),
'currency' => Input::get('currency'),
'description' => Input::get('name'), //I assume this is wrong as it doesn't work.
);
Session::put('params', $params);
Session::save();
$gateway = Omnipay::create('PayPal_Express');
$gateway->setUsername('*****');
$gateway->setPassword('****');
$gateway->setSignature('***');
$gateway->setTestMode(false);
$response = $gateway->purchase($params)->setItems($allProducts)->send();
$data = $response->getData();
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();
}
}
public function getSuccessPayment()
{
$gateway = Omnipay::create('PayPal_Express');
$gateway->setUsername('****');
$gateway->setPassword('****');
$gateway->setSignature('*****');
$gateway->setTestMode(false);
$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') {
etc
Your assumption is correct. It is a bad idea in general to fill payment data from input. Instead you should use data from your product:
'amount' => $product->price,
'currency' => 'USD',
'description' => $product->description,
Otherwise the user can modify the price in html and enjoy cheap checkout ;)
You need to send the item information again, when you send the 'completePurchase' request.
$response = $gateway->completePurchase($params)->setItems($allProducts)->send();

Resources