parent
d5705e1eb6
commit
cc08f85297
@ -1,127 +1,457 @@
|
||||
"""
|
||||
This file is a wrapper for stripe and store handling operations :
|
||||
- subscribe
|
||||
- user
|
||||
- upgrade
|
||||
- downgrade
|
||||
- plans (for a given product)
|
||||
|
||||
@TODO:
|
||||
- Add logging using transport
|
||||
"""
|
||||
import stripe
|
||||
from utils.params import PARAMS as SYS_ARGS
|
||||
from utils import void
|
||||
import json
|
||||
class User :
|
||||
def __init__(self,email,plans):
|
||||
self.plans = plans
|
||||
self.me = {"plan":[],"customer":{},"payments":[]}
|
||||
self.init(email)
|
||||
self.format() #-- creating properties
|
||||
pass
|
||||
def info(self):
|
||||
return self.me['customer']
|
||||
def _add_card(self,card):
|
||||
try:
|
||||
stripe.token.Token.create(customer=self.me["customer"]['id'],card=card)
|
||||
self.init(self.me["customer"]['email'])
|
||||
return 1
|
||||
except Exception as error :
|
||||
print (error)
|
||||
return 0
|
||||
def charge(self,**args) :
|
||||
"""
|
||||
This function will charge a user for a service (given a plan id)
|
||||
:plan_id plan identifier for the current product
|
||||
:card_index provide a token (otherwise will use a valid card)
|
||||
"""
|
||||
plan_id = args['plan_id']
|
||||
if len(self.me["payments"]) == 1 :
|
||||
card_index = 0
|
||||
else:
|
||||
card_index = args['card_index']
|
||||
plan = [item[plan_id] for item in self.plans if item['id'] == plan_id]
|
||||
|
||||
class Store :
|
||||
# stripe_keys = {
|
||||
# "secret_key":SYS_ARGS['stripe']['secret'].strip(),
|
||||
# "publishable_key":SYS_ARGS['stripe']['pub'].strip()
|
||||
# }
|
||||
# stripe.api_key = self.stripe_keys['secret_key']
|
||||
card = {} if plan['amount'] == 0 else self.me["payments"][card_index]
|
||||
params = {}
|
||||
|
||||
def __init__(self,**args):
|
||||
self.get = void()
|
||||
self.get.user = self._get_user
|
||||
self.get.plans = self._get_plans
|
||||
product_name = args['product']
|
||||
stripe.api_key = args['secret'] if 'secret' in args else stripe.api_key
|
||||
if stripe.api_key :
|
||||
params['customer'] = self.me["customer"]['id']
|
||||
params ['amount'] = plan['amount']
|
||||
params ['currency'] = plan['currency']
|
||||
params ['description'] = " ".join([self.product['statement_descriptor'],plan['nickname']])
|
||||
if 'source' in card :
|
||||
params ['source'] = card['source']
|
||||
|
||||
self.__init_product(product_name)
|
||||
else:
|
||||
print (['secret' in args, stripe.api_key is None])
|
||||
stripe.charge.Charge.create(params)
|
||||
del params['amount'], params['currency']
|
||||
|
||||
stripe.invoice.Invoice.create(**params)
|
||||
pass
|
||||
def __init_product(self,product_name):
|
||||
PRODUCT_INDEX = 2
|
||||
DATA_TYPE_INDEX = 1
|
||||
STATUS_INDEX = 0
|
||||
resp = stripe.product.Product.list().to_dict_recursive()['data']
|
||||
self.product = []
|
||||
self.plan = []
|
||||
|
||||
if resp :
|
||||
def format(self):
|
||||
|
||||
if resp :
|
||||
self.product = [p for p in resp if p['name'] == product_name]
|
||||
self.product = self.product[0] if self.product else []
|
||||
else:
|
||||
self.product = resp[0]
|
||||
self.plan = void()
|
||||
self.plan.info = lambda: self.me["plan"]
|
||||
# self.user.plan.cancel = lambda id: stripe.subscription.Subscription.delete(self.customer['id'],prorate=True,invoice_now=True)
|
||||
|
||||
if 'id' in self.product :
|
||||
self.__init_plan(self.product['id'])
|
||||
self.card = void ()
|
||||
self.card.exists = lambda: len(self.me["payments"]) > 0
|
||||
self.card.add = self._add_card
|
||||
self.card.charge = self.charge
|
||||
self.card.html = lambda: [{} for card in self.me["payments"]]
|
||||
self.card.delete = lambda index: stripe.customer.Customer.delete_source(self.me["customer"]['id'],self.me["payment"][index])
|
||||
|
||||
def init(self,email):
|
||||
#
|
||||
# get customer information
|
||||
# email = args['email']
|
||||
# self.user_plan = []
|
||||
# self.customer = {}
|
||||
customers = stripe.customer.Customer.list(email=email).to_dict_recursive()['data']
|
||||
if customers :
|
||||
customers = customers[0]
|
||||
else:
|
||||
#
|
||||
# The user doesn't exist, we must create the user (without payment initially)
|
||||
# We can probably assign the user to a free plan if available
|
||||
#
|
||||
customers = stripe.customer.Customer.Create(email=email)
|
||||
free_plan = [item for item in self.plans if item['amount'] == 0]
|
||||
if free_plan :
|
||||
free_plan = free_plan[0]
|
||||
self.plan.subscribe(free_plan['id'],email)
|
||||
# self.customer = {"email":email,"id":customers['id']}
|
||||
self.me["customer"] = {"email":email,"id":customers['id']}
|
||||
#
|
||||
# extract payments available,
|
||||
if 'sources' in customers and 'data' in customers['sources'] :
|
||||
if customers['sources']['data'] :
|
||||
# self.payment = [ card.to_dict_recursive() for card in customers['sources']['data'] ]
|
||||
self.me['payments'] = [ card.to_dict_recursive() for card in customers['sources']['data'] ]
|
||||
info = customers #self.me['customer']
|
||||
subscriptions = info['subscriptions']['data']
|
||||
ids = [plan['id'] for plan in self.plans ]
|
||||
_found = None
|
||||
for sub in subscriptions :
|
||||
aplan = sub['plan']
|
||||
|
||||
def __init_plan(self,id):
|
||||
if set([aplan['id']]) & set(ids):
|
||||
_found = sub.to_dict_recursive()
|
||||
break
|
||||
self.me["plan"] = _found if _found else []
|
||||
# self.user_plan = _found if _found else None
|
||||
class Store :
|
||||
def __init__(self,**args):
|
||||
"""
|
||||
This function will retrieve plan information associated with the given product id
|
||||
Creating an instance of a store. A store is a proxy to stripe (https://stripe.com)
|
||||
:name name of the product
|
||||
:secret stripe api key
|
||||
"""
|
||||
self.plans = stripe.plan.Plan.list(product=id).to_dict_recursive()['data']
|
||||
|
||||
self.products = []
|
||||
self.plans = []
|
||||
self.product = {}
|
||||
|
||||
def _get_user(self,**args):
|
||||
product_name = args['name']
|
||||
stripe.api_key = args['secret'] if 'secret' in args else stripe.api_key
|
||||
resp = stripe.product.Product.list().to_dict_recursive()['data']
|
||||
if resp :
|
||||
self.products = [item.to_dict_recursive() for item in resp]
|
||||
if len(self.products) > 1 :
|
||||
self.product = [item for item in self.products if item['name'] == product_name]
|
||||
self.product = self.product[0] if self.product else []
|
||||
else:
|
||||
self.product = self.products[0]
|
||||
#
|
||||
# if we have a product we should get the list of plans associated
|
||||
#
|
||||
def init(self,email):
|
||||
"""
|
||||
This function will return a customer information and associated plan (hopefully)
|
||||
This function pulls a user's information, think of it like a customer walks into a store ...
|
||||
:email
|
||||
"""
|
||||
email = args['email']
|
||||
customers = stripe.customer.Customer.list(email=email).to_dict_recursive()['data']
|
||||
if not customers:
|
||||
return None
|
||||
else:
|
||||
customers = customers[0]
|
||||
return {"email":email,"id":customers['id']}
|
||||
|
||||
pass
|
||||
def __cancel_plan(self,**args) :
|
||||
pass
|
||||
def __set_charge(self,**args):
|
||||
pass
|
||||
def __set_plan(self,**args):
|
||||
|
||||
class Plans(Store) :
|
||||
def __init__(self,**args):
|
||||
"""
|
||||
This function is effectively a subscription for the current user
|
||||
This function will retrieve plan information associated with the given product id
|
||||
"""
|
||||
plan = args['plan']
|
||||
email = args['email']
|
||||
user_plan = args['user_plan'] if 'user_plan' in args else self.get.plans(email=email)
|
||||
if plan == user_plan :
|
||||
#
|
||||
# There is nothing to do here
|
||||
pass
|
||||
Store.__init__(self,**args)
|
||||
self.plans = stripe.plan.Plan.list(product=self.product['id']).to_dict_recursive()['data']
|
||||
for item in self.plans :
|
||||
index = self.plans.index(item)
|
||||
self.plans[index] = item.to_dict_recursive()
|
||||
if 'features' in self.plans[index]['metadata'] :
|
||||
self.plans[index]['metadata']['features'] = json.loads(self.plans[index]['metadata']['features'])
|
||||
self.plans.sort(key=lambda item: item['amount'])
|
||||
if 'email' in args :
|
||||
self.user = User(args['email'],self.plans)
|
||||
else:
|
||||
self.user = None
|
||||
# self.plans = [item.to_dict_recursive() for item in self.plans]
|
||||
self.format()
|
||||
def format(self):
|
||||
self.get = void()
|
||||
self.get.plans = lambda:self.plans
|
||||
self.get.products = lambda:self.products
|
||||
self.plan = void()
|
||||
self.plan.upgrade = self.upgrade
|
||||
self.plan.cancel = self.cancel
|
||||
self.plan.subscribe = self.subscribe
|
||||
def cancel(self,id) :
|
||||
"""
|
||||
This function will cancel a subscription given a user's email/or a subscription for the given product/user
|
||||
We are assuming one subscription one plan, no complex billing is involved (not good for startups)
|
||||
:email,subscription
|
||||
"""
|
||||
stripe.subscription.Subscription.delete(id,prorate=True,invoice_now=True)
|
||||
pass
|
||||
def upgrade(self,id,email):
|
||||
"""
|
||||
A change of plan suggests cancelling the current plan and assigning a new one.
|
||||
If it's a paid plan, the calling code must insure the user has an active token
|
||||
"""
|
||||
if not self.user and email:
|
||||
self.user = User(email,self.plans)
|
||||
|
||||
sub_id = self.user.plan.info()['id']
|
||||
try:
|
||||
self.cancel(sub_id)
|
||||
self.subscribe(id,email)
|
||||
#
|
||||
# we need to cancel, the user_plan unless it is free
|
||||
# We need to reload everything
|
||||
self.user.init(email)
|
||||
except Exception as error :
|
||||
print (error) ;
|
||||
return 0
|
||||
return 1
|
||||
|
||||
pass
|
||||
pass
|
||||
def _get_plans(self,**args) :
|
||||
def subscribe(self,id,email):
|
||||
"""
|
||||
The product name is provided in the constructor and at this poit, if a user email is not provided,
|
||||
This function operates as an accessor to the plans attribute. If an email is provided
|
||||
The function will return the plans associated for a user given the current product.
|
||||
|
||||
:email user email
|
||||
Subscribe a user to a given plan assuming the user has already been initialized
|
||||
The responsibility falls upon the calling code to perform the cancellatioin of the existing plan and perform an upgrade
|
||||
"""
|
||||
if 'email' in args :
|
||||
#
|
||||
email = args['email']
|
||||
info = stripe.customer.Customer.list(email=email).to_dict_recursive()['data']
|
||||
if not self.user :
|
||||
self.user = User(email,self.plans)
|
||||
plan = {"plan": id}
|
||||
amount = sum([item['amount'] for item in self.plans if item['id'] == 0])
|
||||
|
||||
if info :
|
||||
#
|
||||
if 'email' in self.user.info() and email == self.user.info()['email'] :
|
||||
email = self.user.info()['email']
|
||||
else:
|
||||
self.user.init(email)
|
||||
#
|
||||
_found = None
|
||||
ids = [plan['id'] for plan in self.plans ]
|
||||
subscriptions = info[0]['subscriptions']['data']
|
||||
for sub in subscriptions :
|
||||
aplan = sub['plan']
|
||||
if set([aplan['id']]) & set(ids):
|
||||
_found = sub
|
||||
break
|
||||
# We must insure the user is one of our customers i.e perhaps
|
||||
if amount == 0 or self.payment :
|
||||
stripe.subscription.Subscription.create(
|
||||
customer=self.user.info()['id'], #if not email else email,
|
||||
items=[plan]
|
||||
)
|
||||
return 1
|
||||
else:
|
||||
return 0
|
||||
class factory:
|
||||
@staticmethod
|
||||
def instance (**args) :
|
||||
return Plans(**args)
|
||||
|
||||
info = _found if _found else None
|
||||
# if 'email' in args :
|
||||
# store = Plans(**args)
|
||||
|
||||
# else:
|
||||
# store = Plans(**args)
|
||||
# return store
|
||||
# class _Store :
|
||||
# # stripe_keys = {
|
||||
# # "secret_key":SYS_ARGS['stripe']['secret'].strip(),
|
||||
# # "publishable_key":SYS_ARGS['stripe']['pub'].strip()
|
||||
# # }
|
||||
# # stripe.api_key = self.stripe_keys['secret_key']
|
||||
|
||||
# def __init__(saelf,**args):
|
||||
# self.payment = []
|
||||
# self.user_plan = {}
|
||||
# self.customer = {}
|
||||
|
||||
# self.get = void()
|
||||
# # self.get.user = void()
|
||||
# # self.get.user.info = self._get_user
|
||||
# # self.get.user.plan = lambda: self.user_plan if self.user_plan else None
|
||||
|
||||
|
||||
# # self.add = void()
|
||||
# # self.add.user = self.init
|
||||
# # self.add.card = lambda card: stripe.token.Token.create(customer=customer['id'],card=card)
|
||||
|
||||
# self.user = void()
|
||||
# self.user.init = self.init
|
||||
# self.user.info = self._get_user
|
||||
# self.user.plan = void()
|
||||
# self.user.plan.info = lambda: self.user_plan if self.user_plan else None
|
||||
# # self.user.plan.cancel = lambda id: stripe.subscription.Subscription.delete(self.customer['id'],prorate=True,invoice_now=True)
|
||||
|
||||
# self.user.card = void ()
|
||||
# self.user.card.exists = lambda: len(self.payment) > 0
|
||||
# self.user.card.add = self._add_card
|
||||
# self.user.card.charge = self._apply_charge
|
||||
# self.user.card.html = lambda: [{} for card in self.payment]
|
||||
# self.user.card.delete = lambda index: stripe.customer.Customer.delete_source(self.customer['id'],self.payment[index])
|
||||
|
||||
# self.get.plans = self._get_plans
|
||||
|
||||
|
||||
# self.has = void ()
|
||||
|
||||
# product_name = args['product']
|
||||
# stripe.api_key = args['secret'] if 'secret' in args else stripe.api_key
|
||||
# if stripe.api_key :
|
||||
# self.__init_product(product_name)
|
||||
# else:
|
||||
# print (['secret' in args, stripe.api_key is None])
|
||||
# self.plan = void()
|
||||
# self.plan.cancel = self.__cancel_plan
|
||||
# self.plan.subscribe = self.__subscribe_plan
|
||||
# self.plan.upgrade = self.__upgrade_plan
|
||||
# def _apply_charge(self,**args) :
|
||||
# """
|
||||
# This function will charge a user for a service (given a plan id)
|
||||
# :plan_id plan identifier for the current product
|
||||
# :card_index provide a token (otherwise will use a valid card)
|
||||
# """
|
||||
# plan_id = args['plan_id']
|
||||
# if len(self.payment) == 1 :
|
||||
# card_index = 0
|
||||
# else:
|
||||
# card_index = args['card_index']
|
||||
# plan = [item[plan_id] for item in self.plans if item['id'] == plan_id]
|
||||
|
||||
# card = {} if plan['amount'] == 0 else self.payment[card_index]
|
||||
# params = {}
|
||||
|
||||
# params['customer'] = self.customer['id']
|
||||
# params ['amount'] = plan['amount']
|
||||
# params ['currency'] = plan['currency']
|
||||
# params ['description'] = " ".join([self.product['statement_descriptor'],plan['nickname']])
|
||||
# if 'source' in card :
|
||||
# params ['source'] = card['source']
|
||||
|
||||
# stripe.charge.Charge.create(params)
|
||||
# del params['amount'], params['currency']
|
||||
|
||||
# stripe.invoice.Invoice.create(**params )
|
||||
# pass
|
||||
# def __init_product(self,product_name):
|
||||
# PRODUCT_INDEX = 2
|
||||
# DATA_TYPE_INDEX = 1
|
||||
# STATUS_INDEX = 0
|
||||
# resp = stripe.product.Product.list().to_dict_recursive()['data']
|
||||
# self.product = []
|
||||
# self.plan = []
|
||||
# if resp :
|
||||
|
||||
# if resp :
|
||||
# self.product = [p.to_dict_recursive() for p in resp if p['name'] == product_name]
|
||||
# self.product = self.product[0] if self.product else []
|
||||
# else:
|
||||
# self.product = resp[0]
|
||||
|
||||
# if 'id' in self.product :
|
||||
# self.__init_plan(self.product['id'])
|
||||
|
||||
# def __init_plan(self,id):
|
||||
# """
|
||||
# This function will retrieve plan information associated with the given product id
|
||||
# """
|
||||
# self.plans = stripe.plan.Plan.list(product=id).to_dict_recursive()['data']
|
||||
# for item in self.plans :
|
||||
# index = self.plans.index(item)
|
||||
# self.plans[index] = item.to_dict_recursive()
|
||||
# if 'features' in self.plans[index]['metadata'] :
|
||||
# self.plans[index]['metadata']['features'] = json.loads(self.plans[index]['metadata']['features'])
|
||||
# #
|
||||
# # sort items by amounts
|
||||
# #
|
||||
# self.plans.sort(key=lambda item: item['amount'])
|
||||
# # self.plans = [item.to_dict_recursive() for item in self.plans]
|
||||
|
||||
# def init(self,email):
|
||||
# #
|
||||
# # get customer information
|
||||
# # email = args['email']
|
||||
# self.user_plan = []
|
||||
# self.customer = {}
|
||||
# customers = stripe.customer.Customer.list(email=email).to_dict_recursive()['data']
|
||||
# if customers :
|
||||
# customers = customers[0]
|
||||
# else:
|
||||
# #
|
||||
# # The user doesn't exist, we must create the user (without payment initially)
|
||||
# # We can probably assign the user to a free plan if available
|
||||
# #
|
||||
# customers = stripe.customer.Customer.Create(email=email)
|
||||
# free_plan = [item for item in self.plans if item['amount'] == 0]
|
||||
# if free_plan :
|
||||
# free_plan = free_plan[0]
|
||||
# self.plan.subscribe(free_plan['id'],email)
|
||||
# self.customer = {"email":email,"id":customers['id']}
|
||||
# #
|
||||
# # extract payments available,
|
||||
# if 'sources' in customers and 'data' in customers['sources'] :
|
||||
# if customers['sources']['data'] :
|
||||
# self.payment = [ card.to_dict_recursive() for card in customers['sources']['data'] ]
|
||||
# #
|
||||
# # user plans
|
||||
# info = customers
|
||||
# subscriptions = info['subscriptions']['data']
|
||||
# ids = [plan['id'] for plan in self.plans ]
|
||||
# _found = None
|
||||
# for sub in subscriptions :
|
||||
# aplan = sub['plan']
|
||||
|
||||
# if set([aplan['id']]) & set(ids):
|
||||
# _found = sub.to_dict_recursive()
|
||||
# break
|
||||
|
||||
# self.user_plan = _found if _found else None
|
||||
# def _get_user(self,**args):
|
||||
# """
|
||||
# This function will return a customer information and associated plan (hopefully)
|
||||
# :email
|
||||
# """
|
||||
# return self.customer
|
||||
|
||||
# def __cancel_plan(self,id) :
|
||||
# """
|
||||
# This function will cancel a subscription given a user's email/or a subscription for the given product/user
|
||||
# We are assuming one subscription one plan, no complex billing is involved (not good for startups)
|
||||
# :email,subscription
|
||||
# """
|
||||
# stripe.subscription.Subscription.delete(id,prorate=True,invoice_now=True)
|
||||
# pass
|
||||
# def __upgrade_plan(self,id,email=None):
|
||||
# """
|
||||
# A change of plan suggests cancelling the current plan and assigning a new one.
|
||||
# If it's a paid plan, the calling code must insure the user has an active token
|
||||
# """
|
||||
# email = self.customer['email'] if email is None else email
|
||||
# sub_id = self.user.plan.info()['id']
|
||||
# try:
|
||||
# self.plan.cancel(sub_id)
|
||||
# self.plan.subscribe(id,email)
|
||||
# #
|
||||
# # We need to reload everything
|
||||
# self.user.init(email)
|
||||
# except Exception as error :
|
||||
# print (error) ;
|
||||
# return 0
|
||||
# return 1
|
||||
|
||||
# pass
|
||||
# def __subscribe_plan(self,id,email):
|
||||
# """
|
||||
# Subscribe a user to a given plan assuming the user has already been initialized
|
||||
# The responsibility falls upon the calling code to perform the cancellatioin of the existing plan and perform an upgrade
|
||||
# """
|
||||
|
||||
# plan = {"plan": id}
|
||||
# amount = sum([item['amount'] for item in self.plans if item['id'] == 0])
|
||||
|
||||
# if 'email' in self.customer and email == self.customer['email'] :
|
||||
# email = self.customer['email']
|
||||
# else:
|
||||
# self.init(email)
|
||||
# #
|
||||
# # We must insure the user is one of our customers i.e perhaps
|
||||
# if amount == 0 or self.payment :
|
||||
# stripe.subscription.Subscription.create(
|
||||
# customer=self.customer['id'], #if not email else email,
|
||||
# items=[plan]
|
||||
# )
|
||||
# return 1
|
||||
# else:
|
||||
# return 0
|
||||
|
||||
else:
|
||||
info = None
|
||||
return info
|
||||
else :
|
||||
|
||||
return self.plans
|
||||
# def _add_card(self,card):
|
||||
# try:
|
||||
# stripe.token.Token.create(customer=customer['id'],card=card)
|
||||
# self.user.init(self.customer['email'])
|
||||
# return 1
|
||||
# except Exception as error :
|
||||
# print (error)
|
||||
# return 0
|
||||
|
||||
# def _get_plans(self,**args) :
|
||||
# """
|
||||
# This function will provide an plan for a given user given an email or the list of plans
|
||||
# :email user email
|
||||
# """
|
||||
# return self.user_plan if 'email' in args else self.plans
|
||||
|
||||
|
Loading…
Reference in new issue