I've setup Stripe so that customers can manage their subscription through Stripe's customer portal.
In order to keep my app in sync with Stripe, I've created a web hook to handle customer.subscription.updated events. The idea is to simply get the price/plan the customer has changed to and then update a column in the Db to reflect that.
The problem however, is that when a customer makes the change via the portal. My webhook receives 2 subscription updated events. One containing a subscription object holding the old plan/price info, and the other containing a subscription with the new plan and price data.
How would I go about distinguishing which event is for the old price/plan and which is for the new so that I can ignore the old one and only update the db field using the new price/plan?
Event object for old subscription price/plan: https://pastebin.com/NA2KPh90
Event object for new subscription price/plan: https://pastebin.com/qF9g1wDs
Related
I have an event hub trigger function linked to an event hub and I have set it up to receive events. The receive message works fine, and I am able to process the message when it is fired from the source, but recently I have started noticing duplicate events getting processed at the receiver.
How do I determine if these are unique events, with possibly the same payload or the same event processed multiple times? I have read about partition Ids, but seems like that only tells us which partition the message was picked up from. It is very possible that both the messages were picked up from the same partition at interval of some time.
My event hub trigger implementation looks something like follows:
[FunctionName("function-name")]
public async Task RunAsync(
[EventHubTrigger("az_eventhubname",
Connection = "connection-string-path", ConsumerGroup = "%AzureEventHubConsumerName%")] EventData ed,
ExecutionContext eCtx, PartitionContext PartitionContext)
{
var messageBody = Encoding.UTF8.GetString((ed).Body);
// other tasks ...
}
I am able to bind both ExecutionContext and PartitionContext but none of them provide a message id or event id property, neither does EventData
EventData provides only Sequence Number, Offset and Enque Time, in its SystemProperties.
PartitionContext provides the partiton id and other info such as host id, offset, epoch, token, etc.
ExecutionContext provides an invocation id
If Event Hub Triggers do not provide message ids or event ids, how can I distinguish between 2 messages having the same payload?
There is no strong concept of an event identity within Event Hubs; the responsibility of defining what makes an event unique falls to the application. The closest approximation using just the Event Hubs service data would be the combination of the sequence number assigned to the event and the partition that it was read from.
Generally, it is encouraged that publishers and consumers coordinate on an item set in the Properties dictionary that is meaningful within the application context to identify the data.
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.
I have implemented a plugin for my Dynamics CRM which is firing on Update message for incident entity.
Also I have a web service for external users which can update just two attributes of incident entity from outside.
The problem is while external users use the web service to update entity, the plugin will fire also.
I want to bind the plugin going to be fired just inside CRM when incident entity changed and prevent it firing by outside requests.
I checked below conditions in my plugin for preventing infinite loop and it works but not works for preventing firing by outside update requests.
if (context.Depth > 1 ||
context.Mode != 1 ||
context.MessageName != "Update" ||
context.IsolationMode != 1)
{
return;
}
To register plugin I've used the Plugin Registration Tool and I have set the step message to Update, and Run in User's Context as Calling User.
In my web service I've used Xrm.Sdk and Xrm.Sdk.Client to connect to CRM and update entity directly.
ColumnSet cs = new ColumnSet(new string[] {
"description", "statuscode"
});
Guid recordId = new Guid(caseID);
Entity currentRecord = crmService.Retrieve("incident", recordId, cs);
OptionSetValue osv = new OptionSetValue(1);
currentRecord["statuscode"] = osv;
currentRecord["new_answers"] = answer;
currentRecord["new_lastanswerdate"] = currentDate;
crmService.Update(currentRecord);
Anyone has any idea - How can I prevent plugin firing while an entity updated from outside of CRM?
The plugin executes in every server transaction & it gets triggered which is the expected behavior (that's the whole purpose).
You may use some other flag (additional attribute or any service account) which only get updated/used by outside integration, in that case you can check in execution context/target entity and ignore the further execution.
For external integration - you should create an Application user (non-interactive service account). Read more
I know it is a very old question, but there is a property of CrmServiceClient that allows you to bypass custom plugins from executing
You can find more details here CrmServiceClient - BypassPluginExecution
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.
When every I attempt to add a new server callback function I cannot seem to get the callback to show up in the $.connection server callback list.
What do I need to do to refresh the javascript that SignalR produces and sends to the client with the latest list of server callbacks.
I would think that I should be able to just add a server callback for the client to call and rebuild my app and fire up a new instance of Google Chrome and the newly added server callback would be in the list of available callbacks on the client.
For example here is exactly what I've done.
1.) A client joins a group and everyone is notified.
public override Task OnConnected()
{
string pid = this.Context.QueryString["pid"],
uid = this.Context.QueryString["uid"],
ispro = this.Context.QueryString["ispro"];
Groups.Add(this.Context.ConnectionId, pid);
return Clients.Group(pid).joined(new cmsg(Context.ConnectionId, UtilCommon.GetUserMini(new Guid(uid), bool.Parse(ispro))));
}
2.) On the client the joined function is called from the server
this.collaborateHub.client.joined = function (cmsg) {
//
that.chatBox.addAttendee(cmsg);
//let the new attendee know about you
if (cmsg.cnnid !== that.chatBox.getMeAttendee().cnnid) {
that.chatBox.getMeAttendee().newbieid = cmsg.cnnid;
debugger
this.server.addMeNewbie(that.chatBox.getMeAttendee());
};
};
3.) Now, if someone joined and it was not the user of the currently opened window, that means the someone how just joined is someone other than myself, so I need to call the server back and notify the newly joined user to add me to their user list. I stead of having to keep up with the currently signed on users to the given group in a database, I am just using every signed on client of the group as a distributed database and let them manage their own info.
So, I need to call the server callback named addMeNewbie; however, this callback function is not available in the list.
public Task addMeNewbie(cmsg cmsg) {
return Clients.Client(cmsg.newbieid).addCurrAttendee(cmsg);
}
Here is a snapshot of the client side in debug mode
4.) And finally here is the client side callback that i need the server to call so that the newly joined group member can update their list of current group members.
this.collaborateHub.client.addCurrAttendee = function (cmsg) {
debugger
that.chatBox.addAttendee(cmsg);
};
I would think that I should be able to add as many server callbacks as I want and they should show up on the next build and restart of a new instance of Google Chrome; however, this is not the case. What do I need to do to get newly added server callbacks to show up in the available server callbacks on the client side?
This doesn't make since to me, but I am thinking maybe this is a cashing issue or something?
The only callback that is available is the one shown in the snapshot provided. At this time I've only got two callbacks, the one that you see in the snapshot and the one that is not visible.
Somewhere along the way I created a signalr-hubs.js file from the generated JavaScript file that can be retrieved by http://localhost:3250/signalr/hubs and was adding new server functions to my hub but not updating the signalr-hugs.js file.
At this point every time I add a new server callback I retrieve the newly generated proxy by placing this url http://localhost:3250/signalr/hubs into the browser, coping the code, and then updating my signalr-hubs.js file.