def test_incomplete_last_month(self): dates = month_periods( from_date=date(year=2014, month=1, day=9)) self.assertTrue(len(dates) == 13) self.assertTrue( dates[0] == datetime(year=2013, month=2, day=1, tzinfo=utc)) self.assertTrue( dates[1] == datetime(year=2013, month=3, day=1, tzinfo=utc)) self.assertTrue( dates[2] == datetime(year=2013, month=4, day=1, tzinfo=utc)) self.assertTrue( dates[3] == datetime(year=2013, month=5, day=1, tzinfo=utc)) self.assertTrue( dates[4] == datetime(year=2013, month=6, day=1, tzinfo=utc)) self.assertTrue( dates[5] == datetime(year=2013, month=7, day=1, tzinfo=utc)) self.assertTrue( dates[6] == datetime(year=2013, month=8, day=1, tzinfo=utc)) self.assertTrue( dates[7] == datetime(year=2013, month=9, day=1, tzinfo=utc)) self.assertTrue( dates[8] == datetime(year=2013, month=10, day=1, tzinfo=utc)) self.assertTrue( dates[9] == datetime(year=2013, month=11, day=1, tzinfo=utc)) self.assertTrue( dates[10] == datetime(year=2013, month=12, day=1, tzinfo=utc)) self.assertTrue( dates[11] == datetime(year=2014, month=1, day=1, tzinfo=utc)) self.assertTrue( dates[12] == datetime(year=2014, month=1, day=9, tzinfo=utc))
def get(self, request, *args, **kwargs): #pylint: disable=unused-argument self.cache_fields(request) response = HttpResponse(content_type='text/csv') response['Content-Disposition'] = ('attachment; filename="%s.csv"' % self.queryname) writer = csv.writer(response) # column headers values = ['name'] for end_period in month_periods(from_date=self.ends_at): values += [end_period] writer.writerow(values) # rows for key in Transaction.objects.distinct_accounts(): values = [key] + [item[1] for item in monthly_balances( self.organization, key, self.ends_at)] writer.writerow(values) return response
def get(self, request, *args, **kwargs): #pylint: disable=unused-argument self.cache_fields(request) response = HttpResponse(content_type='text/csv') response['Content-Disposition'] = ('attachment; filename="%s.csv"' % self.queryname) writer = csv.writer(response) # column headers values = ['name'] for end_period in month_periods(from_date=self.ends_at): values += [end_period] writer.writerow(values) # rows for key in Transaction.objects.distinct_accounts(): values = [key] + [ item[1] for item in monthly_balances(self.organization, key, self.ends_at) ] writer.writerow(values) return response
def test_month_periods_pos_offset(self): """ Test datetime with positive timeoffset and no timezone """ results = month_periods(from_date="2018-04-18T00:00:00+03:00") results = [str(res) for res in results] self.assertEqual(results, [ '2017-05-01 00:00:00+03:00', '2017-06-01 00:00:00+03:00', '2017-07-01 00:00:00+03:00', '2017-08-01 00:00:00+03:00', '2017-09-01 00:00:00+03:00', '2017-10-01 00:00:00+03:00', '2017-11-01 00:00:00+03:00', '2017-12-01 00:00:00+03:00', '2018-01-01 00:00:00+03:00', '2018-02-01 00:00:00+03:00', '2018-03-01 00:00:00+03:00', '2018-04-01 00:00:00+03:00', '2018-04-18 00:00:00+03:00'])
def test_month_periods_utc(self): """ Test UTC datetime with no timezone """ results = month_periods(from_date="2018-04-18T00:00:00+00:00") results = [str(res) for res in results] self.assertEqual(results, [ '2017-05-01 00:00:00+00:00', '2017-06-01 00:00:00+00:00', '2017-07-01 00:00:00+00:00', '2017-08-01 00:00:00+00:00', '2017-09-01 00:00:00+00:00', '2017-10-01 00:00:00+00:00', '2017-11-01 00:00:00+00:00', '2017-12-01 00:00:00+00:00', '2018-01-01 00:00:00+00:00', '2018-02-01 00:00:00+00:00', '2018-03-01 00:00:00+00:00', '2018-04-01 00:00:00+00:00', '2018-04-18 00:00:00+00:00'])
def test_month_periods_timezone(self): """ Test datetime with a timezone """ results = month_periods(from_date="2018-04-18T00:00:00-04:00", tz="US/Eastern") results = [str(res) for res in results] self.assertEqual(results, [ '2017-05-01 00:00:00-04:00', '2017-06-01 00:00:00-04:00', '2017-07-01 00:00:00-04:00', '2017-08-01 00:00:00-04:00', '2017-09-01 00:00:00-04:00', '2017-10-01 00:00:00-04:00', '2017-11-01 00:00:00-04:00', '2017-12-01 00:00:00-05:00', '2018-01-01 00:00:00-05:00', '2018-02-01 00:00:00-05:00', '2018-03-01 00:00:00-05:00', '2018-04-01 00:00:00-04:00', '2018-04-18 00:00:00-04:00'])
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))
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)
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))
def get_headings(self): return ['name'] + [ end_period for end_period in month_periods(from_date=self.ends_at)]
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.managers.metrics 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=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))
def handle(self, *args, **options): #pylint: disable=too-many-locals,too-many-statements from saas.managers.metrics 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))