예제 #1
0
 def test_pricelist_combination(self):
     product = self.env['product.product'].create({
         'name': 'Super Product',
         'list_price': 100,
         'taxes_id': False,
     })
     current_website = self.env['website'].get_current_website()
     website_pricelist = current_website.get_current_pricelist()
     website_pricelist.write({
         'discount_policy': 'with_discount',
         'item_ids': [(5, 0, 0), (0, 0, {
             'applied_on': '1_product',
             'product_tmpl_id': product.product_tmpl_id.id,
             'min_quantity': 500,
             'compute_price': 'percentage',
             'percent_price': 63,
         })]
     })
     promo_pricelist = self.env['product.pricelist'].create({
         'name': 'Super Pricelist',
         'discount_policy': 'without_discount',
         'item_ids': [(0, 0, {
             'applied_on': '1_product',
             'product_tmpl_id': product.product_tmpl_id.id,
             'base': 'pricelist',
             'base_pricelist_id': website_pricelist.id,
             'compute_price': 'formula',
             'price_discount': 25
         })]
     })
     so = self.env['sale.order'].create({
         'partner_id': self.env.user.partner_id.id,
         'order_line': [(0, 0, {
             'name': product.name,
             'product_id': product.id,
             'product_uom_qty': 1,
             'product_uom': product.uom_id.id,
             'price_unit': product.list_price,
             'tax_id': False,
         })]
     })
     sol = so.order_line
     self.assertEqual(sol.price_total, 100.0)
     so.pricelist_id = promo_pricelist
     with MockRequest(self.env, website=current_website, sale_order_id=so.id):
         so._cart_update(product_id=product.id, line_id=sol.id, set_qty=500)
     self.assertEqual(sol.price_unit, 37.0, 'Both reductions should be applied')
     self.assertEqual(sol.price_reduce, 27.75, 'Both reductions should be applied')
     self.assertEqual(sol.price_total, 13875)
예제 #2
0
    def test_01_create_shipping_address_specific_user_account(self):
        ''' Ensure `website_id` is correctly set (specific_user_account) '''
        p = self.env.user.partner_id
        so = self._create_so(p.id)

        with MockRequest(self.env, website=self.website, sale_order_id=so.id):
            self.WebsiteSaleController.address(**self.default_address_values)
            self.assertFalse(
                self._get_last_address(p).website_id,
                "New shipping address should not have a website set on it (no specific_user_account)."
            )

            self.website.specific_user_account = True

            self.WebsiteSaleController.address(**self.default_address_values)
            self.assertEqual(
                self._get_last_address(p).website_id, self.website,
                "New shipping address should have a website set on it (specific_user_account)."
            )
예제 #3
0
    def test_04_apply_empty_pl(self):
        ''' Ensure empty pl code reset the applied pl '''
        so = self._create_so(self.env.user.partner_id.id)
        eur_pl = self.env['product.pricelist'].create({
            'name':
            'EUR_test',
            'website_id':
            self.website.id,
            'code':
            'EUR_test',
        })

        with MockRequest(self.env, website=self.website, sale_order_id=so.id):
            self.WebsiteSaleController.pricelist('EUR_test')
            self.assertEqual(so.pricelist_id, eur_pl,
                             "Ensure EUR_test is applied")

            self.WebsiteSaleController.pricelist('')
            self.assertNotEqual(
                so.pricelist_id, eur_pl,
                "Pricelist should be removed when sending an empty pl code")
예제 #4
0
    def test_process_attendees_form(self):
        event = self.env['event.event'].create({
            'name': 'Event Update Type',
            'event_type_id': self.event_type_complex.with_user(self.env.user).id,
            'date_begin': FieldsDatetime.to_string(datetime.today() + timedelta(days=1)),
            'date_end': FieldsDatetime.to_string(datetime.today() + timedelta(days=15)),
        })

        form_details = {
            '1-name': 'Pixis',
            '1-email': '*****@*****.**',
            '1-phone': '+32444444444',
            '1-event_ticket_id': '2',
            '2-name': 'Geluchat',
            '2-email': '*****@*****.**',
            '2-phone': '+32777777777',
            '2-event_ticket_id': '3',
            'question_answer-1-%s' % self.event_question_1.id: '5',
            'question_answer-2-%s' % self.event_question_1.id: '9',
            'question_answer-0-%s' % self.event_question_2.id: '7',
            'question_answer-0-%s' % self.event_question_3.id: 'Free Text',
        }

        with MockRequest(self.env):
            registrations = WebsiteEvent()._process_attendees_form(event, form_details)

        self.assertEqual(registrations, [
            {'name': 'Pixis', 'email': '*****@*****.**', 'phone': '+32444444444', 'event_ticket_id': 2,
            'registration_answer_ids': [
                (0, 0, {'question_id': self.event_question_1.id, 'value_answer_id': 5}),
                (0, 0, {'question_id': self.event_question_2.id, 'value_answer_id': 7}),
                (0, 0, {'question_id': self.event_question_3.id, 'value_text_box': 'Free Text'})]},
            {'name': 'Geluchat', 'email': '*****@*****.**', 'phone': '+32777777777', 'event_ticket_id': 3,
            'registration_answer_ids': [
                (0, 0, {'question_id': self.event_question_1.id, 'value_answer_id': 9}),
                (0, 0, {'question_id': self.event_question_2.id, 'value_answer_id': 7}),
                (0, 0, {'question_id': self.event_question_3.id, 'value_text_box': 'Free Text'})]}
        ])
예제 #5
0
 def test_pricelist_with_no_list_price(self):
     product = self.env['product.product'].create({
         'name': 'Super Product',
         'list_price': 0,
         'taxes_id': False,
     })
     current_website = self.env['website'].get_current_website()
     website_pricelist = current_website.get_current_pricelist()
     website_pricelist.write({
         'discount_policy': 'without_discount',
         'item_ids': [(5, 0, 0), (0, 0, {
             'applied_on': '1_product',
             'product_tmpl_id': product.product_tmpl_id.id,
             'min_quantity': 0,
             'compute_price': 'fixed',
             'fixed_price': 10,
         })]
     })
     so = self.env['sale.order'].create({
         'partner_id': self.env.user.partner_id.id,
         'order_line': [(0, 0, {
             'name': product.name,
             'product_id': product.id,
             'product_uom_qty': 5,
             'product_uom': product.uom_id.id,
             'price_unit': product.list_price,
             'tax_id': False,
         })]
     })
     sol = so.order_line
     self.assertEqual(sol.price_total, 0)
     so.pricelist_id = website_pricelist
     with MockRequest(self.env, website=current_website, sale_order_id=so.id):
         so._cart_update(product_id=product.id, line_id=sol.id, set_qty=5)
     self.assertEqual(sol.price_unit, 10.0, 'Pricelist price should be applied')
     self.assertEqual(sol.price_reduce, 10.0, 'Pricelist price should be applied')
     self.assertEqual(sol.price_total, 50.0)
    def test_cart_update_with_fpos(self):
        # We will test that the mapping of an 10% included tax by a 0% by a fiscal position is taken into account when updating the cart
        self.env.user.partner_id.country_id = False
        current_website = self.env['website'].get_current_website()
        pricelist = current_website.get_current_pricelist()
        (self.env['product.pricelist'].search([]) - pricelist).write(
            {'active': False})
        # Add 10% tax on product
        tax10 = self.env['account.tax'].create({
            'name': "Test tax 10",
            'amount': 10,
            'price_include': True,
            'amount_type': 'percent'
        })
        tax0 = self.env['account.tax'].create({
            'name': "Test tax 0",
            'amount': 0,
            'price_include': True,
            'amount_type': 'percent'
        })

        test_product = self.env['product.template'].create({
            'name':
            'Test Product',
            'price':
            110,
            'taxes_id': [(6, 0, [tax10.id])],
        }).with_context(website_id=current_website.id)

        # Add discout of 50% for pricelist
        pricelist.item_ids = self.env['product.pricelist.item'].create({
            'applied_on':
            "1_product",
            'base':
            "list_price",
            'compute_price':
            "percentage",
            'percent_price':
            50,
            'product_tmpl_id':
            test_product.id,
        })

        pricelist.discount_policy = 'without_discount'

        # Create fiscal position mapping taxes 10% -> 0%
        fpos = self.env['account.fiscal.position'].create({
            'name': 'test',
        })
        self.env['account.fiscal.position.tax'].create({
            'position_id': fpos.id,
            'tax_src_id': tax10.id,
            'tax_dest_id': tax0.id,
        })
        so = self.env['sale.order'].create({
            'partner_id':
            self.env.user.partner_id.id,
        })
        sol = self.env['sale.order.line'].create({
            'name':
            test_product.name,
            'product_id':
            test_product.product_variant_id.id,
            'product_uom_qty':
            1,
            'product_uom':
            test_product.uom_id.id,
            'price_unit':
            test_product.list_price,
            'order_id':
            so.id,
            'tax_id': [(6, 0, [tax10.id])],
        })
        self.assertEqual(round(sol.price_total), 110.0,
                         "110$ with 10% included tax")
        so.pricelist_id = pricelist
        so.fiscal_position_id = fpos
        sol.product_id_change()
        with MockRequest(self.env,
                         website=current_website,
                         sale_order_id=so.id):
            so._cart_update(product_id=test_product.product_variant_id.id,
                            line_id=sol.id,
                            set_qty=1)
        self.assertEqual(
            round(sol.price_total), 50,
            "100$ with 50% discount + 0% tax (mapped from fp 10% -> 0%)")
예제 #7
0
 def test_process_att_no_request_lang(self):
     with MockRequest(self.env, website=self.website):
         self._test_att('/', {'href': '/'})
         self._test_att('/en/', {'href': '/'})
         self._test_att('/fr/', {'href': '/fr/'})
예제 #8
0
    def test_visitor_creation_on_tracked_page(self):
        """ Test various flows involving visitor creation and update. """
        existing_visitors = self.env['website.visitor'].search([])
        existing_tracks = self.env['website.track'].search([])
        self.url_open(self.untracked_page.url)
        self.url_open(self.tracked_page.url)
        self.url_open(self.tracked_page.url)

        new_visitor = self.env['website.visitor'].search([
            ('id', 'not in', existing_visitors.ids)
        ])
        new_track = self.env['website.track'].search([('id', 'not in',
                                                       existing_tracks.ids)])
        self.assertEqual(len(new_visitor), 1, "1 visitor should be created")
        self.assertEqual(len(new_track), 1, "There should be 1 tracked page")
        self.assertEqual(new_visitor.visit_count, 1)
        self.assertEqual(new_visitor.website_track_ids, new_track)
        self.assertVisitorTracking(new_visitor, self.tracked_page)

        # ------------------------------------------------------------
        # Admin connects
        # ------------------------------------------------------------

        self.cookies = {'visitor_uuid': new_visitor.access_token}
        with MockRequest(self.env, website=self.website, cookies=self.cookies):
            self.authenticate(self.user_admin.login, 'admin')

        visitor_admin = new_visitor
        # visit a page
        self.url_open(self.tracked_page_2.url)

        # check tracking and visitor / user sync
        self.assertVisitorTracking(visitor_admin,
                                   self.tracked_page | self.tracked_page_2)
        self.assertEqual(visitor_admin.partner_id, self.partner_admin)
        self.assertEqual(visitor_admin.name, self.partner_admin.name)

        # ------------------------------------------------------------
        # Portal connects
        # ------------------------------------------------------------

        with MockRequest(self.env, website=self.website, cookies=self.cookies):
            self.authenticate(self.user_portal.login, 'portal')

        self.assertFalse(
            self.env['website.visitor'].search([
                ('id', 'not in', (existing_visitors | visitor_admin).ids)
            ]), "No extra visitor should be created")

        # visit a page
        self.url_open(self.tracked_page.url)
        self.url_open(self.untracked_page.url)
        self.url_open(self.tracked_page_2.url)
        self.url_open(self.tracked_page_2.url
                      )  # 2 time to be sure it does not record twice

        # new visitor is created
        new_visitors = self.env['website.visitor'].search([
            ('id', 'not in', existing_visitors.ids)
        ])
        self.assertEqual(len(new_visitors), 2,
                         "One extra visitor should be created")
        visitor_portal = new_visitors[0]
        self.assertEqual(visitor_portal.partner_id, self.partner_portal)
        self.assertEqual(visitor_portal.name, self.partner_portal.name)
        self.assertVisitorTracking(visitor_portal,
                                   self.tracked_page | self.tracked_page_2)

        # ------------------------------------------------------------
        # Back to anonymous
        # ------------------------------------------------------------

        # portal user disconnects
        self.logout()

        # visit some pages
        self.url_open(self.tracked_page.url)
        self.url_open(self.untracked_page.url)
        self.url_open(self.tracked_page_2.url)
        self.url_open(self.tracked_page_2.url
                      )  # 2 time to be sure it does not record twice

        # new visitor is created
        new_visitors = self.env['website.visitor'].search([
            ('id', 'not in', existing_visitors.ids)
        ])
        self.assertEqual(len(new_visitors), 3,
                         "One extra visitor should be created")
        visitor_anonymous = new_visitors[0]
        self.cookies['visitor_uuid'] = visitor_anonymous.access_token
        self.assertFalse(visitor_anonymous.name)
        self.assertFalse(visitor_anonymous.partner_id)
        self.assertVisitorTracking(visitor_anonymous,
                                   self.tracked_page | self.tracked_page_2)
        visitor_anonymous_tracks = visitor_anonymous.website_track_ids

        # ------------------------------------------------------------
        # Admin connects again
        # ------------------------------------------------------------

        with MockRequest(self.env, website=self.website, cookies=self.cookies):
            self.authenticate(self.user_admin.login, 'admin')

        # one visitor is deleted
        visitor_anonymous = self.env['website.visitor'].with_context(
            active_test=False).search([('id', '=', visitor_anonymous.id)])
        self.assertVisitorDeactivated(visitor_anonymous, visitor_admin)
        new_visitors = self.env['website.visitor'].search([
            ('id', 'not in', existing_visitors.ids)
        ])
        self.assertEqual(new_visitors, visitor_admin | visitor_portal)
        visitor_admin = self.env['website.visitor'].search([
            ('partner_id', '=', self.partner_admin.id)
        ])
        # tracks are linked
        self.assertTrue(
            visitor_anonymous_tracks < visitor_admin.website_track_ids)
        self.assertEqual(len(visitor_admin.website_track_ids), 4,
                         "There should be 4 tracked page for the admin")

        # ------------------------------------------------------------
        # Back to anonymous
        # ------------------------------------------------------------

        # admin disconnects
        self.logout()

        # visit some pages
        self.url_open(self.tracked_page.url)
        self.url_open(self.untracked_page.url)
        self.url_open(self.tracked_page_2.url)
        self.url_open(self.tracked_page_2.url
                      )  # 2 time to be sure it does not record twice

        # new visitor created
        new_visitors = self.env['website.visitor'].search([
            ('id', 'not in', existing_visitors.ids)
        ])
        self.assertEqual(len(new_visitors), 3,
                         "One extra visitor should be created")
        visitor_anonymous_2 = new_visitors[0]
        self.cookies['visitor_uuid'] = visitor_anonymous_2.access_token
        self.assertFalse(visitor_anonymous_2.name)
        self.assertFalse(visitor_anonymous_2.partner_id)
        self.assertVisitorTracking(visitor_anonymous_2,
                                   self.tracked_page | self.tracked_page_2)
        visitor_anonymous_2_tracks = visitor_anonymous_2.website_track_ids

        # ------------------------------------------------------------
        # Portal connects again
        # ------------------------------------------------------------
        with MockRequest(self.env, website=self.website, cookies=self.cookies):
            self.authenticate(self.user_portal.login, 'portal')

        # one visitor is deleted
        new_visitors = self.env['website.visitor'].search([
            ('id', 'not in', existing_visitors.ids)
        ])
        self.assertEqual(new_visitors, visitor_admin | visitor_portal)
        # tracks are linked
        self.assertTrue(
            visitor_anonymous_2_tracks < visitor_portal.website_track_ids)
        self.assertEqual(len(visitor_portal.website_track_ids), 4,
                         "There should be 4 tracked page for the portal user")

        # simulate the portal user comes back 30min later
        for track in visitor_portal.website_track_ids:
            track.write({
                'visit_datetime':
                track.visit_datetime - timedelta(minutes=30)
            })

        # visit a page
        self.url_open(self.tracked_page.url)
        visitor_portal.invalidate_cache(fnames=['website_track_ids'])
        # tracks are created
        self.assertEqual(len(visitor_portal.website_track_ids), 5,
                         "There should be 5 tracked page for the portal user")

        # simulate the portal user comes back 8hours later
        visitor_portal.write({
            'last_connection_datetime':
            visitor_portal.last_connection_datetime - timedelta(hours=8)
        })
        self.url_open(self.tracked_page.url)
        visitor_portal.invalidate_cache(fnames=['visit_count'])
        # check number of visits
        self.assertEqual(visitor_portal.visit_count, 2,
                         "There should be 2 visits for the portal user")
예제 #9
0
 def test_01_url_lang(self):
     with MockRequest(self.env, website=self.website):
         self.assertEqual(
             url_lang('', '[lang]'), '/[lang]/hello/',
             "`[lang]` is used to be replaced in the url_return after installing a language, it should not be replaced or removed."
         )
def test_02_copy_ids_views_unlink_on_module_update(env):
    """ Ensure copy_ids views are correctly removed during module update.
    - Having an ir.ui.view A in the codebase, eg `website.layout`
    - Having a theme.ir.ui.view B in a theme, inheriting ir.ui.view A
    - Removing the theme.ir.ui.view B from the XML file and then updating the
      theme for a particular website should:
      1. Remove the theme.ir.ui.view record, which is the record pointed by the
         ir.model.data
         -> This is done through the regular Flectra behavior related to the
            ir.model.data and XML file check on upgrade.
      2. Remove the theme.ir.ui.view's copy_ids (sort of the COW views)
         -> Not working for now
      3. (not impact other website using this theme, see below)
         -> This is done through flectra/flectra@96ef4885a79 but did not come with
            tests

      Point 2. was not working, this test aims to ensure it will now.
      Note: This can't be done through a `ondelete=cascade` as this would
            impact other websites when modifying a specific website. This would
            be against the multi-website rule:
            "What is done on a website should not alter other websites."

            Regarding the flow described above, if a theme module was updated
            through the command line (or via the UI, but this is not possible in
            standard as theme modules are hidden from the Apps), it should
            update every website using this theme.
    """
    View = env['ir.ui.view']
    ThemeView = env['theme.ir.ui.view']
    Imd = env['ir.model.data']

    website_1 = env['website'].browse(1)
    website_2 = env['website'].browse(2)
    theme_default = env.ref('base.module_theme_default')

    # Install theme_default on website 1 and website 2
    (website_1 + website_2).theme_id = theme_default
    env['ir.module.module'].with_context(
        load_all_views=True)._theme_load(website_1)
    env['ir.module.module'].with_context(
        load_all_views=True)._theme_load(website_2)

    key = 'theme_default.theme_child_view'
    domain = [
        ('type', '=', 'qweb'),
        ('key', '=', key),
    ]

    def _simulate_xml_view():
        # Simulate a theme.ir.ui.view inside theme_default XML files
        base_view = env.ref('test_website.update_module_base_view')
        theme_child_view = ThemeView.create({
            'name': 'Theme Child View',
            'mode': 'extension',
            'inherit_id': f'{base_view._name},{base_view.id}',
            'arch': '''
                <div position="inside">
                    <p>, and I am inherited by a theme.ir.ui.view</p>
                </div>
            ''',
            'key': key,
        })
        # Create IMD so when updating the module the views will be removed (not found in file)
        Imd.create({
            'module': 'theme_default',
            'name': 'theme_child_view',
            'model': 'theme.ir.ui.view',
            'res_id': theme_child_view.id,
        })
        # Simulate the theme.ir.ui.view being installed on website 1 and 2
        View.create([
            theme_child_view._convert_to_base_model(website_1),
            theme_child_view._convert_to_base_model(website_2),
        ])

        # Ensure views are correctly setup: the theme.ir.ui.view should have been
        # copied to an ir.ui.view for website 1
        view_website_1, view_website_2 = View.search(domain + [
            ('theme_template_id', '=', theme_child_view.id),
            ('website_id', 'in', (website_1 + website_2).ids),
        ])
        assert (set((view_website_1 + view_website_2)).issubset(
            theme_child_view.copy_ids)
                and view_website_1.website_id == website_1
                and view_website_2.website_id == website_2
                ), "Theme View should have been copied to the website."

        return view_website_1, view_website_2, theme_child_view

    ##########################################
    # CASE 1: generic update (-u, migration) #
    ##########################################

    view_website_1, view_website_2, theme_child_view = _simulate_xml_view()

    # Upgrade the module
    theme_default.button_immediate_upgrade()
    env.reset()  # clear the set of environments
    env = env()  # get an environment that refers to the new registry

    # Ensure the theme.ir.ui.view got removed (since there is an IMD but not
    # present in XML files)
    view = env.ref('theme_default.theme_child_view', False)
    assert not view, "Theme view should have been removed during module update."
    assert not theme_child_view.exists(),\
        "Theme view should have been removed during module update. (2)"

    # Ensure copy_ids view got removed (and is not a leftover orphan)
    assert not View.search(domain), "copy_ids views did not get removed!"
    assert not (view_website_1.exists() or view_website_2.exists()),\
        "copy_ids views did not get removed! (2)"

    #####################################################
    # CASE 2: specific update (website theme selection) #
    #####################################################

    view_website_1, view_website_2, theme_child_view = _simulate_xml_view()

    # Upgrade the module
    with MockRequest(env, website=website_1):
        theme_default.button_immediate_upgrade()
    env.reset()  # clear the set of environments
    env = env()  # get an environment that refers to the new registry

    # Ensure the theme.ir.ui.view got removed (since there is an IMD but not
    # present in XML files)
    view = env.ref('theme_default.theme_child_view', False)
    assert not view, "Theme view should have been removed during module update."
    assert not theme_child_view.exists(),\
        "Theme view should have been removed during module update. (2)"

    # Ensure only website_1 copy_ids got removed, website_2 should be untouched
    assert not view_website_1.exists() and view_website_2.exists(),\
        "Only website_1 copy should be removed (2)"
    def test_01_multiwebsite_checks(self):
        """ Ensure the multi website compliance of programs and coupons, both in
            backend and frontend.
        """
        order = self.empty_order
        self.env['sale.order.line'].create({
            'product_id': self.largeCabinet.id,
            'name': 'Large Cabinet',
            'product_uom_qty': 2.0,
            'order_id': order.id,
        })

        def _remove_reward():
            order.order_line.filtered('is_reward_line').unlink()
            self.assertEqual(len(order.order_line.ids), 1,
                             "Program should have been removed")

        def _apply_code(code, backend=True):
            if backend:
                self.env['sale.coupon.apply.code'].with_context(
                    active_id=order.id).create({
                        'coupon_code': code
                    }).process_coupon()
            else:
                self.env['sale.coupon.apply.code'].sudo().apply_coupon(
                    order, code)

        # ==========================================
        # ========== Programs (with code) ==========
        # ==========================================

        # 1. Backend - Generic
        _apply_code(self.p1.promo_code)
        self.assertEqual(
            len(order.order_line.ids), 2,
            "Should get the discount line as it is a generic promo program")
        _remove_reward()

        # 2. Frontend - Generic
        with MockRequest(self.env, website=self.website):
            _apply_code(self.p1.promo_code, False)
            self.assertEqual(
                len(order.order_line.ids), 2,
                "Should get the discount line as it is a generic promo program (2)"
            )
            _remove_reward()

        # make program specific
        self.p1.website_id = self.website.id
        # 3. Backend - Specific
        with self.assertRaises(UserError):
            _apply_code(
                self.p1.promo_code
            )  # the order has no website_id so not possible to use a website specific code

        # 4. Frontend - Specific - Correct website
        order.website_id = self.website.id
        with MockRequest(self.env, website=self.website):
            _apply_code(self.p1.promo_code, False)
            self.assertEqual(
                len(order.order_line.ids), 2,
                "Should get the discount line as it is a specific promo program for the correct website"
            )
            _remove_reward()

        # 5. Frontend - Specific - Wrong website
        self.p1.website_id = self.website2.id
        with MockRequest(self.env, website=self.website):
            _apply_code(self.p1.promo_code, False)
            self.assertEqual(len(order.order_line.ids), 1,
                             "Should not get the reward as wrong website")

        # ==============================
        # =========== Coupons ==========
        # ==============================

        order.website_id = False
        self.env['coupon.generate.wizard'].with_context(
            active_id=self.discount_coupon_program.id).create({
                'nbr_coupons': 4,
            }).generate_coupon()
        coupons = self.discount_coupon_program.coupon_ids

        # 1. Backend - Generic
        _apply_code(coupons[0].code)
        self.assertEqual(
            len(order.order_line.ids), 2,
            "Should get the discount line as it is a generic coupon program")
        _remove_reward()

        # 2. Frontend - Generic
        with MockRequest(self.env, website=self.website):
            _apply_code(coupons[1].code, False)
            self.assertEqual(
                len(order.order_line.ids), 2,
                "Should get the discount line as it is a generic coupon program (2)"
            )
            _remove_reward()

        # make program specific
        self.discount_coupon_program.website_id = self.website.id
        # 3. Backend - Specific
        with self.assertRaises(UserError):
            _apply_code(
                coupons[2].code
            )  # the order has no website_id so not possible to use a website specific code

        # 4. Frontend - Specific - Correct website
        order.website_id = self.website.id
        with MockRequest(self.env, website=self.website):
            _apply_code(coupons[2].code, False)
            self.assertEqual(
                len(order.order_line.ids), 2,
                "Should get the discount line as it is a specific coupon program for the correct website"
            )
            _remove_reward()

        # 5. Frontend - Specific - Wrong website
        self.discount_coupon_program.website_id = self.website2.id
        with MockRequest(self.env, website=self.website):
            _apply_code(coupons[3].code, False)
            self.assertEqual(len(order.order_line.ids), 1,
                             "Should not get the reward as wrong website")

        # ========================================
        # ========== Programs (no code) ==========
        # ========================================

        order.website_id = False
        self.p1.website_id = False
        self.p1.promo_code = False
        self.p1.promo_code_usage = 'no_code_needed'

        # 1. Backend - Generic
        order.recompute_coupon_lines()
        self.assertEqual(
            len(order.order_line.ids), 2,
            "Should get the discount line as it is a generic promo program")

        # 2. Frontend - Generic
        with MockRequest(self.env, website=self.website):
            order.recompute_coupon_lines()
            self.assertEqual(
                len(order.order_line.ids), 2,
                "Should get the discount line as it is a generic promo program (2)"
            )

        # make program specific
        self.p1.website_id = self.website.id
        # 3. Backend - Specific
        order.recompute_coupon_lines()
        self.assertEqual(
            len(order.order_line.ids), 1,
            "The order has no website_id so not possible to use a website specific code"
        )

        # 4. Frontend - Specific - Correct website
        order.website_id = self.website.id
        with MockRequest(self.env, website=self.website):
            order.recompute_coupon_lines()
            self.assertEqual(
                len(order.order_line.ids), 2,
                "Should get the discount line as it is a specific promo program for the correct website"
            )

        # 5. Frontend - Specific - Wrong website
        self.p1.website_id = self.website2.id
        with MockRequest(self.env, website=self.website):
            order.recompute_coupon_lines()
            self.assertEqual(len(order.order_line.ids), 1,
                             "Should not get the reward as wrong website")