I've recently switched payment processing to Stripe. I now need to create a report for our finance department that shows a rollup of transactions within a specified date range. I've started to create a simple PHP web page (and using the Stripe PHP library) that will give the following summaries:
Transaction Count
Transaction Amount
Refund Count
Refund Amount
Fees
Net
I'm having some trouble figuring out how to properly query charges with Stripe for my reporting purposes.
I know I can retrieve charges with:
$charges = Stripe_Charge::all();
And from the returned set of charges, I can compute the summary information that I need in the report. However, this will only return me a maximum of 100 charges, and I don't know how to return the charges within a specified date range.
I'm hoping more experienced Stripe developers can point me to the correct method of building the report I need.
How can I return all charges within a specified date range?
Is there a better way to get this summary information from Stripe?
You could use webhooks to be notified when a charge.succeeded or charge.refunded event occurs and store the relevant information in a database you control. That will give you flexibility to do the reporting you need. You can download charges that have already occurred as a CSV from the Stripe dashboard.
You can paginate through the charges by using the count and offset parameters (documented at https://stripe.com/docs/api?lang=php#list_charges). I would suggest using these to process 100 charges at a time. Then you can stop iterating through your charges once you get a charge beyond your date range.
I received confirmation from a Stripe employee that the only two options are in fact the ones described in the answers from #dwhalen and #Saikat Chakrabarti.
Quoting from the Stripe employee to the same question I asked on Stripe:
Other than the options you described (retrieving all charges, or
tracking in your database as charges come in) there isn't any
alternative way of producing the stats that you want there.
Realize this is old-ish, but.. this is now possible, a php example:
$charges=Stripe_Charge::all(array("created" => array("gt" => $unix_time),"limit" => 100));
You can use offset like
$return = Stripe_Charge::all(array("count" => 100, 'offset' => 0)); // set count
$return = Stripe_Charge::all(array("count" => 100, 'offset' => 100)); // set count
$return = Stripe_Charge::all(array("count" => 100, 'offset' => 200)); // set count
Related
I'm creating a stripe subscription with the following code:
$subscription = $stripe->subscriptions->create([
'customer' => {{CUSTOMER ID}},
'items' => [
[
'price' => $price->id,
'quantity' => $quantity,
],
],
'default_source' => $card,
'billing_cycle_anchor'=> $time,
'proration_behavior' => 'create_prorations',
'transfer_data' => [
'destination'=>{{DESTINATION ID}}
]
]);
Everything works out fine, but there is an issue. The fees fall on the platform's side and here's the dilemma through a realistic outcome:
Customer is charged 0.40 cents. Stripe's fee is 2.9% + 30 cents (.31 cents) and the platform we operate takes 2.5% (.01 cents). As the fee falls on us as the platform, we don't have the money because of the percentage we take. So the solution is to "charge" the connected account for both our take and the credit card processing fee (meaning 2.5% + 2.9% + 30 cents).
The issue here is that we can't use the application_fee_percent because that's purely a percentage (it will ignore the 30 cents - plus this can't be calculated from a percentage basis because prorations are enabled).
I have tried listening to the webhook of invoice.created so that I can calculate the application_fee_amount dynamically but it says "Cannot change finalized invoice." So the question becomes, what's the proper flow here? What am I missing to fix this issue we're having?
Invoices created for less than the minimum amount for the currency do not actually make a charge, and instead just affect the Customer Balance: https://stripe.com/docs/billing/customer/balance#examples
Ok, so I figured it out.
As per the documentation here: https://stripe.com/docs/billing/invoices/subscription
This explains that the first invoice on creating the subscription is created and finalized immediately (you cannot change it), while the next invoice in the billing cycle sits in "draft" for an hour. During that time, you can modify that invoice however you please during that hour. This means I have to figure out a different approach to gathering fees.
While trying to place an order, I'm receiving the following error:
Code: -2010 Account has insufficient balance for requested action
I'm requesting the POST endpoint https://api.binance.com/api/v3/order with the following parameters:
$params =
[
'symbol' => 'BTCUSDT',
'side' => 'BUY',
'type' => 'MARKET',
'quoteOrderQty' => 375.00,
'timestamp' => $timestamp,
];
And I just deposit 400$, which means I have enough funds to purchase 375$ worth of BTC.
What am I missing?
I have had this before numerous times and this is why it happens.
Say you have 0.007821 worth of BTC in your Binance Wallet. And you are trying to place a SELL order. Now, if you end up rounding your quantity to say 4 decimal places, your code would try and SELL 0.0079 BTC. This is obviously more than what you have in your Exchange Wallet. This will cause the "Account has insufficient balance for requested action" error.
Solution: Simply match or reduce the amount in your code that you are trying to SELL to match the amount in your exchange Wallet. So, in this case, try and use the correct rounding decimal places or try to SELL 0.0078 worth of BTC.
I suggest you find your money and convert it to USDT if you want. Check this page using your browser https://binance.com/en/my/wallet/account/main and find what currency do you have now. Keep in mind that USD != USDT
The other option is to make sure you have enough BNB in your account to pay for the fees:
https://dev.binance.vision/t/account-has-insufficient-balance-for-requested-action/2718/6
It is because you are trying to buy 375.00 bitcoin.
quoteOrderQty must reference to the amount of symbol you want to buy.
if you want to buy btc for a percentage of your total money you should use this formula: (YourTotalMoney / CurrentPrice) * (Percentage / 100)
Example: I want to buy BTC using 50% of my USDT
Quantity = (getBalanceUSDT() / getCurrentPriceBTC()) * (50 / 100)
getBalanceUSDT() and getCurrentPriceBTC() are functions you will have to create
Now you can use Quantity for the quoteOrderQty param.
There is a really serious issue about Double Entry Accounting systems with pagination, I think it is common but I still didn't find any solution for my problem yet.
You can use this link to read about the simple Double Entry Accounting systems just like the one I made with Laravel and AngularJS.
In this system, the expected result (for example) is something like this:
ID In Out Balance
1 100.00 0.00 100.00
2 10.00 0.00 110.00
3 0.00 70.00 40.00
4 5.00 0.00 45.00
5 0.00 60.00 -15.00
6 20.00 0.00 5.00
It is very easy to track the balance inside a cumulative function if you were showing all the transactions in one page, the balance in the last transaction is your current balance at the end of the day.
For example, for a specific range of dates $fromDate->$toDate, we do like:
$balanceYesterday = DB::table('journal')->where('date', '<', $fromDate)
->join('transactions','transactions.journal_id','journal.id')->where('transactions.type', "=", 0) /* 0 means the account of the company */
->select(DB::raw('SUM(amount) as total_balance'))
->first()->total_balance;
Now we have balance from yesterday, we depend on it to calculate the balance after that in a cumulative loop until the end of the process, reaching $toDate;
$currentBalance = $currentBalance + $currentTransaction->amount;
$currentTransactionBalance = $currentBalance;
Now the real problem starts when you have a big amount of transactions, and you need to paginate them $journal = $journal->paginate(100);, let's say 100 transactions per page, the system will work as expected for the first page, as we already can calculate the $balanceYesterday and depend on it to calculate the new balance after every transaction to the end of the 100 transactions in the first page.
Next page will have the problem that it doesn't know what was the last balance at the previous transaction in the first page, so it will start again from $balanceYesterday, making the whole table have wrong calculations.
What I did first to fix, was transferring the last transaction amount (in front-end) to the next page as a parameter, and use it as a starting amount to calculate again, and that was the best solution I had as I was using only << PREV and NEXT >> buttons, so it was very easy to fix it like that.
But I lately found out that this workaround will not work if I have a pagination with page numbers, as the user would like to go through pages to explore the journal, now it is impossible to know the last balance at a specific page, and the system will show wrong calculations.
What I am trying to do is finding a way to calculate the balance at a specific transaction, weather it was a credit or debit, I'm looking for a way to know how much the balance was after a specific transaction is done in a specific date, I DON'T WANT TO ADD A NEW BALANCE COLUMN AND SAVE THE BALANCE INSIDE IT, THE USER IS DOING A LOT OF MODIFICATIONS AND EDITS TO THE TRANSACTIONS FROM TIME TO TIME AND THAT WILL BREAK EVERYTHING AS A SMALL AMOUNT MODIFICATION WILL AFFECT ALL THE BALANCES AFTER IT, I CAN NOT depend on IDs of transactions in any method because transactions might have different random dates, so there will be no ordering by ID but there might be ordering by other fields like date or account owner or type or whatever..
I've been scratching my head on this for about 4 months, I searched online and found no solutions, I hope after this long explanation that my problem is clear, and I hope somebody can help me with a solution, please..
Thank you.
I believe the only thing you really need at this point is to calculate the sum of all transactions from the beginning of the paginated data set (all records, not just the current page's) until one before the first record displayed on the current page.
You can get this by finding the number of transactions that occurred between the start of your entire data set and the current page's transactions, retrieving them via LIMIT, and adding them up.
The first thing you'll want to have is the exact constraints of your pagination query. Since we want to grab another subset of paginated records besides the current page, you want to be sure the results of both queries are in the same order. Reusing the query builder object can help (adjust to match your actual pagination query):
$baseQuery = DB::table('journal')
->join('transactions', 'transactions.journal_id', 'journal.id')
->where('date', '>', $fromDate)
->where('date', '<', $toDate)
->where('transactions.type', "=", 0)
->orderBy('date', 'asc');
// Note that we aren't fetching anything here yet.
Then, fetch the paginated result set. This will perform two queries: one for the total count of records, and a second for the specific page's transactions.
$paginatedTransactions = $baseQuery->paginate(100);
From here, we can determine what records we need to retrieve the previous balance for. The pagination object returned is an instance of LengthAwarePaginator, which knows how many records in total, the number of pages, what current page its on, etc.
Using that information, we just do some math to grab the number of records we need:
total records needed = (current page - 1) * records per page
Assuming the user is on page 5, they will see records 401 - 500, so we need to retrieve the previous 400 records.
// If we're on Page 1, or there are not enough records to
// paginate, we don't need to calculate anything.
if ($paginatedTransactions->onFirstPage() || ! $paginatedTransactions->hasPages()) {
// Don't need to calculate a previous balance. Exit early here!
}
// Use helper methods from the Paginator to calculate
// the number of previous transactions.
$limit = ($paginatedTransactions->currentPage() - 1) * $paginatedTransactions->perPage();
Now that we have the number of transactions that occurred within our data set but before the current page, we can retrieve and calculate the sum by again utilizing the base query:
$previousBalance = $baseQuery->limit($limit)->sum('amount');
Adding a highlight here to explain that using your database to perform the SUM calculations will be a big performance benefit, rather than doing it in a loop in PHP. Take advantage of the DB as often as you can!
Add this balance to your original "yesterday" balance, and you should have an accurate beginning balance for the paginated transactions.
Note: everything pseudo-coded from theory, may need adjustments. Happy to revise if there are questions or issues.
You should be able to formulate a truth statement for the balance for each record as long as you can tell what the order is to calculate the sum for the balance at each point within that ordered list.
For sure this come with a massive overhead as you need to query the whole table for each record you display, but first of all one must be able to do that. As you've shown in the example, you are as long as you do not paginate.
What you could do for pagination is to pre-calculate the balance for each record and store it in relation to the original record. This would de-normalize your data but with the benefit that creating the pagination is rather straight forward.
Here is what i am trying to do. Total is $120
1 : First i did a Partial Refund with this charge ID ch_1AfNOwAWa9KSz110***** .
\Stripe\Refund::create(array(
"charge" => 'ch_1AfNOwAWa9KSz*******',
"amount" => 60 * 100,
));
2 : After that i want to refund full the amount that left in this chargeID ch_1AfNOwAWa9KSz110*********
\Stripe\Refund::create(array(
"charge" => 'ch_1AfNOwAWa9KSz1********'
));
I am getting error Charge ch_1AfNOwAWa9KSz110********* has already been refunded.
What should i do first i did partial and after full refund in stripe.?
According to the docs:
You can optionally refund only part of a charge. You can do so
multiple times, until the entire charge has been refunded.
So it seems you can create a refund without an amount (a full refund) only if you have not refunded already (partially), otherwise you need to specify the amount explicitly.
It would be great, though, if Stripe accepted refunding without an amount specified even after a partial refund, meaning to refund the remaining amount.
Based on the docs, I think you want to use the update refund endpoint instead of the create refund endpoint for the second call.
I've inherited a PHP application that accesses v2.3 of the Facebook Marketing API to get daily spend (and other info) per ad. I'm upgrading it to v2.5. I'd like to be able to specify a date and get the insights for that ad for that date. I've tried specifying date_range with a time_increment of 1, but I get only one result set back which seems to contain the totals to date, even if I use a 'since' and 'until' of a single historic date.
function getAds($campaign_id, $time_start, $time_end){
$params = array(
'fields'=>array('id', 'effective_status', 'name'),
'include_deleted'=>true,
'time_increment'=>1,
'time_range'=>array("since"=>$time_start,"until"=>$time_end));
$resp = $this->api->call("/{$campaign_id}/ads/",FacebookAds\Http\RequestInterface::METHOD_GET,$params);
return $resp->getContent();
}
Any pointers as to what I may be doing wrong?
Turns out I was accessing the wrong edge! I needed to access "/{$ad_id}/insights/" with the time_range and time_increment fields. The data is then returned in a array grouped by 1 day increments.