Пример #1
0
    def test_journal_sequence(self):
        self.assertEqual(self.test_move.name, 'MISC/2016/01/0001')
        self.test_move.action_post()
        self.assertEqual(self.test_move.name, 'MISC/2016/01/0001')

        copy1 = self.create_move(date=self.test_move.date)
        self.assertEqual(copy1.name, '/')
        copy1.action_post()
        self.assertEqual(copy1.name, 'MISC/2016/01/0002')

        copy2 = self.create_move(date=self.test_move.date)
        new_journal = self.test_move.journal_id.copy()
        new_journal.code = "MISC2"
        copy2.journal_id = new_journal
        self.assertEqual(copy2.name, 'MISC2/2016/01/0001')
        with Form(copy2) as move_form:  # It is editable in the form
            with mute_logger('flectra.tests.common.onchange'):
                move_form.name = 'MyMISC/2016/0001'
                self.assertIn(
                    'The sequence will restart at 1 at the start of every year',
                    move_form._perform_onchange(['name'
                                                 ])['warning']['message'],
                )
            move_form.journal_id = self.test_move.journal_id
            self.assertEqual(move_form.name, '/')
            move_form.journal_id = new_journal
            self.assertEqual(move_form.name, 'MISC2/2016/01/0001')
            with mute_logger('flectra.tests.common.onchange'):
                move_form.name = 'MyMISC/2016/0001'
                self.assertIn(
                    'The sequence will restart at 1 at the start of every year',
                    move_form._perform_onchange(['name'
                                                 ])['warning']['message'],
                )
        copy2.action_post()
        self.assertEqual(copy2.name, 'MyMISC/2016/0001')

        copy3 = self.create_move(date=copy2.date, journal=new_journal)
        self.assertEqual(copy3.name, '/')
        with self.assertRaises(AssertionError):
            with Form(copy2) as move_form:  # It is not editable in the form
                move_form.name = 'MyMISC/2016/0002'
        copy3.action_post()
        self.assertEqual(copy3.name, 'MyMISC/2016/0002')
        copy3.name = 'MISC2/2016/00002'

        copy4 = self.create_move(date=copy2.date, journal=new_journal)
        copy4.action_post()
        self.assertEqual(copy4.name, 'MISC2/2016/00003')

        copy5 = self.create_move(date=copy2.date, journal=new_journal)
        copy5.date = '2021-02-02'
        copy5.action_post()
        self.assertEqual(copy5.name, 'MISC2/2021/00001')
        copy5.name = 'N\'importe quoi?'

        copy6 = self.create_move(date=copy5.date, journal=new_journal)
        copy6.action_post()
        self.assertEqual(copy6.name, 'N\'importe quoi?1')
Пример #2
0
    def unlink(self):
        """Override to:
        - Clean up the variants that use any of the values in self:
            - Remove the value from the variant if the value belonged to an
                attribute line with only one value.
            - Unlink or archive all related variants.
        - Archive the value if unlink is not possible.

        Archiving is typically needed when the value is referenced elsewhere
        (on a variant that can't be deleted, on a sales order line, ...).
        """
        # Directly remove the values from the variants for lines that had single
        # value (counting also the values that are archived).
        single_values = self.filtered(lambda ptav: len(
            ptav.attribute_line_id.product_template_value_ids) == 1)
        for ptav in single_values:
            ptav.ptav_product_variant_ids.write(
                {'product_template_attribute_value_ids': [(3, ptav.id, 0)]})
        # Try to remove the variants before deleting to potentially remove some
        # blocking references.
        self.ptav_product_variant_ids._unlink_or_archive()
        # Now delete or archive the values.
        ptav_to_archive = self.env['product.template.attribute.value']
        for ptav in self:
            try:
                with self.env.cr.savepoint(), tools.mute_logger(
                        'flectra.sql_db'):
                    super(ProductTemplateAttributeValue, ptav).unlink()
            except Exception:
                # We catch all kind of exceptions to be sure that the operation
                # doesn't fail.
                ptav_to_archive += ptav
        ptav_to_archive.write({'ptav_active': False})
        return True
Пример #3
0
 def test_105_duplicated_translation(self):
     """ Test synchronizing translations with duplicated source """
     # create a category with a French translation
     padawans = self.env['res.partner.category'].create({'name': 'Padawan'})
     self.env['ir.translation'].create({
         'type': 'model',
         'name': 'res.partner.category,name',
         'module':'base',
         'lang': 'fr_FR',
         'res_id': padawans.id,
         'value': 'Apprenti',
         'state': 'translated',
     })
     # change name and insert a duplicate manually
     padawans.write({'name': 'Padawans'})
     with self.assertRaises(IntegrityError), mute_logger('flectra.sql_db'):
         with self.env.cr.savepoint():
             self.env['ir.translation'].create({
                 'type': 'model',
                 'name': 'res.partner.category,name',
                 'module':'base',
                 'lang': 'fr_FR',
                 'res_id': padawans.id,
                 'value': 'Apprentis',
                 'state': 'translated',
             })
     self.env['ir.translation'].translate_fields('res.partner.category', padawans.id, 'name')
     translations = self.env['ir.translation'].search([
         ('res_id', '=', padawans.id), ('name', '=', 'res.partner.category,name'), ('lang', '=', 'fr_FR'),
     ])
     self.assertEqual(len(translations), 1, "Translations were not duplicated after `translate_fields` call")
     self.assertEqual(translations.value, "Apprenti", "The first translation must stay")
Пример #4
0
 def test_events_access_8(self):
     """Access to an unpublished event with portal user."""
     with mute_logger('flectra.addons.http_routing.models.ir_http'):
         self.authenticate('user_portal', 'user_portal')
         unpublished_events = self.events.filtered(lambda event: not event.website_published)
         resp = self.url_open('/event/%i' % unpublished_events[0].id)
         self.assertEqual(resp.status_code, 403, 'Portal user must not have access to unpublished event.')
Пример #5
0
    def test_80_permission(self):
        self.action.write({
            'state':
            'code',
            'code':
            """record.write({'date': datetime.date.today()})""",
        })

        user_demo = self.env.ref("base.user_demo")
        self_demo = self.action.with_user(user_demo.id)

        # can write on contact partner
        self.test_partner.type = "contact"
        self.test_partner.with_user(user_demo.id).check_access_rule("write")

        self_demo.with_context(self.context).run()
        self.assertEqual(self.test_partner.date, date.today())

        # but can not write on private address
        self.test_partner.type = "private"
        with self.assertRaises(AccessError):
            self.test_partner.with_user(
                user_demo.id).check_access_rule("write")
        # nor execute a server action on it
        with self.assertRaises(AccessError), mute_logger(
                'flectra.addons.base.models.ir_actions'):
            self_demo.with_context(self.context).run()
Пример #6
0
 def test_change_login(self):
     new_test_user(self.env, login='******', website_id=self.website_1.id)
     user_belle = new_test_user(self.env,
                                login='******',
                                website_id=self.website_1.id)
     with self.assertRaises(IntegrityError), mute_logger('flectra.sql_db'):
         user_belle.login = '******'
Пример #7
0
 def update(self, inactivity_period):
     """ Updates the last_poll and last_presence of the current user
         :param inactivity_period: duration in milliseconds
     """
     presence = self.search([('user_id', '=', self._uid)], limit=1)
     # compute last_presence timestamp
     last_presence = datetime.datetime.now() - datetime.timedelta(
         milliseconds=inactivity_period)
     values = {
         'last_poll': time.strftime(DEFAULT_SERVER_DATETIME_FORMAT),
     }
     # update the presence or a create a new one
     if not presence:  # create a new presence for the user
         values['user_id'] = self._uid
         values['last_presence'] = last_presence.strftime(
             DEFAULT_SERVER_DATETIME_FORMAT)
         self.create(values)
     else:  # update the last_presence if necessary, and write values
         if datetime.datetime.strptime(
                 presence.last_presence,
                 DEFAULT_SERVER_DATETIME_FORMAT) < last_presence:
             values['last_presence'] = last_presence.strftime(
                 DEFAULT_SERVER_DATETIME_FORMAT)
         # Hide transaction serialization errors, which can be ignored, the presence update is not essential
         with tools.mute_logger('flectra.sql_db'):
             presence.write(values)
     # avoid TransactionRollbackError
     self.env.cr.commit()  # TODO : check if still necessary
Пример #8
0
    def unlink(self):
        """Override to:
        - Archive the line if unlink is not possible.
        - Clean up related values and related variants.

        Archiving is typically needed when the line has values that can't be
        deleted because they are referenced elsewhere (on a variant that can't
        be deleted, on a sales order line, ...).
        """
        # Try to remove the values first to remove some potentially blocking
        # references, which typically works:
        # - For single value lines because the values are directly removed from
        #   the variants.
        # - For values that are present on variants that can be deleted.
        self.product_template_value_ids._only_active().unlink()
        # Keep a reference to the related templates before the deletion.
        templates = self.product_tmpl_id
        # Now delete or archive the lines.
        ptal_to_archive = self.env['product.template.attribute.line']
        for ptal in self:
            try:
                with self.env.cr.savepoint(), tools.mute_logger(
                        'flectra.sql_db'):
                    super(ProductTemplateAttributeLine, ptal).unlink()
            except Exception:
                # We catch all kind of exceptions to be sure that the operation
                # doesn't fail.
                ptal_to_archive += ptal
        ptal_to_archive.write({'active': False})
        # For archived lines `_update_product_template_attribute_values` is
        # implicitly called during the `write` above, but for products that used
        # unlinked lines `_create_variant_ids` has to be called manually.
        (templates - ptal_to_archive.product_tmpl_id)._create_variant_ids()
        return True
    def _procure_calculation_orderpoint(self):
        with api.Environment.manage():
            # As this function is in a new thread, I need to open a new cursor, because the old one may be closed
            new_cr = self.pool.cursor()
            self = self.with_env(self.env(cr=new_cr))
            scheduler_cron = self.sudo().env.ref(
                'stock.ir_cron_scheduler_action')
            # Avoid to run the scheduler multiple times in the same time
            try:
                with tools.mute_logger('flectra.sql_db'):
                    self._cr.execute(
                        "SELECT id FROM ir_cron WHERE id = %s FOR UPDATE NOWAIT",
                        (scheduler_cron.id, ))
            except Exception:
                _logger.info(
                    'Attempt to run procurement scheduler aborted, as already running'
                )
                self._cr.rollback()
                self._cr.close()
                return {}

            for company in self.env.user.company_ids:
                self.env['procurement.group'].run_scheduler(
                    use_new_cursor=self._cr.dbname, company_id=company.id)
            new_cr.close()
            return {}
Пример #10
0
    def test_sequence_concurency(self):
        """Computing the same name in concurent transactions is not allowed."""
        with self.env.registry.cursor() as cr0,\
                self.env.registry.cursor() as cr1,\
                self.env.registry.cursor() as cr2:
            env0 = api.Environment(cr0, SUPERUSER_ID, {})
            env1 = api.Environment(cr1, SUPERUSER_ID, {})
            env2 = api.Environment(cr2, SUPERUSER_ID, {})

            journal = env0['account.journal'].create({
                'name': 'concurency_test',
                'code': 'CT',
                'type': 'general',
            })
            account = env0['account.account'].create({
                'code':
                'CT',
                'name':
                'CT',
                'user_type_id':
                env0.ref('account.data_account_type_fixed_assets').id,
            })
            moves = env0['account.move'].create([{
                'journal_id':
                journal.id,
                'date':
                fields.Date.from_string('2016-01-01'),
                'line_ids': [(0, 0, {
                    'name': 'name',
                    'account_id': account.id
                })]
            }] * 3)
            moves.name = '/'
            moves[0].action_post()
            self.assertEqual(moves.mapped('name'),
                             ['CT/2016/01/0001', '/', '/'])
            env0.cr.commit()

            # start the transactions here on cr2 to simulate concurency with cr1
            env2.cr.execute('SELECT 1')

            move = env1['account.move'].browse(moves[1].id)
            move.action_post()
            env1.cr.commit()

            move = env2['account.move'].browse(moves[2].id)
            with self.assertRaises(
                    psycopg2.OperationalError), env2.cr.savepoint(
                    ), mute_logger('flectra.sql_db'):
                move.action_post()

            self.assertEqual(moves.mapped('name'),
                             ['CT/2016/01/0001', 'CT/2016/01/0002', '/'])
            moves.button_draft()
            moves.posted_before = False
            moves.unlink()
            journal.unlink()
            account.unlink()
            env0.cr.commit()
Пример #11
0
    def create_variant_ids(self):
        Product = self.env["product.product"]
        AttributeValues = self.env['product.attribute.value']
        for tmpl_id in self.with_context(active_test=False):
            # adding an attribute with only one value should not recreate product
            # write this attribute on every product to make sure we don't lose them
            variant_alone = tmpl_id.attribute_line_ids.filtered(lambda line: len(line.value_ids) == 1).mapped('value_ids')
            for value_id in variant_alone:
                updated_products = tmpl_id.product_variant_ids.filtered(lambda product: value_id.attribute_id not in product.mapped('attribute_value_ids.attribute_id'))
                updated_products.write({'attribute_value_ids': [(4, value_id.id)],'default_code': tmpl_id.gt_product_id,'gt_shopify_product':tmpl_id.gt_shopify_product,'gt_shopify_instance_id':tmpl_id.gt_shopify_instance_id.id})

            # iterator of n-uple of product.attribute.value *ids*
            variant_matrix = [
                AttributeValues.browse(value_ids)
                for value_ids in itertools.product(*(line.value_ids.ids for line in tmpl_id.attribute_line_ids if line.value_ids[:1].attribute_id.create_variant))
            ]

            # get the value (id) sets of existing variants
            existing_variants = {frozenset(variant.attribute_value_ids.ids) for variant in tmpl_id.product_variant_ids}
            # -> for each value set, create a recordset of values to create a
            #    variant for if the value set isn't already a variant
            to_create_variants = [
                value_ids
                for value_ids in variant_matrix
                if set(value_ids.ids) not in existing_variants
            ]

            # check product
            variants_to_activate = self.env['product.product']
            variants_to_unlink = self.env['product.product']
            for product_id in tmpl_id.product_variant_ids:
                if not product_id.active and product_id.attribute_value_ids.filtered(lambda r: r.attribute_id.create_variant) in variant_matrix:
                    variants_to_activate |= product_id
                elif product_id.attribute_value_ids.filtered(lambda r: r.attribute_id.create_variant) not in variant_matrix:
                    variants_to_unlink |= product_id
            if variants_to_activate:
                variants_to_activate.write({'active': True})

            # create new product
            for variant_ids in to_create_variants:
                new_variant = Product.create({
                    'product_tmpl_id': tmpl_id.id,
                    'attribute_value_ids': [(6, 0, variant_ids.ids)],
                    'default_code': tmpl_id.gt_product_id,
                    'gt_shopify_product':tmpl_id.gt_shopify_product,
                    'gt_shopify_instance_id':tmpl_id.gt_shopify_instance_id.id,
                })

            # unlink or inactive product
            for variant in variants_to_unlink:
                try:
                    with self._cr.savepoint(), tools.mute_logger('flectra.sql_db'):
                        variant.unlink()
                # We catch all kind of exception to be sure that the operation doesn't fail.
                except (psycopg2.Error, except_orm):
                    variant.write({'active': False})
                    pass
        return True
Пример #12
0
    def test_00_dropship(self):

        # Create a vendor
        supplier_dropship = self.env['res.partner'].create({'name': 'Vendor of Dropshipping test'})

        # Create new product without any routes
        drop_shop_product = self.env['product.product'].create({
            'name': "Pen drive",
            'type': "product",
            'categ_id': self.env.ref('product.product_category_1').id,
            'lst_price': 100.0,
            'standard_price': 0.0,
            'uom_id': self.env.ref('uom.product_uom_unit').id,
            'uom_po_id': self.env.ref('uom.product_uom_unit').id,
            'seller_ids': [(0, 0, {
                'delay': 1,
                'name': supplier_dropship.id,
                'min_qty': 2.0
            })]
        })

        # Create a sales order with a line of 200 PCE incoming shipment, with route_id drop shipping
        so_form = Form(self.env['sale.order'])
        so_form.partner_id = self.env['res.partner'].create({'name': 'My Test Partner'})
        so_form.payment_term_id = self.env.ref('account.account_payment_term_end_following_month')
        with mute_logger('flectra.tests.common.onchange'):
            # otherwise complains that there's not enough inventory and
            # apparently that's normal according to @jco and @sle
            with so_form.order_line.new() as line:
                line.product_id = drop_shop_product
                line.product_uom_qty = 200
                line.price_unit = 1.00
                line.route_id = self.env.ref('stock_dropshipping.route_drop_shipping')
        sale_order_drp_shpng = so_form.save()

        # Confirm sales order
        sale_order_drp_shpng.action_confirm()

        # Check the sales order created a procurement group which has a procurement of 200 pieces
        self.assertTrue(sale_order_drp_shpng.procurement_group_id, 'SO should have procurement group')

        # Check a quotation was created to a certain vendor and confirm so it becomes a confirmed purchase order
        purchase = self.env['purchase.order'].search([('partner_id', '=', supplier_dropship.id)])
        self.assertTrue(purchase, "an RFQ should have been created by the scheduler")
        purchase.button_confirm()
        self.assertEqual(purchase.state, 'purchase', 'Purchase order should be in the approved state')
        self.assertEqual(len(purchase.ids), 1, 'There should be one picking')

        # Send the 200 pieces
        purchase.picking_ids.move_lines.quantity_done = purchase.picking_ids.move_lines.product_qty
        purchase.picking_ids.button_validate()

        # Check one move line was created in Customers location with 200 pieces
        move_line = self.env['stock.move.line'].search([
            ('location_dest_id', '=', self.env.ref('stock.stock_location_customers').id),
            ('product_id', '=', drop_shop_product.id)])
        self.assertEqual(len(move_line.ids), 1, 'There should be exactly one move line')
Пример #13
0
 def test_sale_transaction_mismatch(self):
     """Test that a transaction for the incorrect amount does not validate the SO."""
     # modify order total
     self.order.order_line[0].price_unit = 200.0
     self.transaction._set_transaction_done()
     with mute_logger('flectra.addons.sale.models.payment'):
         self.transaction._post_process_after_done()
     self.assertEqual(
         self.order.state, 'draft',
         'a transaction for an incorrect amount should not validate a quote'
     )
Пример #14
0
 def test_remove_badge_with_give_badge(self):
     self.certification_survey.write({
         'certification_give_badge':
         True,
         'certification_badge_id':
         self.certification_badge.id
     })
     with mute_logger('flectra.sql_db'):
         with self.assertRaises(IntegrityError):
             self.certification_survey.write(
                 {'certification_badge_id': None})
             self.certification_survey.flush(['certification_badge_id'])
Пример #15
0
    def test_same_website_message(self):
        @check  # Check decorator, otherwise translation is not applied
        def check_new_test_user(dbname):
            new_test_user(self.env(context={'land': 'en_US'}),
                          login='******',
                          website_id=self.website_1.id)

        new_test_user(self.env, login='******', website_id=self.website_1.id)

        # Should be a ValidationError (with a nice translated error message),
        # not an IntegrityError
        with self.assertRaises(ValidationError), mute_logger('flectra.sql_db'):
            check_new_test_user(self.env.registry._db.dbname)
Пример #16
0
 def update_records(model, src, field_model='model', field_id='res_id'):
     Model = self.env[model] if model in self.env else None
     if Model is None:
         return
     records = Model.sudo().search([(field_model, '=', 'res.partner'),
                                    (field_id, '=', src.id)])
     try:
         with mute_logger('flectra.sql_db'), self._cr.savepoint():
             return records.sudo().write({field_id: dst_partner.id})
     except psycopg2.Error:
         # updating fails, most likely due to a violated unique constraint
         # keeping record with nonexistent partner_id is useless, better delete it
         return records.sudo().unlink()
Пример #17
0
 def test_unlink(self):
     date_range = self.env['date.range']
     drt = self.env['date.range.type'].create({
         'name': 'Fiscal year',
         'allow_overlap': False
     })
     date_range.create({
         'name': 'FS2016',
         'date_start': '2015-01-01',
         'date_end': '2016-12-31',
         'type_id': drt.id,
     })
     with self.assertRaises(IntegrityError), mute_logger('flectra.sql_db'):
         drt.unlink()
Пример #18
0
 def send_email(self, message, *args, **kwargs):
     with this.registry.cursor() as cr, mute_logger('flectra.sql_db'):
         try:
             # try ro aquire lock (no wait) on notification (should fail)
             cr.execute("SELECT notification_status FROM mail_message_res_partner_needaction_rel WHERE id = %s FOR UPDATE NOWAIT", [notif.id])
         except psycopg2.OperationalError:
             # record already locked by send, all good
             bounce_deferred.append(True)
         else:
             # this should trigger psycopg2.extensions.TransactionRollbackError in send().
             # Only here to simulate the initial use case
             # If the record is lock, this line would create a deadlock since we are in the same thread
             # In practice, the update will wait the end of the send() transaction and set the notif as bounce, as expeced
             cr.execute("UPDATE mail_message_res_partner_needaction_rel SET notification_status='bounce' WHERE id = %s", [notif.id])
     return message['Message-Id']
Пример #19
0
 def test_sale_transaction_partial_delivery(self):
     """Test that with automatic invoice and invoicing policy based on delivered quantity, a transaction for the partial
     amount does not validate the SO."""
     # set automatic invoice
     self.env['ir.config_parameter'].sudo().set_param(
         'sale.automatic_invoice', 'True')
     # modify order total
     self.order.order_line[0].price_unit = 200.0
     # invoicing policy is based on delivered quantity
     self.product_a.invoice_policy = 'delivery'
     self.transaction._set_transaction_done()
     with mute_logger('flectra.addons.sale.models.payment'):
         self.transaction.sudo()._post_process_after_done()
     self.assertEqual(
         self.order.state, 'draft',
         'a partial transaction with automatic invoice and invoice_policy = delivery should not validate a quote'
     )
Пример #20
0
 def test_set_same_badge_on_multiple_survey(self):
     self.certification_survey.write({
         'certification_give_badge':
         True,
         'certification_badge_id':
         self.certification_badge.id
     })
     # set the same badge on another survey should fail:
     with mute_logger('flectra.sql_db'):
         with self.assertRaises(IntegrityError):
             self.certification_survey_2.write({
                 'certification_give_badge':
                 True,
                 'certification_badge_id':
                 self.certification_badge.id
             })
             self.certification_survey.flush()
    def test_constraints(self):
        """The goal of this test is to make sure constraints are correct."""
        with self.assertRaises(UserError, msg="can't change variants creation mode of attribute used on product"):
            self.ram_attribute.create_variant = 'no_variant'

        with self.assertRaises(UserError, msg="can't delete attribute used on product"):
            self.ram_attribute.unlink()

        with self.assertRaises(UserError, msg="can't change the attribute of an value used on product"):
            self.ram_32.attribute_id = self.hdd_attribute.id

        with self.assertRaises(UserError, msg="can't delete value used on product"):
            self.ram_32.unlink()

        with self.assertRaises(ValidationError, msg="can't have attribute without value on product"):
            self.env['product.template.attribute.line'].create({
                'product_tmpl_id': self.computer_case.id,
                'attribute_id': self.hdd_attribute.id,
                'value_ids': [(6, 0, [])],
            })

        with self.assertRaises(ValidationError, msg="value attribute must match line attribute"):
            self.env['product.template.attribute.line'].create({
                'product_tmpl_id': self.computer_case.id,
                'attribute_id': self.ram_attribute.id,
                'value_ids': [(6, 0, [self.ssd_256.id])],
            })

        with self.assertRaises(UserError, msg="can't change the attribute of an attribute line"):
            self.computer_ssd_attribute_lines.attribute_id = self.hdd_attribute.id

        with self.assertRaises(UserError, msg="can't change the product of an attribute line"):
            self.computer_ssd_attribute_lines.product_tmpl_id = self.computer_case.id

        with self.assertRaises(UserError, msg="can't change the value of a product template attribute value"):
            self.computer_ram_attribute_lines.product_template_value_ids[0].product_attribute_value_id = self.hdd_1

        with self.assertRaises(UserError, msg="can't change the product of a product template attribute value"):
            self.computer_ram_attribute_lines.product_template_value_ids[0].product_tmpl_id = self.computer_case.id

        with mute_logger('flectra.sql_db'), self.assertRaises(IntegrityError, msg="can't have two values with the same name for the same attribute"):
            self.env['product.attribute.value'].create({
                'name': '32 GB',
                'attribute_id': self.ram_attribute.id,
            })
Пример #22
0
    def test_stock_orderpoint_wrong_uom(self):

        with mute_logger('flectra.sql_db'):
            with self.assertRaises(ValidationError):
                self.env['stock.warehouse.orderpoint'].create({
                    'warehouse_id':
                    self.warehouse.id,
                    'location_id':
                    self.location_stock.id,
                    'product_id':
                    self.productA.id,
                    'product_max_qty':
                    24,
                    'product_min_qty':
                    12,
                    'procure_uom_id':
                    self.uom_kg.id,
                })
Пример #23
0
 def test_remove_badge_with_give_badge_multi(self):
     self.certification_survey.write({
         'certification_give_badge':
         True,
         'certification_badge_id':
         self.certification_badge.id
     })
     self.certification_survey_2.write({
         'certification_give_badge':
         True,
         'certification_badge_id':
         self.certification_badge_2.id
     })
     surveys = self.env['survey.survey'].browse(
         [self.certification_survey.id, self.certification_survey_2.id])
     with mute_logger('flectra.sql_db'):
         with self.assertRaises(IntegrityError):
             surveys.write({'certification_badge_id': None})
             surveys.flush(['certification_badge_id'])
Пример #24
0
 def _update(self, inactivity_period):
     presence = self.search([('user_id', '=', self._uid)], limit=1)
     # compute last_presence timestamp
     last_presence = datetime.datetime.now() - datetime.timedelta(
         milliseconds=inactivity_period)
     values = {
         'last_poll': time.strftime(DEFAULT_SERVER_DATETIME_FORMAT),
     }
     # update the presence or a create a new one
     if not presence:  # create a new presence for the user
         values['user_id'] = self._uid
         values['last_presence'] = last_presence
         self.create(values)
     else:  # update the last_presence if necessary, and write values
         if presence.last_presence < last_presence:
             values['last_presence'] = last_presence
         # Hide transaction serialization errors, which can be ignored, the presence update is not essential
         with tools.mute_logger('flectra.sql_db'):
             presence.write(values)
             presence.flush()
Пример #25
0
    def _unlink_or_archive(self, check_access=True):
        """Unlink or archive products.
        Try in batch as much as possible because it is much faster.
        Use dichotomy when an exception occurs.
        """

        # Avoid access errors in case the products is shared amongst companies
        # but the underlying objects are not. If unlink fails because of an
        # AccessError (e.g. while recomputing fields), the 'write' call will
        # fail as well for the same reason since the field has been set to
        # recompute.
        if check_access:
            self.check_access_rights('unlink')
            self.check_access_rule('unlink')
            self.check_access_rights('write')
            self.check_access_rule('write')
            self = self.sudo()
            to_unlink = self._filter_to_unlink()
            to_archive = self - to_unlink
            to_archive.write({'active': False})
            self = to_unlink

        try:
            with self.env.cr.savepoint(), tools.mute_logger('flectra.sql_db'):
                self.unlink()
        except Exception:
            # We catch all kind of exceptions to be sure that the operation
            # doesn't fail.
            if len(self) > 1:
                self[:len(self) // 2]._unlink_or_archive(check_access=False)
                self[len(self) // 2:]._unlink_or_archive(check_access=False)
            else:
                if self.active:
                    # Note: this can still fail if something is preventing
                    # from archiving.
                    # This is the case from existing stock reordering rules.
                    self.write({'active': False})
Пример #26
0
    def test_crud_rights(self):
        Post = self.env['forum.post']
        Vote = self.env['forum.post.vote']
        self.user_portal.karma = 500
        self.user_employee.karma = 500

        # create some posts
        self.admin_post = self.post
        self.portal_post = Post.with_user(self.user_portal).create({
            'name':
            'Post from Portal User',
            'content':
            'I am not a bird.',
            'forum_id':
            self.forum.id,
        })
        self.employee_post = Post.with_user(self.user_employee).create({
            'name':
            'Post from Employee User',
            'content':
            'I am not a bird.',
            'forum_id':
            self.forum.id,
        })

        # vote on some posts
        self.employee_vote_on_admin_post = Vote.with_user(
            self.user_employee).create({
                'post_id': self.admin_post.id,
                'vote': '1',
            })
        self.portal_vote_on_admin_post = Vote.with_user(
            self.user_portal).create({
                'post_id': self.admin_post.id,
                'vote': '1',
            })
        self.admin_vote_on_portal_post = Vote.create({
            'post_id':
            self.portal_post.id,
            'vote':
            '1',
        })
        self.admin_vote_on_employee_post = Vote.create({
            'post_id':
            self.employee_post.id,
            'vote':
            '1',
        })

        # One should not be able to modify someone else's vote
        with self.assertRaises(UserError):
            self.admin_vote_on_portal_post.with_user(self.user_employee).write(
                {
                    'vote': '-1',
                })
        with self.assertRaises(UserError):
            self.admin_vote_on_employee_post.with_user(self.user_portal).write(
                {
                    'vote': '-1',
                })

        # One should not be able to give his vote to someone else
        self.employee_vote_on_admin_post.with_user(self.user_employee).write({
            'user_id':
            1,
        })
        self.assertEqual(
            self.employee_vote_on_admin_post.user_id, self.user_employee,
            'User employee should not be able to give its vote ownership to someone else'
        )
        # One should not be able to change his vote's post to a post of his own (would be self voting)
        with self.assertRaises(UserError):
            self.employee_vote_on_admin_post.with_user(
                self.user_employee).write({
                    'post_id': self.employee_post.id,
                })

        # One should not be able to give his vote to someone else
        self.portal_vote_on_admin_post.with_user(self.user_portal).write({
            'user_id':
            1,
        })
        self.assertEqual(
            self.portal_vote_on_admin_post.user_id, self.user_portal,
            'User portal should not be able to give its vote ownership to someone else'
        )
        # One should not be able to change his vote's post to a post of his own (would be self voting)
        with self.assertRaises(UserError):
            self.portal_vote_on_admin_post.with_user(self.user_portal).write({
                'post_id':
                self.portal_post.id,
            })

        # One should not be able to vote for its own post
        with self.assertRaises(UserError):
            Vote.with_user(self.user_employee).create({
                'post_id':
                self.employee_post.id,
                'vote':
                '1',
            })
        # One should not be able to vote for its own post
        with self.assertRaises(UserError):
            Vote.with_user(self.user_portal).create({
                'post_id':
                self.portal_post.id,
                'vote':
                '1',
            })

        with mute_logger('flectra.sql_db'):
            with self.assertRaises(IntegrityError):
                with self.cr.savepoint():
                    # One should not be able to vote more than once on a same post
                    Vote.with_user(self.user_employee).create({
                        'post_id':
                        self.admin_post.id,
                        'vote':
                        '1',
                    })
            with self.assertRaises(IntegrityError):
                with self.cr.savepoint():
                    # One should not be able to vote more than once on a same post
                    Vote.with_user(self.user_employee).create({
                        'post_id':
                        self.admin_post.id,
                        'vote':
                        '1',
                    })

        # One should not be able to create a vote for someone else
        new_employee_vote = Vote.with_user(self.user_employee).create({
            'post_id':
            self.portal_post.id,
            'user_id':
            1,
            'vote':
            '1',
        })
        self.assertEqual(
            new_employee_vote.user_id, self.user_employee,
            'Creating a vote for someone else should not be allowed. It should create it for yourself instead'
        )
        # One should not be able to create a vote for someone else
        new_portal_vote = Vote.with_user(self.user_portal).create({
            'post_id':
            self.employee_post.id,
            'user_id':
            1,
            'vote':
            '1',
        })
        self.assertEqual(
            new_portal_vote.user_id, self.user_portal,
            'Creating a vote for someone else should not be allowed. It should create it for yourself instead'
        )
Пример #27
0
    def test_create_from_ui(self):
        """
        Simulation of sales coming from the interface, even after closing the session
        """

        # I click on create a new session button
        self.pos_config.open_session_cb(check_coa=False)

        current_session = self.pos_config.current_session_id
        num_starting_orders = len(current_session.order_ids)

        untax, atax = self.compute_tax(self.led_lamp, 0.9)
        carrot_order = {
            'data': {
                'amount_paid':
                untax + atax,
                'amount_return':
                0,
                'amount_tax':
                atax,
                'amount_total':
                untax + atax,
                'creation_date':
                fields.Datetime.to_string(fields.Datetime.now()),
                'fiscal_position_id':
                False,
                'pricelist_id':
                self.pos_config.available_pricelist_ids[0].id,
                'lines': [[
                    0, 0, {
                        'discount': 0,
                        'id': 42,
                        'pack_lot_ids': [],
                        'price_unit': 0.9,
                        'product_id': self.led_lamp.id,
                        'price_subtotal': 0.9,
                        'price_subtotal_incl': 1.04,
                        'qty': 1,
                        'tax_ids': [(6, 0, self.led_lamp.taxes_id.ids)]
                    }
                ]],
                'name':
                'Order 00042-003-0014',
                'partner_id':
                False,
                'pos_session_id':
                current_session.id,
                'sequence_number':
                2,
                'statement_ids': [[
                    0, 0, {
                        'amount': untax + atax,
                        'name': fields.Datetime.now(),
                        'payment_method_id': self.cash_payment_method.id
                    }
                ]],
                'uid':
                '00042-003-0014',
                'user_id':
                self.env.uid
            },
            'id': '00042-003-0014',
            'to_invoice': False
        }

        untax, atax = self.compute_tax(self.whiteboard_pen, 1.2)
        zucchini_order = {
            'data': {
                'amount_paid':
                untax + atax,
                'amount_return':
                0,
                'amount_tax':
                atax,
                'amount_total':
                untax + atax,
                'creation_date':
                fields.Datetime.to_string(fields.Datetime.now()),
                'fiscal_position_id':
                False,
                'pricelist_id':
                self.pos_config.available_pricelist_ids[0].id,
                'lines': [[
                    0, 0, {
                        'discount': 0,
                        'id': 3,
                        'pack_lot_ids': [],
                        'price_unit': 1.2,
                        'product_id': self.whiteboard_pen.id,
                        'price_subtotal': 1.2,
                        'price_subtotal_incl': 1.38,
                        'qty': 1,
                        'tax_ids': [(6, 0, self.whiteboard_pen.taxes_id.ids)]
                    }
                ]],
                'name':
                'Order 00043-003-0014',
                'partner_id':
                False,
                'pos_session_id':
                current_session.id,
                'sequence_number':
                self.pos_config.journal_id.id,
                'statement_ids': [[
                    0, 0, {
                        'amount': untax + atax,
                        'name': fields.Datetime.now(),
                        'payment_method_id': self.credit_payment_method.id
                    }
                ]],
                'uid':
                '00043-003-0014',
                'user_id':
                self.env.uid
            },
            'id': '00043-003-0014',
            'to_invoice': False
        }

        untax, atax = self.compute_tax(self.newspaper_rack, 1.28)
        newspaper_rack_order = {
            'data': {
                'amount_paid':
                untax + atax,
                'amount_return':
                0,
                'amount_tax':
                atax,
                'amount_total':
                untax + atax,
                'creation_date':
                fields.Datetime.to_string(fields.Datetime.now()),
                'fiscal_position_id':
                False,
                'pricelist_id':
                self.pos_config.available_pricelist_ids[0].id,
                'lines': [[
                    0, 0, {
                        'discount': 0,
                        'id': 3,
                        'pack_lot_ids': [],
                        'price_unit': 1.28,
                        'product_id': self.newspaper_rack.id,
                        'price_subtotal': 1.28,
                        'price_subtotal_incl': 1.47,
                        'qty': 1,
                        'tax_ids':
                        [[6, False, self.newspaper_rack.taxes_id.ids]]
                    }
                ]],
                'name':
                'Order 00044-003-0014',
                'partner_id':
                False,
                'pos_session_id':
                current_session.id,
                'sequence_number':
                self.pos_config.journal_id.id,
                'statement_ids': [[
                    0, 0, {
                        'amount': untax + atax,
                        'name': fields.Datetime.now(),
                        'payment_method_id': self.bank_payment_method.id
                    }
                ]],
                'uid':
                '00044-003-0014',
                'user_id':
                self.env.uid
            },
            'id': '00044-003-0014',
            'to_invoice': False
        }

        # I create an order on an open session
        self.PosOrder.create_from_ui([carrot_order])
        self.assertEqual(num_starting_orders + 1,
                         len(current_session.order_ids),
                         "Submitted order not encoded")

        # I close the session
        current_session.action_pos_session_closing_control()
        self.assertEqual(current_session.state, 'closed',
                         "Session was not properly closed")
        self.assertFalse(self.pos_config.current_session_id,
                         "Current session not properly recomputed")

        # I keep selling after the session is closed
        with mute_logger('flectra.addons.point_of_sale.models.pos_order'):
            self.PosOrder.create_from_ui(
                [zucchini_order, newspaper_rack_order])
        rescue_session = self.PosSession.search([('config_id', '=',
                                                  self.pos_config.id),
                                                 ('state', '=', 'opened'),
                                                 ('rescue', '=', True)])
        self.assertEqual(
            len(rescue_session), 1,
            "One (and only one) rescue session should be created for orphan orders"
        )
        self.assertIn("(RESCUE FOR %s)" % current_session.name,
                      rescue_session.name,
                      "Rescue session is not linked to the previous one")
        self.assertEqual(len(rescue_session.order_ids), 2,
                         "Rescue session does not contain both orders")

        # I close the rescue session
        rescue_session.action_pos_session_closing_control()
        self.assertEqual(rescue_session.state, 'closed',
                         "Rescue session was not properly closed")
    def test_sale_mrp(self):
        self.env.ref('stock.route_warehouse0_mto').active = True
        warehouse0 = self.env.ref('stock.warehouse0')
        # In order to test the sale_mrp module in OpenERP, I start by creating a new product 'Slider Mobile'
        # I define product category Mobile Products Sellable.

        with mute_logger('flectra.tests.common.onchange'):
            # Suppress warning on "Changing your cost method" when creating a
            # product category
            pc = Form(self.env['product.category'])
        pc.name = 'Mobile Products Sellable'
        product_category_allproductssellable0 = pc.save()

        uom_unit = self.env.ref('uom.product_uom_unit')

        self.assertIn("seller_ids", self.env['product.template'].fields_get())

        # I define product for Slider Mobile.
        product = Form(self.env['product.template'])

        product.categ_id = product_category_allproductssellable0
        product.list_price = 200.0
        product.name = 'Slider Mobile'
        product.type = 'product'
        product.uom_id = uom_unit
        product.uom_po_id = uom_unit
        product.route_ids.clear()
        product.route_ids.add(warehouse0.manufacture_pull_id.route_id)
        product.route_ids.add(warehouse0.mto_pull_id.route_id)
        product_template_slidermobile0 = product.save()

        product_template_slidermobile0.standard_price = 189

        product_component = Form(self.env['product.product'])
        product_component.name = 'Battery'
        product_product_bettery = product_component.save()

        with Form(self.env['mrp.bom']) as bom:
            bom.product_tmpl_id = product_template_slidermobile0
            with bom.bom_line_ids.new() as line:
                line.product_id = product_product_bettery
                line.product_qty = 4

        # I create a sale order for product Slider mobile
        so_form = Form(self.env['sale.order'])
        so_form.partner_id = self.env['res.partner'].create(
            {'name': 'Another Test Partner'})
        with so_form.order_line.new() as line:
            line.product_id = product_template_slidermobile0.product_variant_ids
            line.price_unit = 200
            line.product_uom_qty = 500.0
            line.customer_lead = 7.0
        sale_order_so0 = so_form.save()

        # I confirm the sale order
        sale_order_so0.action_confirm()

        # I verify that a manufacturing order has been generated, and that its name and reference are correct
        mo = self.env['mrp.production'].search(
            [('origin', 'like', sale_order_so0.name)], limit=1)
        self.assertTrue(mo, 'Manufacturing order has not been generated')
Пример #29
0
    def _update_foreign_keys(self, src_partners, dst_partner):
        """ Update all foreign key from the src_partner to dst_partner. All many2one fields will be updated.
            :param src_partners : merge source res.partner recordset (does not include destination one)
            :param dst_partner : record of destination res.partner
        """
        _logger.debug(
            '_update_foreign_keys for dst_partner: %s for src_partners: %s',
            dst_partner.id, str(src_partners.ids))

        # find the many2one relation to a partner
        Partner = self.env['res.partner']
        relations = self._get_fk_on('res_partner')

        self.flush()

        for table, column in relations:
            if 'base_partner_merge_' in table:  # ignore two tables
                continue

            # get list of columns of current table (exept the current fk column)
            query = "SELECT column_name FROM information_schema.columns WHERE table_name LIKE '%s'" % (
                table)
            self._cr.execute(query, ())
            columns = []
            for data in self._cr.fetchall():
                if data[0] != column:
                    columns.append(data[0])

            # do the update for the current table/column in SQL
            query_dic = {
                'table': table,
                'column': column,
                'value': columns[0],
            }
            if len(columns) <= 1:
                # unique key treated
                query = """
                    UPDATE "%(table)s" as ___tu
                    SET "%(column)s" = %%s
                    WHERE
                        "%(column)s" = %%s AND
                        NOT EXISTS (
                            SELECT 1
                            FROM "%(table)s" as ___tw
                            WHERE
                                "%(column)s" = %%s AND
                                ___tu.%(value)s = ___tw.%(value)s
                        )""" % query_dic
                for partner in src_partners:
                    self._cr.execute(
                        query, (dst_partner.id, partner.id, dst_partner.id))
            else:
                try:
                    with mute_logger('flectra.sql_db'), self._cr.savepoint():
                        query = 'UPDATE "%(table)s" SET "%(column)s" = %%s WHERE "%(column)s" IN %%s' % query_dic
                        self._cr.execute(query, (
                            dst_partner.id,
                            tuple(src_partners.ids),
                        ))

                        # handle the recursivity with parent relation
                        if column == Partner._parent_name and table == 'res_partner':
                            query = """
                                WITH RECURSIVE cycle(id, parent_id) AS (
                                        SELECT id, parent_id FROM res_partner
                                    UNION
                                        SELECT  cycle.id, res_partner.parent_id
                                        FROM    res_partner, cycle
                                        WHERE   res_partner.id = cycle.parent_id AND
                                                cycle.id != cycle.parent_id
                                )
                                SELECT id FROM cycle WHERE id = parent_id AND id = %s
                            """
                            self._cr.execute(query, (dst_partner.id, ))
                            # NOTE JEM : shouldn't we fetch the data ?
                except psycopg2.Error:
                    # updating fails, most likely due to a violated unique constraint
                    # keeping record with nonexistent partner_id is useless, better delete it
                    query = 'DELETE FROM "%(table)s" WHERE "%(column)s" IN %%s' % query_dic
                    self._cr.execute(query, (tuple(src_partners.ids), ))

        self.invalidate_cache()
Пример #30
0
 def test_rename_unique(self):
     """ one cannot create two fields with the same name on a given model """
     field1 = self.create_field('x_foo')
     field2 = self.create_field('x_bar')
     with self.assertRaises(IntegrityError), mute_logger('flectra.sql_db'):
         field2.name = field1.name