i working on django application to charge a user before posting his products. i want to offer a free option, how to archive this and save add with sti - django

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

Why is this Django view being executed twice on post?

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.

request.user is not letting me make changes to the current user?

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.

Django form efficiency issue

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()

how to overide in forms queryset none() attribute and somehow allow to save the field?

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

Problem with pymongo and django unique value

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.