-
Notifications
You must be signed in to change notification settings - Fork 58
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Usage records and other fixes #197
base: master
Are you sure you want to change the base?
Usage records and other fixes #197
Conversation
Hey @pandomic! About the commit About About the last two commits, they look great! |
3b62a25
to
2e3ff02
Compare
Hi @H--o-l, I left only subscription items and usage records-related changes. Looking forward to getting them merged. Going back to your question, js-fix was there because of the mounting issue we had with React but leaving it out of scope for now. I hope in the future we will see a containerized version as well ;) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @pandomic !
Again thanks for your work on this PR!
Here is the first series of requests, I mostly check the first commit.
localstripe/resources.py
Outdated
li = List(url, limit=limit, starting_after=starting_after) | ||
li._list = [value for key, value in store.items() | ||
if key.startswith(cls.object + ':') | ||
and value.subscription == subscription] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Plop!
Looking at implementation of _api_list_all
in a few other object, I think here we should use something more like this:
li = super(SubscriptionItem, cls)._api_list_all(
url, limit=limit, starting_after=starting_after)
li._list = [obj for obj in li._list
if value.subscription == subscription]
What it does it's that it re-uses the code of the parent class instead of accessing the store directly.
Do you think it would work?
(I didn't test it, maybe it needs improvement).
localstripe/resources.py
Outdated
except AssertionError: | ||
raise UserError(400, 'Bad request') | ||
|
||
# TODO: implement ending_before |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a few TODO
in the existing code, but they always suggest a better way for something already existing.
If we were to TODO
all missing arguments of the API, the file would be 50% TODOs.
Instead, I propose to remove the missing feature from the function SubscriptionItem._api_list_all()
prototype.
Like that, a motivated contributor could realize that it's missing and open a PR.
@@ -447,6 +449,10 @@ curl -sSfg -u $SK: $HOST/v1/invoices/upcoming?customer=$cus\&subscription_items[ | |||
|
|||
curl -sSfg -u $SK: $HOST/v1/invoices/upcoming?customer=$cus\&subscription=$sub\&subscription_items[0][id]=si_RBrVStcKDimMnp\&subscription_items[0][plan]=basique-annuel\&subscription_proration_date=1504182686\&subscription_tax_percent=20 | |||
|
|||
si=$(curl -sSfg -u $SK: $HOST/v1/subscription_items?subscription=$sub \ | |||
| grep -oE 'si_\w+') | |||
[ -n "$si" ] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In this first commit, si
is not a subscription item, it's two subscription items.
So maybe there could be a first res
that stores them, a check of how many items there is in res
and then, in the second commit a si=$(echo "$res" | head -n 1)
.
It would be more readable for future readers of this code.
What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 split into proposed steps
@@ -6,6 +6,8 @@ set -eux | |||
HOST=http://localhost:8420 | |||
SK=sk_test_12345 | |||
|
|||
curl -X DELETE $HOST/_config/data | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because it's not related to a localstripe feature, but it's more a CI change, this change needs to be inside another PR.
Like that we would be able to discuss it, as long as needed, without blocking this PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 removed this line
localstripe/resources.py
Outdated
try: | ||
assert _type(subscription) is str | ||
assert subscription.startswith('sub_') | ||
Subscription._api_retrieve(subscription) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great to add this line!
But can it be moved outside the try/catch
, I think there is no reason for this line to be in it.
Also can you add a small comment like # to return 404 if not existant
on this line?
* override _api_list_all for subscription items * add `subscription` argument * filter subscription items by subscription id * add a test to verify endpoint works
* add api to record usage * add api to retrieve usage record summaries * add tests for usage records and summaries
2e3ff02
to
ab721fa
Compare
Hi @H--o-l, thanks for the feedback, I added proposed changes and force-pushed them to the current branch |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @pandomic!
Here is a few new comments, I let you see, and don't hesitate if you need me.
@@ -165,6 +165,7 @@ def _api_list_all(cls, url, limit=None, starting_after=None, **kwargs): | |||
if kwargs: | |||
raise UserError(400, 'Unexpected ' + ', '.join(kwargs.keys())) | |||
|
|||
# TODO: implement ending_before |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey!
Please remove this TODO.
@@ -3144,6 +3144,30 @@ def _calculate_amount_in_tier(self, quantity, index): | |||
t = self.plan.tiers[index] | |||
return int(t['unit_amount']) * quantity + int(t['flat_amount']) | |||
|
|||
@classmethod | |||
def _api_list_all(cls, url, subscription=None, limit=None, | |||
starting_after=None, ending_before=None, **kwargs): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please remove ending_before=None
here, so users know it's not implemented.
raise UserError(400, 'Unexpected ' + ', '.join(kwargs.keys())) | ||
|
||
# to return 404 if not existant | ||
Subscription._api_retrieve(subscription) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please move these two lines after the try/except
like in the other interfaces.
) | ||
|
||
li._list = [obj for obj in li._list | ||
if obj.subscription == subscription] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A quick diff proposition here:
- don't add a new line before
)
so we save one line - don't add a new line after
)
so we save one line, and it's more similar to the other API
--- a/localstripe/resources.py
+++ b/localstripe/resources.py
@@ -3160,9 +3160,7 @@ class SubscriptionItem(StripeObject):
raise UserError(400, 'Bad request')
li = super(SubscriptionItem, cls)._api_list_all(
- url, limit=limit, starting_after=starting_after
- )
-
+ url, limit=limit, starting_after=starting_after)
li._list = [obj for obj in li._list
if obj.subscription == subscription]
timestamp=None): | ||
self.quantity = quantity | ||
self.subscription_item = subscription_item_id | ||
self.timestamp = timestamp |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add check of kwargs
and assert of parameters like in the other ressources __init__
function?
Assert should follow the Stripe API documentation on what is mandatory and what's not.
self.subscription_item = subscription_item_id | ||
self.timestamp = timestamp | ||
|
||
super().__init__() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add a small # All exceptions must be raised before this point.
above this line like in the other ressources __init__
?
|
||
usage_records = [value for key, value in store.items() | ||
if key.startswith(cls.object + ':') | ||
and value.subscription_item == subscription_item_id] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When I see this operation, and the routes below (/v1/subscription_items/{subscription_item_id}/usage_records
, /v1/subscription_items/{subscription_item_id}/usage_record_summaries
) I think it would be simpler and more logical to have usage record stored direcly inside the corresponding subscription item.
Also I'm OK with a new object class UsageRecord()
but I think I'm NOK with a class UsageRecord(StripeObject)
, because usage record are never used with the standard APIs that all other StripeObject
implement, ie api_create
, api_retrieve
, api_update
, api_delete
, api_list_all
and associated HTTP route and method (GET object/id
, POST object/id
etc).
So I think that routes /usage_records
and /usage_record_summaries
should be extensions of the object subscription item.
What do you think?
curl -sSfg -u $SK: $HOST/v1/subscription_items/$si/usage_record_summaries \ | ||
| grep -oP '"total_usage": \K([0-9]+)') | ||
[ "$total_usage" -eq 115 ] | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
❤️
Summary