Esempio n. 1
0
    def get(self, request, subscriber_type, **kwargs):
        queryset_view = self.queryset_view_map[subscriber_type]

        class APIViewProxy(queryset_view):
            def __init__(self, provider):
                self.provider = provider
        view_proxy = APIViewProxy(self.get_organization())
        view_proxy.get_range_queryset = MethodType(
            queryset_view.get_range_queryset, view_proxy)

        start_date = datetime_or_now(
            parse_datetime(request.GET.get('start_date', None)))
        end_date = datetime_or_now(
            parse_datetime(request.GET.get('end_date', None)))

        content = StringIO()
        csv_writer = csv.writer(content)
        csv_writer.writerow(['Name', 'Email', 'Registration Date'])
        for org in view_proxy.get_range_queryset(start_date, end_date):
            csv_writer.writerow([
                org.full_name.encode('utf-8'),
                org.email.encode('utf-8'),
                org.created_at])
        content.seek(0)
        resp = HttpResponse(content, content_type='text/csv')
        resp['Content-Disposition'] = \
            'attachment; filename="subscribers-{}-{}.csv"'.format(
                subscriber_type, datetime.now().strftime('%Y%m%d'))
        return resp
Esempio n. 2
0
 def get(self, request, *args, **kwargs):
     #pylint: disable=no-member,unused-argument
     self.provider = self.get_organization()
     start_at = request.GET.get('start_at', None)
     if start_at:
         start_at = parse_datetime(start_at)
     start_at = datetime_or_now(start_at)
     ends_at = request.GET.get('ends_at', None)
     if ends_at:
         ends_at = parse_datetime(ends_at)
     ends_at = datetime_or_now(ends_at)
     queryset = self.get_range_queryset(start_at, ends_at)
     page_object_list = self.paginate_queryset(queryset)
     serializer = self.serializer_class()
     return Response({
         'start_at':
         start_at,
         'ends_at':
         ends_at,
         'count':
         queryset.count(),
         self.queryset_name: [
             serializer.to_representation(organization)
             for organization in page_object_list
         ],
     })
Esempio n. 3
0
 def cache_fields(self, request):
     self.ends_at = datetime_or_now(parse_datetime(request.GET.get("ends_at", "").strip('"')))
     self.start_at = request.GET.get("start_at", None)
     if self.start_at:
         self.start_at = datetime_or_now(parse_datetime(self.start_at.strip('"')))
     else:
         self.start_at = self.ends_at + dateutil.relativedelta.relativedelta(months=-1)
Esempio n. 4
0
    def get(self, request, subscriber_type, **kwargs):
        queryset_view = self.queryset_view_map[subscriber_type]

        class APIViewProxy(queryset_view):
            def __init__(self, provider):
                self.provider = provider

        view_proxy = APIViewProxy(self.get_organization())
        view_proxy.get_range_queryset = MethodType(
            queryset_view.get_range_queryset, view_proxy)

        start_date = datetime_or_now(
            parse_datetime(request.GET.get('start_date', None)))
        end_date = datetime_or_now(
            parse_datetime(request.GET.get('end_date', None)))

        content = StringIO()
        csv_writer = csv.writer(content)
        csv_writer.writerow(['Name', 'Email', 'Registration Date'])
        for org in view_proxy.get_range_queryset(start_date, end_date):
            csv_writer.writerow([
                org.full_name.encode('utf-8'),
                org.email.encode('utf-8'), org.created_at
            ])
        content.seek(0)
        resp = HttpResponse(content, content_type='text/csv')
        resp['Content-Disposition'] = \
            'attachment; filename="subscribers-{}-{}.csv"'.format(
                subscriber_type, datetime.now().strftime('%Y%m%d'))
        return resp
Esempio n. 5
0
    def get(self, request, *args, **kwargs):
        self.provider = self.get_organization()
        self.start_date = datetime_or_now(
            parse_datetime(request.GET.get('start_date', None).strip('"')))
        self.end_date = datetime_or_now(
            parse_datetime(request.GET.get('end_date', None).strip('"')))

        return super(AbstractSubscriberPipelineDownloadView, self).get(
            request, *args, **kwargs)
Esempio n. 6
0
 def cache_fields(self, request):
     self.ends_at = datetime_or_now(
         parse_datetime(request.GET.get('ends_at', '').strip('"')))
     self.start_at = request.GET.get('start_at', None)
     if self.start_at:
         self.start_at = datetime_or_now(
             parse_datetime(self.start_at.strip('"')))
     else:
         self.start_at = (self.ends_at +
                          dateutil.relativedelta.relativedelta(months=-1))
Esempio n. 7
0
 def get_queryset(self):
     '''
     Implement date range filtering
     '''
     qs = super(SmartTransactionListMixin, self).get_queryset()
     start = datetime_or_now(
         parse_datetime(self.request.GET.get('start_at', '').strip('"')))
     end = datetime_or_now(
         parse_datetime(self.request.GET.get('ends_at', '').strip('"')))
     return qs.filter(created_at__gte=start, created_at__lte=end)
Esempio n. 8
0
 def cache_fields(self, request): #pylint: disable=unused-argument
     self.organization = self.get_organization()
     self.start_at = self.request.GET.get('start_at', None)
     if self.start_at:
         self.start_at = parse_datetime(self.start_at)
     self.start_at = datetime_or_now(self.start_at)
     self.ends_at = self.request.GET.get('ends_at', None)
     if self.ends_at:
         self.ends_at = parse_datetime(self.ends_at)
     self.ends_at = datetime_or_now(self.ends_at)
Esempio n. 9
0
 def cache_fields(self, request): #pylint: disable=unused-argument
     self.organization = self.get_organization()
     self.start_at = self.request.GET.get('start_at', None)
     if self.start_at:
         self.start_at = parse_datetime(self.start_at)
     self.start_at = datetime_or_now(self.start_at)
     self.ends_at = self.request.GET.get('ends_at', None)
     if self.ends_at:
         self.ends_at = parse_datetime(self.ends_at)
     self.ends_at = datetime_or_now(self.ends_at)
Esempio n. 10
0
 def get_queryset(self):
     '''
     Implement date range filtering
     '''
     qs = super(SmartTransactionListMixin, self).get_queryset()
     start = datetime_or_now(
         parse_datetime(self.request.GET.get('start_at', '').strip('"')))
     end = datetime_or_now(
         parse_datetime(self.request.GET.get('ends_at', '').strip('"')))
     return qs.filter(created_at__gte=start, created_at__lte=end)
Esempio n. 11
0
 def get_queryset(self):
     kwargs = {}
     start_at = self.request.GET.get("start_at", None)
     if start_at:
         start_at = datetime_or_now(parse_datetime(start_at))
         kwargs.update({"created_at__lt": start_at})
     ends_at = self.request.GET.get("ends_at", None)
     if ends_at:
         ends_at = parse_datetime(ends_at)
     ends_at = datetime_or_now(ends_at)
     return Subscription.objects.filter(
         organization__slug=self.kwargs.get("organization"), ends_at__gte=ends_at, **kwargs
     )
Esempio n. 12
0
 def get_queryset(self):
     kwargs = {}
     start_at = self.request.GET.get('start_at', None)
     if start_at:
         start_at = datetime_or_now(parse_datetime(start_at))
         kwargs.update({'created_at__lt': start_at})
     ends_at = self.request.GET.get('ends_at', None)
     if ends_at:
         ends_at = parse_datetime(ends_at)
     ends_at = datetime_or_now(ends_at)
     return Subscription.objects.filter(
         plan__organization=self.get_organization(),
         ends_at__gte=ends_at, **kwargs).order_by('-ends_at')
Esempio n. 13
0
 def get_queryset(self):
     kwargs = {}
     start_at = self.request.GET.get('start_at', None)
     if start_at:
         start_at = datetime_or_now(parse_datetime(start_at))
         kwargs.update({'created_at__lt': start_at})
     ends_at = self.request.GET.get('ends_at', None)
     if ends_at:
         ends_at = parse_datetime(ends_at)
     ends_at = datetime_or_now(ends_at)
     return Subscription.objects.filter(
         plan__organization=self.get_organization(),
         ends_at__gte=ends_at,
         **kwargs).order_by('-ends_at')
Esempio n. 14
0
 def get_queryset(self):
     kwargs = {}
     start_at = self.request.GET.get('start_at', None)
     if start_at:
         start_at = datetime_or_now(parse_datetime(start_at))
         kwargs.update({'created_at__lt': start_at})
     ends_at = self.request.GET.get('ends_at', None)
     if ends_at:
         ends_at = parse_datetime(ends_at)
     ends_at = datetime_or_now(ends_at)
     return User.objects.exclude(
         Q(manages__subscription__created_at__lt=ends_at) |
         Q(contributes__subscription__created_at__lt=ends_at)).order_by(
             '-date_joined', 'last_name').distinct()
Esempio n. 15
0
 def get_queryset(self):
     kwargs = {}
     start_at = self.request.GET.get('start_at', None)
     if start_at:
         start_at = datetime_or_now(parse_datetime(start_at))
         kwargs.update({'created_at__lt': start_at})
     ends_at = self.request.GET.get('ends_at', None)
     if ends_at:
         ends_at = parse_datetime(ends_at)
     ends_at = datetime_or_now(ends_at)
     return User.objects.exclude(
         Q(manages__subscription__created_at__lt=ends_at)
         | Q(contributes__subscription__created_at__lt=ends_at)).order_by(
             '-date_joined', 'last_name').distinct()
Esempio n. 16
0
    def get(self, request, table_key, *args, **kwargs):
        ends_at = request.GET.get('ends_at', None)
        if ends_at:
            ends_at = parse_datetime(ends_at)
        ends_at = datetime_or_now(ends_at)

        reverse = True
        account_title = 'Payments'
        account = Transaction.FUNDS

        # TODO: refactor to only build the table (customer or amount)
        # relevant to the request

        account_table, customer_table, customer_extra = \
            aggregate_monthly_transactions(self.get_organization(), account,
                account_title=account_title,
                from_date=ends_at,
                reverse=reverse)
        data = SortedDict()
        # By convention, if we have a ``unit``, the table contains
        # amounts in cents. We thus scale by 0.01 to get a human
        # readable 'whole dollar' amounts.
        data['amount'] = {
            "title": "Amount",
            "unit": "$",
            "scale": 0.01,
            "table": account_table
        }
        data['customers'] = {
            "title": "Customers",
            "table": customer_table,
            "extra": customer_extra
        }
        return Response({"title": "Revenue Metrics", "data": data[table_key]})
Esempio n. 17
0
def create_charges_for_balance(until=None):
    """
    Create charges for all accounts payable.
    """
    until = datetime_or_now(until)
    for organization in Organization.objects.all():
        charges = Charge.objects.filter(customer=organization).exclude(
            state=Charge.DONE).aggregate(Sum('amount'))
        inflight_charges = charges['amount__sum']
        # We will create charges only when we have no charges
        # already in flight for this customer.
        if not inflight_charges:
            balance_t = Transaction.objects.get_organization_payable(
                organization, until=until)
            if balance_t.dest_amount > 50:
                LOGGER.info('CHARGE %dc to %s', balance_t.dest_amount,
                            balance_t.dest_organization)
                # Stripe will not processed charges less than 50 cents.
                try:
                    balance_t.save()
                    Charge.objects.charge_card(balance_t.dest_organization,
                                               balance_t)
                except:
                    raise
            else:
                LOGGER.info('SKIP   %s (less than 50c)',
                            balance_t.dest_organization)
        else:
            LOGGER.info('SKIP   %s (one charge already in flight)',
                        balance_t.dest_organization)
Esempio n. 18
0
    def get(self, request, table_key, *args, **kwargs):
        ends_at = request.GET.get('ends_at', None)
        if ends_at:
            ends_at = parse_datetime(ends_at)
        ends_at = datetime_or_now(ends_at)

        reverse = True
        account_title = 'Payments'
        account = Transaction.FUNDS

        # TODO: refactor to only build the table (customer or amount)
        # relevant to the request

        account_table, customer_table, customer_extra = \
            aggregate_monthly_transactions(self.get_organization(), account,
                account_title=account_title,
                from_date=ends_at,
                reverse=reverse)
        data = SortedDict()
        # By convention, if we have a ``unit``, the table contains
        # amounts in cents. We thus scale by 0.01 to get a human
        # readable 'whole dollar' amounts.
        data['amount'] = {"title": "Amount",
                          "unit": "$", "scale": 0.01, "table": account_table}
        data['customers'] = {"title": "Customers",
                             "table": customer_table, "extra": customer_extra}
        return Response(
            {"title": "Revenue Metrics",
            "data": data[table_key]})
Esempio n. 19
0
    def get(self, request, *args, **kwargs):
        ends_at = request.GET.get('ends_at', None)
        if ends_at:
            ends_at = parse_datetime(ends_at)
        ends_at = datetime_or_now(ends_at)

        # XXX to fix: returns payments in customer currency
        account_table, _, _ = \
            aggregate_monthly_transactions(self.get_organization(),
                Transaction.FUNDS, account_title='Payments',
                from_date=ends_at, orig='dest', dest='orig')

        _, refund_amount = aggregate_monthly(self.get_organization(),
                                             Transaction.REFUND,
                                             from_date=ends_at,
                                             orig='dest',
                                             dest='dest')

        account_table += [{"key": "Refunds", "values": refund_amount}]

        return Response({
            "title": "Amount",
            "unit": "$",
            "scale": 0.01,
            "table": account_table
        })
Esempio n. 20
0
    def get(self, request, *args, **kwargs):
        ends_at = request.GET.get('ends_at', None)
        if ends_at:
            ends_at = parse_datetime(ends_at)
        ends_at = datetime_or_now(ends_at)
        organization = self.get_organization()
        table = []
        for plan in Plan.objects.filter(organization=organization):
            values = active_subscribers(plan,
                                        from_date=self.kwargs.get('from_date'))
            table.append({
                "key": plan.slug,
                "values": values,
                "is_active": plan.is_active
            })
        extra = [{
            "key":
            "churn",
            "values":
            churn_subscribers(from_date=self.kwargs.get('from_date'))
        }]

        return Response({
            "title": "Active Subscribers",
            "table": table,
            "extra": extra
        })
Esempio n. 21
0
 def create_charge_on_card(card, amount, unit, descr=None, stmt_descr=None):
     #pylint: disable=too-many-arguments,unused-argument
     LOGGER.debug('create_charge_on_card(amount=%s, unit=%s, descr=%s)',
                  amount, unit, descr)
     created_at = datetime_or_now()
     return (generate_random_slug(), created_at, '1234',
             created_at + datetime.timedelta(days=365))
Esempio n. 22
0
 def create_transfer(organization, amount, descr=None):
     """
     Transfer *amount* into the organization bank account.
     """
     LOGGER.debug("create_transfer(organization=%s, amount=%s, descr=%s)", organization, amount, descr)
     created_at = datetime_or_now()
     return (generate_random_slug(), created_at)
Esempio n. 23
0
    def get_queryset(self):
        """
        GET displays the balance due by a subscriber.

        Template:

        To edit the layout of this page, create a local \
        ``saas/billing/balance.html`` (`example <https://github.com/djaodjin\
/djaodjin-saas/tree/master/saas/templates/saas/billing/balance.html>`__).

        Template context:
          - ``STRIPE_PUB_KEY`` Public key to send to stripe.com
          - ``invoicables`` List of items to be invoiced (with options)
          - ``organization`` The provider of the product
          - ``request`` The HTTP request object

        POST attempts to charge the card for the balance due.
        """
        self.customer = self.get_organization()
        invoicables = []
        created_at = datetime_or_now()
        for subscription in Subscription.objects.active_for(self.customer):
            options = self.get_invoicable_options(subscription, created_at)
            if len(options) > 0:
                invoicables += [{
                    'subscription': subscription,
                    'name': 'cart-%s' % subscription.plan.slug,
                    'lines': [],
                    'options': options
                }]
        return invoicables
Esempio n. 24
0
def create_charges_for_balance(until=None):
    """
    Create charges for all accounts payable.
    """
    until = datetime_or_now(until)
    for organization in Organization.objects.all():
        charges = Charge.objects.filter(customer=organization).exclude(
            state=Charge.DONE).aggregate(Sum('amount'))
        inflight_charges = charges['amount__sum']
        # We will create charges only when we have no charges
        # already in flight for this customer.
        if not inflight_charges:
            balance_t = Transaction.objects.get_organization_payable(
                organization, until=until)
            if balance_t.dest_amount > 50:
                LOGGER.info('CHARGE %dc to %s',
                    balance_t.dest_amount, balance_t.dest_organization)
                # Stripe will not processed charges less than 50 cents.
                try:
                    balance_t.save()
                    Charge.objects.charge_card(
                        balance_t.dest_organization, balance_t)
                except:
                    raise
            else:
                LOGGER.info('SKIP   %s (less than 50c)',
                    balance_t.dest_organization)
        else:
            LOGGER.info('SKIP   %s (one charge already in flight)',
                balance_t.dest_organization)
Esempio n. 25
0
def month_periods(nb_months=12, from_date=None):
    """constructs a list of (nb_months + 1) dates in the past that fall
    on the first of each month until *from_date* which is the last entry
    of the list returned."""
    dates = []
    if from_date and isinstance(from_date, basestring):
        from_date = parse_datetime(from_date)
    from_date = datetime_or_now(from_date)
    dates.append(from_date)
    last = datetime(
        day=from_date.day, month=from_date.month, year=from_date.year,
        tzinfo=utc)
    if last.day != 1:
        last = datetime(day=1, month=last.month, year=last.year, tzinfo=utc)
        dates.append(last)
        nb_months = nb_months - 1
    for _ in range(0, nb_months):
        year = last.year
        month = last.month - 1
        if month < 1:
            year = last.year - month / 12 - 1
            month = 12 - (month % 12)
        last = datetime(day=1, month=month, year=year, tzinfo=utc)
        dates.append(last)
    dates.reverse()
    return dates
Esempio n. 26
0
def month_periods(nb_months=12, from_date=None):
    """constructs a list of (nb_months + 1) dates in the past that fall
    on the first of each month until *from_date* which is the last entry
    of the list returned."""
    dates = []
    if from_date and isinstance(from_date, basestring):
        from_date = parse_datetime(from_date)
    from_date = datetime_or_now(from_date)
    dates.append(from_date)
    last = datetime(day=from_date.day,
                    month=from_date.month,
                    year=from_date.year,
                    tzinfo=utc)
    if last.day != 1:
        last = datetime(day=1, month=last.month, year=last.year, tzinfo=utc)
        dates.append(last)
        nb_months = nb_months - 1
    for _ in range(0, nb_months):
        year = last.year
        month = last.month - 1
        if month < 1:
            year = last.year - month / 12 - 1
            month = 12 - (month % 12)
        last = datetime(day=1, month=month, year=year, tzinfo=utc)
        dates.append(last)
    dates.reverse()
    return dates
Esempio n. 27
0
    def get_queryset(self):
        """
        GET displays the balance due by a subscriber.

        Template:

        To edit the layout of this page, create a local \
        ``saas/billing/balance.html`` (`example <https://github.com/djaodjin\
/djaodjin-saas/tree/master/saas/templates/saas/billing/balance.html>`__).

        Template context:
          - ``STRIPE_PUB_KEY`` Public key to send to stripe.com
          - ``invoicables`` List of items to be invoiced (with options)
          - ``organization`` The provider of the product
          - ``request`` The HTTP request object

        POST attempts to charge the card for the balance due.
        """
        self.customer = self.get_organization()
        invoicables = []
        created_at = datetime_or_now()
        for subscription in Subscription.objects.active_for(self.customer):
            options = self.get_invoicable_options(subscription, created_at)
            if len(options) > 0:
                invoicables += [{
                    'subscription': subscription,
                    'name': 'cart-%s' % subscription.plan.slug,
                    'lines': [],
                    'options': options}]
        return invoicables
Esempio n. 28
0
    def get_queryset(self):
        """
        GET displays the balance due by a subscriber.

        Template:

        To edit the layout of this page, create a local \
        ``saas/billing/balance.html`` (`example <https://github.com/djaodjin\
/djaodjin-saas/tree/master/saas/templates/saas/billing/balance.html>`__).

        Template context:
          - organization
          - request

        POST attempts to charge the card for the balance due.
        """
        self.customer = self.get_organization()
        invoicables = []
        created_at = datetime_or_now()
        for subscription in Subscription.objects.active_for(self.customer):
            options = self.get_invoicable_options(subscription, created_at)
            if len(options) > 0:
                invoicables += [{
                    'subscription': subscription,
                    'name': 'cart-%s' % subscription.plan.slug,
                    'lines': [],
                    'options': options}]
        return invoicables
Esempio n. 29
0
 def get(self, request, *args, **kwargs): #pylint: disable=unused-argument
     organization = self.get_organization()
     at_date = datetime_or_now(request.DATA.get('at', None))
     return Response([{
         'key': Transaction.INCOME,
         'values': monthly_balances(
                     organization, Transaction.INCOME, at_date)
         }])
Esempio n. 30
0
 def get(self, request, *args, **kwargs): #pylint: disable=unused-argument
     organization = self.get_organization()
     start_at = request.GET.get('start_at', None)
     if start_at:
         start_at = parse_datetime(start_at)
     start_at = datetime_or_now(start_at)
     ends_at = request.GET.get('ends_at', None)
     if ends_at:
         ends_at = parse_datetime(ends_at)
     ends_at = datetime_or_now(ends_at)
     result = []
     for key in Transaction.objects.distinct_accounts():
         result += [{
             'key': key,
             'values': monthly_balances(organization, key, ends_at)
         }]
     return Response(result)
Esempio n. 31
0
 def create_charge_on_card(card, amount, unit,
     descr=None, stmt_descr=None):
     #pylint: disable=too-many-arguments,unused-argument
     LOGGER.debug('create_charge_on_card(amount=%s, unit=%s, descr=%s)',
         amount, unit, descr)
     created_at = datetime_or_now()
     return (generate_random_slug(), created_at,
         '1234', created_at + datetime.timedelta(days=365))
Esempio n. 32
0
 def get(self, request, *args, **kwargs):  #pylint: disable=unused-argument
     organization = self.get_organization()
     start_at = request.GET.get('start_at', None)
     if start_at:
         start_at = parse_datetime(start_at)
     start_at = datetime_or_now(start_at)
     ends_at = request.GET.get('ends_at', None)
     if ends_at:
         ends_at = parse_datetime(ends_at)
     ends_at = datetime_or_now(ends_at)
     result = []
     for key in Transaction.objects.distinct_accounts():
         result += [{
             'key': key,
             'values': monthly_balances(organization, key, ends_at)
         }]
     return Response(result)
Esempio n. 33
0
 def create_transfer(organization, amount, descr=None):
     """
     Transfer *amount* into the organization bank account.
     """
     LOGGER.debug('create_transfer(organization=%s, amount=%s, descr=%s)',
                  organization, amount, descr)
     created_at = datetime_or_now()
     return (generate_random_slug(), created_at)
Esempio n. 34
0
 def get_queryset(self):
     self.customer = self.get_organization()
     created_at = datetime_or_now()
     prorate_to_billing = False
     prorate_to = None
     if prorate_to_billing:
         # XXX First we add enough periods to get the next billing date later
         # than created_at but no more than one period in the future.
         prorate_to = self.customer.billing_start
     invoicables = []
     for cart_item in CartItem.objects.get_cart(user=self.request.user):
         if cart_item.email:
             full_name = ' '.join(
                 [cart_item.first_name, cart_item.last_name]).strip()
             for_descr = ', for %s (%s)' % (full_name, cart_item.email)
             organization_queryset = Organization.objects.filter(
                 email=cart_item.email)
             if organization_queryset.exists():
                 organization = organization_queryset.get()
             else:
                 organization = Organization(
                     full_name='%s %s' %
                     (cart_item.first_name, cart_item.last_name),
                     email=cart_item.email)
         else:
             for_descr = ''
             organization = self.customer
         try:
             subscription = Subscription.objects.get(
                 organization=organization, plan=cart_item.plan)
         except Subscription.DoesNotExist:
             ends_at = prorate_to
             if not ends_at:
                 ends_at = created_at
             subscription = Subscription.objects.new_instance(
                 organization, cart_item.plan, ends_at=ends_at)
         lines = []
         options = self.get_invoicable_options(subscription,
                                               created_at,
                                               prorate_to=prorate_to,
                                               coupon=cart_item.coupon)
         if cart_item.nb_periods > 0:
             # The number of periods was already selected so we generate
             # a line instead.
             for line in options:
                 if line.orig_amount == cart_item.nb_periods:
                     line.descr += for_descr
                     lines += [line]
                     options = []
                     break
         invoicables += [{
             'name': cart_item.name,
             'descr': cart_item.descr,
             'subscription': subscription,
             "lines": lines,
             "options": options
         }]
     return invoicables
Esempio n. 35
0
 def get(self, request, *args, **kwargs): #pylint: disable=unused-argument
     organization = self.get_organization()
     start_at = request.GET.get('start_at', None)
     if start_at:
         start_at = parse_datetime(start_at)
     start_at = datetime_or_now(start_at)
     ends_at = request.GET.get('ends_at', None)
     if ends_at:
         ends_at = parse_datetime(ends_at)
     ends_at = datetime_or_now(ends_at)
     result = []
     for key in [Transaction.INCOME, Transaction.BACKLOG,
                 Transaction.RECEIVABLE]:
         result += [{
             'key': key,
             'values': monthly_balances(organization, key, ends_at)
         }]
     return Response({'title': "Balances",
         'unit': "$", 'scale': 0.01, 'table': result})
Esempio n. 36
0
 def get(self, request, *args, **kwargs):
     #pylint: disable=no-member,unused-argument
     self.provider = self.get_organization()
     start_at = request.GET.get('start_at', None)
     if start_at:
         start_at = parse_datetime(start_at)
     start_at = datetime_or_now(start_at)
     ends_at = request.GET.get('ends_at', None)
     if ends_at:
         ends_at = parse_datetime(ends_at)
     ends_at = datetime_or_now(ends_at)
     queryset = self.get_queryset(start_at, ends_at)
     serializer = self.serializer_class()
     return Response({
         'start_at': start_at,
         'ends_at': ends_at,
         'count': queryset.count(),
         self.queryset_name: [serializer.to_native(organization)
             for organization in queryset],
         })
Esempio n. 37
0
 def get_queryset(self):
     self.customer = self.get_organization()
     created_at = datetime_or_now()
     prorate_to_billing = False
     prorate_to = None
     if prorate_to_billing:
         # XXX First we add enough periods to get the next billing date later
         # than created_at but no more than one period in the future.
         prorate_to = self.customer.billing_start
     invoicables = []
     for cart_item in CartItem.objects.get_cart(user=self.request.user):
         if cart_item.email:
             full_name = ' '.join([
                     cart_item.first_name, cart_item.last_name]).strip()
             for_descr = ', for %s (%s)' % (full_name, cart_item.email)
             organization_queryset = Organization.objects.filter(
                 email=cart_item.email)
             if organization_queryset.exists():
                 organization = organization_queryset.get()
             else:
                 organization = Organization(
                     full_name='%s %s' % (
                         cart_item.first_name, cart_item.last_name),
                     email=cart_item.email)
         else:
             for_descr = ''
             organization = self.customer
         try:
             subscription = Subscription.objects.get(
                 organization=organization, plan=cart_item.plan)
         except Subscription.DoesNotExist:
             ends_at = prorate_to
             if not ends_at:
                 ends_at = created_at
             subscription = Subscription.objects.new_instance(
                 organization, cart_item.plan, ends_at=ends_at)
         lines = []
         options = self.get_invoicable_options(subscription, created_at,
             prorate_to=prorate_to, coupon=cart_item.coupon)
         if cart_item.nb_periods > 0:
             # The number of periods was already selected so we generate
             # a line instead.
             for line in options:
                 if line.orig_amount == cart_item.nb_periods:
                     line.descr += for_descr
                     lines += [line]
                     options = []
                     break
         invoicables += [{
             'name': cart_item.name, 'descr': cart_item.descr,
             'subscription': subscription,
             "lines": lines, "options": options}]
     return invoicables
Esempio n. 38
0
def recognize_income(until=None):
    """
    Create all ``Transaction`` necessary to recognize revenue
    on each ``Subscription`` until date specified.
    """
    until = datetime_or_now(until)
    for subscription in Subscription.objects.filter(created_at__lte=until, ends_at__gt=until):
        with transaction.atomic():
            # [``recognize_start``, ``recognize_end``[ is one period over which
            # revenue is recognized. It will slide over the subscription
            # lifetime from ``created_at`` to ``until``.
            to_recognize_amount = 0
            recognize_period = relativedelta(months=1)
            order_subscribe_beg = subscription.created_at
            recognize_start = subscription.created_at
            recognize_end = recognize_start + recognize_period
            for order in Transaction.objects.get_subscription_receivable(subscription):
                # [``order_subscribe_beg``, ``order_subscribe_end``[ is
                # the subset of the subscription lifetime the order paid for.
                # It covers ``total_periods`` plan periods.
                total_periods = order.get_event().plan.period_number(order.descr)
                order_subscribe_end = subscription.plan.end_of_period(order_subscribe_beg, nb_periods=total_periods)
                min_end = min(order_subscribe_end, until)
                while recognize_end <= min_end:
                    # we use ``<=`` here because we compare that bounds
                    # are equal instead of searching for points within
                    # the interval.
                    nb_periods = subscription.nb_periods(recognize_start, recognize_end)
                    to_recognize_amount = (nb_periods * order.dest_amount) / total_periods
                    recognized_amount, _ = Transaction.objects.get_subscription_income_balance(
                        subscription, starts_at=recognize_start, ends_at=recognize_end
                    )
                    # We are not computing a balance sheet here but looking for
                    # a positive amount to compare with the revenue that should
                    # have been recognized.
                    recognized_amount = abs(recognized_amount)
                    if to_recognize_amount > recognized_amount:
                        # We have some amount of revenue to recognize here.
                        # ``at_time`` is set just before ``recognize_end``
                        # so we do not include the newly created transaction
                        # in the subsequent period.
                        Transaction.objects.create_income_recognized(
                            subscription,
                            amount=to_recognize_amount - recognized_amount,
                            at_time=recognize_end - relativedelta(seconds=1),
                            descr=DESCRIBE_RECOGNIZE_INCOME
                            % {"period_start": recognize_start, "period_end": recognize_end},
                        )
                    recognize_start = recognize_end
                    recognize_end += recognize_period
                order_subscribe_beg = order_subscribe_end
                if recognize_end >= until:
                    break
Esempio n. 39
0
 def get_queryset(self):
     self.customer = self.get_organization()
     invoicables = []
     created_at = datetime_or_now()
     for subscription in Subscription.objects.active_for(self.customer):
         options = self.get_invoicable_options(subscription, created_at)
         if len(options) > 0:
             invoicables += [{
                 'subscription': subscription,
                 'name': 'cart-%s' % subscription.plan.slug,
                 'lines': [],
                 'options': options}]
     return invoicables
Esempio n. 40
0
 def get_queryset(self):
     self.customer = self.get_organization()
     invoicables = []
     created_at = datetime_or_now()
     for subscription in Subscription.objects.active_for(self.customer):
         options = self.get_invoicable_options(subscription, created_at)
         if len(options) > 0:
             invoicables += [{
                 'subscription': subscription,
                 'name': 'cart-%s' % subscription.plan.slug,
                 'lines': [],
                 'options': options
             }]
     return invoicables
Esempio n. 41
0
 def redeem(request, coupon_code):
     now = datetime_or_now()
     coupon_applied = False
     for item in CartItem.objects.get_cart(request.user):
         coupon = Coupon.objects.filter(
             Q(ends_at__isnull=True) | Q(ends_at__gt=now),
             code__iexact=coupon_code,  # case incensitive search.
             organization=item.plan.organization).first()
         if coupon and (not coupon.plan or (coupon.plan == item.plan)):
             # Coupon can be restricted to a plan or apply to all plans
             # of an organization.
             coupon_applied = True
             item.coupon = coupon
             item.save()
     return coupon_applied
Esempio n. 42
0
 def redeem(request, coupon_code):
     now = datetime_or_now()
     coupon_applied = False
     for item in CartItem.objects.get_cart(request.user):
         coupon = Coupon.objects.filter(
             Q(ends_at__isnull=True) | Q(ends_at__gt=now),
             code__iexact=coupon_code, # case incensitive search.
             organization=item.plan.organization).first()
         if coupon and (not coupon.plan or (coupon.plan == item.plan)):
             # Coupon can be restricted to a plan or apply to all plans
             # of an organization.
             coupon_applied = True
             item.coupon = coupon
             item.save()
     return coupon_applied
Esempio n. 43
0
 def get(self, request, *args, **kwargs):  #pylint: disable=unused-argument
     organization = self.get_organization()
     start_at = request.GET.get('start_at', None)
     if start_at:
         start_at = parse_datetime(start_at)
     start_at = datetime_or_now(start_at)
     ends_at = request.GET.get('ends_at', None)
     if ends_at:
         ends_at = parse_datetime(ends_at)
     ends_at = datetime_or_now(ends_at)
     result = []
     for key in [
             Transaction.INCOME, Transaction.BACKLOG, Transaction.RECEIVABLE
     ]:
         result += [{
             'key': key,
             'values': monthly_balances(organization, key, ends_at)
         }]
     return Response({
         'title': "Balances",
         'unit': "$",
         'scale': 0.01,
         'table': result
     })
Esempio n. 44
0
def pass_paid_subscription(request, organization=None, plan=None):
    #pylint: disable=unused-argument
    if organization and not isinstance(organization, Organization):
        organization = get_object_or_404(Organization, slug=organization)
    if plan and not isinstance(plan, Plan):
        plan = get_object_or_404(Plan, slug=plan)
    subscribed_at = datetime_or_now()
    subscriptions = Subscription.objects.filter(
        organization=organization, plan=plan,
        ends_at__gt=subscribed_at)
    if not subscriptions.exists():
        raise Http404("%(organization)s has no subscription to %(plan)s'\
' as of %(date)s" % {'organization': organization,
                     'plan': plan, 'date': subscribed_at})
    return not subscriptions.first().is_locked
Esempio n. 45
0
 def reconcile_transfers(self, provider):
     if provider.processor_deposit_key:
         balance = provider.withdraw_available()
         timestamp = datetime_to_timestamp(balance['created_at'])
         try:
             kwargs = self._prepare_request(provider=None)
             transfers = stripe.Transfer.all(created={'gt': timestamp},
                 recipient=provider.processor_deposit_key,
                 **kwargs)
             with transaction.atomic():
                 for transfer in transfers.data:
                     created_at = datetime_or_now(
                         datetime.datetime.fromtimestamp(transfer.created))
                     provider.create_withdraw_transactions(
                         transfer.id, transfer.amount, transfer.currency,
                         transfer.description, created_at=created_at)
         except stripe.error.InvalidRequestError as err:
             LOGGER.exception(err)
Esempio n. 46
0
def pass_paid_subscription(request, organization=None, plan=None):
    #pylint: disable=unused-argument
    if organization and not isinstance(organization, Organization):
        organization = get_object_or_404(Organization, slug=organization)
    if plan and not isinstance(plan, Plan):
        plan = get_object_or_404(Plan, slug=plan)
    subscribed_at = datetime_or_now()
    subscriptions = Subscription.objects.filter(organization=organization,
                                                plan=plan,
                                                ends_at__gt=subscribed_at)
    if not subscriptions.exists():
        raise Http404("%(organization)s has no subscription to %(plan)s'\
' as of %(date)s" % {
            'organization': organization,
            'plan': plan,
            'date': subscribed_at
        })
    return not subscriptions.first().is_locked
Esempio n. 47
0
 def generate_subscriptions(self, subscriber, nb_subscriptions=None):
     at_time = datetime_or_now()
     if nb_subscriptions is None:
         nb_subscriptions = settings.REST_FRAMEWORK['PAGE_SIZE'] * 4
     self.stdout.write("%d subscriptions\n" % nb_subscriptions)
     nb_plans = Plan.objects.count()
     fake = Faker()
     for _ in range(0, nb_subscriptions):
         rank = random.randint(1, nb_plans - 1)
         plan = Plan.objects.all().order_by('pk')[rank]
         created_at = fake.date_time_between_dates(
             datetime_start=at_time - datetime.timedelta(365),
             datetime_end=at_time + datetime.timedelta(365))
         Subscription.objects.create(organization=subscriber,
                                     plan=plan,
                                     created_at=created_at,
                                     ends_at=created_at +
                                     datetime.timedelta(30))
Esempio n. 48
0
def is_testing(site):
    if site.slug in [settings.APP_NAME, '%s-master' % settings.APP_NAME]:
        return False
    if site.db_name == settings.DB_TEST:
        return True
    # We only want to automatically switch to testing if a subscription isn't
    # paid for mallspace. It is necessary for the on-boarding business logic.
    # In streetside, we prefer to avoid an extra query.
    # Implementation note:
    # We use ``organization_id=site.account_id`` such that Django does not
    # start generating queries with our djaodjin-master organization ids
    # into the streetside database.
    if not is_streetside(site):
        subscriptions = Subscription.objects.db_manager(
            using='default').filter(
                organization_id=site.account_id,
                ends_at__gt=datetime_or_now()).exclude(plan__slug='streetside')
        return not subscriptions.exists()
    return False
Esempio n. 49
0
    def get(self, request, *args, **kwargs):
        ends_at = request.GET.get('ends_at', None)
        if ends_at:
            ends_at = parse_datetime(ends_at)
        ends_at = datetime_or_now(ends_at)

        account_title = 'Payments'
        account = Transaction.RECEIVABLE
        # We use ``Transaction.RECEIVABLE`` which technically counts the number
        # or orders, not the number of payments.

        _, customer_table, customer_extra = \
            aggregate_monthly_transactions(self.get_organization(), account,
                account_title=account_title,
                from_date=ends_at)

        return Response(
            {"title": "Customers",
                "table": customer_table, "extra": customer_extra})
Esempio n. 50
0
    def get(self, request, *args, **kwargs):
        ends_at = request.GET.get('ends_at', None)
        if ends_at:
            ends_at = parse_datetime(ends_at)
        ends_at = datetime_or_now(ends_at)
        organization = self.get_organization()
        table = []
        for plan in Plan.objects.filter(organization=organization):
            values = active_subscribers(
                plan, from_date=self.kwargs.get('from_date'))
            table.append({"key": plan.slug, "values": values,
                          "is_active": plan.is_active})
        extra = [{"key": "churn",
            "values": churn_subscribers(
                from_date=self.kwargs.get('from_date'))}]

        return Response(
            {"title": "Active Subscribers",
                "table": table, "extra": extra})
Esempio n. 51
0
    def get(self, request, *args, **kwargs):
        ends_at = request.GET.get('ends_at', None)
        if ends_at:
            ends_at = parse_datetime(ends_at)
        ends_at = datetime_or_now(ends_at)

        account_title = 'Payments'
        account = Transaction.RECEIVABLE
        # We use ``Transaction.RECEIVABLE`` which technically counts the number
        # or orders, not the number of payments.

        _, customer_table, customer_extra = \
            aggregate_monthly_transactions(self.get_organization(), account,
                account_title=account_title,
                from_date=ends_at)

        return Response({
            "title": "Customers",
            "table": customer_table,
            "extra": customer_extra
        })
Esempio n. 52
0
    def get(self, request, *args, **kwargs):
        ends_at = request.GET.get('ends_at', None)
        if ends_at:
            ends_at = parse_datetime(ends_at)
        ends_at = datetime_or_now(ends_at)

        # XXX to fix: returns payments in customer currency
        account_table, _, _ = \
            aggregate_monthly_transactions(self.get_organization(),
                Transaction.FUNDS, account_title='Payments',
                from_date=ends_at, orig='dest', dest='orig')

        _, refund_amount = aggregate_monthly(
            self.get_organization(), Transaction.REFUND,
            from_date=ends_at, orig='dest', dest='dest')

        account_table += [{"key": "Refunds",
                           "values": refund_amount}]

        return Response(
            {"title": "Amount",
            "unit": "$", "scale": 0.01, "table": account_table})
    def _handle(self, *args, **options):
        #pylint: disable=too-many-locals,too-many-statements
        from saas.managers.metrics import month_periods  # avoid import loop
        from saas.models import (Charge, ChargeItem, Organization, Plan,
                                 Subscription)

        if 'database' in options:
            db_name = options['database']
            set_current_site(get_site_model().objects.get(
                slug=options['provider'], db_name=db_name),
                             path_prefix='')
        else:
            db_name = 'default'
        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 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)
                transaction_item = Transaction.objects.new_subscription_order(
                    subscription,
                    nb_natural_periods=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=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))
Esempio n. 54
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))
Esempio n. 55
0
 def get_filename(self):
     return 'subscribers-{}-{}.csv'.format(
         self.subscriber_type, datetime_or_now().strftime('%Y%m%d'))
Esempio n. 56
0
    def handle(self, *args, **options):
        #pylint: disable=too-many-locals,too-many-statements
        from saas.managers.metrics import month_periods # avoid import loop
        from saas.models import (Charge, ChargeItem, Organization, Plan,
            Subscription)

        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 len(args) > 0:
            from_date = datetime.datetime.strptime(
                args[0], '%Y-%m-%d')
        # Create Income transactions that represents a growing bussiness.
        provider = Organization.objects.get(pk=2)
        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.new_instance(
                    customer, plan, ends_at=now + datetime.timedelta(days=31))
                subscription.save()
                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(all_subscriptions,
                all_subscriptions.count() - nb_churn_customers)
            for subscription in subscriptions:
                nb_periods = random.randint(1, 6)
                transaction_item = Transaction.objects.new_subscription_order(
                    subscription, nb_natural_periods=nb_periods,
                    created_at=end_period)
                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()
            print "%d new and %d churned customers at %s" % (
                nb_new_customers, nb_churn_customers, end_period)
Esempio n. 57
0
 def get_queryset(self):
     #pylint: disable=too-many-locals
     self.customer = self.get_organization()
     created_at = datetime_or_now()
     prorate_to_billing = False
     prorate_to = None
     if prorate_to_billing:
         # XXX First we add enough periods to get the next billing date later
         # than created_at but no more than one period in the future.
         prorate_to = self.customer.billing_start
     invoicables = []
     for cart_item in CartItem.objects.get_cart(user=self.request.user):
         if cart_item.email:
             full_name = ' '.join([
                     cart_item.first_name, cart_item.last_name]).strip()
             for_descr = ', for %s (%s)' % (full_name, cart_item.email)
             organization_queryset = Organization.objects.filter(
                 email=cart_item.email)
             if organization_queryset.exists():
                 organization = organization_queryset.get()
             else:
                 organization = Organization(
                     full_name='%s %s' % (
                         cart_item.first_name, cart_item.last_name),
                     email=cart_item.email)
         else:
             for_descr = ''
             organization = self.customer
         try:
             # If we can extend a current ``Subscription`` we will.
             # XXX For each (organization, plan) there should not
             #     be overlapping timeframe [created_at, ends_at[,
             #     None-the-less, it might be a good idea to catch
             #     and throw a nice error message in case.
             subscription = Subscription.objects.get(
                 organization=organization, plan=cart_item.plan,
                 ends_at__gt=datetime_or_now())
         except Subscription.DoesNotExist:
             ends_at = prorate_to
             if not ends_at:
                 ends_at = created_at
             subscription = Subscription.objects.new_instance(
                 organization, cart_item.plan, ends_at=ends_at)
         lines = []
         options = self.get_invoicable_options(subscription, created_at,
             prorate_to=prorate_to, coupon=cart_item.coupon)
         if cart_item.nb_periods > 0:
             # The number of periods was already selected so we generate
             # a line instead.
             for line in options:
                 plan = subscription.plan
                 nb_periods = plan.period_number(line.descr)
                 if nb_periods == cart_item.nb_periods:
                     # ``TransactionManager.new_subscription_order``
                     # will have created a ``Transaction``
                     # with the ultimate subscriber
                     # as payee. Overriding ``dest_organization`` here
                     # insures in all cases (bulk and direct buying),
                     # the transaction is recorded (in ``execute_order``)
                     # on behalf of the customer on the checkout page.
                     line.dest_organization = self.customer
                     line.descr += for_descr
                     lines += [line]
                     options = []
                     break
         invoicables += [{
             'name': cart_item.name, 'descr': cart_item.descr,
             'subscription': subscription,
             "lines": lines, "options": options}]
     return invoicables
    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))
Esempio n. 59
0
 def get_filename(self):
     return 'registered-{}.csv'.format(datetime_or_now().strftime('%Y%m%d'))
Esempio n. 60
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))