Example #1
0
 def get_cost_amount(self, cr, uid, product, product_qty, context=None):
     price_unit_precision = self.pool['decimal.precision'].precision_get(cr, uid, 'Sale Price')
     if product.is_kit:
         bom_obj = self.pool['mrp.bom']
         amount = 0.0
         for bom in product.bom_lines:
             bom_product_ids = bom_obj.search(cr, uid, [('bom_id', '=', bom.id)], context=context)
             bom_products = bom_obj.browse(cr, uid, bom_product_ids, context)
             for bom_product in bom_products:
                 if not bom_product.product_id.product_tmpl_id.type == 'service':
                     amount += bom_product.product_id.standard_price * bom_product.product_qty
         return rounding(amount * product_qty, 10 ** - price_unit_precision)
     else:
         return rounding(product.standard_price * product_qty, 10 ** - price_unit_precision)
 def get_cost_amount(self, cr, uid, product, product_qty, context=None):
     price_unit_precision = self.pool['decimal.precision'].precision_get(cr, uid, 'Sale Price')
     if product.is_kit:
         bom_obj = self.pool['mrp.bom']
         amount = 0.0
         for bom in product.bom_lines:
             bom_product_ids = bom_obj.search(cr, uid, [('bom_id', '=', bom.id)], context=context)
             bom_products = bom_obj.browse(cr, uid, bom_product_ids)
             for bom_product in bom_products:
                 if not bom_product.product_id.product_tmpl_id.type == 'service':
                     amount += bom_product.product_id.standard_price * bom_product.product_qty
         return rounding(amount * product_qty, 10 ** - price_unit_precision)
     else:
         return rounding(product.standard_price * product_qty, 10 ** - price_unit_precision)
Example #3
0
 def get_cost_amount(self, cr, uid, product, product_qty, context=None):
     price_unit_precision = self.pool["decimal.precision"].precision_get(cr, uid, "Sale Price")
     if product.is_kit:
         bom_obj = self.pool["mrp.bom"]
         amount = 0.0
         for bom in product.bom_lines:
             bom_product_ids = bom_obj.search(cr, uid, [("bom_id", "=", bom.id)])
             bom_products = bom_obj.browse(cr, uid, bom_product_ids)
             for bom_product in bom_products:
                 if not bom_product.product_id.product_tmpl_id.type == "service":
                     amount += bom_product.product_id.standard_price * bom_product.product_qty
         return rounding(amount * product_qty, 10 ** -price_unit_precision)
     else:
         return rounding(product.standard_price * product_qty, 10 ** -price_unit_precision)
Example #4
0
    def split_line(self, cr, uid, ids, context=None):
        '''
        Create a new order line and change the quantity of the old line
        '''
        line_obj = self.pool.get('sale.order.line')

        if not context:
            context = {}

        if isinstance(ids, (int, long)):
            ids = [ids]
        context['keepDateAndDistrib'] = True
        for split in self.browse(cr, uid, ids, context=context):
            # Check if the sum of new line and old line qty is equal to the original qty
            if split.new_line_qty > split.original_qty:
                raise osv.except_osv(_('Error'), _('You cannot have a new quantity greater than the original quantity !'))
            elif split.new_line_qty <= 0.00:
                raise osv.except_osv(_('Error'), _('The new quantity must be positive !'))
            elif split.new_line_qty == split.original_qty:
                raise osv.except_osv(_('Error'), _('The new quantity must be different than the original quantity !'))
            elif split.new_line_qty != rounding(split.new_line_qty, split.sale_line_id.product_uom.rounding):
                raise osv.except_osv(_('Error'), _('The new quantity must be a multiple of %s !') % split.sale_line_id.product_uom.rounding)
            else:
                # Change the qty of the old line
                line_obj.write(cr, uid, [split.sale_line_id.id], {'product_uom_qty': split.original_qty - split.new_line_qty}, context=context)
                # copy data
                so_copy_data = {'is_line_split': True, # UTP-972: Indicate that the line is split
                                'product_uom_qty': split.new_line_qty}
                # following new sequencing policy, we check if resequencing occur (behavior 1).
                # if not (behavior 2), the split line keeps the same line number as original line
                if not line_obj.allow_resequencing(cr, uid, [split.sale_line_id.id], context=context):
                    # set default value for line_number as the same as original line
                    so_copy_data.update({'line_number': split.sale_line_id.line_number})
                # Create the new line
                new_line_id = line_obj.copy(cr, uid, split.sale_line_id.id, so_copy_data, context=context)
                self.infolog(cr, uid, "The FO/IR line id:%s (%s) has been split" % (
                    split.sale_line_id.id,
                    split.sale_line_id.line_number,
                ))

        return {'type': 'ir.actions.act_window_close'}
Example #5
0
    def price_get_multi(self, cr, uid, pricelist_ids, products_by_qty_by_partner, context=None):

        def _create_parent_category_list(id, lst):
            if not id:
                return []
            parent = product_category_tree.get(id)
            if parent:
                lst.append(parent)
                return _create_parent_category_list(parent, lst)
            else:
                return lst
        # _create_parent_category_list

        if context is None:
            context = {}

        date = time.strftime('%Y-%m-%d')
        if 'date' in context:
            date = context['date']

        currency_obj = self.pool.get('res.currency')
        product_obj = self.pool.get('product.product')
        product_category_obj = self.pool.get('product.category')
        product_uom_obj = self.pool.get('product.uom')
        supplierinfo_obj = self.pool.get('product.supplierinfo')
        price_type_obj = self.pool.get('product.price.type')
        product_pricelist_version_obj = self.pool.get('product.pricelist.version')

        # product.pricelist.version:
        if pricelist_ids:
            pricelist_version_ids = pricelist_ids
        else:
            # all pricelists:
            pricelist_version_ids = self.pool.get('product.pricelist').search(cr, uid, [], context=context)

        pricelist_version_ids = list(set(pricelist_version_ids))
        plversions_search_args = [
            ('pricelist_id', 'in', pricelist_version_ids),
            '|',
            ('date_start', '=', False),
            ('date_start', '<=', date),
            '|',
            ('date_end', '=', False),
            ('date_end', '>=', date),
        ]

        plversion_ids = product_pricelist_version_obj.search(cr, uid, plversions_search_args)
        if len(pricelist_version_ids) != len(plversion_ids):
            msg = "At least one pricelist has no active version !\nPlease create or activate one."
            raise osv.except_osv(_('Warning !'), _(msg))

        # product.product:
        product_ids = [i[0] for i in products_by_qty_by_partner]
        #products = dict([(item['id'], item) for item in product_obj.read(cr, uid, product_ids, ['categ_id', 'product_tmpl_id', 'uos_id', 'uom_id'])])
        products = product_obj.browse(cr, uid, product_ids, context=context)
        products_dict = dict([(item.id, item) for item in products])

        # product.category:
        product_category_ids = product_category_obj.search(cr, uid, [])
        product_categories = product_category_obj.read(cr, uid, product_category_ids, ['parent_id'])
        product_category_tree = dict([(item['id'], item['parent_id'][0]) for item in product_categories if item['parent_id']])

        results = {}
        for product_id, qty, partner in products_by_qty_by_partner:
            for pricelist_id in pricelist_version_ids:
                price = False

                tmpl_id = products_dict[product_id].product_tmpl_id and products_dict[product_id].product_tmpl_id.id or False

                categ_id = products_dict[product_id].categ_id and products_dict[product_id].categ_id.id or False
                categ_ids = _create_parent_category_list(categ_id, [categ_id])
                if categ_ids:
                    categ_where = '(categ_id IN (' + ','.join(map(str, categ_ids)) + '))'
                else:
                    categ_where = '(categ_id IS NULL)'

                cr.execute(
                    'SELECT i.*, pl.currency_id '
                    'FROM product_pricelist_item AS i, '
                        'product_pricelist_version AS v, product_pricelist AS pl '
                    'WHERE (product_tmpl_id IS NULL OR product_tmpl_id = %s) '
                        'AND (product_id IS NULL OR product_id = %s) '
                        'AND (' + categ_where + ' OR (categ_id IS NULL)) '
                        'AND price_version_id = %s '
                        'AND (min_quantity IS NULL OR min_quantity <= %s) '
                        'AND i.price_version_id = v.id AND v.pricelist_id = pl.id '
                    'ORDER BY sequence',
                    (tmpl_id, product_id, plversion_ids[0], qty))
                res1 = cr.dictfetchall()
                uom_price_already_computed = False
                for res in res1:
                    if res:
                        if res['base'] == -1:
                            if not res['base_pricelist_id']:
                                price = 0.0
                            else:
                                price_tmp = self.price_get(cr, uid,
                                        [res['base_pricelist_id']], product_id,
                                        qty, context=context)[res['base_pricelist_id']]
                                ptype_src = self.browse(cr, uid, res['base_pricelist_id']).currency_id.id
                                price = currency_obj.compute(cr, uid, ptype_src, res['currency_id'], price_tmp, round=False)
                        elif res['base'] == -2:
                            # this section could be improved by moving the queries outside the loop:
                            where = []
                            if partner:
                                where = [('name', '=', partner) ]
                            sinfo = supplierinfo_obj.search(cr, uid,
                                    [('product_id', '=', tmpl_id)] + where)
                            price = 0.0
                            if sinfo:
                                qty_in_product_uom = qty
                                product_default_uom = product_obj.read(cr, uid, [tmpl_id], ['uom_id'])[0]['uom_id'][0]
                                seller_uom = supplierinfo_obj.read(cr, uid, sinfo, ['product_uom'])[0]['product_uom'][0]
                                if seller_uom and product_default_uom and product_default_uom != seller_uom:
                                    uom_price_already_computed = True
                                    qty_in_product_uom = product_uom_obj._compute_qty(cr, uid, product_default_uom, qty, to_uom_id=seller_uom)
                                cr.execute('SELECT * ' \
                                        'FROM pricelist_partnerinfo ' \
                                        'WHERE suppinfo_id IN %s' \
                                            'AND min_quantity <= %s ' \
                                        'ORDER BY min_quantity DESC LIMIT 1', (tuple(sinfo),qty_in_product_uom,))
                                res2 = cr.dictfetchone()
                                if res2:
                                    price = res2['price']
                        #This is added by product_pricelist_fixed_price
                        elif res['base'] == -3:
                            price = res['fixed_price']
                        #End
                        else:
                            price_type = price_type_obj.browse(cr, uid, int(res['base']))
                            price = currency_obj.compute(cr, uid,
                                    price_type.currency_id.id, res['currency_id'],
                                    product_obj.price_get(cr, uid, [product_id],
                                        price_type.field,context=context)[product_id], round=False, context=context)

                        if price:
                            price_limit = price

                            price = price * (1.0+(res['price_discount'] or 0.0))
                            price = rounding(price, res['price_round'])
                            price += (res['price_surcharge'] or 0.0)
                            if res['price_min_margin']:
                                price = max(price, price_limit+res['price_min_margin'])
                            if res['price_max_margin']:
                                price = min(price, price_limit+res['price_max_margin'])
                            break

                    else:
                        # False means no valid line found ! But we may not raise an
                        # exception here because it breaks the search
                        price = False

                if price:
                    if 'uom' in context and not uom_price_already_computed:
                        product = products_dict[product_id]
                        uom = product.uos_id or product.uom_id
                        price = self.pool.get('product.uom')._compute_price(cr, uid, uom.id, price, context['uom'])

                if results.get(product_id):
                    results[product_id][pricelist_id] = price
                else:
                    results[product_id] = {pricelist_id: price}

        return results
Example #6
0
    def split_line(self, cr, uid, ids, context=None):
        '''
        Create a new order line and change the quantity of the old line
        '''
        # objects
        wf_service = netsvc.LocalService("workflow")
        po_line_obj = self.pool.get('purchase.order.line')
        so_line_obj = self.pool.get('sale.order.line')
        so_obj = self.pool.get('sale.order')
        move_obj = self.pool.get('stock.move')
        proc_obj = self.pool.get('procurement.order')

        # Some verifications
        if context is None:
            context = {}
        if isinstance(ids, (int, long)):
            ids = [ids]

        context.update({'split_line': True})
        context.update({'keepDateAndDistrib': True})

        for split in self.browse(cr, uid, ids, context=context):
            # Check if the sum of new line and old line qty is equal to the original qty
            if split.new_line_qty > split.original_qty:
                raise osv.except_osv(_('Error'), _('You cannot have a new quantity greater than the original quantity !'))
            elif split.new_line_qty <= 0.00:
                raise osv.except_osv(_('Error'), _('The new quantity must be positive !'))
            elif split.new_line_qty == split.original_qty:
                raise osv.except_osv(_('Error'), _('The new quantity must be different than the original quantity !'))
            elif split.new_line_qty != rounding(split.new_line_qty, split.purchase_line_id.product_uom.rounding):
                raise osv.except_osv(_('Error'), _('The new quantity must be a multiple of %s !') % split.purchase_line_id.product_uom.rounding)
            else:
                self.infolog(cr, uid, "The PO line id:%s (line number: %s) has been split" % (
                    split.purchase_line_id.id, split.purchase_line_id.line_number,
                ))

                # Change the qty of the old line
                po_line_obj.write(cr, uid, [split.purchase_line_id.id], {'product_qty': split.original_qty - split.new_line_qty,
                                                                         'price_unit': split.purchase_line_id.price_unit,}, context=context)
                # Change the qty on the linked procurement order
                #if split.purchase_line_id.procurement_id:
                #    proc_obj.write(cr, uid, [split.purchase_line_id.procurement_id.id], {'product_qty': split.original_qty - split.new_line_qty})

                # we treat two different cases
                # 1) the check box impact corresponding Fo is checked
                #    we create a Fo line by copying related Fo line. we then execute procurement creation function, and process the procurement
                #    the merge into the actual Po is forced
                # if Internal Request, we do not update corresponding Internal Request
                link_wiz = split.corresponding_so_line_id_split_po_line_wizard
                external_ir = link_wiz and link_wiz.order_id and (not link_wiz.order_id.procurement_request or link_wiz.order_id.location_requestor_id.usage == 'customer')
                if split.corresponding_so_line_id_split_po_line_wizard and split.impact_so_split_po_line_wizard and external_ir:
                    # copy the original sale order line, reset po_cft to 'po' (we don't want a new tender if any)
                    so_copy_data = {'line_number': split.corresponding_so_line_id_split_po_line_wizard.line_number, # the Fo is not draft anyway, following sequencing policy, split Fo line maintains original one
                                    'po_cft': 'po',
                                    'product_uom_qty': split.new_line_qty,
                                    'product_uos_qty': split.new_line_qty,
                                    'so_back_update_dest_po_id_sale_order_line': split.purchase_line_id.order_id.id,
                                    'so_back_update_dest_pol_id_sale_order_line': split.purchase_line_id.id,
                                    }
                    new_so_line_id = so_line_obj.copy(cr, uid, split.corresponding_so_line_id_split_po_line_wizard.id, so_copy_data, context=dict(context, keepDateAndDistrib=True))
                    so_line_obj.write(cr, uid, new_so_line_id, {
                        'supplier': split.corresponding_so_line_id_split_po_line_wizard.supplier.id,
                        'type': 'make_to_order',
                        'is_line_split': True,
                    }, context=context)
                    # change the initial qty on the initial FO line
                    so_line_obj.write(cr, uid, split.corresponding_so_line_id_split_po_line_wizard.id, {
                        'product_uom_qty': split.original_qty - split.new_line_qty,
                        'product_uos_qty': split.original_qty - split.new_line_qty,
                    }, context=dict(context, keepDateAndDistrib=True))
                    # call the new procurement creation method
                    so_obj.action_ship_proc_create(cr, uid, [split.corresponding_so_id_split_po_line_wizard.id], context=context)
                    # run the procurement, the make_po function detects the link to original po
                    # and force merge the line to this po (even if it is not draft anymore)
                    # run the procurement, the make_po function detects the link to original po
                    # and force merge the line to this po (even if it is not draft anymore)
                    new_data_so = so_line_obj.read(cr, uid, [new_so_line_id], ['procurement_id', 'line_number', 'sync_order_line_db_id'], context=context)
                    new_proc_id = new_data_so[0]['procurement_id'][0]

                    if external_ir and split.purchase_line_id and split.purchase_line_id.move_dest_id:
                        move = move_obj.browse(cr, uid, split.purchase_line_id.move_dest_id.id, context=context)
                        proc_move_id = proc_obj.read(cr, uid, new_proc_id, ['move_id'], context=context)['move_id'][0]
                        new_move_id = move.id

                        if move.product_qty > split.new_line_qty:
                            new_move_id = move_obj.copy(cr, uid, move.id, {'product_qty': split.new_line_qty,
                                                                           'product_uos_qty': split.new_line_qty,
                                                                           'line_number': new_data_so[0]['line_number'],
                                                                           'sale_line_id': new_so_line_id}, context=context)
                            move_obj.action_confirm(cr, uid, [new_move_id], context=context)

                            move_obj.write(cr, uid, [move.id], {'product_qty': move.product_qty - split.new_line_qty,
                                                                'product_uos_qty': move.product_qty - split.new_line_qty}, context=context)
                        else:
                            # No update of OUT when IN is received to avoid more qty than expected
                            move_obj.write(cr, uid, [move.id], {'processed_stock_move': True}, context=context)

                        move_obj.write(cr, uid, proc_move_id, {'state': 'draft'}, context=context)
                        proc_obj.write(cr, uid, [new_proc_id], {'close_move': False, 'move_id': new_move_id}, context=context)
                        move_obj.unlink(cr, uid, proc_move_id, context=context)

                    if link_wiz.order_id.partner_id.partner_type != 'external':
                        self.pool.get('sync.sale.order.line.split').create(cr, uid, {
                            'partner_id': link_wiz.order_id.partner_id.id,
                            'old_sync_order_line_db_id': link_wiz.sync_order_line_db_id,
                            'new_sync_order_line_db_id': new_data_so[0]['sync_order_line_db_id'],
                            'new_line_qty': split.new_line_qty,
                            'old_line_qty': split.original_qty,
                        }, context=context)

                    wf_service.trg_validate(uid, 'procurement.order', new_proc_id, 'button_check', cr)
                    new_po_ids = po_line_obj.search(cr, uid, [('procurement_id', '=', new_proc_id)], context=context)
                    if context.get('split_sync_order_line_db_id'):
                        po_line_obj.write(cr, uid, new_po_ids, {'sync_order_line_db_id': context.get('split_sync_order_line_db_id')}, context=context)
                    # if original po line is confirmed, we action_confirm new line
                    if split.purchase_line_id.state == 'confirmed':
                        # the correct line number according to new line number policy is set in po_line_values_hook of order_line_number/order_line_number.py/procurement_order
                        po_line_obj.action_confirm(cr, uid, new_po_ids, context=context)
                        if context.get('from_simu_screen'):
                            return new_po_ids[0]
                else:
                    # 2) the check box impact corresponding Fo is not check or does not apply (po from scratch or from replenishment),
                    #    a new line is simply created
                    # Create the new line
                    move_dest_id = split.purchase_line_id.move_dest_id and split.purchase_line_id.move_dest_id.id or False
                    sale_line_id = split.corresponding_so_line_id_split_po_line_wizard and split.corresponding_so_line_id_split_po_line_wizard.id or False
                    proc_id = split.corresponding_so_line_id_split_po_line_wizard.procurement_id and split.corresponding_so_line_id_split_po_line_wizard.procurement_id.id or False
                    if split.purchase_line_id.procurement_id and move_dest_id and not link_wiz.order_id.procurement_request:
                        new_dest_id = move_obj.copy(cr, uid, move_dest_id, {'product_qty': split.new_line_qty}, context=context)
                        move_obj.action_confirm(cr, uid, [new_dest_id])
                        move_obj.write(cr, uid, [move_dest_id], {'product_qty': split.original_qty - split.new_line_qty}, context=context)
                        move_dest_id = new_dest_id

                        new_proc_id = proc_obj.copy(cr, uid, split.purchase_line_id.procurement_id.id, {
                            'product_qty': split.new_line_qty,
                            'purchase_id': split.purchase_line_id.order_id.id,
                            'move_id': new_dest_id,
                            'from_splitted_po_line': True,
                        }, context=context)
                        proc_obj.write(cr, uid, [split.purchase_line_id.procurement_id.id], {
                            'product_qty': split.original_qty - split.new_line_qty,
                        }, context=context)
                        wf_service.trg_validate(uid, 'procurement.order', new_proc_id, 'button_confirm', cr)
                        wf_service.trg_validate(uid, 'procurement.order', new_proc_id, 'button_check', cr)
                        proc_id = new_proc_id

                    po_copy_data = {'is_line_split': True, # UTP-972: Indicate only that the line is a split one
                                    'change_price_manually': split.purchase_line_id.change_price_manually,
                                    'price_unit': split.purchase_line_id.price_unit,
                                    'move_dest_id': move_dest_id,
                                    'sale_line_id': sale_line_id,
                                    'procurement_id': proc_id,
                                    'product_qty': split.new_line_qty}
                    # following new sequencing policy, we check if resequencing occur (behavior 1).
                    # if not (behavior 2), the split line keeps the same line number as original line
                    if not po_line_obj.allow_resequencing(cr, uid, [split.purchase_line_id.id], context=context):
                        # set default value for line_number as the same as original line
                        po_copy_data.update({'line_number': split.purchase_line_id.line_number})

                    new_line_ids = []
                    if split.purchase_line_id.procurement_id and move_dest_id and not link_wiz.order_id.procurement_request:
                        new_line_ids = po_line_obj.search(cr, uid, [('procurement_id', '=', new_proc_id)], context=context)
                        po_line_obj.write(cr, uid, new_line_ids, po_copy_data, context=context)
                    else:
                        # copy original line
                        new_line_id = po_line_obj.copy(cr, uid, split.purchase_line_id.id, po_copy_data, context=context)
                        new_line_ids.append(new_line_id)
                    # if original po line is confirmed, we action_confirm new line
                    if split.purchase_line_id.state == 'confirmed':
                        po_line_obj.action_confirm(cr, uid, new_line_ids, context=context)

                    if context.get('from_simu_screen'):
                        return new_line_ids[0]

        if context.get('from_simu_screen'):
            return False

        return {'type': 'ir.actions.act_window_close'}
    def update_or_create_line(self, cr, uid, values, context=None):
        '''
            values = {
                'name': expense_line.name,
                'product': expense_line.product_id,
                'product_qty': expense_line.unit_quantity,
                'product_uom': expense_line.uom_id,  # Optional, is not required.
                'account_id': expense_line.analytic_account.id,
                'unit_amount': values.get('unit_amount', False),  # Optional, is not required
                'date': expense_line.date_value + ' 00:00:00',
                'ref': hr_expense.name,
                'origin_document': expense_line
            }
        '''
        
        journals = {
            'hr.expense.line': {'journal': 'expense_journal_id', 'name': _('Expense Journal')},
            'stock.move': {'journal': 'delivery_note_journal_id', 'name': _('Delivery Note Journal')}
        }
        
        if values.get('account_id', False):
            user = self.pool['res.users'].browse(cr, uid, uid, context)
            
            journal = getattr(user.company_id, journals[values['origin_document']._name]['journal'])
            if journal:
                journal_id = journal.id
            else:
                raise orm.except_orm('Error', _('{journal} is not defined for this company').format(journal=journals[values['origin_document']._name]['name']))
            
            product_qty = values.get('product_qty', 1)
            price_unit_precision = self.pool['decimal.precision'].precision_get(cr, uid, 'Sale Price')
            
            if values.get('unit_amount', False):
                amount = rounding(values['unit_amount'] * product_qty, 10 ** - price_unit_precision)
            elif values.get('product', False):
                amount = self.get_cost_amount(cr, uid, values['product'], product_qty, context)
            else:
                return False
            
            if values.get('product', False):
                general_account_id = values['product'].product_tmpl_id.property_account_expense.id
                
                if not general_account_id:
                    general_account_id = values['product'].categ_id.property_account_expense_categ.id
                if not general_account_id:
                    raise orm.except_orm(_('Error!'),
                                         _('''There is no expense account defined
                                            for this product: "{0}" (id:{1})''').format(values['product'].name, values['product'].id,))
            else:
                general_account_id = False
            
            line_date = datetime.datetime.strptime(values['date'], DEFAULT_SERVER_DATETIME_FORMAT)
            line_date = datetime.date(year=line_date.year, month=line_date.month, day=line_date.day)
            
            analytic_line_ids = self.search(cr, uid, [('origin_document', '=', '{model}, {document_id}'.format(model=values['origin_document']._name, document_id=values['origin_document'].id))], context=context)

            if analytic_line_ids:
                return self.write(cr, uid, analytic_line_ids, {
                    'amount': -amount,
                    'user_id': uid,
                    'name': values['name'],
                    'unit_amount': product_qty,  # What a strange idea to call product_qty unit_amount!!!
                    'date': line_date,
                    'company_id': user.company_id.id,
                    'account_id': values['account_id'],
                    'general_account_id': general_account_id,
                    'product_id': values['product'].id,
                    'product_uom_id': values.get('product_uom', values['product'].uom_id.id),
                    'journal_id': journal_id,
                    'amount_currency': 0.0,
                    'ref': values.get('ref', False),
                    'origin_document': '{model}, {document_id}'.format(model=values['origin_document']._name, document_id=values['origin_document'].id)
                }, context)
            else:
                return self.create(cr, uid, {
                    'amount': -amount,
                    'user_id': uid,
                    'name': values['name'],
                    'unit_amount': product_qty,
                    'date': line_date,
                    'company_id': user.company_id.id,
                    'account_id': values['account_id'],
                    'general_account_id': general_account_id,
                    'product_id': values['product'].id,
                    'product_uom_id': values.get('product_uom', values['product'].uom_id.id),
                    'journal_id': journal_id,
                    'amount_currency': 0.0,
                    'ref': values.get('ref', False),
                    'origin_document': '{model}, {document_id}'.format(model=values['origin_document']._name, document_id=values['origin_document'].id)
                }, context)
        else:
            return False
Example #8
0
    def price_get_multi(self,
                        cr,
                        uid,
                        pricelist_ids,
                        products_by_qty_by_partner,
                        context=None):
        """multi products 'price_get'.
           @param pricelist_ids:
           @param products_by_qty:
           @param partner:
           @param context: {
             'date': Date of the pricelist (%Y-%m-%d),}
           @return: a dict of dict with product_id as key and a dict 'price by pricelist' as value
        """
        def _create_parent_category_list(id, lst):
            if not id:
                return []
            parent = product_category_tree.get(id)
            if parent:
                lst.append(parent)
                return _create_parent_category_list(parent, lst)
            else:
                return lst

        # _create_parent_category_list

        if context is None:
            context = {}

        date = time.strftime('%Y-%m-%d')
        if 'date' in context:
            date = context['date']

        currency_obj = self.pool.get('res.currency')
        product_obj = self.pool.get('product.product')
        product_category_obj = self.pool.get('product.category')
        product_uom_obj = self.pool.get('product.uom')
        supplierinfo_obj = self.pool.get('product.supplierinfo')
        price_type_obj = self.pool.get('product.price.type')

        # product.pricelist.version:
        if not pricelist_ids:
            pricelist_ids = self.pool.get('product.pricelist').search(
                cr, uid, [], context=context)

        pricelist_version_ids = self.pool.get(
            'product.pricelist.version').search(cr, uid, [
                ('pricelist_id', 'in', pricelist_ids),
                '|',
                ('date_start', '=', False),
                ('date_start', '<=', date),
                '|',
                ('date_end', '=', False),
                ('date_end', '>=', date),
            ])
        if len(pricelist_ids) != len(pricelist_version_ids):
            raise osv.except_osv(
                _('Warning!'),
                _("At least one pricelist has no active version !\nPlease create or activate one."
                  ))

        # product.product:
        product_ids = [i[0] for i in products_by_qty_by_partner]
        products = product_obj.browse(cr, uid, product_ids, context=context)
        products_dict = dict([(item.id, item) for item in products])

        # product.category:
        product_category_ids = product_category_obj.search(cr, uid, [])
        product_categories = product_category_obj.read(cr, uid,
                                                       product_category_ids,
                                                       ['parent_id'])
        product_category_tree = dict([(item['id'], item['parent_id'][0])
                                      for item in product_categories
                                      if item['parent_id']])

        results = {}
        for product_id, qty, partner in products_by_qty_by_partner:
            for pricelist_id in pricelist_ids:
                price = False

                tmpl_id = products_dict[
                    product_id].product_tmpl_id and products_dict[
                        product_id].product_tmpl_id.id or False

                categ_id = products_dict[product_id].categ_id and products_dict[
                    product_id].categ_id.id or False
                categ_ids = _create_parent_category_list(categ_id, [categ_id])
                if categ_ids:
                    categ_where = '(categ_id IN (' + ','.join(
                        map(str, categ_ids)) + '))'
                else:
                    categ_where = '(categ_id IS NULL)'

                if partner:
                    partner_where = 'base <> -2 OR %s IN (SELECT name FROM product_supplierinfo WHERE product_id = %s) '
                    partner_args = (partner, tmpl_id)
                else:
                    partner_where = 'base <> -2 '
                    partner_args = ()

                pl = self.pool.get('product.pricelist').browse(cr,
                                                               uid,
                                                               pricelist_id,
                                                               context=context)
                if pl.type == "purchase":
                    product = products_dict[product_id]
                    if 'uom' in context:
                        uom = product.uom_po_id
                        if uom.id != context['uom']:
                            qty = qty * product.uom_po_id.factor / product.uom_id.factor

                cr.execute(
                    'SELECT i.*, pl.currency_id '
                    'FROM product_pricelist_item AS i, '
                    'product_pricelist_version AS v, product_pricelist AS pl '
                    'WHERE (product_tmpl_id IS NULL OR product_tmpl_id = %s) '
                    'AND (product_id IS NULL OR product_id = %s) '
                    'AND (' + categ_where + ' OR (categ_id IS NULL)) '
                    'AND (' + partner_where + ') '
                    'AND price_version_id = %s '
                    'AND (min_quantity IS NULL OR min_quantity <= %s) '
                    'AND i.price_version_id = v.id AND v.pricelist_id = pl.id '
                    'ORDER BY sequence', (tmpl_id, product_id) + partner_args +
                    (pricelist_version_ids[0], qty))
                res1 = cr.dictfetchall()
                uom_price_already_computed = False
                for res in res1:
                    if res:
                        if res['base'] == -1:
                            if not res['base_pricelist_id']:
                                price = 0.0
                            else:
                                price_tmp = self.price_get(
                                    cr,
                                    uid, [res['base_pricelist_id']],
                                    product_id,
                                    qty,
                                    context=context)[res['base_pricelist_id']]
                                ptype_src = self.browse(
                                    cr, uid,
                                    res['base_pricelist_id']).currency_id.id
                                uom_price_already_computed = True
                                price = currency_obj.compute(
                                    cr,
                                    uid,
                                    ptype_src,
                                    res['currency_id'],
                                    price_tmp,
                                    round=False)
                        elif res['base'] == -2:
                            # this section could be improved by moving the queries outside the loop:
                            where = []
                            if partner:
                                where = [('name', '=', partner)]
                            sinfo = supplierinfo_obj.search(
                                cr, uid,
                                [('product_id', '=', tmpl_id)] + where)
                            price = 0.0
                            if sinfo:
                                qty_in_product_uom = qty
                                product_default_uom = product_obj.read(
                                    cr, uid, [product_id],
                                    ['uom_id'])[0]['uom_id'][0]
                                supplier = supplierinfo_obj.browse(
                                    cr, uid, sinfo, context=context)[0]
                                seller_uom = supplier.product_uom and supplier.product_uom.id or False
                                if seller_uom and product_default_uom and product_default_uom != seller_uom:
                                    uom_price_already_computed = True
                                    qty_in_product_uom = product_uom_obj._compute_qty(
                                        cr,
                                        uid,
                                        product_default_uom,
                                        qty,
                                        to_uom_id=seller_uom)
                                cr.execute('SELECT * ' \
                                        'FROM pricelist_partnerinfo ' \
                                        'WHERE suppinfo_id IN %s' \
                                            'AND min_quantity <= %s ' \
                                        'ORDER BY min_quantity DESC LIMIT 1', (tuple(sinfo), qty_in_product_uom,))
                                res2 = cr.dictfetchone()
                                if res2:
                                    price = res2['price']
                        #Add by Andy
                        elif res['base'] == -3:
                            price = False
                        else:
                            price_type = price_type_obj.browse(
                                cr, uid, int(res['base']))
                            uom_price_already_computed = True
                            price = currency_obj.compute(
                                cr,
                                uid,
                                price_type.currency_id.id,
                                res['currency_id'],
                                product_obj.price_get(
                                    cr,
                                    uid, [product_id],
                                    price_type.field,
                                    context=context)[product_id],
                                round=False,
                                context=context)

                        if price is not False:
                            price_limit = price
                            price = price * (1.0 +
                                             (res['price_discount'] or 0.0))
                            price = rounding(
                                price, res['price_round']
                            )  #TOFIX: rounding with tools.float_rouding
                            price += (res['price_surcharge'] or 0.0)
                            if res['price_min_margin']:
                                price = max(
                                    price,
                                    price_limit + res['price_min_margin'])
                            if res['price_max_margin']:
                                price = min(
                                    price,
                                    price_limit + res['price_max_margin'])
                            break
                        #Add by Andy
                        else:
                            if res['base'] == -3:
                                price = res['price_surcharge'] or 0.0
                                product = products_dict[product_id]
                                if 'uom' in context:
                                    uom = product.uom_po_id
                                    if uom.id != context['uom']:
                                        price = product_uom_obj._compute_price(
                                            cr, uid, uom.id, price,
                                            context['uom'])
                                uom_price_already_computed = True
                                #Todo: # Use company currency?
                                if 'currency_id' in context:
                                    price = currency_obj.compute(
                                        cr,
                                        uid,
                                        1,
                                        context['currency_id'],
                                        price,
                                        context=context)
                                if price:
                                    break
                    else:
                        # False means no valid line found ! But we may not raise an
                        # exception here because it breaks the search
                        price = False

                if price:
                    results['item_id'] = res['id']
                    if 'uom' in context and not uom_price_already_computed:
                        product = products_dict[product_id]
                        uom = product.uos_id or product.uom_id
                        price = product_uom_obj._compute_price(
                            cr, uid, uom.id, price, context['uom'])

                if results.get(product_id):
                    results[product_id][pricelist_id] = price
                else:
                    results[product_id] = {pricelist_id: price}

        return results
    def price_get_multi(self, cr, uid, pricelist_ids, products_by_qty_by_partner, context=None):
        def _create_parent_category_list(id, lst):
            if not id:
                return []
            parent = product_category_tree.get(id)
            if parent:
                lst.append(parent)
                return _create_parent_category_list(parent, lst)
            else:
                return lst

        # _create_parent_category_list

        if context is None:
            context = {}

        date = time.strftime("%Y-%m-%d")
        if "date" in context:
            date = context["date"]

        currency_obj = self.pool.get("res.currency")
        product_obj = self.pool.get("product.product")
        product_category_obj = self.pool.get("product.category")
        product_uom_obj = self.pool.get("product.uom")
        supplierinfo_obj = self.pool.get("product.supplierinfo")
        price_type_obj = self.pool.get("product.price.type")
        product_pricelist_version_obj = self.pool.get("product.pricelist.version")

        # product.pricelist.version:
        if pricelist_ids:
            pricelist_version_ids = pricelist_ids
        else:
            # all pricelists:
            pricelist_version_ids = self.pool.get("product.pricelist").search(cr, uid, [], context=context)

        pricelist_version_ids = list(set(pricelist_version_ids))
        plversions_search_args = [
            ("pricelist_id", "in", pricelist_version_ids),
            "|",
            ("date_start", "=", False),
            ("date_start", "<=", date),
            "|",
            ("date_end", "=", False),
            ("date_end", ">=", date),
        ]

        plversion_ids = product_pricelist_version_obj.search(cr, uid, plversions_search_args)
        if len(pricelist_version_ids) != len(plversion_ids):
            msg = "At least one pricelist has no active version !\nPlease create or activate one."
            raise osv.except_osv(_("Warning !"), _(msg))

        # product.product:
        product_ids = [i[0] for i in products_by_qty_by_partner]
        # products = dict([(item['id'], item) for item in product_obj.read(cr, uid, product_ids, ['categ_id', 'product_tmpl_id', 'uos_id', 'uom_id'])])
        products = product_obj.browse(cr, uid, product_ids, context=context)
        products_dict = dict([(item.id, item) for item in products])

        # product.category:
        product_category_ids = product_category_obj.search(cr, uid, [])
        product_categories = product_category_obj.read(cr, uid, product_category_ids, ["parent_id"])
        product_category_tree = dict(
            [(item["id"], item["parent_id"][0]) for item in product_categories if item["parent_id"]]
        )

        results = {}
        for product_id, qty, partner in products_by_qty_by_partner:
            for pricelist_id in pricelist_version_ids:
                price = False

                tmpl_id = (
                    products_dict[product_id].product_tmpl_id and products_dict[product_id].product_tmpl_id.id or False
                )

                categ_id = products_dict[product_id].categ_id and products_dict[product_id].categ_id.id or False
                categ_ids = _create_parent_category_list(categ_id, [categ_id])
                if categ_ids:
                    categ_where = "(categ_id IN (" + ",".join(map(str, categ_ids)) + "))"
                else:
                    categ_where = "(categ_id IS NULL)"

                cr.execute(
                    "SELECT i.*, pl.currency_id "
                    "FROM product_pricelist_item AS i, "
                    "product_pricelist_version AS v, product_pricelist AS pl "
                    "WHERE (product_tmpl_id IS NULL OR product_tmpl_id = %s) "
                    "AND (product_id IS NULL OR product_id = %s) "
                    "AND (" + categ_where + " OR (categ_id IS NULL)) "
                    "AND price_version_id = %s "
                    "AND (min_quantity IS NULL OR min_quantity <= %s) "
                    "AND i.price_version_id = v.id AND v.pricelist_id = pl.id "
                    "ORDER BY sequence",
                    (tmpl_id, product_id, plversion_ids[0], qty),
                )
                res1 = cr.dictfetchall()
                uom_price_already_computed = False
                for res in res1:
                    if res:
                        if res["base"] == -1:
                            if not res["base_pricelist_id"]:
                                price = 0.0
                            else:
                                price_tmp = self.price_get(
                                    cr, uid, [res["base_pricelist_id"]], product_id, qty, context=context
                                )[res["base_pricelist_id"]]
                                ptype_src = self.browse(cr, uid, res["base_pricelist_id"]).currency_id.id
                                price = currency_obj.compute(
                                    cr, uid, ptype_src, res["currency_id"], price_tmp, round=False
                                )
                        elif res["base"] == -2:
                            # this section could be improved by moving the queries outside the loop:
                            where = []
                            if partner:
                                where = [("name", "=", partner)]
                            sinfo = supplierinfo_obj.search(cr, uid, [("product_id", "=", tmpl_id)] + where)
                            price = 0.0
                            if sinfo:
                                qty_in_product_uom = qty
                                product_default_uom = product_obj.read(cr, uid, [tmpl_id], ["uom_id"])[0]["uom_id"][0]
                                seller_uom = supplierinfo_obj.read(cr, uid, sinfo, ["product_uom"])[0]["product_uom"][0]
                                if seller_uom and product_default_uom and product_default_uom != seller_uom:
                                    uom_price_already_computed = True
                                    qty_in_product_uom = product_uom_obj._compute_qty(
                                        cr, uid, product_default_uom, qty, to_uom_id=seller_uom
                                    )
                                cr.execute(
                                    "SELECT * "
                                    "FROM pricelist_partnerinfo "
                                    "WHERE suppinfo_id IN %s"
                                    "AND min_quantity <= %s "
                                    "ORDER BY min_quantity DESC LIMIT 1",
                                    (tuple(sinfo), qty_in_product_uom),
                                )
                                res2 = cr.dictfetchone()
                                if res2:
                                    price = res2["price"]

                        # This is added by product_pricelist_fixed_price
                        elif res["base"] == -3:
                            price = res["fixed_price"]
                            break
                        # End

                        else:
                            price_type = price_type_obj.browse(cr, uid, int(res["base"]))
                            price = currency_obj.compute(
                                cr,
                                uid,
                                price_type.currency_id.id,
                                res["currency_id"],
                                product_obj.price_get(cr, uid, [product_id], price_type.field, context=context)[
                                    product_id
                                ],
                                round=False,
                                context=context,
                            )

                        if price and res["base"] != -3:  # Modified by product_pricelist_fixed_price
                            price_limit = price

                            price = price * (1.0 + (res["price_discount"] or 0.0))
                            price = rounding(price, res["price_round"])
                            price += res["price_surcharge"] or 0.0
                            if res["price_min_margin"]:
                                price = max(price, price_limit + res["price_min_margin"])
                            if res["price_max_margin"]:
                                price = min(price, price_limit + res["price_max_margin"])
                            break

                    else:
                        # False means no valid line found ! But we may not raise an
                        # exception here because it breaks the search
                        price = False

                if price:
                    if "uom" in context and not uom_price_already_computed:
                        product = products_dict[product_id]
                        uom = product.uos_id or product.uom_id
                        price = self.pool.get("product.uom")._compute_price(cr, uid, uom.id, price, context["uom"])

                if results.get(product_id):
                    results[product_id][pricelist_id] = price
                else:
                    results[product_id] = {pricelist_id: price}

        return results
Example #10
0
    def update_or_create_line(self, cr, uid, values, context=None):
        """
            values = {
                'name': expense_line.name,
                'product': expense_line.product_id,
                'product_qty': expense_line.unit_quantity,
                'product_uom': expense_line.uom_id,  # Optional, is not required.
                'account_id': expense_line.analytic_account.id,
                'unit_amount': values.get('unit_amount', False),  # Optional, is not required
                'date': expense_line.date_value + ' 00:00:00',
                'ref': hr_expense.name,
                'origin_document': expense_line
            }
        """

        journals = {
            "hr.expense.line": {"journal": "expense_journal_id", "name": _("Expense Journal")},
            "stock.move": {"journal": "delivery_note_journal_id", "name": _("Delivery Note Journal")},
        }

        if values.get("account_id", False):
            user = self.pool["res.users"].browse(cr, uid, uid, context)

            journal = getattr(user.company_id, journals[values["origin_document"]._name]["journal"])
            if journal:
                journal_id = journal.id
            else:
                raise orm.except_orm(
                    "Error",
                    _("{journal} is not defined for this company").format(
                        journal=journals[values["origin_document"]._name]["name"]
                    ),
                )

            product_qty = values.get("product_qty", 1)
            price_unit_precision = self.pool["decimal.precision"].precision_get(cr, uid, "Sale Price")

            if values.get("unit_amount", False):
                amount = rounding(values["unit_amount"] * product_qty, 10 ** -price_unit_precision)
            elif values.get("product", False):
                amount = self.get_cost_amount(cr, uid, values["product"], product_qty, context)
            else:
                return False

            if values.get("product", False):
                general_account_id = values["product"].product_tmpl_id.property_account_expense.id

                if not general_account_id:
                    general_account_id = values["product"].categ_id.property_account_expense_categ.id
                if not general_account_id:
                    raise orm.except_orm(
                        _("Error!"),
                        _(
                            """There is no expense account defined
                                            for this product: "{0}" (id:{1})"""
                        ).format(values["product"].name, values["product"].id),
                    )
            else:
                general_account_id = False

            line_date = datetime.datetime.strptime(values["date"], DEFAULT_SERVER_DATETIME_FORMAT)
            line_date = datetime.date(year=line_date.year, month=line_date.month, day=line_date.day)

            analytic_line_ids = self.search(
                cr,
                uid,
                [
                    (
                        "origin_document",
                        "=",
                        "{model}, {document_id}".format(
                            model=values["origin_document"]._name, document_id=values["origin_document"].id
                        ),
                    )
                ],
                context,
            )

            if analytic_line_ids:
                return self.write(
                    cr,
                    uid,
                    analytic_line_ids,
                    {
                        "amount": -amount,
                        "user_id": uid,
                        "name": values["name"],
                        "unit_amount": product_qty,  # What a strange idea to call product_qty unit_amount!!!
                        "date": line_date,
                        "company_id": user.company_id.id,
                        "account_id": values["account_id"],
                        "general_account_id": general_account_id,
                        "product_id": values["product"].id,
                        "product_uom_id": values.get("product_uom", values["product"].uom_id.id),
                        "journal_id": journal_id,
                        "amount_currency": 0.0,
                        "ref": values.get("ref", False),
                        "origin_document": "{model}, {document_id}".format(
                            model=values["origin_document"]._name, document_id=values["origin_document"].id
                        ),
                    },
                    context,
                )
            else:
                return self.create(
                    cr,
                    uid,
                    {
                        "amount": -amount,
                        "user_id": uid,
                        "name": values["name"],
                        "unit_amount": product_qty,
                        "date": line_date,
                        "company_id": user.company_id.id,
                        "account_id": values["account_id"],
                        "general_account_id": general_account_id,
                        "product_id": values["product"].id,
                        "product_uom_id": values.get("product_uom", values["product"].uom_id.id),
                        "journal_id": journal_id,
                        "amount_currency": 0.0,
                        "ref": values.get("ref", False),
                        "origin_document": "{model}, {document_id}".format(
                            model=values["origin_document"]._name, document_id=values["origin_document"].id
                        ),
                    },
                    context,
                )
        else:
            return False
Example #11
0
    def update_or_create_line(self, cr, uid, values, context=None):
        '''
            values = {
                'name': expense_line.name,
                'product': expense_line.product_id,
                'product_qty': expense_line.unit_quantity,
                'product_uom': expense_line.uom_id,  # Optional, is not required.
                'account_id': expense_line.analytic_account.id,
                'unit_amount': values.get('unit_amount', False),  # Optional, is not required
                'date': expense_line.date_value + ' 00:00:00',
                'ref': hr_expense.name,
                'origin_document': expense_line
            }
        '''
        
        journals = {
            'hr.expense.line': {'journal': 'expense_journal_id', 'name': _('Expense Journal')},
            'stock.move': {'journal': 'delivery_note_journal_id', 'name': _('Delivery Note Journal')}
        }
        
        if values.get('account_id', False):
            user = self.pool['res.users'].browse(cr, uid, uid, context)
            
            journal = getattr(user.company_id, journals[values['origin_document']._name]['journal'])
            if journal:
                journal_id = journal.id
            else:
                raise orm.except_orm('Error', _('{journal} is not defined for this company').format(journal=journals[values['origin_document']._name]['name']))
            
            product_qty = values.get('product_qty', 1)
            price_unit_precision = self.pool['decimal.precision'].precision_get(cr, uid, 'Sale Price')
            
            if values.get('unit_amount', False):
                amount = rounding(values['unit_amount'] * product_qty, 10 ** - price_unit_precision)
            elif values.get('product', False):
                amount = self.get_cost_amount(cr, uid, values['product'], product_qty, context)
            else:
                return False
            
            if values.get('product', False):
                general_account_id = values['product'].product_tmpl_id.property_account_expense.id
                
                if not general_account_id:
                    general_account_id = values['product'].categ_id.property_account_expense_categ.id
                if not general_account_id:
                    raise orm.except_orm(_('Error!'),
                                         _('''There is no expense account defined
                                            for this product: "{0}" (id:{1})''').format(values['product'].name, values['product'].id,))
            else:
                general_account_id = False
            
            line_date = datetime.datetime.strptime(values['date'], DEFAULT_SERVER_DATETIME_FORMAT)
            line_date = datetime.date(year=line_date.year, month=line_date.month, day=line_date.day)
            
            analytic_line_ids = self.search(cr, uid, [('origin_document', '=', '{model}, {document_id}'.format(model=values['origin_document']._name, document_id=values['origin_document'].id))], context=context)

            if analytic_line_ids:
                return self.write(cr, uid, analytic_line_ids, {
                    'amount': -amount,
                    'user_id': uid,
                    'name': values['name'],
                    'unit_amount': product_qty,  # What a strange idea to call product_qty unit_amount!!!
                    'date': line_date,
                    'company_id': user.company_id.id,
                    'account_id': values['account_id'],
                    'general_account_id': general_account_id,
                    'product_id': values['product'].id,
                    'product_uom_id': values.get('product_uom', values['product'].uom_id.id),
                    'journal_id': journal_id,
                    'amount_currency': 0.0,
                    'ref': values.get('ref', False),
                    'origin_document': '{model}, {document_id}'.format(model=values['origin_document']._name, document_id=values['origin_document'].id)
                }, context)
            else:
                return self.create(cr, uid, {
                    'amount': -amount,
                    'user_id': uid,
                    'name': values['name'],
                    'unit_amount': product_qty,
                    'date': line_date,
                    'company_id': user.company_id.id,
                    'account_id': values['account_id'],
                    'general_account_id': general_account_id,
                    'product_id': values['product'].id,
                    'product_uom_id': values.get('product_uom', values['product'].uom_id.id),
                    'journal_id': journal_id,
                    'amount_currency': 0.0,
                    'ref': values.get('ref', False),
                    'origin_document': '{model}, {document_id}'.format(model=values['origin_document']._name, document_id=values['origin_document'].id)
                }, context)
        else:
            return False
Example #12
0
    def price_get_multi(self,
                        cr,
                        uid,
                        pricelist_ids,
                        products_by_qty_by_partner,
                        context=None):
        def _create_parent_category_list(id, lst):
            if not id:
                return []
            parent = product_category_tree.get(id)
            if parent:
                lst.append(parent)
                return _create_parent_category_list(parent, lst)
            else:
                return lst

        # _create_parent_category_list

        if context is None:
            context = {}

        date = time.strftime('%Y-%m-%d')
        if 'date' in context:
            date = context['date']

        currency_obj = self.pool.get('res.currency')
        product_obj = self.pool.get('product.product')
        product_category_obj = self.pool.get('product.category')
        product_uom_obj = self.pool.get('product.uom')
        supplierinfo_obj = self.pool.get('product.supplierinfo')
        price_type_obj = self.pool.get('product.price.type')
        product_pricelist_version_obj = self.pool.get(
            'product.pricelist.version')

        # product.pricelist.version:
        if pricelist_ids:
            pricelist_version_ids = pricelist_ids
        else:
            # all pricelists:
            pricelist_version_ids = self.pool.get('product.pricelist').search(
                cr, uid, [], context=context)

        pricelist_version_ids = list(set(pricelist_version_ids))
        plversions_search_args = [
            ('pricelist_id', 'in', pricelist_version_ids),
            '|',
            ('date_start', '=', False),
            ('date_start', '<=', date),
            '|',
            ('date_end', '=', False),
            ('date_end', '>=', date),
        ]

        plversion_ids = product_pricelist_version_obj.search(
            cr, uid, plversions_search_args)
        if len(pricelist_version_ids) != len(plversion_ids):
            msg = "At least one pricelist has no active version !\nPlease create or activate one."
            raise osv.except_osv(_('Warning !'), _(msg))

        # product.product:
        product_ids = [i[0] for i in products_by_qty_by_partner]
        #products = dict([(item['id'], item) for item in product_obj.read(cr, uid, product_ids, ['categ_id', 'product_tmpl_id', 'uos_id', 'uom_id'])])
        products = product_obj.browse(cr, uid, product_ids, context=context)
        products_dict = dict([(item.id, item) for item in products])

        # product.category:
        product_category_ids = product_category_obj.search(cr, uid, [])
        product_categories = product_category_obj.read(cr, uid,
                                                       product_category_ids,
                                                       ['parent_id'])
        product_category_tree = dict([(item['id'], item['parent_id'][0])
                                      for item in product_categories
                                      if item['parent_id']])

        results = {}
        for product_id, qty, partner in products_by_qty_by_partner:
            for pricelist_id in pricelist_version_ids:
                price = False

                tmpl_id = products_dict[
                    product_id].product_tmpl_id and products_dict[
                        product_id].product_tmpl_id.id or False

                categ_id = products_dict[product_id].categ_id and products_dict[
                    product_id].categ_id.id or False
                categ_ids = _create_parent_category_list(categ_id, [categ_id])
                if categ_ids:
                    categ_where = '(categ_id IN (' + ','.join(
                        map(str, categ_ids)) + '))'
                else:
                    categ_where = '(categ_id IS NULL)'

                cr.execute(
                    'SELECT i.*, pl.currency_id '
                    'FROM product_pricelist_item AS i, '
                    'product_pricelist_version AS v, product_pricelist AS pl '
                    'WHERE (product_tmpl_id IS NULL OR product_tmpl_id = %s) '
                    'AND (product_id IS NULL OR product_id = %s) '
                    'AND (' + categ_where + ' OR (categ_id IS NULL)) '
                    'AND price_version_id = %s '
                    'AND (min_quantity IS NULL OR min_quantity <= %s) '
                    'AND i.price_version_id = v.id AND v.pricelist_id = pl.id '
                    'ORDER BY sequence',
                    (tmpl_id, product_id, plversion_ids[0], qty))
                res1 = cr.dictfetchall()
                uom_price_already_computed = False
                for res in res1:
                    if res:
                        if res['base'] == -1:
                            if not res['base_pricelist_id']:
                                price = 0.0
                            else:
                                price_tmp = self.price_get(
                                    cr,
                                    uid, [res['base_pricelist_id']],
                                    product_id,
                                    qty,
                                    context=context)[res['base_pricelist_id']]
                                ptype_src = self.browse(
                                    cr, uid,
                                    res['base_pricelist_id']).currency_id.id
                                price = currency_obj.compute(
                                    cr,
                                    uid,
                                    ptype_src,
                                    res['currency_id'],
                                    price_tmp,
                                    round=False)
                        elif res['base'] == -2:
                            # this section could be improved by moving the queries outside the loop:
                            where = []
                            if partner:
                                where = [('name', '=', partner)]
                            sinfo = supplierinfo_obj.search(
                                cr, uid,
                                [('product_id', '=', tmpl_id)] + where)
                            price = 0.0
                            if sinfo:
                                qty_in_product_uom = qty
                                product_default_uom = product_obj.read(
                                    cr, uid, [tmpl_id],
                                    ['uom_id'])[0]['uom_id'][0]
                                seller_uom = supplierinfo_obj.read(
                                    cr, uid, sinfo,
                                    ['product_uom'])[0]['product_uom'][0]
                                if seller_uom and product_default_uom and product_default_uom != seller_uom:
                                    uom_price_already_computed = True
                                    qty_in_product_uom = product_uom_obj._compute_qty(
                                        cr,
                                        uid,
                                        product_default_uom,
                                        qty,
                                        to_uom_id=seller_uom)
                                cr.execute('SELECT * ' \
                                        'FROM pricelist_partnerinfo ' \
                                        'WHERE suppinfo_id IN %s' \
                                            'AND min_quantity <= %s ' \
                                        'ORDER BY min_quantity DESC LIMIT 1', (tuple(sinfo),qty_in_product_uom,))
                                res2 = cr.dictfetchone()
                                if res2:
                                    price = res2['price']
                        #This is added by product_pricelist_fixed_price
                        elif res['base'] == -3:
                            price = res['fixed_price']
                        #End
                        else:
                            price_type = price_type_obj.browse(
                                cr, uid, int(res['base']))
                            price = currency_obj.compute(
                                cr,
                                uid,
                                price_type.currency_id.id,
                                res['currency_id'],
                                product_obj.price_get(
                                    cr,
                                    uid, [product_id],
                                    price_type.field,
                                    context=context)[product_id],
                                round=False,
                                context=context)

                        if price:
                            price_limit = price

                            price = price * (1.0 +
                                             (res['price_discount'] or 0.0))
                            price = rounding(price, res['price_round'])
                            price += (res['price_surcharge'] or 0.0)
                            if res['price_min_margin']:
                                price = max(
                                    price,
                                    price_limit + res['price_min_margin'])
                            if res['price_max_margin']:
                                price = min(
                                    price,
                                    price_limit + res['price_max_margin'])
                            break

                    else:
                        # False means no valid line found ! But we may not raise an
                        # exception here because it breaks the search
                        price = False

                if price:
                    if 'uom' in context and not uom_price_already_computed:
                        product = products_dict[product_id]
                        uom = product.uos_id or product.uom_id
                        price = self.pool.get('product.uom')._compute_price(
                            cr, uid, uom.id, price, context['uom'])

                if results.get(product_id):
                    results[product_id][pricelist_id] = price
                else:
                    results[product_id] = {pricelist_id: price}

        return results
Example #13
0
    def product_id_change(self, cr, uid, ids, pricelist, product, qty, uom,
            partner_id, date_order=False, fiscal_position=False, date_planned=False,
            name=False, price_unit=False, notes=False):
        if not pricelist:
            raise osv.except_osv(_('No Pricelist !'), _('You have to select a pricelist or a supplier in the purchase form !\nPlease set one before choosing a product.'))
        if not  partner_id:
            raise osv.except_osv(_('No Partner!'), _('You have to select a partner in the purchase form !\nPlease set one partner before choosing a product.'))
        if not product:
            return {'value': {'price_unit': price_unit or 0.0, 'name': name or '',
                'notes': notes or'', 'product_uom' : uom or False}, 'domain':{'product_uom':[]}}
        res = {}
        prod= self.pool.get('product.product').browse(cr, uid, product)

        product_uom_pool = self.pool.get('product.uom')
        lang=False
        if partner_id:
            lang=self.pool.get('res.partner').read(cr, uid, partner_id, ['lang'])['lang']
        context = self.pool.get('res.users').context_get(cr, uid)
        context_partner = {'lang':lang, 'partner_id': partner_id}
        prod = self.pool.get('product.product').browse(cr, uid, product, context=context)
        prod_uom_po = prod.uom_po_id.id
        if not uom:
            uom = prod_uom_po
        if not date_order:
            date_order = time.strftime('%Y-%m-%d')
        qty = qty or 1.0
        seller_delay = 0

        prod_name = self.pool.get('product.product').name_get(cr, uid, [prod.id], context=context_partner)[0][1]
        res = {}
        for s in prod.seller_ids:
            if s.name.id == partner_id:
                seller_delay = s.delay
                if s.product_uom:
                    temp_qty = product_uom_pool._compute_qty(cr, uid, s.product_uom.id, s.min_qty, to_uom_id=prod.uom_id.id)
                    uom = s.product_uom.id #prod_uom_po
                temp_qty = s.min_qty # supplier _qty assigned to temp
                if qty < temp_qty: # If the supplier quantity is greater than entered from user, set minimal.
                    qty = temp_qty
                    res.update({'warning': {'title': _('Warning'), 'message': _('The selected supplier has a minimal quantity set to %s, you cannot purchase less.') % qty}})
        qty_in_product_uom = product_uom_pool._compute_qty(cr, uid, uom, qty, to_uom_id=prod.uom_id.id)
        price = self.pool.get('product.pricelist').price_get(cr,uid,[pricelist],
                    product, qty_in_product_uom or 1.0, partner_id, {
                        'uom': uom,
                        'date': date_order,
                        })[pricelist]
        # at end, round price depending of 'Purchase Price' decimal precision
        price_unit_precision = self.pool.get('decimal.precision').precision_get(cr, uid, 'Purchase Price')
        price = rounding(price, 10**-price_unit_precision)
        if price is False:
            warning = {
                'title': 'No valid pricelist line found !',
                'message':
                    "Couldn't find a pricelist line matching this product and quantity.\n"
                    "You have to change either the product, the quantity or the pricelist."
                }
            res.update({'warning': warning})
        dt = (datetime.now() + relativedelta(days=int(seller_delay) or 0.0)).strftime('%Y-%m-%d %H:%M:%S')


        res.update({'value': {'price_unit': price, 'name': prod_name,
            'taxes_id':map(lambda x: x.id, prod.supplier_taxes_id),
            'date_planned': date_planned or dt,'notes': notes or prod.description_purchase,
            'product_qty': qty,
            'product_uom': uom}})
        domain = {}

        taxes = self.pool.get('account.tax').browse(cr, uid,map(lambda x: x.id, prod.supplier_taxes_id))
        fpos = fiscal_position and self.pool.get('account.fiscal.position').browse(cr, uid, fiscal_position) or False
        res['value']['taxes_id'] = self.pool.get('account.fiscal.position').map_tax(cr, uid, fpos, taxes)

        res2 = self.pool.get('product.uom').read(cr, uid, [uom], ['category_id'])
        res3 = prod.uom_id.category_id.id
        domain = {'product_uom':[('category_id','=',res2[0]['category_id'][0])]}
        if res2[0]['category_id'][0] != res3:
            raise osv.except_osv(_('Wrong Product UOM !'), _('You have to select a product UOM in the same category than the purchase UOM of the product'))

        res['domain'] = domain
        return res
Example #14
0
    def price_get_multi(self, cr, uid, pricelist_ids, products_by_qty_by_partner, context=None):
        """multi products 'price_get'.
           @param pricelist_ids:
           @param products_by_qty:
           @param partner:
           @param context: {
             'date': Date of the pricelist (%Y-%m-%d),}
           @return: a dict of dict with product_id as key and a dict 'price by pricelist' as value
        """

        def _create_parent_category_list(id, lst):
            if not id:
                return []
            parent = product_category_tree.get(id)
            if parent:
                lst.append(parent)
                return _create_parent_category_list(parent, lst)
            else:
                return lst
        # _create_parent_category_list

        if context is None:
            context = {}

        date = time.strftime('%Y-%m-%d')
        if 'date' in context:
            date = context['date']

        currency_obj = self.pool.get('res.currency')
        product_obj = self.pool.get('product.product')
        product_category_obj = self.pool.get('product.category')
        product_uom_obj = self.pool.get('product.uom')
        supplierinfo_obj = self.pool.get('product.supplierinfo')
        price_type_obj = self.pool.get('product.price.type')

        # product.pricelist.version:
        if not pricelist_ids:
            pricelist_ids = self.pool.get('product.pricelist').search(cr, uid, [], context=context)

        pricelist_version_ids = self.pool.get('product.pricelist.version').search(cr, uid, [
                                                        ('pricelist_id', 'in', pricelist_ids),
                                                        '|',
                                                        ('date_start', '=', False),
                                                        ('date_start', '<=', date),
                                                        '|',
                                                        ('date_end', '=', False),
                                                        ('date_end', '>=', date),
                                                    ])
        if len(pricelist_ids) != len(pricelist_version_ids):
            raise osv.except_osv(_('Warning!'), _("At least one pricelist has no active version !\nPlease create or activate one."))

        # product.product:
        product_ids = [i[0] for i in products_by_qty_by_partner]
        products = product_obj.browse(cr, uid, product_ids, context=context)
        products_dict = dict([(item.id, item) for item in products])

        # product.category:
        product_category_ids = product_category_obj.search(cr, uid, [])
        product_categories = product_category_obj.read(cr, uid, product_category_ids, ['parent_id'])
        product_category_tree = dict([(item['id'], item['parent_id'][0]) for item in product_categories if item['parent_id']])

        results = {}
        for product_id, qty, partner in products_by_qty_by_partner:
            for pricelist_id in pricelist_ids:
                price = False

                tmpl_id = products_dict[product_id].product_tmpl_id and products_dict[product_id].product_tmpl_id.id or False

                categ_id = products_dict[product_id].categ_id and products_dict[product_id].categ_id.id or False
                categ_ids = _create_parent_category_list(categ_id, [categ_id])
                if categ_ids:
                    categ_where = '(categ_id IN (' + ','.join(map(str, categ_ids)) + '))'
                else:
                    categ_where = '(categ_id IS NULL)'

                if partner:
                    partner_where = 'base <> -2 OR %s IN (SELECT name FROM product_supplierinfo WHERE product_id = %s) '
                    partner_args = (partner, tmpl_id)
                else:
                    partner_where = 'base <> -2 '
                    partner_args = ()

                pl = self.pool.get('product.pricelist').browse(cr, uid, pricelist_id, context=context) 
                if pl.type == "purchase":
                    product = products_dict[product_id]
                    if 'uom' in context:
                        uom = product.uom_po_id
                        if uom.id != context['uom']:
                            qty = qty * product.uom_po_id.factor / product.uom_id.factor

                cr.execute(
                    'SELECT i.*, pl.currency_id '
                    'FROM product_pricelist_item AS i, '
                        'product_pricelist_version AS v, product_pricelist AS pl '
                    'WHERE (product_tmpl_id IS NULL OR product_tmpl_id = %s) '
                        'AND (product_id IS NULL OR product_id = %s) '
                        'AND (' + categ_where + ' OR (categ_id IS NULL)) '
                        'AND (' + partner_where + ') '
                        'AND price_version_id = %s '
                        'AND (min_quantity IS NULL OR min_quantity <= %s) '
                        'AND i.price_version_id = v.id AND v.pricelist_id = pl.id '
                    'ORDER BY sequence',
                    (tmpl_id, product_id) + partner_args + (pricelist_version_ids[0], qty))
                res1 = cr.dictfetchall()
                uom_price_already_computed = False
                for res in res1:
                    if res:
                        if res['base'] == -1:
                            if not res['base_pricelist_id']:
                                price = 0.0
                            else:
                                price_tmp = self.price_get(cr, uid,
                                        [res['base_pricelist_id']], product_id,
                                        qty, context=context)[res['base_pricelist_id']]
                                ptype_src = self.browse(cr, uid, res['base_pricelist_id']).currency_id.id
                                uom_price_already_computed = True
                                price = currency_obj.compute(cr, uid, ptype_src, res['currency_id'], price_tmp, round=False)
                        elif res['base'] == -2:
                            # this section could be improved by moving the queries outside the loop:
                            where = []
                            if partner:
                                where = [('name', '=', partner) ]
                            sinfo = supplierinfo_obj.search(cr, uid,
                                    [('product_id', '=', tmpl_id)] + where)
                            price = 0.0
                            if sinfo:
                                qty_in_product_uom = qty
                                product_default_uom = product_obj.read(cr, uid, [product_id], ['uom_id'])[0]['uom_id'][0]
                                supplier = supplierinfo_obj.browse(cr, uid, sinfo, context=context)[0]
                                seller_uom = supplier.product_uom and supplier.product_uom.id or False
                                if seller_uom and product_default_uom and product_default_uom != seller_uom:
                                    uom_price_already_computed = True
                                    qty_in_product_uom = product_uom_obj._compute_qty(cr, uid, product_default_uom, qty, to_uom_id=seller_uom)
                                cr.execute('SELECT * ' \
                                        'FROM pricelist_partnerinfo ' \
                                        'WHERE suppinfo_id IN %s' \
                                            'AND min_quantity <= %s ' \
                                        'ORDER BY min_quantity DESC LIMIT 1', (tuple(sinfo), qty_in_product_uom,))
                                res2 = cr.dictfetchone()
                                if res2:
                                    price = res2['price']
                        #Add by Andy
                        elif res['base'] == -3:
                            price = False
                        else:
                            price_type = price_type_obj.browse(cr, uid, int(res['base']))
                            uom_price_already_computed = True
                            price = currency_obj.compute(cr, uid,
                                    price_type.currency_id.id, res['currency_id'],
                                    product_obj.price_get(cr, uid, [product_id],
                                    price_type.field, context=context)[product_id], round=False, context=context)

                        if price is not False:
                            price_limit = price
                            price = price * (1.0 + (res['price_discount'] or 0.0))
                            price = rounding(price, res['price_round']) #TOFIX: rounding with tools.float_rouding
                            price += (res['price_surcharge'] or 0.0)
                            if res['price_min_margin']:
                                price = max(price, price_limit + res['price_min_margin'])
                            if res['price_max_margin']:
                                price = min(price, price_limit + res['price_max_margin'])
                            break
                        #Add by Andy
                        else:        
                            if res['base'] == -3:
                                price = res['price_surcharge'] or 0.0                                    
                                product = products_dict[product_id]
                                if 'uom' in context:
                                    uom = product.uom_po_id
                                    if uom.id != context['uom']:
                                        price = product_uom_obj._compute_price(cr, uid, uom.id, price, context['uom'])
                                uom_price_already_computed = True
                                #Todo: # Use company currency?
                                if 'currency_id' in context:                                    
                                    price = currency_obj.compute(cr, uid, 1,
                                        context['currency_id'], price, context=context)
                                if price:
                                    break
                    else:
                        # False means no valid line found ! But we may not raise an
                        # exception here because it breaks the search
                        price = False

                if price:
                    results['item_id'] = res['id']
                    if 'uom' in context and not uom_price_already_computed:
                        product = products_dict[product_id]
                        uom = product.uos_id or product.uom_id
                        price = product_uom_obj._compute_price(cr, uid, uom.id, price, context['uom'])

                if results.get(product_id):
                    results[product_id][pricelist_id] = price
                else:
                    results[product_id] = {pricelist_id: price}

        return results