def _init_pro_with_rb_plan_and_version(self): plan = SoftwarePlan( name="Pro_with_30_RB_reports", description="Pro + 30 report builder reports", edition=SoftwarePlanEdition.PRO, visibility=SoftwarePlanVisibility.INTERNAL, ) plan.save() role = Role.objects.create( slug="pro_with_rb_30_role", name="Pro + 30 rb reports", ) for privilege in [privileges.REPORT_BUILDER_30]: # Doesn't actually include the pro roles... privilege = Role.objects.get(slug=privilege) Grant.objects.create( from_role=role, to_role=privilege, ) self.pro_rb_version = SoftwarePlanVersion( plan=plan, role=role ) product = SoftwareProduct.objects.get(name='CommCare Pro', product_type=SoftwareProductType.COMMCARE) rate = product.get_rate() rate.save() self.pro_rb_version.product_rate = rate self.pro_rb_version.save()
def save(self, request): if not self.is_update: messages.info(request, "No changes to rates and roles were present, so the current version was kept.") return if self.cleaned_data['create_new_role']: role = Role.objects.create( slug=self.cleaned_data['new_role_slug'], name=self.cleaned_data['new_role_name'], description=self.cleaned_data['new_role_description'], ) for privilege in self.cleaned_data['privileges']: privilege = Role.objects.get(slug=privilege) Grant.objects.create( from_role=role, to_role=privilege, ) else: role = Role.objects.get(slug=self.cleaned_data['role_slug']) new_version = SoftwarePlanVersion( plan=self.plan, role=role ) new_version.save() for feature_rate in self.new_feature_rates: feature_rate.save() new_version.feature_rates.add(feature_rate) for product_rate in self.new_product_rates: product_rate.save() new_version.product_rates.add(product_rate) new_version.save() messages.success(request, 'The version for %s Software Plan was successfully updated.' % new_version.plan.name)
def test_changes_inactive_versions(self): plan = SoftwarePlan(name='Test Plan') plan.save() inactive_version = SoftwarePlanVersion( role=self.old_role, plan=plan, product_rate=self.generic_product_rate, is_active=False, ) inactive_version.save() self.assertEqual(inactive_version.version, 1) active_role = Role.objects.create(slug='active_role', name='active') active_version = SoftwarePlanVersion( role=active_role, plan=plan, product_rate=self.generic_product_rate) active_version.save() change_role_for_software_plan_version('old_role', 'new_role') # refetch plan = SoftwarePlan.objects.get(name='Test Plan') # ensure software plan's active version is still the active role self.assertEqual(plan.get_version().role.slug, 'active_role') inactive_version = plan.softwareplanversion_set.filter( is_active=False).latest('date_created') # ensure the inactive plan version was updated to the new role self.assertEqual(inactive_version.role.slug, 'new_role')
def test_limit_to_plan_version_id(self): plan_to_update = SoftwarePlan(name='Plan To Update') plan_to_update.save() version_to_update = SoftwarePlanVersion( role=self.old_role, plan=plan_to_update, product_rate=self.generic_product_rate) version_to_update.save() plan_to_ignore = SoftwarePlan(name='Plan To Ignore') plan_to_ignore.save() version_to_ignore = SoftwarePlanVersion( role=self.old_role, plan=plan_to_ignore, product_rate=self.generic_product_rate) version_to_ignore.save() change_role_for_software_plan_version( 'old_role', 'new_role', limit_to_plan_version_id=version_to_update.id) # refetch plan_to_update = SoftwarePlan.objects.get(name='Plan To Update') plan_to_ignore = SoftwarePlan.objects.get(name='Plan To Ignore') self.assertEqual(plan_to_update.get_version().role.slug, 'new_role') self.assertEqual(plan_to_ignore.get_version().role.slug, 'old_role')
def test_dry_run(self): plan = SoftwarePlan(name='Test Plan') plan.save() version = SoftwarePlanVersion(role=self.old_role, plan=plan, product_rate=self.generic_product_rate) version.save() change_role_for_software_plan_version('old_role', 'new_role', dry_run=True) # refetch plan = SoftwarePlan.objects.get(name='Test Plan') self.assertEqual(plan.get_version().role.slug, 'old_role')
def test_raises_exception_if_plan_version_id_does_not_reference_old_role( self): plan = SoftwarePlan(name='Test Plan 1') plan.save() version = SoftwarePlanVersion(role=self.old_role, plan=plan, product_rate=self.generic_product_rate) version.save() Role.objects.create(slug='mismatch_role', name='mismatch') with self.assertRaises(PlanVersionAndRoleMismatch): change_role_for_software_plan_version( 'mismatch_role', 'new_role', limit_to_plan_version_id=version.id)
def test_changes_active_versions(self): plan = SoftwarePlan(name='Test Plan') plan.save() active_version = SoftwarePlanVersion( role=self.old_role, plan=plan, product_rate=self.generic_product_rate, is_active=True) active_version.save() self.assertEqual(active_version.version, 1) change_role_for_software_plan_version('old_role', 'new_role') # refetch plan = SoftwarePlan.objects.get(name='Test Plan') self.assertEqual(plan.get_version().version, 1) self.assertEqual(plan.get_version().role.slug, 'new_role')
def _get_or_create_new_software_plan_version(plan, from_version, new_role, dry_run=False): dry_run_tag = '[DRY_RUN]' if dry_run else '' version = plan.get_version() if version and version.role.slug == new_role.slug: logger.info( f'{dry_run_tag}Found software plan version for plan {plan.name} with role {new_role.slug}.' ) return version else: new_version = SoftwarePlanVersion( plan=plan, product_rate=from_version.product_rate, role=new_role, ) if not dry_run: new_version.save() new_version.feature_rates.set( list(from_version.feature_rates.all())) new_version.save() logger.info( f'{dry_run_tag}Created new software plan version for plan {plan.name} with role {new_role.slug}.' ) return new_version
def _instantiate_plans_from_list(plan_list): plans = [] for plan in plan_list: software_plan, created = SoftwarePlan.objects.get_or_create(name=plan['name']) plan_version = SoftwarePlanVersion( plan=software_plan, role=role_gen.arbitrary_role(), ) plan_version.save() plan_version.product_rates.add(SoftwareProductRate.new_rate(plan['name'], plan['fee'])) for rate in plan['rates']: plan_version.feature_rates.add( FeatureRate.new_rate( rate['name'], rate['type'], monthly_fee=rate.get('fee'), monthly_limit=rate.get('limit'), per_excess_fee=rate.get('excess'), ) ) plan_version.save() plans.append(software_plan) return plans
def ensure_plans(self, dry_run=False): edition_to_features = self.ensure_features(dry_run=dry_run) for product_type in self.product_types: for edition in self.editions: role_slug = self.BOOTSTRAP_EDITION_TO_ROLE[edition] try: role = Role.objects.get(slug=role_slug) except ObjectDoesNotExist: logging.info("Could not find the role '%s'. Did you forget to run cchq_prbac_bootstrap?") logging.info("Aborting. You should figure this out.") return software_plan_version = SoftwarePlanVersion(role=role) product, product_rates = self.ensure_product_and_rate(product_type, edition, dry_run=dry_run) feature_rates = self.ensure_feature_rates(edition_to_features[edition], edition, dry_run=dry_run) software_plan = SoftwarePlan( name='%s Edition' % product.name, edition=edition, visibility=SoftwarePlanVisibility.PUBLIC ) if dry_run: logging.info("[DRY RUN] Creating Software Plan: %s" % software_plan) else: try: software_plan = SoftwarePlan.objects.get(name=software_plan.name) logging.info("Plan '%s' already exists. Using existing plan to add version." % software_plan.name) except ObjectDoesNotExist: software_plan.save() logging.info("Creating Software Plan: %s" % software_plan) software_plan_version.plan = software_plan software_plan_version.save() for product_rate in product_rates: software_plan_version.product_rates.add(product_rate) for feature_rate in feature_rates: software_plan_version.feature_rates.add(feature_rate) software_plan_version.save() default_product_plan = DefaultProductPlan(product_type=product.product_type, edition=edition) if dry_run: logging.info("[DRY RUN] Setting plan as default for product '%s' and edition '%s'." % (product.product_type, default_product_plan.edition)) else: try: default_product_plan = DefaultProductPlan.objects.get(product_type=product.product_type, edition=edition) logging.info("Default for product '%s' and edition '%s' already exists." % (product.product_type, default_product_plan.edition)) except ObjectDoesNotExist: default_product_plan.plan = software_plan default_product_plan.save() logging.info("Setting plan as default for product '%s' and edition '%s'." % (product.product_type, default_product_plan.edition))
def ensure_plans(self, dry_run=False): edition_to_features = self.ensure_features(dry_run=dry_run) for product_type in self.product_types: for edition in self.editions: role_slug = self.BOOTSTRAP_EDITION_TO_ROLE[edition] try: role = Role.objects.get(slug=role_slug) except ObjectDoesNotExist: logger.info("Could not find the role '%s'. Did you forget to run cchq_prbac_bootstrap?") logger.info("Aborting. You should figure this out.") return software_plan_version = SoftwarePlanVersion(role=role) product, product_rates = self.ensure_product_and_rate(product_type, edition, dry_run=dry_run) feature_rates = self.ensure_feature_rates(edition_to_features[edition], edition, dry_run=dry_run) software_plan = SoftwarePlan( name='%s Edition' % product.name, edition=edition, visibility=SoftwarePlanVisibility.PUBLIC ) if dry_run: logger.info("[DRY RUN] Creating Software Plan: %s" % software_plan.name) else: try: software_plan = SoftwarePlan.objects.get(name=software_plan.name) if self.verbose: logger.info("Plan '%s' already exists. Using existing plan to add version." % software_plan.name) except SoftwarePlan.DoesNotExist: software_plan.save() if self.verbose: logger.info("Creating Software Plan: %s" % software_plan.name) software_plan_version.plan = software_plan software_plan_version.save() for product_rate in product_rates: product_rate.save() software_plan_version.product_rates.add(product_rate) for feature_rate in feature_rates: feature_rate.save() software_plan_version.feature_rates.add(feature_rate) software_plan_version.save() if edition == SoftwarePlanEdition.ADVANCED: trials = [True, False] else: trials = [False] for is_trial in trials: default_product_plan = DefaultProductPlan(product_type=product.product_type, edition=edition, is_trial=is_trial) if dry_run: logger.info("[DRY RUN] Setting plan as default for product '%s' and edition '%s'." % (product.product_type, default_product_plan.edition)) else: try: default_product_plan = DefaultProductPlan.objects.get(product_type=product.product_type, edition=edition, is_trial=is_trial) if self.verbose: logger.info("Default for product '%s' and edition " "'%s' already exists." % ( product.product_type, default_product_plan.edition )) except ObjectDoesNotExist: default_product_plan.plan = software_plan default_product_plan.save() if self.verbose: logger.info("Setting plan as default for product '%s' and edition '%s'." % (product.product_type, default_product_plan.edition))
class TestSubscriptionPermissionsChanges(BaseAccountingTest): def setUp(self): super(TestSubscriptionPermissionsChanges, self).setUp() self.project = Domain( name="test-sub-changes", is_active=True, ) self.project.save() self.admin_user = generator.arbitrary_web_user() self.admin_user.add_domain_membership(self.project.name, is_admin=True) self.admin_user.save() self.account = BillingAccount.get_or_create_account_by_domain( self.project.name, created_by=self.admin_user.username)[0] self.advanced_plan = DefaultProductPlan.get_default_plan_by_domain( self.project.name, edition=SoftwarePlanEdition.ADVANCED) self._init_pro_with_rb_plan_and_version() def _init_pro_with_rb_plan_and_version(self): plan = SoftwarePlan( name="Pro_with_30_RB_reports", description="Pro + 30 report builder reports", edition=SoftwarePlanEdition.PRO, visibility=SoftwarePlanVisibility.INTERNAL, ) plan.save() role = Role.objects.create( slug="pro_with_rb_30_role", name="Pro + 30 rb reports", ) for privilege in [privileges.REPORT_BUILDER_30]: # Doesn't actually include the pro roles... privilege = Role.objects.get(slug=privilege) Grant.objects.create( from_role=role, to_role=privilege, ) self.pro_rb_version = SoftwarePlanVersion( plan=plan, role=role ) product = SoftwareProduct.objects.get(name='CommCare Pro', product_type=SoftwareProductType.COMMCARE) rate = product.get_rate() rate.save() self.pro_rb_version.product_rate = rate self.pro_rb_version.save() def _subscribe_to_advanced(self): return Subscription.new_domain_subscription( self.account, self.project.name, self.advanced_plan, web_user=self.admin_user.username ) def _subscribe_to_pro_with_rb(self): subscription = Subscription.get_subscribed_plan_by_domain(self.project)[1] new_subscription = subscription.change_plan( self.pro_rb_version, date_end=None, web_user=self.admin_user, service_type=SubscriptionType.IMPLEMENTATION, pro_bono_status=ProBonoStatus.NO, internal_change=True, ) return new_subscription def test_app_icon_permissions(self): LOGO_HOME = u'hq_logo_android_home' LOGO_LOGIN = u'hq_logo_android_login' advanced_sub = self._subscribe_to_advanced() with open(os.path.join(os.path.dirname(__file__), 'data', 'app-commcare-icon-standard.json')) as f: standard_source = json.load(f) with open(os.path.join(os.path.dirname(__file__), 'data', 'app-commcare-icon-build.json')) as f: build_source = json.load(f) app_standard = Application.wrap(standard_source) app_standard.save() self.assertEqual(self.project.name, app_standard.domain) app_build = Application.wrap(build_source) app_build.save() self.assertEqual(self.project.name, app_build.domain) self.assertTrue(LOGO_HOME in app_standard.logo_refs.keys()) self.assertTrue(LOGO_LOGIN in app_standard.logo_refs.keys()) self.assertTrue(LOGO_HOME in app_build.logo_refs.keys()) self.assertTrue(LOGO_LOGIN in app_build.logo_refs.keys()) advanced_sub.cancel_subscription(web_user=self.admin_user.username) app_standard = Application.get(app_standard._id) app_build = Application.get(app_build._id) self.assertFalse(LOGO_HOME in app_standard.logo_refs.keys()) self.assertFalse(LOGO_LOGIN in app_standard.logo_refs.keys()) self.assertFalse(LOGO_HOME in app_build.logo_refs.keys()) self.assertFalse(LOGO_LOGIN in app_build.logo_refs.keys()) self._subscribe_to_advanced() app_standard = Application.get(app_standard._id) app_build = Application.get(app_build._id) self.assertTrue(LOGO_HOME in app_standard.logo_refs.keys()) self.assertTrue(LOGO_LOGIN in app_standard.logo_refs.keys()) self.assertTrue(LOGO_HOME in app_build.logo_refs.keys()) self.assertTrue(LOGO_LOGIN in app_build.logo_refs.keys()) def test_report_builder_datasource_deactivation(self): def _get_data_source(id_): return get_datasource_config(id_, self.project.name)[0] # Upgrade the domain # (for the upgrade to work, there has to be an existing subscription, # which is why we subscribe to advanced first) self._subscribe_to_advanced() pro_with_rb_sub = self._subscribe_to_pro_with_rb() # Create reports and data sources builder_report_data_source = DataSourceConfiguration( domain=self.project.name, is_deactivated=False, referenced_doc_type="XFormInstance", table_id="foo", ) other_data_source = DataSourceConfiguration( domain=self.project.name, is_deactivated=False, referenced_doc_type="XFormInstance", table_id="bar", ) builder_report_data_source.save() other_data_source.save() report_builder_report = ReportConfiguration( domain=self.project.name, config_id=builder_report_data_source._id, report_meta=ReportMeta(created_by_builder=True), ) report_builder_report.save() # downgrade the domain pro_with_rb_sub.cancel_subscription(web_user=self.admin_user.username) # Check that the builder data source is deactivated builder_report_data_source = _get_data_source(builder_report_data_source._id) self.assertTrue(builder_report_data_source.is_deactivated) # Check that the other data source has not been deactivated other_data_source = _get_data_source(other_data_source._id) self.assertFalse(other_data_source.is_deactivated) # upgrade the domain # (for the upgrade to work, there has to be an existing subscription, # which is why we subscribe to advanced first) self._subscribe_to_advanced() pro_with_rb_sub = self._subscribe_to_pro_with_rb() # check that the data source is activated builder_report_data_source = _get_data_source(builder_report_data_source._id) self.assertFalse(builder_report_data_source.is_deactivated) # delete the data sources builder_report_data_source.delete() other_data_source.delete() # Delete the report report_builder_report.delete() # reset the subscription pro_with_rb_sub.cancel_subscription(web_user=self.admin_user.username) def tearDown(self): self.project.delete() self.admin_user.delete() generator.delete_all_subscriptions() generator.delete_all_accounts() super(TestSubscriptionPermissionsChanges, self).tearDown()
class TestSubscriptionPermissionsChanges(BaseAccountingTest): def setUp(self): super(TestSubscriptionPermissionsChanges, self).setUp() self.project = Domain( name="test-sub-changes", is_active=True, ) self.project.save() self.admin_username = generator.create_arbitrary_web_user_name() self.account = BillingAccount.get_or_create_account_by_domain( self.project.name, created_by=self.admin_username)[0] self.advanced_plan = DefaultProductPlan.get_default_plan_version( edition=SoftwarePlanEdition.ADVANCED) self._init_pro_with_rb_plan_and_version() def _init_pro_with_rb_plan_and_version(self): plan = SoftwarePlan( name="Pro_with_30_RB_reports", description="Pro + 30 report builder reports", edition=SoftwarePlanEdition.PRO, visibility=SoftwarePlanVisibility.INTERNAL, ) plan.save() role = Role.objects.create( slug="pro_with_rb_30_role", name="Pro + 30 rb reports", ) for privilege in [privileges.REPORT_BUILDER_30 ]: # Doesn't actually include the pro roles... privilege = Role.objects.get(slug=privilege) Grant.objects.create( from_role=role, to_role=privilege, ) self.pro_rb_version = SoftwarePlanVersion(plan=plan, role=role) self.pro_rb_version.product_rate = DefaultProductPlan.get_default_plan_version( SoftwarePlanEdition.PRO).product_rate self.pro_rb_version.save() def _subscribe_to_advanced(self): return Subscription.new_domain_subscription( self.account, self.project.name, self.advanced_plan, web_user=self.admin_username) def _subscribe_to_pro_with_rb(self): subscription = Subscription.get_active_subscription_by_domain( self.project.name) new_subscription = subscription.change_plan( self.pro_rb_version, date_end=None, web_user=self.admin_username, service_type=SubscriptionType.IMPLEMENTATION, pro_bono_status=ProBonoStatus.NO, internal_change=True, ) return new_subscription def test_app_icon_permissions(self): LOGO_HOME = u'hq_logo_android_home' LOGO_LOGIN = u'hq_logo_android_login' advanced_sub = self._subscribe_to_advanced() with open( os.path.join(os.path.dirname(__file__), 'data', 'app-commcare-icon-standard.json')) as f: standard_source = json.load(f) with open( os.path.join(os.path.dirname(__file__), 'data', 'app-commcare-icon-build.json')) as f: build_source = json.load(f) app_standard = Application.wrap(standard_source) app_standard.save() self.assertEqual(self.project.name, app_standard.domain) app_build = Application.wrap(build_source) app_build.save() self.assertEqual(self.project.name, app_build.domain) self.assertTrue(LOGO_HOME in app_standard.logo_refs) self.assertTrue(LOGO_LOGIN in app_standard.logo_refs) self.assertTrue(LOGO_HOME in app_build.logo_refs) self.assertTrue(LOGO_LOGIN in app_build.logo_refs) community_sub = advanced_sub.change_plan( DefaultProductPlan.get_default_plan_version()) app_standard = Application.get(app_standard._id) app_build = Application.get(app_build._id) self.assertFalse(LOGO_HOME in app_standard.logo_refs) self.assertFalse(LOGO_LOGIN in app_standard.logo_refs) self.assertFalse(LOGO_HOME in app_build.logo_refs) self.assertFalse(LOGO_LOGIN in app_build.logo_refs) community_sub.change_plan( DefaultProductPlan.get_default_plan_version( edition=SoftwarePlanEdition.ADVANCED)) app_standard = Application.get(app_standard._id) app_build = Application.get(app_build._id) self.assertTrue(LOGO_HOME in app_standard.logo_refs) self.assertTrue(LOGO_LOGIN in app_standard.logo_refs) self.assertTrue(LOGO_HOME in app_build.logo_refs) self.assertTrue(LOGO_LOGIN in app_build.logo_refs) def test_report_builder_datasource_deactivation(self): def _get_data_source(id_): return get_datasource_config(id_, self.project.name)[0] # Upgrade the domain # (for the upgrade to work, there has to be an existing subscription, # which is why we subscribe to advanced first) self._subscribe_to_advanced() pro_with_rb_sub = self._subscribe_to_pro_with_rb() # Create reports and data sources builder_report_data_source = DataSourceConfiguration( domain=self.project.name, is_deactivated=False, referenced_doc_type="XFormInstance", table_id="foo", ) other_data_source = DataSourceConfiguration( domain=self.project.name, is_deactivated=False, referenced_doc_type="XFormInstance", table_id="bar", ) builder_report_data_source.save() other_data_source.save() report_builder_report = ReportConfiguration( domain=self.project.name, config_id=builder_report_data_source._id, report_meta=ReportMeta(created_by_builder=True), ) report_builder_report.save() # downgrade the domain community_sub = pro_with_rb_sub.change_plan( DefaultProductPlan.get_default_plan_version()) # Check that the builder data source is deactivated builder_report_data_source = _get_data_source( builder_report_data_source._id) self.assertTrue(builder_report_data_source.is_deactivated) # Check that the other data source has not been deactivated other_data_source = _get_data_source(other_data_source._id) self.assertFalse(other_data_source.is_deactivated) # upgrade the domain # (for the upgrade to work, there has to be an existing subscription, # which is why we subscribe to advanced first) community_sub.change_plan( DefaultProductPlan.get_default_plan_version( edition=SoftwarePlanEdition.ADVANCED)) pro_with_rb_sub = self._subscribe_to_pro_with_rb() # check that the data source is activated builder_report_data_source = _get_data_source( builder_report_data_source._id) self.assertFalse(builder_report_data_source.is_deactivated) # delete the data sources builder_report_data_source.delete() other_data_source.delete() # Delete the report report_builder_report.delete() # reset the subscription pro_with_rb_sub.change_plan( DefaultProductPlan.get_default_plan_version()) def tearDown(self): self.project.delete() super(TestSubscriptionPermissionsChanges, self).tearDown()