Stripe / Stripe.net invoice.payment_succeeded does not include Subscription details - c#

I am conducting a simple localhost test using stripe CLI.
When I execute the command:
stripe trigger invoice.payment_succeeded
My local webhook picks everything up perfectly and the test data they generate is sent to me. The only issue I have is when the code is deserialized:
if (stripeEvent.Type == "invoice.payment_succeeded")
{
Invoice successInvoice = (Invoice)stripeEvent.Data.Object;
...
The object stripeEvent (of type Invoice) does not have a subscription value for it, or a subscription id, for me to map back to what subscription the customer is under.
Sure, I can see the invoice amount, but I'd like to know more details now on this item.
I was reading something about how Stripe will send over a successful invoice charge but may not initially include subscription details on it, but that concerns me since I want to know the associated subscription.
Any ideas? Am I looking at the wrong webhook event?

Luckily I just figured it out - if you are testing using the CLI, you need to first create a subscription i.e.
stripe trigger customer.subscription.created
and then once you do this, if you then execute your payment
stripe trigger invoice.payment_succeeded
Doing it in this order will then ensure the ID comes in (but not the whole subscription object). but that's ok - you can fetch the whole subscription using the ID like so:
if (successInvoice.SubscriptionId != null)
{
var service = new SubscriptionService();
var subscription = service.Get(successInvoice.SubscriptionId);
if (subscription != null)
{
var plan = subscription.Plan; //do stuff with plan
}
}

The Invoice object definitely has a reference to the Subscription: https://stripe.com/docs/api/invoices/object?lang=dotnet#invoice_object-subscription
It's true that the webhook event that describes the Invoice won't contain many details on the Subscription, but you can then either retrieve the Subscription by using the aforementioned ID or retrieve the Invoice from the API whilst expanding the Subscription.

Related

How do you attach a Payment Method to a Payment Intent using the Stripe API

I've read a lot of documentation on "why" my Stripe payment intents are left in a status of "The Customer has not entered a payment method" and that "We recommend that you explicitly provide the payment_method going forward" however I can't tell how do that (provide the payment_method).
When I initialise the Payment Intent object I have "AutomaticPaymentMethods" enabled. I only have 1 payment method enabled in my Stripe Dashboard (cards).
(Also, I'm using Blazor with JS interop for this - if that is relevant...)
string customerId = await getCustomer(); // fetch existing customer from Stripe API based on current user or create a new one
Stripe.PaymentMethodService pms = new PaymentMethodService();
Stripe.PaymentIntentCreateOptions options = new PaymentIntentCreateOptions
{
Amount = p.UnitAmount,
Currency = p.Currency,
Customer = customerId,
ReceiptEmail = "test#malinator.com",
Description = "Test Purchase",
StatementDescriptor = "Test Purchase",
AutomaticPaymentMethods = new PaymentIntentAutomaticPaymentMethodsOptions
{
Enabled = true,
},
};
Stripe.PaymentIntentService pis = new Stripe.PaymentIntentService();
Stripe.PaymentIntent pi = pis.Create(options);
return pi;
The Payment Method is null on the resulting Payment Intent object.
It is still null after the payment details have been completed in the "payment-element" on my HTML form.
Is the payment_method something I can set up as the Payment Intent object is created (as I only wish to use "cards" at the moment anyway), or is it something I need to set in the confirm_payment JS call? (Either way, how to I obtain that Payment Method?)
Your code creates a PaymentIntent server-side for say $10 USD. This represents the "state machine" of an overall payment for the customer. They might never pay, or they might try to pay once and get a decline or a success, or they might get declined, try another card and see a success. Each "payment attempt" is represented in the API as a Charge object and the corresponding payment method details associated with that are represented as a PaymentMethod.
Now all of that "payment attempt" happens client-side where you collect payment method details and you use those to "confirm the PaymentIntent".
You mentioned you are using PaymentElement which is Stripe's newer UI library component to collect payment method details and accept a payment client-side. Since you only accept card payments, the PaymentElement would get initialized with your PaymentIntent's client_secret and render the card form to collect those card details.
What you need to do here is have a button to "pay" and when it's clicked, your Javascript code should call the confirmPayment() method from Stripe.js. Doing that will use the card details entered by the customer and attempt to confirm the PaymentIntent that is for a specific amount and currency. This payment might succeed, in which case the customer is redirected to your return_url, or it might be declined in which case the promise completes with error details you can handle to surface an error.
What you need to do here is look into your client-side code, ensure that you call confirmPayment() as expected and debug the response you get back to help narrow it down.
After the PaymentIntent is confirmed successfully and has status: 'succeeded' then it will have payment_method: 'pm_123' that is the id of the PaymentMethod object associated with the successful confirmation. All the information about that card would be on the successful Charge object associated with it inside payment_method_details.

Any downsides to replacing REST endpoints with SignalR?

I'm building a fairly simple single page app. It's basically a list of items, where each item has some details, an activity log, and a current status along with some buttons to trigger actions on the server to advance the status along a workflow.
It was originally written using MVC and REST/Web API but I got stuck on the problem of keeping concurrent users up to date. For example, if User A adds an item, we want the list on User B's screen to now update to include it.
To solve this I looked into SignalR which works great. But I had a problem.
When adding an item (using POST) the callback adds the item on the requesting client. This is fine.
I then triggered a SignalR broadcast on the server to tell all clients about the new item. This worked fine except the local client, who now has 2 items.
I was looking into filtering the duplicate id client-side, or sending the connection id with the POST, then broadcast to all clients except the requester but it seems a bit needlessly complicated.
Instead I'm just doing this.
public class UpdateHub : Hub
{
public void AddNewItem(NewItem item)
{
// and some server-side stuff, persist in the data store, etc
item.trackingID = new Guid();
item.addLogEntry("new item");
// ...
dataStore.addItem(item);
// send message type and data payload
Clients.All.broadcastMessage("add", item);
}
}
It seems a lot simpler to just get rid of all the REST stuff altogether, so am I missing anything important?
It'll run on an intranet for a handful of users using IE11+ and I guess we do lose some commonly-understood semantics around HTTP response codes for error handling, but I don't think that's a huge deal in this situation.
In order to solve duplicate you can try to use Clients.Others inside Hub class, or AllExcept(id) if you not in the Hub class.
Clients.Others.broadcastMessage("add", item);
In your case using SignalR shouldn`t have any downsides.

How to Update Account in StripeApi using C#?

I am trying to update Account in Stripe Api using Stripe.netlibrary ,using StripeAccountService and storing it in StripeAccountclass which i made by myself to store the result returned by API :
var accountService = new StripeAccountService("secretKey in string");
StripeRequestOptions option = new StripeRequestOptions();
option.StripeConnectAccountId = "AccountId to update";
StripeAccount x = accountService.Get(option);
x.Email = "Local#local.com";
//Then i do not know how to save changes back to api now.
But StripeAccountService class has no Update method define. How I can perform update on the Account.
I am using this library. Stripe api does have an update method too here.
Stripe.net does not support managed accounts: "Managed Accounts are a valuable service as well, but they are not available in Stripe.net yet." https://github.com/jaymedavis/stripe.net#stripe-connect
Stripe.net doesnot support Managed account but it can be done using following approach it is for update account.
I won't be able to give code but can provide the correct approach, it is tested.
https://api.stripe.com/v1/account
is the Url for updating stripe account.
Now you need to add two header and a body you can try WebRequest or httpclient class.
The reason i am unable to provide code because i did not do any research in adding multiple headers and a body.
so it would look something like this
Header
Property value
Authorization bearer "SecretKey"
Stripe-Account "acct_16uR8kKN01245679"
Body
Property value
email "test#test.com"
support_phone "555-867-5309"
You can see complete property list here. i picked few for demonstration purpose only.
Then save the response in any variable and it is done.

Contact presence/status on Lync 2013 SDK shows "Presence unknown" until manual client search

I'm working on an automation service for lync that will automatically add people to an IM conversation based on their availability/lync "presence". It essentially goes down a list, checks who is online, and adds the first person to a call.
The problem I'm getting is that sometimes (usually when lync had to be restarted), it does not always fetch the contact's presence.
First I just had it grab the presence. Then I added code to check for the ContactInformationChanged event firing, but that does not seem to happen unless I go into the app and manually type the alias I'm looking for.
Is there a Refresh() method I'm missing somewhere? Or is there any way to force it to find this? Here's my search methods:
public Contact GetContact(string emailAddress)
{
Contact user;
lock (ContactLookupCache)
{
while (!ContactLookupCache.TryGetValue(emailAddress.ToLower(), out user))
{
lock (Client)
{
Client.ContactManager.BeginSearch(emailAddress, this.HandleContactLookup, null);
}
Monitor.Wait(ContactLookupCache);
}
}
return user;
}
public string GetContactPresenceState(Contact contact)
{
string presenceStatus = contact.GetContactInformation(ContactInformationType.Activity).ToString();
// see if the status is either "Presence unknown" or "Updating..."
if (IsUnknownPresenceState(presenceStatus))
{
lock (contact)
{
//bug?? This event seems to only fire sometimes when you search on the app for contact details
contact.ContactInformationChanged += (object sender, ContactInformationChangedEventArgs e) =>
{
if (e.ChangedContactInformation.Contains(ContactInformationType.Activity))
{
lock (contact)
{
presenceStatus = contact.GetContactInformation(ContactInformationType.Activity).ToString();
if(!IsUnknownPresenceState(presenceStatus))
Monitor.PulseAll(contact);
}
}
};
Monitor.Wait(contact);
}
}
return presenceStatus;
}
Also, sorry for the crappy code... I was just trying to get it to work and kept throwing more junk code in hoping something would help.
Could you verify that the code works fine for all the contacts in your contact list and it's just the ones that aren't listed where presence change events aren't raised correctly?
This makes sense to me given you are using the client SDK which will only tell you about events the client is interested in. For example it would be pretty traffic intensive if all 85,000 clients received the presence changes for the other 85,000 clients in a company.
I think you are in the realms of either polling the presence at regular intervals or adding the contacts to the client (perhaps under a relevant group just to keep things tidy).
Failing that you may want to looking into the UCMA SDK which is better suited to centralised services than the client SDK.

Magento: Getting the transaction ID via soap

i recently tried to connect to a magento webshop via magentos SOAPv2 adapter.
Sharpdevelop did generate some c# wrappers getting the WSDL.
I could login and query orders, but when it comes to payment methods I was wondering why there's no way to get the transaction ID.
Here's what I tried:
salesOrderEntity ent = ms.salesOrderInfo(mlogin,"<my_order_id>");
The salesOrderEntity class contains a salesOrderPaymentEntity which should contain an attribute last_trans_id, but it doesn't.
Does anyone have an idea where to get the transaction ID from payment information? I didn't even find a reference to last_trans_id in the proxy code generated by sharpdevelop.
Thanks in advance for any suggestions.
-chris-
After some time i took up this question again and found a solution in my case.
A salesOrderEntity contains a list of salesOrderStatusHistoryEntity objects.
And those contain a field named 'comment' where in my case the Transaction IDs can by found in a textual way like
Transaction ID:"800736757864..."
This helped me.
Chris the OP has answered the question, but just to add some extra value to this Q&A here's the code I've got working.
As some background, the reason I am using Transaction IDs at all is because they are used by Paypal. I'm writing a cron job that pulls the Paypal orders from the Paypal API for the previous 24 hours, then we pull all orders from Magento via SOAP for the previous 24 hours, get the transaction IDs and match them to the Paypal list. It's to make sure there are no Paypal orders which are not on Magento, occasionally we get an IPN failure which prevents Magento quotes being converted to orders and the customer gets billed by Paypal but no product is shipped to them as the order is never created. If there's a mismatch an email alert is sent to customer services.
$startDate = gmdate('Y-m-d H:i:s', strtotime('-1 day', time()));
$complex_params =array(
array('key'=>'created_at','value'=>array('key' =>'from','value' => $startDate))
);
$result = $client_v2->salesOrderList($session_id, array('complex_filter' => $complex_params));
// We've got all the orders, now we need to run through them and get the transaction id from the order info
// We create an array just to hold the transaction Ids
$ikoTransactionIds = array();
foreach ($result as $invoice) {
$invoiceInfo = $client_v2->salesOrderInfo($session_id, $invoice->increment_id);
$history = $invoiceInfo->status_history;
$comments = $history[0]->comment;
// Only the Paypal based records have transaction Ids in the comments, orders placed via credit card do not. In these cases $comments are null
if ($comments) {
// Check if the text 'Transaction ID:' exists at all
if ((strpos($comments, "Transaction ID:")) !== FALSE) {
list($before, $transactionId) = explode('Transaction ID: ', $comments);
// Remove the trailing period
$transactionId = rtrim($transactionId ,".");
// Remove the quotes
$transactionId = str_replace('"', '', $transactionId);
// We add the id to our array of ids for this Magento install
$ikoTransactionIds[] = $transactionId;
}
}
}

Categories