def form_valid(self, form): """ If the form is valid we, optionally, checkout the cart items and charge the invoiced items which are due now. """ # We remember the card by default. ``stripeToken`` is not present # when we are creating charges on a card already on file. if 'remember_card' in self.request.POST: # Workaround: Django does not take into account the value # of Field.initial anymore. Worse, it will defaults to False # when the field is not present in the POST. remember_card = form.cleaned_data['remember_card'] else: remember_card = form.fields['remember_card'].initial stripe_token = form.cleaned_data['stripeToken'] # deep copy the invoicables because we are updating the list in place # and we don't want to keep the edited state on a card failure. self.sole_provider = None invoicables = copy.deepcopy(self.invoicables) for invoicable in invoicables: # We use two conventions here: # 1. POST parameters prefixed with cart- correspond to an entry # in the invoicables # 2. Amounts for each line in a entry are unique and are what # is passed for the value of the matching POST parameter. plan = invoicable['subscription'].plan plan_key = invoicable['name'] if self.sole_provider is None: self.sole_provider = plan.organization elif self.sole_provider != plan.organization: self.sole_provider = False if plan_key in form.cleaned_data: selected_line = int(form.cleaned_data[plan_key]) for line in invoicable['options']: if line.dest_amount == selected_line: # Normalize unlock line description to # "subscribe <plan> until ..." if match_unlock(line.descr): nb_periods = plan.period_number(line.descr) line.descr = describe_buy_periods( plan, plan.end_of_period(line.created_at, nb_periods), nb_periods) invoicable['lines'] += [line] try: self.charge = self.customer.checkout(invoicables, self.request.user, token=stripe_token, remember_card=remember_card) if self.charge and self.charge.invoiced_total_amount > 0: messages.info(self.request, "A receipt will be sent to"\ " %(email)s once the charge has been processed. Thank you." % {'email': self.customer.email}) except ProcessorError as err: messages.error(self.request, err) return self.form_invalid(form) return super(CardInvoicablesFormMixin, self).form_valid(form)
def form_valid(self, form): """ If the form is valid we, optionally, checkout the cart items and charge the invoiced items which are due now. """ # We remember the card by default. ``stripeToken`` is not present # when we are creating charges on a card already on file. if 'remember_card' in self.request.POST: # Workaround: Django does not take into account the value # of Field.initial anymore. Worse, it will defaults to False # when the field is not present in the POST. remember_card = form.cleaned_data['remember_card'] else: remember_card = form.fields['remember_card'].initial stripe_token = form.cleaned_data['stripeToken'] # deep copy the invoicables because we are updating the list in place # and we don't want to keep the edited state on a card failure. self.sole_provider = None invoicables = copy.deepcopy(self.invoicables) for invoicable in invoicables: # We use two conventions here: # 1. POST parameters prefixed with cart- correspond to an entry # in the invoicables # 2. Amounts for each line in a entry are unique and are what # is passed for the value of the matching POST parameter. plan = invoicable['subscription'].plan plan_key = invoicable['name'] if self.sole_provider is None: self.sole_provider = plan.organization elif self.sole_provider != plan.organization: self.sole_provider = False if plan_key in form.cleaned_data: selected_line = int(form.cleaned_data[plan_key]) for line in invoicable['options']: if line.dest_amount == selected_line: # Normalize unlock line description to # "subscribe <plan> until ..." if match_unlock(line.descr): nb_periods = plan.period_number(line.descr) line.descr = describe_buy_periods(plan, plan.end_of_period(line.created_at, nb_periods), nb_periods) invoicable['lines'] += [line] try: self.charge = self.customer.checkout( invoicables, self.request.user, token=stripe_token, remember_card=remember_card) if self.charge and self.charge.invoiced_total_amount > 0: messages.info(self.request, "A receipt will be sent to"\ " %(email)s once the charge has been processed. Thank you." % {'email': self.customer.email}) except ProcessorError as err: messages.error(self.request, err) return self.form_invalid(form) return super(CardInvoicablesFormMixin, self).form_valid(form)
def form_valid(self, form): """ If the form is valid we, optionally, checkout the cart items and charge the invoiced items which are due now. """ # XXX We always remember the card instead of taking input # from the form.cleaned_data['remember_card'] field. remember_card = True stripe_token = form.cleaned_data['stripeToken'] if not stripe_token: LOGGER.error("POST to payment page without a stripeToken (%s)", form.cleaned_data) # deep copy the invoicables because we are updating the list in place # and we don't want to keep the edited state on a card failure. self.sole_provider = None invoicables = copy.deepcopy(self.invoicables) for invoicable in invoicables: # We use two conventions here: # 1. POST parameters prefixed with cart- correspond to an entry # in the invoicables # 2. Amounts for each line in a entry are unique and are what # is passed for the value of the matching POST parameter. plan = invoicable['subscription'].plan plan_key = invoicable['name'] if self.sole_provider is None: self.sole_provider = plan.organization elif self.sole_provider != plan.organization: self.sole_provider = False if plan_key in form.cleaned_data: selected_line = int(form.cleaned_data[plan_key]) for line in invoicable['options']: if line.dest_amount == selected_line: # Normalize unlock line description to # "subscribe <plan> until ..." if match_unlock(line.descr): line.descr = describe_buy_periods( plan, plan.end_of_period(line.created_at, line.orig_amount), line.orig_amount) invoicable['lines'] += [line] try: self.charge = self.customer.checkout(invoicables, self.request.user, token=stripe_token, remember_card=remember_card) if self.charge and self.charge.invoiced_total_amount > 0: messages.info(self.request, "A receipt will be sent to"\ " %(email)s once the charge has been processed. Thank you." % {'email': self.customer.email}) except ProcessorError as err: messages.error(self.request, err) return self.form_invalid(form) return super(CardInvoicablesFormMixin, self).form_valid(form)
def generate_transactions(self, provider, processor, from_date, ends_at, fake=None, profile_pictures_dir=None): """ Create Income transactions that represents a growing bussiness. """ #pylint: disable=too-many-locals from saas.metrics.base import month_periods # avoid import loop if not fake: fake = Faker() user_model = get_user_model() # Load list of profile pcitures profile_pictures_males = [] profile_pictures_females = [] if profile_pictures_dir: for picture_name in os.listdir(profile_pictures_dir): if picture_name.startswith("1"): profile_pictures_males += [ "/media/livedemo/profiles/%s" % picture_name ] else: profile_pictures_females += [ "/media/livedemo/profiles/%s" % picture_name ] for end_period in month_periods(from_date=from_date): nb_new_customers = random.randint(0, 9) for _ in range(nb_new_customers): queryset = Plan.objects.filter(organization=provider, period_amount__gt=0) plan = queryset[random.randint(0, queryset.count() - 1)] created = False trials = 0 while not created: try: picture = None if random.randint(0, 1): full_name = fake.name_male() if profile_pictures_males: picture = profile_pictures_males[ random.randint( 0, len(profile_pictures_males) - 1)] else: full_name = fake.name_female() if profile_pictures_females: picture = profile_pictures_females[ random.randint( 0, len(profile_pictures_females) - 1)] slug = slugify('demo%d' % random.randint(1, 1000)) email = "%s@%s" % (slug, fake.domain_name()) first_name, mid_name, last_name = \ full_name_natural_split(full_name) customer, created = Organization.objects.get_or_create( slug=slug, full_name=full_name, email=email, phone=fake.phone_number(), street_address=fake.street_address(), locality=fake.city(), postal_code=fake.postcode(), region=fake.state_abbr(), country=fake.country_code(), picture=picture) user, created = user_model.objects.get_or_create( username=slug, email=email, first_name=first_name, last_name=last_name) customer.add_manager(user, at_time=end_period) #pylint: disable=catching-non-exception except IntegrityError: trials = trials + 1 if trials > 10: raise RuntimeError( 'impossible to create a new customer after 10 trials.' ) Organization.objects.filter(pk=customer.id).update( created_at=end_period) subscription = Subscription.objects.create( organization=customer, plan=plan, ends_at=ends_at + datetime.timedelta(days=31)) Subscription.objects.filter(pk=subscription.id).update( created_at=end_period) # Insert some churn in % churn_rate = 2 all_subscriptions = Subscription.objects.filter( plan__organization=provider) nb_churn_customers = (all_subscriptions.count() * churn_rate // 100) subscriptions = random.sample( list(all_subscriptions), all_subscriptions.count() - nb_churn_customers) for subscription in subscriptions: nb_periods = random.randint(1, 6) subscription.ends_at = subscription.plan.end_of_period( subscription.ends_at, nb_periods=nb_periods) transaction_item = Transaction.objects.new_subscription_order( subscription, amount=subscription.plan.period_amount * nb_periods, descr=humanize.describe_buy_periods( subscription.plan, subscription.ends_at, nb_periods), created_at=end_period) if transaction_item.dest_amount < 50: continue subscription.save() transaction_item.orig_amount = transaction_item.dest_amount transaction_item.orig_unit = transaction_item.dest_unit transaction_item.save() charge = Charge.objects.create( created_at=transaction_item.created_at, amount=transaction_item.dest_amount, customer=subscription.organization, description=humanize.DESCRIBE_CHARGED_CARD % { 'charge': generate_random_slug(prefix='ch_'), 'organization': subscription.organization }, last4=1241, exp_date=datetime_or_now(), processor=processor, processor_key="ch_%s" % str(transaction_item.pk), state=Charge.CREATED) charge.created_at = transaction_item.created_at charge.save() ChargeItem.objects.create(invoiced=transaction_item, charge=charge) charge.payment_successful() churned = all_subscriptions.exclude( pk__in=[subscription.pk for subscription in subscriptions]) for subscription in churned: subscription.ends_at = end_period subscription.save() self.stdout.write( "%d new and %d churned customers at %s\n" % (nb_new_customers, nb_churn_customers, end_period))
def handle(self, *args, **options): #pylint: disable=too-many-locals,too-many-statements from saas.metrics.base import month_periods # avoid import loop RazorpayBackend.bypass_api = True now = datetime.datetime.utcnow().replace(tzinfo=utc) from_date = now from_date = datetime.datetime(year=from_date.year, month=from_date.month, day=1) if args: from_date = datetime.datetime.strptime(args[0], '%Y-%m-%d') # Create a set of 3 plans broker = get_broker() plan, _ = Plan.objects.get_or_create(slug='basic', defaults={ 'title': "Basic", 'description': "Basic Plan", 'period_amount': 24900, 'broker_fee_percent': 0, 'period_type': 4, 'organization': broker, 'is_active': True }) advance_discount = AdvanceDiscount.objects.get_or_create( plan=plan, discount_type=AdvanceDiscount.PERCENTAGE, amount=1000, length=12) Plan.objects.get_or_create(slug='medium', defaults={ 'title': "Medium", 'description': "Medium Plan", 'period_amount': 24900, 'broker_fee_percent': 0, 'period_type': 4, 'organization': broker, 'is_active': True }) plan, _ = Plan.objects.get_or_create(slug='premium', defaults={ 'title': "Premium", 'description': "Premium Plan", 'period_amount': 18900, 'broker_fee_percent': 0, 'period_type': 4, 'organization': broker, 'is_active': True }) advance_discount = AdvanceDiscount.objects.get_or_create( plan=plan, discount_type=AdvanceDiscount.PERCENTAGE, amount=81, length=12) # Create Income transactions that represents a growing bussiness. provider = Organization.objects.get(slug=options['provider']) processor = Organization.objects.get(pk=PROCESSOR_ID) for end_period in month_periods(from_date=from_date): nb_new_customers = random.randint(0, 9) for _ in range(nb_new_customers): queryset = Plan.objects.filter(organization=provider, period_amount__gt=0) plan = queryset[random.randint(0, queryset.count() - 1)] created = False trials = 0 while not created: try: first_name = self.FIRST_NAMES[random.randint( 0, len(self.FIRST_NAMES) - 1)] last_name = self.LAST_NAMES[random.randint( 0, len(self.LAST_NAMES) - 1)] full_name = '%s %s' % (first_name, last_name) slug = slugify('demo%d' % random.randint(1, 1000)) customer, created = Organization.objects.get_or_create( slug=slug, full_name=full_name) #pylint: disable=catching-non-exception except IntegrityError: trials = trials + 1 if trials > 10: raise RuntimeError( 'impossible to create a new customer after 10 trials.' ) Organization.objects.filter(pk=customer.id).update( created_at=end_period) subscription = Subscription.objects.create( organization=customer, plan=plan, ends_at=now + datetime.timedelta(days=31)) Subscription.objects.filter(pk=subscription.id).update( created_at=end_period) # Insert some churn in % churn_rate = 2 all_subscriptions = Subscription.objects.filter( plan__organization=provider) nb_churn_customers = (all_subscriptions.count() * churn_rate // 100) subscriptions = random.sample( list(all_subscriptions), all_subscriptions.count() - nb_churn_customers) for subscription in subscriptions: nb_periods = random.randint(1, 6) amount = nb_periods * subscription.plan.period_amount ends_at = subscription.plan.end_of_period( subscription.ends_at, nb_periods) transaction_item = Transaction.objects.new_subscription_order( subscription, amount=amount, descr=humanize.describe_buy_periods( subscription.plan, ends_at, nb_periods), created_at=end_period) if transaction_item.dest_amount < 50: continue transaction_item.orig_amount = transaction_item.dest_amount transaction_item.orig_unit = transaction_item.dest_unit transaction_item.save() charge = Charge.objects.create( created_at=transaction_item.created_at, amount=transaction_item.dest_amount, customer=subscription.organization, description='Charge for %d periods' % nb_periods, last4=1241, exp_date=datetime_or_now(), processor=processor, processor_key=str(transaction_item.pk), # XXX We can't do that yet because of # ``PROCESSOR_BACKEND.charge_distribution(self)`` # unit=transaction_item.dest_unit, state=Charge.CREATED) charge.created_at = transaction_item.created_at charge.save() ChargeItem.objects.create(invoiced=transaction_item, charge=charge) charge.payment_successful() churned = all_subscriptions.exclude( pk__in=[subscription.pk for subscription in subscriptions]) for subscription in churned: subscription.ends_at = end_period subscription.save() self.stdout.write( "%d new and %d churned customers at %s" % (nb_new_customers, nb_churn_customers, end_period))
def generate_transactions(self, provider, processor, from_date, ends_at): """ Create Income transactions that represents a growing bussiness. """ #pylint: disable=too-many-locals from saas.managers.metrics import month_periods # avoid import loop for end_period in month_periods(from_date=from_date): nb_new_customers = random.randint(0, 9) for _ in range(nb_new_customers): queryset = Plan.objects.filter(organization=provider, period_amount__gt=0) plan = queryset[random.randint(0, queryset.count() - 1)] created = False trials = 0 while not created: try: first_name = self.FIRST_NAMES[random.randint( 0, len(self.FIRST_NAMES) - 1)] last_name = self.LAST_NAMES[random.randint( 0, len(self.LAST_NAMES) - 1)] full_name = '%s %s' % (first_name, last_name) slug = slugify('demo%d' % random.randint(1, 1000)) customer, created = Organization.objects.get_or_create( slug=slug, full_name=full_name) #pylint: disable=catching-non-exception except IntegrityError: trials = trials + 1 if trials > 10: raise RuntimeError( 'impossible to create a new customer after 10 trials.' ) Organization.objects.filter(pk=customer.id).update( created_at=end_period) subscription = Subscription.objects.create( organization=customer, plan=plan, ends_at=ends_at + datetime.timedelta(days=31)) Subscription.objects.filter(pk=subscription.id).update( created_at=end_period) # Insert some churn in % churn_rate = 2 all_subscriptions = Subscription.objects.filter( plan__organization=provider) nb_churn_customers = (all_subscriptions.count() * churn_rate // 100) subscriptions = random.sample( list(all_subscriptions), all_subscriptions.count() - nb_churn_customers) for subscription in subscriptions: nb_periods = random.randint(1, 6) subscription.ends_at = subscription.plan.end_of_period( subscription.ends_at, nb_periods=nb_periods) transaction_item = Transaction.objects.new_subscription_order( subscription, amount=subscription.plan.period_amount * nb_periods, descr=humanize.describe_buy_periods( subscription.plan, subscription.ends_at, nb_periods), created_at=end_period) if transaction_item.dest_amount < 50: continue subscription.save() transaction_item.orig_amount = transaction_item.dest_amount transaction_item.orig_unit = transaction_item.dest_unit transaction_item.save() charge = Charge.objects.create( created_at=transaction_item.created_at, amount=transaction_item.dest_amount, customer=subscription.organization, description='Charge for %d periods' % nb_periods, last4=1241, exp_date=datetime_or_now(), processor=processor, processor_key=transaction_item.pk, # XXX We can't do that yet because of # ``processor_backend.charge_distribution(self)`` # unit=transaction_item.dest_unit, state=Charge.CREATED) charge.created_at = transaction_item.created_at charge.save() ChargeItem.objects.create(invoiced=transaction_item, charge=charge) charge.payment_successful() churned = all_subscriptions.exclude( pk__in=[subscription.pk for subscription in subscriptions]) for subscription in churned: subscription.ends_at = end_period subscription.save() self.stdout.write( "%d new and %d churned customers at %s\n" % (nb_new_customers, nb_churn_customers, end_period))