def test_calculate_refund_above_max_refund(self): charge = Charge( id="ch_111111", customer=self.customer, amount=decimal.Decimal("500.00") ) self.assertEqual( charge._calculate_refund_amount(amount=decimal.Decimal("600.00")), 50000 )
def test__attach_objects_hook_missing_source_data( self, mock_account, mock_payment_method, mock_charge_account, mock_charge_source ): """Make sure we handle the case where the source data is empty or insufficient.""" charge = Charge( amount=50, currency="usd", id="ch_test", status=ChargeStatus.failed, captured=False, paid=False, ) mock_cls = create_autospec(spec=Charge, spec_set=True) # Empty data dict works for this test since we only look up the source key and # everything else is mocked. mock_data = {} starting_source = charge.source charge._attach_objects_hook(cls=mock_cls, data=mock_data) # source shouldn't be touched self.assertEqual(starting_source, charge.source) mock_payment_method._get_or_create_source.assert_not_called() # try again with a source key, but no object sub key. mock_data = {"source": {"foo": "bar"}} charge._attach_objects_hook(cls=mock_cls, data=mock_data) # source shouldn't be touched self.assertEqual(starting_source, charge.source) mock_payment_method._get_or_create_source.assert_not_called()
def test_sync_from_stripe_data_no_customer( self, charge_retrieve_mock, balance_transaction_retrieve_mock, default_account_mock ): from djstripe.settings import STRIPE_SECRET_KEY default_account_mock.return_value = self.account fake_charge_copy = deepcopy(FAKE_CHARGE) fake_charge_copy.pop("customer", None) # remove invoice since it requires a customer fake_charge_copy.pop("invoice", None) Charge.sync_from_stripe_data(fake_charge_copy) assert Charge.objects.count() == 1 charge = Charge.objects.get() assert charge.customer is None charge_retrieve_mock.assert_not_called() balance_transaction_retrieve_mock.assert_called_once_with( api_key=STRIPE_SECRET_KEY, expand=[], id=FAKE_BALANCE_TRANSACTION["id"] ) self.assert_fks( charge, expected_blank_fks={ "djstripe.Account.business_logo", "djstripe.Charge.customer", "djstripe.Charge.dispute", "djstripe.Charge.invoice", "djstripe.Charge.transfer", "djstripe.Customer.coupon", "djstripe.Plan.product", }, )
def test_calculate_refund_amount_full_refund(self): charge = Charge( stripe_id="ch_111111", customer=self.customer, amount=decimal.Decimal("500.00") ) self.assertEqual(charge._calculate_refund_amount(), 50000)
def test__attach_objects_hook_no_destination_account( self, mock_account, mock_payment_method, mock_charge_account, mock_charge_source ): """Test that _attach_objects_hook works as expected when there is no destination account.""" charge = Charge( amount=50, currency="usd", id="ch_test", status=ChargeStatus.failed, captured=False, paid=False, ) mock_cls = create_autospec(spec=Charge, spec_set=True) mock_cls._stripe_object_destination_to_account.return_value = False mock_data = {"source": {"object": "foo"}} mock_payment_method._get_or_create_source.return_value = ("bar", "unused") charge._attach_objects_hook(cls=mock_cls, data=mock_data) # expect the attributes to be set appropriately self.assertEqual(mock_account.get_default_account.return_value, charge.account) self.assertEqual( mock_payment_method._get_or_create_source.return_value[0], charge.source ) # expect the appropriate calls to be made mock_cls._stripe_object_destination_to_account.assert_called_once_with( target_cls=mock_account, data=mock_data ) mock_payment_method._get_or_create_source.assert_called_once_with( data=mock_data["source"], source_type=mock_data["source"]["object"] )
def test_sync_from_stripe_data_no_customer(self, default_account_mock): default_account_mock.return_value = self.account fake_charge_copy = deepcopy(FAKE_CHARGE) fake_charge_copy.pop("customer", None) Charge.sync_from_stripe_data(fake_charge_copy) assert Charge.objects.count() == 1 charge = Charge.objects.get() assert charge.customer is None
def test_calculate_refund_amount_partial_refund(self): charge = Charge( stripe_id="ch_111111", customer=self.customer, amount=decimal.Decimal("500.00") ) self.assertEquals( charge.calculate_refund_amount(amount=decimal.Decimal("300.00")), 30000 )
def test_str(self): charge = Charge( amount=50, currency="usd", id="ch_test", status=ChargeStatus.failed, captured=False, paid=False, ) self.assertEqual(str(charge), "$50.00 USD (Uncaptured)") charge.captured = True self.assertEqual(str(charge), "$50.00 USD (Failed)") charge.status = ChargeStatus.succeeded charge.dispute = Dispute() self.assertEqual(str(charge), "$50.00 USD (Disputed)") charge.dispute = None charge.refunded = True charge.amount_refunded = 50 self.assertEqual(str(charge), "$50.00 USD (Refunded)") charge.refunded = False self.assertEqual(str(charge), "$50.00 USD (Partially refunded)") charge.amount_refunded = 0 self.assertEqual(str(charge), "$50.00 USD")
def test_capture_charge( self, balance_transaction_retrieve_mock, charge_retrieve_mock, default_account_mock ): default_account_mock.return_value = self.account fake_charge_no_invoice = deepcopy(FAKE_CHARGE) fake_charge_no_invoice.update({"invoice": None}) charge_retrieve_mock.return_value = fake_charge_no_invoice charge, created = Charge._get_or_create_from_stripe_object(fake_charge_no_invoice) self.assertTrue(created) captured_charge = charge.capture() self.assertTrue(captured_charge.captured) self.assert_fks( charge, expected_blank_fks={ "djstripe.Account.business_logo", "djstripe.Charge.dispute", "djstripe.Charge.invoice", "djstripe.Charge.transfer", "djstripe.Customer.coupon", "djstripe.Plan.product", }, )
def test_sync_from_stripe_data_max_amount( self, default_account_mock, subscription_retrieve_mock, product_retrieve_mock, invoice_retrieve_mock, charge_retrieve_mock, balance_transaction_retrieve_mock, ): default_account_mock.return_value = self.account fake_charge_copy = deepcopy(FAKE_CHARGE) # https://support.stripe.com/questions/what-is-the-maximum-amount-i-can-charge-with-stripe fake_charge_copy.update({"amount": 99999999}) charge = Charge.sync_from_stripe_data(fake_charge_copy) self.assertEqual(Decimal("999999.99"), charge.amount) self.assertEqual(True, charge.paid) self.assertEqual(False, charge.refunded) self.assertEqual(True, charge.captured) self.assertEqual(False, charge.disputed) self.assertEqual(0, charge.amount_refunded) charge_retrieve_mock.assert_not_called() self.assert_fks( charge, expected_blank_fks={ "djstripe.Account.business_logo", "djstripe.Charge.dispute", "djstripe.Charge.transfer", "djstripe.Customer.coupon", }, )
def sync_charges(apps, schema_editor): # This is okay, since we're only doing a forward migration. from djstripe.models import Charge from djstripe.context_managers import stripe_temporary_api_version with stripe_temporary_api_version("2016-03-07"): if Charge.objects.count(): print("syncing charges. This may take a while.") for charge in tqdm(Charge.objects.all(), desc="Sync", unit=" charges"): try: Charge.sync_from_stripe_data(charge.api_retrieve()) except InvalidRequestError: tqdm.write("There was an error while syncing charge ({charge_id}).".format(charge_id=charge.stripe_id)) print("Charge sync complete.")
def test_refund_charge(self, charge_retrieve_mock, default_account_mock): default_account_mock.return_value = self.account fake_charge_no_invoice = deepcopy(FAKE_CHARGE) fake_charge_no_invoice.update({"invoice": None}) charge_retrieve_mock.return_value = fake_charge_no_invoice charge, created = Charge._get_or_create_from_stripe_object(fake_charge_no_invoice) self.assertTrue(created) charge.refund() refunded_charge, created2 = Charge._get_or_create_from_stripe_object(fake_charge_no_invoice) self.assertFalse(created2) self.assertEqual(refunded_charge.refunded, True) self.assertEqual(refunded_charge.amount_refunded, decimal.Decimal("22.00"))
def test_refund_charge( self, charge_retrieve_mock, balance_transaction_retrieve_mock, default_account_mock ): default_account_mock.return_value = self.account fake_charge_no_invoice = deepcopy(FAKE_CHARGE) fake_charge_no_invoice.update({"invoice": None}) charge_retrieve_mock.return_value = fake_charge_no_invoice charge, created = Charge._get_or_create_from_stripe_object(fake_charge_no_invoice) self.assertTrue(created) self.assert_fks( charge, expected_blank_fks={ "djstripe.Account.business_logo", "djstripe.Charge.dispute", "djstripe.Charge.invoice", "djstripe.Charge.transfer", "djstripe.Customer.coupon", }, ) charge.refund() refunded_charge, created2 = Charge._get_or_create_from_stripe_object( fake_charge_no_invoice ) self.assertFalse(created2) self.assertEqual(refunded_charge.refunded, True) self.assertEqual(refunded_charge.amount_refunded, decimal.Decimal("22.00")) self.assert_fks( refunded_charge, expected_blank_fks={ "djstripe.Account.business_logo", "djstripe.Charge.dispute", "djstripe.Charge.invoice", "djstripe.Charge.transfer", "djstripe.Customer.coupon", }, )
def test_sync_from_stripe_data_refunded( self, subscription_retrieve_mock, product_retrieve_mock, invoice_retrieve_mock, charge_retrieve_mock, balance_transaction_retrieve_mock, default_account_mock, ): from djstripe.settings import STRIPE_SECRET_KEY default_account_mock.return_value = self.account fake_charge_copy = deepcopy(FAKE_CHARGE_REFUNDED) charge = Charge.sync_from_stripe_data(fake_charge_copy) self.assertEqual(Decimal("22"), charge.amount) self.assertEqual(True, charge.paid) self.assertEqual(True, charge.refunded) self.assertEqual(True, charge.captured) self.assertEqual(False, charge.disputed) self.assertEqual("VideoDoc consultation for ivanp0001 berkp0001", charge.description) self.assertEqual(charge.amount, charge.amount_refunded) charge_retrieve_mock.assert_not_called() # We expect two calls - for charge and then for charge.refunds balance_transaction_retrieve_mock.assert_has_calls( [ call(api_key=STRIPE_SECRET_KEY, expand=[], id=FAKE_BALANCE_TRANSACTION["id"]), call( api_key=STRIPE_SECRET_KEY, expand=[], id=FAKE_BALANCE_TRANSACTION_REFUND["id"] ), ] ) refunds = list(charge.refunds.all()) self.assertEqual(len(refunds), 1) refund = refunds[0] self.assertEqual(refund.id, FAKE_REFUND["id"]) self.assertNotEqual(charge.balance_transaction.id, refund.balance_transaction.id) self.assertEqual(charge.balance_transaction.id, FAKE_BALANCE_TRANSACTION["id"]) self.assertEqual(refund.balance_transaction.id, FAKE_BALANCE_TRANSACTION_REFUND["id"]) self.assert_fks( charge, expected_blank_fks={ "djstripe.Account.business_logo", "djstripe.Charge.dispute", "djstripe.Charge.transfer", "djstripe.Customer.coupon", }, )
def test_sync_from_stripe_data_unsupported_source(self, default_account_mock): default_account_mock.return_value = self.account fake_charge_copy = deepcopy(FAKE_CHARGE) fake_charge_copy.update({"source": {"id": "test_id", "object": "unsupported"}}) charge = Charge.sync_from_stripe_data(fake_charge_copy) self.assertEqual("test_id", charge.source_stripe_id) self.assertEqual("unsupported", charge.source_type) self.assertEqual(charge.source, PaymentMethod.objects.get(id="test_id"))
def test_capture_charge(self, charge_retrieve_mock, default_account_mock): default_account_mock.return_value = self.account fake_charge_no_invoice = deepcopy(FAKE_CHARGE) fake_charge_no_invoice.update({"invoice": None}) charge_retrieve_mock.return_value = fake_charge_no_invoice charge, created = Charge._get_or_create_from_stripe_object(fake_charge_no_invoice) self.assertTrue(created) captured_charge = charge.capture() self.assertTrue(captured_charge.captured)
def test_sync_from_stripe_data(self): charge = Charge.sync_from_stripe_data(FAKE_CHARGE) self.assertEqual(self.invoice, charge.invoice) self.assertEqual("9999", charge.card_last_4) self.assertEqual("Visa", charge.card_kind) self.assertEqual(Decimal("9.95"), charge.amount) self.assertEqual(True, charge.paid) self.assertEqual(False, charge.refunded) self.assertEqual(True, charge.captured) self.assertEqual(Decimal("0"), charge.fee) self.assertEqual(False, charge.disputed) self.assertEqual("test_description", charge.description) self.assertEqual(None, charge.amount_refunded)
def test_sync_from_stripe_data_with_destination(self, account_retrieve_mock, charge_retrieve_mock): account_retrieve_mock.return_value = FAKE_ACCOUNT fake_charge_copy = deepcopy(FAKE_CHARGE) fake_charge_copy.update({"destination": FAKE_ACCOUNT["id"]}) charge_retrieve_mock.return_value = fake_charge_copy charge, created = Charge._get_or_create_from_stripe_object(fake_charge_copy) self.assertTrue(created) self.assertEqual(2, Account.objects.count()) account = Account.objects.get(stripe_id=FAKE_ACCOUNT["id"]) self.assertEqual(account, charge.account)
def test_sync_from_stripe_data_max_amount(self, default_account_mock): default_account_mock.return_value = self.account fake_charge_copy = deepcopy(FAKE_CHARGE) # https://support.stripe.com/questions/what-is-the-maximum-amount-i-can-charge-with-stripe fake_charge_copy.update({"amount": 99999999}) charge = Charge.sync_from_stripe_data(fake_charge_copy) self.assertEqual(Decimal("999999.99"), charge.amount) self.assertEqual(True, charge.paid) self.assertEqual(False, charge.refunded) self.assertEqual(True, charge.captured) self.assertEqual(False, charge.disputed) self.assertEqual(0, charge.amount_refunded)
def test_sync_from_stripe_data_with_transfer(self, default_account_mock, transfer_retrieve_mock, charge_retrieve_mock): default_account_mock.return_value = self.account fake_transfer = deepcopy(FAKE_TRANSFER) fake_charge_copy = deepcopy(FAKE_CHARGE) fake_charge_copy.update({"transfer": fake_transfer["id"]}) transfer_retrieve_mock.return_value = fake_transfer charge_retrieve_mock.return_value = fake_charge_copy charge, created = Charge._get_or_create_from_stripe_object(fake_charge_copy) self.assertTrue(created) self.assertNotEqual(None, charge.transfer) self.assertEqual(fake_transfer["id"], charge.transfer.stripe_id)
def test_sync_from_stripe_data(self, default_account_mock): default_account_mock.return_value = self.account fake_charge_copy = deepcopy(FAKE_CHARGE) fake_charge_copy.update({"application_fee": {"amount": 0}}) charge = Charge.sync_from_stripe_data(FAKE_CHARGE) self.assertEqual(Decimal("22"), charge.amount) self.assertEqual(True, charge.paid) self.assertEqual(False, charge.refunded) self.assertEqual(True, charge.captured) self.assertEqual(False, charge.disputed) self.assertEqual("VideoDoc consultation for ivanp0001 berkp0001", charge.description) self.assertEqual(0, charge.amount_refunded) self.assertEqual("card_16YKQh2eZvKYlo2Cblc5Feoo", charge.source_stripe_id) self.assertEqual(charge.source_type, LegacySourceType.card)
def test_sync_from_stripe_data_with_transfer( self, default_account_mock, subscription_retrieve_mock, product_retrieve_mock, transfer_retrieve_mock, invoice_retrieve_mock, charge_retrieve_mock, balance_transaction_retrieve_mock, ): from djstripe.settings import STRIPE_SECRET_KEY default_account_mock.return_value = self.account fake_transfer = deepcopy(FAKE_TRANSFER) fake_charge_copy = deepcopy(FAKE_CHARGE) fake_charge_copy.update({"transfer": fake_transfer["id"]}) transfer_retrieve_mock.return_value = fake_transfer charge_retrieve_mock.return_value = fake_charge_copy charge, created = Charge._get_or_create_from_stripe_object( fake_charge_copy, current_ids={fake_charge_copy["id"]} ) self.assertTrue(created) self.assertNotEqual(None, charge.transfer) self.assertEqual(fake_transfer["id"], charge.transfer.id) charge_retrieve_mock.assert_not_called() balance_transaction_retrieve_mock.assert_called_once_with( api_key=STRIPE_SECRET_KEY, expand=[], id=FAKE_BALANCE_TRANSACTION["id"] ) self.assert_fks( charge, expected_blank_fks={ "djstripe.Account.business_logo", "djstripe.Charge.dispute", "djstripe.Customer.coupon", }, )
def test_sync_from_stripe_data( self, subscription_retrieve_mock, product_retrieve_mock, invoice_retrieve_mock, charge_retrieve_mock, balance_transaction_retrieve_mock, default_account_mock, ): from djstripe.settings import STRIPE_SECRET_KEY default_account_mock.return_value = self.account fake_charge_copy = deepcopy(FAKE_CHARGE) fake_charge_copy.update({"application_fee": {"amount": 0}}) charge = Charge.sync_from_stripe_data(fake_charge_copy) self.assertEqual(Decimal("22"), charge.amount) self.assertEqual(True, charge.paid) self.assertEqual(False, charge.refunded) self.assertEqual(True, charge.captured) self.assertEqual(False, charge.disputed) self.assertEqual("VideoDoc consultation for ivanp0001 berkp0001", charge.description) self.assertEqual(0, charge.amount_refunded) self.assertEqual("card_16YKQh2eZvKYlo2Cblc5Feoo", charge.source_id) self.assertEqual(charge.source.type, LegacySourceType.card) charge_retrieve_mock.assert_not_called() balance_transaction_retrieve_mock.assert_called_once_with( api_key=STRIPE_SECRET_KEY, expand=[], id=FAKE_BALANCE_TRANSACTION["id"] ) self.assert_fks( charge, expected_blank_fks={ "djstripe.Account.business_logo", "djstripe.Charge.dispute", "djstripe.Charge.transfer", "djstripe.Customer.coupon", }, )
def test_sync_from_stripe_data_with_destination( self, file_retrive_mock, invoice_retrieve_mock, subscription_retrieve_mock, product_retrieve_mock, balance_transaction_retrieve_mock, account_retrieve_mock, charge_retrieve_mock, ): from djstripe.settings import STRIPE_SECRET_KEY account_retrieve_mock.return_value = FAKE_ACCOUNT fake_charge_copy = deepcopy(FAKE_CHARGE) fake_charge_copy.update({"destination": FAKE_ACCOUNT["id"]}) charge, created = Charge._get_or_create_from_stripe_object( fake_charge_copy, current_ids={fake_charge_copy["id"]} ) self.assertTrue(created) self.assertEqual(2, Account.objects.count()) account = Account.objects.get(id=FAKE_ACCOUNT["id"]) self.assertEqual(account, charge.account) charge_retrieve_mock.assert_not_called() balance_transaction_retrieve_mock.assert_called_once_with( api_key=STRIPE_SECRET_KEY, expand=[], id=FAKE_BALANCE_TRANSACTION["id"] ) self.assert_fks( charge, expected_blank_fks={ "djstripe.Charge.dispute", "djstripe.Charge.transfer", "djstripe.Customer.coupon", }, )
def test_sync_from_stripe_data_unsupported_source( self, invoice_retrieve_mock, subscription_retrieve_mock, product_retrieve_mock, charge_retrieve_mock, balance_transaction_retrieve_mock, default_account_mock, ): from djstripe.settings import STRIPE_SECRET_KEY default_account_mock.return_value = self.account fake_charge_copy = deepcopy(FAKE_CHARGE) fake_charge_copy.update({"source": {"id": "test_id", "object": "unsupported"}}) charge = Charge.sync_from_stripe_data(fake_charge_copy) self.assertEqual("test_id", charge.source_id) self.assertEqual("unsupported", charge.source.type) self.assertEqual(charge.source, DjstripePaymentMethod.objects.get(id="test_id")) # alias to old model name should work the same self.assertEqual(charge.source, PaymentMethod.objects.get(id="test_id")) charge_retrieve_mock.assert_not_called() balance_transaction_retrieve_mock.assert_called_once_with( api_key=STRIPE_SECRET_KEY, expand=[], id=FAKE_BALANCE_TRANSACTION["id"] ) self.assert_fks( charge, expected_blank_fks={ "djstripe.Account.business_logo", "djstripe.Charge.dispute", "djstripe.Charge.transfer", "djstripe.Customer.coupon", }, )
def test_calculate_refund_amount_full_refund(self): charge = Charge(stripe_id="ch_111111", customer=self.customer, amount=decimal.Decimal("500.00")) self.assertEqual(charge._calculate_refund_amount(), 50000)
def test_send_receipt_not_sent(self, get_current_mock): charge = Charge(receipt_sent=True) charge.send_receipt() # Assert the condition caused exit self.assertFalse(get_current_mock.called)
class InvoiceTest(TestCase): def setUp(self): self.customer = Customer.objects.create(stripe_id="cus_xxxxxxxxxxxxxxx") self.invoice = Invoice.objects.create(stripe_id="inv_xxxxxxxx123456", customer=self.customer, period_start=timezone.now(), period_end=timezone.now() + timedelta(days=5), subtotal=Decimal("35.00"), total=Decimal("50.00"), date=timezone.now(), charge="crg_xxxxxxxxx12345") def test_tostring(self): self.assertEquals("<total=50.00, paid=False, stripe_id=inv_xxxxxxxx123456>", str(self.invoice)) @patch("stripe.Invoice.retrieve") def test_retry_true(self, invoice_retrieve_mock): return_value = self.invoice.retry() invoice_retrieve_mock.assert_called_once_with(self.invoice.stripe_id) self.assertTrue(return_value) @patch("stripe.Invoice.retrieve") def test_retry_false(self, invoice_retrieve_mock): invoice = self.invoice invoice.pk = None invoice.stripe_id = "inv_xxxxxxxx1234567" invoice.paid = True invoice.save() return_value = invoice.retry() self.assertFalse(invoice_retrieve_mock.called) self.assertFalse(return_value) def test_status_open(self): status = self.invoice.status() self.assertEqual("Open", status) def test_status_paid(self): invoice = self.invoice invoice.pk = None invoice.stripe_id = "inv_xxxxxxxx12345678" invoice.paid = True invoice.save() status = invoice.status() self.assertEqual("Paid", status) def test_status_closed(self): invoice = self.invoice invoice.pk = None invoice.stripe_id = "inv_xxxxxxxx123456789" invoice.closed = True invoice.save() status = invoice.status() self.assertEqual("Closed", status) def test_sync_from_stripe_data(self): invoice = Invoice.sync_from_stripe_data(FAKE_INVOICE) self.assertEqual("in_xxxxxxxxxxxxxxx", invoice.stripe_id) self.assertEqual(False, invoice.attempted) self.assertEqual(False, invoice.closed) self.assertEqual(False, invoice.paid) self.assertEqual(Decimal("9.95"), invoice.subtotal) self.assertEqual(Decimal("9.95"), invoice.total) self.assertEqual("", invoice.charge) self.assertEqual(1, invoice.items.count()) invoice_item = invoice.items.all()[0] self.assertEqual("sub_xxxxxxxxxxxxxxx", invoice_item.stripe_id) self.assertEqual(Decimal("9.95"), invoice_item.amount) self.assertEqual("usd", invoice_item.currency) self.assertEqual(False, invoice_item.proration) self.assertEqual("", invoice_item.description) self.assertEqual("subscription", invoice_item.line_type) self.assertEqual("test", invoice_item.plan) self.assertEqual(1, invoice_item.quantity) # period_end is determined by latest invoice_item self.assertEqual(invoice_item.period_end, invoice.period_end) # Update invoice Invoice.sync_from_stripe_data(FAKE_INVOICE) def test_sync_from_stripe_data_no_plan(self): FAKE_INVOICE_NO_PLAN = deepcopy(FAKE_INVOICE) FAKE_INVOICE_NO_PLAN["id"] = "in_yyyyyyyyyyyyyyy" FAKE_INVOICE_NO_PLAN["subscription"] = "sub_yyyyyyyyyyyyyyy" FAKE_INVOICE_NO_PLAN["lines"]["data"][0]["id"] = "sub_yyyyyyyyyyyyyyy" FAKE_INVOICE_NO_PLAN["lines"]["data"][0]["plan"] = None invoice = Invoice.sync_from_stripe_data(FAKE_INVOICE_NO_PLAN) self.assertEqual(1, invoice.items.count()) invoice_item = invoice.items.all()[0] self.assertEqual("", invoice_item.plan) @patch("djstripe.models.Charge.send_receipt") @patch("djstripe.models.Customer.record_charge") def test_sync_from_stripe_data_with_charge(self, record_charge_mock, send_receipt_mock): record_charge_mock.return_value = Charge(customer=self.customer) FAKE_INVOICE_WITH_CHARGE = deepcopy(FAKE_INVOICE) FAKE_INVOICE_WITH_CHARGE["id"] = "in_zzzzzzzzzzzzzzz" FAKE_INVOICE_WITH_CHARGE["subscription"] = "sub_zzzzzzzzzzzzzzz" FAKE_INVOICE_WITH_CHARGE["lines"]["data"][0]["id"] = "sub_zzzzzzzzzzzzzzz" FAKE_INVOICE_WITH_CHARGE["charge"] = "taco" Invoice.sync_from_stripe_data(FAKE_INVOICE_WITH_CHARGE) record_charge_mock.assert_called_once_with("taco") send_receipt_mock.assert_called_once_with() @patch("djstripe.models.Charge.send_receipt") @patch("djstripe.models.Customer.record_charge", return_value=Charge()) def test_sync_from_stripe_data_with_charge_no_receipt(self, record_charge_mock, send_receipt_mock): record_charge_mock.return_value = Charge(customer=self.customer) FAKE_INVOICE_WITH_CHARGE = deepcopy(FAKE_INVOICE) FAKE_INVOICE_WITH_CHARGE["id"] = "in_zzzzzzzzzzzzzzz1" FAKE_INVOICE_WITH_CHARGE["subscription"] = "sub_zzzzzzzzzzzzzzz1" FAKE_INVOICE_WITH_CHARGE["lines"]["data"][0]["id"] = "sub_zzzzzzzzzzzzzzz1" FAKE_INVOICE_WITH_CHARGE["charge"] = "taco1" Invoice.sync_from_stripe_data(FAKE_INVOICE_WITH_CHARGE, send_receipt=False) record_charge_mock.assert_called_once_with("taco1") self.assertFalse(send_receipt_mock.called) @patch("djstripe.models.Invoice.sync_from_stripe_data") @patch("stripe.Invoice.retrieve", return_value="lock") def test_handle_event_payment_failed(self, invoice_retrieve_mock, sync_invoice_mock): fake_event = Event(kind="invoice.payment_failed", validated_message={"data": {"object": {"id": "door"}}}) invoice_webhook_handler(fake_event, fake_event.message["data"], "invoice", "payment_failed") invoice_retrieve_mock.assert_called_once_with("door") sync_invoice_mock.assert_called_once_with("lock", send_receipt=True) @patch("djstripe.models.Invoice.sync_from_stripe_data") @patch("stripe.Invoice.retrieve", return_value="key") def test_handle_event_payment_succeeded(self, invoice_retrieve_mock, sync_invoice_mock): fake_event = Event(kind="invoice.payment_succeeded", validated_message={"data": {"object": {"id": "lock"}}}) invoice_webhook_handler(fake_event, fake_event.message["data"], "invoice", "payment_failed") invoice_retrieve_mock.assert_called_once_with("lock") sync_invoice_mock.assert_called_once_with("key", send_receipt=True)
def test___str__(self): charge = Charge( amount=50, currency="usd", id="ch_test", status=ChargeStatus.failed, captured=False, paid=False, ) self.assertEqual(str(charge), "$50.00 USD (Uncaptured)") charge.captured = True self.assertEqual(str(charge), "$50.00 USD (Failed)") charge.status = ChargeStatus.succeeded charge.disputed = True self.assertEqual(str(charge), "$50.00 USD (Disputed)") charge.disputed = False charge.refunded = True charge.amount_refunded = 50 self.assertEqual(str(charge), "$50.00 USD (Refunded)") charge.refunded = False charge.amount_refunded = 0 self.assertEqual(str(charge), "$50.00 USD (Succeeded)") charge.status = ChargeStatus.pending self.assertEqual(str(charge), "$50.00 USD (Pending)")
def test_str(self): charge = Charge(amount=50, paid=True, stripe_id='charge_xxxxxxxxxxxxxx') self.assertEqual("<amount=50, paid=True, stripe_id=charge_xxxxxxxxxxxxxx>", str(charge))
def test_sync_from_stripe_data_refunded_on_update( self, subscription_retrieve_mock, product_retrieve_mock, invoice_retrieve_mock, charge_retrieve_mock, default_account_mock, ): # first sync charge (as per test_sync_from_stripe_data) then sync refunded version, # to hit the update code-path instead of insert from djstripe.settings import STRIPE_SECRET_KEY default_account_mock.return_value = self.account fake_charge_copy = deepcopy(FAKE_CHARGE) with patch( "stripe.BalanceTransaction.retrieve", return_value=deepcopy(FAKE_BALANCE_TRANSACTION) ): charge = Charge.sync_from_stripe_data(fake_charge_copy) self.assertEqual(Decimal("22"), charge.amount) self.assertEqual(True, charge.paid) self.assertEqual(False, charge.refunded) self.assertEqual(True, charge.captured) self.assertEqual(False, charge.disputed) self.assertEqual(len(charge.refunds.all()), 0) fake_charge_refunded_copy = deepcopy(FAKE_CHARGE_REFUNDED) with patch( "stripe.BalanceTransaction.retrieve", return_value=deepcopy(FAKE_BALANCE_TRANSACTION_REFUND), ) as balance_transaction_retrieve_mock: charge_refunded = Charge.sync_from_stripe_data(fake_charge_refunded_copy) self.assertEqual(charge.id, charge_refunded.id) self.assertEqual(Decimal("22"), charge_refunded.amount) self.assertEqual(True, charge_refunded.paid) self.assertEqual(True, charge_refunded.refunded) self.assertEqual(True, charge_refunded.captured) self.assertEqual(False, charge_refunded.disputed) self.assertEqual( "VideoDoc consultation for ivanp0001 berkp0001", charge_refunded.description ) self.assertEqual(charge_refunded.amount, charge_refunded.amount_refunded) charge_retrieve_mock.assert_not_called() balance_transaction_retrieve_mock.assert_called_once_with( api_key=STRIPE_SECRET_KEY, expand=[], id=FAKE_BALANCE_TRANSACTION_REFUND["id"] ) refunds = list(charge_refunded.refunds.all()) self.assertEqual(len(refunds), 1) refund = refunds[0] self.assertEqual(refund.id, FAKE_REFUND["id"]) self.assertNotEqual( charge_refunded.balance_transaction.id, refund.balance_transaction.id ) self.assertEqual( charge_refunded.balance_transaction.id, FAKE_BALANCE_TRANSACTION["id"] ) self.assertEqual(refund.balance_transaction.id, FAKE_BALANCE_TRANSACTION_REFUND["id"]) self.assert_fks( charge_refunded, expected_blank_fks={ "djstripe.Account.business_logo", "djstripe.Charge.dispute", "djstripe.Charge.transfer", "djstripe.Customer.coupon", }, )
class TestCustomer(TestCase): fake_current_subscription = CurrentSubscription( plan="test_plan", quantity=1, start=timezone.now(), amount=decimal.Decimal(25.00)) fake_current_subscription_cancelled_in_stripe = CurrentSubscription( plan="test_plan", quantity=1, start=timezone.now(), amount=decimal.Decimal(25.00), status=CurrentSubscription.STATUS_ACTIVE) def setUp(self): self.user = get_user_model().objects.create_user( username="******", email="*****@*****.**") self.customer = Customer.objects.create( subscriber=self.user, stripe_id="cus_xxxxxxxxxxxxxxx", card_fingerprint="YYYYYYYY", card_last_4="2342", card_kind="Visa") def test_tostring(self): self.assertEquals( "<patrick, [email protected], stripe_id=cus_xxxxxxxxxxxxxxx>", str(self.customer)) @patch("stripe.Customer.retrieve") def test_customer_purge_leaves_customer_record(self, customer_retrieve_fake): self.customer.purge() customer = Customer.objects.get(stripe_id=self.customer.stripe_id) self.assertTrue(customer.subscriber is None) self.assertTrue(customer.card_fingerprint == "") self.assertTrue(customer.card_last_4 == "") self.assertTrue(customer.card_kind == "") self.assertTrue( get_user_model().objects.filter(pk=self.user.pk).exists()) @patch("stripe.Customer.retrieve") def test_customer_delete_same_as_purge(self, customer_retrieve_fake): self.customer.delete() customer = Customer.objects.get(stripe_id=self.customer.stripe_id) self.assertTrue(customer.subscriber is None) self.assertTrue(customer.card_fingerprint == "") self.assertTrue(customer.card_last_4 == "") self.assertTrue(customer.card_kind == "") self.assertTrue( get_user_model().objects.filter(pk=self.user.pk).exists()) @patch("stripe.Customer.retrieve") def test_customer_purge_raises_customer_exception(self, customer_retrieve_mock): customer_retrieve_mock.side_effect = stripe.InvalidRequestError( "No such customer:", "blah") self.customer.purge() customer = Customer.objects.get(stripe_id=self.customer.stripe_id) self.assertTrue(customer.subscriber is None) self.assertTrue(customer.card_fingerprint == "") self.assertTrue(customer.card_last_4 == "") self.assertTrue(customer.card_kind == "") self.assertTrue( get_user_model().objects.filter(pk=self.user.pk).exists()) customer_retrieve_mock.assert_called_once_with(self.customer.stripe_id) @patch("stripe.Customer.retrieve") def test_customer_delete_raises_unexpected_exception( self, customer_retrieve_mock): customer_retrieve_mock.side_effect = stripe.InvalidRequestError( "Unexpected Exception", "blah") with self.assertRaisesMessage(stripe.InvalidRequestError, "Unexpected Exception"): self.customer.purge() customer_retrieve_mock.assert_called_once_with(self.customer.stripe_id) def test_change_charge(self): self.assertTrue(self.customer.can_charge()) @patch("stripe.Customer.retrieve") def test_cannot_charge(self, customer_retrieve_fake): self.customer.delete() self.assertFalse(self.customer.can_charge()) def test_charge_accepts_only_decimals(self): with self.assertRaises(ValueError): self.customer.charge(10) @patch("stripe.Charge.retrieve") def test_record_charge(self, charge_retrieve_mock): charge_retrieve_mock.return_value = { "id": "ch_XXXXXX", "card": { "last4": "4323", "type": "Visa" }, "amount": 1000, "paid": True, "refunded": False, "captured": True, "fee": 499, "dispute": None, "created": 1363911708, "customer": "cus_xxxxxxxxxxxxxxx" } obj = self.customer.record_charge("ch_XXXXXX") self.assertEquals(Charge.objects.get(stripe_id="ch_XXXXXX").pk, obj.pk) self.assertEquals(obj.paid, True) self.assertEquals(obj.disputed, False) self.assertEquals(obj.refunded, False) self.assertEquals(obj.amount_refunded, None) @patch("stripe.Charge.retrieve") def test_refund_charge(self, charge_retrieve_mock): charge = Charge.objects.create(stripe_id="ch_XXXXXX", customer=self.customer, card_last_4="4323", card_kind="Visa", amount=decimal.Decimal("10.00"), paid=True, refunded=False, fee=decimal.Decimal("4.99"), disputed=False) charge_retrieve_mock.return_value.refund.return_value = { "id": "ch_XXXXXX", "card": { "last4": "4323", "type": "Visa" }, "amount": 1000, "paid": True, "refunded": True, "captured": True, "amount_refunded": 1000, "fee": 499, "dispute": None, "created": 1363911708, "customer": "cus_xxxxxxxxxxxxxxx" } charge.refund() charge2 = Charge.objects.get(stripe_id="ch_XXXXXX") self.assertEquals(charge2.refunded, True) self.assertEquals(charge2.amount_refunded, decimal.Decimal("10.00")) @patch("stripe.Charge.retrieve") def test_refund_charge_passes_extra_args(self, charge_retrieve_mock): charge = Charge.objects.create(stripe_id="ch_XXXXXX", customer=self.customer, card_last_4="4323", card_kind="Visa", amount=decimal.Decimal("10.00"), paid=True, refunded=False, fee=decimal.Decimal("4.99"), disputed=False) charge_retrieve_mock.return_value.refund.return_value = { "id": "ch_XXXXXX", "card": { "last4": "4323", "type": "Visa" }, "amount": 1000, "paid": True, "refunded": True, "captured": True, "amount_refunded": 1000, "fee": 499, "dispute": None, "created": 1363911708, "customer": "cus_xxxxxxxxxxxxxxx" } charge.refund(amount=decimal.Decimal("10.00"), reverse_transfer=True, refund_application_fee=False) _, kwargs = charge_retrieve_mock.return_value.refund.call_args self.assertEquals(kwargs["reverse_transfer"], True) self.assertEquals(kwargs["refund_application_fee"], False) @patch("stripe.Charge.retrieve") def test_capture_charge(self, charge_retrieve_mock): charge = Charge.objects.create(stripe_id="ch_XXXXXX", customer=self.customer, card_last_4="4323", card_kind="Visa", amount=decimal.Decimal("10.00"), paid=True, refunded=False, captured=False, fee=decimal.Decimal("4.99"), disputed=False) charge_retrieve_mock.return_value.capture.return_value = { "id": "ch_XXXXXX", "card": { "last4": "4323", "type": "Visa" }, "amount": 1000, "paid": True, "refunded": True, "captured": True, "amount_refunded": 1000, "fee": 499, "dispute": None, "created": 1363911708, "customer": "cus_xxxxxxxxxxxxxxx" } charge2 = charge.capture() self.assertEquals(charge2.captured, True) @patch("stripe.Charge.retrieve") def test_refund_charge_object_returned(self, charge_retrieve_mock): charge = Charge.objects.create(stripe_id="ch_XXXXXX", customer=self.customer, card_last_4="4323", card_kind="Visa", amount=decimal.Decimal("10.00"), paid=True, refunded=False, fee=decimal.Decimal("4.99"), disputed=False) charge_retrieve_mock.return_value.refund.return_value = { "id": "ch_XXXXXX", "card": { "last4": "4323", "type": "Visa" }, "amount": 1000, "paid": True, "refunded": True, "captured": True, "amount_refunded": 1000, "fee": 499, "dispute": None, "created": 1363911708, "customer": "cus_xxxxxxxxxxxxxxx" } charge2 = charge.refund() self.assertEquals(charge2.refunded, True) self.assertEquals(charge2.amount_refunded, decimal.Decimal("10.00")) def test_calculate_refund_amount_full_refund(self): charge = Charge(stripe_id="ch_111111", customer=self.customer, amount=decimal.Decimal("500.00")) self.assertEquals(charge.calculate_refund_amount(), 50000) def test_calculate_refund_amount_partial_refund(self): charge = Charge(stripe_id="ch_111111", customer=self.customer, amount=decimal.Decimal("500.00")) self.assertEquals( charge.calculate_refund_amount(amount=decimal.Decimal("300.00")), 30000) def test_calculate_refund_above_max_refund(self): charge = Charge(stripe_id="ch_111111", customer=self.customer, amount=decimal.Decimal("500.00")) self.assertEquals( charge.calculate_refund_amount(amount=decimal.Decimal("600.00")), 50000) @patch("stripe.Charge.retrieve") @patch("stripe.Charge.create") def test_charge_converts_dollars_into_cents(self, charge_create_mock, charge_retrieve_mock): charge_create_mock.return_value.id = "ch_XXXXX" charge_retrieve_mock.return_value = { "id": "ch_XXXXXX", "card": { "last4": "4323", "type": "Visa" }, "amount": 1000, "paid": True, "refunded": False, "captured": True, "fee": 499, "dispute": None, "created": 1363911708, "customer": "cus_xxxxxxxxxxxxxxx" } self.customer.charge(amount=decimal.Decimal("10.00")) _, kwargs = charge_create_mock.call_args self.assertEquals(kwargs["amount"], 1000) @patch("stripe.Charge.retrieve") @patch("stripe.Charge.create") def test_charge_passes_extra_arguments(self, charge_create_mock, charge_retrieve_mock): charge_create_mock.return_value.id = "ch_XXXXX" charge_retrieve_mock.return_value = { "id": "ch_XXXXXX", "card": { "last4": "4323", "type": "Visa" }, "amount": 1000, "paid": True, "refunded": False, "captured": True, "fee": 499, "dispute": None, "created": 1363911708, "customer": "cus_xxxxxxxxxxxxxxx" } self.customer.charge(amount=decimal.Decimal("10.00"), capture=True, destination='a_stripe_client_id') _, kwargs = charge_create_mock.call_args self.assertEquals(kwargs["capture"], True) self.assertEquals(kwargs["destination"], 'a_stripe_client_id') @patch( "djstripe.models.djstripe_settings.trial_period_for_subscriber_callback", return_value="donkey") @patch("stripe.Customer.create", return_value=PropertyMock(id="cus_xxx1234567890")) def test_create_trial_callback(self, customer_create_mock, callback_mock): user = get_user_model().objects.create_user(username="******", email="*****@*****.**") Customer.create(user) customer_create_mock.assert_called_once_with(email=user.email) callback_mock.assert_called_once_with(user) @patch("djstripe.models.Customer.subscribe") @patch("djstripe.models.djstripe_settings.DEFAULT_PLAN", new_callable=PropertyMock, return_value="schreck") @patch( "djstripe.models.djstripe_settings.trial_period_for_subscriber_callback", return_value="donkey") @patch("stripe.Customer.create", return_value=PropertyMock(id="cus_xxx1234567890")) def test_create_default_plan(self, customer_create_mock, callback_mock, default_plan_fake, subscribe_mock): user = get_user_model().objects.create_user(username="******", email="*****@*****.**") Customer.create(user) customer_create_mock.assert_called_once_with(email=user.email) callback_mock.assert_called_once_with(user) subscribe_mock.assert_called_once_with(plan=default_plan_fake, trial_days="donkey") @patch("djstripe.models.Customer.stripe_customer", new_callable=PropertyMock) def test_update_card(self, customer_stripe_customer_mock): customer_stripe_customer_mock.return_value = PropertyMock( active_card=PropertyMock(fingerprint="test_fingerprint", last4="1234", type="test_type", exp_month=12, exp_year=2020)) self.customer.update_card("test") self.assertEqual("test_fingerprint", self.customer.card_fingerprint) self.assertEqual("1234", self.customer.card_last_4) self.assertEqual("test_type", self.customer.card_kind) self.assertEqual(12, self.customer.card_exp_month) self.assertEqual(2020, self.customer.card_exp_year) @patch( "djstripe.models.Customer.invoices", new_callable=PropertyMock, return_value=PropertyMock( name="filter", filter=MagicMock(return_value=[ MagicMock(name="inv", retry=MagicMock(name="retry", return_value="test")) ]))) @patch("djstripe.models.Customer.sync_invoices") def test_retry_unpaid_invoices(self, sync_invoices_mock, invoices_mock): self.customer.retry_unpaid_invoices() sync_invoices_mock.assert_called_once_with() # TODO: Figure out how to assert on filter and retry mocks @patch("djstripe.models.Customer.invoices", new_callable=PropertyMock, return_value=PropertyMock( name="filter", filter=MagicMock(return_value=[ MagicMock(name="inv", retry=MagicMock( name="retry", return_value="test", side_effect=stripe.InvalidRequestError( "Invoice is already paid", "blah"))) ]))) @patch("djstripe.models.Customer.sync_invoices") def test_retry_unpaid_invoices_expected_exception(self, sync_invoices_mock, invoices_mock): try: self.customer.retry_unpaid_invoices() except: self.fail("Exception was unexpectedly raise.") @patch("djstripe.models.Customer.invoices", new_callable=PropertyMock, return_value=PropertyMock( name="filter", filter=MagicMock(return_value=[ MagicMock(name="inv", retry=MagicMock( name="retry", return_value="test", side_effect=stripe.InvalidRequestError( "This should fail!", "blah"))) ]))) @patch("djstripe.models.Customer.sync_invoices") def test_retry_unpaid_invoices_unexpected_exception( self, sync_invoices_mock, invoices_mock): with self.assertRaisesMessage(stripe.InvalidRequestError, "This should fail!"): self.customer.retry_unpaid_invoices() @patch("stripe.Invoice.create") def test_send_invoice_success(self, invoice_create_mock): return_status = self.customer.send_invoice() self.assertTrue(return_status) invoice_create_mock.assert_called_once_with( customer=self.customer.stripe_id) @patch("stripe.Invoice.create") def test_send_invoice_failure(self, invoice_create_mock): invoice_create_mock.side_effect = stripe.InvalidRequestError( "Invoice creation failed.", "blah") return_status = self.customer.send_invoice() self.assertFalse(return_status) invoice_create_mock.assert_called_once_with( customer=self.customer.stripe_id) @patch("djstripe.models.Customer.stripe_customer", new_callable=PropertyMock) def test_sync_active_card(self, stripe_customer_mock): stripe_customer_mock.return_value = PropertyMock( active_card=PropertyMock( fingerprint="cherry", last4="4429", type="apple", exp_month=12, exp_year=2020, ), deleted=False) self.customer.sync() self.assertEqual("cherry", self.customer.card_fingerprint) self.assertEqual("4429", self.customer.card_last_4) self.assertEqual("apple", self.customer.card_kind) self.assertEqual(12, self.customer.card_exp_month) self.assertEqual(2020, self.customer.card_exp_year) @patch("djstripe.models.Customer.stripe_customer", new_callable=PropertyMock, return_value=PropertyMock(active_card=None, deleted=False)) def test_sync_no_card(self, stripe_customer_mock): self.customer.sync() self.assertEqual("YYYYYYYY", self.customer.card_fingerprint) self.assertEqual("2342", self.customer.card_last_4) self.assertEqual("Visa", self.customer.card_kind) @patch("djstripe.models.Customer.stripe_customer", new_callable=PropertyMock, return_value=PropertyMock(deleted=True)) def test_sync_deleted_in_stripe(self, stripe_customer_mock): self.customer.sync() customer = Customer.objects.get(stripe_id=self.customer.stripe_id) self.assertTrue(customer.subscriber is None) self.assertTrue(customer.card_fingerprint == "") self.assertTrue(customer.card_last_4 == "") self.assertTrue(customer.card_kind == "") self.assertTrue( get_user_model().objects.filter(pk=self.user.pk).exists()) @patch("djstripe.models.Invoice.sync_from_stripe_data") @patch("djstripe.models.Customer.stripe_customer", new_callable=PropertyMock, return_value=PropertyMock(invoices=MagicMock( return_value=PropertyMock(data=["apple", "orange", "pear"])))) def test_sync_invoices(self, stripe_customer_mock, sync_from_stripe_data_mock): self.customer.sync_invoices() sync_from_stripe_data_mock.assert_any_call("apple", send_receipt=False) sync_from_stripe_data_mock.assert_any_call("orange", send_receipt=False) sync_from_stripe_data_mock.assert_any_call("pear", send_receipt=False) self.assertEqual(3, sync_from_stripe_data_mock.call_count) @patch("djstripe.models.Invoice.sync_from_stripe_data") @patch("djstripe.models.Customer.stripe_customer", new_callable=PropertyMock, return_value=PropertyMock(invoices=MagicMock( return_value=PropertyMock(data=[])))) def test_sync_invoices_none(self, stripe_customer_mock, sync_from_stripe_data_mock): self.customer.sync_invoices() self.assertFalse(sync_from_stripe_data_mock.called) @patch("djstripe.models.Customer.record_charge") @patch("djstripe.models.Customer.stripe_customer", new_callable=PropertyMock, return_value=PropertyMock(charges=MagicMock( return_value=PropertyMock(data=[ PropertyMock(id="herbst"), PropertyMock(id="winter"), PropertyMock(id="fruehling"), PropertyMock(id="sommer") ])))) def test_sync_charges(self, stripe_customer_mock, record_charge_mock): self.customer.sync_charges() record_charge_mock.assert_any_call("herbst") record_charge_mock.assert_any_call("winter") record_charge_mock.assert_any_call("fruehling") record_charge_mock.assert_any_call("sommer") self.assertEqual(4, record_charge_mock.call_count) @patch("djstripe.models.Customer.record_charge") @patch("djstripe.models.Customer.stripe_customer", new_callable=PropertyMock, return_value=PropertyMock(charges=MagicMock( return_value=PropertyMock(data=[])))) def test_sync_charges_none(self, stripe_customer_mock, record_charge_mock): self.customer.sync_charges() self.assertFalse(record_charge_mock.called) @patch("djstripe.models.Customer.stripe_customer", new_callable=PropertyMock, return_value=PropertyMock(subscription=None)) def test_sync_current_subscription_no_stripe_subscription( self, stripe_customer_mock): self.assertEqual(None, self.customer.sync_current_subscription()) @patch("djstripe.models.djstripe_settings.plan_from_stripe_id", return_value="test_plan") @patch("djstripe.models.convert_tstamp", return_value=timezone.make_aware(datetime.datetime(2015, 6, 19))) @patch("djstripe.models.Customer.current_subscription", new_callable=PropertyMock, return_value=fake_current_subscription) @patch("djstripe.models.Customer.stripe_customer", new_callable=PropertyMock, return_value=PropertyMock(subscription=PropertyMock( plan=PropertyMock(id="fish", amount=5000), quantity=5, trial_start=False, trial_end=False, cancel_at_period_end=False, status="tree"))) def test_sync_current_subscription_update_no_trial( self, stripe_customer_mock, customer_subscription_mock, convert_tstamp_fake, plan_getter_mock): tz_test_time = timezone.make_aware(datetime.datetime(2015, 6, 19)) self.customer.sync_current_subscription() plan_getter_mock.assert_called_with("fish") self.assertEqual("test_plan", self.fake_current_subscription.plan) self.assertEqual(decimal.Decimal("50.00"), self.fake_current_subscription.amount) self.assertEqual("tree", self.fake_current_subscription.status) self.assertEqual(5, self.fake_current_subscription.quantity) self.assertEqual(False, self.fake_current_subscription.cancel_at_period_end) self.assertEqual(tz_test_time, self.fake_current_subscription.canceled_at) self.assertEqual(tz_test_time, self.fake_current_subscription.start) self.assertEqual(tz_test_time, self.fake_current_subscription.current_period_start) self.assertEqual(tz_test_time, self.fake_current_subscription.current_period_end) self.assertEqual(None, self.fake_current_subscription.trial_start) self.assertEqual(None, self.fake_current_subscription.trial_end) @patch("djstripe.models.Customer.current_subscription", new_callable=PropertyMock, return_value=fake_current_subscription_cancelled_in_stripe) @patch("djstripe.models.Customer.stripe_customer", new_callable=PropertyMock, return_value=PropertyMock(subscription=None)) def test_sync_current_subscription_subscription_cancelled_from_Stripe( self, stripe_customer_mock, customer_subscription_mock): self.assertEqual(CurrentSubscription.STATUS_CANCELLED, self.customer.sync_current_subscription().status) @patch("djstripe.models.Customer.send_invoice") @patch("djstripe.models.Customer.sync_current_subscription") @patch("djstripe.models.Customer.stripe_customer.update_subscription") @patch("djstripe.models.Customer.stripe_customer", new_callable=PropertyMock, return_value=PropertyMock()) def test_subscribe_trial_plan(self, stripe_customer_mock, update_subscription_mock, sync_subscription_mock, send_invoice_mock): trial_days = 7 # From settings self.customer.subscribe(plan="test_trial") sync_subscription_mock.assert_called_once_with() send_invoice_mock.assert_called_once_with() _, call_kwargs = update_subscription_mock.call_args self.assertIn("trial_end", call_kwargs) self.assertLessEqual( call_kwargs["trial_end"], timezone.now() + datetime.timedelta(days=trial_days)) @patch("djstripe.models.Customer.send_invoice") @patch("djstripe.models.Customer.sync_current_subscription") @patch("djstripe.models.Customer.stripe_customer.update_subscription") @patch("djstripe.models.Customer.stripe_customer", new_callable=PropertyMock, return_value=PropertyMock()) def test_subscribe_trial_days_kwarg(self, stripe_customer_mock, update_subscription_mock, sync_subscription_mock, send_invoice_mock): trial_days = 9 self.customer.subscribe(plan="test", trial_days=trial_days) sync_subscription_mock.assert_called_once_with() send_invoice_mock.assert_called_once_with() _, call_kwargs = update_subscription_mock.call_args self.assertIn("trial_end", call_kwargs) self.assertLessEqual( call_kwargs["trial_end"], timezone.now() + datetime.timedelta(days=trial_days)) @patch("djstripe.models.Customer.send_invoice") @patch("djstripe.models.Customer.sync_current_subscription") @patch("djstripe.models.Customer.current_subscription", new_callable=PropertyMock, return_value=fake_current_subscription) @patch("djstripe.models.Customer.stripe_customer", new_callable=PropertyMock, return_value=PropertyMock()) def test_subscribe_not_charge_immediately(self, stripe_customer_mock, customer_subscription_mock, sync_subscription_mock, send_invoice_mock): self.customer.subscribe(plan="test", charge_immediately=False) sync_subscription_mock.assert_called_once_with() self.assertFalse(send_invoice_mock.called) @patch("djstripe.models.Charge.send_receipt") @patch("djstripe.models.Customer.record_charge", return_value=Charge()) @patch("stripe.Charge.create", return_value={"id": "test_charge_id"}) def test_charge_not_send_receipt(self, charge_create_mock, record_charge_mock, send_receipt_mock): self.customer.charge(amount=decimal.Decimal("50.00"), send_receipt=False) self.assertTrue(charge_create_mock.called) record_charge_mock.assert_called_once_with("test_charge_id") self.assertFalse(send_receipt_mock.called) @patch("stripe.InvoiceItem.create") def test_add_invoice_item(self, invoice_item_create_mock): self.customer.add_invoice_item(amount=decimal.Decimal("50.00"), currency="eur", invoice_id=77, description="test") invoice_item_create_mock.assert_called_once_with( amount=5000, currency="eur", invoice=77, description="test", customer=self.customer.stripe_id) def test_add_invoice_item_bad_decimal(self): with self.assertRaisesMessage( ValueError, "You must supply a decimal value representing dollars."): self.customer.add_invoice_item(amount=5000)
def test_sync_from_stripe_data_refunded_on_update( self, subscription_retrieve_mock, product_retrieve_mock, paymentmethod_card_retrieve_mock, payment_intent_retrieve_mock, invoice_retrieve_mock, charge_retrieve_mock, default_account_mock, ): # first sync charge (as per test_sync_from_stripe_data) # then sync refunded version, to hit the update code-path instead of insert from djstripe.settings import STRIPE_SECRET_KEY default_account_mock.return_value = self.account fake_charge_copy = deepcopy(FAKE_CHARGE) with patch( "stripe.BalanceTransaction.retrieve", return_value=deepcopy(FAKE_BALANCE_TRANSACTION), ): charge = Charge.sync_from_stripe_data(fake_charge_copy) self.assertEqual(Decimal("20"), charge.amount) self.assertEqual(True, charge.paid) self.assertEqual(False, charge.refunded) self.assertEqual(True, charge.captured) self.assertEqual(False, charge.disputed) self.assertEqual(len(charge.refunds.all()), 0) fake_charge_refunded_copy = deepcopy(FAKE_CHARGE_REFUNDED) with patch( "stripe.BalanceTransaction.retrieve", return_value=deepcopy(FAKE_BALANCE_TRANSACTION_REFUND), ) as balance_transaction_retrieve_mock: charge_refunded = Charge.sync_from_stripe_data( fake_charge_refunded_copy) self.assertEqual(charge.id, charge_refunded.id) self.assertEqual(Decimal("20"), charge_refunded.amount) self.assertEqual(True, charge_refunded.paid) self.assertEqual(True, charge_refunded.refunded) self.assertEqual(True, charge_refunded.captured) self.assertEqual(False, charge_refunded.disputed) self.assertEqual("Subscription creation", charge_refunded.description) self.assertEqual(charge_refunded.amount, charge_refunded.amount_refunded) charge_retrieve_mock.assert_not_called() balance_transaction_retrieve_mock.assert_called_once_with( api_key=STRIPE_SECRET_KEY, expand=[], id=FAKE_BALANCE_TRANSACTION_REFUND["id"], stripe_account=None, ) refunds = list(charge_refunded.refunds.all()) self.assertEqual(len(refunds), 1) refund = refunds[0] self.assertEqual(refund.id, FAKE_REFUND["id"]) self.assertNotEqual(charge_refunded.balance_transaction.id, refund.balance_transaction.id) self.assertEqual(charge_refunded.balance_transaction.id, FAKE_BALANCE_TRANSACTION["id"]) self.assertEqual(refund.balance_transaction.id, FAKE_BALANCE_TRANSACTION_REFUND["id"]) self.assert_fks( charge_refunded, expected_blank_fks=self.default_expected_blank_fks | { "djstripe.Account.branding_logo", "djstripe.Account.branding_icon" }, )
def test_sync_from_stripe_data_refunded( self, subscription_retrieve_mock, product_retrieve_mock, paymentmethod_card_retrieve_mock, payment_intent_retrieve_mock, invoice_retrieve_mock, charge_retrieve_mock, balance_transaction_retrieve_mock, default_account_mock, ): from djstripe.settings import STRIPE_SECRET_KEY default_account_mock.return_value = self.account fake_charge_copy = deepcopy(FAKE_CHARGE_REFUNDED) charge = Charge.sync_from_stripe_data(fake_charge_copy) self.assertEqual(Decimal("20"), charge.amount) self.assertEqual(True, charge.paid) self.assertEqual(True, charge.refunded) self.assertEqual(True, charge.captured) self.assertEqual(False, charge.disputed) self.assertEqual("Subscription creation", charge.description) self.assertEqual(charge.amount, charge.amount_refunded) charge_retrieve_mock.assert_not_called() # We expect two calls - for charge and then for charge.refunds balance_transaction_retrieve_mock.assert_has_calls([ call( api_key=STRIPE_SECRET_KEY, expand=[], id=FAKE_BALANCE_TRANSACTION["id"], stripe_account=None, ), call( api_key=STRIPE_SECRET_KEY, expand=[], id=FAKE_BALANCE_TRANSACTION_REFUND["id"], stripe_account=None, ), ]) refunds = list(charge.refunds.all()) self.assertEqual(len(refunds), 1) refund = refunds[0] self.assertEqual(refund.id, FAKE_REFUND["id"]) self.assertNotEqual(charge.balance_transaction.id, refund.balance_transaction.id) self.assertEqual(charge.balance_transaction.id, FAKE_BALANCE_TRANSACTION["id"]) self.assertEqual(refund.balance_transaction.id, FAKE_BALANCE_TRANSACTION_REFUND["id"]) self.assert_fks( charge, expected_blank_fks=self.default_expected_blank_fks | { "djstripe.Account.branding_logo", "djstripe.Account.branding_icon" }, )
def test_sync_from_stripe_data_refunded_on_update( self, subscription_retrieve_mock, invoice_retrieve_mock, charge_retrieve_mock, default_account_mock, ): # first sync charge (as per test_sync_from_stripe_data) then sync refunded version, # to hit the update code-path instead of insert from djstripe.settings import STRIPE_SECRET_KEY default_account_mock.return_value = self.account fake_charge_copy = deepcopy(FAKE_CHARGE) with patch("stripe.BalanceTransaction.retrieve", return_value=deepcopy(FAKE_BALANCE_TRANSACTION)): charge = Charge.sync_from_stripe_data(fake_charge_copy) self.assertEqual(Decimal("22"), charge.amount) self.assertEqual(True, charge.paid) self.assertEqual(False, charge.refunded) self.assertEqual(True, charge.captured) self.assertEqual(False, charge.disputed) self.assertEqual(len(charge.refunds.all()), 0) fake_charge_refunded_copy = deepcopy(FAKE_CHARGE_REFUNDED) with patch( "stripe.BalanceTransaction.retrieve", return_value=deepcopy(FAKE_BALANCE_TRANSACTION_REFUND), ) as balance_transaction_retrieve_mock: charge_refunded = Charge.sync_from_stripe_data( fake_charge_refunded_copy) self.assertEqual(charge.id, charge_refunded.id) self.assertEqual(Decimal("22"), charge_refunded.amount) self.assertEqual(True, charge_refunded.paid) self.assertEqual(True, charge_refunded.refunded) self.assertEqual(True, charge_refunded.captured) self.assertEqual(False, charge_refunded.disputed) self.assertEqual("VideoDoc consultation for ivanp0001 berkp0001", charge_refunded.description) self.assertEqual(charge_refunded.amount, charge_refunded.amount_refunded) charge_retrieve_mock.assert_not_called() balance_transaction_retrieve_mock.assert_called_once_with( api_key=STRIPE_SECRET_KEY, expand=[], id=FAKE_BALANCE_TRANSACTION_REFUND["id"]) refunds = list(charge_refunded.refunds.all()) self.assertEqual(len(refunds), 1) refund = refunds[0] self.assertEqual(refund.id, FAKE_REFUND["id"]) self.assertNotEqual(charge_refunded.balance_transaction.id, refund.balance_transaction.id) self.assertEqual(charge_refunded.balance_transaction.id, FAKE_BALANCE_TRANSACTION["id"]) self.assertEqual(refund.balance_transaction.id, FAKE_BALANCE_TRANSACTION_REFUND["id"]) self.assert_fks( charge_refunded, expected_blank_fks={ "djstripe.Account.business_logo", "djstripe.Charge.dispute", "djstripe.Charge.transfer", "djstripe.Customer.coupon", "djstripe.Plan.product", }, )