예제 #1
0
    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)
예제 #2
0
    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)
예제 #3
0
    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)
예제 #4
0
 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))
예제 #6
0
 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))