Пример #1
0
    def _remove_reified_groups(self, values):
        """
        The method to return values without reified group fields

        Args:
         * values - dict of values

        Methods:
         * is_boolean_group
         * get_boolean_group
         * is_selection_groups
         * get_selection_groups

        Returns:
         * dict of updated values
        """
        add, rem = [], []
        values1 = {}
        for key, val in values.items():
            if is_boolean_group(key):
                (add if val else rem).append(get_boolean_group(key))
            elif is_selection_groups(key):
                rem += get_selection_groups(key)
                if val:
                    add.append(val)
            else:
                values1[key] = val
        if 'group_ids' not in values and (add or rem):
            values1['group_ids'] = list(chain(
                pycompat.izip(repeat(3), rem),
                pycompat.izip(repeat(4), add)
            ))
        return values1
Пример #2
0
    def test_banxico_currency_update(self):
        self.company.currency_id = self.mxn
        # Using self.usd.rate=1 and self.mxn.rate != 1
        self.set_rate(self.usd, 1.0)
        self.assertEqual(self.usd.rate, 1.0)
        self.set_rate(self.mxn, 10.0)
        self.assertEqual(self.mxn.rate, 10.0)
        with patch('suds.client.Client', new=serviceClientMock):
            self.company.update_currency_rates()
        self.assertNotEqual(self.usd.rate, 1.0)
        self.assertNotEqual(self.mxn.rate, 10.0)
        foreigns1 = [
            foreign_currency._convert(1.0,
                                      self.mxn,
                                      company=self.company,
                                      date=fields.Date.today())
            for foreign_currency in self.foreign_currencies
        ]

        # Using self.mxn.rate=1 and self.usd.rate != 1
        self.set_rate(self.mxn, 1.0)
        self.assertEqual(self.mxn.rate, 1.0)
        self.set_rate(self.usd, 0.1)
        self.assertEqual(self.usd.compare_amounts(self.usd.rate, 0.1), 0)
        with patch('suds.client.Client', new=serviceClientMock):
            self.company.update_currency_rates()
        self.assertEqual(self.mxn.rate, 1.0)
        self.assertNotEqual(self.usd.rate, 1.0 / 10.0)
        foreigns2 = [
            foreign_currency._convert(1.0,
                                      self.mxn,
                                      company=self.company,
                                      date=fields.Date.today())
            for foreign_currency in self.foreign_currencies
        ]
        for curr, foreign1, foreign2 in pycompat.izip(self.foreign_currencies,
                                                      foreigns1, foreigns2):
            self.assertEqual(
                curr.compare_amounts(foreign1, foreign2), 0,
                "%s diff rate %s != %s" % (curr.name, foreign1, foreign2))
        # Compare expected xml mocked rate values vs real ones
        for curr, real_rate, expected_rate in pycompat.izip(
                self.foreign_currencies, foreigns1,
                self.foreign_expected_rates):
            self.assertEqual(
                curr.compare_amounts(real_rate, expected_rate), 0,
                "%s diff rate %s != %s" %
                (curr.name, real_rate, expected_rate))
Пример #3
0
    def process_bank_statement_line(self, st_line_ids, data):
        """ Handles data sent from the bank statement reconciliation widget
            (and can otherwise serve as an old-API bridge)

            :param st_line_ids
            :param list of dicts data: must contains the keys
                'counterpart_aml_dicts', 'payment_aml_ids' and 'new_aml_dicts',
                whose value is the same as described in process_reconciliation
                except that ids are used instead of recordsets.
        """
        st_lines = self.env['account.bank.statement.line'].browse(st_line_ids)
        AccountMoveLine = self.env['account.move.line']
        ctx = dict(self._context, force_price_include=False)

        for st_line, datum in pycompat.izip(st_lines, data):
            payment_aml_rec = AccountMoveLine.browse(datum.get('payment_aml_ids', []))

            for aml_dict in datum.get('counterpart_aml_dicts', []):
                aml_dict['move_line'] = AccountMoveLine.browse(aml_dict['counterpart_aml_id'])
                del aml_dict['counterpart_aml_id']

            if datum.get('partner_id') is not None:
                st_line.write({'partner_id': datum['partner_id']})

            st_line.with_context(ctx).process_reconciliation(
                datum.get('counterpart_aml_dicts', []),
                payment_aml_rec,
                datum.get('new_aml_dicts', []))
Пример #4
0
    def create(self, vals_list):
        ''' Store the initial standard price in order to be able to retrieve the cost of a product template for a given date'''
        # TDE FIXME: context brol
        for vals in vals_list:
            tools.image_resize_images(vals)
        templates = super(ProductTemplate, self).create(vals_list)
        if "create_product_product" not in self._context:
            templates.with_context(create_from_tmpl=True).create_variant_ids()

        # This is needed to set given values to first variant after creation
        for template, vals in pycompat.izip(templates, vals_list):
            related_vals = {}
            if vals.get('barcode'):
                related_vals['barcode'] = vals['barcode']
            if vals.get('default_code'):
                related_vals['default_code'] = vals['default_code']
            if vals.get('standard_price'):
                related_vals['standard_price'] = vals['standard_price']
            if vals.get('volume'):
                related_vals['volume'] = vals['volume']
            if vals.get('weight'):
                related_vals['weight'] = vals['weight']
            if related_vals:
                template.write(related_vals)

        return templates
Пример #5
0
    def create(self, vals_list):
        if self.env.context.get('import_file'):
            self._check_import_consistency(vals_list)
        for vals in vals_list:
            if vals.get('website'):
                vals['website'] = self._clean_website(vals['website'])
            if vals.get('parent_id'):
                vals['company_name'] = False
            if vals.get('customer'):
                vals['customer'] = False
            # compute default image in create, because computing gravatar in the onchange
            # cannot be easily performed if default images are in the way
            if not vals.get('image'):
                vals['image'] = self._get_default_image(
                    vals.get('type'), vals.get('is_company'),
                    vals.get('parent_id'))
            tools.image_resize_images(vals, sizes={'image': (1024, None)})
        partners = super(Partner, self).create(vals_list)

        if self.env.context.get('_partners_skip_fields_sync'):
            return partners

        for partner, vals in pycompat.izip(partners, vals_list):
            partner._fields_sync(vals)
            partner._handle_first_contact_creation()
        return partners
Пример #6
0
    def _get_post_karma_rights(self):
        user = self.env.user
        is_admin = user.id == SUPERUSER_ID
        # sudoed recordset instead of individual posts so values can be
        # prefetched in bulk
        for post, post_sudo in pycompat.izip(self, self.sudo()):
            is_creator = post.create_uid == user

            post.karma_accept = post.forum_id.karma_answer_accept_own if post.parent_id.create_uid == user else post.forum_id.karma_answer_accept_all
            post.karma_edit = post.forum_id.karma_edit_own if is_creator else post.forum_id.karma_edit_all
            post.karma_close = post.forum_id.karma_close_own if is_creator else post.forum_id.karma_close_all
            post.karma_unlink = post.forum_id.karma_unlink_own if is_creator else post.forum_id.karma_unlink_all
            post.karma_comment = post.forum_id.karma_comment_own if is_creator else post.forum_id.karma_comment_all
            post.karma_comment_convert = post.forum_id.karma_comment_convert_own if is_creator else post.forum_id.karma_comment_convert_all

            post.can_ask = is_admin or user.karma >= post.forum_id.karma_ask
            post.can_answer = is_admin or user.karma >= post.forum_id.karma_answer
            post.can_accept = is_admin or user.karma >= post.karma_accept
            post.can_edit = is_admin or user.karma >= post.karma_edit
            post.can_close = is_admin or user.karma >= post.karma_close
            post.can_unlink = is_admin or user.karma >= post.karma_unlink
            post.can_upvote = is_admin or user.karma >= post.forum_id.karma_upvote
            post.can_downvote = is_admin or user.karma >= post.forum_id.karma_downvote
            post.can_comment = is_admin or user.karma >= post.karma_comment
            post.can_comment_convert = is_admin or user.karma >= post.karma_comment_convert
            post.can_view = is_admin or user.karma >= post.karma_close or (post_sudo.create_uid.karma > 0 and (post_sudo.active or post_sudo.create_uid == user))
            post.can_display_biography = is_admin or post_sudo.create_uid.karma >= post.forum_id.karma_user_bio
            post.can_post = is_admin or user.karma >= post.forum_id.karma_post
            post.can_flag = is_admin or user.karma >= post.forum_id.karma_flag
            post.can_moderate = is_admin or user.karma >= post.forum_id.karma_moderate
Пример #7
0
    def test_invoice_with_discount(self):
        """ Test invoice with a discount and check discount applied on both SO lines and an invoice lines """
        # Update discount and delivered quantity on SO lines
        self.sol_prod_order.write({'discount': 20.0})
        self.sol_serv_deliver.write({'discount': 20.0, 'qty_delivered': 4.0})
        self.sol_serv_order.write({'discount': -10.0})
        self.sol_prod_deliver.write({'qty_delivered': 2.0})

        for line in self.sale_order.order_line.filtered(lambda l: l.discount):
            product_price = line.price_unit * line.product_uom_qty
            self.assertEquals(line.discount, (product_price - line.price_subtotal) / product_price * 100, 'Discount should be applied on order line')

        self.sale_order.action_confirm()

        # Let's do an invoice with invoiceable lines
        payment = self.env['sale.advance.payment.inv'].with_context(self.context).create({
            'advance_payment_method': 'delivered'
        })
        payment.create_invoices()
        invoice = self.sale_order.invoice_ids[0]
        invoice.action_invoice_open()

        # Check discount appeared on both SO lines and invoice lines
        for line, inv_line in pycompat.izip(self.sale_order.order_line, invoice.invoice_line_ids):
            self.assertEquals(line.discount, inv_line.discount, 'Discount on lines of order and invoice should be same')
Пример #8
0
    def _compute_display_name(self):
        self2 = self.with_context(display_website=False)
        super(Partner, self2)._compute_display_name()

        # onchange uses the cache to retrieve value, we need to copy computed_value into the initial env
        for record, record2 in izip(self, self2):
            record.display_name = record2.display_name
Пример #9
0
 def create(self, vals_list):
     result = super(Base, self).create(vals_list)
     for record, values in pycompat.izip(result, vals_list):
         if not values:
             continue
         write_log(record, 'create', values)
     return result
Пример #10
0
    def _create_all_specific_views(self, processed_modules):
        """ When creating a generic child view, we should
            also create that view under specific view trees (COW'd).
            Top level view (no inherit_id) do not need that behavior as they
            will be shared between websites since there is no specific yet.
        """
        # Only for the modules being processed
        regex = '^(%s)[.]' % '|'.join(processed_modules)
        # Retrieve the views through a SQl query to avoid ORM queries inside of for loop
        # Retrieves all the views that are missing their specific counterpart with all the
        # specific view parent id and their website id in one query
        query = """
            SELECT generic.id, ARRAY[array_agg(spec_parent.id), array_agg(spec_parent.website_id)]
              FROM ir_ui_view generic
        INNER JOIN ir_ui_view generic_parent ON generic_parent.id = generic.inherit_id
        INNER JOIN ir_ui_view spec_parent ON spec_parent.key = generic_parent.key
         LEFT JOIN ir_ui_view specific ON specific.key = generic.key AND specific.website_id = spec_parent.website_id
             WHERE generic.type='qweb'
               AND generic.website_id IS NULL
               AND generic.key ~ %s
               AND spec_parent.website_id IS NOT NULL
               AND specific.id IS NULL
          GROUP BY generic.id
        """
        self.env.cr.execute(query, (regex, ))
        result = dict(self.env.cr.fetchall())

        for record in self.browse(result.keys()):
            specific_parent_view_ids, website_ids = result[record.id]
            for specific_parent_view_id, website_id in pycompat.izip(specific_parent_view_ids, website_ids):
                record.with_context(website_id=website_id).write({
                    'inherit_id': specific_parent_view_id,
                })
        super(View, self)._create_all_specific_views(processed_modules)
Пример #11
0
    def process_bank_statement_line(self, st_line_ids, data):
        """ Handles data sent from the bank statement reconciliation widget
            (and can otherwise serve as an old-API bridge)

            :param st_line_ids
            :param list of dicts data: must contains the keys
                'counterpart_aml_dicts', 'payment_aml_ids' and 'new_aml_dicts',
                whose value is the same as described in process_reconciliation
                except that ids are used instead of recordsets.
        """
        st_lines = self.env['account.bank.statement.line'].browse(st_line_ids)
        AccountMoveLine = self.env['account.move.line']
        ctx = dict(self._context, force_price_include=False)

        for st_line, datum in pycompat.izip(st_lines, data):
            payment_aml_rec = AccountMoveLine.browse(datum.get('payment_aml_ids', []))

            for aml_dict in datum.get('counterpart_aml_dicts', []):
                aml_dict['move_line'] = AccountMoveLine.browse(aml_dict['counterpart_aml_id'])
                del aml_dict['counterpart_aml_id']

            if datum.get('partner_id') is not None:
                st_line.write({'partner_id': datum['partner_id']})

            st_line.with_context(ctx).process_reconciliation(
                datum.get('counterpart_aml_dicts', []),
                payment_aml_rec,
                datum.get('new_aml_dicts', []))
Пример #12
0
 def _compute_full_name(self):
     # Important: value must be stored in environment of group, not group1!
     for group, group1 in pycompat.izip(self, self.sudo()):
         if group1.category_id:
             group.full_name = '%s / %s' % (group1.category_id.name, group1.name)
         else:
             group.full_name = group1.name
Пример #13
0
    def _website_price(self):
        qty = self._context.get('quantity', 1.0)
        partner = self.env.user.partner_id
        current_website = self.env['website'].get_current_website()
        pricelist = current_website.get_current_pricelist()
        company_id = current_website.company_id

        context = dict(self._context, pricelist=pricelist.id, partner=partner)
        self2 = self.with_context(
            context) if self._context != context else self

        ret = self.env.user.has_group(
            'account.group_show_line_subtotals_tax_excluded'
        ) and 'total_excluded' or 'total_included'

        for p, p2 in pycompat.izip(self, self2):
            taxes = partner.property_account_position_id.map_tax(
                p.sudo().taxes_id.filtered(
                    lambda x: x.company_id == company_id), p, partner)
            p.website_price = taxes.compute_all(p2.price,
                                                pricelist.currency_id,
                                                quantity=qty,
                                                product=p2,
                                                partner=partner)[ret]
            price_without_pricelist = taxes.compute_all(
                p.list_price, pricelist.currency_id)[ret]
            p.website_price_difference = False if float_is_zero(
                price_without_pricelist - p.website_price,
                precision_rounding=pricelist.currency_id.rounding) else True
            p.website_public_price = taxes.compute_all(p2.lst_price,
                                                       quantity=qty,
                                                       product=p2,
                                                       partner=partner)[ret]
Пример #14
0
 def create(self, vals_list):
     products = super(ProductProduct, self.with_context(create_product_product=True)).create(vals_list)
     for product, vals in pycompat.izip(products, vals_list):
         # When a unique variant is created from tmpl then the standard price is set by _set_standard_price
         if not (self.env.context.get('create_from_tmpl') and len(product.product_tmpl_id.product_variant_ids) == 1):
             product._set_standard_price(vals.get('standard_price') or 0.0)
     return products
Пример #15
0
    def _compute_product_price_rule(self):
        pricelist_id_or_name = self._context.get('pricelist')
        pricelist_item = {}
        if pricelist_id_or_name:
            pricelist = None
            partner = self._context.get('partner', False)
            quantity = self._context.get('quantity', 1.0)

            # Support context pricelists specified as display_name or ID for compatibility
            if isinstance(pricelist_id_or_name, pycompat.string_types):
                pricelist_name_search = self.env['product.pricelist'].name_search(pricelist_id_or_name, operator='=',
                                                                                  limit=1)
                if pricelist_name_search:
                    pricelist = self.env['product.pricelist'].browse([pricelist_name_search[0][0]])
            elif isinstance(pricelist_id_or_name, pycompat.integer_types):
                pricelist = self.env['product.pricelist'].browse(pricelist_id_or_name)

            if pricelist:
                quantities = [quantity] * len(self)
                partners = [partner] * len(self)
                pricelist_item = pricelist.price_rule_get_multi(list(pycompat.izip(self, quantities, partners)))

        for product in self:
            rule_id = pricelist_item.get(product.id) and pricelist_item.get(product.id).get(pricelist.id)[1]
            if rule_id:
                pricelist_code = self.env['product.pricelist.item'].browse([rule_id])
                if pricelist_code:
                    product.pricelist_code = pricelist_code.code
Пример #16
0
    def _website_price(self):
        qty = self._context.get('quantity', 1.0)
        partner = self.env.user.partner_id
        pricelist = self.env['website'].get_current_website(
        ).get_current_pricelist()

        context = dict(self._context, pricelist=pricelist.id, partner=partner)
        self2 = self.with_context(
            context) if self._context != context else self

        ret = self.env.user.has_group(
            'sale.group_show_price_subtotal'
        ) and 'total_excluded' or 'total_included'

        for p, p2 in pycompat.izip(self, self2):
            taxes = partner.property_account_position_id.map_tax(p.taxes_id)
            p.website_price = taxes.compute_all(p2.price,
                                                pricelist.currency_id,
                                                quantity=qty,
                                                product=p2,
                                                partner=partner)[ret]
            p.website_public_price = taxes.compute_all(p2.lst_price,
                                                       quantity=qty,
                                                       product=p2,
                                                       partner=partner)[ret]
Пример #17
0
    def create(self, vals_list):
        ''' Store the initial standard price in order to be able to retrieve the cost of a product template for a given date'''
        # TDE FIXME: context brol
        for vals in vals_list:
            tools.image_resize_images(vals)
        templates = super(ProductTemplate, self).create(vals_list)
        if "create_product_product" not in self._context:
            templates.with_context(create_from_tmpl=True).create_variant_ids()

        # This is needed to set given values to first variant after creation
        for template, vals in pycompat.izip(templates, vals_list):
            related_vals = {}
            if vals.get('barcode'):
                related_vals['barcode'] = vals['barcode']
            if vals.get('default_code'):
                related_vals['default_code'] = vals['default_code']
            if vals.get('standard_price'):
                related_vals['standard_price'] = vals['standard_price']
            if vals.get('volume'):
                related_vals['volume'] = vals['volume']
            if vals.get('weight'):
                related_vals['weight'] = vals['weight']
            if related_vals:
                template.write(related_vals)

        return templates
Пример #18
0
    def _get_post_karma_rights(self):
        user = self.env.user
        is_admin = user.id == SUPERUSER_ID
        # sudoed recordset instead of individual posts so values can be
        # prefetched in bulk
        for post, post_sudo in pycompat.izip(self, self.sudo()):
            is_creator = post.create_uid == user

            post.karma_accept = post.forum_id.karma_answer_accept_own if post.parent_id.create_uid == user else post.forum_id.karma_answer_accept_all
            post.karma_edit = post.forum_id.karma_edit_own if is_creator else post.forum_id.karma_edit_all
            post.karma_close = post.forum_id.karma_close_own if is_creator else post.forum_id.karma_close_all
            post.karma_unlink = post.forum_id.karma_unlink_own if is_creator else post.forum_id.karma_unlink_all
            post.karma_comment = post.forum_id.karma_comment_own if is_creator else post.forum_id.karma_comment_all
            post.karma_comment_convert = post.forum_id.karma_comment_convert_own if is_creator else post.forum_id.karma_comment_convert_all

            post.can_ask = is_admin or user.karma >= post.forum_id.karma_ask
            post.can_answer = is_admin or user.karma >= post.forum_id.karma_answer
            post.can_accept = is_admin or user.karma >= post.karma_accept
            post.can_edit = is_admin or user.karma >= post.karma_edit
            post.can_close = is_admin or user.karma >= post.karma_close
            post.can_unlink = is_admin or user.karma >= post.karma_unlink
            post.can_upvote = is_admin or user.karma >= post.forum_id.karma_upvote
            post.can_downvote = is_admin or user.karma >= post.forum_id.karma_downvote
            post.can_comment = is_admin or user.karma >= post.karma_comment
            post.can_comment_convert = is_admin or user.karma >= post.karma_comment_convert
            post.can_view = is_admin or user.karma >= post.karma_close or (post_sudo.create_uid.karma > 0 and (post_sudo.active or post_sudo.create_uid == user))
            post.can_display_biography = is_admin or post_sudo.create_uid.karma >= post.forum_id.karma_user_bio
            post.can_post = is_admin or user.karma >= post.forum_id.karma_post
            post.can_flag = is_admin or user.karma >= post.forum_id.karma_flag
            post.can_moderate = is_admin or user.karma >= post.forum_id.karma_moderate
Пример #19
0
 def _compute_full_name(self):
     # Important: value must be stored in environment of group, not group1!
     for group, group1 in pycompat.izip(self, self.sudo()):
         if group1.category_id:
             group.full_name = '%s / %s' % (group1.category_id.name, group1.name)
         else:
             group.full_name = group1.name
Пример #20
0
 def create(self, vals_list):
     user_ids_list = [vals.pop('users', None) for vals in vals_list]
     groups = super(GroupsImplied, self).create(vals_list)
     for group, user_ids in pycompat.izip(groups, user_ids_list):
         if user_ids:
             # delegate addition of users to add implied groups
             group.write({'users': user_ids})
     return groups
Пример #21
0
 def _compute_full_name(self):
     # 仅仅原子权限组name才显示全名
     for group, group1 in pycompat.izip(self, self.sudo()):
         if group1.category_id and group1.atomic:
             group.full_name = '%s / %s' % (group1.category_id.name,
                                            group1.name)
         else:
             group.full_name = group1.name
Пример #22
0
    def test_multiple(self):
        """ With two "concurrent" o2ms, exports the first line combined, then
        exports the rows for the first o2m, then the rows for the second o2m.
        """
        fields = ['const', 'child1/value', 'child2/value']
        child1 = [(0, False, {
            'value': v,
            'str': 'record%.02d' % index
        }) for index, v in pycompat.izip(itertools.count(), [4, 42, 36, 4, 13])
                  ]
        child2 = [(0, False, {
            'value': v,
            'str': 'record%.02d' % index
        }) for index, v in pycompat.izip(itertools.count(10),
                                         [8, 12, 8, 55, 33, 13])]

        self.assertEqual(
            self.export(child1=child1, child2=False, fields=fields), [
                [u'36', u'4', False],
                ['', u'42', ''],
                ['', u'36', ''],
                ['', u'4', ''],
                ['', u'13', ''],
            ])
        self.assertEqual(
            self.export(child1=False, child2=child2, fields=fields), [
                [u'36', False, u'8'],
                ['', '', u'12'],
                ['', '', u'8'],
                ['', '', u'55'],
                ['', '', u'33'],
                ['', '', u'13'],
            ])
        self.assertEqual(
            self.export(child1=child1, child2=child2, fields=fields), [
                [u'36', u'4', u'8'],
                ['', u'42', ''],
                ['', u'36', ''],
                ['', u'4', ''],
                ['', u'13', ''],
                ['', '', u'12'],
                ['', '', u'8'],
                ['', '', u'55'],
                ['', '', u'33'],
                ['', '', u'13'],
            ])
Пример #23
0
 def _compute_location_description(self):
     for operation, operation_sudo in izip(self, self.sudo()):
         operation.from_loc = '%s%s' % (
             operation_sudo.location_id.name,
             operation.product_id and operation_sudo.package_id.name or '')
         operation.to_loc = '%s%s' % (operation_sudo.location_dest_id.name,
                                      operation_sudo.result_package_id.name
                                      or '')
Пример #24
0
 def write(self, values):
     res = super(GroupsImplied, self).write(values)
     if values.get('users') or values.get('implied_ids'):
         # add all implied groups (to all users of each group)
         for group in self:
             vals = {'users': list(pycompat.izip(repeat(4), group.with_context(active_test=False).users.ids))}
             super(GroupsImplied, group.trans_implied_ids).write(vals)
     return res
Пример #25
0
 def write(self, values):
     res = super(GroupsImplied, self).write(values)
     if values.get('users') or values.get('implied_ids'):
         # add all implied groups (to all users of each group)
         for group in self:
             vals = {'users': list(pycompat.izip(repeat(4), group.with_context(active_test=False).users.ids))}
             super(GroupsImplied, group.trans_implied_ids).write(vals)
     return res
Пример #26
0
 def create(self, vals_list):
     user_ids_list = [vals.pop('users', None) for vals in vals_list]
     groups = super(GroupsImplied, self).create(vals_list)
     for group, user_ids in pycompat.izip(groups, user_ids_list):
         if user_ids:
             # delegate addition of users to add implied groups
             group.write({'users': user_ids})
     return groups
Пример #27
0
 def _website_price(self):
     # First filter out the ones that have no variant:
     # This makes sure that every template below has a corresponding product in the zipped result.
     self = self.filtered('product_variant_id')
     # use mapped who returns a recordset with only itself to prefetch (and don't prefetch every product_variant_ids)
     for template, product in pycompat.izip(self, self.mapped('product_variant_id')):
         template.website_price = product.website_price
         template.website_public_price = product.website_public_price
Пример #28
0
 def iter_tax_codes(self):
     keys = [c.value for c in self.sheet_tax_codes.row(0)]
     yield keys
     for i in range(1, self.sheet_tax_codes.nrows):
         row = (c.value for c in self.sheet_tax_codes.row(i))
         d = OrderedDict(pycompat.izip(keys, row))
         d['sign'] = int(d['sign'])
         d['sequence'] = int(d['sequence'])
         yield d
Пример #29
0
 def create(self, vals_list):
     products = super(ProductProduct, self.with_context(create_product_product=True)).create(vals_list)
     for product, vals in pycompat.izip(products, vals_list):
         # When a unique variant is created from tmpl then the standard price is set by _set_standard_price
         if not (self.env.context.get('create_from_tmpl') and len(product.product_tmpl_id.product_variant_ids) == 1):
             product._set_standard_price(vals.get('standard_price') or 0.0)
     # `_get_variant_id_for_combination` depends on existing variants
     self.clear_caches()
     return products
Пример #30
0
 def _website_price(self):
     # First filter out the ones that have no variant:
     # This makes sure that every template below has a corresponding product in the zipped result.
     self = self.filtered('product_variant_id')
     # use mapped who returns a recordset with only itself to prefetch (and don't prefetch every product_variant_ids)
     for template, product in pycompat.izip(
             self, self.mapped('product_variant_id')):
         template.website_price = product.website_price
         template.website_public_price = product.website_public_price
Пример #31
0
 def create(self, vals_list):
     """A function like create of the original in order to track the changing of done moves qty"""
     mls = super(StockMoveLineInheritProductStockPriceConnector,
                 self).create(vals_list)
     for ml, vals in izip(mls, vals_list):
         if ml.state == 'done':
             if ml.product_id.type == 'product':
                 ml.send_new_stock_data_product_connector_webserver()
     return mls
Пример #32
0
    def message_post(self, **kwargs):
        # OVERRIDE
        # /!\ 'default_res_id' in self._context is used to don't process attachment when using a form view.
        res = super(AccountInvoice, self).message_post(**kwargs)

        def _get_attachment_filename(attachment):
            # Handle both _Attachment namedtuple in mail.thread or ir.attachment.
            return hasattr(attachment, 'fname') and getattr(attachment, 'fname') or attachment.name

        def _get_attachment_content(attachment):
            # Handle both _Attachment namedtuple in mail.thread or ir.attachment.
            return hasattr(attachment, 'content') and getattr(attachment, 'content') or base64.b64decode(attachment.datas)

        if 'default_res_id' not in self._context and len(self) == 1 and self.state == 'draft' and self.type in ('in_invoice', 'in_refund'):
            # Get attachments.
            # - 'attachments' is a namedtuple defined in mail.thread looking like:
            # _Attachment = namedtuple('Attachment', ('fname', 'content', 'info'))
            # - 'attachment_ids' is a list of ir.attachment records ids.
            attachments = kwargs.get('attachments', [])
            if kwargs.get('attachment_ids'):
                attachments += self.env['ir.attachment'].browse(kwargs['attachment_ids'])

            for attachment in attachments:
                filename = _get_attachment_filename(attachment)
                content = _get_attachment_content(attachment)

                # Check if the attachment is a pdf.
                if not filename.endswith('.pdf'):
                    continue

                buffer = io.BytesIO(content)
                try:
                    reader = PdfFileReader(buffer)

                    # Search for Factur-x embedded file.
                    if reader.trailer['/Root'].get('/Names') and reader.trailer['/Root']['/Names'].get('/EmbeddedFiles'):
                        # N.B: embedded_files looks like:
                        # ['file.xml', {'/Type': '/Filespec', '/F': 'file.xml', '/EF': {'/F': IndirectObject(22, 0)}}]
                        embedded_files = reader.trailer['/Root']['/Names']['/EmbeddedFiles']['/Names']
                        # '[::2]' because it's a list [fn_1, content_1, fn_2, content_2, ..., fn_n, content_2]
                        for filename_obj, content_obj in list(pycompat.izip(embedded_files, embedded_files[1:]))[::2]:
                            content = content_obj.getObject()['/EF']['/F'].getData()

                            if filename_obj == 'factur-x.xml':
                                try:
                                    tree = etree.fromstring(content)
                                except:
                                    continue

                                self._import_facturx_invoice(tree)
                                buffer.close()
                                return res
                except:
                    # Malformed PDF.
                    pass
                buffer.close()
        return res
Пример #33
0
def load_information_from_description_file(module, mod_path=None):
    """
    :param module: The name of the module (sale, purchase, ...)
    :param mod_path: Physical path of module, if not providedThe name of the module (sale, purchase, ...)
    """
    if not mod_path:
        mod_path = get_module_path(module, downloaded=True)
    manifest_file = module_manifest(mod_path)
    if manifest_file:
        # default values for descriptor
        info = {
            'application': False,
            'author': 'Odoo S.A.',
            'auto_install': False,
            'category': 'Uncategorized',
            'depends': [],
            'description': '',
            'icon': get_module_icon(module),
            'installable': True,
            'license': 'LGPL-3',
            'post_load': None,
            'version': '1.0',
            'web': False,
            'sequence': 100,
            'summary': '',
            'website': '',
        }
        info.update(
            pycompat.izip(
                'depends data demo test init_xml update_xml demo_xml'.split(),
                iter(list, None)))

        f = tools.file_open(manifest_file, mode='rb')
        try:
            info.update(ast.literal_eval(pycompat.to_native(f.read())))
        finally:
            f.close()

        if not info.get('description'):
            readme_path = [
                opj(mod_path, x) for x in README
                if os.path.isfile(opj(mod_path, x))
            ]
            if readme_path:
                readme_text = tools.file_open(readme_path[0]).read()
                info['description'] = readme_text

        if 'active' in info:
            # 'active' has been renamed 'auto_install'
            info['auto_install'] = info['active']

        info['version'] = adapt_version(info['version'])
        return info

    _logger.debug('module %s: no manifest file found %s', module,
                  MANIFEST_NAMES)
    return {}
Пример #34
0
    def create(self, vals_list):
        # Override the original create function for the inherited model
        templates = super(Custom_ProductTemplate_PedroLara,
                          self).create(vals_list)
        for template, vals in pycompat.izip(templates, vals_list):
            # Set udPallet value from form
            template.udPallet = vals.get('udPallet') or 0

        return templates
Пример #35
0
    def message_post(self, **kwargs):
        # OVERRIDE
        # /!\ 'default_res_id' in self._context is used to don't process attachment when using a form view.
        res = super(AccountInvoice, self).message_post(**kwargs)

        def _get_attachment_filename(attachment):
            # Handle both _Attachment namedtuple in mail.thread or ir.attachment.
            return hasattr(attachment, 'fname') and getattr(attachment, 'fname') or attachment.name

        def _get_attachment_content(attachment):
            # Handle both _Attachment namedtuple in mail.thread or ir.attachment.
            return hasattr(attachment, 'content') and getattr(attachment, 'content') or base64.b64decode(attachment.datas)

        if 'default_res_id' not in self._context and len(self) == 1 and self.state == 'draft' and self.type in ('in_invoice', 'in_refund'):
            # Get attachments.
            # - 'attachments' is a namedtuple defined in mail.thread looking like:
            # _Attachment = namedtuple('Attachment', ('fname', 'content', 'info'))
            # - 'attachment_ids' is a list of ir.attachment records ids.
            attachments = kwargs.get('attachments', [])
            if kwargs.get('attachment_ids'):
                attachments += self.env['ir.attachment'].browse(kwargs['attachment_ids'])

            for attachment in attachments:
                filename = _get_attachment_filename(attachment)
                content = _get_attachment_content(attachment)

                # Check if the attachment is a pdf.
                if not filename.endswith('.pdf'):
                    continue

                buffer = io.BytesIO(content)
                try:
                    reader = PdfFileReader(buffer)

                    # Search for Factur-x embedded file.
                    if reader.trailer['/Root'].get('/Names') and reader.trailer['/Root']['/Names'].get('/EmbeddedFiles'):
                        # N.B: embedded_files looks like:
                        # ['file.xml', {'/Type': '/Filespec', '/F': 'file.xml', '/EF': {'/F': IndirectObject(22, 0)}}]
                        embedded_files = reader.trailer['/Root']['/Names']['/EmbeddedFiles']['/Names']
                        # '[::2]' because it's a list [fn_1, content_1, fn_2, content_2, ..., fn_n, content_2]
                        for filename_obj, content_obj in list(pycompat.izip(embedded_files, embedded_files[1:]))[::2]:
                            content = content_obj.getObject()['/EF']['/F'].getData()

                            if filename_obj == 'factur-x.xml':
                                try:
                                    tree = etree.fromstring(content)
                                except:
                                    continue

                                self._import_facturx_invoice(tree)
                                buffer.close()
                                return res
                except:
                    # Malformed PDF.
                    pass
                buffer.close()
        return res
Пример #36
0
 def create(self, vals_list):
     templates = super(ProductTemplate, self).create(vals_list)
     for template, vals in pycompat.izip(templates, vals_list):
         related_vals = {}
         if vals.get('fleet_vehicle_model_id'):
             related_vals['fleet_vehicle_model_id'] = vals[
                 'fleet_vehicle_model_id']
         if related_vals:
             template.write(related_vals)
     return templates
Пример #37
0
    def test_multiple(self):
        """ With two "concurrent" o2ms, exports the first line combined, then
        exports the rows for the first o2m, then the rows for the second o2m.
        """
        fields = ['const', 'child1/value', 'child2/value']
        child1 = [(0, False, {'value': v, 'str': 'record%.02d' % index})
                  for index, v in pycompat.izip(itertools.count(), [4, 42, 36, 4, 13])]
        child2 = [(0, False, {'value': v, 'str': 'record%.02d' % index})
                  for index, v in pycompat.izip(itertools.count(10), [8, 12, 8, 55, 33, 13])]

        self.assertEqual(
            self.export(child1=child1, child2=False, fields=fields),
            [
                [u'36', u'4', False],
                ['', u'42', ''],
                ['', u'36', ''],
                ['', u'4', ''],
                ['', u'13', ''],
            ])
        self.assertEqual(
            self.export(child1=False, child2=child2, fields=fields),
            [
                [u'36', False, u'8'],
                ['', '', u'12'],
                ['', '', u'8'],
                ['', '', u'55'],
                ['', '', u'33'],
                ['', '', u'13'],
            ])
        self.assertEqual(
            self.export(child1=child1, child2=child2, fields=fields),
            [
                [u'36', u'4', u'8'],
                ['', u'42', ''],
                ['', u'36', ''],
                ['', u'4', ''],
                ['', u'13', ''],
                ['', '', u'12'],
                ['', '', u'8'],
                ['', '', u'55'],
                ['', '', u'33'],
                ['', '', u'13'],
            ])
Пример #38
0
        def chk(lst, verbose=False):
            pvs = []
            for v in lst:
                pv = parse_version(v)
                pvs.append(pv)
                if verbose:
                    print(v, pv)

            for a, b in pycompat.izip(pvs, pvs[1:]):
                assert a < b, '%s < %s == %s' % (a, b, a < b)
Пример #39
0
    def chk(lst, verbose=False):
        pvs = []
        for v in lst:
            pv = parse_version(v)
            pvs.append(pv)
            if verbose:
                print(v, pv)

        for a, b in pycompat.izip(pvs, pvs[1:]):
            assert a < b, '%s < %s == %s' % (a, b, a < b)
Пример #40
0
    def _website_price(self):

        qty = self._context.get('quantity', 1.0)
        partner = self.env.user.partner_id
        current_website = self.env['website'].get_current_website()
        pricelist = current_website.get_current_pricelist()
        company_id = current_website.company_id

        context = dict(self._context, pricelist=pricelist.id, partner=partner)
        self2 = self.with_context(
            context) if self._context != context else self

        for p, p2 in pycompat.izip(self, self2):

            has_margin = any(p.sudo().taxes_id.filtered('on_margin'))
            is_public = self.env.user == request.website.user_id
            show_total_included = bool(is_public
                                       or (has_margin and not is_public))

            ret = 'total_included' if show_total_included else 'total_excluded'

            taxes = partner.property_account_position_id.map_tax(
                p.sudo().taxes_id.filtered(
                    lambda x: x.company_id == company_id))

            taxes_website_price = taxes.compute_all(p2.price,
                                                    pricelist.currency_id,
                                                    quantity=qty,
                                                    product=p2,
                                                    partner=partner)
            p.website_price = taxes_website_price[ret]

            # We must convert the price_without_pricelist in the same currency than the
            # website_price, otherwise the comparison doesn't make sense. Moreover, we show a price
            # difference only if the website price is lower
            price_without_pricelist = p.list_price
            if company_id.currency_id != pricelist.currency_id:
                price_without_pricelist = company_id.currency_id._convert(
                    price_without_pricelist, pricelist.currency_id)

            taxes_price_without_pricelist = taxes.compute_all(
                price_without_pricelist, pricelist.currency_id)
            price_without_pricelist = taxes_price_without_pricelist[ret]

            p.website_price_difference = True if float_compare(
                price_without_pricelist,
                p.website_price,
                precision_rounding=pricelist.currency_id.rounding
            ) > 0 else False

            taxes_website_public_price = taxes.compute_all(p2.lst_price,
                                                           quantity=qty,
                                                           product=p2,
                                                           partner=partner)
            p.website_public_price = taxes_website_public_price[ret]
Пример #41
0
    def _load_records_create(self, vals_list):
        partners = super(Partner,
                         self.with_context(_partners_skip_fields_sync=True)
                         )._load_records_create(vals_list)

        # batch up first part of _fields_sync
        # group partners by commercial_partner_id (if not self) and parent_id (if type == contact)
        groups = collections.defaultdict(list)
        for partner, vals in pycompat.izip(partners, vals_list):
            cp_id = None
            if vals.get(
                    'parent_id') and partner.commercial_partner_id != partner:
                cp_id = partner.commercial_partner_id.id

            add_id = None
            if partner.parent_id and partner.type == 'contact':
                add_id = partner.parent_id.id
            groups[(cp_id, add_id)].append(partner.id)

        for (cp_id, add_id), children in groups.items():
            # values from parents (commercial, regular) written to their common children
            to_write = {}
            # commercial fields from commercial partner
            if cp_id:
                to_write = self.browse(cp_id)._update_fields_values(
                    self._commercial_fields())
            # address fields from parent
            if add_id:
                parent = self.browse(add_id)
                for f in self._address_fields():
                    v = parent[f]
                    if v:
                        to_write[f] = v.id if isinstance(
                            v, models.BaseModel) else v
            if to_write:
                self.browse(children).write(to_write)

        # do the second half of _fields_sync the "normal" way
        for partner, vals in pycompat.izip(partners, vals_list):
            partner._children_sync(vals)
            partner._handle_first_contact_creation()
        return partners
Пример #42
0
 def create_rates(self):
     # Let's delete rates that could be messy to have
     self.rate_model.search([]).unlink()
     dates = (self.today, self.yesterday, self.a_week_ago)
     rates = (1.25, 1.00, 1/1.25)
     for date, rate in izip(dates, rates):
         self.rate_model.create({
             'currency_id': self.usd.id,
             'company_id': self.company.id,
             'name': date,
             'rate': rate})
Пример #43
0
 def get_products_price(self, products, quantities, partners, date=False, uom_id=False):
     """ For a given pricelist, return price for products
     Returns: dict{product_id: product price}, in the given pricelist """
     self.ensure_one()
     return {
         product_id: res_tuple[0]
         for product_id, res_tuple in pycompat.items(self._compute_price_rule(
             list(pycompat.izip(products, quantities, partners)),
             date=date,
             uom_id=uom_id
         ))
     }
Пример #44
0
def load_information_from_description_file(module, mod_path=None):
    """
    :param module: The name of the module (sale, purchase, ...)
    :param mod_path: Physical path of module, if not providedThe name of the module (sale, purchase, ...)
    """
    if not mod_path:
        mod_path = get_module_path(module, downloaded=True)
    manifest_file = module_manifest(mod_path)
    if manifest_file:
        # default values for descriptor
        info = {
            'application': False,
            'author': 'Odoo S.A.',
            'auto_install': False,
            'category': 'Uncategorized',
            'depends': [],
            'description': '',
            'icon': get_module_icon(module),
            'installable': True,
            'license': 'LGPL-3',
            'post_load': None,
            'version': '1.0',
            'web': False,
            'sequence': 100,
            'summary': '',
            'website': '',
        }
        info.update(pycompat.izip(
            'depends data demo test init_xml update_xml demo_xml'.split(),
            iter(list, None)))

        f = tools.file_open(manifest_file, mode='rb')
        try:
            info.update(ast.literal_eval(pycompat.to_native(f.read())))
        finally:
            f.close()

        if not info.get('description'):
            readme_path = [opj(mod_path, x) for x in README
                           if os.path.isfile(opj(mod_path, x))]
            if readme_path:
                readme_text = tools.file_open(readme_path[0]).read()
                info['description'] = readme_text

        if 'active' in info:
            # 'active' has been renamed 'auto_install'
            info['auto_install'] = info['active']

        info['version'] = adapt_version(info['version'])
        return info

    _logger.debug('module %s: no manifest file found %s', module, MANIFEST_NAMES)
    return {}
Пример #45
0
    def _website_price(self):
        qty = self._context.get('quantity', 1.0)
        partner = self.env.user.partner_id
        pricelist = self.env['website'].get_current_website().get_current_pricelist()

        context = dict(self._context, pricelist=pricelist.id, partner=partner)
        self2 = self.with_context(context) if self._context != context else self

        ret = self.env.user.has_group('sale.group_show_price_subtotal') and 'total_excluded' or 'total_included'

        for p, p2 in pycompat.izip(self, self2):
            taxes = partner.property_account_position_id.map_tax(p.taxes_id)
            p.website_price = taxes.compute_all(p2.price, pricelist.currency_id, quantity=qty, product=p2, partner=partner)[ret]
            p.website_public_price = taxes.compute_all(p2.lst_price, quantity=qty, product=p2, partner=partner)[ret]
Пример #46
0
 def _inverse_display_name(self):
     names = self.display_name.split('/')
     # determine sequence of categories
     categories = []
     for name in names[:-1]:
         category = self.search([('name', 'ilike', name.strip())])
         categories.append(category[0])
     categories.append(self)
     # assign parents following sequence
     for parent, child in pycompat.izip(categories, categories[1:]):
         if parent and child:
             child.parent = parent
     # assign name of last category, and reassign display_name (to normalize it)
     self.name = names[-1].strip()
Пример #47
0
 def _are_archs_equal(self, arch1, arch2):
     # Note that comparing the strings would not be ok as attributes order
     # must not be relevant
     if arch1.tag != arch2.tag:
         return False
     if arch1.text != arch2.text:
         return False
     if arch1.tail != arch2.tail:
         return False
     if arch1.attrib != arch2.attrib:
         return False
     if len(arch1) != len(arch2):
         return False
     return all(self._are_archs_equal(arch1, arch2) for arch1, arch2 in pycompat.izip(arch1, arch2))
Пример #48
0
    def _remove_reified_groups(self, values):
        """ return `values` without reified group fields """
        add, rem = [], []
        values1 = {}

        for key, val in values.items():
            if is_boolean_group(key):
                (add if val else rem).append(get_boolean_group(key))
            elif is_selection_groups(key):
                rem += get_selection_groups(key)
                if val:
                    add.append(val)
            else:
                values1[key] = val

        if 'groups_id' not in values and (add or rem):
            # remove group ids in `rem` and add group ids in `add`
            values1['groups_id'] = list(itertools.chain(
                pycompat.izip(repeat(3), rem),
                pycompat.izip(repeat(4), add)
            ))

        return values1
Пример #49
0
 def create(self, vals_list):
     for vals in vals_list:
         if vals.get('website'):
             vals['website'] = self._clean_website(vals['website'])
         if vals.get('parent_id'):
             vals['company_name'] = False
         # compute default image in create, because computing gravatar in the onchange
         # cannot be easily performed if default images are in the way
         if not vals.get('image'):
             vals['image'] = self._get_default_image(vals.get('type'), vals.get('is_company'), vals.get('parent_id'))
         tools.image_resize_images(vals, sizes={'image': (1024, None)})
     partners = super(Partner, self).create(vals_list)
     for partner, vals in pycompat.izip(partners, vals_list):
         partner._fields_sync(vals)
         partner._handle_first_contact_creation()
     return partners
Пример #50
0
 def test_read_group_without_name_get(self):
     model = self.env['test_performance.base']
     expected = self.expected_read_group()
     # use read_group and check the expected result
     with self.assertQueryCount(__system__=1, demo=1):
         model.invalidate_cache()
         result = model.read_group([], ['partner_id', 'value'], ['partner_id'])
         self.assertEqual(len(result), len(expected))
         for res, exp in pycompat.izip(result, expected):
             self.assertEqual(res['__domain'], exp['__domain'])
             self.assertEqual(res['partner_id'][0], exp['partner_id'][0])
             self.assertEqual(res['partner_id_count'], exp['partner_id_count'])
             self.assertEqual(res['value'], exp['value'])
     # now serialize to json, which should force evaluation
     with self.assertQueryCount(__system__=1, demo=1):
         json.dumps(result)
Пример #51
0
    def create(self, values):
        """ To avoid crash during import due to unique email, return the existing records if any """
        sql = '''SELECT id, email FROM mail_blacklist
                WHERE LOWER(email) = any (array[%s])
                ''' % (', '.join(['%s'] * len(values)))
        params = [value['email'].lower() for value in values]
        self._cr.execute(sql, params)
        records = self._cr.fetchall()

        bl_ids = bl_emails = []
        if records:
            bl_ids, bl_emails = list(izip(*records))
        non_blacklisted_records = [value for value in values if value['email'] not in bl_emails]

        # TODO DBE Fixme : reorder ids according to incoming ids.
        results = super(MailBlackList, self).create(non_blacklisted_records)
        return self.env['mail.blacklist'].browse(bl_ids) | results
Пример #52
0
Файл: main.py Проект: 10537/odoo
    def get_attribute_value_ids(self, product):
        res = super(WebsiteSale, self).get_attribute_value_ids(product)
        variant_ids = [r[0] for r in res]
        # recordsets conserve the order
        for r, variant in izip(res, request.env['product.product'].sudo().browse(variant_ids)):
            r.extend([{
                'virtual_available': variant.virtual_available,
                'product_type': variant.type,
                'inventory_availability': variant.inventory_availability,
                'available_threshold': variant.available_threshold,
                'custom_message': variant.custom_message,
                'product_template': variant.product_tmpl_id.id,
                'cart_qty': variant.cart_qty,
                'uom_name': variant.uom_id.name,
            }])

        return res
Пример #53
0
    def _website_price(self):
        qty = self._context.get('quantity', 1.0)
        partner = self.env.user.partner_id
        current_website = self.env['website'].get_current_website()
        pricelist = current_website.get_current_pricelist()
        company_id = current_website.company_id

        context = dict(self._context, pricelist=pricelist.id, partner=partner)
        self2 = self.with_context(context) if self._context != context else self

        ret = self.env.user.has_group('sale.group_show_price_subtotal') and 'total_excluded' or 'total_included'

        for p, p2 in pycompat.izip(self, self2):
            taxes = partner.property_account_position_id.map_tax(p.taxes_id.filtered(lambda x: x.company_id == company_id))
            p.website_price = taxes.compute_all(p2.price, pricelist.currency_id, quantity=qty, product=p2, partner=partner)[ret]
            price_without_pricelist = taxes.compute_all(p.list_price, pricelist.currency_id)[ret]
            p.website_price_difference = False if float_is_zero(price_without_pricelist - p.website_price, precision_rounding=pricelist.currency_id.rounding) else True
            p.website_public_price = taxes.compute_all(p2.lst_price, quantity=qty, product=p2, partner=partner)[ret]
Пример #54
0
 def test_spaces(self):
     """ Create translations where value has surrounding spaces. """
     archf = '<form string="%s"><div>%s</div><div>%s</div></form>'
     terms_en = ('Knife', 'Fork', 'Spoon')
     terms_fr = (' Couteau', 'Fourchette ', ' Cuiller ')
     view0 = self.env['ir.ui.view'].create({
         'name': 'test',
         'model': 'res.partner',
         'arch': archf % terms_en,
     })
     for src, value in list(pycompat.izip(terms_en, terms_fr)):
         self.env['ir.translation'].create({
             'type': 'model',
             'name': 'ir.ui.view,arch_db',
             'lang': 'fr_FR',
             'res_id': view0.id,
             'src': src,
             'value': value,
         })
Пример #55
0
    def test_copy(self):
        """ Create a simple view, fill in translations, and copy it. """
        env_en = self.env(context={})
        env_fr = self.env(context={'lang': 'fr_FR'})

        archf = '<form string="%s"><div>%s</div><div>%s</div></form>'
        terms_en = ('Knife', 'Fork', 'Spoon')
        terms_fr = ('Couteau', 'Fourchette', 'Cuiller')
        view0 = self.env['ir.ui.view'].create({
            'name': 'test',
            'model': 'res.partner',
            'arch': archf % terms_en,
        })
        for src, value in list(pycompat.izip(terms_en, terms_fr)):
            self.env['ir.translation'].create({
                'type': 'model',
                'name': 'ir.ui.view,arch_db',
                'lang': 'fr_FR',
                'res_id': view0.id,
                'src': src,
                'value': value,
            })

        # check translated field
        self.assertEqual(view0.with_env(env_en).arch_db, archf % terms_en)
        self.assertEqual(view0.with_env(env_fr).arch_db, archf % terms_fr)

        # copy without lang
        view1 = view0.with_env(env_en).copy({})
        self.assertEqual(view1.with_env(env_en).arch_db, archf % terms_en)
        self.assertEqual(view1.with_env(env_fr).arch_db, archf % terms_fr)

        # copy with lang='fr_FR'
        view2 = view0.with_env(env_fr).copy({})
        self.assertEqual(view2.with_env(env_en).arch_db, archf % terms_en)
        self.assertEqual(view2.with_env(env_fr).arch_db, archf % terms_fr)

        # copy with lang='fr_FR' and translate=html_translate
        self.patch(type(self.env['ir.ui.view']).arch_db, 'translate', html_translate)
        view3 = view0.with_env(env_fr).copy({})
        self.assertEqual(view3.with_env(env_en).arch_db, archf % terms_en)
        self.assertEqual(view3.with_env(env_fr).arch_db, archf % terms_fr)
Пример #56
0
    def test_create_multi(self):
        """ create for multiple records """
        # assumption: 'res.bank' does not override 'create'
        vals_list = [{'name': name} for name in ('Foo', 'Bar', 'Baz')]
        vals_list[0]['email'] = '*****@*****.**'
        for vals in vals_list:
            record = self.env['res.bank'].create(vals)
            self.assertEqual(len(record), 1)
            self.assertEqual(record.name, vals['name'])
            self.assertEqual(record.email, vals.get('email', False))

        records = self.env['res.bank'].create([])
        self.assertFalse(records)

        records = self.env['res.bank'].create(vals_list)
        self.assertEqual(len(records), len(vals_list))
        for record, vals in pycompat.izip(records, vals_list):
            self.assertEqual(record.name, vals['name'])
            self.assertEqual(record.email, vals.get('email', False))

        # create countries and states
        vals_list = [{
            'name': 'Foo',
            'state_ids': [
                (0, 0, {'name': 'North Foo', 'code': 'NF'}),
                (0, 0, {'name': 'South Foo', 'code': 'SF'}),
                (0, 0, {'name': 'West Foo', 'code': 'WF'}),
                (0, 0, {'name': 'East Foo', 'code': 'EF'}),
            ],
        }, {
            'name': 'Bar',
            'state_ids': [
                (0, 0, {'name': 'North Bar', 'code': 'NB'}),
                (0, 0, {'name': 'South Bar', 'code': 'SB'}),
            ],
        }]
        foo, bar = self.env['res.country'].create(vals_list)
        self.assertEqual(foo.name, 'Foo')
        self.assertCountEqual(foo.mapped('state_ids.code'), ['NF', 'SF', 'WF', 'EF'])
        self.assertEqual(bar.name, 'Bar')
        self.assertCountEqual(bar.mapped('state_ids.code'), ['NB', 'SB'])
Пример #57
0
    def test_invoice_with_discount(self):
        """ Test invoice with a discount and check discount applied on both SO lines and an invoice lines """
        # Update discount and delivered quantity on SO lines
        self.sol_prod_order.write({'discount': 20.0})
        self.sol_serv_deliver.write({'discount': 20.0, 'qty_delivered': 4.0})
        self.sol_serv_order.write({'discount': -10.0})
        self.sol_prod_deliver.write({'qty_delivered': 2.0})

        for line in self.sale_order.order_line.filtered(lambda l: l.discount):
            product_price = line.price_unit * line.product_uom_qty
            self.assertEquals(line.discount, (product_price - line.price_subtotal) / product_price * 100, 'Discount should be applied on order line')

        # lines are in draft
        for line in self.sale_order.order_line:
            self.assertTrue(float_is_zero(line.untaxed_amount_to_invoice, precision_digits=2), "The amount to invoice should be zero, as the line is in draf state")
            self.assertTrue(float_is_zero(line.untaxed_amount_invoiced, precision_digits=2), "The invoiced amount should be zero, as the line is in draft state")

        self.sale_order.action_confirm()

        for line in self.sale_order.order_line:
            self.assertTrue(float_is_zero(line.untaxed_amount_invoiced, precision_digits=2), "The invoiced amount should be zero, as the line is in draft state")

        self.assertEquals(self.sol_serv_order.untaxed_amount_to_invoice, 297, "The untaxed amount to invoice is wrong")
        self.assertEquals(self.sol_serv_deliver.untaxed_amount_to_invoice, self.sol_serv_deliver.qty_delivered * self.sol_serv_deliver.price_reduce, "The untaxed amount to invoice should be qty deli * price reduce, so 4 * (180 - 36)")
        self.assertEquals(self.sol_prod_deliver.untaxed_amount_to_invoice, 140, "The untaxed amount to invoice should be qty deli * price reduce, so 4 * (180 - 36)")

        # Let's do an invoice with invoiceable lines
        payment = self.env['sale.advance.payment.inv'].with_context(self.context).create({
            'advance_payment_method': 'delivered'
        })
        payment.create_invoices()
        invoice = self.sale_order.invoice_ids[0]
        invoice.action_invoice_open()

        # Check discount appeared on both SO lines and invoice lines
        for line, inv_line in pycompat.izip(self.sale_order.order_line, invoice.invoice_line_ids):
            self.assertEquals(line.discount, inv_line.discount, 'Discount on lines of order and invoice should be same')
Пример #58
0
 def _compute_location_description(self):
     for operation, operation_sudo in izip(self, self.sudo()):
         operation.from_loc = '%s%s' % (operation_sudo.location_id.name, operation.product_id and operation_sudo.package_id.name or '')
         operation.to_loc = '%s%s' % (operation_sudo.location_dest_id.name, operation_sudo.result_package_id.name or '')
Пример #59
0
    def test_rounding_03(self):
        """ Test rounding methods with 3 digits. """

        def try_round(amount, expected, digits=3, method='HALF-UP'):
            value = float_round(amount, precision_digits=digits, rounding_method=method)
            result = float_repr(value, precision_digits=digits)
            self.assertEqual(result, expected, 'Rounding error: got %s, expected %s' % (result, expected))

        try_round(2.6745, '2.675')
        try_round(-2.6745, '-2.675')
        try_round(2.6744, '2.674')
        try_round(-2.6744, '-2.674')
        try_round(0.0004, '0.000')
        try_round(-0.0004, '-0.000')
        try_round(357.4555, '357.456')
        try_round(-357.4555, '-357.456')
        try_round(457.4554, '457.455')
        try_round(-457.4554, '-457.455')

        # Try some rounding value with rounding method UP instead of HALF-UP
        # We use 8.175 because when normalizing 8.175 with precision_digits=3 it gives
        # us 8175,0000000001234 as value, and if not handle correctly the rounding UP
        # value will be incorrect (should be 8,175 and not 8,176)
        try_round(8.175, '8.175', method='UP')
        try_round(8.1751, '8.176', method='UP')
        try_round(-8.175, '-8.175', method='UP')
        try_round(-8.1751, '-8.176', method='UP')
        try_round(-6.000, '-6.000', method='UP')
        try_round(1.8, '2', 0, method='UP')
        try_round(-1.8, '-2', 0, method='UP')

        # Try some rounding value with rounding method DOWN instead of HALF-UP
        # We use 2.425 because when normalizing 2.425 with precision_digits=3 it gives
        # us 2424.9999999999995 as value, and if not handle correctly the rounding DOWN
        # value will be incorrect (should be 2.425 and not 2.424)
        try_round(2.425, '2.425', method='DOWN')
        try_round(2.4249, '2.424', method='DOWN')
        try_round(-2.425, '-2.425', method='DOWN')
        try_round(-2.4249, '-2.424', method='DOWN')
        try_round(-2.500, '-2.500', method='DOWN')
        try_round(1.8, '1', 0, method='DOWN')
        try_round(-1.8, '-1', 0, method='DOWN')

        # Extended float range test, inspired by Cloves Almeida's test on bug #882036.
        fractions = [.0, .015, .01499, .675, .67499, .4555, .4555, .45555]
        expecteds = ['.00', '.02', '.01', '.68', '.67', '.46', '.456', '.4556']
        precisions = [2, 2, 2, 2, 2, 2, 3, 4]
        # Note: max precision for double floats is 53 bits of precision or
        # 17 significant decimal digits
        for magnitude in range(7):
            for frac, exp, prec in pycompat.izip(fractions, expecteds, precisions):
                for sign in [-1,1]:
                    for x in range(0, 10000, 97):
                        n = x * 10 ** magnitude
                        f = sign * (n + frac)
                        f_exp = ('-' if f != 0 and sign == -1 else '') + str(n) + exp
                        try_round(f, f_exp, digits=prec)

        def try_zero(amount, expected):
            self.assertEqual(float_is_zero(amount, precision_digits=3), expected,
                             "Rounding error: %s should be zero!" % amount)

        try_zero(0.0002, True)
        try_zero(-0.0002, True)
        try_zero(0.00034, True)
        try_zero(0.0005, False)
        try_zero(-0.0005, False)
        try_zero(0.0008, False)
        try_zero(-0.0008, False)

        def try_compare(amount1, amount2, expected):
            self.assertEqual(float_compare(amount1, amount2, precision_digits=3), expected,
                             "Rounding error, compare_amounts(%s,%s) should be %s" % (amount1, amount2, expected))

        try_compare(0.0003, 0.0004, 0)
        try_compare(-0.0003, -0.0004, 0)
        try_compare(0.0002, 0.0005, -1)
        try_compare(-0.0002, -0.0005, 1)
        try_compare(0.0009, 0.0004, 1)
        try_compare(-0.0009, -0.0004, -1)
        try_compare(557.4555, 557.4556, 0)
        try_compare(-557.4555, -557.4556, 0)
        try_compare(657.4444, 657.445, -1)
        try_compare(-657.4444, -657.445, 1)

        # Rounding to unusual rounding units (e.g. coin values)
        def try_round(amount, expected, precision_rounding=None, method='HALF-UP'):
            value = float_round(amount, precision_rounding=precision_rounding, rounding_method=method)
            result = float_repr(value, precision_digits=2)
            self.assertEqual(result, expected, 'Rounding error: got %s, expected %s' % (result, expected))

        try_round(-457.4554, '-457.45', precision_rounding=0.05)
        try_round(457.444, '457.50', precision_rounding=0.5)
        try_round(457.3, '455.00', precision_rounding=5)
        try_round(457.5, '460.00', precision_rounding=5)
        try_round(457.1, '456.00', precision_rounding=3)
        try_round(2.5, '2.50', precision_rounding=0.05, method='DOWN')
        try_round(-2.5, '-2.50', precision_rounding=0.05, method='DOWN')