Stripe, users can not download their invoice - php

I am working with Stripe Payment Gateway and everything is working so far, except the option, that my users can download their invoice on my website. It is possible to download an invoice inside the stripe dashboard but that is not what I need. After my users made a payment, they should be able to download their invoices to my system.
Currently I am working with stripe webhooks. A user makes a payment and the data is saved inside my database. This is how my code looks like:
\Stripe\Stripe::setApiKey("$stripe_secret_key_test");
// Retrieve the request's body and parse it as JSON:
$input = #file_get_contents('php://input');
$event_json = json_decode($input);
// Update database with new billing entry
if ($event_json->type == 'invoice.payment_succeeded') {
$invoice_id = $event_json->data->object->id;
$customer = $event_json->data->object->customer;
$date = $event_json->data->object->date;
$price = $event_json->data->object->amount_paid;
$user = $event_json->data->object->lines->data[0]->metadata->userid;
$stripe_sub_id = $event_json->data->object->lines->data[0]->id;
$plan_id = $event_json->data->object->lines->data[0]->plan->id;
$stamp_created = $event_json->data->object->lines->data[0]->plan->created;
$comments = $event_json->data->object->lines->data[0]->plan->nickname;
$period_start = $event_json->data->object->lines->data[0]->period->start;
$period_end = $event_json->data->object->lines->data[0]->period->end;
$content=array("invoice"=>$invoice_id,
"user"=>$user,
"stripe_cust_id"=>$customer,
"stripe_sub_id"=>$stripe_sub_id,
"idea_id"=>0,
"billing_date"=>$date,
"plan"=>$plan_id,
"price"=>$price,
"stamp_created"=>$stamp_created,
"period_start"=>$period_start,
"period_end"=>$period_end,
"status"=>'paid',
"printed"=>0);
insertGWInfo('billing',$content);
$content=array("user"=>$user,
"trans_time"=>date("Y-m-d H:i:s"),
"ip"=>$_SERVER['REMOTE_ADDR'],
"trans_type"=>1,
"cash_amount"=>$price,
"comments"=>"Subscription for ".$comments."",
"idea_id"=>0);
insertGWInfo('user_accounting',$content);
}
Now I´ve created a table where I fetch those entries from my database and display them to my customer. I would like to have a button now with "Download Invoice" where my customers can download the subscription invoice which appears monthly.
Any idea how I can do this? I have the invoice_id but where do I get the URL to download an invoice? I wasn´t able to find anything inside the stripe docs. Any help would be really appreciated.
EDIT:
Here is the JSON outcome for invoice.payment_suceeded:
"{
"created": 1326853478,
"livemode": false,
"id": "evt_00000000000000",
"type": "invoice.payment_succeeded",
"object": "event",
"request": null,
"pending_webhooks": 1,
"api_version": "2018-02-28",
"data": {
"object": {
"id": "in_00000000000000",
"object": "invoice",
"amount_due": 1000,
"amount_paid": 1000,
"amount_remaining": 0,
"application_fee": null,
"attempt_count": 1,
"attempted": true,
"billing": "charge_automatically",
"charge": "_00000000000000",
"closed": true,
"currency": "eur",
"customer": "cus_00000000000000",
"date": 1526455801,
"description": null,
"discount": null,
"due_date": null,
"ending_balance": 0,
"forgiven": false,
"lines": {
"data": [
{
"id": "sub_Cs4DUPJKcAJ7cg",
"object": "line_item",
"amount": 1000,
"currency": "eur",
"description": "1 standard-inv × Standard Investor (at €10.00 / month)",
"discountable": true,
"livemode": false,
"metadata": {
},
"period": {
"end": 1531726201,
"start": 1529134201
},
"plan": {
"id": "3",
"object": "plan",
"aggregate_usage": null,
"amount": 1000,
"billing_scheme": "per_unit",
"created": 1526375755,
"currency": "eur",
"interval": "month",
"interval_count": 1,
"livemode": false,
"metadata": {
},
"nickname": "Standard Plan for Investors",
"product": "prod_CrihTVfgRHgImD",
"tiers": null,
"tiers_mode": null,
"transform_usage": null,
"trial_period_days": null,
"usage_type": "licensed"
},
"proration": false,
"quantity": 1,
"subscription": null,
"subscription_item": "si_Cs4DrvYN2FlCbS",
"type": "subscription"
}
],
"has_more": false,
"object": "list",
"url": "/v1/invoices/in_1CSK5FDsOByhb3e8m8Z1BooY/lines"
},
"livemode": false,
"metadata": {
},
"next_payment_attempt": null,
"number": "774C629-0001",
"paid": true,
"period_end": 1526455801,
"period_start": 1526455801,
"receipt_number": null,
"starting_balance": 0,
"statement_descriptor": null,
"subscription": "sub_00000000000000",
"subtotal": 1000,
"tax": null,
"tax_percent": null,
"total": 1000,
"webhooks_delivered_at": 1526455810
}
}
}"

Stripe DOES support this now. The PDF link is available by listing the invoices via the API and accessing the invoice_pdf attribute of an invoice.
Here's how you can get an array of invoices with their PDF links:
const invoicesResponse = await stripe.invoices.list({ customer: customerStripeId });
const invoices = invoicesResponse.map(invoice => ({
invoiceId: invoice['id'],
pdf: invoice['invoice_pdf'],
}));
return invoices;
Here's the API docs:
https://stripe.com/docs/api/invoices/object#invoice_object-invoice_pdf Thanks #avelis for the suggestion.

Stripe does not support downloading the invoice as a PDF at the moment via the API and it is only available in the dashboard instead.
For now, the best solution is to build your own invoice receipt/pdf instead. You can retrieve the Invoice object via the API which tells you what the invoice is for: period, amount, when it was paid, what's in that invoice, etc. And you can then generate your own receipt for your customers on your end.

it is posible :) works like a charm with the Python API.
import stripe
import requests
stripe_keys = {'secret_key': 'XXXxxxx','publishable_key': 'XXXxxxx'}
stripe.api_key = stripe_keys['secret_key']
stripe_subscription_id = 'XXXXXXX'
invoices = stripe.Invoice.list(subscription=stripe_subscription_id)
for inv in invoices:
pdf = inv.invoice_pdf
invoice_file = requests.get(pdf)
open('C://User//XXXXX//Desktop//invoice.pdf', 'wb').write(invoice_file.content)

There is a much easier way now. Following are the steps I follow to use Stripe's default method to download the invoice pdf.
Find the customer for which I want to download the invoice in pdf format
const findCustomerByEmail = async (email) => {
try {
const customer = await stripe.customers.list({
email,
limit: 1,
});
if (customer.data.length !== 0) {
return customer.data[0].id;
}
} catch (e) {
return (e);
}
};
Now that I have the customer, I then find all the invoices of the user:
exports.getInvoices = async (req, res, next) => {
const cusStripeId = await findCustomerByEmail(req.user.email);
const invoices = await stripe.invoices.list({
limit: 3000,
customer: cusStripeId,
});
res.status(httpStatus.OK).json(invoices);
};
Now I have a list of the invoices for this user. I can traverse through all the invoices.
invoices.data[0].invoice_pdf
invoices object is an array, and the data[0].invoice_pdf has a link that will download pdf. As an alternative we can also see the invoice as an html page without the need to download it, as follows.
invoices.data[0].hosted_invoice_url

Related

Pass data from curl to view on codeigniter

I have a json data from the curl, then I want to send it to a view in codeigniter but when I display it appears an error "illegal string offset".
json data:
{
"ProgramId": "29aee327-cd89-48c0-b79f-69a0e2b03709",
"ProgramName": "Microsoft CSP",
"CountryFullName": "Indonesia",
"CurrencyCode": "IDR",
"ProductGroups": [
{
"GroupName": "Microsoft 365",
"Products": [
{
"ProductId": "3451a3b0-8cda-44a7-bad7-c30be81c4aaa",
"ProductName": "Microsoft 365 F1",
"ProductGroup": "Microsoft 365",
"ProductSku": "3451A3B0-8CDA-44A7-BAD7-C30BE81C4AAA",
"Price": 0,
"MinQty": 1,
"MaxQty": 10000000,
"Qty": 0,
"UnitPrice": 132300,
"ProductUnit": "Licenses",
"RetailPrice": 147000,
"CommitmentValue": null,
"TieredProductSku": null,
"ProductType": "NON-SPECIFIC",
"ProductDescription": "Designed to meet the needs of firstline workers in your organization. Offers best-in-class productivity across devices while providing IT with security and control.",
"ProductShortDescription": null,
"ProductRestrictions": null,
"IsTrialProduct": false,
"BillingCycleDuration": 1
}
],
"IsExpanded": true,
"Order": -10
}
then I retrieve the data from a controller to be sent to the display, here I use the file_get_contents function
public function index()
{
$this->template->add_includes('js', 'assets/js/holder.js');
$init = "";
$this->template->add_init($init);
// GET data
$source = base_url().'api/products/'.$this->tenantId;
$content = file_get_contents($source);
$result = json_decode($content, true);
//print_r($result); exit;
$data['products']=$result;
$this->template->load('templates/Template', 'Demo',$data);
}

Stripe, Retrieve Card Info from Event

This was working for me on one account and today I added my listener to a new Stripe account and now it is no longer working. When a customer adds a new payment method to their account, the event customer.source.created is fired. Here is my code that WAS working (this is an excerpt):
<?php
if($event->type == 'customer.source.created') {
$cardID = $event_json->data->object->id;
$customerID = $event_json->data->object->customer;
$brand = $event_json->data->object->brand;
$last4 = $event_json->data->object->last4;
$exp_month = $event_json->data->object->exp_month;
$exp_year = $event_json->data->object->exp_year;
}
?>
Here is a sample Stripe JSON response:
{
"id": "evt_1DLkAh2Y54K5YG39Lku1hJ1G",
"object": "event",
"api_version": "2018-09-24",
"created": 1539664123,
"data": {
"object": {
"id": "card_1DLkAf2Y54K5YG39C0jMpCOj",
"object": "card",
"address_city": null,
"address_country": null,
"address_line1": null,
"address_line1_check": null,
"address_line2": null,
"address_state": null,
"address_zip": null,
"address_zip_check": null,
"brand": "JCB",
"country": "JP",
"customer": "cus_DnCcf39Nqp4RwF",
"cvc_check": "pass",
"dynamic_last4": null,
"exp_month": 12,
"exp_year": 2024,
"fingerprint": "t56gZmsPg6ztkHFH",
"funding": "credit",
"last4": "0000",
"metadata": {
},
"name": null,
"tokenization_method": null
}
},
"livemode": false,
"pending_webhooks": 2,
"request": {
"id": "req_L9pvt2RR3VSZoG",
"idempotency_key": null
},
"type": "customer.source.created"
}
The Stripe response code is 200. I have other events in my listener like charge.succeeded that are working just fine with pretty much the same coding methods. Right now, I can't get the $cardID to echo. So I'm wondering if Stripe changed something recently. I am running the latest version in Webhooks. I did try to revert to an older version but that didn't work either.
Ok this was a very stupid issue I didn't catch. The stripe account that I set up today was in an older version and there was an update available. I didn't catch that because I was working in test mode and you can only upgrade in live mode.
So, after upgrading, everything works perfectly. Hours of wasted time and something so simple.

Parse data from data sent by webhooks

A webhook is sending me some data to the URl I have provided. I am trying to catch the data. This is the code I am using:-
if ($this->input->server('REQUEST_METHOD') == 'POST')
{
file_put_contents('test.txt', file_get_contents('php://input'));
......................
}
The data which got saved in the txt file is this:-
{
"created_at": "2017-04-04 12:03:07 UTC",
"href": "http://api.groovehq.com/v1/tickets/131",
"links": {
"customer": {
"id": "0454984580",
"href": "http://api.groovehq.com/v1/customers/ncc2017customer#gmail.com"
},
"drafts": {
"href": "http://api.groovehq.com/v1/tickets/131/drafts"
},
"state": {
"href": "http://api.groovehq.com/v1/tickets/131/state"
},
"messages": {
"href": "http://api.groovehq.com/v1/tickets/131/messages"
}
},
"number": 131,
"priority": "low",
"resolution_time": null,
"state": "unread",
"title": "gh",
"updated_at": "2017-04-04 12:03:07 UTC",
"system_updated_at": "2017-04-04 12:03:07 UTC",
"assigned_group_id": null,
"assigned_group": null,
"closed_by": null,
"tags": [
],
"mailbox": "Inbox",
"mailbox_id": "1923237790",
"message_count": 1,
"summary": "Complaint Date: 2017-4-22 Service Provider: Airtel Type of Complaint: Billing NCC need to do: Investigate and resolve the issue Complaint Details: Vb",
"type": "API",
"snoozed_until": null,
"last_message": "Complaint Date: 2017-4-22<br />\nService Provider: Airtel<br />\nType of Complaint: Billing<br />\nNCC need to do: Investigate and resolve the issue<br />\nComplaint Details: Vb",
"assignee": null,
"app_url": "https://matrixdroid.groovehq.com/groove_client/tickets/44746020",
"app_customer_url": "https://matrixdroid.groovehq.com/groove_client/contacts/customers/17295897",
"customer_name": "ncc2017customer#gmail.com",
"last_message_plain_text": "Complaint Date: 2017-4-22\nService Provider: Airtel\nType of Complaint: Billing\nNCC need to do: Investigate and resolve the issue\nComplaint Details: Vb"
}
Now, I need to get the links->customer->href data
How can I get this?
I tried this:-
$json_data = file_get_contents('php://input');
$json_decode_data = json_decode($json_data);
file_put_contents('test.txt', $json_decode_data['links']['customer']['href']);
Nothing getting written in the txt file. How can I parse the href data?
json_decode() will produce a StdClass by default. If you want an array, add a true parameter. Then use the correct variable, being $data, when referencing it:
$data = json_decode(file_get_contents('php://input'), true);
To get data of the href, you need to do something like this
<?php
$data = json_decode(file_get_contents('test.txt'));
echo '<pre>';
print_r($data->links->customer->href);
?>

Displaying nested json in laravel 5.2

I have a nested json file
{
"event_type": "INCOMING_BTC",
"event_uid": "5515c5601f7b3",
"datetime": "2015-03-27 21:02:37",
"resources": [
{
"resource_type": "transaction",
"resource": {
"id": 105062,
"datetime": "2015-03-27 21:02:23",
"description": "Money from Xapo Tip",
"order_type": "payment_received",
"from": {
"type": "btc_address",
"id": "1AqF787aPHgPRZ81kdQSeEwW46yjyrAaxR"
},
"to": {
"destination_type": "btc_address",
"destination_id": "1N65Bz88zKUDPKhUUsx8f9Qwsuo96Hqz7S",
"to_account": 1276
},
"generic_type": "credit",
"amount": "0.0000001",
"currency": "BTC",
"status": "completed",
"txConfidence": 1,
"rejection_reason": null,
"notes": null,
"base_currency": "USD",
"exchange_rate": null,
"exchange_amount": null
}
},
{
"resource_type": "address",
"resource": {
"id": "1N65Bz88zKUDPKhUUsx8f9Qwsuo96Hqz7S",
"address": "1N65Bz88zKUDPKhUUsx8f9Qwsuo96Hqz7S",
"meta_data": null,
"label": null,
"total_received": "0.00000350",
"created_at": "2015-03-08 14:50:59",
"address_type": "multisig",
"id_account": "1276"
}
}
]
}
And I have saved this file in public folder with name xapojson.txt
In my routes file I have done json_decode to decode this data to a variable 'transaction' and passed it to view
Route::get('/', function () {
$transaction = json_decode(file_get_contents('xapojson.txt'));
return view('transaction', compact('transaction'));
});
Now in transaction view I have to display the data from this nested json.
I have tried out lots of variation and searched on google and stackoverflow but nothing worked.
I found this somewhat helpful Check this out. But it also do not get into more nesting.
In the view I have to display these datas:-
resources[0]->resource->from->type
resources[0]->resource->id
resources[0]->resource->from->id
resources[0]->resource->status
resources[0]->resource->amount
resources[0]->resource->currency
resources[0]->resource->to->destination_id
datetime
Please help me on displaying the above fields.
Try using
$transaction = json_decode(file_get_contents('xapojson.txt'), true);
Well when I made this code work in simple php, I extracted the data by
$xapo_json = file_get_contents('xapojson.txt');
$xapo_json_decoded = json_decode($xapo_json);
$from_type = $xapo_json_decoded->resources[0]->resource->from->type;
$transacid = $xapo_json_decoded->resources[0]->resource->id;
$from = $xapo_json_decoded->resources[0]->resource->from->id;
$status = $xapo_json_decoded->resources[0]->resource->status;
$amount = $xapo_json_decoded->resources[0]->resource->amount;
$currency = $xapo_json_decoded->resources[0]->resource->currency;
$to = $xapo_json_decoded->resources[0]->resource->to->destination_id;
$datetime = $xapo_json_decoded->datetime;
Then in the routes file i changed
return view('transaction', compact('transaction'));
to
return View::make('transaction')->with('transaction',$transaction);
And in view I used this
{{ $transaction->resources[0]->resource->from->id }}
Voila, It works
you can do it with the below code ( am taking div as example you can change it to table or whatever
#foreach($transaction->resources as $resource)
#if(is_set($resource->from))
<div>{{$resource->from->type}}</div>
#endif
<div>{{$resource->id}}</div>
#if(is_set($resource->from))
<div>{{$resource->from->id}}</div>
#endif
<div>{{$resource->status}}</div>
<div>{{$resource->amount}}</div>
<div>{{$resource->currency}}</div>
<div>{{$resource->to->destination_id}}</div>
#endforeach

zencoder notifications json

I'm working with some videos on PHP, using zencoder to encode the videos, save them on s3 and then notify my site back when it's all done.
Everything is working until I have to process the notifications returned as json and pull out the new url to the saved video.
this:
$notification = $zencoder->notifications->parseIncoming();
if($notification->job->state == "finished")
{
$encode_id=$notification->job->id;
}
works fine. I just need some pointers on accessing the url.
The notification is sent as:
{
"output": {
"frame_rate": 30.0,
"label": "video_id_",
"total_bitrate_in_kbps": 3115,
"md5_checksum": null,
"channels": "2",
"audio_codec": "aac",
"duration_in_ms": 4225,
"video_codec": "h264",
"url": "http://my_url/597bd3592bf4a9d70f04dc676c44de6d.mp4",
"thumbnails": [{
"label": null,
"images": [{
"url": "http://my_url/_key__0000.png",
"format": "PNG",
"dimensions": "640x360",
"file_size_bytes": 482422
}]
}],
"video_bitrate_in_kbps": 3052,
"width": 640,
"format": "mpeg4",
"height": 360,
"audio_sample_rate": 44100,
"state": "finished",
"audio_bitrate_in_kbps": 63,
"id": 41424918,
"file_size_in_bytes": 1625847
},
"input": {
"frame_rate": 30.0,
"total_bitrate_in_kbps": 3867,
"md5_checksum": null,
"channels": "2",
"audio_codec": "aac",
"duration_in_ms": 4167,
"video_codec": "h264",
"video_bitrate_in_kbps": 3764,
"width": 640,
"format": "mpeg4",
"height": 360,
"audio_sample_rate": 44100,
"state": "finished",
"audio_bitrate_in_kbps": 103,
"id": 22371764,
"file_size_in_bytes": 2028809
},
"job": {
"created_at": "2012-07-14T22:25:08Z",
"test": true,
"updated_at": "2012-07-14T22:25:47Z",
"submitted_at": "2012-07-14T22:25:08Z",
"pass_through": null,
"state": "finished",
"id": 22377083
}
}
but something like: $video_file=$notification->output->url; doesn't.
What am I missing?
If you don't want to use the parseIncoming method...
Use:
$notification = json_decode(trim(file_get_contents('php://input')), true);
as apposed to:
$notification = $zencoder->notifications->parseIncoming();
The second paramater of 'true' will format the results as an array as apposed to an object. From there, you can access all the values like:
$notification['output']['file_size_in_bytes'];
The parseIncoming method will return a stdClass, so referencing values within it is done with:
$notification->key

Categories