dmjio / stripe

:moneybag: Stripe API
http://hackage.haskell.org/package/stripe-haskell
177 stars 74 forks source link

get total number of charges #72

Closed legrostdg closed 7 years ago

legrostdg commented 7 years ago

I need to get the total number of paid charges, and the total number of refunded charges. With curl, I can do:

curl 'https://api.stripe.com/v1/charges?paid=true&limit=0&include\[\]=total_count' -u sk_test_mykey:
curl 'https://api.stripe.com/v1/charges?refunded=true&limit=0&include\[\]=total_count' -u sk_test_mykey:

I don't get how to get this with stripe-haskell, though: it always returns totalCount = Nothing

dmjio commented 7 years ago

If you run this code with your secret key, does it return a list of charges?

{-# LANGUAGE OverloadedStrings #-}
import Web.Stripe
import Web.Stripe.Charge

main :: IO ()
main = do
  let config = StripeConfig (StripeKey "secret_key")
  print =<< stripe config getCharges

If so, can you filter by chargePaid and chargeRefunded ?

dmjio commented 7 years ago

I assume you want to specify a customer as well, so you'll need to do:

print =<< stripe config (getCharges -&- CustomerId "customer-id")
legrostdg commented 7 years ago

I'm not sure you understood what I meant: what I want is the total number of all charges (charges paid and charges refunded, but that's a detail). stripe config (getCharges -&- Limit 0) returns:

    Right (StripeList {list = [Charge {chargeId = ChargeId "ch_1ARl4RLcbELZNEfI00NB1Wic", chargeObject = "charge", chargeCreated = 2017-06-06 17:02:19 UTC, chargeLiveMode = False, chargePaid = True, chargeAmount = Amount {getAmount = 2000}, chargeCurrency = EUR, chargeRefunded = False, chargeCreditCard = Card {cardId = CardId "card_1ARl4PLcbELZNEfIp38DUhsT", cardObject = "card", cardLastFour = "4242", cardBrand = Visa, cardFunding = "credit", cardExpMonth = ExpMonth 12, cardExpYear = ExpYear 2019, cardFingerprint = "KyHOC6VwLSLSstF9", cardCountry = "US", cardName = Nothing, cardAddressLine1 = Nothing, cardAddressLine2 = Nothing, cardAddressCity = Nothing, cardAddressState = Nothing, cardAddressZip = Nothing, cardAddressCountry = Nothing, cardCVCCheck = Just "pass", cardAddressLine1Check = Nothing, cardAddressZipCheck = Nothing, cardCustomerId = Nothing}, chargeCaptured = True, chargeRefunds = StripeList {list = [], stripeUrl = "/v1/charges/ch_1ARl4RLcbELZNEfI00NB1Wic/refunds", object = "list", totalCount = Just 0, hasMore = False}, chargeBalanceTransaction = Just (Id (TransactionId "txn_1ARl4RLcbELZNEfID1uctHHz")), chargeFailureMessage = Nothing, chargeFailureCode = Nothing, chargeAmountRefunded = 0, chargeCustomerId = Nothing, chargeInvoice = Nothing, chargeDescription = Just (Description "Test"), chargeDispute = Nothing, chargeMetaData = MetaData [("postalcode","12345"),("address","123 Balba Street"),("gift","apples"),("city","Mexico")], chargeStatementDescription = Nothing, chargeReceiptEmail = Just "mexico@example.com", chargeReceiptNumber = Nothing}], stripeUrl = "/v1/charges", object = "list", totalCount = Nothing, hasMore = True})

(note the totalCount = Nothing at the end), while curl 'https://api.stripe.com/v1/charges?limit=0&include\[\]=total_count' -u sk_secretkey returns

{
  "object": "list",
  "data": [
    {
      "id": "ch_1ARl4RLcbELZNEfI00NB1Wic",
      "object": "charge",
      "amount": 2000,
      "amount_refunded": 0,
      "application": null,
      "application_fee": null,
      "balance_transaction": "txn_1ARl4RLcbELZNEfID1uctHHz",
      "captured": true,
      "created": 1496768539,
      "currency": "eur",
      "customer": null,
      "description": "Test",
      "destination": null,
      "dispute": null,
      "failure_code": null,
      "failure_message": null,
      "fraud_details": {},
      "invoice": null,
      "livemode": false,
      "metadata": {
        "address": "123 Balba Street",
        "postalcode": "12345",
        "city": "Mexico",
        "gift": "apples"
      },
      "on_behalf_of": null,
      "order": null,
      "outcome": {
        "network_status": "approved_by_network",
        "reason": null,
        "risk_level": "normal",
        "seller_message": "Payment complete.",
        "type": "authorized"
      },
      "paid": true,
      "receipt_email": "mexico@example.com",
      "receipt_number": null,
      "refunded": false,
      "refunds": {
        "object": "list",
        "data": [],
        "has_more": false,
        "total_count": 0,
        "url": "/v1/charges/ch_1ARl4RLcbELZNEfI00NB1Wic/refunds"
      },
      "review": null,
      "shipping": null,
      "source": {
        "id": "card_1ARl4PLcbELZNEfIp38DUhsT",
        "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": "Visa",
        "country": "US",
        "customer": null,
        "cvc_check": "pass",
        "dynamic_last4": null,
        "exp_month": 12,
        "exp_year": 2019,
        "fingerprint": "KyHOC6VwLSLSstF9",
        "funding": "credit",
        "last4": "4242",
        "metadata": {},
        "name": null,
        "tokenization_method": null
      },
      "source_transfer": null,
      "statement_descriptor": null,
      "status": "succeeded",
      "transfer_group": null
    }
  ],
  "has_more": true,
  "total_count": 28,
  "url": "/v1/charges"
}

"total_count": 28

I can't get all the charges and print the list length, as the API limits this number to 100 (and it would be a total waste of bandwidth).

dmjio commented 7 years ago

@legrostdg, I understand now.

Per the wayback machine (to verify w/ the 2014 API version we use), it seems like this is possible.

You can optionally request that the response include the total count of all charges that match your filters. To do so, specify include[]=total_count in your request.

https://web.archive.org/web/20141129193408/https://stripe.com/docs/api#list_charges

After looking at the code, it doesn't seem like we've added this case when constructing the query parameters. But since the param API is extensible (thanks to @stepcut) it might be possible to add include[]=total_count

@legrostdg. Can you try this? Note, I haven't tested this code.

{-# LANGUAGE OverloadedStrings         #-}                                                                                                     
{-# LANGUAGE MultiParamTypeClasses     #-}                                                                                                     
import Web.Stripe                                                                                                                              
import Web.Stripe.Charge                                                                                                                       

main :: IO ()                                                                                                                                  
main = do                                                                                                                                      
  let config = StripeConfig (StripeKey "secret_key")                                                                                           
  print =<< stripe config (getCharges -&- TotalCount)                                                                                          

data TotalCount = TotalCount                                                                                                                   

instance ToStripeParam TotalCount where                                                                                                        
  toStripeParam TotalCount xs = ("include[]", "total_count") : xs                                                                                                          

instance StripeHasParam GetCharges TotalCount 
legrostdg commented 7 years ago

Oh, great, I didn't notice how easy it is to extend the API! I guess I can manage my usecase now, with your TotalCount and with new ChargePaid & ChargeRefunded. This may be a nice addition to stripe-haskell... Do you want me to submit a pull request for this?

Thanks a lot for this and for having checked the availability of include[]=total_count in the API version.

dmjio commented 7 years ago

@legrostdg, No problem, glad it's working. If you created a PR for this, I would gladly accept it. From those API docs, it seems the endpoints that support include[]=total_count are the following:

Should help guide which instances need to be defined.

dmjio commented 7 years ago

@legrostdg, marking as resolved, therefore closing. Please let me know if I should keep open.