Skip to content

Commit

Permalink
API Updates (#727)
Browse files Browse the repository at this point in the history
  • Loading branch information
dcr-stripe authored Jul 9, 2021
1 parent e7e2eba commit ce5d34a
Show file tree
Hide file tree
Showing 5 changed files with 204 additions and 1 deletion.
1 change: 1 addition & 0 deletions stripe/api_resources/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
from stripe.api_resources.price import Price
from stripe.api_resources.product import Product
from stripe.api_resources.promotion_code import PromotionCode
from stripe.api_resources.quote import Quote
from stripe.api_resources.recipient import Recipient
from stripe.api_resources.recipient_transfer import RecipientTransfer
from stripe.api_resources.refund import Refund
Expand Down
86 changes: 86 additions & 0 deletions stripe/api_resources/quote.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
from __future__ import absolute_import, division, print_function

import stripe
from stripe import api_requestor
from stripe import util
from stripe.api_resources.abstract import CreateableAPIResource
from stripe.api_resources.abstract import ListableAPIResource
from stripe.api_resources.abstract import UpdateableAPIResource
from stripe.api_resources.abstract import custom_method
from stripe.six.moves.urllib.parse import quote_plus


@custom_method("accept", http_verb="post")
@custom_method("cancel", http_verb="post")
@custom_method("finalize_quote", http_verb="post", http_path="finalize")
@custom_method("list_line_items", http_verb="get", http_path="line_items")
class Quote(CreateableAPIResource, ListableAPIResource, UpdateableAPIResource):
OBJECT_NAME = "quote"

def accept(self, idempotency_key=None, **params):
url = self.instance_url() + "/accept"
headers = util.populate_headers(idempotency_key)
self.refresh_from(self.request("post", url, params, headers))
return self

def cancel(self, idempotency_key=None, **params):
url = self.instance_url() + "/cancel"
headers = util.populate_headers(idempotency_key)
self.refresh_from(self.request("post", url, params, headers))
return self

def finalize_quote(self, idempotency_key=None, **params):
url = self.instance_url() + "/finalize"
headers = util.populate_headers(idempotency_key)
self.refresh_from(self.request("post", url, params, headers))
return self

def list_line_items(self, idempotency_key=None, **params):
url = self.instance_url() + "/line_items"
headers = util.populate_headers(idempotency_key)
self.refresh_from(self.request("get", url, params, headers))
return self

@classmethod
def _cls_pdf(
cls,
sid,
api_key=None,
idempotency_key=None,
stripe_version=None,
stripe_account=None,
**params
):
url = "%s/%s/%s" % (
cls.class_url(),
quote_plus(util.utf8(sid)),
"pdf",
)
requestor = api_requestor.APIRequestor(
api_key,
api_base=stripe.upload_api_base,
api_version=stripe_version,
account=stripe_account,
)
headers = util.populate_headers(idempotency_key)
response, _ = requestor.request_stream("get", url, params, headers)
return response

@util.class_method_variant("_cls_pdf")
def pdf(
self,
api_key=None,
api_version=None,
stripe_version=None,
stripe_account=None,
**params
):
version = api_version or stripe_version
requestor = api_requestor.APIRequestor(
api_key,
api_base=stripe.upload_api_base,
api_version=version,
account=stripe_account,
)
url = self.instance_url() + "/pdf"
return requestor.request_stream("get", url, params=params)
1 change: 1 addition & 0 deletions stripe/object_classes.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
api_resources.Price.OBJECT_NAME: api_resources.Price,
api_resources.Product.OBJECT_NAME: api_resources.Product,
api_resources.PromotionCode.OBJECT_NAME: api_resources.PromotionCode,
api_resources.Quote.OBJECT_NAME: api_resources.Quote,
api_resources.radar.EarlyFraudWarning.OBJECT_NAME: api_resources.radar.EarlyFraudWarning,
api_resources.radar.ValueList.OBJECT_NAME: api_resources.radar.ValueList,
api_resources.radar.ValueListItem.OBJECT_NAME: api_resources.radar.ValueListItem,
Expand Down
115 changes: 115 additions & 0 deletions tests/api_resources/test_quote.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
from __future__ import absolute_import, division, print_function

import stripe
import pytest


TEST_RESOURCE_ID = "qt_123"


class TestQuote(object):
@pytest.fixture(scope="function")
def setup_upload_api_base(self):
stripe.upload_api_base = stripe.api_base
yield
stripe.api_base = stripe.upload_api_base
stripe.upload_api_base = "https://files.stripe.com"

def test_is_listable(self, request_mock):
resources = stripe.Quote.list()
request_mock.assert_requested("get", "/v1/quotes")
assert isinstance(resources.data, list)
assert isinstance(resources.data[0], stripe.Quote)

def test_is_retrievable(self, request_mock):
resource = stripe.Quote.retrieve(TEST_RESOURCE_ID)
request_mock.assert_requested(
"get", "/v1/quotes/%s" % TEST_RESOURCE_ID
)
assert isinstance(resource, stripe.Quote)

def test_is_creatable(self, request_mock):
resource = stripe.Quote.create(customer="cus_123")
request_mock.assert_requested("post", "/v1/quotes")
assert isinstance(resource, stripe.Quote)

def test_is_saveable(self, request_mock):
resource = stripe.Quote.retrieve(TEST_RESOURCE_ID)
resource.metadata["key"] = "value"
resource.save()
request_mock.assert_requested(
"post", "/v1/quotes/%s" % TEST_RESOURCE_ID
)

def test_is_modifiable(self, request_mock):
resource = stripe.Quote.modify(
TEST_RESOURCE_ID, metadata={"key": "value"}
)
request_mock.assert_requested(
"post", "/v1/quotes/%s" % TEST_RESOURCE_ID
)
assert isinstance(resource, stripe.Quote)

def test_can_finalize_quote(self, request_mock):
resource = stripe.Quote.retrieve(TEST_RESOURCE_ID)
resource = resource.finalize_quote()
request_mock.assert_requested(
"post", "/v1/quotes/%s/finalize" % TEST_RESOURCE_ID
)
assert isinstance(resource, stripe.Quote)

def test_can_finalize_quote_classmethod(self, request_mock):
resource = stripe.Quote.finalize_quote(TEST_RESOURCE_ID)
request_mock.assert_requested(
"post", "/v1/quotes/%s/finalize" % TEST_RESOURCE_ID
)
assert isinstance(resource, stripe.Quote)

def test_can_cancel(self, request_mock):
resource = stripe.Quote.retrieve(TEST_RESOURCE_ID)
resource = resource.cancel()
request_mock.assert_requested(
"post", "/v1/quotes/%s/cancel" % TEST_RESOURCE_ID
)
assert isinstance(resource, stripe.Quote)

def test_can_cancel_classmethod(self, request_mock):
resource = stripe.Quote.cancel(TEST_RESOURCE_ID)
request_mock.assert_requested(
"post", "/v1/quotes/%s/cancel" % TEST_RESOURCE_ID
)
assert isinstance(resource, stripe.Quote)

def test_can_accept(self, request_mock):
resource = stripe.Quote.retrieve(TEST_RESOURCE_ID)
resource = resource.accept()
request_mock.assert_requested(
"post", "/v1/quotes/%s/accept" % TEST_RESOURCE_ID
)
assert isinstance(resource, stripe.Quote)

def test_can_accept_classmethod(self, request_mock):
resource = stripe.Quote.accept(TEST_RESOURCE_ID)
request_mock.assert_requested(
"post", "/v1/quotes/%s/accept" % TEST_RESOURCE_ID
)
assert isinstance(resource, stripe.Quote)

def test_can_pdf(self, setup_upload_api_base, request_mock):
resource = stripe.Quote.retrieve(TEST_RESOURCE_ID)
stream, _ = resource.pdf()
request_mock.assert_api_base(stripe.upload_api_base)
request_mock.assert_requested_stream(
"get", "/v1/quotes/%s/pdf" % TEST_RESOURCE_ID
)
content = stream.io.read()
assert content == b"Stripe binary response"

def test_can_pdf_classmethod(self, setup_upload_api_base, request_mock):
stream = stripe.Quote.pdf(TEST_RESOURCE_ID)
request_mock.assert_api_base(stripe.upload_api_base)
request_mock.assert_requested_stream(
"get", "/v1/quotes/%s/pdf" % TEST_RESOURCE_ID
)
content = stream.io.read()
assert content == b"Stripe binary response"
2 changes: 1 addition & 1 deletion tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from tests.request_mock import RequestMock
from tests.stripe_mock import StripeMock

MOCK_MINIMUM_VERSION = "0.107.0"
MOCK_MINIMUM_VERSION = "0.109.0"

# Starts stripe-mock if an OpenAPI spec override is found in `openapi/`, and
# otherwise fall back to `STRIPE_MOCK_PORT` or 12111.
Expand Down

0 comments on commit ce5d34a

Please sign in to comment.