Ejemplo n.º 1
0
 def test_absolute_benefit_offer_availability(self):
     """
     Verify that enterprise offer condition returns correct result for an absolute benefit with
     discount value greater than course price.
     """
     offer = factories.EnterpriseOfferFactory(
         partner=self.partner,
         benefit=factories.EnterpriseAbsoluteDiscountBenefitFactory(
             value=150),
         max_discount=Decimal(300),
         total_discount=Decimal(200))
     basket = BasketFactory(site=self.site, owner=self.user)
     basket.add_product(self.course_run.seat_products[0])
     self.mock_catalog_contains_course_runs(
         [self.course_run.id],
         self.condition.enterprise_customer_uuid,
         enterprise_customer_catalog_uuid=self.condition.
         enterprise_customer_catalog_uuid,
     )
     self.assertTrue(self.condition.is_satisfied(offer, basket))
Ejemplo n.º 2
0
 def test_is_satisfied_contains_content_items_failure(self):
     """ Ensure the condition returns false if the contains_content_item call fails. """
     offer = factories.EnterpriseOfferFactory(partner=self.partner,
                                              condition=self.condition)
     basket = BasketFactory(site=self.site, owner=self.user)
     basket.add_product(self.course_run.seat_products[0])
     self.mock_enterprise_learner_api(
         learner_id=self.user.id,
         enterprise_customer_uuid=str(
             self.condition.enterprise_customer_uuid),
         course_run_id=self.course_run.id,
     )
     self.mock_catalog_contains_course_runs(
         [self.course_run.id],
         self.condition.enterprise_customer_uuid,
         enterprise_customer_catalog_uuid=self.condition.
         enterprise_customer_catalog_uuid,
         contains_content=False,
         raise_exception=True)
     self.assertFalse(self.condition.is_satisfied(offer, basket))
Ejemplo n.º 3
0
 def test_email_status_update_success(
         self,
         post_data,
         response_data,
         status_code,
 ):
     """ Verify the endpoint updated the email status in offer_assignment """
     enterprise_offer = factories.EnterpriseOfferFactory(max_global_applications=None)
     offer_assignment = factories.OfferAssignmentFactory(
         offer=enterprise_offer,
         code='jfhrmndk554lwre',
         user_email='*****@*****.**',
     )
     post_data['offer_assignment_id'] = offer_assignment.id
     response_data['offer_assignment_id'] = offer_assignment.id
     response = self.client.post(self.path, data=json.dumps(post_data), content_type='application/json')
     self.assertEqual(response.status_code, status_code)
     self.assertDictEqual(response_data, response.json())
     updated_offer_assignment = OfferAssignment.objects.get(id=offer_assignment.id)
     self.assertEqual(updated_offer_assignment.status, OFFER_ASSIGNED)
Ejemplo n.º 4
0
 def test_max_user_applications_clean(self):
     """
     Verify that `clean` for `max_user_applications` field is working as expected.
     """
     num_applications = 3
     expected_errors = {
         'max_user_applications': [
             'Ensure new value must be greater than or equal to consumed({}) value.'
             .format(num_applications)
         ]
     }
     # create an enterprise offer that can be used upto 5 times and has already been used 3 times
     offer = factories.EnterpriseOfferFactory(max_user_applications=5,
                                              max_user_discount=500)
     for _ in range(num_applications):
         order = OrderFactory(user=self.user, status=ORDER.COMPLETE)
         OrderDiscountFactory(order=order, offer_id=offer.id, amount=10)
     # now try to update the offer with max_user_applications set to 2
     # which is less than the number of times this offer has already been used
     data = self.generate_data(max_user_applications=2)
     self.assert_form_errors(data, expected_errors, instance=offer)
Ejemplo n.º 5
0
    def test_offer_form_with_per_user_increased_limits(self):
        """
        Verify that an existing enterprise offer can be updated with per user increased limits.
        """
        data = self.generate_data(max_user_applications=40,
                                  max_user_discount=7000)
        self.mock_specific_enterprise_customer_api(
            data['enterprise_customer_uuid'])

        # create an enterprise offer with both max_global_applications and max_discount
        offer = factories.EnterpriseOfferFactory(max_user_applications=30,
                                                 max_user_discount=5000)
        # now try to update the offer with increased values
        form = EnterpriseOfferForm(request=self.request,
                                   data=data,
                                   instance=offer)
        self.assertTrue(form.is_valid())
        offer = form.save()
        self.assertEqual(offer.max_user_applications,
                         data['max_user_applications'])
        self.assertEqual(offer.max_user_discount, data['max_user_discount'])
Ejemplo n.º 6
0
 def test_absolute_benefit_offer_availability_with_max_user_discount(self):
     """
     Verify that enterprise offer condition returns correct result for an absolute benefit with
     discount value greater than course price.
     """
     offer = factories.EnterpriseOfferFactory(
         partner=self.partner,
         benefit=factories.EnterpriseAbsoluteDiscountBenefitFactory(value=150),
         max_user_discount=150
     )
     for _ in range(5):
         order = OrderFactory(user=self.user, status=ORDER.COMPLETE)
         OrderDiscountFactory(order=order, offer_id=offer.id, amount=10)
     basket = BasketFactory(site=self.site, owner=self.user)
     basket.add_product(self.course_run.seat_products[0])
     self.mock_catalog_contains_course_runs(
         [self.course_run.id],
         self.condition.enterprise_customer_uuid,
         enterprise_customer_catalog_uuid=self.condition.enterprise_customer_catalog_uuid,
     )
     self.assertTrue(self.condition.is_satisfied(offer, basket))
Ejemplo n.º 7
0
    def test_save_edit(self):
        """ Previously-created ConditionalOffer, Benefit, and Condition instances should be updated. """
        offer = factories.EnterpriseOfferFactory()
        ecm = EnterpriseContractMetadata(
            discount_value=self.contract_discount_value,
            discount_type=self.contract_discount_type,
            amount_paid=self.prepaid_invoice_amount,
        )
        offer.enterprise_contract_metadata = ecm
        data = self.generate_data(
            enterprise_customer_uuid=offer.condition.enterprise_customer_uuid,
            benefit_type=Benefit.FIXED
        )
        self.mock_specific_enterprise_customer_api(data['enterprise_customer_uuid'])
        form = EnterpriseOfferForm(request=self.request, data=data, instance=offer)
        form.is_valid()
        form.save()

        offer.refresh_from_db()
        self.assert_enterprise_offer_conditions(
            offer,
            data['enterprise_customer_uuid'],
            data['enterprise_customer_name'],
            data['enterprise_customer_catalog_uuid'],
            data['benefit_value'],
            data['benefit_type'],
            'Discount of type {} provided by {} for {}.'.format(
                ConditionalOffer.SITE,
                data['enterprise_customer_name'][:48],
                data['enterprise_customer_catalog_uuid']
            ),
            data['contract_discount_type'],
            data['contract_discount_value'],
            data['prepaid_invoice_amount'],
            data['sales_force_id'],
            data['max_global_applications'],
            data['max_discount'],
            data['max_user_applications'],
            data['max_user_discount'],
        )
Ejemplo n.º 8
0
    def create_data(self, voucher_type, max_uses, assignments):
        """
        Create vouchers, offers and offer assignments.
        """
        codes = {assignment['code'] for assignment in assignments}
        emails = sorted(
            {assignment['user_email']
             for assignment in assignments})
        quantity = len(codes)

        voucher_types = (Voucher.MULTI_USE, Voucher.ONCE_PER_CUSTOMER,
                         Voucher.MULTI_USE_PER_CUSTOMER)
        num_of_offers = quantity if voucher_type in voucher_types else 1

        offers = []
        for __ in range(num_of_offers):
            offers.append(
                factories.EnterpriseOfferFactory(
                    max_global_applications=max_uses))

        coupon = self.create_coupon(quantity=quantity,
                                    voucher_type=voucher_type)
        for index, info in enumerate(
                zip(coupon.attr.coupon_vouchers.vouchers.all(), codes)):
            voucher, code = info
            voucher.code = code
            voucher.offers.add(offers[index] if len(offers) > 1 else offers[0])
            voucher.save()

        data = {'codes': codes, 'emails': emails}
        serializer = CouponCodeAssignmentSerializer(data=data,
                                                    context={
                                                        'coupon':
                                                        coupon,
                                                        'template':
                                                        'An Email Template'
                                                    })
        if serializer.is_valid():
            serializer.save()
            assignments = serializer.data
Ejemplo n.º 9
0
    def test_is_satisfied(self, num_orders, email, offer_status,
                          condition_result, mock_request):
        """
        Ensure that condition returns expected result.
        """
        mock_request.return_value = self.request
        voucher = factories.VoucherFactory(usage=Voucher.SINGLE_USE,
                                           num_orders=num_orders)
        enterprise_offer = factories.EnterpriseOfferFactory(
            max_global_applications=None)
        voucher.offers.add(enterprise_offer)
        basket = BasketFactory(site=self.site, owner=UserFactory(email=email))
        basket.vouchers.add(voucher)
        factories.OfferAssignmentFactory(
            offer=enterprise_offer,
            code=voucher.code,
            user_email=email,
            status=offer_status,
        )

        assert self.condition.is_satisfied(enterprise_offer,
                                           basket) == condition_result
Ejemplo n.º 10
0
    def test_is_satisfied_with_course_entitlement_request_error(self):
        """ Ensure the condition returns False if an error occurs while fetching course details. """
        offer = factories.EnterpriseOfferFactory(partner=self.partner, condition=self.condition)
        basket = BasketFactory(site=self.site, owner=self.user)
        basket.add_product(self.entitlement)

        self.mock_course_detail_endpoint_error(
            self.entitlement,
            discovery_api_url=self.site_configuration.discovery_api_url,
            error=ReqConnectionError
        )
        self.mock_enterprise_learner_api(
            learner_id=self.user.id,
            enterprise_customer_uuid=str(self.condition.enterprise_customer_uuid),
            course_run_id=self.course_run.id,
        )
        self.mock_catalog_contains_course_runs(
            [self.entitlement.attr.UUID],
            self.condition.enterprise_customer_uuid,
            enterprise_customer_catalog_uuid=self.condition.enterprise_customer_catalog_uuid,
        )
        self.assertFalse(self.condition.is_satisfied(offer, basket))
Ejemplo n.º 11
0
    def test_is_satisfied_with_course_entitlement(self):
        """ Ensure the condition returns true if the basket contains a course entitlement. """
        offer = factories.EnterpriseOfferFactory(partner=self.partner, condition=self.condition)
        basket = BasketFactory(site=self.site, owner=self.user)
        basket.add_product(self.entitlement)

        self.mock_course_detail_endpoint(
            discovery_api_url=self.site_configuration.discovery_api_url,
            course=self.entitlement
        )
        self.mock_enterprise_learner_api(
            learner_id=self.user.id,
            enterprise_customer_uuid=str(self.condition.enterprise_customer_uuid),
            course_run_id=self.course_run.id,
        )
        self.mock_catalog_contains_course_runs(
            [self.entitlement.attr.UUID],
            self.condition.enterprise_customer_uuid,
            enterprise_customer_catalog_uuid=self.condition.enterprise_customer_catalog_uuid,
        )

        self.assertTrue(self.condition.is_satisfied(offer, basket))
Ejemplo n.º 12
0
 def test_init(self):
     """ The constructor should pull initial data from the passed-in instance. """
     enterprise_offer = factories.EnterpriseOfferFactory()
     ecm = EnterpriseContractMetadata(
         discount_value=25,
         discount_type=EnterpriseContractMetadata.PERCENTAGE,
         amount_paid=12345)
     enterprise_offer.enterprise_contract_metadata = ecm
     form = EnterpriseOfferForm(instance=enterprise_offer)
     self.assertEqual(uuid.UUID(form['enterprise_customer_uuid'].value()),
                      enterprise_offer.condition.enterprise_customer_uuid)
     self.assertEqual(
         uuid.UUID(form['enterprise_customer_catalog_uuid'].value()),
         enterprise_offer.condition.enterprise_customer_catalog_uuid)
     self.assertEqual(form['benefit_type'].value(),
                      enterprise_offer.benefit.proxy().benefit_class_type)
     self.assertEqual(form['benefit_value'].value(),
                      enterprise_offer.benefit.value)
     self.assertEqual(form['contract_discount_type'].value(),
                      EnterpriseContractMetadata.PERCENTAGE)
     self.assertEqual(form['contract_discount_value'].value(), 25)
     self.assertEqual(form['prepaid_invoice_amount'].value(), 12345)
Ejemplo n.º 13
0
    def test_multi_use_per_customer_voucher(self):
        """
        Verify `MULTI_USE_PER_CUSTOMER` behaves as expected.
        """
        voucher_data = dict(self.data, usage=Voucher.MULTI_USE_PER_CUSTOMER)
        enterprise_offer = factories.EnterpriseOfferFactory(
            max_global_applications=3)
        voucher = factories.VoucherFactory(**voucher_data)
        voucher.offers.add(enterprise_offer)

        user1 = UserFactory(email='*****@*****.**')
        user2 = UserFactory(email='*****@*****.**')

        self.use_voucher(voucher, user1)

        is_available, message = voucher.is_available_to_user(user1)
        assert (is_available, message) == (True, '')

        is_available, message = voucher.is_available_to_user(user2)
        assert (is_available,
                message) == (False,
                             'This voucher is assigned to another user.')
Ejemplo n.º 14
0
 def test_offer_availability_with_max_user_discount(self, discount_type,
                                                    num_prev_orders,
                                                    benefit_value,
                                                    is_satisfied):
     """
     Verify that enterprise offer with discount type percentage and absolute, condition returns correct result
     based on user limits in the offer.
     """
     benefits = {
         Benefit.PERCENTAGE:
         factories.EnterprisePercentageDiscountBenefitFactory(
             value=benefit_value),
         Benefit.FIXED:
         factories.EnterpriseAbsoluteDiscountBenefitFactory(
             value=benefit_value),
     }
     offer = factories.EnterpriseOfferFactory(
         partner=self.partner,
         benefit=benefits[discount_type],
         max_user_discount=150)
     for _ in range(num_prev_orders):
         order = OrderFactory(user=self.user, status=ORDER.COMPLETE)
         OrderDiscountFactory(order=order, offer_id=offer.id, amount=10)
     basket = BasketFactory(site=self.site, owner=self.user)
     basket.add_product(self.course_run.seat_products[0])
     basket.add_product(self.entitlement)
     self.mock_course_detail_endpoint(
         discovery_api_url=self.site_configuration.discovery_api_url,
         course=self.entitlement)
     self.mock_catalog_contains_course_runs(
         [self.course_run.id],
         self.condition.enterprise_customer_uuid,
         self.site.siteconfiguration.enterprise_api_url,
         enterprise_customer_catalog_uuid=self.condition.
         enterprise_customer_catalog_uuid,
     )
     self.assertEqual(self.condition.is_satisfied(offer, basket),
                      is_satisfied)
Ejemplo n.º 15
0
    def test_is_satisfied_when_owner_has_no_assignment(self):
        """
        Ensure that condition returns expected result the basket owner has no assignments.

        # voucher has free slots(3) available, no offer assignment for basket owner,
        # assignments(2) exist for other users, voucher has some redemptions(num_orders = 2)
        # basket owner is allowed to redeem the voucher
        """
        code = 'TA7WCQD3T4C7GHZ4'
        num_orders = 2
        max_global_applications = 7

        enterprise_offer = factories.EnterpriseOfferFactory(max_global_applications=max_global_applications)
        voucher = factories.VoucherFactory(usage=Voucher.MULTI_USE, code=code, num_orders=num_orders)
        voucher.offers.add(enterprise_offer)

        factories.OfferAssignmentFactory(offer=enterprise_offer, code=code, user_email='*****@*****.**')
        factories.OfferAssignmentFactory(offer=enterprise_offer, code=code, user_email='*****@*****.**')

        basket = factories.BasketFactory(site=self.site, owner=factories.UserFactory(email='*****@*****.**'))
        basket.vouchers.add(voucher)

        assert self.condition.is_satisfied(enterprise_offer, basket) is True
Ejemplo n.º 16
0
    def test_offer_availability_with_max_discount(self, discount_type,
                                                  total_discount,
                                                  benefit_value, is_satisfied):
        """
        Verify that enterprise offer with discount type percentage and absolute, condition returns correct result
        based on total_discount(consumed discount so far) and discount on course price covered by the offer.
        """
        benefits = {
            Benefit.PERCENTAGE:
            factories.EnterprisePercentageDiscountBenefitFactory(
                value=benefit_value),
            Benefit.FIXED:
            factories.EnterpriseAbsoluteDiscountBenefitFactory(
                value=benefit_value),
        }

        offer = factories.EnterpriseOfferFactory(
            partner=self.partner,
            benefit=benefits[discount_type],
            max_discount=Decimal(5000),
            total_discount=total_discount)
        basket = BasketFactory(site=self.site, owner=self.user)
        basket.add_product(self.course_run.seat_products[0])
        basket.add_product(self.entitlement)
        self.mock_course_detail_endpoint(
            discovery_api_url=self.site_configuration.discovery_api_url,
            course=self.entitlement)
        self.mock_catalog_contains_course_runs(
            [self.course_run.id],
            self.condition.enterprise_customer_uuid,
            self.site.siteconfiguration.enterprise_api_url,
            enterprise_customer_catalog_uuid=self.condition.
            enterprise_customer_catalog_uuid,
        )
        self.assertEqual(self.condition.is_satisfied(offer, basket),
                         is_satisfied)
Ejemplo n.º 17
0
 def test_email_status_update_success(
         self,
         post_data,
         response_data,
         status_code
 ):
     """ Verify the endpoint updated the email status in offer_assignment """
     enterprise_offer = factories.EnterpriseOfferFactory(max_global_applications=None)
     offer_assignment = factories.OfferAssignmentFactory(
         offer=enterprise_offer,
         code='jfhrmndk554lwre',
         user_email='*****@*****.**',
         status=OFFER_ASSIGNED
     )
     OfferAssignmentEmailAttempt.objects.create(offer_assignment=offer_assignment, send_id=post_data.get('send_id'))
     with LogCapture(level=logging.INFO) as log:
         with mock.patch("ecommerce.extensions.api.v2.views.assignmentemail.SailthruClient.receive_hardbounce_post",
                         return_value=True):
             response = self.client.post(self.path, data=json.dumps(post_data), content_type='application/json')
     log.check_present()
     self.assertEqual(response.status_code, status_code)
     self.assertDictEqual(response_data, response.json())
     updated_offer_assignment = OfferAssignment.objects.get(id=offer_assignment.id)
     self.assertEqual(updated_offer_assignment.status, OFFER_ASSIGNMENT_EMAIL_BOUNCED)
Ejemplo n.º 18
0
    def setup_enterprise_coupon_data(self, mock_learner_api=True):
        offer = factories.EnterpriseOfferFactory(
            partner=self.partner,
            condition=self.condition,
            offer_type=ConditionalOffer.VOUCHER)
        basket = factories.BasketFactory(site=self.site, owner=self.user)
        basket.add_product(self.course_run.seat_products[0])
        if mock_learner_api:
            self.mock_enterprise_learner_api(
                learner_id=self.user.id,
                enterprise_customer_uuid=str(
                    self.condition.enterprise_customer_uuid),
                course_run_id=self.course_run.id,
            )
        else:
            self.mock_enterprise_learner_api_for_learner_with_no_enterprise()

        self.mock_catalog_contains_course_runs(
            [self.course_run.id],
            self.condition.enterprise_customer_uuid,
            enterprise_customer_catalog_uuid=self.condition.
            enterprise_customer_catalog_uuid,
        )
        return offer, basket
Ejemplo n.º 19
0
 def test_is_satisfied_empty_basket(self):
     """ Ensure the condition returns False if the basket is empty. """
     offer = factories.EnterpriseOfferFactory(partner=self.partner, condition=self.condition)
     basket = factories.BasketFactory(site=self.site, owner=self.user)
     self.assertTrue(basket.is_empty)
     self.assertFalse(self.condition.is_satisfied(offer, basket))
Ejemplo n.º 20
0
 def test_is_satisfied_site_mismatch(self):
     """ Ensure the condition returns False if the offer partner does not match the basket site partner. """
     offer = factories.EnterpriseOfferFactory(partner=SiteConfigurationFactory().partner, condition=self.condition)
     basket = factories.BasketFactory(site=self.site, owner=self.user)
     basket.add_product(self.test_product)
     self.assertFalse(self.condition.is_satisfied(offer, basket))
Ejemplo n.º 21
0
    def setUp(self):
        super(BackfillOpportunityIdsCommandTests, self).setUp()

        # coupons and offers created for these enterprises are missing opportunity ids in database
        self.enterprise_without_opportunity_ids = {
            'af4b351f-5f1c-4fc3-af41-48bb38fcb161': 'sf100',
            '8212a8d8-c6b1-4023-8754-4d687c43d72f': 'sf200',
        }

        # coupons and offers created for these enterprise have the opportunity id
        self.enterprise_with_opportunity_id = ('68c7b796-3d9c-4038-a870-3b5eb75c5d39', 'sf999')

        # create enterprise coupons, enterprise offers and manual orders without opportunity id
        for enterprise_customer, __ in self.enterprise_without_opportunity_ids.items():
            self.init_data(enterprise_customer)

        # create an enterprise coupon, enterprise offer and manual order offer with opportunity id
        self.init_data(
            self.enterprise_with_opportunity_id[0],
            self.enterprise_with_opportunity_id[1],
        )

        # multi contracts data setup for coupons and offers
        self.multi_contract_vouchers = [
            ['0a434fa0-2edb-416a-ba24-0d504cc8f6d2', 1345, 'Voucher', 3000, 'OID400'],
            ['0a434fa0-2edb-416a-ba24-0d504cc8f6d2', 2876, 'Voucher', 3000, 'OID400'],
            ['0a434fa0-2edb-416a-ba24-0d504cc8f6d2', 9034, 'Voucher', 3000, 'OID450'],
            ['0a434fa0-2edb-416a-ba24-0d504cc8f6d2', 2223, 'Voucher', 3001, 'OID444'],
        ]

        created = []
        for record in self.multi_contract_vouchers:
            if record[3] not in created:
                created.append(record[3])
                coupon = self.create_coupon(enterprise_customer=record[0])
                coupon.id = record[3]
                coupon.save()

        self.multi_contract_ent_offers = [
            ['56b250c3-0050-47da-819c-e677fb8c03be', 4000, 'Site', '', 'OID500'],
            ['56b250c3-0050-47da-819c-e677fb8c03be', 4000, 'Site', '', 'OID500'],
            ['56b250c3-0050-47da-819c-e677fb8c03be', 4000, 'Site', '', 'OID550'],
            ['56b250c3-0050-47da-819c-e677fb8c03be', 4001, 'Site', '', 'OID555'],
        ]
        created = []
        for record in self.multi_contract_ent_offers:
            if record[1] not in created:
                created.append(record[1])
                factories.EnterpriseOfferFactory(
                    id=record[1],
                    condition=factories.EnterpriseCustomerConditionFactory(
                        enterprise_customer_uuid=record[0]
                    )
                )

        self.multi_contract_manual_offers = [
            ['1204f563-ef3d-47cb-85c4-f67de61c5733', 6000, 'User', '', 'OID600'],
            ['1204f563-ef3d-47cb-85c4-f67de61c5733', 6000, 'User', '', 'OID600'],
            ['1204f563-ef3d-47cb-85c4-f67de61c5733', 6000, 'User', '', 'OID650'],
            ['1204f563-ef3d-47cb-85c4-f67de61c5733', 6001, 'User', '', 'OID666'],
        ]
        created = []
        for record in self.multi_contract_manual_offers:
            if record[1] not in created:
                created.append(record[1])
                factories.ManualEnrollmentOrderOfferFactory(
                    id=record[1],
                    condition=factories.ManualEnrollmentOrderDiscountConditionFactory(
                        enterprise_customer_uuid=record[0]
                    )
                )

        self.multi_contract_enterprises_with_opportunity_ids_only = [
            ['1e57ef1f-c96b-47dd-9a7e-0bb24022ede5', '', '', '', 'OID700'],
            ['11e0a60d-0f79-4d96-a55b-4e126cb34a51', '', '', '', 'OID800'],
            ['9b951dd8-4bbd-4b5b-9186-c4bee1c96e1a', '', '', '', 'OID900'],
        ]
        for record in self.multi_contract_enterprises_with_opportunity_ids_only:
            self.init_data(record[0])