I was asked to increase the amount of all plan in Stripe. So I wrote the following script in ruby to delete old plan and create new plan with the same id with different amount:
for stripe_plan in Stripe::Plan.list
new_amount = (stripe_plan.amount*1.1).floor
Stripe::Plan.delete(stripe_plan.id)
new_stripe_plan = Stripe::Plan.create(
nickname: stripe_plan.nickname,
amount: new_amount,
interval: stripe_plan.interval,
currency: stripe_plan.currency,
product: stripe_plan.product
)
The problem is if one fails (most likely not), it might result in some plans are updated and others are not, which is not consistent.
The question is: Is there any transaction method to rollback Stripe create, update, delete when it fails?
If this is not a question for stackoverflow, please comment, I will delete this.
Instead of modifying the price of existing plans, you should create new plans with the updated cost, then assign them to the appropriate users. This will allow you to simply check if any users are on old plans if something were to go wrong.
Related
For about a year now, I've been running a social iOS app on a parse server with thousands of users. All my data are stored in a MongoDB. The thing is, the structure of my database has to be improved. For example, the current "Following" system has to be changed in a way that it is gonna be completely different.
My question is, what is the best practise of making that change, considering that not all of my users are going to do the update? How can I be sure that there will be no confusion with the data between the old and the new users?
Edit:
Current Following system:
Here, every time I follow someone, I find the "user" and I append my userId, to his "followers" array...
|objectId <String>| -- |createdAt <Date>| -- |user <Pointer _User>| -- |followers <Array>|
New Following system:
Here, every time I follow someone, I create a new object, where "following" is the current user and "follower", is the user I just followed...
|objectId <String>| -- |createdAt <Date>| -- |following <Pointer _User>| -- |follower <Pointer _User>|
I'm aware of the customer.subscriptions.trial_will_end event. It fires 3 days before a trial ends.
I couldn't find an event that actually fires when the trial is over and the customer hasn't paid. This would be useful to do something simple like this to turn off features:
customer.update_attributes(active_account: false)
Without a webhook like that, I'm looking at scheduling some tasks to check unconfirmed customers periodically and turn off features accordingly. The webhook seems cleaner though and less prone to errors on my side. Is there an event/webhook in line with these goals? FYI, customers don't have to put in a card when they start the trial - so autobilling is not an option.
When the trial period ends, there will be a customer.subscription.updated event and an invoice.created event. An hour (or so) later, you'll then either see an invoice.payment_succeeded event or an invoice.payment_failed event. From those, you'll know whether the payment went through or not.
Cheers,
Larry
PS I work on Support at Stripe.
To add to Larry's answer and share how I got around the lack of a trial ended webhook, here's what I did.
In invoice.payment_failed webhook, I checked:
Is this the first invoice since the subscription start?
Does the customer have any cards saved?
If these checks fail, then I assume the trial has just ended with no billing details entered, and I cancel the subscription.
Example in Python:
# get account from my database
account = models.account.get_one({ 'stripe.id': invoice['customer'] })
# get stripe customer and subscription
customer = stripe.Customer.retrieve(account['stripe']['id'])
subscription = customer.subscriptions.retrieve(account['stripe']['subscription']['id'])
# perform checks
cards_count = customer['sources']['total_count']
now = datetime.fromtimestamp(int(invoice['date']))
trial_start = datetime.fromtimestamp(int(subscription['start']))
days_since = (now - trial_start).days
# cancel if 14 days since subscription start and no billing details added
if days_since == 14 and cards_count < 1:
subscription.delete()
Just add 3 days to the free trial period and use the customer.subscriptions.trial_will_end event and update the subscription with 'trial_end=now'
I think there is another way that can be handled easly. So invoice.payment_failed should be listened, in all invoice related events, inside event.data.object, there is subscription id or subscription object, you should get subscription id and retrieve subscription then you can get both product id and price id.
By price id or by product id you can know current subscription.
I need to allow less-privileged users to propose changes to a record but have them sit somewhere until an administrator approves them. It should be similar to the way Stack Overflow allows users with lower reputation to propose an edit to a question or answer which must be reviewed by someone with higher reputation.
In papertrail terms, I'd like to allow users to create versions of a record without actually committing those changes to the record itself—future versions, rather than past versions. Then I'd like to allow another user to "revert" ("prevert"?) to the new version.
Is this something papertrail supports? Or is there another gem that can do this?
I know that this question is very old but let me explain how I managed to solve it:
Suppose that I have a model Post, two users: A and B, that A is authorized to update posts but he needs B approval before committing the changes, B is the monitor who can approve updates and can update posts as well.
I added a method to revert the record to a particular version of it so we can update it with whatever version we want:
def revert_to(version)
raise 'not version of this model' unless self == version.item
changes = version.changeset.select{ |k, v| not SKIP_FIELDS.include?(k) }.map{ |k,v| [k.to_sym, v[1]] }.to_h
self.update_attributes(changes)
end
I got that method from this Stackoverflow answer but I modified it a bit.
The trick is to not update the record itself if the current user A hasn't authorized to commit changing, rather than updating, a new Paper Trail version will be created, then the monitor B can accept the new changes by reverting the original record to that version.
For that I used a function from Paper Trail core paper_trail.record_update().
A:
p = Post.find(1)
p.title = "A new pending version"
p.paper_trail.record_update(nil)
B as a monitor:
p = Publication.find(1)
p.revert_to(p.versions.last)
B as an editor:
p = Publication.find(1)
p.title = "p will be updated to this version immediately"
p.paper_trail.record_update(nil)
p.save
I added has_paper_trail to Post model but I restricted it on create and destroy actions because as I said above I don't want a new version to be created after updating, I want it to be created before.
has_paper_trail :on => [:create, :destroy]
I'm facing the same problem right now.
No, it's not supported by paper_trail, but maybe we can achieve it adding an approved attribute to our Record. It should default to false so that, when the Record object is saved, a new paper_trail version is created with that attribute set to false.
Later an AdminUser can approve the record setting approved to true and paper_trail will create the new approved version.
It's not the cleanest solution but it should work. And we could also add other attributes to your Record model such as approved_by and approved_at, should you we them.
Mmm.. I'm thinking about it..
Please let me know if you found a better solution!
I would like to add a invite code requirement for users to register in my application. I investigated the devise_invitable gem for devise and this looks very promising. However, It should not be possible to continuously invite people to the application, like devise_invitable does.
To solve the problem, I need to implant user levels in my application. I found this project on github and now I got the following idea: Once a user registers (invited by another existing user) it starts in level 1 and must complete tasks in order to archive experience points. He works his/her way up to the next level where he can invite 1 new member and then in the next level he can invite 1 other and in the next level, the user can invite 2 members, so on, so on.
I am fairy new to Ruby and I'd like to know how to encomplish this and to know if this is even possible to insert in my users controller.
Thank you for reading and have a nice day.
This should be a fairly straight forward process, as the number of invitations a user has is just an integer stored in your database. It could be something as simple as:
def level_up(level)
self.invitation_limit += level
self.save
end
While a very simple implementation, you just pass in the users level, add it to their current number of invitations, and save the user. It all really depends on how fancy you want to get, but it really comes down to basic math, and saving it to the database.
I'm not sure if this changed since the question was asked in 2012, but devise_invitable has an invitation_limit parameter:
invitation_limit: The number of invitations users can send. The default value of nil means users can send as many invites as they want, there is no limit for any user, invitation_limit column is not used. A setting of 0 means they can't send invitations. A setting n > 0 means they can send n invitations. You can change invitation_limit column for some users so they can send more or less invitations, even with global invitation_limit = 0.
You can see how this parameter is used by looking at the source here. One important part:
# Return true if this user has invitations left to send
def has_invitations_left?
if self.class.invitation_limit.present?
if invitation_limit
return invitation_limit > 0
else
return self.class.invitation_limit > 0
end
else
return true
end
end
I am writing an app which will sit between a vendors proprietary inventory management system and their Shopify shop. The app will periodically update Shopify from new data generated by the inventory management system. It will also provide end-points for Shopify webhooks.
I am currently doing something like this (pseudo-ruby with much stuff omitted):
def update_product_with_proxy(product_proxy)
product_proxy.variant_proxies.dirty.each do |variant_proxy|
update_variant_with_proxy(variant_proxy)
end
if product_proxy.dirty_proxy
shopify_product = ShopifyAPI::Product.find(product_proxy.shopify_id)
shopify_product.update_attributes({some attributes here})
end
end
Elsewhere:
def update_variant_with_proxy(variant_proxy)
shopify_variant = ShopifyAPI::Variant.find(variant_proxy.shopify_id)
shopify_variant.update_attributes({some attributes here})
end
This seems terribly inefficient as I have to fetch each updated ShopifyAPI::Product and ShopifyAPI::Variant before I can update them (I have their id's cached locally). It takes about 25 minutes for an update cycle updating 24 products each with 16 variants. Rails spends less than 2 seconds updating my product/variant proxies. The other 99% of the time is spent talking to Shopify. I must be doing something wrong.
Given that I know the id of the remote object is there a way to updated it directly without having to fetch it first?
cheers,
-tomek
First things first: You can update variants through their parent product. Once you've grabbed the product it'll have the variant info with it so you can edit them, save, and the changes will be persisted in a single API call. That'll save you some time.
Second: You can create an object locally using the gem, give it an id, and then call save to initiate the PUT request without first fetching the object from Shopify. Something like this should do the trick:
product = ShopifyAPI::Product.new(:id => 1, :title => "My new title")
product.save
Putting those two things together should give you what you want: The ability to update a product's variants in a single API call.
Note: For future reference, the shopify_api gem is built on Active Resource, so anything you can do with that library you can do with the gem.