def test_cancel_handler_clears_paid_status(self): self.user.is_paid = 1 self.user.stripe_customer_id = "fake" self.user.save() pl = PaymentLog(processor=PaymentLog.STRIPE, user_id=self.user.id, status="payment", subscription_id="fake-sub", transaction_serial_number=1) pl.save() # stub out the underlying stripe things fake_plan = Mock() fake_plan.id = options.stripe_annual_plan_id fake_subscription = Mock() fake_subscription.id = "fake-sub" fake_subscription.status = "active" fake_subscription.plan = fake_plan fake_subscription.current_period_start = 1489464525 fake_subscription.current_period_end = 1521000525 fake_subscription.delete.return_value = None customer = stripe.Customer(id=self.user.stripe_customer_id) customer.subscriptions = Mock() customer.subscriptions.data = [fake_subscription] customer.subscriptions.retrieve.return_value = fake_subscription with patch("stripe.Customer") as CustomerMock: CustomerMock.retrieve.return_value = customer response = self.post_url("/account/payment/cancel", {}) user = User.get(self.user.id) self.assertEqual(user.is_paid, 0)
def apply_to_user(self, user_): from models import PaymentLog promotion = self.get_promotion() self.offered_by_user_id = 0 if not self.offered_by_user_id and promotion is not None: shake = promotion.shake() if shake is not None: # if this promotion is related to a shake # associate the voucher with that shake's owner self.offered_by_user_id = shake.user_id now = datetime.datetime.utcnow() # if the user has a voucher, then we need # to apply a credit to their account using # payment_log in addition to creating the # voucher record and claiming it. self.claimed_by_user_id = user_.id self.claimed_at = now.strftime("%Y-%m-%d %H:%M:%S") self.save() # now record to payment_log that this # user has claimed a voucher. next_date = None amount = None promotion = self.get_promotion() # make a sensible "transaction amount" description # that we use for the settings screen if promotion is not None \ and promotion.membership_months > 0: months = promotion.membership_months days = int((365 * (months/12.0)) + 0.5) next_date = now + datetime.timedelta(days=days) if months >= 12 and months % 12 == 0: years = months / 12 if years == 1: amount = '1 Year' elif years > 1: amount = '%d Years' % years elif months == 1: amount = '1 Month' elif months > 1: amount = '%d Months' % months pl = PaymentLog( user_id = user_.id, status = "credit", reference_id = promotion.id, transaction_id = self.voucher_key, operation = "redeem", transaction_date = now.strftime("%Y-%m-%d %H:%M:%S"), next_transaction_date = next_date.strftime("%Y-%m-%d %H:%M:%S"), buyer_email = user_.email, buyer_name = (user_.full_name or user_.name), transaction_amount = amount, payment_reason = "MLTSHP Paid Account", payment_method = "voucher", processor = PaymentLog.VOUCHER, transaction_serial_number = 0 ) pl.save() # update user paid status if necessary if user_.is_paid != 1: user_.is_paid = 1 user_.save() payment_notifications(user_, "redeemed", amount)
def post(self): current_user = self.get_current_user_object() # an existing, paying user can't subscribe again... # we also won't allow users with unconfirmed emails to subscribe # should we message here? if current_user.is_paid == 1 or current_user.email_confirmed != 1: return self.redirect("/account/settings") token_id = self.get_argument("token") if token_id is None: # invalid request raise "Invalid request" customer = None sub = None stripe_customer_id = current_user.stripe_customer_id if stripe_customer_id is not None: try: customer = stripe.Customer.retrieve(stripe_customer_id) except stripe.error.InvalidRequestError: pass if customer and getattr(customer, "deleted", False): customer = None try: if customer is None: # create a new customer object for this subscription customer = stripe.Customer.create( description="MLTSHP user %s" % current_user.name, email=current_user.email, plan=options.stripe_annual_plan_id, card=token_id, # obtained with Checkout.js metadata={"mltshp_user": current_user.name}, ) # if this works, we should have a customer with 1 subscription, this one if customer.subscriptions.total_count > 0: sub = customer.subscriptions.data[0] else: sub = customer.subscriptions.create( plan=options.stripe_annual_plan_id, card=token_id) except stripe.error.CardError as ex: return self.render("account/return-subscription-completed.html", error=unicode(ex)) if not sub: raise Exception("Error issuing subscription") amount = "USD %0.2f" % (sub.plan.amount / 100.0) payment_log = PaymentLog( processor=PaymentLog.STRIPE, user_id=current_user.id, status="subscribed", reference_id=sub.id, # ?? transaction_id=sub.id, # ?? operation="order", transaction_date=datetime.datetime.fromtimestamp( sub.current_period_start).strftime("%Y-%m-%d %H:%M:%S"), next_transaction_date=datetime.datetime.fromtimestamp( sub.current_period_end).strftime("%Y-%m-%d %H:%M:%S"), buyer_email=current_user.email, buyer_name=current_user.display_name(), recipient_email="*****@*****.**", recipient_name="MLTSHP, LLC", payment_reason="MLTSHP Paid Account", transaction_serial_number=1, subscription_id=sub.id, payment_method="CC", transaction_amount=amount, ) payment_log.save() current_user.is_paid = 1 if current_user.stripe_customer_id != customer.id: current_user.stripe_customer_id = customer.id current_user.save() if options.postmark_api_key: pm = postmark.PMMail( api_key=options.postmark_api_key, sender="*****@*****.**", to="*****@*****.**", subject="%s has created a subscription" % (payment_log.buyer_name), text_body= "Subscription ID: %s\nBuyer Name:%s\nBuyer Email:%s\nUser ID:%s\n" % (payment_log.subscription_id, payment_log.buyer_name, payment_log.buyer_email, current_user.id)) pm.send() payment_notifications(current_user, "subscription", amount) return self.render("account/return-subscription-completed.html")
def post(self): current_user = self.get_current_user_object() token_id = None if current_user.stripe_customer_id is None: token_id = self.get_argument("token") if token_id is None: # invalid request raise Exception("Invalid request") plan_id = self.get_argument("plan_id") if plan_id not in ("mltshp-single", "mltshp-double"): raise Exception("Invalid request") quantity = 1 if plan_id == "mltshp-double": quantity = int(float(self.get_argument("quantity"))) if quantity < 24 or quantity > 500: raise "Invalid request" customer = None sub = None stripe_customer_id = current_user.stripe_customer_id if stripe_customer_id is not None: try: customer = stripe.Customer.retrieve(stripe_customer_id) except stripe.error.InvalidRequestError: pass if customer and getattr(customer, "deleted", False): customer = None try: if customer is None: if token_id is None: # FIXME: handle this more gracefully... raise "Invalid request" # create a new customer object for this subscription customer = stripe.Customer.create( description="MLTSHP user %s" % current_user.name, email=current_user.email, metadata={"mltshp_user": current_user.name}, source=token_id, ) # if this works, we should have a customer with 1 subscription, this one if customer.subscriptions.total_count > 0: sub = customer.subscriptions.data[0] if sub.plan != plan_id: sub.plan = plan_id if plan_id == "mltshp-double": sub.quantity = quantity else: sub.quantity = 1 sub.save() else: if plan_id == "mltshp-double": sub = customer.subscriptions.create(plan=plan_id, quantity=quantity) else: sub = customer.subscriptions.create(plan=plan_id) except stripe.error.CardError as ex: return self.render("account/return-subscription-completed.html", error=unicode(ex), has_data_to_migrate=False) if not sub: raise Exception("Error issuing subscription") amount = "USD %0.2f" % ((sub.plan.amount / 100.0) * quantity) payment_log = PaymentLog( processor=PaymentLog.STRIPE, user_id=current_user.id, status="subscribed", reference_id=sub.id, # ?? transaction_id=sub.id, # ?? operation="order", transaction_date=datetime.datetime.fromtimestamp( sub.current_period_start).strftime("%Y-%m-%d %H:%M:%S"), next_transaction_date=datetime.datetime.fromtimestamp( sub.current_period_end).strftime("%Y-%m-%d %H:%M:%S"), buyer_email=current_user.email, buyer_name=current_user.display_name(), recipient_email="*****@*****.**", recipient_name="MLTSHP, Inc.", payment_reason="MLTSHP Membership", transaction_serial_number=1, subscription_id=sub.id, payment_method="CC", transaction_amount=amount, ) payment_log.save() current_user.is_paid = 1 current_user.stripe_plan_id = plan_id if plan_id == "mltshp-double": current_user.stripe_plan_rate = quantity else: current_user.stripe_plan_rate = None if current_user.stripe_customer_id != customer.id: current_user.stripe_customer_id = customer.id current_user.save() if options.postmark_api_key: pm = postmark.PMMail( api_key=options.postmark_api_key, sender="*****@*****.**", to="*****@*****.**", subject="%s has created a subscription" % (payment_log.buyer_name), text_body= "Subscription ID: %s\nBuyer Name:%s\nBuyer Email:%s\nUser ID:%s\n" % (payment_log.subscription_id, payment_log.buyer_name, payment_log.buyer_email, current_user.id)) pm.send() payment_notifications(current_user, "subscription", amount) has_data_to_migrate = not MigrationState.has_migrated(current_user.id) return self.render("account/return-subscription-completed.html", has_data_to_migrate=has_data_to_migrate)
def post(self): # type of message is passed through "type" parameter json_response = json.loads(self.request.body) body_str = json.dumps(json_response).replace("\n", "\\n") stripe_customer_id = None period_start = None period_end = None checkout_id = None status = None subscription_id = None charge_id = None amount = 0 operation = None evt = stripe.convert_to_stripe_object(json_response, options.stripe_secret_key, None) if evt.type == 'invoice.payment_failed': # subscription failed to be paid due to a problem # with the member's credit card or something # for now, just email [email protected] about this stripe_customer_id = evt.data.object.customer subscriber = User.get("stripe_customer_id=%s and deleted=0", stripe_customer_id) if subscriber and options.postmark_api_key: pm = postmark.PMMail( api_key=options.postmark_api_key, sender="*****@*****.**", to="*****@*****.**", subject="%s has a subscription failure" % (subscriber.display_name()), text_body= "Subscription ID: %s\nBuyer Name:%s\nBuyer Email:%s\nUser ID:%s\n" % (subscription_id, subscriber.display_name(), subscriber.email, subscriber.id)) pm.send() return self.finish("OK") elif evt.type == 'customer.subscription.created': # important properties # customer - should be recorded already in account.stripe_customer_id # current_period_start # current_period_end # plan.id (mltshp-annual) stripe_customer_id = evt.data.object.customer period_start = evt.data.object.current_period_start period_end = evt.data.object.current_period_end checkout_id = evt.data.object.id status = "subscribed" # evt.type operation = "subscribe" subscription_id = evt.data.object.id amount = evt.data.object.plan.amount elif evt.type == "customer.subscription.deleted": stripe_customer_id = evt.data.object.customer period_start = evt.data.object.current_period_start period_end = evt.data.object.current_period_end status = "canceled" # evt.type operation = "cancel" subscription_id = evt.data.object.id elif evt.type == 'invoice.payment_succeeded': # customer # date # lines.subscriptions[0].plan.id # period.start # period.end # total line_items = [ item for item in evt.data.object.lines.data if item.type == "subscription" and item.plan.id in (options.stripe_annual_plan_id, options.stripe_monthly_plan_id) ] if line_items: line_item = line_items[0] stripe_customer_id = evt.data.object.customer period_start = line_item.period.start period_end = line_item.period.end checkout_id = evt.data.object.id status = "payment" # evt.type operation = "pay" subscription_id = evt.data.object.subscription charge_id = evt.data.object.charge amount = evt.data.object.total else: # unsupported event type; just ignore it return self.finish("OK") subscriber = None if stripe_customer_id: subscriber = User.get("stripe_customer_id=%s and deleted=0", stripe_customer_id) if subscriber is None: # raise an exception for this... #raise Exception("failed to locate user for stripe_customer_id %s" # % stripe_customer_id) return self.finish("OK") #create a payment log record amount = "USD %0.2f" % (amount / 100.0) pl = PaymentLog(user_id=subscriber.id, status=status, reference_id=checkout_id, transaction_id=charge_id, operation=operation, transaction_date=datetime.datetime.fromtimestamp( period_start).strftime("%Y-%m-%d %H:%M:%S"), next_transaction_date=datetime.datetime.fromtimestamp( period_end).strftime("%Y-%m-%d %H:%M:%S"), buyer_email=subscriber.email, buyer_name=subscriber.display_name(), recipient_email="*****@*****.**", recipient_name="MLTSHP, LLC", payment_reason="MLTSHP Paid Account", transaction_serial_number=1, subscription_id=subscription_id, payment_method='CC', transaction_amount=amount, processor=PaymentLog.STRIPE) pl.save() if evt.type == "customer.subscription.deleted": subscriber.is_paid = 0 else: subscriber.is_paid = 1 subscriber.save() return self.finish("OK")