i am working on django application where admin can set pricing,and give coupon, my proble is how to offer a free option or free listing whe you are using stripe.
this is a function on my views.py
`#login_required(login_url='/users/login')
def create_ad_func(request):
user = request.user
if request.method == "POST":
data = dict(request.POST)
data = clean(data)
ad = AdList.objects.create_ad(**data)
img_counter = 0
img_files = request.FILES
if len(request.FILES) > 0:
for ad_img in request.FILES:
print(img_files[ad_img])
upload_img(ad_img, img_files, ad)
else:
url = upload_image(request.FILES[ad_img], ad.id, img_counter)
img_counter = img_counter + 1
data[ad_img] = url
date_time = arrow.utcnow().format('YYYY-MM-DD HH:mm:ss')
data['post_date'] = date_time
pprint(data)
AdList.objects.filter(pk=ad.id).update(**data)
objectss = AdList.objects.filter(pk=ad.id)
subscription_list = ['urgent_ad', 'regular_ad', 'featured_ad']
for key in data.keys():
if key in subscription_list:
ad_subscription = AdSubscription.objects.values()[0]
price = ad_subscription[key]
charge = ad_subscription[key] * 100
print(price, charge)
key = settings.STRIPE_PUBLISHABLE_KEY
return render(request, 'checkout.html', {"user": request.user, 'ad': ad, 'price':price, 'key':key, 'charge':charge})
else:
ad_subscription = AdSubscription.objects.values()[0]
return render(request, 'ad-list-cat.html', {"user": request.user, "subscription": ad_subscription})
and this is my manage.py
class AdListManager(BaseUserManager):
"""
Custom user model manager where email is the unique identifiers
for authentication instead of usernames.
"""
def create_ad(self, **data):
"""
Create and save a User with the given email and password.
"""
email = data["email"]
email = self.normalize_email(email)
ad = self.model(**data)
ad.save()
message="your ad was published successiful"
return ad,message
def update_ad(self, pk, data):
pprint(data)
self.model.objects.filter(pk=pk).update(**data)
def list_ads(self, email):
return self.model.objects.filter(email=email)
i tried to modify so that if the value is les than <5 charge 0 but problem is that stripe do not accepte zero charge.
this is what i tried.
#login_required(login_url='/users/login')
def create_ad_func(request):
user = request.user
if request.method == "POST":
data = dict(request.POST)
data = clean(data)
ad = AdList.objects.create_ad(**data)
img_counter = 0
img_files = request.FILES
if len(request.FILES) > 0:
for ad_img in request.FILES:
print(img_files[ad_img])
upload_img(ad_img, img_files, ad)
else:
url = upload_image(request.FILES[ad_img], ad.id, img_counter)
img_counter = img_counter + 1
data[ad_img] = url
date_time = arrow.utcnow().format('YYYY-MM-DD HH:mm:ss')
data['post_date'] = date_time
pprint(data)
AdList.objects.filter(pk=ad.id).update(**data)
objectss = AdList.objects.filter(pk=ad.id)
subscription_list = ['urgent_ad', 'regular_ad', 'featured_ad']
for key in data.keys():
if key in subscription_list:
ad_subscription = AdSubscription.objects.values()[0]
if ad_subscription[key] < 5:
# save the subscription without charging with stripe
ad.subscriptions.create(
items=[{
'price': 'price_id',
'quantity': 1,
}],
expand=['latest_invoice.payment_intent']
)
price = 0
charge = 0
else:
price = ad_subscription[key]
charge = ad_subscription[key] * 100
key = settings.STRIPE_PUBLISHABLE_KEY
return render(request, 'checkout.html', {"user": request.user, 'ad': ad, 'price':price, 'key':key, 'charge':charge})
else:
ad_subscription = AdSubscription.objects.values()[0]
return render(request, 'ad-list-cat.html', {"user": request.user, "subscription": ad_subscription})
any help to archive an option of adding a free listing option while using stripe?`
I guess you want to offer a free trial for you customer? If so, you can specify a trial_end or trial_period_days when creating a subscription. Alternatively, you can also use a coupon to apply discounts to invoices generated for this particular subscription.
Related
I have a Django view that signs a user up to a free trial through Stripe. When the view makes a POST request, it does so twice.
I've tried idempotency keys, both after the if request.method == 'POST' line and in the initial rendering of the view. The customer in Stripe always ends up with two identical payment sources and two identical subscriptions to the plan.
def start_trial(request):
title = 'get started'
description = title
form = MembershipForm()
key = settings.STRIPE_PUBLISHABLE_KEY
trial_days = 30
coupon = None
custom_message = ''
subscription_idempotency = str(uuid.uuid4())
source_idempotency = str(uuid.uuid4())
try:
vendor = Vendor.objects.get(user=request.user)
custom_message = vendor.message
coupon = Coupon.objects.get(vendor.coupon)
coupon = coupon.stripe_coupon_id
trial_days = vendor.trial_days
except Vendor.DoesNotExist:
pass
try:
partner = Partner.objects.get(user=request.user)
custom_message = partner.message
coupon = Coupon.objects.get(partner.coupon)
coupon = coupon.stripe_coupon_id
trial_days = partner.trial_days
except Partner.DoesNotExist:
pass
if request.method == 'POST':
form = MembershipForm(request.POST)
if form.is_valid():
user = request.user
plan = Membership.objects.get(type_of=form.cleaned_data['plan'])
# stripe needs to attempt to create a customer
# TODO what if there's already a membership/subscription?
user_membership = UserMembership.objects.get(user=request.user)
stripe_subscription = stripe.Subscription.create(
customer=user_membership.stripe_customer_id,
items=[
{"plan": plan.stripe_plan_id}
],
trial_period_days=trial_days,
coupon=coupon,
idempotency_key=subscription_idempotency,
)
subscription = Subscription.objects.create(
user_membership=user_membership, stripe_subscription_id=stripe_subscription.id)
subscription.save()
stripe.Customer.create_source(user_membership.stripe_customer_id,
source=request.POST.get('stripeToken'),
idempotency_key=source_idempotency)
user_membership.membership = plan
user_membership.save()
user.is_subscriber = True
user.save()
# if subscription status is incomplete, display error.
# if passes, redirect to onboarding
message = 'yay'
messages.success(request, message=message)
return HttpResponseRedirect('/onboarding/')
return render(request, 'memberships/free_trial.html',
{'title': title, 'description': description, 'form': form,
'key': key, 'custom_message': custom_message})
Data always ends up in Stripe twice. Log shows:
[18/Jun/2019 11:05:21] "POST /memberships/free-trial/ HTTP/1.1" 302 0
[18/Jun/2019 11:05:22] "POST /memberships/free-trial/ HTTP/1.1" 302 0
Thanks to #duck for pointing me in the right direction. I had unseen (to me) JavaScript duplicating what was happening in the view. Removed the offending file and the problem is solved.
In my view function, I'm trying to make 2 modifications to the current user; consider him a premium subscriber by marking model field is_premium_subscriber as True and adding him to a group named Premium Agents.
However the changes don't seem to be registering in my views.py! Here is my code:
def payment_response(request):
new_charge = PremiumSubscriptionCharge()
if request.method == "POST":
... Some code here
try:
... lots of code here
new_charge.agent = request.user # This line is working fine, meaning request.user is properly assigned to the current user
request.user.is_premium_subscriber = True # This is not working, is_premium_subscriber is still false after the request
premium_agent_group = Group.objects.get(name='Premium Agents')
premium_agent_group.user_set.add(request.user) # This is not working either, the current user does not get added to the group.
request.user.save() # I don't know if this is necessary, but I put it here just in case.
except stripe.error.CardError as ce:
... some code
else:
... some code
My user model for reference. I created a custom User model by inheriting AbstractUser... could this have caused the issue?
class Agent(AbstractUser):
is_premium_subscriber = models.BooleanField(default=False)
Full views function:
def payment_response(request):
new_charge = PremiumSubscriptionCharge()
if request.method == "POST":
token = request.POST.get("stripeToken")
try:
customer = stripe.Customer.create(
email = request.user.email,
source = token,
)
charge = stripe.Charge.create(
amount = 1500,
currency = 'cad',
customer = customer.id,
description = "Agent Premium Subscription"
)
subscription = stripe.Subscription.create(
customer=customer.id,
items=[
{
"plan": "premiumagent",
},
],
)
new_charge.stripe_charge_id = charge.id
new_charge.agent = request.user
new_charge.customer = charge.customer
new_charge.stripe_subscription_id = subscription.id
request.user.is_premium_subscriber = True
premium_agent_group = Group.objects.get(name='Premium Agents')
premium_agent_group.user_set.add(request.user)
request.user.save()
except stripe.error.CardError as ce:
return False, ce
else:
new_charge.save()
return redirect("payment_success")
Okay I was working on something else, came back to it, and now it is working. What the. Thank you to those who commented.
I have inherited some code that was handled by multiple developers, and as such, there is no standard for the product. I am having significant performance issues, and am remedying a lot of them, but don't know how to break this one down. When the user submits on a page that pre-populates with data, and allows the user to select a date for the activity, they can submit, and anything with a date goes away for them. The problem is within the views.py. When the user submits, the following code runs, and hangs up at formset = formset(request.POST). I'm assuming that there are multiple db calls happening, but am not seeing them when I print to terminal. Below is the entirety of the submission process.
STATES = ['Routed','Reconciled']
formset = None
form = StudyOnlyForm()
study_pk = request.GET.get('study', '0')
if study_pk == '' or study_pk == '0':
study_pk = 0
# child transactions that are 'Recoginzed',
# reportable with a 'Routed' parent
qs = Transaction.objects.filter(contract__reportable=True,
cleared = False,
contract__study__pk=study_pk,
transaction_status='Recognized',
parent_transaction__isnull=False,
parent_transaction__transaction_status__in=STATES)
#Designed to capture standalone contracts
qs1 = Transaction.objects.filter(contract__reportable=True,
cleared = False,
contract__study__pk=study_pk,
contract__contract_type__name='Standalone',
transaction_status__in=STATES)
#Captures Arms contracts for Milestone payments
parent_list = []
arms_list = []
parent = Transaction.objects.filter(parent_transaction__isnull=True,
contract__reportable=True,
cleared = False,
contract__study__pk=study_pk,
contract__contract_type__name='ARMs',
transaction_status__in=STATES)
children = Transaction.objects.filter(contract__reportable=True,
cleared = False,
contract__study__pk=study_pk,
transaction_status='Recognized',
contract__contract_type__name='ARMs',
parent_transaction__isnull=False,
parent_transaction__transaction_status__in=STATES)
for child_item in children:
parent_list.append(child_item.parent_transaction.pk)
arms_list.append(child_item.pk)
for parent_item in parent:
if parent_item.pk not in parent_list:
arms_list.append(parent_item.pk)
qs3 = Transaction.objects.filter(pk__in=arms_list)
qs4 = qs | qs1 | qs3
qs = qs4.order_by('-pk')
formset = modelformset_factory(Transaction, form=PaidDateForm, extra=0, can_delete=False)
if request.method == "POST":
print 'if request.POST'
print datetime.datetime.now()
formset = formset(request.POST)
print 'created formset'
print datetime.datetime.now()
if formset.is_valid():
print 'formset valid'
print datetime.datetime.now()
updated_transactions = formset.save(commit=False)
print 'updated transactions'
print datetime.datetime.now()
for trans in updated_transactions:
if trans.paid_amount is not None and trans.date_cleared is not None:
trans_to_change = Transaction.objects.get(pk=trans.pk)
trans_to_change.paid_amount = trans.paid_amount
trans_to_change.date_cleared = trans.date_cleared
trans_to_change.paid_currency = trans_to_change.entered_currency
trans_to_change.paid_amount_usd =
Decimal(str(trans_to_change.paid_amount * Decimal(str(trans_to_change.exchange_rate)).quantize(Decimal('0.01')))).quantize(Decimal('0.01'))
trans_to_change.edited_by = request.user
trans_to_change.cleared = True
trans_to_change.save()
if updated_transactions:
messages.add_message(request, messages.INFO, 'The transactions have been updated successfully.')
return HttpResponseRedirect(reverse('track:update_pdate'))
else:
messages.add_message(request, messages.INFO, 'No transactions have been updated.')
return render_to_response(
'track/paid_date_update.html',
{'formset':formset,
'form': form,
'study_pk':study_pk,
},
context_instance=template.RequestContext(request))
else:
formset = formset(queryset=qs)
return render_to_response(
'track/paid_date_update.html',
{'formset':formset,
'form': form,
'study_pk':study_pk,
},
context_instance=template.RequestContext(request))
Forms:
class StudyOnlyForm(forms.Form):
action = forms.CharField(widget=forms.HiddenInput())
#
# JBL - Q4.0 changed this form to pull all studies (previously
# only 'active' studies), which really means all studies
# that are not 'ccc' studies
#
study = forms.ModelChoiceField(required=False,
label='Protocol',
queryset=Study.objects.all().exclude(study_status='ccc'))
def __init__(self, *args, **kwargs):
self.req = True
if 'req' in kwargs:
self.req = kwargs.pop('req')
super(StudyOnlyForm, self).__init__(*args, **kwargs)
print 'StudyOnlyForm() init'
self.fields['study'].required = self.req
class PaidDateForm(forms.ModelForm):
formfield_callback = jquery_datefield
paid_amount = forms.DecimalField(label="Cleared
Amount",max_digits=14,decimal_places=2,required=False)
date_cleared = forms.DateField(label="Cleared Date",widget=JQueryDateWidget(),
input_formats=settings.DATE_INPUT_FORMATS, required=False)
class Meta:
model = Transaction
include = ('date_time_created')
def __init__(self, *args, **kwargs):
super(PaidDateForm, self).__init__(*args, **kwargs)
print 'PaidDateForm init'
for field in self.fields:
if field != 'date_cleared':
self.fields[field].widget = forms.HiddenInput()
self.fields['paid_amount'].widget.attrs['size'] = 12
self.initial['paid_amount'] = '%.2f' % (self.instance.usd_amount)
You restrict the queryset in the GET branch, but not the POST branch. That means that the POST branch creates a formset containing every transaction.
replace your for loop:
for trans in updated_transactions.exclude(paid_amount=None, date_cleared=None).all():
trans_to_change = Transaction.objects.get(pk=trans.pk)
trans_to_change.paid_amount = trans.paid_amount
trans_to_change.date_cleared = trans.date_cleared
trans_to_change.paid_currency = trans_to_change.entered_currency
trans_to_change.paid_amount_usd = Decimal(str(trans_to_change.paid_amount * Decimal(str(trans_to_change.exchange_rate)).quantize(Decimal('0.01')))).quantize(Decimal('0.01'))
trans_to_change.edited_by = request.user
trans_to_change.cleared = True
trans_to_change.save()
I have models.py
class Visit(Model):
reference_visit = models.ForeignKey('self',
help_text="Visit needs a refrence to Prior Visits",
null=True, blank=True)
show_prior_responses = models.BooleanField(default=False,
help_text="Show PriorResponses")
# has many field but i am making it short.
def __unicode__(self):
result = """Visit id:%s pt:%s""" % (self.id, self.patient.id)
return result
forms.py
class VisitSetupForm(Form):
list_visit_ids = ModelChoiceField(
queryset=Visit.objects.none(),
empty_label='Select Revisit ID',required=False)
show_prior_visit = ModelChoiceField(
queryset=User.objects.all(),
empty_label="Select User for Revisit",required = False)
has many but question is on list_visit_ids.
views.py
def setup(request):
"""
Allow an Admin user the ability to setup a patient & visit all at once.
"""
if request.user.is_superuser:
form_class = AdminVisitSetupForm
all_topics = True
else:
form_class = VisitSetupForm
all_topics = False
f = form_class()
# Get a list of topics for each report.
report_topics = {}
for r in Interview.objects.all():
report_topics[r.id] = [t['ad'] for t in r.topics.values('ad')]
data = {
'superuser':request.user.is_superuser,
'report_topics':simplejson.dumps(report_topics)
}
try:
request.user.reviewer
data['reviewer'] = True
except:
pass
if request.method == "POST":
f = form_class(request.POST)
if f.is_valid():
# Create the patient, generate a password, and send them on their way.
cd = f.cleaned_data
patient = None
if cd['revisit']:
# Check for an existing user first.
try:
patient = Patient.objects.get(username=cd['username'])
except Patient.DoesNotExist, e:
data['form'] = f
data['msg'] = 'There is no user with this username.'
return render_to_response('visit/setup.html', data, context_instance=RequestContext(request))
admin_user = get_user(request)
organization = None
if admin_user:
organization = admin_user.organization
if patient and not request.user.is_superuser:
# Make sure the patient they've selected is one of their own.
if patient.organization != organization:
return HttpResponseForbidden('You are not allowed to see this page.')
if not patient:
password = generate_password()
user = User.objects.create_user(cd['username'], cd['contact_email'], password)
user.first_name = cd['first_name']
user.last_name = cd['last_name']
user.save()
patient = Patient(
user=user,
username=user.username,
contact_phone=cd['contact_phone'],
date_of_birth=cd['date_of_birth'],
email=user.email,
first_name=user.first_name,
gender=cd['gender'],
last_name=user.last_name,
maiden_name=cd['maiden_name'],
organization=organization,
patient_type=cd['patient_type'],
security_answer=cd['security_answer'],
security_question=cd['security_question'],
)
patient.save()
# Send them an email.
t = loader.get_template('www/new_account.txt')
c = Context({
'password':'%s-%s-%s' % (password[:3], password[3:5], password[5:]),
'patient':patient
})
msg = t.render(c)
try:
send_mail(
'A request by your physician to do an online medical history before your appointment.',
msg,
'support#careprep.com',
[user.email]
)
except Exception, e:
log.error('Could not send email for new account %s because: [%s]' % (user.username, e))
request.session['password'] = password
# Create the Visit, too.
interview = cd['interview']
list_visit_ids = cd['list_visit_ids']
print list_visit_ids
visit = Visit(
reference_visit = cd['list_visit_ids'],
show_prior_responses = cd['show_prior_responses'],
patient=patient
)
if request.user.is_superuser:
topics = cd['topics']
else:
topics = set(list(interview.topics.all()) + list(cd['topics']))
reviewer_mode = cd.get('reviewer_mode') or patient.patient_type == 'Reviewer'
url, visit = initialize_visit(
request,
patient=patient,
starting_section=interview.starting_section,
visit_title='%s %s' % (patient, interview.title),
topics=topics,
reviewer_mode=reviewer_mode,
chief_complaint=cd['chief_complaint'],
location=cd['interview_site'],
reference_visit = cd['list_visit_ids'],
show_prior_responses = cd['show_prior_responses'],
)
next_url = "/visit/confirmation/%s/%s/?next=%s" % (patient.user.id, interview.id, url)
else:
v = Visit.objects.get(pk=request.POST['list_visit_ids'])
print v
return HttpResponseRedirect(next_url)
# all the fields that are not given pls ignore.
The template is fine.
Now watch forms.py when i do list_visit_ids = ModelChoiceField(queryset=Visit.objects.all(), empty_label='Select Revisit ID',required=False) It works perfectly fine on my local machine.But on my server it has around 6000 visit objects so this page hangs or i should say keep on loading.
So initially i changed it to list_visit_ids = ModelChoiceField(queryset=Visit.objects.none(), empty_label='Select Revisit ID',required=False)
Now i know that by this the form becomes invalid and should go to the else part Now my question how do i make reference_visit=cd['list_visit_ids'] in else (form is invalid)
case save().How do i override the none() attribute.
Thanks in advance i will really appreciate.
If your goal is to save your html page load by removing the 6000 choices (which I've done too: 10000+ <option> fields wrapped by misc html will absolutely choke a page), you shouldn't be using a ChoiceField at all. By setting queryset=Visit.objects.none() you're allowing zero choices and nothing passed in will validate.
You either show 6000 select item drop downs, radio boxes, etc., or find a way to /not/ have a giant select drop down (such as a hidden input or charfield), not fake around a ModelChoiceField who's main purpose is to populate that select drop down and validate.
In short: don't use a ModelChoiceField if you're not going to be using the html choices generated by it. Use something else and do the validation / model pulling yourself via the clean_FOO methods.
class MyForm(forms.Form):
my_input = forms.CharField()
def clean_my_input(self):
input = self.cleaned_data.get('my_input')
try:
return MyModel.objects.get(pk=input) # add a filter here if you want
# (whatever filters you were using in the queryset argument)
except MyModel.DoesNotExist:
raise forms.ValidationError("Doesn't exist / is invalid")
return input
I am writing django app that as a beckend is using mongodb. I am curently writing register part. Here is how I connecto to database in settings.py
if socket.gethostname() == "Production server":
CON = Connection()
DB = CON.fish
else:
CON = Connection()
DB = CON.test
DB.user.ensure_index([("username", ASCENDING),("email",ASCENDING)],unique = True)#,drop_dups=True
Here is mye register view:
def register(request):
"""
handle user registration
code variable is for testing purposes
"""
if request.method== 'GET':
form = RegisterForm(auto_id=False)
code = 1
return render_to_response('register_home.html',locals(),context_instance=RequestContext(request))
elif request.method == 'POST':
form = RegisterForm(request.POST)
if form.is_valid():
password = form.cleaned_data['password']
password_confirmation = form.cleaned_data['password_confirmation']
if password == password_confirmation:
login = form.cleaned_data['login']
email = form.cleaned_data['email']
newsletter = form.cleaned_data['newsletter']
key = register_user(login,email,password,newsletter)
if key:
#send email
send_mail("Dziękujemy za rejestrację"," Klucz aktywacyjny to " + key,settings.EMAIL_HOST_USER,[email])
request.session['email'] = email
return redirect(register_success)
else:
code = 4
error = "Login/email taken"
return render_to_response('register_home.html',locals(),context_instance=RequestContext(request))
else:
code = 3
error = "invalid password"
return render_to_response('register_home.html',locals(),context_instance=RequestContext(request))
else:
code = 2
return render_to_response('register_home.html',locals(),context_instance=RequestContext(request))
Here is my function I use to register user:
def register_user(login,email,password,newsletter):
"""
This function will return activation key for this user if user was added successfully or none otherwise
"""
key = generate_activation_key()
user = {
"username":login,
"email":email,
"password":crypt_password(password),
"date_join": datetime.now(),
"key": key
}
if newsletter:
user['newsletter'] = True
try:
settings.DB.user.insert(user,safe = True)
except DuplicateKeyError, error:
logging.debug("error raise during saving user")
return None
except OperationFailure, error:
logging.critical("Cannot save to database")
logging.critical(error)
else:
#we have no errors users is registred
return key
And when I test it in the browser it seems to be working. But I write test for it and it isn't working anymore. Here is code for test:
def test_valid_credentials(self):
#now try to register valid user
data = {'login':'test','password':'zaq12wsx','password_confirmation':'zaq12wsx','terms':True,'newsletter':True,'email':'test#test.com'}
response = self.c.post(reverse('register'),data)
#our user should be registred
self.assertEquals(302, response.status_code,'We dont have benn redirected')
self.assertEqual(len(mail.outbox), 1,'No activation email was sent')
#clen email box
mail.outbox = []
#now try to add another user with the same data
response = self.c.post(reverse('register'),data)
#template should be rendered with error message about used login and email
self.assertEquals(200, response.status_code)#this fails
And here is error that i get.
self.assertEquals(200, response.status_code)
AssertionError: 200 != 302
So user was registred with the same username and email which shoudn't happen. Any sugestions? Thanks in advance
Why don't you use https://github.com/django-mongodb-engine/mongodb-engine it works almost perfect with Django ORM. Works like a charm for me.