def do_partial(self, cr, uid, ids, context=None):
        """ Makes partial moves and pickings done.
        @param self: The object pointer.
        @param cr: A database cursor
        @param uid: ID of the user currently logged in
        @param fields: List of fields for which we want default values
        @param context: A standard dictionary
        @return: A dictionary which of fields with values.
        """
        pick_obj = self.pool.get('stock.picking')
        uom_obj = self.pool.get('product.uom')

        picking_ids = context.get('active_ids', False)
        partial = self.browse(cr, uid, ids[0], context=context)
        partial_datas = {
            'delivery_date' : partial.date
        }

        for pick in pick_obj.browse(cr, uid, picking_ids, context=context):
            picking_type = self.get_picking_type(cr, uid, pick, context=context)
            moves_list = picking_type == 'in' and partial.product_moves_in or partial.product_moves_out

            for move in moves_list:

                #Adding a check whether any line has been added with new qty
                if not move.move_id:
                    raise osv.except_osv(_('Processing Error'),\
                    _('You cannot add any new move while validating the picking, rather you can split the lines prior to validation!'))

                calc_qty = uom_obj._compute_qty(cr, uid, move.product_uom.id, \
                                    move.quantity, move.move_id.product_uom.id)
                #Adding a check whether any move line contains exceeding qty to original moveline
                product_uom = self.pool.get('decimal.precision').precision_get(cr, uid, 'Product UOM')
                if round(calc_qty, product_uom) > round(move.move_id.product_qty, product_uom):
                    precision = '%0.' + str(dp.get_precision('Product UoM')(cr)[1] or 0) + 'f'
                    raise osv.except_osv(_('Processing Error'),
                    _('Processing quantity %s %s for %s is larger than the available quantity %s %s !')\
                    % (precision % calc_qty, move.product_uom.name, move.product_id.name,\
                       precision % move.move_id.product_qty, move.move_id.product_uom.name))

                #Adding a check whether any move line contains qty less than zero
                if calc_qty < 0:
                    precision = '%0.' + str(dp.get_precision('Product UoM')(cr)[1] or 0) + 'f'
                    raise osv.except_osv(_('Processing Error'), \
                            _('Can not process quantity %s for Product %s !') \
                            % (precision % move.quantity, move.product_id.name))

                partial_datas['move%s' % (move.move_id.id)] = {
                    'product_id': move.product_id.id,
                    'product_qty': calc_qty,
                    'product_uom': move.move_id.product_uom.id,
                    'prodlot_id': move.prodlot_id.id,
                }
                if (picking_type == 'in') and (move.product_id.cost_method == 'average'):
                    partial_datas['move%s' % (move.move_id.id)].update({
                                                    'product_price' : move.cost,
                                                    'product_currency': move.currency.id,
                                                    })
        pick_obj.do_partial(cr, uid, picking_ids, partial_datas, context=context)
        return {'type': 'ir.actions.act_window_close'}
Example #2
0
    def agg_righe_iva(self, cr, uid, ids, context):
        def get_perc_iva(self, cr, uid, ids, idiva, context):
            dati = self.pool.get("account.tax").read(cr, uid, [idiva], (["amount", "type"]), context=context)
            return dati[0]["amount"]

        res = super(FiscalDocIva, self).agg_righe_iva(
            cr, uid, ids, context
        )  # prima ricalcola il castelletto iva standard
        res = self.pool.get("conai.castelletto").agg_tot_conai(cr, uid, ids, context)
        conai_ids = self.pool.get("conai.castelletto").search(cr, uid, [("name", "=", ids)])
        if conai_ids:  # ci sono righe di castelletto conai
            for riga_cast in self.pool.get("conai.castelletto").browse(cr, uid, conai_ids):
                iva_id = self.pool.get("fiscaldoc.iva").search(
                    cr, uid, [("name", "=", riga_cast.name.id), ("codice_iva", "=", riga_cast.codice_iva.id)]
                )
                if iva_id:  # somma il solo imponibile
                    iva = {}
                    iva["imponibile"] = (
                        self.pool.get("fiscaldoc.iva").browse(cr, uid, iva_id[0]).imponibile + riga_cast.totale_conai
                    )
                    ok = self.pool.get("fiscaldoc.iva").write(cr, uid, [iva_id[0]], iva)
            # ora ricalcola l'imposta
            righe_iva = self.pool.get("fiscaldoc.iva").search(cr, uid, [("name", "=", ids)])
            for rg_iva in self.pool.get("fiscaldoc.iva").browse(cr, uid, righe_iva):
                perc_iva = get_perc_iva(self, cr, uid, ids, rg_iva.codice_iva.id, context)
                imposta = rg_iva.imponibile * perc_iva
                imposta = arrot(cr, uid, imposta, dp.get_precision("Account"))
                ok = self.pool.get("fiscaldoc.iva").write(cr, uid, [rg_iva.id], {"imposta": imposta})
Example #3
0
 def balance_move(self, cr, uid, move_id, context=None):
     currency_obj = self.pool.get('res.currency')
     move = self.pool.get('account.move').browse(cr, uid, move_id, context)
     amount = 0.0
     for line in move.line_id:
         amount += line.debit - line.credit
     amount = currency_obj.round(cr, uid, move.company_id.currency_id, amount)
     # check if balance differs for more than 1 decimal according to account decimal precision
     if  abs(amount * 10 ** dp.get_precision('Account')(cr)[1]) > 1:
         raise orm.except_orm(_('Error'), _('The generated payment entry is unbalanced for more than 1 decimal'))
     if not currency_obj.is_zero(cr, uid, move.company_id.currency_id, amount):
         for line in move.line_id:
             # adjust the first move line that's not receivable, payable or liquidity
             if line.account_id.type != 'receivable' and line.account_id.type != 'payable' and line.account_id.type != 'liquidity':
                 if line.credit:
                     line.write({
                         'credit': line.credit + amount,
                         }, update_check=False)
                 elif line.debit:
                     line.write({
                         'debit': line.debit - amount,
                         }, update_check=False)
                 if line.tax_amount:
                     line.write({
                         'tax_amount': line.tax_amount + amount,
                         }, update_check=False)
                 break
     return amount
Example #4
0
    def _link_payment(self, cursor, uid, trans, payment_lines,
                      partner_ids, bank_account_ids, log, linked_payments):
        '''
        Find the payment order belonging to this reference - if there is one
        This is the easiest part: when sending payments, the returned bank info
        should be identical to ours.
        '''
        # TODO: Not sure what side effects are created when payments are done
        # for credited customer invoices, which will be matched later on too.
        digits = dp.get_precision('Account')(cursor)[1]
        candidates = [x for x in payment_lines
                      if x.communication == trans.reference 
                      and round(x.amount, digits) == -round(trans.transferred_amount, digits)
                      and trans.remote_account in (x.bank_id.acc_number,
                                                   x.bank_id.iban)
                     ]
        if len(candidates) == 1:
            candidate = candidates[0]
            # Check cache to prevent multiple matching of a single payment
            if candidate.id not in linked_payments:
                linked_payments[candidate.id] = True
                payment_line_obj = self.pool.get('payment.line')
                payment_line_obj.write(cursor, uid, [candidate.id], {
                    'export_state': 'done',
                    'date_done': trans.effective_date.strftime('%Y-%m-%d')}
                )
                
                return self._get_move_info(cursor, uid, candidate.move_line_id)

        return False
 def generadist(self, cr, uid, ids, context=None): 
 
  Parametri = self.browse(cr, uid, ids)[0]
  cerca = [
          ('data_scadenza', '>=', Parametri.da_data_scadenza),
          ('data_scadenza', '<=', Parametri.a_data_scadenza),
          ('distinta', '=', None),
          ]
  ids_eff = self.pool.get('effetti').search(cr, uid, cerca,order='data_scadenza')
  First = True
  totale_distinta = 0
  if ids_eff:
    for effetto in self.pool.get('effetti').browse(cr, uid, ids_eff):
        if not effetto.distinta or len(effetto.distinta)==0:
            if First:
                First = False
                # crea l'id della distinta
                testa_distinta = {
                                  'banca_pres':Parametri.banca_pres.id,
                                  'data_distinta':Parametri.data_distinta,
                                  'st_anag_compl':Parametri.st_anag_compl,
                                  'data_presentazione':Parametri.data_presentazione,
                                  'note':'Distinta'
                                  }
                id_distinta = self.pool.get('distinte.effetti').create(cr, uid, testa_distinta)
            
            if totale_distinta + effetto.importo_effetto <= Parametri.totale_importo:
                totale_distinta += arrot(cr,uid,effetto.importo_effetto,dp.get_precision('Account'))
                riga_distinta = {
                                 'name':id_distinta,
                                 'effetto_id':effetto.id,
                                 }
                id_riga_distinta = self.pool.get('distinte.effetti.righe').create(cr, uid, riga_distinta)
                agg_effetto = {
                               'distinta':self.pool.get('distinte.effetti').browse(cr, uid, [id_distinta])[0].name,
                               }
                #import pdb;pdb.set_trace()
                ok = self.pool.get('effetti').write(cr, uid, [effetto.id], agg_effetto) 
    # Scrive l'importo totale della distinta  
    testa_distinta = {
                                  'totale_distinta':totale_distinta,
                       }
    ok = self.pool.get('distinte.effetti').write(cr, uid, [id_distinta], testa_distinta)
         
             
    return {
         'name': _('Distinte Effetti'),
         'view_type': 'form',
         'view_mode': 'form,tree',
         'res_model': 'distinte.effetti',
         'res_id':id_distinta,
         'view_id': False,
         'context': context,
         'type': 'ir.actions.act_window',
      }      
  else:
     raise osv.except_osv(_('ERRORE !'), _('Non ci sono Effetti per questa selezione  '))   
     return {'type': 'ir.actions.act_window_close'}    # non va bene deve aprire la finestra degli effetti
Example #6
0
def float_round(cr,f_val,application = None):
    """
    使用decimal precision 设置ktv_fee,四舍五入给定的float
    """
    dp_name = application if application else "ktv_fee"
    dp_compute = dp.get_precision(dp_name)

    precision,scale = dp_compute(cr)

    ret = tools.float_round(f_val,precision_digits=scale)
    return ret
Example #7
0
    def _tot_riga_conai(self, cr, uid, ids, field_name, arg, context=None):

        res = {}
        if context is None:
            context = {}

        for line in self.browse(cr, uid, ids, context=context):
            if (
                line.name.esenzione_conai and line.name.scad_esenzione_conai >= line.name.data_documento
            ):  # c'è una esenzione conai
                # c'è un codice di esenzione
                res[line.id] = line.prezzo_conai * line.peso_conai
                res[line.id] = res[line.id] * (1 - line.name.esenzione_conai.perc / 100)
            else:
                res[line.id] = line.prezzo_conai * line.peso_conai
            res[line.id] = arrot(cr, uid, res[line.id], dp.get_precision("Account"))  # arrotonda a 2 cifre in genere
        return res
class structural_costs_impact_wizard(osv.osv_memory):
    """
    Wizard to percentually impact structural costs on service products
    """
    def onchange_analytic_account(self, cr, uid, ids, fiscalyear_id, period_id,
                                  account_id):
        """
            Gets total amount from chosen analytical account and year
        """
        res = {}
        context = {}
        res['structural_cost'] = 0.0
        struct_cost_facade = self.pool.get('product.percent.struct.costs')
        sales_facade = self.pool.get('sale.order')
        if account_id:
            fiscalyear = self.pool.get('account.fiscalyear').browse(
                cr, uid, fiscalyear_id)
            if not period_id:
                context['from_date'] = fiscalyear.date_start
                context['to_date'] = fiscalyear.date_stop
            else:
                period = self.pool.get('account.period').browse(
                    cr, uid, period_id)
                context['from_date'] = period.date_start
                context['to_date'] = period.date_stop
            account = self.pool.get('account.analytic.account').browse(
                cr, uid, account_id, context)
            res['structural_cost'] = account.credit

            #Forces creation of product lines based on sales made on chosen period and fiscal year...
            period_sales = sales_facade.browse(
                cr, uid,
                sales_facade.search(
                    cr, uid, [('state', 'not in', ['draft', 'cancel']),
                              ('date_order', '<=', context['to_date']),
                              ('date_order', '>=', context['from_date'])]))
            distinct_sale_products = {}
            product_line_ids = []
            for sale in period_sales:
                for line in sale.order_line:
                    if line.product_id:
                        if line.product_id.id not in distinct_sale_products.keys(
                        ):
                            distinct_sale_products[
                                line.product_id.id] = line.product_uom_qty
                        else:
                            distinct_sale_products[
                                line.product_id.id] += line.product_uom_qty

            for product_id in distinct_sale_products.keys():
                vals_product_line = {
                    'product_id': product_id,
                    'total_sales': distinct_sale_products[product_id],
                    'forecasted_sales': distinct_sale_products[product_id],
                    #'wizard_id': self.next_id + 1
                }
                #line_id = struct_cost_facade.create(cr, uid, vals_product_line)
                product_line_ids.append(vals_product_line)

            res['products_percent'] = product_line_ids

        return {'value': res}

    def onchange_cost_method(self, cr, uid, ids, cost_method, structural_cost,
                             products_percent):
        """
            Gets amount to impact over chosen products based on sales forecast
        """
        res = {}
        res['cost_to_impact'] = 0.0
        sum_forecasted_sales = 0.0
        if cost_method == 'uniform':
            for product_line in products_percent:
                sum_forecasted_sales += product_line[2]['forecasted_sales']
            res['cost_to_impact'] = structural_cost / sum_forecasted_sales
        return {'value': res}

    def _get_current_user_company(self, cr, uid, context={}):
        """
            Obtiene la compañía del usuario activo
        """
        current_user = self.pool.get('res.users').browse(cr, uid, uid)
        return current_user.company_id.id

    def _get_previous_fiscalyear(self, cr, uid, context):
        """
            Get previous current year
        """
        fyear_facade = self.pool.get('account.fiscalyear')
        current_fyear = context and context.get(
            'fiscalyear_id', None) or fyear_facade.browse(cr, uid, uid)
        try:
            prev_date_start = '%s-01-01' % (
                str(int(current_fyear.date_start[0:4]) - 1))
        except Exception:
            raise osv.except_osv(_('Error!'),
                                 _('Are fiscal years already defined...?'))
        prev_date_end = '%s-12-31' % (
            str(int(current_fyear.date_start[0:4]) - 1))
        prev_fyear = fyear_facade.search(
            cr, uid, [('company_id', '=', current_fyear.company_id.id),
                      ('date_start', '>=', prev_date_start),
                      ('date_stop', '<=', prev_date_end)])
        prev_fyear = prev_fyear and prev_fyear[0] or None
        if not prev_fyear:
            return current_fyear.id
        else:
            return prev_fyear

    def action_impact_struct_costs(self, cr, uid, ids, *args):
        """
            Simply opens a list view of all modified products
        """
        modified_prod_ids = []
        view_facade = self.pool.get('ir.ui.view')
        product_facade = self.pool.get('product.product')
        for wizard in self.browse(cr, uid, ids):
            for line in wizard.products_percent:
                product_facade.write(
                    cr, uid, line.product_id.id,
                    {'structural_cost': wizard.cost_to_impact})
                modified_prod_ids.append(line.product_id.id)

            product_list_view_id = view_facade.search(
                cr, uid,
                [('name', '=', 'view.add.costs.product.view.list')])[0]
            product_form_view_id = view_facade.search(
                cr, uid,
                [('name', '=', 'view.add.costs.product.view.form')])[0]

            #Finalmente, devolvemos la vista correspondiente...
            return {
                'name':
                _('Impacted Products'),
                'type':
                'ir.actions.act_window',
                'res_model':
                'product.product',
                'view_type':
                'form',
                'view_mode':
                'tree,form',
                'domain':
                "[('id', 'in', %s)]" % modified_prod_ids,
                'view_id':
                False,
                'views': [(product_list_view_id, 'tree'),
                          (product_form_view_id, 'form'), (False, 'calendar'),
                          (False, 'graph')],
            }

    _name = 'structural.costs.impact.wizard'
    _description = "Structural costs impact Wizard"

    _columns = {
        'prev_fyear_id':
        fields.many2one('account.fiscalyear',
                        'Fiscal Year to Look',
                        required=True),
        'prev_period_id':
        fields.many2one('account.period', 'Period'),
        'struct_analytic_acc_id':
        fields.many2one('account.analytic.account',
                        'Structural Expenses Analytic Account'),
        'structural_cost':
        fields.float('Structural Costs',
                     digits_compute=dp.get_precision('Account')),
        'products_percent':
        fields.one2many(
            'product.percent.struct.costs', 'wizard_id',
            'Sold Products during chosen fiscal year and/or period'),
        'structural_cost_method':
        fields.selection(
            COST_METHODS,
            'Cost Method',
            required=True,
            help=
            'Uniform method: all costs are distributed equally amongst products.'
        ),
        'cost_to_impact':
        fields.float('Cost over products',
                     digits_compute=dp.get_precision('Account'),
                     help='Cost based on forecasted sales.'),
        'company_id':
        fields.many2one('res.company', 'Company')
    }
    _defaults = {
        #'prev_fyear_id': _get_previous_fiscalyear,
        'company_id':
        lambda self, cr, uid, context: self._get_current_user_company(
            cr, uid, context),
        'structural_cost_method':
        lambda *a: 'novalid'
    }
Example #9
0
class product_product(osv.osv):
    def view_header_get(self, cr, uid, view_id, view_type, context=None):
        if context is None:
            context = {}
        res = super(product_product,
                    self).view_header_get(cr, uid, view_id, view_type, context)
        if (context.get('categ_id', False)):
            return _('Products: ') + self.pool.get('product.category').browse(
                cr, uid, context['categ_id'], context=context).name
        return res

    def _product_price(self, cr, uid, ids, name, arg, context=None):
        res = {}
        if context is None:
            context = {}
        quantity = context.get('quantity') or 1.0
        pricelist = context.get('pricelist', False)
        if pricelist:
            for id in ids:
                try:
                    price = self.pool.get('product.pricelist').price_get(
                        cr, uid, [pricelist], id, quantity,
                        context=context)[pricelist]
                except:
                    price = 0.0
                res[id] = price
        for id in ids:
            res.setdefault(id, 0.0)
        return res

    def _get_product_available_func(states, what):
        def _product_available(self, cr, uid, ids, name, arg, context=None):
            return {}.fromkeys(ids, 0.0)

        return _product_available

    _product_qty_available = _get_product_available_func(('done', ),
                                                         ('in', 'out'))
    _product_virtual_available = _get_product_available_func(
        ('confirmed', 'waiting', 'assigned', 'done'), ('in', 'out'))
    _product_outgoing_qty = _get_product_available_func(
        ('confirmed', 'waiting', 'assigned'), ('out', ))
    _product_incoming_qty = _get_product_available_func(
        ('confirmed', 'waiting', 'assigned'), ('in', ))

    def _product_lst_price(self, cr, uid, ids, name, arg, context=None):
        res = {}
        product_uom_obj = self.pool.get('product.uom')
        for id in ids:
            res.setdefault(id, 0.0)
        for product in self.browse(cr, uid, ids, context=context):
            if 'uom' in context:
                uom = product.uos_id or product.uom_id
                res[product.id] = product_uom_obj._compute_price(
                    cr, uid, uom.id, product.list_price, context['uom'])
            else:
                res[product.id] = product.list_price
            res[product.id] = (res[product.id] or 0.0) * (
                product.price_margin or 1.0) + product.price_extra
        return res

    def _get_partner_code_name(self,
                               cr,
                               uid,
                               ids,
                               product,
                               partner_id,
                               context=None):
        for supinfo in product.seller_ids:
            if supinfo.name.id == partner_id:
                return {
                    'code': supinfo.product_code or product.default_code,
                    'name': supinfo.product_name or product.name,
                    'variants': ''
                }
        res = {
            'code': product.default_code,
            'name': product.name,
            'variants': product.variants
        }
        return res

    def _product_code(self, cr, uid, ids, name, arg, context=None):
        res = {}
        if context is None:
            context = {}
        for p in self.browse(cr, uid, ids, context=context):
            res[p.id] = self._get_partner_code_name(cr,
                                                    uid, [],
                                                    p,
                                                    context.get(
                                                        'partner_id', None),
                                                    context=context)['code']
        return res

    def _product_partner_ref(self, cr, uid, ids, name, arg, context=None):
        res = {}
        if context is None:
            context = {}
        for p in self.browse(cr, uid, ids, context=context):
            data = self._get_partner_code_name(cr,
                                               uid, [],
                                               p,
                                               context.get('partner_id', None),
                                               context=context)
            if not data['variants']:
                data['variants'] = p.variants
            if not data['code']:
                data['code'] = p.code
            if not data['name']:
                data['name'] = p.name
            res[p.id] = (data['code'] and ('['+data['code']+'] ') or '') + \
                    (data['name'] or '') + (data['variants'] and (' - '+data['variants']) or '')
        return res

    _defaults = {
        'active': lambda *a: 1,
        'price_extra': lambda *a: 0.0,
        'price_margin': lambda *a: 1.0,
    }

    _name = "product.product"
    _description = "Product"
    _table = "product_product"
    _inherits = {'product.template': 'product_tmpl_id'}
    _order = 'default_code,name_template'
    _columns = {
        'qty_available':
        fields.function(_product_qty_available,
                        method=True,
                        type='float',
                        string='Real Stock'),
        'virtual_available':
        fields.function(_product_virtual_available,
                        method=True,
                        type='float',
                        string='Virtual Stock'),
        'incoming_qty':
        fields.function(_product_incoming_qty,
                        method=True,
                        type='float',
                        string='Incoming'),
        'outgoing_qty':
        fields.function(_product_outgoing_qty,
                        method=True,
                        type='float',
                        string='Outgoing'),
        'price':
        fields.function(_product_price,
                        method=True,
                        type='float',
                        string='Pricelist',
                        digits_compute=dp.get_precision('Sale Price')),
        'lst_price':
        fields.function(_product_lst_price,
                        method=True,
                        type='float',
                        string='Public Price',
                        digits_compute=dp.get_precision('Sale Price')),
        'code':
        fields.function(_product_code,
                        method=True,
                        type='char',
                        string='Reference'),
        'partner_ref':
        fields.function(_product_partner_ref,
                        method=True,
                        type='char',
                        string='Customer ref'),
        'default_code':
        fields.char('Reference', size=64),
        'active':
        fields.boolean(
            'Active',
            help=
            "If the active field is set to False, it will allow you to hide the product without removing it."
        ),
        'variants':
        fields.char('Variants', size=64),
        'product_tmpl_id':
        fields.many2one('product.template',
                        'Product Template',
                        required=True,
                        ondelete="cascade"),
        'ean13':
        fields.char('EAN13', size=13),
        'packaging':
        fields.one2many(
            'product.packaging',
            'product_id',
            'Logistical Units',
            help=
            "Gives the different ways to package the same product. This has no impact on the picking order and is mainly used if you use the EDI module."
        ),
        'price_extra':
        fields.float('Variant Price Extra',
                     digits_compute=dp.get_precision('Sale Price')),
        'price_margin':
        fields.float('Variant Price Margin',
                     digits_compute=dp.get_precision('Sale Price')),
        'pricelist_id':
        fields.dummy(string='Pricelist',
                     relation='product.pricelist',
                     type='many2one'),
        'name_template':
        fields.related('product_tmpl_id',
                       'name',
                       string="Name",
                       type='char',
                       size=128,
                       store=True),
    }

    def unlink(self, cr, uid, ids, context=None):
        unlink_ids = []
        unlink_product_tmpl_ids = []
        for product in self.browse(cr, uid, ids, context=context):
            tmpl_id = product.product_tmpl_id.id
            # Check if the product is last product of this template
            other_product_ids = self.search(cr,
                                            uid,
                                            [('product_tmpl_id', '=', tmpl_id),
                                             ('id', '!=', product.id)],
                                            context=context)
            if not other_product_ids:
                unlink_product_tmpl_ids.append(tmpl_id)
            unlink_ids.append(product.id)
        self.pool.get('product.template').unlink(cr,
                                                 uid,
                                                 unlink_product_tmpl_ids,
                                                 context=context)
        return super(product_product, self).unlink(cr,
                                                   uid,
                                                   unlink_ids,
                                                   context=context)

    def onchange_uom(self, cursor, user, ids, uom_id, uom_po_id):
        if uom_id and uom_po_id:
            uom_obj = self.pool.get('product.uom')
            uom = uom_obj.browse(cursor, user, [uom_id])[0]
            uom_po = uom_obj.browse(cursor, user, [uom_po_id])[0]
            if uom.category_id.id != uom_po.category_id.id:
                return {'value': {'uom_po_id': uom_id}}
        return False

    def _check_ean_key(self, cr, uid, ids, context=None):
        for product in self.browse(cr, uid, ids, context=context):
            res = check_ean(product.ean13)
        return res

    _constraints = [(_check_ean_key, 'Error: Invalid ean code', ['ean13'])]

    def on_order(self, cr, uid, ids, orderline, quantity):
        pass

    def name_get(self, cr, user, ids, context=None):
        if context is None:
            context = {}
        if not len(ids):
            return []

        def _name_get(d):
            name = d.get('name', '')
            code = d.get('default_code', False)
            if code:
                name = '[%s] %s' % (code, name)
            if d.get('variants'):
                name = name + ' - %s' % (d['variants'], )
            return (d['id'], name)

        partner_id = context.get('partner_id', False)

        result = []
        for product in self.browse(cr, user, ids, context=context):
            sellers = filter(lambda x: x.name.id == partner_id,
                             product.seller_ids)
            if sellers:
                for s in sellers:
                    mydict = {
                        'id': product.id,
                        'name': s.product_name or product.name,
                        'default_code': s.product_code or product.default_code,
                        'variants': product.variants
                    }
                    result.append(_name_get(mydict))
            else:
                mydict = {
                    'id': product.id,
                    'name': product.name,
                    'default_code': product.default_code,
                    'variants': product.variants
                }
                result.append(_name_get(mydict))
        return result

    def name_search(self,
                    cr,
                    user,
                    name='',
                    args=None,
                    operator='ilike',
                    context=None,
                    limit=100):
        if not args:
            args = []
        if name:
            ids = self.search(cr,
                              user, [('default_code', '=', name)] + args,
                              limit=limit,
                              context=context)
            if not len(ids):
                ids = self.search(cr,
                                  user, [('ean13', '=', name)] + args,
                                  limit=limit,
                                  context=context)
            if not len(ids):
                ids = self.search(cr,
                                  user,
                                  [
                                      '|', ('name', operator, name),
                                      ('default_code', operator, name)
                                  ] + args,
                                  limit=limit,
                                  context=context)
            if not len(ids):
                ptrn = re.compile('(\[(.*?)\])')
                res = ptrn.search(name)
                if res:
                    ids = self.search(
                        cr,
                        user, [('default_code', '=', res.group(2))] + args,
                        limit=limit,
                        context=context)
        else:
            ids = self.search(cr, user, args, limit=limit, context=context)
        result = self.name_get(cr, user, ids, context=context)
        return result

    #
    # Could be overrided for variants matrices prices
    #
    def price_get(self, cr, uid, ids, ptype='list_price', context=None):
        if context is None:
            context = {}

        if 'currency_id' in context:
            pricetype_obj = self.pool.get('product.price.type')
            price_type_id = pricetype_obj.search(cr, uid,
                                                 [('field', '=', ptype)])[0]
            price_type_currency_id = pricetype_obj.browse(
                cr, uid, price_type_id).currency_id.id

        res = {}
        product_uom_obj = self.pool.get('product.uom')
        for product in self.browse(cr, uid, ids, context=context):
            res[product.id] = product[ptype] or 0.0
            if ptype == 'list_price':
                res[product.id] = (res[product.id] * (product.price_margin or 1.0)) + \
                        product.price_extra
            if 'uom' in context:
                uom = product.uos_id or product.uom_id
                res[product.id] = product_uom_obj._compute_price(
                    cr, uid, uom.id, res[product.id], context['uom'])
            # Convert from price_type currency to asked one
            if 'currency_id' in context:
                # Take the price_type currency from the product field
                # This is right cause a field cannot be in more than one currency
                res[product.id] = self.pool.get('res.currency').compute(
                    cr,
                    uid,
                    price_type_currency_id,
                    context['currency_id'],
                    res[product.id],
                    context=context)

        return res

    def copy(self, cr, uid, id, default=None, context=None):
        if context is None:
            context = {}

        product = self.read(cr, uid, id, ['name'], context=context)
        if not default:
            default = {}
        default = default.copy()
        default['name'] = product['name'] + _(' (copy)')

        if context.get('variant', False):
            fields = [
                'product_tmpl_id', 'active', 'variants', 'default_code',
                'price_margin', 'price_extra'
            ]
            data = self.read(cr, uid, id, fields=fields, context=context)
            for f in fields:
                if f in default:
                    data[f] = default[f]
            data['product_tmpl_id'] = data.get('product_tmpl_id', False) \
                    and data['product_tmpl_id'][0]
            del data['id']
            return self.create(cr, uid, data)
        else:
            return super(product_product, self).copy(cr,
                                                     uid,
                                                     id,
                                                     default=default,
                                                     context=context)
Example #10
0
class account_invoice(osv.osv):

    _name = "account.invoice"
    _inherit = "account.invoice"
    _description = 'Invoice'

    def _amount_all(self, cr, uid, ids, name, args, context=None):
        res = {}
        for invoice in self.browse(cr, uid, ids, context=context):
            res[invoice.id] = {
                'amount_untaxed': 0.0,
                'amount_tax': 0.0,
                'amount_total': 0.0,
                'add_disc_amt': 0.0,
                'amount_net': 0.0,
            }
            for line in invoice.invoice_line:
                res[invoice.id]['amount_untaxed'] += line.price_subtotal
            res[invoice.id]['add_disc_amt'] = res[
                invoice.id]['amount_untaxed'] * invoice.add_disc / 100
            for line in invoice.tax_line:
                res[invoice.id]['amount_tax'] += line.amount
            res[invoice.id]['amount_net'] = res[
                invoice.id]['amount_untaxed'] - res[invoice.id]['add_disc_amt']
            res[invoice.id]['amount_total'] = res[
                invoice.id]['amount_tax'] + res[invoice.id]['amount_net']
        return res

    _columns = {
        'add_disc':
        fields.float('Additional Discount(%)',
                     digits=(4, 2),
                     readonly=True,
                     states={'draft': [('readonly', False)]}),
        'add_disc_amt':
        fields.function(_amount_all,
                        method=True,
                        digits_compute=dp.get_precision('Sale Price'),
                        string='Additional Disc Amt',
                        store=True,
                        multi='sums',
                        help="The additional discount on untaxed amount."),
        'amount_net':
        fields.function(_amount_all,
                        method=True,
                        digits_compute=dp.get_precision('Sale Price'),
                        string='Net Amount',
                        store=True,
                        multi='sums',
                        help="The amount after additional discount."),
        'amount_untaxed':
        fields.function(_amount_all,
                        method=True,
                        digits_compute=dp.get_precision('Account'),
                        string='Untaxed',
                        store=True,
                        multi='all'),
        'amount_tax':
        fields.function(_amount_all,
                        method=True,
                        digits_compute=dp.get_precision('Account'),
                        string='Tax',
                        store=True,
                        multi='all'),
        'amount_total':
        fields.function(_amount_all,
                        method=True,
                        digits_compute=dp.get_precision('Account'),
                        string='Total',
                        store=True,
                        multi='all'),
    }

    _defaults = {
        'add_disc': 0.0,
    }
Example #11
0
            [('draft', 'Draft'), ('done', 'Done'), ('load', 'Load')],
            string='State', required=True, readonly=True),
        'limit': fields.integer(
            'Limit records', readonly=True,
            states={'draft': [('readonly', False)]},
            help="limit the profit query to this number of record (0 = all)"),
        'name': fields.char(
            'Name', size=64, required=False, readonly=False),
        'date_start': fields.date(
            'From', required=False, select=True),
        'date_end': fields.date(
            'To', required=False, select=True),
        'est_util': fields.boolean(
            'Estimate utls'),
        'force_months': fields.integer(
            'Force months qty', digits_compute=dp.get_precision('Account'),
            help="Set months to be projected (0=auto)"),
        }

    _defaults = {
        'state': lambda *a: 'draft',
        'est_util': lambda *a: True,
        }

    _sql_constraints = [
        ]

    ##-------------------------------------------------------------------------

    ##---------------------------------------------------------- public methods
Example #12
0
class _base_stock_picking(object):
    def onchange_logis_company(self,
                               cr,
                               uid,
                               ids,
                               logistic_company_id,
                               context=None):
        company_code = ''
        if logistic_company_id:
            logistic_company_obj = self.pool.get('logistic.company')
            company_code = logistic_company_obj.read(
                cr,
                uid,
                logistic_company_id, ['ship_company_code'],
                context=context)['ship_company_code']
        res = {'value': {'ship_company_code': company_code}}
        return res

    def init(self, cr):
        cr.execute(
            'alter table stock_picking alter column tot_ship_weight type numeric(16,3)'
        )

    def copy(self, cr, uid, id, default=None, context=None):
        if default is None:
            default = {}
        default['ship_state'] = 'draft'
        res = super(stock_picking, self).copy(cr,
                                              uid,
                                              id,
                                              default,
                                              context=context)
        return res

    def distribute_weight(self, cr, uid, ids, context=None):
        pack_ids_list = self.read(cr,
                                  uid,
                                  ids,
                                  ['packages_ids', 'tot_del_order_weight'],
                                  context=context)
        for pack_ids in pack_ids_list:
            if pack_ids['tot_del_order_weight'] and pack_ids['packages_ids']:
                avg_weight = pack_ids['tot_del_order_weight'] / len(
                    pack_ids['packages_ids'])
                self.pool.get('stock.packages').write(cr,
                                                      uid,
                                                      pack_ids['packages_ids'],
                                                      {'weight': avg_weight},
                                                      context=context)
        return True

    def _total_weight_net(self, cr, uid, ids, field_name, arg, context=None):
        """Compute the total net weight of the given Delivery order."""
        result = {}
        for pick in self.browse(cr, uid, ids, context=context):
            result[pick.id] = 0.0
            for line in pick.packages_ids:
                if line.weight:
                    result[pick.id] += line.weight
        return result

    def _total_ord_weight_net(self,
                              cr,
                              uid,
                              ids,
                              field_name,
                              arg,
                              context=None):
        """Compute the total net weight of the given Delivery order."""
        result = {}
        for pick in self.browse(cr, uid, ids, context=context):
            result[pick.id] = 0.0
            for line in pick.move_lines:
                if line.product_id:
                    result[pick.
                           id] += line.product_qty * line.product_id.weight_net
        return result

    def _get_move_order(self, cr, uid, ids, context=None):
        """Get the picking ids of the given Stock Moves."""
        result = {}
        for line in self.pool.get('stock.move').browse(cr,
                                                       uid,
                                                       ids,
                                                       context=context):
            result[line.picking_id.id] = True
        return result.keys()

    def _get_order(self, cr, uid, ids, context=None):
        """Get the picking ids of the given Stock Packages."""
        result = {}
        for line in self.pool.get('stock.packages').browse(cr,
                                                           uid,
                                                           ids,
                                                           context=None):
            result[line.pick_id.id] = True
        return result.keys()

    def _get_company_code(self, cr, user, context=None):
        return []

    _columns = {
        'logis_company':
        fields.many2one(
            'logistic.company',
            'Logistics Company',
            help='Name of the Logistics company providing the shipper services.'
        ),
        'freight':
        fields.boolean(
            'Shipment',
            help='Indicates if the shipment is a freight shipment.'),
        'sat_delivery':
        fields.boolean(
            'Saturday Delivery',
            help='Indicates is it is appropriate to send delivery on Saturday.'
        ),
        'package_type':
        fields.selection([('01', 'Letter'),
                          ('02', 'Customer Supplied Package'), ('03', 'Tube'),
                          ('04', 'PAK'), ('21', 'ExpressBox'),
                          ('24', '25KG Box'), ('25', '10KG Box'),
                          ('30', 'Pallet'), ('2a', 'Small Express Box'),
                          ('2b', 'Medium Express Box'),
                          ('2c', 'Large Express Box')],
                         'Package Type',
                         help='Indicates the type of package'),
        'bill_shipping':
        fields.selection([('shipper', 'Shipper'), ('receiver', 'Receiver'),
                          ('thirdparty', 'Third Party')],
                         'Bill Shipping to',
                         help='Shipper, Receiver, or Third Party.'),
        'with_ret_service':
        fields.boolean(
            'With Return Services',
            help='Include Return Shipping Information in the package.'),
        'tot_ship_weight':
        fields.function(
            _total_weight_net,
            method=True,
            type='float',
            digits=(16, 3),
            string='Total Shipment Weight',
            store={
                'stock.picking':
                (lambda self, cr, uid, ids, c={}: ids, ['packages_ids'], -10),
                'stock.packages': (_get_order, ['weight'], -10),
            },
            help=
            "Adds the Total Weight of all the packages in the Packages Table.",
        ),
        'tot_del_order_weight':
        fields.function(
            _total_ord_weight_net,
            method=True,
            readonly=True,
            string='Total Order Weight',
            store=False,
            help=
            "Adds the Total Weight of all the packages in the Packages Table."
        ),
        'packages_ids':
        fields.one2many("stock.packages", 'pick_id', 'Packages Table'),
        'ship_state':
        fields.selection([('draft', 'Draft'), ('in_process', 'In Process'),
                          ('ready_pick', 'Ready for Pickup'),
                          ('shipped', 'Shipped'), ('delivered', 'Delivered'),
                          ('void', 'Void'), ('hold', 'Hold'),
                          ('cancelled', 'Cancelled')],
                         'Shipping Status',
                         readonly=True,
                         help='The current status of the shipment'),
        'trade_mark':
        fields.text('Trademarks AREA'),
        'ship_message':
        fields.text('Message'),
        'address_validate':
        fields.selection([('validate', 'Validate'),
                          ('nonvalidate', 'No Validation')],
                         'Address Validation',
                         help=''' No Validation = No address validation.
                                              Validate = Fail on failed address validation.
                                              Defaults to validate. Note: Full address validation is not performed. Therefore, it is
                                              the responsibility of the Shipping Tool User to ensure the address entered is correct to
                                              avoid an address correction fee.'''
                         ),
        'ship_description':
        fields.text('Description'),
        'ship_from':
        fields.boolean(
            'Ship From',
            help=
            'Required if pickup location is different from the shipper\'s address..'
        ),
        'ship_from_tax_id_no':
        fields.char('Identification Number', size=30, select=1),
        'shipcharge':
        fields.float('Shipping Cost', readonly=True),
        'ship_from_address':
        fields.many2one('res.partner', 'Ship From Address', size=30),
        #         'address': fields.many2one('res.partner', 'Ship From Address'),
        'tot_order_weight':
        fields.related('sale_id',
                       'total_weight_net',
                       type='float',
                       relation='sale.order',
                       string='Total Order Weight'),
        'comm_inv':
        fields.boolean('Commercial Invoice'),
        'cer_orig':
        fields.boolean('U.S. Certificate of Origin'),
        'nafta_cer_orig':
        fields.boolean('NAFTA Certificate of Origin'),
        'sed':
        fields.boolean('Shipper Export Declaration (SED)'),
        'prod_option':
        fields.selection([('01', 'AVAILABLE TO CUSTOMS UPON REQUEST'),
                          ('02', 'SAME AS EXPORTER'), ('03', 'ATTACHED LIST'),
                          ('04', 'UNKNOWN'), (' ', ' ')], 'Option'),
        'prod_company':
        fields.char(
            'CompanyName',
            size=256,
            help='Only applicable when producer option is empty or not present.'
        ),
        'prod_tax_id_no':
        fields.char(
            'TaxIdentificationNumber',
            size=256,
            help='Only applicable when producer option is empty or not present.'
        ),
        'prod_address_id':
        fields.many2one(
            'res.partner',
            'Producer Address',
            help='Only applicable when producer option is empty or not present.'
        ),
        'inv_option':
        fields.selection([('01', 'Unknown'), ('02', 'Various'), (' ', ' ')],
                         'Sold to Option'),
        'inv_company':
        fields.char(
            'CompanyName',
            size=256,
            help='Only applicable when Sold to option is empty or not present.'
        ),
        'inv_tax_id_no':
        fields.char(
            'TaxIdentificationNumber',
            size=256,
            help='Only applicable when Sold to option is empty or not present.'
        ),
        'inv_att_name':
        fields.char(
            'AttentionName',
            size=256,
            help='Only applicable when Sold to option is empty or not present.'
        ),
        'inv_address_id':
        fields.many2one(
            'res.partner',
            'Sold To Address',
            help='Only applicable when Sold to option is empty or not present.'
        ),
        'blanket_begin_date':
        fields.date('Blanket Begin Date'),
        'blanket_end_date':
        fields.date('Blanket End Date'),
        'comm_code':
        fields.char(
            'Commodity Code',
            size=256,
        ),
        'exp_carrier':
        fields.char('ExportingCarrier', size=256),
        'ship_company_code':
        fields.selection(_get_company_code,
                         'Ship Company',
                         method=True,
                         size=64),
        'ship_charge':
        fields.float('Value', digits_compute=dp.get_precision('Account'))
    }

    _defaults = {
        'address_validate': 'nonvalidate',
        'comm_inv': False,
        'cer_orig': False,
        'nafta_cer_orig': False,
        'sed': False,
        'ship_state': 'draft',
        'bill_shipping': 'shipper',
        'ship_charge': 0.0
    }

    def process_ship(self, cr, uid, ids, context=None):
        return True

    def print_labels(self, cr, uid, ids, context=None):
        if not ids: return []
        return {
            'type': 'ir.actions.report.xml',
            'report_name': 'multiple.label.print',
            'datas': {
                'model': 'stock.picking',
                'id': ids and ids[0] or False,
                'ids': ids,
                'report_type': 'pdf'
            },
            'nodestroy': True
        }

    def print_packing_slips(self, cr, uid, ids, context=None):
        if not ids: return []
        packages_ids = []
        for package in self.browse(cr, uid, ids[0]).packages_ids:
            packages_ids.append(package.id)
        return {
            'type': 'ir.actions.report.xml',
            'report_name': 'package.packing.slip.print',
            'datas': {
                'model': 'stock.packages',
                'id': ids and ids[0] or False,
                'ids': packages_ids,
                'report_type': 'pdf'
            },
            'nodestroy': True
        }

    def process_void(self, cr, uid, ids, context=None):
        picking_pool = self.pool.get('stock.picking')
        packages_pool = self.pool.get('stock.packages')
        return packages_pool.cancel_postage(
            cr,
            uid, [
                package.id for order in picking_pool.browse(cr, uid, ids)
                for package in order.packages_ids
            ],
            context=context)

    def _get_account_analytic_invoice(self, cursor, user, picking, move_line):
        partner_id = picking.partner_id and picking.partner_id.id or False
        analytic_obj = self.pool.get('account.analytic.default')
        rec = analytic_obj.account_get(cursor,
                                       user,
                                       move_line.product_id.id,
                                       partner_id,
                                       user,
                                       time.strftime('%Y-%m-%d'),
                                       context={})
        if rec:
            return rec.analytic_id.id
        return super(stock_picking, self)._get_account_analytic_invoice(
            cursor, user, picking, move_line)

    def send_conf_mail(self, cr, uid, ids, context=None):
        for id in ids:
            obj = self.browse(cr, uid, id)
            if obj and obj.address_id and obj.address_id.email:
                email_temp_obj = self.pool.get('email.template')
                template_id = email_temp_obj.search(
                    cr,
                    uid, [('object_name.model', '=', 'stock.picking'),
                          ('ship_mail', '=', True)],
                    context=context)
                if template_id:
                    template_obj_list = email_temp_obj.browse(
                        cr, uid, template_id)
                    for template_obj in template_obj_list:
                        subj = self.get_value(obj, template_obj,
                                              'def_subject') or ''
                        vals = {
                            'email_to':
                            self.get_value(cr, uid, obj, template_obj.def_to,
                                           context) or '',
                            'body_text':
                            self.get_value(cr, uid, obj,
                                           template_obj.def_body_text) or '',
                            'body_html':
                            self.get_value(cr, uid, obj,
                                           template_obj.def_body_html) or '',
                            'account_id':
                            template_obj.from_account.id,
                            'folder':
                            'outbox',
                            'state':
                            'na',
                            'subject':
                            self.get_value(cr, uid, obj,
                                           template_obj.def_subject) or '',
                            'email_cc':
                            self.get_value(cr, uid, obj, template_obj.def_cc)
                            or '',
                            'email_bcc':
                            self.get_value(cr, uid, obj, template_obj.def_bcc)
                            or '',
                            'email_from':
                            template_obj.from_account.email_id or '',
                            'reply_to':
                            self.get_value(cr, uid, obj, template_obj.reply_to)
                            or '',
                            'date_mail':
                            time.strftime('%Y-%m-%d %H:%M:%S'),
                        }
                        if vals['email_to'] and vals['account_id']:
                            mail_id = self.pool.get(
                                'email_template.mailbox').create(
                                    cr, uid, vals, context=context)
                            data = {}
                            data['model'] = 'stock.picking'
                            if template_obj.report_template:
                                reportname = 'report.' + self.pool.get(
                                    'ir.actions.report.xml').read(
                                        cr,
                                        uid,
                                        template_obj.report_template.id,
                                        ['report_name'],
                                        context=context)['report_name']
                                service = netsvc.LocalService(reportname)
                                (result,
                                 format) = service.create(cr,
                                                          uid, [id],
                                                          data,
                                                          context=context)
                                email_temp_obj._add_attachment(
                                    cr,
                                    uid,
                                    mail_id,
                                    subj,
                                    base64.b64encode(result),
                                    template_obj.file_name or 'Order.pdf',
                                    context=context)
        return True
    def split(self, cr, uid, ids, move_ids, context=None):
        #~ """ To split stock moves into production lot
        #~ @param self: The object pointer.
        #~ @param cr: A database cursor
        #~ @param uid: ID of the user currently logged in
        #~ @param ids: the ID or list of IDs if we want more than one
        #~ @param move_ids: the ID or list of IDs of stock move we want to split
        #~ @param context: A standard dictionary
        #~ @return:
        #~ """
        check_aux = True
        if context is None:
            context = {}
        inventory_id = context.get('inventory_id', False)
        prodlot_obj = self.pool.get('stock.production.lot')
        inventory_obj = self.pool.get('stock.inventory')
        move_obj = self.pool.get('stock.move')
        new_move = []

        for data in self.browse(cr, uid, ids, context=context):

            check = self.check_serial(cr, uid, ids, data, context=context)

            if check:
                raise osv.except_osv(_("User Error"), _(
                    "These serial has already been used \n%s") % check)

            for move in move_obj.browse(cr, uid, move_ids, context=context):
                move_qty = move.product_qty
                quantity_rest = move.product_qty
                uos_qty_rest = move.product_uos_qty
                new_move = []
                total_move_qty = 0.0
                psm = data.psm
                if psm:
                    lines = psm.split('\n')
                    lines = list(set(lines))
                    if '' in lines:
                        lines.remove('')
                else:
                    lines = []

                for line in lines:
                    if move.product_id.track_serial_incoming and move.product_id.track_serial_outgoing and move.picking_id.type == 'out':
                        spl_ids = prodlot_obj.search(cr, uid, [(
                            'product_id', '=', move.product_id.id), ('name', '=', line)])
                        if len(spl_ids) < 1:
                            raise osv.except_osv(_('Error !'), _(
                                'This serial %s is not exist') % line)

                if move.picking_id.type == "in":
                    self.track_serial_incoming(
                        cr, uid, ids, data.product_id.id, lines, context=context)
                    check_aux = False

                for line in lines:
                    quantity = 1
                    total_move_qty += quantity
                    if total_move_qty > move_qty:
                        precision = '%0.' + str(dp.get_precision(
                            'Product UoM')(cr)[1] or 0) + 'f'
                        raise osv.except_osv(_('Processing Error'), _('Processing quantity %s for %s is larger than the available quantity %s!')
                                             % (precision % total_move_qty, move.product_id.name, precision % move_qty))
                    if quantity <= 0 or move_qty == 0:
                        continue
                    quantity_rest -= quantity
                    uos_qty = quantity / move_qty * move.product_uos_qty
                    uos_qty_rest = quantity_rest / \
                        move_qty * move.product_uos_qty
                    if quantity_rest < 0:
                        quantity_rest = quantity
                        break
                    default_val = {
                        'product_qty': quantity,
                        'product_uos_qty': uos_qty,
                        'state': move.state
                    }
                    if quantity_rest > 0:
                        current_move = move_obj.copy(
                            cr, uid, move.id, default_val, context=context)
                        if inventory_id and current_move:
                            inventory_obj.write(cr, uid, inventory_id, {
                                                'move_ids': [(4, current_move)]}, context=context)
                        new_move.append(current_move)

                    if quantity_rest == 0:
                        current_move = move.id

                    picking = self.pool.get('stock.move').browse(cr, uid, context.get(
                        'active_ids'), context=context)[0].picking_id

                    if picking.type == 'out':

                        spl_id = prodlot_obj.search(cr, uid, [(
                            'product_id', '=', move.product_id.id), ('name', '=', line)])
                        if spl_id:
                            prodlot_obj.write(cr, uid, [spl_id], {'check_serial': True, 'ref':  self.pool.get(
                                'ir.sequence').get(cr, uid, 'psm.stock.production.lot')+':'+picking.name})

                            prodlot_brw = prodlot_obj.browse(
                                cr, uid, [spl_id], context=context)[0]

                            if not prodlot_brw.check_serial:

                                prodlot_id = prodlot_brw.id
                            else:
                                raise osv.except_osv(_('Error !'), _(
                                    'These serial already by used in other outgoing picking %s ') % '\n'.join(res))
                        else:
                            prodlot_id = False
                            if not prodlot_id:
                                picking = self.pool.get('stock.move').browse(cr, uid, context.get(
                                    'active_ids'), context=context)[0].picking_id
                                prodlot_id = prodlot_obj.create(cr, uid, {
                                    'name': line,
                                    'product_id': move.product_id.id,
                                    'ref':  self.pool.get('ir.sequence').get(cr, uid, 'psm.stock.production.lot')+':'+picking.name,
                                    'check_serial': check_aux,
                                    'company_id': picking.company_id.id,
                                }, context=context)
                    else:
                        prodlot_id = False
                        if not prodlot_id:
                            picking = self.pool.get('stock.move').browse(cr, uid, context.get(
                                'active_ids'), context=context)[0].picking_id
                            prodlot_id = prodlot_obj.create(cr, uid, {
                                'name': line,
                                'product_id': move.product_id.id,
                                'ref':  self.pool.get('ir.sequence').get(cr, uid, 'psm.stock.production.lot')+':'+picking.name,
                                'check_serial': check_aux,
                                'company_id': picking.company_id.id,
                            }, context=context)

                    move_obj.write(cr, uid, [current_move], {
                                   'prodlot_id': prodlot_id, 'state': move.state})

                    update_val = {}
                    if quantity_rest > 0:
                        update_val['product_qty'] = quantity_rest
                        update_val['product_uos_qty'] = uos_qty_rest
                        update_val['state'] = move.state
                        move_obj.write(cr, uid, [move.id], update_val)

        return new_move
class change_standard_price(osv.osv_memory):
    _name = "stock.change.standard.price"
    _description = "Change Standard Price"
    _columns = {
        'new_price':
        fields.float(
            'Price',
            required=True,
            digits_compute=dp.get_precision('Account'),
            help=
            "If cost price is increased, stock variation account will be debited "
            "and stock output account will be credited with the value = (difference of amount * quantity available).\n"
            "If cost price is decreased, stock variation account will be creadited and stock input account will be debited."
        ),
        'stock_account_input':
        fields.many2one('account.account', 'Stock Input Account'),
        'stock_account_output':
        fields.many2one('account.account', 'Stock Output Account'),
        'stock_journal':
        fields.many2one('account.journal', 'Stock journal', required=True),
        'enable_stock_in_out_acc':
        fields.boolean('Enable Related Account', ),
    }

    def default_get(self, cr, uid, fields, context=None):
        """ To get default values for the object.
         @param self: The object pointer.
         @param cr: A database cursor
         @param uid: ID of the user currently logged in
         @param fields: List of fields for which we want default values
         @param context: A standard dictionary
         @return: A dictionary which of fields with values.
        """
        if context is None:
            context = {}
        product_pool = self.pool.get('product.product')
        product_obj = product_pool.browse(cr, uid,
                                          context.get('active_id', False))
        res = super(change_standard_price, self).default_get(cr,
                                                             uid,
                                                             fields,
                                                             context=context)

        accounts = product_pool.get_product_accounts(cr,
                                                     uid,
                                                     context.get(
                                                         'active_id', False),
                                                     context={})

        price = product_obj.standard_price

        if 'new_price' in fields:
            res.update({'new_price': price})
        if 'stock_account_input' in fields:
            res.update(
                {'stock_account_input': accounts['stock_account_input']})
        if 'stock_account_output' in fields:
            res.update(
                {'stock_account_output': accounts['stock_account_output']})
        if 'stock_journal' in fields:
            res.update({'stock_journal': accounts['stock_journal']})
        if 'enable_stock_in_out_acc' in fields:
            res.update({'enable_stock_in_out_acc': True})

        return res

    # onchange_price function is not used anywhere
    def onchange_price(self, cr, uid, ids, new_price, context=None):
        """ Sets stock input and output account according to the difference
            of old price and new price.
        @param self: The object pointer.
        @param cr: A database cursor
        @param uid: ID of the user currently logged in
        @param ids: List of IDs selected
        @param new_price: Changed price
        @param context: A standard dictionary
        @return: Dictionary of values
        """
        if context is None:
            context = {}
        product_obj = self.pool.get('product.product').browse(cr,
                                                              uid,
                                                              context.get(
                                                                  'active_id',
                                                                  False),
                                                              context=context)
        price = product_obj.standard_price
        diff = price - new_price
        if diff > 0:
            return {'value': {'enable_stock_in_out_acc': True}}
        else:
            return {'value': {'enable_stock_in_out_acc': False}}

    def change_price(self, cr, uid, ids, context=None):
        """ Changes the Standard Price of Product.
            And creates an account move accordingly.
        @param self: The object pointer.
        @param cr: A database cursor
        @param uid: ID of the user currently logged in
        @param ids: List of IDs selected
        @param context: A standard dictionary
        @return:
        """
        if context is None:
            context = {}
        rec_id = context and context.get('active_id', False)
        assert rec_id, _('Active ID is not set in Context')
        prod_obj = self.pool.get('product.product')
        res = self.browse(cr, uid, ids, context=context)
        datas = {
            'new_price': res[0].new_price,
            'stock_output_account': res[0].stock_account_output.id,
            'stock_input_account': res[0].stock_account_input.id,
            'stock_journal': res[0].stock_journal.id
        }
        prod_obj.do_change_standard_price(cr, uid, [rec_id], datas, context)
        return {'type': 'ir.actions.act_window_close'}
Example #15
0
class change_production_qty(osv.osv_memory):
    _name = 'change.production.qty'
    _description = 'Change Quantity of Products'

    _columns = {
        'product_qty':
        fields.float('Product Qty',
                     digits_compute=dp.get_precision('Product UoM'),
                     required=True),
    }

    def default_get(self, cr, uid, fields, context=None):
        """ To get default values for the object.
        @param self: The object pointer.
        @param cr: A database cursor
        @param uid: ID of the user currently logged in
        @param fields: List of fields for which we want default values 
        @param context: A standard dictionary 
        @return: A dictionary which of fields with values. 
        """
        if context is None:
            context = {}
        res = super(change_production_qty, self).default_get(cr,
                                                             uid,
                                                             fields,
                                                             context=context)
        prod_obj = self.pool.get('mrp.production')
        prod = prod_obj.browse(cr,
                               uid,
                               context.get('active_id'),
                               context=context)
        if 'product_qty' in fields:
            res.update({'product_qty': prod.product_qty})
        return res

    def _update_product_to_produce(self, cr, uid, prod, qty, context=None):
        move_lines_obj = self.pool.get('stock.move')
        for m in prod.move_created_ids:
            move_lines_obj.write(cr, uid, [m.id], {'product_qty': qty})

    def change_prod_qty(self, cr, uid, ids, context=None):
        """ 
        Changes the Quantity of Product.
        @param self: The object pointer.
        @param cr: A database cursor
        @param uid: ID of the user currently logged in
        @param ids: List of IDs selected 
        @param context: A standard dictionary 
        @return:
        """
        record_id = context and context.get('active_id', False)
        assert record_id, _('Active Id is not found')
        prod_obj = self.pool.get('mrp.production')
        bom_obj = self.pool.get('mrp.bom')
        for wiz_qty in self.browse(cr, uid, ids, context=context):
            prod = prod_obj.browse(cr, uid, record_id, context=context)
            prod_obj.write(cr, uid, prod.id,
                           {'product_qty': wiz_qty.product_qty})
            prod_obj.action_compute(cr, uid, [prod.id])
            move_lines = prod.move_lines
            move_lines.extend(prod.picking_id.move_lines)

            move_lines_obj = self.pool.get('stock.move')
            for move in move_lines:
                bom_point = prod.bom_id
                bom_id = prod.bom_id.id
                if not bom_point:
                    bom_id = bom_obj._bom_find(cr, uid, prod.product_id.id,
                                               prod.product_uom.id)
                    if not bom_id:
                        raise osv.except_osv(
                            _('Error'),
                            _("Couldn't find bill of material for product"))
                    prod_obj.write(cr, uid, [prod.id], {'bom_id': bom_id})
                    bom_point = bom_obj.browse(cr, uid, [bom_id])[0]

                if not bom_id:
                    raise osv.except_osv(
                        _('Error'),
                        _("Couldn't find bill of material for product"))

                factor = prod.product_qty * prod.product_uom.factor / bom_point.product_uom.factor
                res = bom_obj._bom_explode(cr, uid, bom_point,
                                           factor / bom_point.product_qty, [])
                for r in res[0]:
                    if r['product_id'] == move.product_id.id:
                        move_lines_obj.write(cr, uid, [move.id],
                                             {'product_qty': r['product_qty']})
            self._update_product_to_produce(cr,
                                            uid,
                                            prod,
                                            wiz_qty.product_qty,
                                            context=context)

        return {}
import time

from osv import osv, fields
import decimal_precision as dp

FISCAL_RULE_COLUMNS = {
                       'partner_fiscal_type_id': fields.many2one('l10n_br_account.partner.fiscal.type', 
                                                                 'Tipo Fiscal do Parceiro'),
                       'fiscal_operation_category_id': fields.many2one('l10n_br_account.fiscal.operation.category', 
                                                                       'Categoria', requeried=True),
                       'fiscal_type': fields.selection([('1', 'Simples Nacional'), 
                                                        ('2', 'Simples Nacional – excesso de sublimite de receita bruta'), 
                                                        ('3', 'Regime Normal')], 
                                                       'Regime Tributário', required=True),
                       'revenue_start': fields.float('Faturamento Inicial',
                                                     digits_compute=dp.get_precision('Account'),
                                                     help="Faixa inicial de faturamento bruto"),
                       'revenue_end': fields.float('Faturamento Final',
                                                   digits_compute=dp.get_precision('Account'),
                                                   help="Faixa inicial de faturamento bruto"),}

FISCAL_RULE_DEFAULTS = {
                        'fiscal_type': '3',
                        'revenue_start': 0.00,
                        'revenue_end': 0.00,}

class account_fiscal_position_rule_template(osv.osv):
    _inherit = 'account.fiscal.position.rule.template'
    _columns = FISCAL_RULE_COLUMNS
    _defaults = FISCAL_RULE_DEFAULTS
Example #17
0
    def check_partite(self,cr,uid,ids,context=False):        
        res = False
        if ids:
            for move in self.browse(cr,uid,ids):                             
                if move.flag_partite=='C':
                    #deve creare una partita                 
                    for move_line in move.line_id:                       
                       conto = False
                     #  import pdb;pdb.set_trace()
                       if (not move_line.partita_id) and (not move_line.par_saldi):
                        if move.flag_cliente:
                            if move_line.partner_id.property_account_receivable:
                                conto = move_line.partner_id.property_account_receivable.id
                            else:
                                raise osv.except_osv(_('Errore !'), _('Partita Non Creata Per assenza del Pagamento sulla riga del Partner ' + move_line.partner_id.ref ))
                        if move.flag_fornitore:
                            conto = move_line.partner_id.property_account_payable.id
                        if conto == move_line.account_id.id:
                            # è la riga del cliente
                            if move_line.pagamento_id:
                                importo = float(abs(move_line.credit-move_line.debit))
                                testa = {
                                         'riga_reg_pnt':move_line.id,
                                         'reg_pnt':move.id,
                                         'num_reg': move.ref,
                                         'data_reg': move.date,
                                         'tipo_documento': move.tipo_documento,
                                         'numero_doc':move.numero_doc,
                                         'data_doc':move.data_doc,
                                         'partner_id': move_line.partner_id.id,
                                         'pagamento_id':move_line.pagamento_id.id,
                                         'totale_partita':arrot(cr,uid,importo,dp.get_precision('Account')),
                                         }
                                id_testa_par = self.pool.get('account.partite').create(cr,uid,testa)                           
                                scadenze = self.pool.get('account.payment.term').compute(cr, uid, move_line.pagamento_id.id,importo, move.data_doc, context)
                                if scadenze:
                                    for scadenza in scadenze:
                                        riga_scad = {
                                                     'name':id_testa_par,                                                     
                                                     'data_scadenza':scadenza[0],
                                                     'importo':arrot(cr,uid,scadenza[1],dp.get_precision('Account')),
                                                     }
                                        res = self.pool.get('account.partite_scadenze').create(cr, uid, riga_scad)
                                #import pdb;pdb.set_trace()
                                ok = self.pool.get('account.partite').write(cr,uid,id_testa_par,testa)
                                ok = self.pool.get('account.move.line').write(cr,uid,[move_line.id],{'partita_id':id_testa_par})        
                            else:
                                raise osv.except_osv(_('Errore !'), _('Partita Non Creata Per assenza del Pagamento sulla riga del Partner'))
                                            
                if move.flag_partite=='S':
                    # TO DO deve lanciare un wizard per saldare ci proviamo a lanciare una action e vediamo
                            #import pdb;pdb.set_trace()
                            #raise osv.except_osv(_('Errore !'), _('Non è Possibile Saldare le Partite Collegate Usare la Funzione SaldaConto'))
                            #return True
                            pass
#                            return {
#                                    'name': 'Saldaconto Partner',
#                                    'view_type': 'form',
#                                    'view_mode': 'form',
#                                    'res_model': 'salda.partite',
#                                    'type': 'ir.actions.act_window',
#                                    'target': 'new',
#                                    'context': context
#                                    }
        return res
Example #18
0
    def get_out(self, cr, uid, ids, context=None):

        """
         Create the entries in the CashBox   .
         @param self: The object pointer.
         @param cr: A database cursor
         @param uid: ID of the user currently logged in
         @param context: A standard dictionary
         @return :Return of operation of product
        """
        vals = {}
        statement_obj = self.pool.get('account.bank.statement')
        statement_line_obj = self.pool.get('account.bank.statement.line')
        product_obj = self.pool.get('product.template')
        productp_obj = self.pool.get('product.product')
        res_obj = self.pool.get('res.users')
        for data in  self.read(cr, uid, ids, context=context):
            curr_company = res_obj.browse(cr, uid, uid, context=context).company_id.id
            statement_id = statement_obj.search(cr, uid, [('journal_id', '=', data['journal_id']), ('company_id', '=', curr_company), ('user_id', '=', uid), ('state', '=', 'open')], context=context)
            monday = (datetime.today() + relativedelta(weekday=0)).strftime('%Y-%m-%d')
            sunday = (datetime.today() + relativedelta(weekday=6)).strftime('%Y-%m-%d')
            done_statmt = statement_obj.search(cr, uid, [('date', '>=', monday+' 00:00:00'), ('date', '<=', sunday+' 23:59:59'), ('journal_id', '=', data['journal_id']), ('company_id', '=', curr_company), ('user_id', '=', uid)], context=context)
            stat_done = statement_obj.browse(cr, uid, done_statmt, context=context)
            address_u = res_obj.browse(cr, uid, uid, context=context).address_id
            am = 0.0

            amount_check = productp_obj.browse(cr, uid, data['product_id'], context=context).am_out or False
            for st in stat_done:
                for s in st.line_ids:
                    if address_u and s.partner_id == address_u.partner_id and s.am_out:
                        am += s.amount
            if (-data['amount'] or 0.0) + am < -(res_obj.browse(cr, uid, uid, context=context).company_id.max_diff or 0.0) and amount_check:
                val = (res_obj.browse(cr, uid, uid).company_id.max_diff or 0.0) + am
                precision = '%0.' + str(dp.get_precision('Point Of Sale Discount')(cr)[1] or 0) + 'f'
                raise osv.except_osv(_('Error !'), _('The maximum value you can still withdraw is exceeded. \n Remaining value is equal to %s') % (precision % val,))

            acc_id = product_obj.browse(cr, uid, data['product_id'], context=context).property_account_income
            if not acc_id:
                raise osv.except_osv(_('Error !'), _('please check that account is set to %s')%(product_obj.browse(cr, uid, data['product_id'], context=context).name))
            if not statement_id:
                raise osv.except_osv(_('Error !'), _('You have to open at least one cashbox'))
            if statement_id:
                statement_id = statement_id[0]
            if not statement_id:
                statement_id = statement_obj.create(cr, uid, {
                                    'date': time.strftime('%Y-%m-%d 00:00:00'),
                                    'journal_id': data['journal_id'],
                                    'company_id': curr_company,
                                    'user_id': uid,
                                }, context=context)
            vals['statement_id'] = statement_id
            vals['journal_id'] = data['journal_id']
            if acc_id:
                vals['account_id'] = acc_id.id
            amount = data['amount'] or 0.0
            if data['amount'] > 0:
                amount = -data['amount']
            vals['amount'] = amount
            if productp_obj.browse(cr, uid, data['product_id'], context=context).am_out:
                vals['am_out'] = True
            vals['ref'] = data['ref'] or ''
            vals['name'] = "%s: %s " % (product_obj.browse(cr, uid, data['product_id'], context=context).name, data['name'].decode('utf8'))
            address_u = res_obj.browse(cr, uid, uid, context=context).address_id
            if address_u:
                vals['partner_id'] = address_u.partner_id and address_u.partner_id.id or None
            statement_line_obj.create(cr, uid, vals, context=context)
        return {}
Example #19
0
    def split(self, cr, uid, ids, move_ids, context=None):
        """ To split stock moves into production lot
        @param self: The object pointer.
        @param cr: A database cursor
        @param uid: ID of the user currently logged in
        @param ids: the ID or list of IDs if we want more than one
        @param move_ids: the ID or list of IDs of stock move we want to split
        @param context: A standard dictionary
        @return:
        """
        if context is None:
            context = {}
        inventory_id = context.get('inventory_id', False)
        prodlot_obj = self.pool.get('stock.production.lot')
        inventory_obj = self.pool.get('stock.inventory')
        move_obj = self.pool.get('stock.move')
        new_move = []
        for data in self.browse(cr, uid, ids, context=context):
            for move in move_obj.browse(cr, uid, move_ids, context=context):
                move_qty = move.product_qty
                quantity_rest = move.product_qty
                uos_qty_rest = move.product_uos_qty
                new_move = []
                if data.use_exist:
                    lines = [l for l in data.line_exist_ids if l]
                else:
                    lines = [l for l in data.line_ids if l]
                total_move_qty = 0.0
                for line in lines:
                    quantity = line.quantity
                    total_move_qty += quantity
                    if total_move_qty > move_qty:
                        precision = '%0.' + str(dp.get_precision('Product UoM')(cr)[1] or 0) + 'f'
                        raise osv.except_osv(_('Processing Error'), _('Processing quantity %s for %s is larger than the available quantity %s!')\
                                     % (precision % total_move_qty, move.product_id.name, precision % move_qty))
                    if quantity <= 0 or move_qty == 0:
                        continue
                    quantity_rest -= quantity
                    uos_qty = quantity / move_qty * move.product_uos_qty
                    uos_qty_rest = quantity_rest / move_qty * move.product_uos_qty
                    if quantity_rest < 0:
                        quantity_rest = quantity
                        break
                    default_val = {
                        'product_qty': quantity,
                        'product_uos_qty': uos_qty,
                        'state': move.state
                    }
                    if quantity_rest > 0:
                        current_move = move_obj.copy(cr, uid, move.id, default_val, context=context)
                        if inventory_id and current_move:
                            inventory_obj.write(cr, uid, inventory_id, {'move_ids': [(4, current_move)]}, context=context)
                        new_move.append(current_move)

                    if quantity_rest == 0:
                        current_move = move.id
                    prodlot_id = False
                    if data.use_exist:
                        prodlot_id = line.prodlot_id.id
                    if not prodlot_id:
                        prodlot_id = prodlot_obj.create(cr, uid, {
                            'name': line.name,
                            'product_id': move.product_id.id},
                        context=context)

                    move_obj.write(cr, uid, [current_move], {'prodlot_id': prodlot_id, 'state':move.state})

                    update_val = {}
                    if quantity_rest > 0:
                        update_val['product_qty'] = quantity_rest
                        update_val['product_uos_qty'] = uos_qty_rest
                        update_val['state'] = move.state
                        move_obj.write(cr, uid, [move.id], update_val)

        return new_move
    def importa(self, cr, uid, ids, context=None):

        FinoaData = self.browse(cr, uid, ids)[0].a_data_doc
        Scadobj = self.pool.get("fiscaldoc.scadenze")
        FatObj = self.pool.get("fiscaldoc.header")
        # import pdb;pdb.set_trace()
        filtro1 = [("tipo_documento", "in", ("FA", "FI", "FD"))]
        idsTipoDoc = self.pool.get("fiscaldoc.causalidoc").search(cr, uid, filtro1)
        idsTipoDoc = tuple(idsTipoDoc)
        filtro = [("data_documento", "<=", FinoaData), ("tipo_doc", "in", idsTipoDoc)]
        idsFat = tuple(FatObj.search(cr, uid, filtro))  # PRENDE TUTTI I DOCUMENTI FINO ALLA DATA INTERESSATA ghfg
        filtro = [
            ("name", "in", idsFat),
            ("effetto_scadenza_id", "=", ""),
            ("tipo_scadenza", "=", "RB"),
            ("generato_effetto", "=", False),
        ]
        idsScad = Scadobj.search(cr, uid, filtro)
        ids_effetti = []
        if idsScad:
            for scad_id in idsScad:
                Scadenzabrw = Scadobj.browse(cr, uid, [scad_id])[0]
                if (
                    not Scadenzabrw.name.partner_id.raggruppa_riba
                ):  # se il partner raggruppa gli effetti ragiona diversamente
                    NumEff = self.pool.get("ir.sequence").get(cr, uid, "effetti")
                    if Scadenzabrw.name.banca_patner.id:
                        TestaEffetto = {
                            "name": NumEff,
                            "data_scadenza": Scadenzabrw.data_scadenza,
                            "cliente_id": Scadenzabrw.name.partner_id.id,
                            "banca_patner": Scadenzabrw.name.banca_patner.id,
                            "note": "Doc.N " + str(Scadenzabrw.name.numdoc) + "Del " + Scadenzabrw.name.data_documento,
                            "importo_effetto": arrot(
                                cr, uid, Scadenzabrw.importo_scadenza, dp.get_precision("Account")
                            ),
                        }
                        idHeadEffetto = self.pool.get("effetti").create(cr, uid, TestaEffetto)
                        ids_effetti.append(idHeadEffetto)
                        RigaEffetto = {
                            "name": idHeadEffetto,
                            "scadenza_id": Scadenzabrw.id,
                            "numero_doc": Scadenzabrw.name.name,
                            "importo_scadenza": Scadenzabrw.importo_scadenza,
                            "data_documento": Scadenzabrw.name.data_documento,
                            "totale_documento": arrot(
                                cr, uid, Scadenzabrw.name.totale_documento, dp.get_precision("Account")
                            ),
                            "pagamento": Scadenzabrw.name.pagamento_id.id,
                        }
                        idRigaScadEff = self.pool.get("effetti.scadenze").create(cr, uid, RigaEffetto)
                        ok = self.pool.get("effetti").write(cr, uid, idHeadEffetto, TestaEffetto)
                        for scad_eff in self.pool.get("effetti").browse(cr, uid, idHeadEffetto).righe_scadenze:
                            ok = Scadobj.write(
                                cr,
                                uid,
                                scad_eff.scadenza_id.id,
                                {"effetto_scadenza_id": scad_eff.id, "generato_effetto": True},
                            )
                    else:
                        raise osv.except_osv(_("ERRORE !"), _("Banca Assente sul documento " + Scadenzabrw.name.name))

                else:
                    # TO DO deve raggruppare l'effetto su + scadenze
                    filtro = [("data_scadenza", "", Scadenzabrw.data_scadenza), ("cliente_id", "", "isnull")]
                    pass
                """ Verifica che non esista già un effetto non presentato con la stessa scadenza 
                se non  esiste crea l'effetto altrimenti aggiunge solo la scadenza e ne ricaolcola il totale effetto  """
            pass
        else:
            raise osv.except_osv(_("ERRORE !"), _("NON SONO STATI TROVATI EFFETTI DA IMPORTARE"))
        # return {'type': 'ir.actions.act_window_close'}    # non va bene deve aprire la finestra degli effetti
        return {
            "name": _("Effetti"),
            "view_type": "form",
            "view_mode": "tree,form",
            "res_model": "effetti",
            "res_id": ids_effetti,
            "view_id": False,
            "context": context,
            "type": "ir.actions.act_window",
        }
    def scrive_account_move_line(self,cr, uid,move_head,doc, context):
        
        def default_riga(move_head,doc):
            riga = {
                    'name': move_head.ref,
                    'period_id':move_head.period_id.id,
                    'journal_id':move_head.journal_id.id,
                    'partner_id':doc.partner_id.id,
                    'move_id':move_head.id,
                    'date':move_head.date,
                    'ref':move_head.ref,
                    'causale_id':move_head.causale_id.id,                    
                    }
            return riga
        
        def cerca_controp(riga_doc):
            conto_id = False
            if riga_doc.contropartita:
                conto_id= riga_doc.contropartita.id
            elif riga_doc.product_id.categ_id.property_account_income_categ:
                conto_id = riga_doc.product_id.categ_id.property_account_income_categ.id
            return conto_id
        
        
        testo_log = """ """
        flag_scritto= True
        # ora cicla sulle righe documento, ma deve riportarsi gli sconti di testata.
        # spese diverse 
        ids_controp = self.pool.get('controp.costi.ricavi').search(cr,uid,[])
        if ids_controp:
            controp_obj= self.pool.get('controp.costi.ricavi').browse(cr,uid,ids_controp[0])
        else:
            raise osv.except_osv(_('ERRORE !'), _('NON SONO DEFINITE LE CONTROPARTITE COSTI E RICAVI '))
            flag_scritto= False
        if doc.spese_imballo:
                     riga = default_riga(move_head,doc)
                     if doc.tipo_documento=="NC":
                         segno = "DA"
                     else:
                        segno = "AV"       
                     if segno=="DA":
                        #segno dare
                        riga['credit']=0
                        riga['debit']=doc.spese_imballo     
                     else:
                        #segno dare
                        riga['credit']=doc.spese_imballo     
                        riga['debit']=0
                     riga['account_id']= controp_obj.conto_v_sp_imballo.id
                     #import pdb;pdb.set_trace()
                     print "riga spese imballo ", riga
                     id_riga = self.pool.get('account.move.line').create(cr,uid,riga) # RIGA IMBALLO
                     if not id_riga:
                         flag_scritto= False
            
        if doc.spese_incasso:
                     riga = default_riga(move_head,doc)
                     if doc.tipo_documento=="NC":
                         segno = "DA"
                     else:
                        segno = "AV"       
                     if segno=="DA":
                        #segno dare
                        riga['credit']=0
                        riga['debit']=doc.spese_incasso     
                     else:
                        #segno dare
                        riga['credit']=doc.spese_incasso     
                        riga['debit']=0
                     riga['account_id']= controp_obj.conto_v_sp_incasso.id
                   #  import pdb;pdb.set_trace()
                     print "riga spese incasso ", riga
                     id_riga = self.pool.get('account.move.line').create(cr,uid,riga) # RIGA INCASSO
                     if not id_riga:
                         flag_scritto= False
                         
                         
        if doc.spese_trasporto:
                     riga = default_riga(move_head,doc)
                     if doc.tipo_documento=="NC":
                         segno = "DA"
                     else:
                        segno = "AV"       
                     if segno=="DA":
                        #segno dare
                        riga['credit']=0
                        riga['debit']=doc.spese_trasporto     
                     else:
                        #segno dare
                        riga['credit']=doc.spese_trasporto     
                        riga['debit']=0
                     riga['account_id']= controp_obj.conto_v_sp_trasporto.id
         #            import pdb;pdb.set_trace()
                     print "riga spese trasporto ", riga
                     id_riga = self.pool.get('account.move.line').create(cr,uid,riga) # RIGA TRASPORTO
                     if not id_riga:
                         flag_scritto= False
#        if flag_scritto:
#             testo_log += "  Documento "+ doc.name + "  CONTABILIZZATO ALLA REGISTRAZIONE "+ move_obj.name +'\n'
        riga = default_riga(move_head,doc)
        riga['pagamento_id']=doc.pagamento_id.id
        righe={}
        for riga_art in doc.righe_articoli:
                 if doc.sconto_partner or doc.sconto_pagamento:
                    netto = riga_art.totale_riga
                    if doc.sconto_partner:
                        netto = netto-(netto*doc.sconto_partner/100)
                        netto = arrot(cr,uid,netto,dp.get_precision('Account'))
                    if doc.sconto_pagamento:
                        netto = netto-(netto*doc.sconto_pagamento/100)
                        netto = arrot(cr,uid,netto,dp.get_precision('Account'))
                 else:
                    netto = riga_art.totale_riga
                 conto = cerca_controp(riga_art)
                 if not conto:
                    testo_log += "  Documento "+ doc.name + " riga "+ riga_art.product_id.default_code+ ' senza contropartita ricavi '+'DOCUMENTO NON CONTABILIZZATO \n'
                    flag_scritto= False
                 else:
                    if netto==0:
                       pass
                    else:
                     riga= righe.get(conto,False)
                     if not riga:
                        riga = default_riga(move_head,doc)
                        riga['credit']=0
                        riga['debit']=0
                        
                     if doc.tipo_documento=="NC":
                         segno = "DA"
                     else:
                        segno = "AV"       
                     if segno=="DA":
                        if  True :# netto>0:  messo in rem per sommare algebricamnete sul totale conto se c'è solo l'importo negativo
                        #segno dare
                            riga['credit']+=0
                            riga['debit']+=netto   
                        else: 
                            riga['credit']+=netto*-1
                            riga['debit']+=0 
 
                     else:
                        #segno dare
                        if True : #netto>0: messo in rem per sommare algebricamnete sul totale conto si incazzerà se c'è solo l'importo negativo
                            riga['credit']+=netto     
                            riga['debit']+=0
                        else:
                            riga['credit']+=0   
                            riga['debit']+=netto*-1
                           
                     riga['account_id']= conto
                     #import pdb;pdb.set_trace()
                     righe[conto]=riga
        if righe:
            for riga in righe.values():
               # import pdb;pdb.set_trace()
                print "riga ricavo ", riga
                id_riga = self.pool.get('account.move.line').create(cr,uid,riga) # RIGA RICAVO
                if not id_riga:
                         flag_scritto= False
        #cicla sulle righe iva adesso e scrive le stesse
        for riga_iva in doc.righe_totali_iva:
            riga = default_riga(move_head,doc)
            riga['pagamento_id']=doc.pagamento_id.id
            segno = move_head.causale_id.segno_conto_iva
            conto = move_head.causale_id.conto_iva.id
            riga['account_id']=conto
            riga['imponibile']=riga_iva.imponibile
            riga['account_tax_id']=riga_iva.codice_iva.id
            if segno=="DA":
             #segno dare
             riga['credit']=0
             riga['debit']=riga_iva.imposta
            else:
             #segno dare
             riga['credit']=riga_iva.imposta       
             riga['debit']=0
            #import pdb;pdb.set_trace()
            print "riga iva ", riga
            id_riga = self.pool.get('account.move.line').create(cr,uid,riga) # RIGA IVA
            if not id_riga:
                 flag_scritto= False
        # inizia con lo scrivere i dati del cliente
        riga = default_riga(move_head,doc)
        if doc.tipo_documento=="NC":
            segno = "AV"
        else:
            segno = "DA"       
        if segno=="DA":
            #segno dare
            riga['credit']=0
            riga['debit']=doc.totale_documento       
        else:
            #segno dare
            riga['credit']=doc.totale_documento       
            riga['debit']=0
        riga['account_id']= doc.partner_id.property_account_receivable.id
        riga['totdocumento']=doc.totale_documento
        riga['pagamento_id']=doc.pagamento_id.id
        #import pdb;pdb.set_trace()
        print "riga cliente ", riga
        id_riga = self.pool.get('account.move.line').create(cr,uid,riga) # RIGA CLIENTE
        if not id_riga:
             flag_scritto= False
        #cicla sulle righe iva adesso e scrive le stesse
            
            
        
        
        
        
        
        return [testo_log,flag_scritto]
Example #22
0
class product_product(orm.Model):
    """
    Inherit Product in order to add an "Bom Stock" field
    """
    class CreateWarehouseProcess(multiprocessing.Process):
        def __init__(self, cr, uid, ids, field_names, arg, context,
                     return_funct_dict):
            # Inizializzazione superclasse
            multiprocessing.Process.__init__(self)
            self.cr = pooler.get_db(cr.dbname).cursor()
            self.uid = uid
            self.ids = ids
            self.field_names = field_names
            self.arg = arg
            self.context = context
            self.return_funct_dict = return_funct_dict
            self.product_product_obj = pooler.get_pool(
                self.cr.dbname).get('product.product')

        def run(self):
            try:
                self.return_funct_dict.update(
                    self.product_product_obj._product_available(
                        self.cr, self.uid, self.ids, self.field_names,
                        self.arg, self.context))
            except Exception as e:
                # Annulla le modifiche fatte
                _logger.error(u'Error: {error}'.format(error=e))
                self.cr.rollback()
            if not self.cr.closed:
                self.cr.close()
            p = psutil.Process(self.pid)
            p.kill()
            _logger.info(u'STOP: {error}'.format(error=self))
            return True

        def __del__(self):
            if not self.cr.closed:
                self.cr.close()
            return True

    class CreateProductCost(multiprocessing.Process):
        def __init__(self, cr, uid, ids, bom_properties, context,
                     return_funct_dict):
            # Inizializzazione superclasse
            multiprocessing.Process.__init__(self)
            self.cr = pooler.get_db(cr.dbname).cursor()
            self.uid = uid
            self.ids = ids
            self.bom_properties = bom_properties
            self.context = context
            self.return_funct_dict = return_funct_dict
            self.product_product_obj = pooler.get_pool(
                self.cr.dbname).get('product.product')

        def run(self):
            try:
                for product in self.product_product_obj.browse(
                        self.cr, self.uid, self.ids, context=self.context):
                    self.return_funct_dict[
                        product.
                        id] = self.product_product_obj._compute_product_purchase_price(
                            self.cr,
                            self.uid,
                            product,
                            self.bom_properties,
                            context=self.context)
            except Exception as e:
                # Annulla le modifiche fatte
                _logger.error(u'Error: {error}'.format(error=e))
                self.cr.rollback()
            if not self.cr.closed:
                self.cr.close()
            p = psutil.Process(self.pid)
            p.kill()
            _logger.info(u'STOP: {error}'.format(error=self))
            return True

        def __del__(self):
            _logger.info(u'TERMINATE: {error}'.format(error=self))
            if not self.cr.closed:
                self.cr.close()
            return True

    class UpdateCachePrice(threading.Thread):
        def __init__(self,
                     cr,
                     uid,
                     product_product_obj,
                     split_ids,
                     context=None):
            self.cr = pooler.get_db(cr.dbname).cursor()
            self.product_product_obj = product_product_obj
            self.uid = uid
            self.context = context
            self.product_ids = split_ids

            threading.Thread.__init__(self)

        def run(self):
            try:
                for product in self.product_product_obj.read(
                        self.cr, self.uid, self.product_ids, ['cost_price'],
                        self.context):
                    cost_price = product['cost_price']
                return True
            except Exception as e:
                # Rollback
                _logger.error(u'Error: {error}'.format(error=e))
                self.cr.rollback()
            finally:
                if not self.cr.closed:
                    self.cr.close()
            return True

        def terminate(self):
            if not self.cr.closed:
                self.cr.close()
            return True

    @staticmethod
    def _chunkIt(seq, size):
        newseq = []
        splitsize = 1.0 / size * len(seq)
        for line in range(size):
            newseq.append(
                seq[int(round(line *
                              splitsize)):int(round((line + 1) * splitsize))])
        return newseq

    _inherit = 'product.product'

    # def _get_prefered_supplier(self, cr, uid, ids, field_name, args, context):
    #     res = {}
    #     for line in self.browse(cr, uid, ids, context):
    #         res[line.id] = line.seller_ids and line.seller_ids[0].name.id or False
    #     return res

    def __init__(self, cr, uid):
        super(product_product, self).__init__(cr, uid)

        if CACHE_TYPE == 'redis':
            try:
                from openerp.addons.core_extended.redis import Redis
                host = config.get('redis_host', 'localhost')

                self.product_cost_cache = Redis(host,
                                                database=cr.db_name,
                                                model=self._name)
            except:
                _logger.error("Unable to import Redis")
                from openerp.addons.core_extended.dict_cache import SimpleCache
                self.product_cost_cache = SimpleCache()
        else:
            from openerp.addons.core_extended.dict_cache import SimpleCache
            self.product_cost_cache = SimpleCache()

    def _hook_compute_purchase_price_no_supplier(self, product):
        return product.standard_price

    def product_cache(func):
        def cached_product(self,
                           cr,
                           uid,
                           product,
                           bom_properties,
                           context=None):
            if product.id in self.product_cost_cache and not context.get(
                    'partner_name', False):
                _logger.debug('Returning from cache')
                return self.product_cost_cache[product.id]
            else:
                value = func(self,
                             cr,
                             uid,
                             product,
                             bom_properties,
                             context=context)
                self.product_cost_cache[product.id] = value
                return value

        if ENABLE_CACHE:
            return cached_product
        else:
            return func

    @product_cache
    def _get_subproduct_cost_price(self,
                                   cr,
                                   uid,
                                   product,
                                   bom_properties,
                                   context=None):
        return product.cost_price

    @product_cache
    def _compute_product_purchase_price(self,
                                        cr,
                                        uid,
                                        product,
                                        bom_properties,
                                        context=None):
        context = context or self.pool['res.users'].context_get(cr, uid)
        bom_properties = bom_properties or []
        user = self.pool['res.users'].browse(cr, uid, uid, context)

        bom_obj = self.pool['mrp.bom']
        uom_obj = self.pool['product.uom']

        debug_logger = True

        if ENABLE_CACHE:
            if debug_logger:
                _logger.debug(
                    u'[{product.default_code}] {product.name}'.format(
                        product=product))
            # cached_price = self.product_cost_cache.get(product_id, 0)

        bom_id = bom_obj._bom_find(cr,
                                   uid,
                                   product.id,
                                   product_uom=None,
                                   properties=bom_properties)
        if bom_id:
            sub_bom_ids = bom_obj.search(cr,
                                         uid, [('bom_id', '=', bom_id)],
                                         context=context)
            sub_products = bom_obj.browse(cr, uid, sub_bom_ids, context)

            price = 0.
            if ENABLE_CACHE and debug_logger:
                _logger.debug(
                    u'[{product.default_code}] Start Explosion ========================'
                    .format(product=product))

            for sub_product in sub_products:
                if sub_product.product_id.id == product.id:
                    error = "Product '{product.name}' (id: {product.id}) is referenced to itself".format(
                        product=product)
                    _logger.error(error)
                    continue

                # std_price = sub_product.standard_price
                # if ENABLE_CACHE:
                #     if sub_product.product_id.id in self.product_cost_cache:
                #         std_price = self.product_cost_cache[sub_product.product_id.id]
                #     else:
                #         std_price = sub_product.product_id.cost_price
                #         self.product_cost_cache[sub_product.product_id.id] = std_price
                # else:
                #     std_price = sub_product.product_id.cost_price
                std_price = self._get_subproduct_cost_price(
                    cr, uid, sub_product.product_id, False, context)

                qty = uom_obj._compute_qty(
                    cr,
                    uid,
                    from_uom_id=sub_product.product_uom.id,
                    qty=sub_product.product_qty,
                    to_uom_id=sub_product.product_id.uom_po_id.id)
                if ENABLE_CACHE and debug_logger:
                    _logger.debug(
                        u'[{product.default_code}] price += {std_price} * {qty}'
                        .format(product=sub_product.product_id,
                                std_price=std_price,
                                qty=qty))

                # print(std_price, qty)
                price += std_price * qty

            if sub_products:
                # Don't use browse when we already have it
                bom = sub_products[0].bom_id
            else:
                bom = bom_obj.browse(cr, uid, bom_id, context)

            if bom.routing_id and not context.get('exclude_routing', False):
                for wline in bom.routing_id.workcenter_lines:
                    wc = wline.workcenter_id
                    cycle = wline.cycle_nbr
                    # hour = (wc.time_start + wc.time_stop + cycle * wc.time_cycle) * (wc.time_efficiency or 1.0)
                    price += wc.costs_cycle * cycle + wc.costs_hour * wline.hour_nbr
            price /= bom.product_qty
            price = uom_obj._compute_price(cr, uid, bom.product_uom.id, price,
                                           bom.product_id.uom_id.id)
            if ENABLE_CACHE and debug_logger:
                _logger.debug(
                    u'==== SUM [{product.default_code}] bom_price = {price}'.
                    format(product=product, price=price))

            return price
        else:
            # no BoM: use standard_price
            # use standard_price if no supplier indicated

            # if product_id in self.product_cost_cache and ENABLE_CACHE and not context.get('partner_name', False):
            #     return self.product_cost_cache[product_id]

            if product.prefered_supplier:
                pricelist = product.prefered_supplier.property_product_pricelist_purchase or False
                ctx = {'date': time.strftime(DEFAULT_SERVER_DATE_FORMAT)}
                if context.get('partner_name', False):
                    partner_name = context.get('partner_name')
                    partner_ids = self.pool['res.partner'].search(
                        cr,
                        uid, [('name', '=', partner_name)],
                        context=context)
                    partner_id = partner_ids[0]
                else:
                    partner_id = False
                if pricelist:
                    price, rule = self.pool[
                        'product.pricelist'].price_rule_get_multi(
                            cr,
                            uid, [pricelist.id],
                            products_by_qty_by_partner=[(product, 1,
                                                         partner_id)],
                            context=context)[product.id][pricelist.id]
                else:
                    raise orm.except_orm(
                        _("Error"),
                        _("The supplier {supplier} have no pricelist associated"
                          ).format(supplier=product.prefered_supplier.name))

                price_subtotal = 0.0
                if pricelist:
                    from_currency = pricelist.currency_id.id
                    to_currency = user.company_id.currency_id.id
                    price_subtotal = self.pool['res.currency'].compute(
                        cr,
                        uid,
                        from_currency_id=from_currency,
                        to_currency_id=to_currency,
                        from_amount=price,
                        context=context)
                cost_price = price_subtotal or price or product.standard_price
            else:
                cost_price = self._hook_compute_purchase_price_no_supplier(
                    product)

            if ENABLE_CACHE and debug_logger:
                _logger.debug(
                    u'NO BOM [{product.default_code}] price = {price}'.format(
                        product=product, price=cost_price))

            return cost_price

    def _compute_purchase_price_new(self,
                                    cr,
                                    uid,
                                    ids,
                                    product_uom=None,
                                    bom_properties=None,
                                    context=None):
        '''
        Compute the purchase price, taking into account sub products and routing
        '''

        context = context or self.pool['res.users'].context_get(cr, uid)
        bom_properties = bom_properties or []

        if not ids:
            ids = self.search(cr, uid, [])

        workers = multiprocessing.cpu_count() / 2
        res = dict.fromkeys(ids, 0.0)
        with multiprocessing.Manager() as manager:
            return_funct_dict = manager.dict()
            threads = []
            for product_ids in self._chunkIt(ids, workers):
                if product_ids:
                    thread = self.CreateProductCost(cr, uid, product_ids,
                                                    bom_properties, context,
                                                    return_funct_dict)
                    # thread.daemon = True
                    thread.start()
                    threads.append(thread)
            # wait for finish all multiprocessing created
            for job in threads:
                job.join()
            for return_funct_dict_key in return_funct_dict.keys():
                res[return_funct_dict_key] = return_funct_dict[
                    return_funct_dict_key]
        #
        # for product in self.browse(cr, uid, ids, context):
        #     try:
        #         res[product.id] = self._compute_product_purchase_price(cr, uid, product, bom_properties,
        #                                                                context=context)
        #     except Exception as e:
        #         res[product.id] = 99999999
        #         _logger.error(u'{product} ERRORE: {error}'.format(product=product.name_get()[0][1], error=e))

        return res

    def get_cost_field(self, cr, uid, ids, context=None):
        start_time = datetime.now()
        context = context or self.pool['res.users'].context_get(cr, uid)
        end_time = datetime.now()
        duration_seconds = (end_time - start_time)
        duration = '{sec}'.format(sec=duration_seconds)
        _logger.info(u'get_cost_field get in {duration} for {id}'.format(
            duration=duration, id=ids))
        res = self._cost_price(cr, uid, ids, '', [], context)
        return res

    def _cost_price(self, cr, uid, ids, field_name, arg, context=None):
        # _logger.error(
        #     u'START _cost_price for {ids} and {field}'.format(ids=ids, field=field_name))
        context = context or self.pool['res.users'].context_get(cr, uid)
        product_uom = context.get('product_uom')
        bom_properties = context.get('properties')
        company = self.pool['res.users'].browse(cr, uid, uid,
                                                context=context).company_id
        ctx = context.copy()
        ctx.update({'exclude_routing': company.exclude_routing})

        # Set to False to use old function
        new = True

        if new:
            start_time = datetime.now()
            res = self._compute_purchase_price_new(cr,
                                                   uid,
                                                   ids,
                                                   product_uom,
                                                   bom_properties,
                                                   context=ctx)
            end_time = datetime.now()
            duration_seconds = (end_time - start_time)
            duration = '{sec}'.format(sec=duration_seconds)
            _logger.info(
                u'_cost_price_new get in {duration} for {qty} products'.format(
                    duration=duration, qty=len(ids)))
        # else:
        #     start_time = datetime.now()
        #     res = self._compute_purchase_price(cr, uid, ids, product_uom, bom_properties, context=ctx)
        #     end_time = datetime.now()
        #     duration_seconds = (end_time - start_time)
        #     duration = '{sec}'.format(sec=duration_seconds)
        #     _logger.info(u'_cost_price get in {duration} for {qty} products'.format(duration=duration, qty=len(ids)))

        return res

    def _kit_filter(self, cr, uid, obj, name, args, context):
        context = context or self.pool['res.users'].context_get(cr, uid)

        if not args:
            return []
        bom_obj = self.pool['mrp.bom']
        for search in args:
            if search[0] == 'is_kit':
                if search[2]:
                    bom_ids = bom_obj.search(cr,
                                             uid, [('bom_id', '=', False)],
                                             context=context)
                    if bom_ids:
                        bom_product_ids = self.search(
                            cr,
                            uid, [('bom_ids', 'in', bom_ids)],
                            context=context)
                        # res = [bom.product_id.id for bom in bom_obj.browse(cr, uid, bom_ids, context)]
                        return [('id', 'in', bom_product_ids)]
                    else:
                        return [('id', 'in', [])]
        return []

    def _is_kit(self,
                cr,
                uid,
                ids,
                product_uom=None,
                bom_properties=None,
                context=None):
        if not len(ids):
            return []
        '''
        Show if have or not a bom
        '''
        res = {}
        ids = ids or []
        for product_id in ids:
            # bom_id = bom_obj._bom_find(cr, uid, product.id, product_uom=None, properties=bom_properties)
            cr.execute(
                """SELECT id FROM mrp_bom WHERE product_id={product_id} and bom_id is null"""
                .format(product_id=product_id))
            bom_id = cr.fetchall()
            if not bom_id:
                res[product_id] = False
            else:
                res[product_id] = True
        return res

    """
    Inherit Product in order to add an "Bom Stock" field
    """

    def _bom_stock_mapping(self, cr, uid, context=None):
        return {
            'real': 'qty_available',
            'virtual': 'virtual_available',
            'immediately': 'immediately_usable_qty'
        }

    # from profilehooks import profile
    # @profile(immediate=True)

    def _compute_bom_stock(self,
                           cr,
                           uid,
                           product,
                           quantities,
                           ref_stock,
                           context=None):
        context = context or self.pool['res.users'].context_get(cr, uid)
        bom_obj = self.pool['mrp.bom']
        uom_obj = self.pool['product.uom']
        mapping = self._bom_stock_mapping(cr, uid, context=context)
        stock_field = mapping[ref_stock]

        product_qty = quantities.get(stock_field, 0.0)
        # find a bom on the product
        bom_id = bom_obj._bom_find(cr,
                                   uid,
                                   product.id,
                                   product.uom_id.id,
                                   properties=[])

        if bom_id:
            prod_min_quantities = []
            bom = bom_obj.browse(cr, uid, bom_id, context=context)
            if bom.bom_lines:
                stop_compute_bom = False
                # Compute stock qty of each product used in the BoM and
                # get the minimal number of items we can produce with them
                for line in bom.bom_lines:
                    prod_min_quantity = 0.0
                    bom_qty = line.product_id[
                        stock_field]  # expressed in product UOM
                    # the reference stock of the component must be greater
                    # than the quantity of components required to
                    # build the bom
                    line_product_qty = uom_obj._compute_qty_obj(
                        cr,
                        uid,
                        line.product_uom,
                        line.product_qty,
                        line.product_id.uom_id,
                        context=context)

                    if line_product_qty and (bom_qty > line_product_qty):
                        prod_min_quantity = bom_qty / line_product_qty  # line.product_qty is always > 0
                    else:
                        # if one product has not enough stock,
                        # we do not need to compute next lines
                        # because the final quantity will be 0.0 in any case
                        stop_compute_bom = True

                    prod_min_quantities.append(prod_min_quantity)
                    if stop_compute_bom:
                        break
            produced_qty = uom_obj._compute_qty_obj(cr,
                                                    uid,
                                                    bom.product_uom,
                                                    bom.product_qty,
                                                    bom.product_id.uom_id,
                                                    context=context)
            if prod_min_quantities:
                product_qty += min(prod_min_quantities) * produced_qty
            else:
                product_qty += produced_qty
        return product_qty

    def _product_available_thread(self,
                                  cr,
                                  uid,
                                  ids,
                                  field_names=[],
                                  arg=False,
                                  context=None):

        # We need available, virtual or immediately usable
        # quantity which is selected from company to compute Bom stock Value
        # so we add them in the calculation.
        context = context or self.pool['res.users'].context_get(cr, uid)
        start_time = datetime.now()
        comp_obj = self.pool['res.company']
        if 'bom_stock' in field_names:
            field_names.append('qty_available')
            field_names.append('immediately_usable_qty')
            field_names.append('virtual_available')

        company_id = self.pool['res.users']._get_company(cr,
                                                         uid,
                                                         context=context)
        company = comp_obj.read(cr,
                                uid,
                                company_id,
                                ['exclude_consu_stock', 'ref_stock'],
                                context=context)

        res = {}
        for product_id in ids:
            res[product_id] = {}.fromkeys(field_names, 0.0)

        if company['exclude_consu_stock']:
            product_stock_ids = self.search(
                cr,
                uid, [('id', 'in', ids),
                      ('type', 'not in', ['consu', 'service'])],
                context=context)
        else:
            product_stock_ids = ids
        if product_stock_ids:  # if product_stock_ids is [] get_product_available on stock search for all product
            workers = multiprocessing.cpu_count() / 2
            with multiprocessing.Manager() as manager:
                return_funct_dict = manager.dict()
                threads = []
                for split in self._chunkIt(product_stock_ids, workers):
                    if split:
                        thread = self.CreateWarehouseProcess(
                            cr, uid, split, field_names, arg, context,
                            return_funct_dict)
                        thread.daemon = True
                        thread.start()
                        threads.append(thread)
                # wait for finish all multiprocessing created
                for job in threads:
                    job.join()
                for return_funct_dict_key in return_funct_dict.keys():
                    res[return_funct_dict_key] = return_funct_dict[
                        return_funct_dict_key]

        if 'bom_stock' in field_names:
            for product_id, stock_qty in res.iteritems():
                product = self.browse(cr, uid, product_id, context=context)
                res[product_id]['bom_stock'] = self._compute_bom_stock(
                    cr,
                    uid,
                    product,
                    stock_qty,
                    company['ref_stock'],
                    context=context)
        end_time = datetime.now()
        duration_seconds = (end_time - start_time)
        duration = '{sec}'.format(sec=duration_seconds)
        _logger.info(
            u'_product_available get in {duration}'.format(duration=duration))
        return res

    def _get_boms(self, cr, uid, ids, field_name, arg, context):
        result = {}
        for product_id in ids:
            result[product_id] = self.pool['mrp.bom'].search(
                cr,
                uid, [('product_id', '=', product_id), ('bom_id', '=', False)],
                context=context)
        return result

    def _get_prefered_supplier(self, cr, uid, ids, field_name, arg, context):
        result = {}
        for product in self.browse(cr, uid, ids, context):
            result[product.id] = product.seller_ids and product.seller_ids[
                0].name.id or False
        return result

    def price_get(self, cr, uid, ids, ptype='list_price', context=None):
        start_time = datetime.now()
        context = context or self.pool['res.users'].context_get(cr, uid)
        if 'currency_id' in context:
            pricetype_obj = self.pool['product.price.type']
            price_type_id = pricetype_obj.search(cr,
                                                 uid, [('field', '=', ptype)],
                                                 context=context)[0]
            price_type_currency_id = pricetype_obj.browse(
                cr, uid, price_type_id, context).currency_id.id

        res = {}
        product_uom_obj = self.pool['product.uom']
        for product in self.browse(cr, uid, ids, context=context):
            res[product.id] = product[ptype] or 0.0

            if ptype == 'standard_price' and product.is_kit:
                res[product.id] = product.cost_price or product.standard_price

            if ptype == 'list_price':
                res[product.id] = (
                    res[product.id] *
                    (product.price_margin or 1.0)) + product.price_extra
            if 'uom' in context:
                uom = product.uom_id or product.uos_id
                res[product.id] = product_uom_obj._compute_price(
                    cr, uid, uom.id, res[product.id], context['uom'])
            # Convert from price_type currency to asked one
            if 'currency_id' in context:
                # Take the price_type currency from the product field
                # This is right cause a field cannot be in more than one currency
                res[product.id] = self.pool['res.currency'].compute(
                    cr,
                    uid,
                    price_type_currency_id,
                    context['currency_id'],
                    res[product.id],
                    context=context)
        end_time = datetime.now()
        duration_seconds = (end_time - start_time)
        duration = '{sec}'.format(sec=duration_seconds)
        _logger.info(u'price_get get in {duration}'.format(duration=duration))
        return res

    _columns = {
        'date_inventory': fields.function(lambda *a, **k: {}, method=True, type='date', string="Date Inventory"),
        'cost_price': fields.function(_cost_price,
                                      method=True,
                                      string=_('Cost Price (incl. BoM)'),
                                      digits_compute=dp.get_precision('Purchase Price'),
                                      help="The cost price is the standard price or, if the product has a bom, "
                                           "the sum of all standard price of its components. it take also care of the "
                                           "bom costing like cost per cylce."),
        'prefered_supplier': fields.function(_get_prefered_supplier, type='many2one', relation='res.partner',
                                             string='Prefered Supplier'),
        'is_kit': fields.function(_is_kit, fnct_search=_kit_filter, method=True, type="boolean", string="Kit"),
        'bom_lines': fields.function(_get_boms, relation='mrp.bom', string='Boms', type='one2many', method=True),
        'qty_available': fields.function(
            _product_available_thread,
            multi='qty_available',
            type='float',
            digits_compute=dp.get_precision('Product UoM'),
            string='Quantity On Hand',
            help="Current quantity of products.\n"
                 "In a context with a single Stock Location, this includes "
                 "goods stored at this Location, or any of its children.\n"
                 "In a context with a single Warehouse, this includes "
                 "goods stored in the Stock Location of this Warehouse, "
                 "or any "
                 "of its children.\n"
                 "In a context with a single Shop, this includes goods "
                 "stored in the Stock Location of the Warehouse of this Shop, "
                 "or any of its children.\n"
                 "Otherwise, this includes goods stored in any Stock Location "
                 "typed as 'internal'."),
        'virtual_available': fields.function(
            _product_available_thread,
            multi='qty_available',
            type='float',
            digits_compute=dp.get_precision('Product UoM'),
            string='Quantity Available',
            help="Forecast quantity (computed as Quantity On Hand "
                 "- Outgoing + Incoming)\n"
                 "In a context with a single Stock Location, this includes "
                 "goods stored at this Location, or any of its children.\n"
                 "In a context with a single Warehouse, this includes "
                 "goods stored in the Stock Location of this Warehouse, "
                 "or any "
                 "of its children.\n"
                 "In a context with a single Shop, this includes goods "
                 "stored in the Stock Location of the Warehouse of this Shop, "
                 "or any of its children.\n"
                 "Otherwise, this includes goods stored in any Stock Location "
                 "typed as 'internal'."),
        'incoming_qty': fields.function(
            _product_available_thread,
            multi='qty_available',
            type='float',
            digits_compute=dp.get_precision('Product UoM'),
            string='Incoming',
            help="Quantity of products that are planned to arrive.\n"
                 "In a context with a single Stock Location, this includes "
                 "goods arriving to this Location, or any of its children.\n"
                 "In a context with a single Warehouse, this includes "
                 "goods arriving to the Stock Location of this Warehouse, or "
                 "any of its children.\n"
                 "In a context with a single Shop, this includes goods "
                 "arriving to the Stock Location of the Warehouse of this "
                 "Shop, or any of its children.\n"
                 "Otherwise, this includes goods arriving to any Stock "
                 "Location typed as 'internal'."),
        'outgoing_qty': fields.function(
            _product_available_thread,
            multi='qty_available',
            type='float',
            digits_compute=dp.get_precision('Product UoM'),
            string='Outgoing',
            help="Quantity of products that are planned to leave.\n"
                 "In a context with a single Stock Location, this includes "
                 "goods leaving from this Location, or any of its children.\n"
                 "In a context with a single Warehouse, this includes "
                 "goods leaving from the Stock Location of this Warehouse, or "
                 "any of its children.\n"
                 "In a context with a single Shop, this includes goods "
                 "leaving from the Stock Location of the Warehouse of this "
                 "Shop, or any of its children.\n"
                 "Otherwise, this includes goods leaving from any Stock "
                 "Location typed as 'internal'."),
        'immediately_usable_qty': fields.function(
            _product_available_thread,
            digits_compute=dp.get_precision('Product UoM'),
            type='float',
            string='Immediately Usable',
            multi='qty_available',
            help="Quantity of products really available for sale." \
                 "Computed as: Quantity On Hand - Outgoing."),
        'bom_stock': fields.function(
            _product_available_thread,
            digits_compute=dp.get_precision('Product UoM'),
            type='float',
            string='Bill of Materials Stock',
            help="Quantities of products based on Bill of Materials, "
                 "useful to know how much of this "
                 "product you could produce. "
                 "Computed as:\n "
                 "Reference stock of this product + "
                 "how much could I produce of this product with the BoM"
                 "Components",
            multi='qty_available'),
    }

    def unlink(self, cr, uid, ids, context=None):
        context = context or self.pool['res.users'].context_get(cr, uid)
        if self.pool['sale.order.line'].search(cr,
                                               uid,
                                               [('product_id', 'in', ids)],
                                               context=context):
            raise orm.except_orm(
                _("Error"),
                _("The product is used on same Sale Order, deactivate it"))
        if self.pool['mrp.bom'].search(cr,
                                       uid, [('product_id', 'in', ids)],
                                       context=context):
            raise orm.except_orm(
                _("Error"),
                _("The product is used on same BOM, deactivate it"))
        return super(product_product, self).unlink(cr, uid, ids, context)

    def copy(self, cr, uid, product_id, default=None, context=None):
        """Copies the product and the BoM of the product"""
        context = context or self.pool['res.users'].context_get(cr, uid)
        copy_id = super(product_product, self).copy(cr, uid, product_id,
                                                    default, context)

        if 'bom_ids' not in default:
            bom_obj = self.pool['mrp.bom']
            bom_ids = bom_obj.search(cr,
                                     uid, [('product_id', '=', product_id),
                                           ('bom_id', '=', False)],
                                     context=context)

            for bom_id in bom_ids:
                bom_obj.copy(cr,
                             uid,
                             bom_id, {'product_id': copy_id},
                             context=context)

        return copy_id

    def update_product_bom_price(self, cr, uid, ids, context=None):
        """
        This Function is call by scheduler.
        """
        context = context or self.pool['res.users'].context_get(cr, uid)
        for product in self.browse(cr, uid, ids, context):
            product.write({'standard_price': product.cost_price})
        return True

    def update_bom_price(self, cr, uid, context=None):
        """
        This Function is call by scheduler.
        """
        context = context or self.pool['res.users'].context_get(cr, uid)
        # search product with kit
        product_ids = self.search(cr,
                                  uid, [('is_kit', '=', True)],
                                  context=context)
        for product in self.browse(cr, uid, product_ids, context):
            self.write(cr, uid, product.id,
                       {'standard_price': product.cost_price}, context)
        return True

    # from profilehooks import profile
    # @profile(immediate=True)
    def update_cache_price(self, cr, uid, context=None):
        """
        This Function is called by scheduler.
        """
        context = context or self.pool['res.users'].context_get(cr, uid)
        return True
        if ENABLE_CACHE:
            if context.get('product_ids', False):
                product_to_browse_ids = context['product_ids']
            else:
                cache_length = len(self.product_cost_cache)
                cache_ids = self.product_cost_cache.keys()
                cache_ids = [int(cache_id) for cache_id in cache_ids]
                product_ids = self.search(cr, uid, [], context=context)
                _logger.info(u'Cache {cache} of {product}'.format(
                    cache=cache_length, product=len(product_ids)))
                product_to_browse_ids = list(set(product_ids) - set(cache_ids))
            if product_to_browse_ids:
                _logger.setLevel(logging.WARNING)

                if CACHE_TYPE == 'redis':
                    workers = multiprocessing.cpu_count()
                    if workers > 1:
                        workers = workers / 2
                    # threads = []
                    for split in self._chunkIt(product_to_browse_ids, workers):
                        if split:
                            thread = self.UpdateCachePrice(
                                cr, uid, self, split, context)
                            thread.start()
                            # threads.append(thread)

                    # for job in threads:
                    #     job.join()
                else:
                    for product in self.browse(cr, uid, product_ids, context):
                        # Get price to trigger cache calculation
                        cost_price = product.cost_price

        return True

    def write(self, cr, uid, ids, vals, context=None):
        context = context or self.pool['res.users'].context_get(cr, uid)

        if not isinstance(ids, (list, tuple)):
            ids = [ids]

        res = super(product_product, self).write(cr, uid, ids, vals, context)
        changed_product = []
        if ENABLE_CACHE:
            if 'standard_price' in vals or 'seller_ids' in vals:
                bom_obj = self.pool['mrp.bom']
                changed_product = bom_obj.GetWhereUsed(cr, uid, ids,
                                                       context)[1].keys()
            for product_id in changed_product:
                if int(product_id) in self.product_cost_cache:
                    del self.product_cost_cache[int(product_id)]
            # if CACHE_TYPE == 'redis':
            #     ctx = context.copy()
            #     ctx['product_ids'] = [int(product_id) for product_id in changed_product]
            #     self.update_cache_price(cr, uid, context=ctx)

        return res

    def fields_get(self, cr, uid, allfields=None, context=None):
        context = context or self.pool['res.users'].context_get(cr, uid)
        group_obj = self.pool['res.groups']
        ret = super(product_product, self).fields_get(cr,
                                                      uid,
                                                      allfields=allfields,
                                                      context=context)

        if not (group_obj.user_in_group(
                cr, uid, uid, 'product_bom.group_modify_product',
                context=context)
                or group_obj.user_in_group(cr,
                                           uid,
                                           uid,
                                           'product_bom.group_create_product',
                                           context=context)):
            for fields in ret.keys():
                ret[fields]['readonly'] = True
        return ret
Example #23
0
class pos_order(osv.osv):
    _name = "pos.order"
    _description = "Point of Sale"
    _order = "id desc"

    def create_from_ui(self, cr, uid, orders, context=None):
        #_logger.info("orders: %r", orders)
        list = []
        for order in orders:
            # order :: {'name': 'Order 1329148448062', 'amount_paid': 9.42, 'lines': [[0, 0, {'discount': 0, 'price_unit': 1.46, 'product_id': 124, 'qty': 5}], [0, 0, {'discount': 0, 'price_unit': 0.53, 'product_id': 62, 'qty': 4}]], 'statement_ids': [[0, 0, {'journal_id': 7, 'amount': 9.42, 'name': '2012-02-13 15:54:12', 'account_id': 12, 'statement_id': 21}]], 'amount_tax': 0, 'amount_return': 0, 'amount_total': 9.42}
            order_obj = self.pool.get('pos.order')
            # get statements out of order because they will be generated with add_payment to ensure
            # the module behavior is the same when using the front-end or the back-end
            statement_ids = order.pop('statement_ids')
            order_id = self.create(cr, uid, order, context)
            list.append(order_id)
            # call add_payment; refer to wizard/pos_payment for data structure
            # add_payment launches the 'paid' signal to advance the workflow to the 'paid' state
            data = {
                'journal': statement_ids[0][2]['journal_id'],
                'amount': order['amount_paid'],
                'payment_name': order['name'],
                'payment_date': statement_ids[0][2]['name'],
            }
            order_obj.add_payment(cr, uid, order_id, data, context=context)
        return list

    def unlink(self, cr, uid, ids, context=None):
        for rec in self.browse(cr, uid, ids, context=context):
            if rec.state not in ('draft', 'cancel'):
                raise osv.except_osv(
                    _('Unable to Delete !'),
                    _('In order to delete a sale, it must be new or cancelled.'
                      ))
        return super(pos_order, self).unlink(cr, uid, ids, context=context)

    def onchange_partner_id(self, cr, uid, ids, part=False, context=None):
        if not part:
            return {'value': {}}
        pricelist = self.pool.get('res.partner').browse(
            cr, uid, part, context=context).property_product_pricelist.id
        return {'value': {'pricelist_id': pricelist}}

    def _amount_all(self, cr, uid, ids, name, args, context=None):
        tax_obj = self.pool.get('account.tax')
        cur_obj = self.pool.get('res.currency')
        res = {}
        for order in self.browse(cr, uid, ids, context=context):
            res[order.id] = {
                'amount_paid': 0.0,
                'amount_return': 0.0,
                'amount_tax': 0.0,
            }
            val1 = val2 = 0.0
            cur = order.pricelist_id.currency_id
            for payment in order.statement_ids:
                res[order.id]['amount_paid'] += payment.amount
                res[order.id]['amount_return'] += (payment.amount < 0
                                                   and payment.amount or 0)
            for line in order.lines:
                val1 += line.price_subtotal_incl
                val2 += line.price_subtotal
            res[order.id]['amount_tax'] = cur_obj.round(
                cr, uid, cur, val1 - val2)
            res[order.id]['amount_total'] = cur_obj.round(cr, uid, cur, val1)
        return res

    def _default_sale_journal(self, cr, uid, context=None):
        res = self.pool.get('account.journal').search(cr,
                                                      uid,
                                                      [('type', '=', 'sale')],
                                                      limit=1)
        return res and res[0] or False

    def _default_shop(self, cr, uid, context=None):
        res = self.pool.get('sale.shop').search(cr, uid, [])
        return res and res[0] or False

    def copy(self, cr, uid, id, default=None, context=None):
        if not default:
            default = {}
        d = {
            'state': 'draft',
            'invoice_id': False,
            'account_move': False,
            'picking_id': False,
            'statement_ids': [],
            'nb_print': 0,
            'name': self.pool.get('ir.sequence').get(cr, uid, 'pos.order'),
        }
        d.update(default)
        return super(pos_order, self).copy(cr, uid, id, d, context=context)

    _columns = {
        'name':
        fields.char('Order Ref',
                    size=64,
                    required=True,
                    states={'draft': [('readonly', False)]},
                    readonly=True),
        'company_id':
        fields.many2one('res.company', 'Company', required=True,
                        readonly=True),
        'shop_id':
        fields.many2one('sale.shop',
                        'Shop',
                        required=True,
                        states={'draft': [('readonly', False)]},
                        readonly=True),
        'date_order':
        fields.datetime('Date Ordered', readonly=True, select=True),
        'user_id':
        fields.many2one(
            'res.users',
            'Connected Salesman',
            help=
            "Person who uses the the cash register. It could be a reliever, a student or an interim employee."
        ),
        'amount_tax':
        fields.function(_amount_all,
                        string='Taxes',
                        digits_compute=dp.get_precision('Point Of Sale'),
                        multi='all'),
        'amount_total':
        fields.function(_amount_all, string='Total', multi='all'),
        'amount_paid':
        fields.function(_amount_all,
                        string='Paid',
                        states={'draft': [('readonly', False)]},
                        readonly=True,
                        digits_compute=dp.get_precision('Point Of Sale'),
                        multi='all'),
        'amount_return':
        fields.function(_amount_all,
                        'Returned',
                        digits_compute=dp.get_precision('Point Of Sale'),
                        multi='all'),
        'lines':
        fields.one2many('pos.order.line',
                        'order_id',
                        'Order Lines',
                        states={'draft': [('readonly', False)]},
                        readonly=True),
        'statement_ids':
        fields.one2many('account.bank.statement.line',
                        'pos_statement_id',
                        'Payments',
                        states={'draft': [('readonly', False)]},
                        readonly=True),
        'pricelist_id':
        fields.many2one('product.pricelist',
                        'Pricelist',
                        required=True,
                        states={'draft': [('readonly', False)]},
                        readonly=True),
        'partner_id':
        fields.many2one('res.partner',
                        'Customer',
                        change_default=True,
                        select=1,
                        states={
                            'draft': [('readonly', False)],
                            'paid': [('readonly', False)]
                        }),
        'state':
        fields.selection([('draft', 'New'), ('cancel', 'Cancelled'),
                          ('paid', 'Paid'), ('done', 'Posted'),
                          ('invoiced', 'Invoiced')],
                         'State',
                         readonly=True),
        'invoice_id':
        fields.many2one('account.invoice', 'Invoice'),
        'account_move':
        fields.many2one('account.move', 'Journal Entry', readonly=True),
        'picking_id':
        fields.many2one('stock.picking', 'Picking', readonly=True),
        'note':
        fields.text('Internal Notes'),
        'nb_print':
        fields.integer('Number of Print', readonly=True),
        'sale_journal':
        fields.many2one('account.journal',
                        'Journal',
                        required=True,
                        states={'draft': [('readonly', False)]},
                        readonly=True),
    }

    def _default_pricelist(self, cr, uid, context=None):
        res = self.pool.get('sale.shop').search(cr, uid, [], context=context)
        if res:
            shop = self.pool.get('sale.shop').browse(cr,
                                                     uid,
                                                     res[0],
                                                     context=context)
            return shop.pricelist_id and shop.pricelist_id.id or False
        return False

    _defaults = {
        'user_id':
        lambda self, cr, uid, context: uid,
        'state':
        'draft',
        'name':
        lambda obj, cr, uid, context: obj.pool.get('ir.sequence').get(
            cr, uid, 'pos.order'),
        'date_order':
        lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'),
        'nb_print':
        0,
        'company_id':
        lambda self, cr, uid, c: self.pool.get('res.users').browse(
            cr, uid, uid, c).company_id.id,
        'sale_journal':
        _default_sale_journal,
        'shop_id':
        _default_shop,
        'pricelist_id':
        _default_pricelist,
    }

    def test_paid(self, cr, uid, ids, context=None):
        """A Point of Sale is paid when the sum
        @return: True
        """
        for order in self.browse(cr, uid, ids, context=context):
            if order.lines and not order.amount_total:
                return True
            if (not order.lines) or (not order.statement_ids) or \
                (abs(order.amount_total-order.amount_paid) > 0.00001):
                return False
        return True

    def create_picking(self, cr, uid, ids, context=None):
        """Create a picking for each order and validate it."""
        picking_obj = self.pool.get('stock.picking')
        partner_obj = self.pool.get('res.partner')
        move_obj = self.pool.get('stock.move')

        for order in self.browse(cr, uid, ids, context=context):
            if not order.state == 'draft':
                continue
            addr = order.partner_id and partner_obj.address_get(
                cr, uid, [order.partner_id.id], ['delivery']) or {}
            picking_id = picking_obj.create(
                cr,
                uid, {
                    'origin': order.name,
                    'address_id': addr.get('delivery', False),
                    'type': 'out',
                    'company_id': order.company_id.id,
                    'move_type': 'direct',
                    'note': order.note or "",
                    'invoice_state': 'none',
                    'auto_picking': True,
                },
                context=context)
            self.write(cr,
                       uid, [order.id], {'picking_id': picking_id},
                       context=context)
            location_id = order.shop_id.warehouse_id.lot_stock_id.id
            output_id = order.shop_id.warehouse_id.lot_output_id.id

            for line in order.lines:
                if line.product_id and line.product_id.type == 'service':
                    continue
                if line.qty < 0:
                    location_id, output_id = output_id, location_id

                move_obj.create(cr,
                                uid, {
                                    'name': line.name,
                                    'product_uom': line.product_id.uom_id.id,
                                    'product_uos': line.product_id.uom_id.id,
                                    'picking_id': picking_id,
                                    'product_id': line.product_id.id,
                                    'product_uos_qty': abs(line.qty),
                                    'product_qty': abs(line.qty),
                                    'tracking_id': False,
                                    'state': 'draft',
                                    'location_id': location_id,
                                    'location_dest_id': output_id,
                                },
                                context=context)
                if line.qty < 0:
                    location_id, output_id = output_id, location_id

            wf_service = netsvc.LocalService("workflow")
            wf_service.trg_validate(uid, 'stock.picking', picking_id,
                                    'button_confirm', cr)
            picking_obj.force_assign(cr, uid, [picking_id], context)
        return True

    def set_to_draft(self, cr, uid, ids, *args):
        if not len(ids):
            return False
        for order in self.browse(cr, uid, ids, context=context):
            if order.state <> 'cancel':
                raise osv.except_osv(
                    _('Error!'),
                    _('In order to set to draft a sale, it must be cancelled.')
                )
        self.write(cr, uid, ids, {'state': 'draft'})
        wf_service = netsvc.LocalService("workflow")
        for i in ids:
            wf_service.trg_create(uid, 'pos.order', i, cr)
        return True

    def cancel_order(self, cr, uid, ids, context=None):
        """ Changes order state to cancel
        @return: True
        """
        stock_picking_obj = self.pool.get('stock.picking')
        for order in self.browse(cr, uid, ids, context=context):
            wf_service.trg_validate(uid, 'stock.picking', order.picking_id.id,
                                    'button_cancel', cr)
            if stock_picking_obj.browse(
                    cr, uid, order.picking_id.id,
                    context=context).state <> 'cancel':
                raise osv.except_osv(_('Error!'),
                                     _('Unable to cancel the picking.'))
        self.write(cr, uid, ids, {'state': 'cancel'}, context=context)
        return True

    def add_payment(self, cr, uid, order_id, data, context=None):
        """Create a new payment for the order"""
        statement_obj = self.pool.get('account.bank.statement')
        statement_line_obj = self.pool.get('account.bank.statement.line')
        prod_obj = self.pool.get('product.product')
        property_obj = self.pool.get('ir.property')
        curr_c = self.pool.get('res.users').browse(cr,
                                                   uid,
                                                   uid,
                                                   context=context).company_id
        curr_company = curr_c.id
        order = self.browse(cr, uid, order_id, context=context)
        ids_new = []
        args = {
            'amount': data['amount'],
        }
        if 'payment_date' in data.keys():
            args['date'] = data['payment_date']
        args['name'] = order.name
        if data.get('payment_name', False):
            args['name'] = args['name'] + ': ' + data['payment_name']
        account_def = property_obj.get(cr,
                                       uid,
                                       'property_account_receivable',
                                       'res.partner',
                                       context=context)
        args['account_id'] = (order.partner_id and order.partner_id.property_account_receivable \
                             and order.partner_id.property_account_receivable.id) or (account_def and account_def.id) or False
        args['partner_id'] = order.partner_id and order.partner_id.id or None

        if not args['account_id']:
            if not args['partner_id']:
                msg = _(
                    'There is no receivable account defined to make payment')
            else:
                msg = _(
                    'There is no receivable account defined to make payment for the partner: "%s" (id:%d)'
                ) % (
                    order.partner_id.name,
                    order.partner_id.id,
                )
            raise osv.except_osv(_('Configuration Error !'), msg)

        statement_id = statement_obj.search(
            cr,
            uid, [('journal_id', '=', int(data['journal'])),
                  ('company_id', '=', curr_company), ('user_id', '=', uid),
                  ('state', '=', 'open')],
            context=context)
        if len(statement_id) == 0:
            raise osv.except_osv(_('Error !'),
                                 _('You have to open at least one cashbox'))
        if statement_id:
            statement_id = statement_id[0]
        args['statement_id'] = statement_id
        args['pos_statement_id'] = order_id
        args['journal_id'] = int(data['journal'])
        args['type'] = 'customer'
        args['ref'] = order.name
        statement_line_obj.create(cr, uid, args, context=context)
        ids_new.append(statement_id)

        wf_service = netsvc.LocalService("workflow")
        wf_service.trg_validate(uid, 'pos.order', order_id, 'paid', cr)
        wf_service.trg_write(uid, 'pos.order', order_id, cr)

        return statement_id

    def refund(self, cr, uid, ids, context=None):
        """Create a copy of order  for refund order"""
        clone_list = []
        line_obj = self.pool.get('pos.order.line')
        for order in self.browse(cr, uid, ids, context=context):
            clone_id = self.copy(cr,
                                 uid,
                                 order.id, {
                                     'name': order.name + ' REFUND',
                                 },
                                 context=context)
            clone_list.append(clone_id)

        for clone in self.browse(cr, uid, clone_list, context=context):
            for order_line in clone.lines:
                line_obj.write(cr,
                               uid, [order_line.id], {'qty': -order_line.qty},
                               context=context)

        new_order = ','.join(map(str, clone_list))
        abs = {
            #'domain': "[('id', 'in', ["+new_order+"])]",
            'name': _('Return Products'),
            'view_type': 'form',
            'view_mode': 'form',
            'res_model': 'pos.order',
            'res_id': clone_list[0],
            'view_id': False,
            'context': context,
            'type': 'ir.actions.act_window',
            'nodestroy': True,
            'target': 'current',
        }
        return abs

    def action_invoice_state(self, cr, uid, ids, context=None):
        return self.write(cr, uid, ids, {'state': 'invoiced'}, context=context)

    def action_invoice(self, cr, uid, ids, context=None):
        wf_service = netsvc.LocalService("workflow")
        inv_ref = self.pool.get('account.invoice')
        inv_line_ref = self.pool.get('account.invoice.line')
        product_obj = self.pool.get('product.product')
        inv_ids = []

        for order in self.pool.get('pos.order').browse(cr,
                                                       uid,
                                                       ids,
                                                       context=context):
            if order.invoice_id:
                inv_ids.append(order.invoice_id.id)
                continue

            if not order.partner_id:
                raise osv.except_osv(
                    _('Error'), _('Please provide a partner for the sale.'))

            acc = order.partner_id.property_account_receivable.id
            inv = {
                'name': order.name,
                'origin': order.name,
                'account_id': acc,
                'journal_id': order.sale_journal.id or None,
                'type': 'out_invoice',
                'reference': order.name,
                'partner_id': order.partner_id.id,
                'comment': order.note or '',
                'currency_id': order.pricelist_id.currency_id.
                id,  # considering partner's sale pricelist's currency
            }
            inv.update(
                inv_ref.onchange_partner_id(cr, uid, [], 'out_invoice',
                                            order.partner_id.id)['value'])
            if not inv.get('account_id', None):
                inv['account_id'] = acc
            inv_id = inv_ref.create(cr, uid, inv, context=context)

            self.write(cr,
                       uid, [order.id], {
                           'invoice_id': inv_id,
                           'state': 'invoiced'
                       },
                       context=context)
            inv_ids.append(inv_id)
            for line in order.lines:
                inv_line = {
                    'invoice_id': inv_id,
                    'product_id': line.product_id.id,
                    'quantity': line.qty,
                }
                inv_name = product_obj.name_get(cr,
                                                uid, [line.product_id.id],
                                                context=context)[0][1]
                inv_line.update(
                    inv_line_ref.product_id_change(
                        cr,
                        uid, [],
                        line.product_id.id,
                        line.product_id.uom_id.id,
                        line.qty,
                        partner_id=order.partner_id.id,
                        fposition_id=order.partner_id.
                        property_account_position.id)['value'])
                if line.product_id.description_sale:
                    inv_line['note'] = line.product_id.description_sale
                inv_line['price_unit'] = line.price_unit
                inv_line['discount'] = line.discount
                inv_line['name'] = inv_name
                inv_line['invoice_line_tax_id'] = ('invoice_line_tax_id' in inv_line)\
                    and [(6, 0, inv_line['invoice_line_tax_id'])] or []
                inv_line_ref.create(cr, uid, inv_line, context=context)
            inv_ref.button_reset_taxes(cr, uid, [inv_id], context=context)
            wf_service.trg_validate(uid, 'pos.order', order.id, 'invoice', cr)

        if not inv_ids: return {}

        mod_obj = self.pool.get('ir.model.data')
        res = mod_obj.get_object_reference(cr, uid, 'account', 'invoice_form')
        res_id = res and res[1] or False
        return {
            'name': _('Customer Invoice'),
            'view_type': 'form',
            'view_mode': 'form',
            'view_id': [res_id],
            'res_model': 'account.invoice',
            'context': "{'type':'out_invoice'}",
            'type': 'ir.actions.act_window',
            'nodestroy': True,
            'target': 'current',
            'res_id': inv_ids and inv_ids[0] or False,
        }

    def create_account_move(self, cr, uid, ids, context=None):
        """Create a account move line of order grouped by products or not."""
        account_move_obj = self.pool.get('account.move')
        account_move_line_obj = self.pool.get('account.move.line')
        account_period_obj = self.pool.get('account.period')
        period = account_period_obj.find(cr, uid, context=context)[0]
        account_tax_obj = self.pool.get('account.tax')
        res_obj = self.pool.get('res.users')
        property_obj = self.pool.get('ir.property')

        for order in self.browse(cr, uid, ids, context=context):
            if order.state <> 'paid': continue

            curr_c = res_obj.browse(cr, uid, uid).company_id
            comp_id = res_obj.browse(cr, order.user_id.id,
                                     order.user_id.id).company_id
            comp_id = comp_id and comp_id.id or False
            to_reconcile = []
            group_tax = {}
            account_def = property_obj.get(cr,
                                           uid,
                                           'property_account_receivable',
                                           'res.partner',
                                           context=context).id

            order_account = order.partner_id and order.partner_id.property_account_receivable and order.partner_id.property_account_receivable.id or account_def or curr_c.account_receivable.id

            # Create an entry for the sale
            move_id = account_move_obj.create(
                cr,
                uid, {
                    'journal_id': order.sale_journal.id,
                },
                context=context)

            # Create an move for each order line
            for line in order.lines:
                tax_amount = 0
                taxes = [t for t in line.product_id.taxes_id]
                computed = account_tax_obj.compute_all(
                    cr, uid, taxes,
                    line.price_unit * (100.0 - line.discount) / 100.0,
                    line.qty)
                computed_taxes = computed['taxes']

                for tax in computed_taxes:
                    tax_amount += round(tax['amount'], 2)
                    group_key = (tax['tax_code_id'], tax['base_code_id'],
                                 tax['account_collected_id'])

                    if group_key in group_tax:
                        group_tax[group_key] += round(tax['amount'], 2)
                    else:
                        group_tax[group_key] = round(tax['amount'], 2)
                amount = line.price_subtotal

                # Search for the income account
                if line.product_id.property_account_income.id:
                    income_account = line.product_id.property_account_income.id
                elif line.product_id.categ_id.property_account_income_categ.id:
                    income_account = line.product_id.categ_id.property_account_income_categ.id
                else:
                    raise osv.except_osv(_('Error !'), _('There is no income '\
                        'account defined for this product: "%s" (id:%d)') \
                        % (line.product_id.name, line.product_id.id, ))

                # Empty the tax list as long as there is no tax code:
                tax_code_id = False
                tax_amount = 0
                while computed_taxes:
                    tax = computed_taxes.pop(0)
                    if amount > 0:
                        tax_code_id = tax['base_code_id']
                        tax_amount = line.price_subtotal * tax['base_sign']
                    else:
                        tax_code_id = tax['ref_base_code_id']
                        tax_amount = line.price_subtotal * tax['ref_base_sign']
                    # If there is one we stop
                    if tax_code_id:
                        break

                # Create a move for the line
                account_move_line_obj.create(
                    cr,
                    uid, {
                        'name':
                        line.name,
                        'date':
                        order.date_order[:10],
                        'ref':
                        order.name,
                        'quantity':
                        line.qty,
                        'product_id':
                        line.product_id.id,
                        'move_id':
                        move_id,
                        'account_id':
                        income_account,
                        'company_id':
                        comp_id,
                        'credit': ((amount > 0) and amount) or 0.0,
                        'debit': ((amount < 0) and -amount) or 0.0,
                        'journal_id':
                        order.sale_journal.id,
                        'period_id':
                        period,
                        'tax_code_id':
                        tax_code_id,
                        'tax_amount':
                        tax_amount,
                        'partner_id':
                        order.partner_id and order.partner_id.id or False
                    },
                    context=context)

                # For each remaining tax with a code, whe create a move line
                for tax in computed_taxes:
                    if amount > 0:
                        tax_code_id = tax['base_code_id']
                        tax_amount = line.price_subtotal * tax['base_sign']
                    else:
                        tax_code_id = tax['ref_base_code_id']
                        tax_amount = line.price_subtotal * tax['ref_base_sign']
                    if not tax_code_id:
                        continue

                    account_move_line_obj.create(
                        cr,
                        uid, {
                            'name': "Tax" + line.name,
                            'date': order.date_order[:10],
                            'ref': order.name,
                            'product_id': line.product_id.id,
                            'quantity': line.qty,
                            'move_id': move_id,
                            'account_id': income_account,
                            'company_id': comp_id,
                            'credit': 0.0,
                            'debit': 0.0,
                            'journal_id': order.sale_journal.id,
                            'period_id': period,
                            'tax_code_id': tax_code_id,
                            'tax_amount': tax_amount,
                        },
                        context=context)

            # Create a move for each tax group
            (tax_code_pos, base_code_pos, account_pos) = (0, 1, 2)
            for key, amount in group_tax.items():
                account_move_line_obj.create(
                    cr,
                    uid, {
                        'name': 'Tax',
                        'date': order.date_order[:10],
                        'ref': order.name,
                        'move_id': move_id,
                        'company_id': comp_id,
                        'quantity': line.qty,
                        'product_id': line.product_id.id,
                        'account_id': key[account_pos],
                        'credit': ((amount > 0) and amount) or 0.0,
                        'debit': ((amount < 0) and -amount) or 0.0,
                        'journal_id': order.sale_journal.id,
                        'period_id': period,
                        'tax_code_id': key[tax_code_pos],
                        'tax_amount': amount,
                    },
                    context=context)

            # counterpart
            to_reconcile.append(account_move_line_obj.create(cr, uid, {
                'name': order.name,
                'date': order.date_order[:10],
                'ref': order.name,
                'move_id': move_id,
                'company_id': comp_id,
                'account_id': order_account,
                'credit': ((order.amount_total < 0) and -order.amount_total)\
                    or 0.0,
                'debit': ((order.amount_total > 0) and order.amount_total)\
                    or 0.0,
                'journal_id': order.sale_journal.id,
                'period_id': period,
                'partner_id': order.partner_id and order.partner_id.id or False
            }, context=context))
            self.write(cr,
                       uid,
                       order.id, {
                           'state': 'done',
                           'account_move': move_id
                       },
                       context=context)
        return True

    def action_payment(self, cr, uid, ids, context=None):
        return self.write(cr, uid, ids, {'state': 'payment'}, context=context)

    def action_paid(self, cr, uid, ids, context=None):
        context = context or {}
        self.create_picking(cr, uid, ids, context=None)
        self.write(cr, uid, ids, {'state': 'paid'}, context=context)
        return True

    def action_cancel(self, cr, uid, ids, context=None):
        self.write(cr, uid, ids, {'state': 'cancel'}, context=context)
        return True

    def action_done(self, cr, uid, ids, context=None):
        self.create_account_move(cr, uid, ids, context=context)
        return True
Example #24
0
class wiz_crear_factura(osv.osv_memory):
    _name = 'wiz.crear.factura'
    _description = 'Asistente para crear las facturas'

    _columns = {
        'partner_id':
        fields.many2one('res.partner', 'Empresa', readonly=True),
        'journal_id':
        fields.many2one('account.journal',
                        'Diario',
                        domain=[('type', '=', 'purchase')],
                        required=True),
        'description':
        fields.char('Descripción', size=64, required=True),
        'importe':
        fields.float('Importe', digits_compute=dp.get_precision('Account')),
        'pago':
        fields.integer('Pago'),
        'type':
        fields.char('Tipo de Pago', size=1),
    }

    def default_get(self, cr, uid, fields_list, context=None):
        values = {}
        if context['active_model'] == "l10n.es.tesoreria.pagos.var.plan":
            obj = self.pool.get('l10n.es.tesoreria.pagos.var.plan')
            type = 'V'
        else:
            obj = self.pool.get('l10n.es.tesoreria.pagos.period.plan')
            type = 'P'
        for pago in obj.browse(cr, uid, context['active_ids']):
            if pago.factura_id:
                raise osv.except_osv(
                    _('Error!'),
                    _('Este pago ya tiene una factura asignado!!'))
            values = {
                'partner_id': pago.partner_id.id,
                'journal_id': pago.diario.id,
                'description': pago.name,
                'importe': pago.importe,
                'pago': int(pago.id),
                'type': type,
            }
        return values

    def button_create_inv(self, cr, uid, ids, context=None):
        invoice_obj = self.pool.get('account.invoice')
        invoice_line_obj = self.pool.get('account.invoice.line')
        address_obj = self.pool.get('res.partner.address')
        for wiz in self.browse(cr, uid, ids):
            address = address_obj.search(
                cr, uid, [('partner_id', '=', wiz.partner_id.id)])
            if address:
                values = {
                    'name':
                    'Prev: ' + wiz.description + '/ Importe: ' +
                    str(wiz.importe),
                    'reference':
                    'Prev: ' + wiz.description + '/ Importe: ' +
                    str(wiz.importe),
                    'partner_id':
                    wiz.partner_id.id,
                    'journal_id':
                    wiz.journal_id.id,
                    'address_invoice_id':
                    address[0],
                    'type':
                    'in_invoice',
                    'account_id':
                    wiz.partner_id.property_account_receivable.id,
                }
                if wiz.partner_id.property_payment_term:
                    values.update({
                        'payment_term':
                        wiz.partner_id.property_payment_term.id
                    })
                if wiz.partner_id.payment_type_customer:
                    values.update({
                        'payment_type':
                        wiz.partner_id.payment_type_customer.id
                    })
                if wiz.partner_id.property_account_position:
                    values.update({
                        'fiscal_position':
                        wiz.partner_id.property_account_position.id
                    })
            else:
                raise osv.except_osv(_('Error!'),
                                     _('Address not found for Partner: '),
                                     wiz.partner_id.name)

            invoice_id = invoice_obj.create(cr, uid, values)

            if wiz.type == 'V':
                obj = self.pool.get('l10n.es.tesoreria.pagos.var.plan')
            else:
                obj = self.pool.get('l10n.es.tesoreria.pagos.period.plan')

            obj.write(cr, uid, wiz.pago, {
                'factura_id': invoice_id,
                'diario': wiz.journal_id.id,
                'pagado': 1
            })
        return {'type': 'ir.actions.act_window_close'}
        ('confirmed4', 'Waiting CEO Approve'),
        ('approved', 'Approved'),
        ('except_picking', 'Shipping Exception'),
        ('except_invoice', 'Invoice Exception'),
        ('done', 'Done'),
        ('cancel', 'Cancelled')
    ]

    _columns = {
        'state'                 : fields.selection(STATE_SELECTION, 'State', readonly=True, help="The state of the purchase order or the quotation request. A quotation is a purchase order in a 'Draft' state. Then the order has to be confirmed by the user, the state switch to 'Confirmed'. Then the supplier must confirm the order to change the state to 'Approved'. When the purchase order is paid and received, the state becomes 'Done'. If a cancel action occurs in the invoice or in the reception of goods, the state becomes in exception.", select=True),
        'budget_info_ids_po'    : fields.many2many('budget.info.po', 'budget_info_rel_po', 'order_id', 'budget_info_id_po', 'Budget Line', readonly=True),
        'budget_note'           : fields.text('Budget Note'),
        'budget_note_line_ids'  : fields.one2many('budget.note.po', 'order_id', 'Budget Note History'),
        
        #######DICOUNT#####################
        'amount_untaxed': fields.function(_amount_all, method=True, digits_compute= dp.get_precision('Purchase Price'), string='Untaxed Amount',
            store={
                'purchase.order.line': (_get_order, None, 10),
                'purchase.order': (lambda self, cr, uid, ids, c={}: ids, ['discount_total'], 20),
            }, multi="sums", help="The amount without tax"),
        'amount_tax': fields.function(_amount_all, method=True, digits_compute= dp.get_precision('Purchase Price'), string='Taxes',
            store={
                'purchase.order.line': (_get_order, None, 10),
                'purchase.order': (lambda self, cr, uid, ids, c={}: ids, ['discount_total'], 20),
            }, multi="sums", help="The tax amount"),
        'amount_total': fields.function(_amount_all, method=True, digits_compute= dp.get_precision('Purchase Price'), string='Total',
            store={
                'purchase.order.line': (_get_order, None, 10),
                'purchase.order': (lambda self, cr, uid, ids, c={}: ids, ['discount_total'], 20),
            }, multi="sums",help="The total amount"),
        'discount_total': fields.float('Discount Total(%)', digits=(16,2)),
Example #26
0
class changes_production_lot_stock(osv.osv):
    def default_get(self, cr, uid, ids, fields, context=None):
        if context is None:
            context = {}
        res = {}
        company_id = self.pool.get('res.company')._company_default_get(
            cr, uid, 'changes.production.lot.stock', context=context),
        print "company_id", company_id
        res.update({'company_id': company_id[0]})

        return res

    _name = 'changes.production.lot.stock'

    _columns = {
        'name':
        fields.many2one('stock.production.lot', 'Lot number'),
        'stock_driver':
        fields.boolean('Driver'),
        'product_id':
        fields.many2one('product.product', 'Product'),
        'company_id':
        fields.many2one('res.company', 'Company', required=True),
        'factor':
        fields.integer('Factor',
                       help="This field define the field in readonly"),
        'location_id':
        fields.char('Location', 128),
        'length':
        fields.float('Length (m)',
                     digits_compute=dp.get_precision('Extra UOM data')),
        'heigth':
        fields.float('Heigth (m)',
                     digits_compute=dp.get_precision('Extra UOM data')),
        'diff':
        fields.float('Diff', digits_compute=dp.get_precision('Product UoM')),
        'width':
        fields.float('Width (m)',
                     digits_compute=dp.get_precision('Extra UOM data')),
        'quantity':
        fields.float('Quantity',
                     digits_compute=dp.get_precision('Product UoM')),
        'pieces_qty':
        fields.integer('Pieces'),
        'new_location_id':
        fields.char('New Location', 128),
        'new_length':
        fields.float('New Length (m)',
                     digits_compute=dp.get_precision('Extra UOM data')),
        'new_heigth':
        fields.float('New Heigth (m)',
                     digits_compute=dp.get_precision('Extra UOM data')),
        'new_width':
        fields.float(' New Width (m)',
                     digits_compute=dp.get_precision('Extra UOM data')),
        'new_quantity':
        fields.float('New Quantity',
                     digits_compute=dp.get_precision('Product UoM')),
        'new_pieces_qty':
        fields.integer('New Pieces'),
        'description_stock_id':
        fields.many2one('descriptions.changes.production.lot.stock',
                        'Time Descriptions'),
    }
    _defaults = {
        'company_id':
        lambda s, cr, uid, c: s.pool.get('res.company')._company_default_get(
            cr, uid, 'changes.production.lot.stock', context=c),
    }

    def create(self, cr, uid, vals, context=None):
        """
        Create a new register with thes fields reandonly that dot save in the data base
        """
        company_id = self.pool.get('res.company')._company_default_get(
            cr, uid, 'purchase.order.line', context=context),
        print "valssss", vals
        if vals.get('name', False):
            lot_obj = self.pool.get('stock.production.lot')
            product_obj = self.pool.get('product.uom')
            lot_brw = lot_obj.browse(cr, uid, vals['name'], context=None)
            pieces = product_obj._compute_pieces2(
                cr, uid, lot_brw.product_id.stock_driver, lot_brw.virtual,
                lot_brw.length, lot_brw.heigth, lot_brw.width)
            area_old = lot_brw.virtual
            if lot_brw.product_id.stock_driver == 'tile':
                area_new = product_obj._compute_area(
                    cr, uid, lot_brw.product_id.stock_driver,
                    vals['new_pieces_qty'],
                    lot_brw.product_id.tile_format_id.length,
                    lot_brw.product_id.tile_format_id.heigth, lot_brw.width)
                diff = area_new - area_old
                vals.update({
                    'diff': diff,
                    'new_quantity': area_new,
                    'length': lot_brw.product_id.tile_format_id.length,
                    'new_length': lot_brw.product_id.tile_format_id.length,
                    'heigth': lot_brw.product_id.tile_format_id.heigth,
                    'new_heigth': lot_brw.product_id.tile_format_id.heigth,
                    'width': lot_brw.width,
                    'pieces_qty': pieces,
                    'quantity': lot_brw.virtual,
                    'company_id': company_id[0]
                })

            if lot_brw.product_id.stock_driver == 'slab':
                area_new = product_obj._compute_area(
                    cr, uid, lot_brw.product_id.stock_driver,
                    vals['new_pieces_qty'], vals['new_length'],
                    vals['new_heigth'], lot_brw.width)
                diff = area_new - area_old
                vals.update({
                    'diff': diff,
                    'new_quantity': area_new,
                    'length': vals['new_length'],
                    'heigth': vals['new_heigth'],
                    'width': lot_brw.width,
                    'pieces_qty': pieces,
                    'quantity': lot_brw.virtual,
                    'company_id': company_id[0]
                })

            if lot_brw.product_id.stock_driver == 'block':
                area_new = product_obj._compute_area(
                    cr, uid, lot_brw.product_id.stock_driver,
                    vals['new_pieces_qty'], vals['new_length'],
                    vals['new_heigth'], lot_brw.width)
                diff = area_new - area_old
                vals.update({
                    'diff': diff,
                    'new_quantity': area_new,
                    'length': vals['new_length'],
                    'heigth': vals['new_heigth'],
                    'width': vals['new_width'],
                    'pieces_qty': pieces,
                    'quantity': lot_brw.virtual,
                    'company_id': company_id[0]
                })

        return super(changes_production_lot_stock,
                     self).create(cr, uid, vals, context)

    def write(self, cr, uid, ids, vals, context=None):
        """
        Chages for save changes in the field readonly
        """
        if context is None:
            context = {}
        if 'name' in vals:
            lot_obj = self.pool.get('stock.production.lot')
            product_obj = self.pool.get('product.uom')
            lot_brw = lot_obj.browse(cr, uid, vals['name'], context=None)
            pieces = product_obj._compute_pieces2(
                cr, uid, lot_brw.product_id.stock_driver, lot_brw.virtual,
                lot_brw.length, lot_brw.heigth, lot_brw.width)
            area_old = lot_brw.virtual
            if lot_brw.product_id.stock_driver == 'tile':
                area_new = product_obj._compute_area(
                    cr, uid, lot_brw.product_id.stock_driver,
                    vals['new_pieces_qty'],
                    lot_brw.product_id.tile_format_id.length,
                    lot_brw.product_id.tile_format_id.heigth, lot_brw.width)
                diff = area_new - area_old
                vals.update({
                    'diff': diff,
                    'new_quantity': area_new,
                    'length': lot_brw.product_id.tile_format_id.length,
                    'new_length': lot_brw.product_id.tile_format_id.length,
                    'heigth': lot_brw.product_id.tile_format_id.heigth,
                    'new_heigth': lot_brw.product_id.tile_format_id.heigth,
                    'width': lot_brw.width,
                    'pieces_qty': pieces,
                    'quantity': lot_brw.virtual,
                    'company_id': company_id[0]
                })

            if lot_brw.product_id.stock_driver == 'slab':
                area_new = product_obj._compute_area(
                    cr, uid, lot_brw.product_id.stock_driver,
                    vals['new_pieces_qty'], vals['new_length'],
                    vals['new_heigth'], lot_brw.width)
                diff = area_new - area_old
                vals.update({
                    'diff': diff,
                    'new_quantity': area_new,
                    'length': vals['new_length'],
                    'heigth': vals['new_heigth'],
                    'width': lot_brw.width,
                    'pieces_qty': pieces,
                    'quantity': lot_brw.virtual,
                    'company_id': company_id[0]
                })

            if lot_brw.product_id.stock_driver == 'block':
                area_new = product_obj._compute_area(
                    cr, uid, lot_brw.product_id.stock_driver,
                    vals['new_pieces_qty'], vals['new_length'],
                    vals['new_heigth'], lot_brw.width)
                diff = area_new - area_old
                vals.update({
                    'diff': diff,
                    'new_quantity': area_new,
                    'length': vals['new_length'],
                    'heigth': vals['new_heigth'],
                    'width': vals['new_width'],
                    'pieces_qty': pieces,
                    'quantity': lot_brw.virtual,
                    'company_id': company_id[0]
                })

        return super(changes_production_lot_stock, self).write(cr,
                                                               uid,
                                                               ids,
                                                               vals,
                                                               context=context)

    def unlink(self, cr, uid, ids, context=None):
        """
         Modified to avoid delete a line of change confirmed
        
        """

        changes_orders = self.browse(cr, uid, ids, context=context)
        unlink_ids = []
        for s in changes_orders:
            if s.description_stock_id.state in ('draft'):
                unlink_ids.append(s.id)
            else:
                raise osv.except_osv(
                    _('Invalid action !'),
                    _('Cannot delete this changes which are already confirmed !'
                      ))
        return super(changes_production_lot_stock, self).unink(cr,
                                                               uid,
                                                               unlink_ids,
                                                               context=context)

    def onchange_changes_stock(self,
                               cr,
                               uid,
                               ids,
                               name,
                               length,
                               heigth,
                               width,
                               quantity,
                               new_length,
                               new_heigth,
                               new_width,
                               new_pieces_qty,
                               context=None):
        print "ids", ids
        if context is None:
            context = {}
        res = {'value': {}}
        lot_obj = self.pool.get('stock.production.lot')
        stock_move_obj = self.pool.get('stock.move')
        product_obj = self.pool.get('product.uom')
        if name:
            lot_brw = lot_obj.browse(cr, uid, name, context=None)
            area_org = quantity
            if lot_brw.product_id.stock_driver in ('slab', 'block'):
                new_pieces_qty = 1
                res['value'].update({'new_pieces_qty': new_pieces_qty})
            area_new = product_obj._compute_area(
                cr, uid, lot_brw.product_id.stock_driver, new_pieces_qty,
                new_length, new_heigth, new_width)
            diff = area_new - area_org
            res['value'].update({'new_quantity': area_new})
            res['value'].update({'diff': diff})

        return res

    def onchage_default(self, cr, uid, ids, lot_number, context=None):
        """
        @param lot_number id of the lot for add the values by fefault
        """
        if context is None:
            context = {}
        res = {'value': {}}
        lot_obj = self.pool.get('stock.production.lot')
        stock_move_obj = self.pool.get('stock.move')
        product_obj = self.pool.get('product.uom')
        if lot_number:
            lot_brw = lot_obj.browse(cr, uid, lot_number, context=None)
            res['value'].update({'length': lot_brw.length})
            res['value'].update({'heigth': lot_brw.heigth})
            res['value'].update({'width': lot_brw.width})
            res['value'].update({'quantity': lot_brw.virtual})
            res['value'].update({
                'pieces_qty':
                product_obj._compute_pieces2(cr, uid,
                                             lot_brw.product_id.stock_driver,
                                             lot_brw.virtual, lot_brw.length,
                                             lot_brw.heigth, lot_brw.width)
            })

            if lot_brw.product_id.stock_driver == 'normal':
                res['value'].update({'factor': 3})
                res['value'].update({'new_length': lot_brw.length})
                res['value'].update({'new_heigth': lot_brw.heigth})
                res['value'].update({'new_width': lot_brw.width})

            if lot_brw.product_id.stock_driver == 'tile':
                res['value'].update({'factor': 2})
                res['value'].update(
                    {'new_length': lot_brw.product_id.tile_format_id.length})
                res['value'].update(
                    {'new_heigth': lot_brw.product_id.tile_format_id.heigth})

            if lot_brw.product_id.stock_driver == 'slab':
                res['value'].update({'factor': 1})
                res['value'].update({'new_length': lot_brw.length})
                res['value'].update({'new_heigth': lot_brw.heigth})
                res['value'].update({'new_width': lot_brw.width})

            if lot_brw.product_id.stock_driver == 'block':
                res['value'].update({'factor': 0})
                res['value'].update({'new_length': lot_brw.length})
                res['value'].update({'new_heigth': lot_brw.heigth})
                res['value'].update({'new_width': lot_brw.width})

        return res
    def agg_righe_provdoc(self, cr, uid, doc_id, context):
            if doc_id:
                
              if type(doc_id)==type([]):
                    doc = self.pool.get('fiscaldoc.header').browse(cr,uid,doc_id)[0]
              else:
                    doc = self.pool.get('fiscaldoc.header').browse(cr,uid,doc_id)
              if doc.tipo_doc.tipo_documento <> 'DT':
                part = doc.partner_id
                lista={}
                lista2={}
                for riga in doc.righe_articoli:
                    if riga.name.sconto_partner or riga.name.sconto_pagamento:
                        netto = riga.totale_riga
                        if riga.name.sconto_partner:
                            netto = netto-(netto*riga.name.sconto_partner/100)
                            netto = arrot(cr,uid,netto,dp.get_precision('Account'))
                        if riga.name.sconto_pagamento:
                            netto = netto-(netto*riga.name.sconto_pagamento/100)
                            netto = arrot(cr,uid,netto,dp.get_precision('Account'))
                    else:
                        netto = riga.totale_riga
                    netto = arrot(cr,uid,netto,dp.get_precision('Account'))
                    
                    if lista.get(riga.perc_provv,False):
                        # esiste già una riga di provvigione uguale
                        dati_record = lista[riga.perc_provv]                        
                        imponibile = netto
                        provvigione = imponibile * riga.perc_provv/100
                        dati_record['imponibile'] += imponibile
                        if doc.tipo_doc.tipo_documento <> 'NC':
                            dati_record['provvigione'] += provvigione
                        else:
                            dati_record['provvigione'] += provvigione*-1
                        lista[riga.perc_provv] = dati_record
                    else:
                        # nuova riga di provvigione
                        imponibile = netto
                        if doc.tipo_doc.tipo_documento <> 'NC':
                            provvigione = imponibile * riga.perc_provv/100
                        else:
                            provvigione = imponibile * riga.perc_provv/100*-1
                        
                        dati_record = {'imponibile':imponibile,'provvigione':provvigione}
                        lista.update({riga.perc_provv:dati_record})
                        
                    if lista2.get(riga.perc_provvag2,False):
                        # esiste già una riga di provvigione uguale
                        dati_record = lista2[riga.perc_provvag2]                        
                        imponibile = netto
                        provvigione = imponibile * riga.perc_provvag2/100
                        dati_record['imponibile'] += imponibile
                        if doc.tipo_doc.tipo_documento <> 'NC':
                            dati_record['provvigione'] += provvigione
                        else:
                            dati_record['provvigione'] += provvigione*-1

                        lista2[riga.perc_provvag2] = dati_record
                    else:
                        # nuova riga di provvigione
                        imponibile = netto
                        if doc.tipo_doc.tipo_documento <> 'NC':
                            provvigione = imponibile * riga.perc_provvag2/100
                        else:
                            provvigione = imponibile * riga.perc_provvag2/100*-1
                        
                        
                        dati_record = {'imponibile':imponibile,'provvigione':provvigione}
                        lista.update({riga.perc_provvag2:dati_record})


                lines = self.search(cr, uid, [('name', '=', part.agent_id.id),('documento_id','=',doc.id)])
                if lines:
                    res = self.unlink(cr, uid, lines, context) 
                if lista:
                    for riga in lista:
                        if lista[riga]['provvigione']<>0:
                         record = {
                                  'name':part.agent_id.id,
                                  'documento_id':doc.id,
                                  'imponibile':lista[riga]['imponibile'],
                                  'provvigione':lista[riga]['provvigione'],
                                  'commission_rate':riga,
                                  } 
                     
                         id_r= self.create(cr,uid,record)
                lines = self.search(cr, uid, [('name', '=', part.agent2_id.id),('documento_id','=',doc.id)])
                if lines:
                    res = self.unlink(cr, uid, lines, context) 
                if lista2:
                    for riga in lista2:
                        record = {
                                  'name':part.agent2_id.id,
                                  'documento_id':doc.id,
                                  'imponibile':lista2[riga]['imponibile'],
                                  'provvigione':lista2[riga]['provvigione'],
                                  'commission_rate':riga,
                                  } 
                     
                        id_r= self.create(cr,uid,record)

            return True
Example #28
0
class product_variant_dimension_value(osv.osv):
    _name = "product.variant.dimension.value"
    _description = "Dimension Value"
    _rec_name = "option_id"

    def unlink(self, cr, uid, ids, context=None):
        for value in self.browse(cr, uid, ids, context=context):
            if value.product_ids:
                product_list = '\n    - ' + '\n    - '.join(
                    [product.name for product in value.product_ids])
                raise osv.except_osv(
                    _('Dimension value can not be removed'),
                    _("The value %s is used in the product : %s \n Please remove this product before removing the value"
                      % (value.option_id.name, product_list)))
        return super(product_variant_dimension_value,
                     self).unlink(cr, uid, ids, context)

    def _get_dimension_values(self, cr, uid, ids, context=None):
        return self.pool.get('product.variant.dimension.value').search(
            cr, uid, [('dimension_id', 'in', ids)], context=context)

    _columns = {
        'option_id':
        fields.many2one('product.variant.dimension.option',
                        'Option',
                        required=True),
        'sequence':
        fields.integer('Sequence'),
        'price_extra':
        fields.float('Sale Price Extra',
                     digits_compute=dp.get_precision('Sale Price')),
        'price_margin':
        fields.float('Sale Price Margin',
                     digits_compute=dp.get_precision('Sale Price')),
        'cost_price_extra':
        fields.float('Cost Price Extra',
                     digits_compute=dp.get_precision('Purchase Price')),
        'dimension_id':
        fields.related('option_id',
                       'dimension_id',
                       type="many2one",
                       relation="product.variant.dimension.type",
                       string="Dimension Type",
                       store=True),
        'product_tmpl_id':
        fields.many2one('product.template',
                        'Product Template',
                        ondelete='cascade'),
        'dimension_sequence':
        fields.related(
            'dimension_id',
            'sequence',
            string=
            "Related Dimension Sequence",  #used for ordering purposes in the "variants"
            store={
                'product.variant.dimension.type':
                (_get_dimension_values, ['sequence'], 10),
            }),
        'product_ids':
        fields.many2many('product.product',
                         'product_product_dimension_rel',
                         'dimension_id',
                         'product_id',
                         'Variant',
                         readonly=True),
        'active':
        fields.boolean(
            'Active?',
            help=
            "If false, this value will be not use anymore for generating variant"
        ),
    }

    _defaults = {
        'active': lambda *a: 1,
    }

    _order = "dimension_sequence, sequence, option_id"
Example #29
0
class stock_picking_out(osv.osv):

    _inherit = "stock.picking.out"

    def _total_weight_net(self, cr, uid, ids, field_name, arg, context=None):
        return self.pool.get('stock.picking')._total_weight_net(
            cr, uid, ids, field_name, arg, context)

    def _get_order(self, cr, uid, ids, context=None):
        return self.pool.get('stock.picking')._get_order(cr, uid, ids, context)

    def _total_ord_weight_net(self,
                              cr,
                              uid,
                              ids,
                              field_name,
                              arg,
                              context=None):
        return self.pool.get('stock.picking')._total_ord_weight_net(
            cr, uid, ids, field_name, arg, context)

    def _get_company_code(self, cr, user, context=None):
        return self.pool.get('stock.picking')._get_company_code(
            cr, user, context)

    def onchange_logis_company(self,
                               cr,
                               uid,
                               ids,
                               logistic_company_id,
                               context=None):
        return self.pool.get('stock.picking').onchange_logis_company(
            cr, uid, ids, logistic_company_id, context)

    def distribute_weight(self, cr, uid, ids, context=None):
        return self.pool.get('stock.picking').distribute_weight(
            cr, uid, ids, context)

    def process_ship(self, cr, uid, ids, context=None):
        return self.pool.get('stock.picking').process_ship(
            cr, uid, ids, context)

    _columns = {
        'logis_company':
        fields.many2one(
            'logistic.company',
            'Shipper Company',
            help='Name of the Logistics company providing the shipper services.'
        ),
        'freight':
        fields.boolean(
            'Shipment',
            help='Indicates if the shipment is a freight shipment.'),
        'sat_delivery':
        fields.boolean(
            'Saturday Delivery',
            help='Indicates is it is appropriate to send delivery on Saturday.'
        ),
        'package_type':
        fields.selection([('01', 'Letter'),
                          ('02', 'Customer Supplied Package'), ('03', 'Tube'),
                          ('04', 'PAK'), ('21', 'ExpressBox'),
                          ('24', '25KG Box'), ('25', '10KG Box'),
                          ('30', 'Pallet'), ('2a', 'Small Express Box'),
                          ('2b', 'Medium Express Box'),
                          ('2c', 'Large Express Box')],
                         'Package Type',
                         help='Indicates the type of package'),
        'bill_shipping':
        fields.selection([('shipper', 'Shipper'), ('receiver', 'Receiver'),
                          ('thirdparty', 'Third Party')],
                         'Bill Shipping to',
                         help='Shipper, Receiver, or Third Party.'),
        'with_ret_service':
        fields.boolean(
            'With Return Services',
            help='Include Return Shipping Information in the package.'),
        'tot_ship_weight':
        fields.function(
            _total_weight_net,
            method=True,
            type='float',
            digits=(16, 3),
            string='Shipment Weight',
            store={
                'stock.picking':
                (lambda self, cr, uid, ids, c={}: ids, ['packages_ids'], -10),
                'stock.packages': (_get_order, ['weight'], -10),
            },
            help=
            "Adds the Total Weight of all the packages in the Packages Table.",
        ),
        'tot_del_order_weight':
        fields.function(
            _total_ord_weight_net,
            method=True,
            readonly=True,
            string='Total Order Weight',
            store=False,
            help=
            "Adds the Total Weight of all the packages in the Packages Table."
        ),
        'packages_ids':
        fields.one2many("stock.packages", 'pick_id', 'Packages Table'),
        'shipcharge':
        fields.float('Shipping Cost', readonly=True),
        'ship_state':
        fields.selection([('draft', 'Draft'), ('in_process', 'In Process'),
                          ('ready_pick', 'Ready for Pickup'),
                          ('shipped', 'Shipped'), ('delivered', 'Delivered'),
                          ('void', 'Void'), ('hold', 'Hold'),
                          ('cancelled', 'Cancelled')],
                         'Shipping Status',
                         readonly=True,
                         help='The current status of the shipment'),
        'trade_mark':
        fields.text('Trademarks AREA'),
        'ship_message':
        fields.text('Message'),
        'address_validate':
        fields.selection([('validate', 'Validate'),
                          ('nonvalidate', 'No Validation')],
                         'Address Validation',
                         help=''' No Validation = No address validation.
                                              Validate = Fail on failed address validation.
                                              Defaults to validate. Note: Full address validation is not performed. Therefore, it is
                                              the responsibility of the Shipping Tool User to ensure the address entered is correct to
                                              avoid an address correction fee.'''
                         ),
        'ship_description':
        fields.text('Description'),
        'ship_from':
        fields.boolean(
            'Ship From',
            help=
            'Required if pickup location is different from the shipper\'s address..'
        ),
        'ship_from_tax_id_no':
        fields.char('Identification Number', size=64, select=1),
        'ship_from_address':
        fields.many2one('res.partner', 'Ship From Address'),
        #         'address': fields.many2one('res.partner', 'Ship From Address'),
        'tot_order_weight':
        fields.related('sale_id',
                       'total_weight_net',
                       type='float',
                       relation='sale.order',
                       string='Total Order Weight'),
        'comm_inv':
        fields.boolean('Commercial Invoice'),
        'cer_orig':
        fields.boolean('U.S. Certificate of Origin'),
        'nafta_cer_orig':
        fields.boolean('NAFTA Certificate of Origin'),
        'sed':
        fields.boolean('Shipper Export Declaration (SED)'),
        'prod_option':
        fields.selection([('01', 'AVAILABLE TO CUSTOMS UPON REQUEST'),
                          ('02', 'SAME AS EXPORTER'), ('03', 'ATTACHED LIST'),
                          ('04', 'UNKNOWN'), (' ', ' ')], 'Option'),
        'prod_company':
        fields.char(
            'CompanyName',
            size=256,
            help='Only applicable when producer option is empty or not present.'
        ),
        'prod_tax_id_no':
        fields.char(
            'TaxIdentificationNumber',
            size=256,
            help='Only applicable when producer option is empty or not present.'
        ),
        'prod_address_id':
        fields.many2one(
            'res.partner',
            'Producer Address',
            help='Only applicable when producer option is empty or not present.'
        ),
        'inv_option':
        fields.selection([('01', 'Unknown'), ('02', 'Various'), (' ', ' ')],
                         'Sold to Option'),
        'inv_company':
        fields.char(
            'CompanyName',
            size=256,
            help='Only applicable when Sold to option is empty or not present.'
        ),
        'inv_tax_id_no':
        fields.char(
            'TaxIdentificationNumber',
            size=256,
            help='Only applicable when Sold to option is empty or not present.'
        ),
        'inv_att_name':
        fields.char(
            'AttentionName',
            size=256,
            help='Only applicable when Sold to option is empty or not present.'
        ),
        'inv_address_id':
        fields.many2one(
            'res.partner',
            'Sold To Address',
            help='Only applicable when Sold to option is empty or not present.'
        ),
        'blanket_begin_date':
        fields.date('Blanket Begin Date'),
        'blanket_end_date':
        fields.date('Blanket End Date'),
        'comm_code':
        fields.char(
            'Commodity Code',
            size=256,
        ),
        'exp_carrier':
        fields.char('ExportingCarrier', size=256),
        'ship_company_code':
        fields.selection(_get_company_code,
                         'Ship Company',
                         method=True,
                         size=64),
        'ship_charge':
        fields.float('Value', digits_compute=dp.get_precision('Account'))
    }

    _defaults = {
        'address_validate': 'nonvalidate',
        'comm_inv': False,
        'cer_orig': False,
        'nafta_cer_orig': False,
        'sed': False,
        'ship_state': 'draft',
        'bill_shipping': 'shipper',
        'ship_charge': 0.0
    }

    def print_labels(self, cr, uid, ids, context=None):
        if not ids: return []
        return {
            'type': 'ir.actions.report.xml',
            'report_name': 'multiple.label.print',
            'datas': {
                'model': 'stock.picking',
                'id': ids and ids[0] or False,
                'ids': ids,
                'report_type': 'pdf'
            },
            'nodestroy': True
        }

    def print_packing_slips(self, cr, uid, ids, context=None):
        if not ids: return []
        packages_ids = []
        for package in self.browse(cr, uid, ids[0]).packages_ids:
            packages_ids.append(package.id)
        x = {
            'type': 'ir.actions.report.xml',
            'report_name': 'package.packing.slip.print',
            'datas': {
                'model': 'stock.packages',
                'id': ids and ids[0] or False,
                'ids': packages_ids,
                'report_type': 'pdf'
            },
            'nodestroy': True
        }
        return x
Example #30
0
class product_product(product_variant_osv):
    _inherit = "product.product"

    def init(self, cr):
        #For the first installation if you already have product in your database the name of the existing product will be empty, so we fill it
        cr.execute(
            "update product_product set name=name_template where name is null;"
        )
        return True

    def unlink(self, cr, uid, ids, context=None):
        if context is None:
            context = {}
        context['unlink_from_product_product'] = True
        return super(product_product, self).unlink(cr, uid, ids, context)

    def build_product_name(self, cr, uid, ids, context=None):
        return self.build_product_field(cr, uid, ids, 'name', context=None)

    def build_product_field(self, cr, uid, ids, field, context=None):
        if context is None:
            context = {}

        def get_description_sale(product):
            return self.parse(cr,
                              uid,
                              product,
                              product.product_tmpl_id.description_sale,
                              context=context)

        def get_name(product):
            if context.get('variants_values', False):
                return (product.product_tmpl_id.name or '') + ' ' + (
                    context['variants_values'][product.id] or '')
            return (product.product_tmpl_id.name
                    or '') + ' ' + (product.variants or '')

        context['is_multi_variants'] = True
        obj_lang = self.pool.get('res.lang')
        lang_ids = obj_lang.search(cr,
                                   uid, [('translatable', '=', True)],
                                   context=context)
        lang_code = [
            x['code'] for x in obj_lang.read(
                cr, uid, lang_ids, ['code'], context=context)
        ]
        for code in lang_code:
            context['lang'] = code
            for product in self.browse(cr, uid, ids, context=context):
                new_field_value = eval(
                    "get_" + field + "(product)")  # TODO convert to safe_eval
                cur_field_value = safe_eval("product." + field,
                                            {'product': product})
                if new_field_value != cur_field_value:
                    self.write(cr,
                               uid,
                               product.id, {field: new_field_value},
                               context=context)
        return True

    def write(self, cr, uid, ids, vals, context=None):
        if isinstance(ids, (int, long)):
            ids = [ids]
        if context is None:
            context = {}
        res = super(product_product, self).write(cr,
                                                 uid,
                                                 ids,
                                                 vals.copy(),
                                                 context=context)

        ids_simple = self.search(
            cr,
            uid, [['id', 'in', ids], ['is_multi_variants', '=', False]],
            context=context)

        if not context.get('iamthechild', False) and ids_simple:
            vals_to_write = self.get_vals_to_write(vals)

            if vals_to_write:
                obj_tmpl = self.pool.get('product.template')
                ctx = context.copy()
                ctx['iamthechild'] = True
                tmpl_ids = obj_tmpl.search(cr, uid,
                                           [['variant_ids', 'in', ids_simple]])
                obj_tmpl.write(cr, uid, tmpl_ids, vals_to_write, context=ctx)
        return res

    def create(self, cr, uid, vals, context=None):
        #TAKE CARE for inherits objects openerp will create firstly the product_template and after the product_product
        # and so the duplicated fields (duplicated field = field which are on the template and on the variant) will be on the product_template and not on the product_product
        #Also when a product is created the duplicated field are empty for the product.product, this is why the field name can not be a required field
        #This should be fix in the orm in the futur
        ids = super(product_product, self).create(
            cr, uid, vals.copy(), context=context
        )  #using vals.copy() if not the vals will be changed by calling the super method
        ####### write the value in the product_product
        if context is None:
            context = {}
        ctx = context.copy()
        ctx['iamthechild'] = True
        vals_to_write = self.get_vals_to_write(vals)
        if vals_to_write:
            self.write(cr, uid, ids, vals_to_write, context=ctx)
        return ids

    def parse(self, cr, uid, o, text, context=None):
        if not text:
            return ''
        vals = text.split('[_')
        description = ''
        for val in vals:
            if '_]' in val:
                sub_val = val.split('_]')
                try:
                    description += (safe_eval(sub_val[0], {
                        'o': o,
                        'context': context
                    }) or '') + sub_val[1]
                except:
                    LOGGER.notifyChannel(
                        'product_variant_multi', netsvc.LOG_ERROR,
                        "%s can't eval. Description is blank" % (sub_val[0]))
                    description += ''
            else:
                description += val
        return description

    def generate_product_code(self,
                              cr,
                              uid,
                              product_obj,
                              code_generator,
                              context=None):
        '''I wrote this stupid function to be able to inherit it in a custom module !'''
        return self.parse(cr,
                          uid,
                          product_obj,
                          code_generator,
                          context=context)

    def build_product_code_and_properties(self, cr, uid, ids, context=None):
        if context is None:
            context = {}
        for product in self.browse(cr, uid, ids, context=context):
            new_default_code = self.generate_product_code(
                cr,
                uid,
                product,
                product.product_tmpl_id.code_generator,
                context=context)
            current_values = {
                'default_code': product.default_code,
                'track_production': product.track_production,
                'track_outgoing': product.track_outgoing,
                'track_incoming': product.track_incoming,
            }
            new_values = {
                'default_code': new_default_code,
                'track_production':
                product.product_tmpl_id.variant_track_production,
                'track_outgoing':
                product.product_tmpl_id.variant_track_outgoing,
                'track_incoming':
                product.product_tmpl_id.variant_track_incoming,
            }
            if new_values != current_values:
                self.write(cr, uid, product.id, new_values, context=context)
        return True

    def product_ids_variant_changed(self, cr, uid, ids, res, context=None):
        '''it's a hook for product_variant_multi advanced'''
        return True

    def generate_variant_name(self, cr, uid, product_id, context=None):
        '''Do the generation of the variant name in a dedicated function, so that we can
        inherit this function to hack the code generation'''
        if context is None:
            context = {}
        product = self.browse(cr, uid, product_id, context=context)
        model = product.variant_model_name
        r = map(
            lambda dim: [
                dim.dimension_id.sequence,
                self.parse(cr, uid, dim, model, context=context)
            ], product.dimension_value_ids)
        r.sort()
        r = [x[1] for x in r]
        new_variant_name = (product.variant_model_name_separator or '').join(r)
        return new_variant_name

    def build_variants_name(self, cr, uid, ids, context=None):
        for product in self.browse(cr, uid, ids, context=context):
            new_variant_name = self.generate_variant_name(cr,
                                                          uid,
                                                          product.id,
                                                          context=context)
            if new_variant_name != product.variants:
                self.write(cr,
                           uid,
                           product.id, {'variants': new_variant_name},
                           context=context)
        return True

    def _check_dimension_values(
        self, cr, uid, ids
    ):  # TODO: check that all dimension_types of the product_template have a corresponding dimension_value ??
        for p in self.browse(cr, uid, ids, {}):
            buffer = []
            for value in p.dimension_value_ids:
                buffer.append(value.dimension_id)
            unique_set = set(buffer)
            if len(unique_set) != len(buffer):
                return False
        return True

    def compute_product_dimension_extra_price(self,
                                              cr,
                                              uid,
                                              product_id,
                                              product_price_extra=False,
                                              dim_price_margin=False,
                                              dim_price_extra=False,
                                              context=None):
        if context is None:
            context = {}
        dimension_extra = 0.0
        product = self.browse(cr, uid, product_id, context=context)
        for dim in product.dimension_value_ids:
            if product_price_extra and dim_price_margin and dim_price_extra:
                dimension_extra += safe_eval(
                    'product.' + product_price_extra,
                    {'product': product}) * safe_eval(
                        'dim.' + dim_price_margin, {'dim': dim}) + safe_eval(
                            'dim.' + dim_price_extra, {'dim': dim})
            elif not product_price_extra and not dim_price_margin and dim_price_extra:
                dimension_extra += safe_eval('dim.' + dim_price_extra,
                                             {'dim': dim})
            elif product_price_extra and dim_price_margin and not dim_price_extra:
                dimension_extra += safe_eval('product.' + product_price_extra,
                                             {'product': product}) * safe_eval(
                                                 'dim.' + dim_price_margin,
                                                 {'dim': dim})
            elif product_price_extra and not dim_price_margin and dim_price_extra:
                dimension_extra += safe_eval('product.' + product_price_extra,
                                             {'product': product}) + safe_eval(
                                                 'dim.' + dim_price_extra,
                                                 {'dim': dim})

        if 'uom' in context:
            product_uom_obj = self.pool.get('product.uom')
            uom = product.uos_id or product.uom_id
            dimension_extra = product_uom_obj._compute_price(
                cr, uid, uom.id, dimension_extra, context['uom'])
        return dimension_extra

    def compute_dimension_extra_price(self,
                                      cr,
                                      uid,
                                      ids,
                                      result,
                                      product_price_extra=False,
                                      dim_price_margin=False,
                                      dim_price_extra=False,
                                      context=None):
        if context is None:
            context = {}
        for product in self.browse(cr, uid, ids, context=context):
            dimension_extra = self.compute_product_dimension_extra_price(
                cr,
                uid,
                product.id,
                product_price_extra=product_price_extra,
                dim_price_margin=dim_price_margin,
                dim_price_extra=dim_price_extra,
                context=context)
            result[product.id] += dimension_extra
        return result

    def price_get(self, cr, uid, ids, ptype='list_price', context=None):
        if context is None:
            context = {}
        result = super(product_product, self).price_get(cr,
                                                        uid,
                                                        ids,
                                                        ptype,
                                                        context=context)
        if ptype == 'list_price':  #TODO check if the price_margin on the dimension is very usefull, maybe we will remove it
            result = self.compute_dimension_extra_price(
                cr,
                uid,
                ids,
                result,
                product_price_extra='price_extra',
                dim_price_margin='price_margin',
                dim_price_extra='price_extra',
                context=context)

        elif ptype == 'standard_price':
            result = self.compute_dimension_extra_price(
                cr,
                uid,
                ids,
                result,
                product_price_extra='cost_price_extra',
                dim_price_extra='cost_price_extra',
                context=context)
        return result

    def _product_lst_price(self, cr, uid, ids, name, arg, context=None):
        if context is None:
            context = {}
        result = super(product_product,
                       self)._product_lst_price(cr,
                                                uid,
                                                ids,
                                                name,
                                                arg,
                                                context=context)
        result = self.compute_dimension_extra_price(
            cr,
            uid,
            ids,
            result,
            product_price_extra='price_extra',
            dim_price_margin='price_margin',
            dim_price_extra='price_extra',
            context=context)
        return result

    def copy(self, cr, uid, id, default=None, context=None):
        if default is None:
            default = {}
        default = default.copy()
        default.update({
            'variant_ids': False,
        })
        return super(product_product, self).copy(cr, uid, id, default, context)

    def _product_compute_weight_volume(self,
                                       cr,
                                       uid,
                                       ids,
                                       fields,
                                       arg,
                                       context=None):
        result = {}
        # print 'compute', ids, fields, context
        for product in self.browse(cr, uid, ids, context=context):
            result[product.id] = {}
            result[product.
                   id]['weight'] = product.weight + product.additional_weight
            result[product.id][
                'weight_net'] = product.weight_net + product.additional_weight_net
            result[product.
                   id]['volume'] = product.volume + product.additional_volume
        return result

    _columns = {
        'name':
        fields.char('Name', size=128, translate=True, select=True),
        'dimension_value_ids':
        fields.many2many('product.variant.dimension.value',
                         'product_product_dimension_rel',
                         'product_id',
                         'dimension_id',
                         'Dimensions',
                         domain="[('product_tmpl_id','=',product_tmpl_id)]"),
        'cost_price_extra':
        fields.float('Purchase Extra Cost',
                     digits_compute=dp.get_precision('Purchase Price')),
        'lst_price':
        fields.function(_product_lst_price,
                        method=True,
                        type='float',
                        string='List Price',
                        digits_compute=dp.get_precision('Sale Price')),
        #the way the weight are implemented are not clean at all, we should redesign the module product form the addons in order to get something correclty.
        #indeed some field of the template have to be overwrited like weight, name, weight_net, volume.
        #in order to have a consitent api we should use the same field for getting the weight, now we have to use "weight" or "total_weight" not clean at all with external syncronization
        'total_weight':
        fields.function(_product_compute_weight_volume,
                        method=True,
                        type='float',
                        string='Gross weight',
                        help="The gross weight in Kg.",
                        multi='weight_volume'),
        'total_weight_net':
        fields.function(_product_compute_weight_volume,
                        method=True,
                        type='float',
                        string='Net weight',
                        help="The net weight in Kg.",
                        multi='weight_volume'),
        'total_volume':
        fields.function(_product_compute_weight_volume,
                        method=True,
                        type='float',
                        string='Volume',
                        help="The volume in m3.",
                        multi='weight_volume'),
        'additional_weight':
        fields.float('Additional Gross weight',
                     help="The additional gross weight in Kg."),
        'additional_weight_net':
        fields.float('Additional Net weight',
                     help="The additional net weight in Kg."),
        'additional_volume':
        fields.float('Additional Volume', help="The additional volume in Kg."),
    }
    _constraints = [
        (_check_dimension_values,
         'Several dimension values for the same dimension type',
         ['dimension_value_ids']),
    ]
Example #31
0
class member(osv.osv):
    '''会员信息设置'''
    _name = "member_management.member"
    _descripton = "会员信息"

    _rec_name = "member_no"

    def _compute_balance_and_points(self, cr, uid, ids, field_name, args,
                                    context):
        '''
      计算卡余额与积分
      '''
        ret = {}

        for record in self.browse(cr, uid, ids):
            sum_charge = sum_present_charge_fee = sum_consumption = sum_balance = 0.0
            sum_points = 0
            for charge in record.member_charge_ids:
                sum_charge += charge.charge_fee  #充值金额合计
                sum_present_charge_fee += charge.present_charge_fee  #充值赠送金额合计
            for consumption in record.member_consumption_ids:
                sum_consumption += consumption.paid_fee
                sum_points += consumption.points

            ret[record.id] = {
                'balance':
                sum_charge + sum_present_charge_fee - sum_consumption,
                #TODO  计算积分点数时,需要减去积分兑换中扣除的积分
                'points': sum_points,
            }

        return ret

    _columns = {
        "member_no":
        fields.char("member_no",
                    size=30,
                    readonly=True,
                    select=True,
                    help="会员编号,由系统自动生成",
                    required=True),
        "name":
        fields.char("name", size=20, required=True, help="会员名称"),
        "member_class_id":
        fields.many2one("member_management.member_class",
                        "member_class_id",
                        select=True,
                        required=True,
                        help="会员等级"),
        "member_card_no":
        fields.char("card_id",
                    size=30,
                    select=True,
                    required=True,
                    help="会员卡号,卡具上印刷的编号"),
        "photo":
        fields.binary("photo", filter=".jpg,.png,.bmp"),
        "card_fee":
        fields.float("make_fee", digits=(10, 2), help="制卡费用,默认取会员等级中的制卡费用"),
        "up_card_fee":
        fields.float("up_card_fee", digits=(10, 2), help="补卡费用,默认取会员等级中的制卡费用"),
        "begin_datetime":
        fields.datetime("begin_datetime",
                        readonly=True,
                        required=True,
                        help="发卡时间"),
        "valid_date":
        fields.date("valid_date", help="卡有效期"),
        "overdraft_fee":
        fields.float("overdraft_fee", digits=(10, 2), help="可透支额度"),
        "card_password":
        fields.char("card_password", size=20, required=True, help="卡密码,不可为空"),
        "phone":
        fields.char("phone", size=20, help="联系电话"),
        "birthday":
        fields.date("birthday", help="联系电话"),
        "sex":
        fields.selection(helper.sexes_for_select, "sex", help="性别"),
        "id_type":
        fields.selection(helper.id_types_for_select, "id_type", help="证件类型"),
        "id_no":
        fields.char("id_no", size=30, help="证件号码"),
        "v_no":
        fields.char("v_no", size=30, help="车牌号码"),
        "qq":
        fields.char("qq", size=30, help="QQ号码"),
        "email":
        fields.char("email", size=30, help="邮件地址"),
        "company":
        fields.char("company", size=30, help="工作单位"),
        "address":
        fields.char("address", size=60, help="地址"),
        "member_charge_ids":
        fields.one2many('member_management.member_charge',
                        'member_id',
                        help="会员充值记录"),
        "member_consumption_ids":
        fields.one2many('member_management.member_consumption',
                        'member_id',
                        help="会员消费记录"),
        "balance":
        fields.function(
            _compute_balance_and_points,
            type='float',
            multi="compute_fields",
            string="balance",
            digits_compute=dp.get_precision('member_management_fee'),
            help="卡余额"),
        "points":
        fields.function(_compute_balance_and_points,
                        type='integer',
                        multi="cimpute_fields",
                        string="points",
                        help="卡积分"),
        "card_state":
        fields.boolean("state"),
        "active":
        fields.boolean("active"),
        'room_fee_discount':
        fields.related('member_class_id',
                       'room_fee_discount',
                       type='float',
                       string='房费折扣'),
        'drinks_fee_discount':
        fields.related('member_class_id',
                       'drinks_fee_discount',
                       type='float',
                       string='酒水费折扣'),
    }
    _defaults = {
        "active":
        True,
        "card_state":
        True,
        "card_fee":
        0.0,
        'up_card_fee':
        0.0,
        "overdraft_fee":
        0.0,
        'begin_datetime':
        fields.datetime.now,
        'member_no':
        lambda obj, cr, uid, context: obj.pool.get('ir.sequence').get(
            cr, uid, 'member_management.member'),
        'balance':
        0.0,
    }

    def calculate_casher_shift_report(self, cr, uid, start_datetime,
                                      end_datetime):
        '''
        计算会员卡业务发生情况
        :param start_datetime datetime 业务起始时间
        :param end_datetime datetime 业务结束时间
        :return dict 
                'member_card_count'      新会员数量
                'member_card_fee'   会员卡销售金额
                'member_charge_fee' 会员充值金额
        '''
        pool = self.pool
        #计算新办会员卡数量
        ids = self.search(
            cr, uid,
            [('begin_datetime', '>=', helper.strftime(start_datetime)),
             ('begin_datetime', '<=', helper.strftime(end_datetime))])
        member_card_count = len(ids)
        member_card_fee = 0.0
        for r in self.browse(cr, uid, ids):
            member_card_fee += r.card_fee + r.up_card_fee

        #计算会员充值金额
        charge_fee = 0.0
        charge_ids =  pool.get('member_management.member_charge').search(cr,uid,[('bill_datetime','>=',helper.strftime(start_datetime)), \
            ('bill_datetime','<=',helper.strftime(end_datetime))])
        for r in pool.get('member_management.member_charge').browse(
                cr, uid, charge_ids):
            charge_fee += r.charge_fee

        return {
            'member_card_count': member_card_count,
            'new_member_card_fee': member_card_fee,
            'member_charge_fee': charge_fee,
        }
Example #32
0
class account_invoice(osv.osv):

    _inherit = "account.invoice"
    _name = "account.invoice"

    def _amount_all_3(self, cr, uid, ids, name, args, context=None):
        res = {}
        amount_untaxed = 0

        for invoice in self.browse(cr, uid, ids, context=context):
            res[invoice.id] = {
                'base_doce_iva': 0.00,
                'base_cero_iva': 0.00,
                'vat_doce_subtotal': 0.00,
                'vat_cero_subtotal': 0.00,
                'total_iva': 0.00,
                'total_with_vat': 0.00,
                'total_to_withhold': 0.00,
            }

        for line in invoice.invoice_line:
            amount_untaxed += line.price_subtotal

        for line in invoice.tax_line:
            if line.amount > 0:
                if line.type_ec == 'iva' and line.amount > 0:
                    res[invoice.id]['base_doce_iva'] += line.base
                    res[invoice.id]['vat_doce_subtotal'] += line.amount
                if line.type_ec == 'iva':
                    res[invoice.id]['total_iva'] += line.amount
            else:
                if line.type_ec == 'iva' and line.amount == 0 and not (
                        'RETENCION' in line.name):
                    res[invoice.id]['base_cero_iva'] += line.base
                    res[invoice.id]['vat_cero_subtotal'] += line.amount
                res[invoice.id]['total_to_withhold'] += line.amount

        res[invoice.id]['total_with_vat'] = amount_untaxed + res[invoice.id][
            'vat_cero_subtotal'] + res[invoice.id]['vat_doce_subtotal']

        return res

    _columns = {
        #TODO hacer obligatorio el campo name que almacenara el numero de la factura
        'internal_number':
        fields.char(
            'Invoice Number',
            size=17,
            readonly=False,
            help=
            "Unique number of the invoice, computed automatically when the invoice is created."
        ),
        #'supplier_invoice_number': fields.char('Supplier Invoice Number', size=18, help="The reference of this invoice as provided by the supplier.", readonly=True, states={'draft':[('readonly',False)]}),
        # 'shop_id':fields.many2one('sale.shop', 'Shop', readonly=True, states={'draft':[('readonly',False)]}),
        'printer_id':
        fields.many2one('sri.printer.point',
                        'Printer Point',
                        required=False,
                        ondelete='restrict'),
        'invoice_address':
        fields.char(
            "Invoice address",
            help=
            "Invoice address as in VAT document, saved in invoice only not in partner"
        ),
        'invoice_phone':
        fields.char(
            "Invoice phone",
            help=
            "Invoice phone as in VAT document, saved in invoice only not in partner"
        ),
        # invoice_rectification_id la factura a la cual se esta rectificando, invoice_rectification_ids las facturas que rectifican a la actual
        'invoice_rectification_id':
        fields.many2one(
            'account.invoice',
            'Modified Invoice',
            readonly=True,
            states={'draft': [('readonly', False)]},
            help="This field sets the invoice that is being modified",
            track_visibility='always'),
        'invoice_rectification_ids':
        fields.one2many(
            'account.invoice',
            'invoice_rectification_id',
            'Modified Invoices',
            readonly=True,
            help=
            "This field sets the invoices those are modifying the actual invoice",
            track_visibility='always'),
        'base_doce_iva':
        fields.function(_amount_all_3,
                        digits_compute=dp.get_precision('Account'),
                        string='IVA 12 Base',
                        store=True,
                        multi='all1'),
        'base_cero_iva':
        fields.function(_amount_all_3,
                        method=True,
                        digits_compute=dp.get_precision('Account'),
                        string='IVA 0 Base',
                        store=True,
                        multi='all1'),
        'vat_doce_subtotal':
        fields.function(_amount_all_3,
                        method=True,
                        digits_compute=dp.get_precision('Account'),
                        string='IVA 12 %',
                        store=True,
                        multi='all1'),
        'vat_cero_subtotal':
        fields.function(_amount_all_3,
                        method=True,
                        digits_compute=dp.get_precision('Account'),
                        string='IVA 0 %',
                        store=True,
                        multi='all1'),
        'total_iva':
        fields.function(_amount_all_3,
                        method=True,
                        digits_compute=dp.get_precision('Account'),
                        string='Total IVA',
                        store=True,
                        multi='all1'),
        'total_with_vat':
        fields.function(_amount_all_3,
                        method=True,
                        digits_compute=dp.get_precision('Account'),
                        string='Total with taxes',
                        store=True,
                        multi='all1'),
        'total_to_withhold':
        fields.function(_amount_all_3,
                        method=True,
                        digits_compute=dp.get_precision('Account'),
                        string='Total to withhold',
                        store=True,
                        multi='all1'),
    }

    RE_PREFIXED_INVOICE = re.compile('^\d+-\d+-\d+$')

    def __init__(self, pool, cr):
        """
        Durante la inicialización del modelo correremos un SQL para borrar una
        constraint de SQL que de alguna manera nunca fue borrada, y no tenemos
        en este OpenERP un mecanismo que gestione migraciones, por lo que este
        proceso deberíamos hacerlo manualmente.

        Cuando el módulo se inicializa (se construye) toma dos valores: el pool
        para poder obtener otros objetos, y el cr para ejecutar consultas de
        postgresql. Tomando ese cursor ejecutamos -LUEGO de llamar al super-
        una sentencia SQL de borrado de constraint:

        ALTER TABLE account_invoice DROP CONSTRAINT IF EXISTS account_invoice_number_uniq

        (http://www.postgresql.org/docs/9.1/static/sql-altertable.html).

        El nombre de la tabla está dado a falta de un nombre preconfigurado para
        la tabla en este modelo, por el nombre de la propia clase (account_invoice).

        El nombre de la constraint viene dado por lo reportado en FDU-636.

        Se envuelve todo en un try ... finally ya que, si no existen las tablas al momento
        de crear este modulo, entonces no deberia importarnos el hecho de que esta consulta
        sql falle por una tabla que no exista.
        :param pool:
        :param cr:
        :return:
        """
        super(account_invoice, self).__init__(pool, cr)
        try:
            cr.execute(
                'ALTER TABLE account_invoice DROP CONSTRAINT IF EXISTS account_invoice_number_uniq'
            )
            pass
        finally:
            pass  #ignoramos cualquier error.

    def _check_number_invoice(self, cr, uid, ids, context=None):
        res = True

    def unlink(self, cr, uid, ids, context=None):
        """
        Allow delete a invoice in draft state
        """
        invoices = self.read(cr, uid, ids, ['state'], context=context)
        unlink_ids = []

        for inv in invoices:
            if inv['state'] == 'draft':
                unlink_ids.append(inv['id'])
                # write False in the invoice number, this allow eliminate the invoice
                self.write(cr, uid, inv['id'], {'internal_number': False})
            else:
                raise osv.except_osv(
                    _('Invalid action!'),
                    _('You can delete Invoice in state Draft'))

        return super(account_invoice, self).unlink(cr, uid, unlink_ids,
                                                   context)

    def copy(self, cr, uid, id, default=None, context=None):
        """
        Copia una factura pero le pone el prefijo en lugar
        de copiar tambien el numero interno. si el numero
        interno no tiene forma de xxx-xxx-xxxxxx entonces
        no copia prefijo, pone una cadena vacia
        """
        obj = self.browse(cr, uid, id)
        default = default or {}

        internal_number = obj.internal_number
        if (self.RE_PREFIXED_INVOICE.match(internal_number)):
            default['internal_number'] = '-'.join(
                internal_number.split('-')[0:2] + [''])
        else:
            default['internal_number'] = ''
        default.update({'name': ''})

        return super(account_invoice, self).copy(cr, uid, id, default, context)

    def onchange_internal_number(self,
                                 cr,
                                 uid,
                                 ids,
                                 internal_number,
                                 context=None):

        value = {}

        if not internal_number:
            return {'value': value}
        internal_number = str(internal_number)
        number_split = str.split(internal_number, "-")

        if len(number_split) == 3 and number_split[2] != "":
            if len(number_split[2]) < 17:
                #require auto complete
                pos = 0
                fill = 9 - len(number_split[2])
                for car in number_split[2]:
                    if car != '0':
                        break
                    pos = pos + 1

                number_split[2] = number_split[
                    2][:pos] + "0" * fill + number_split[2][pos:]

                value.update({
                    'internal_number':
                    number_split[0] + "-" + number_split[1] + "-" +
                    number_split[2],
                })

        return {'value': value}

    def onchange_date_invoice(self, cr, uid, ids, date_invoice, context=None):
        '''
        Asigna un periodo fiscal acorde a la fecha
        '''
        res = {}
        warning = {}
        periodo = ""
        if not date_invoice:
            return {}
        obj_period = self.pool.get('account.period')
        period_id = obj_period.search(cr, uid,
                                      [('date_start', '<=', date_invoice),
                                       ('date_stop', '>=', date_invoice)])
        if not period_id:
            warning = {
                'title':
                _('Warning!'),
                'message':
                _('No existe un período contable para esta fecha. There is no date for this accounting period.'
                  )
            }
        else:
            period = obj_period.browse(cr, uid, period_id, context=context)
            periodo = period.pop().id
        res = {
            'value': {
                'period_id': periodo
            },
            'warning': warning,
            'domain': {}
        }
        return res

    def _default_printer_point(self, cr, uid, context=None):
        '''
        Si el usuario tiene configurado un printer point lo selecciona
        Caso contrario intenta con el 001-001
        '''

        printer_point_id = False
        #intenta el printer_point del usuario
        user_obj = self.pool.get('res.users')
        printer = user_obj.browse(cr, uid, uid).printer_id
        if printer:
            printer_point_id = printer.id
            return printer_point_id

        #si no esta definido usamos el primero que exista, usuallmente sera el 001-001
        printer_point_obj = self.pool.get('sri.printer.point')
        printer_point_id = printer_point_obj.search(cr, uid, [], limit=1)

        if printer_point_id:
            return printer_point_id[0]

        return None

    def _suggested_internal_number(self,
                                   cr,
                                   uid,
                                   printer_id=None,
                                   type=None,
                                   company_id=None,
                                   context=None):
        '''Numero de factura sugerida para facturas de venta y compra, depende del punto de impresion
           Puede ser redefinida posteriormente por ejemplo para numeracion automatica
        '''
        if context is None:
            context = {}

        if 'type' in context:
            type = context['type']

        if not printer_id:
            printer_id = self._default_printer_point(cr, uid, context)

        number = False  #por ejemplo para facturas de tipo hr_advance

        # Se corrige las devoluciones y las facturas con sus prefijos correspondientes
        if type in ['out_invoice', 'out_refund']:
            number = '001-001-'
            printer = self.pool.get('sri.printer.point').browse(
                cr, uid, printer_id, context=context)
            if printer.prefix:
                number = printer.prefix
            else:
                number = printer.shop_id.number + "-" + printer.name + "-"
        if type in ['in_invoice', 'in_refund']:
            number = '001-001-'
        return number

    def _get_internal_number_by_sequence(self, cr, uid, obj_inv, context=None):
        """
        Generates, for the given object and number, a valid autogenerated number
          (if it can do  and neither the current user has,
        """

        #we must ensure there's an available printer point by invoice, by user, or the first one
        printer_id = obj_inv.printer_id or self.pool.get('res.users').browse(
            cr, uid, uid).printer_id
        if not printer_id:
            ppobj = self.pool.get('sri.printer.point')
            pprecs_limit1 = ppobj.search(cr, uid, [], limit=1)
            pprec_first = pprecs_limit1[0] if pprecs_limit1 else False
            printer_id = ppobj.browse(cr, uid,
                                      pprec_first) if pprec_first else False

        #if no invoice is found, we return the number as-is
        if not printer_id:
            return obj_inv.number

        #we get the document type to fetch from the printer.
        #if the invoice has a wrong type, the passed type is
        #  None, which will cause the number to be returned.
        document_type = {
            'out_invoice': 'invoice',
            'out_refund': 'refund'
        }.get(obj_inv.type)

        return self.pool.get('sri.printer.point').get_next_sequence_number(
            cr, uid, printer_id, document_type, obj_inv.number, context)

    def action_number(self, cr, uid, ids, context=None):
        """
        This method allows the usage of custom sequentials for the printer point.
        It stores the internal_number from the number field, passed to an internal
          check from the current printer point
        """
        super(account_invoice, self).action_number(cr, uid, ids, context)
        for obj_inv in self.browse(cr, uid, ids, context=context):
            number = self._get_internal_number_by_sequence(
                cr, uid, obj_inv, context)
            self.write(cr, uid, ids, {
                'internal_number': number,
                'name': number,
                'number': number
            })
        return True

    def _default_internal_number(self, cr, uid, context=None):
        '''Numero de factura sugerida para facturas de venta y compra, depende del punto de impresion
           Puede ser redefinida posteriormente por ejemplo para numeracion automatica
        '''
        number = ''
        type = ''
        printer_id = None

        if context is None:
            context = {}

        if context.has_key('type'):
            type = context['type']

        if context.has_key('printer_id'):
            printer_id = context['printer_id']

        if not printer_id:
            printer_id = self._default_printer_point(cr, uid, context)

        if printer_id and type:
            number = self._suggested_internal_number(cr, uid, printer_id, type,
                                                     None, context)

        return number

    def _default_date_invoice(self, cr, uid, context=None):
        '''Fecha por defecto es hoy
        '''
        #TODO: Incluir el calculo de zona horaria
        #TODO: Colocar esta funcion en el default
        return str(lambda *a: time.strftime('%Y-%m-%d'), )

    _defaults = {
        'printer_id': _default_printer_point,
        'internal_number': _default_internal_number,
        'date_invoice': lambda *a: time.strftime('%Y-%m-%d'),
    }

    def _prepare_invoice_header(self,
                                cr,
                                uid,
                                partner_id,
                                type,
                                inv_date=None,
                                printer_id=None,
                                context=None):
        """Retorna los valores ecuatorianos para el header de una factura
           Puede ser usado en ordenes de compra, venta, proyectos, facturacion desde bodegas, etc
           @partner_id es un objeto partner
           @type es el tipo de factura, ej. out_invoice
           @inv_date es la fecha prevista de la factura, si no se provee se asume hoy
        """

        if context is None:
            context = {}
        invoice_vals = {}

        partner_obj = self.pool.get('res.partner')
        invoice_address = partner_obj.get_company_address(cr, uid, partner_id)
        invoice_phone = partner_obj.get_company_phone(cr, uid, partner_id)

        inv_obj = self.pool.get('account.invoice')
        printer_id = printer_id or inv_obj._default_printer_point(cr, uid, uid)
        internal_number = ''
        if printer_id:
            internal_number = inv_obj._suggested_internal_number(
                cr, uid, printer_id, type, context)

        invoice_vals.update({
            'invoice_address': invoice_address or '',
            'invoice_phone': invoice_phone or '',
            'internal_number': internal_number or '',
            'printer_id': printer_id,
            'date_invoice': time.strftime('%Y-%m-%d')
        })
        return invoice_vals
Example #33
0
class product_template(osv.osv):
    _name = "product.template"
    _description = "Product Template"

    def _calc_seller(self, cr, uid, ids, fields, arg, context=None):
        result = {}
        for product in self.browse(cr, uid, ids, context=context):
            for field in fields:
                result[product.id] = {field: False}
            result[product.id]['seller_delay'] = 1
            if product.seller_ids:
                partner_list = sorted([
                    (partner_id.sequence, partner_id)
                    for partner_id in product.seller_ids
                    if partner_id and isinstance(partner_id.sequence, (int,
                                                                       long))
                ])
                main_supplier = partner_list and partner_list[
                    0] and partner_list[0][1] or False
                result[product.id][
                    'seller_delay'] = main_supplier and main_supplier.delay or 1
                result[product.id][
                    'seller_qty'] = main_supplier and main_supplier.qty or 0.0
                result[product.id][
                    'seller_id'] = main_supplier and main_supplier.name.id or False
        return result

    _columns = {
        'name':
        fields.char('Name',
                    size=128,
                    required=True,
                    translate=True,
                    select=True),
        'product_manager':
        fields.many2one('res.users',
                        'Product Manager',
                        help="This is use as task responsible"),
        'description':
        fields.text('Description', translate=True),
        'description_purchase':
        fields.text('Purchase Description', translate=True),
        'description_sale':
        fields.text('Sale Description', translate=True),
        'type':
        fields.selection(
            [('product', 'Stockable Product'), ('consu', 'Consumable'),
             ('service', 'Service')],
            'Product Type',
            required=True,
            help=
            "Will change the way procurements are processed. Consumables are stockable products with infinite stock, or for use when you have no inventory management in the system."
        ),
        'supply_method':
        fields.selection(
            [('produce', 'Produce'), ('buy', 'Buy')],
            'Supply method',
            required=True,
            help=
            "Produce will generate production order or tasks, according to the product type. Purchase will trigger purchase orders when requested."
        ),
        'sale_delay':
        fields.float(
            'Customer Lead Time',
            help=
            "This is the average delay in days between the confirmation of the customer order and the delivery of the finished products. It's the time you promise to your customers."
        ),
        'produce_delay':
        fields.float(
            'Manufacturing Lead Time',
            help=
            "Average delay in days to produce this product. This is only for the production order and, if it is a multi-level bill of material, it's only for the level of this product. Different lead times will be summed for all levels and purchase orders."
        ),
        'procure_method':
        fields.selection(
            [('make_to_stock', 'Make to Stock'),
             ('make_to_order', 'Make to Order')],
            'Procurement Method',
            required=True,
            help=
            "'Make to Stock': When needed, take from the stock or wait until re-supplying. 'Make to Order': When needed, purchase or produce for the procurement request."
        ),
        'rental':
        fields.boolean('Can be Rent'),
        'categ_id':
        fields.many2one('product.category',
                        'Category',
                        required=True,
                        change_default=True,
                        domain="[('type','=','normal')]",
                        help="Select category for the current product"),
        'list_price':
        fields.float(
            'Sale Price',
            digits_compute=dp.get_precision('Sale Price'),
            help=
            "Base price for computing the customer price. Sometimes called the catalog price."
        ),
        'standard_price':
        fields.float(
            'Cost Price',
            required=True,
            digits_compute=dp.get_precision('Purchase Price'),
            help=
            "Product's cost for accounting stock valuation. It is the base price for the supplier price."
        ),
        'volume':
        fields.float('Volume', help="The volume in m3."),
        'weight':
        fields.float('Gross weight', help="The gross weight in Kg."),
        'weight_net':
        fields.float('Net weight', help="The net weight in Kg."),
        'cost_method':
        fields.selection(
            [('standard', 'Standard Price'), ('average', 'Average Price')],
            'Costing Method',
            required=True,
            help=
            "Standard Price: the cost price is fixed and recomputed periodically (usually at the end of the year), Average Price: the cost price is recomputed at each reception of products."
        ),
        'warranty':
        fields.float('Warranty (months)'),
        'sale_ok':
        fields.boolean(
            'Can be Sold',
            help=
            "Determines if the product can be visible in the list of product within a selection from a sale order line."
        ),
        'purchase_ok':
        fields.boolean(
            'Can be Purchased',
            help=
            "Determine if the product is visible in the list of products within a selection from a purchase order line."
        ),
        'state':
        fields.selection(
            [('', ''), ('draft', 'In Development'), ('sellable', 'Normal'),
             ('end', 'End of Lifecycle'), ('obsolete', 'Obsolete')],
            'Status',
            help="Tells the user if he can use the product or not."),
        'uom_id':
        fields.many2one(
            'product.uom',
            'Default Unit Of Measure',
            required=True,
            help="Default Unit of Measure used for all stock operation."),
        'uom_po_id':
        fields.many2one(
            'product.uom',
            'Purchase Unit of Measure',
            required=True,
            help=
            "Default Unit of Measure used for purchase orders. It must be in the same category than the default unit of measure."
        ),
        'uos_id':
        fields.many2one(
            'product.uom',
            'Unit of Sale',
            help=
            'Used by companies that manage two units of measure: invoicing and inventory management. For example, in food industries, you will manage a stock of ham but invoice in Kg. Keep empty to use the default UOM.'
        ),
        'uos_coeff':
        fields.float('UOM -> UOS Coeff',
                     digits=(16, 4),
                     help='Coefficient to convert UOM to UOS\n'
                     ' uos = uom * coeff'),
        'mes_type':
        fields.selection((('fixed', 'Fixed'), ('variable', 'Variable')),
                         'Measure Type',
                         required=True),
        'seller_delay':
        fields.function(
            _calc_seller,
            method=True,
            type='integer',
            string='Supplier Lead Time',
            multi="seller_delay",
            help=
            "This is the average delay in days between the purchase order confirmation and the reception of goods for this product and for the default supplier. It is used by the scheduler to order requests based on reordering delays."
        ),
        'seller_qty':
        fields.function(
            _calc_seller,
            method=True,
            type='float',
            string='Supplier Quantity',
            multi="seller_qty",
            help="This is minimum quantity to purchase from Main Supplier."),
        'seller_id':
        fields.function(
            _calc_seller,
            method=True,
            type='many2one',
            relation="res.partner",
            string='Main Supplier',
            help="Main Supplier who has highest priority in Supplier List.",
            multi="seller_id"),
        'seller_ids':
        fields.one2many('product.supplierinfo', 'product_id', 'Partners'),
        'loc_rack':
        fields.char('Rack', size=16),
        'loc_row':
        fields.char('Row', size=16),
        'loc_case':
        fields.char('Case', size=16),
        'company_id':
        fields.many2one('res.company', 'Company', select=1),
    }

    def _get_uom_id(self, cr, uid, *args):
        cr.execute('select id from product_uom order by id limit 1')
        res = cr.fetchone()
        return res and res[0] or False

    def _default_category(self, cr, uid, context=None):
        if context is None:
            context = {}
        if 'categ_id' in context and context['categ_id']:
            return context['categ_id']
        md = self.pool.get('ir.model.data')
        res = md.get_object_reference(cr, uid, 'product', 'cat0') or False
        return res and res[1] or False

    def onchange_uom(self, cursor, user, ids, uom_id, uom_po_id):
        if uom_id:
            return {'value': {'uom_po_id': uom_id}}
        return False

    _defaults = {
        'company_id':
        lambda s, cr, uid, c: s.pool.get('res.company')._company_default_get(
            cr, uid, 'product.template', context=c),
        'type':
        lambda *a: 'product',
        'list_price':
        lambda *a: 1,
        'cost_method':
        lambda *a: 'standard',
        'supply_method':
        lambda *a: 'buy',
        'standard_price':
        lambda *a: 1,
        'sale_ok':
        lambda *a: 1,
        'sale_delay':
        lambda *a: 7,
        'produce_delay':
        lambda *a: 1,
        'purchase_ok':
        lambda *a: 1,
        'procure_method':
        lambda *a: 'make_to_stock',
        'uom_id':
        _get_uom_id,
        'uom_po_id':
        _get_uom_id,
        'uos_coeff':
        lambda *a: 1.0,
        'mes_type':
        lambda *a: 'fixed',
        'categ_id':
        _default_category,
        'type':
        lambda *a: 'consu',
    }

    def _check_uom(self, cursor, user, ids, context=None):
        for product in self.browse(cursor, user, ids, context=context):
            if product.uom_id.category_id.id <> product.uom_po_id.category_id.id:
                return False
        return True

    def _check_uos(self, cursor, user, ids, context=None):
        for product in self.browse(cursor, user, ids, context=context):
            if product.uos_id \
                    and product.uos_id.category_id.id \
                    == product.uom_id.category_id.id:
                return False
        return True

    _constraints = [
        (_check_uom,
         'Error: The default UOM and the purchase UOM must be in the same category.',
         ['uom_id']),
    ]

    def name_get(self, cr, user, ids, context=None):
        if context is None:
            context = {}
        if 'partner_id' in context:
            pass
        return super(product_template, self).name_get(cr, user, ids, context)
Example #34
0
class product_product(orm.Model):
    """
    Inherit Product in order to add an "Bom Stock" field
    """
    _inherit = 'product.product'

    # def _get_prefered_supplier(self, cr, uid, ids, field_name, args, context):
    #     res = {}
    #     for line in self.browse(cr, uid, ids, context):
    #         res[line.id] = line.seller_ids and line.seller_ids[0].name.id or False
    #     return res

    def __init__(self, cr, uid):
        super(product_product, self).__init__(cr, uid)
        self.product_cost_cache = {}

    def _compute_purchase_price(self,
                                cr,
                                uid,
                                ids,
                                product_uom=None,
                                bom_properties=None,
                                context=None):
        '''
        Compute the purchase price, taking into account sub products and routing
        '''

        context = context or self.pool['res.users'].context_get(cr, uid)
        bom_properties = bom_properties or []
        user = self.pool['res.users'].browse(cr, uid, uid, context)

        bom_obj = self.pool['mrp.bom']
        uom_obj = self.pool['product.uom']

        res = {}
        ids = ids or []

        for product in self.browse(cr, uid, ids, context):
            # print(u'{product.id}: {product.name}'.format(product=product))
            bom_id = bom_obj._bom_find(cr,
                                       uid,
                                       product.id,
                                       product_uom=None,
                                       properties=bom_properties)
            if bom_id:
                sub_bom_ids = bom_obj.search(cr,
                                             uid, [('bom_id', '=', bom_id)],
                                             context=context)
                sub_products = bom_obj.browse(cr, uid, sub_bom_ids, context)

                price = 0.

                for sub_product in sub_products:
                    if sub_product.product_id.id == product.id:
                        error = "Product '{product.name}' (id: {product.id}) is referenced to itself".format(
                            product=product)
                        _logger.error(error)
                        continue

                    # std_price = sub_product.standard_price
                    if ENABLE_CACHE:
                        if sub_product.product_id.id in self.product_cost_cache:
                            std_price = self.product_cost_cache[
                                sub_product.product_id.id]
                        else:
                            std_price = sub_product.product_id.cost_price
                            self.product_cost_cache[
                                sub_product.product_id.id] = std_price
                    else:
                        std_price = sub_product.product_id.cost_price

                    qty = uom_obj._compute_qty(
                        cr,
                        uid,
                        from_uom_id=sub_product.product_uom.id,
                        qty=sub_product.product_qty,
                        to_uom_id=sub_product.product_id.uom_po_id.id)
                    price += std_price * qty
                    # if sub_product.routing_id:
                    #     for wline in sub_product.routing_id.workcenter_lines:
                    #         wc = wline.workcenter_id
                    #         cycle = wline.cycle_nbr
                    #         # hour = (wc.time_start + wc.time_stop + cycle * wc.time_cycle) * (wc.time_efficiency or 1.0)
                    #         price += wc.costs_cycle * cycle + wc.costs_hour * wline.hour_nbr

                if sub_products:
                    # Don't use browse when we already have it
                    bom = sub_products[0].bom_id
                else:
                    bom = bom_obj.browse(cr, uid, bom_id, context)

                if bom.routing_id:
                    for wline in bom.routing_id.workcenter_lines:
                        wc = wline.workcenter_id
                        cycle = wline.cycle_nbr
                        # hour = (wc.time_start + wc.time_stop + cycle * wc.time_cycle) * (wc.time_efficiency or 1.0)
                        price += wc.costs_cycle * cycle + wc.costs_hour * wline.hour_nbr
                price /= bom.product_qty
                price = uom_obj._compute_price(cr, uid, bom.product_uom.id,
                                               price, bom.product_id.uom_id.id)
                res[product.id] = price
            else:
                # no BoM: use standard_price
                # use standard_price if no supplier indicated

                if product.id in self.product_cost_cache and ENABLE_CACHE:
                    res[product.id] = self.product_cost_cache[product.id]
                    continue

                if product.prefered_supplier:
                    pricelist = product.prefered_supplier.property_product_pricelist_purchase or False
                    ctx = {'date': time.strftime(DEFAULT_SERVER_DATE_FORMAT)}
                    price = self.pool['product.pricelist'].price_get(
                        cr, uid, [pricelist.id], product.id, 1,
                        context=ctx)[pricelist.id] or 0

                    price_subtotal = 0.0
                    if pricelist:
                        from_currency = pricelist.currency_id.id
                        to_currency = user.company_id.currency_id.id
                        price_subtotal = self.pool['res.currency'].compute(
                            cr,
                            uid,
                            from_currency_id=from_currency,
                            to_currency_id=to_currency,
                            from_amount=price,
                            context=context)

                    res[product.id] = price_subtotal or price
                else:
                    res[product.id] = product.standard_price

                if ENABLE_CACHE:
                    self.product_cost_cache[product.id] = res[product.id]
                continue

        return res

    def get_cost_field(self, cr, uid, ids, context=None):
        start_time = datetime.now()
        context = context or self.pool['res.users'].context_get(cr, uid)
        end_time = datetime.now()
        duration_seconds = (end_time - start_time)
        duration = '{sec}'.format(sec=duration_seconds)
        _logger.info(u'get_cost_field get in {duration} for {id}'.format(
            duration=duration, id=ids))
        res = self._cost_price(cr, uid, ids, '', [], context)
        return res

    def _cost_price(self, cr, uid, ids, field_name, arg, context=None):
        start_time = datetime.now()
        # _logger.error(
        #     u'START _cost_price for {ids} and {field}'.format(ids=ids, field=field_name))
        context = context or self.pool['res.users'].context_get(cr, uid)
        product_uom = context.get('product_uom')
        bom_properties = context.get('properties')
        res = self._compute_purchase_price(cr, uid, ids, product_uom,
                                           bom_properties, context)
        end_time = datetime.now()
        duration_seconds = (end_time - start_time)
        duration = '{sec}'.format(sec=duration_seconds)
        _logger.info(
            u'_cost_price get in {duration}'.format(duration=duration))
        return res

    def _kit_filter(self, cr, uid, obj, name, args, context):
        if not args:
            return []
        bom_obj = self.pool['mrp.bom']
        for search in args:
            if search[0] == 'is_kit':
                if search[2]:
                    bom_ids = bom_obj.search(cr,
                                             uid, [('bom_id', '=', False)],
                                             context=context)
                    if bom_ids:
                        res = [
                            bom.product_id.id for bom in bom_obj.browse(
                                cr, uid, bom_ids, context)
                        ]
                        return [('id', 'in', res)]
                    else:
                        return [('id', 'in', [])]
        return []

    def _is_kit(self,
                cr,
                uid,
                ids,
                product_uom=None,
                bom_properties=None,
                context=None):
        if not len(ids):
            return []
        '''
        Show if have or not a bom
        '''
        start_time = datetime.now()
        context = context or self.pool['res.users'].context_get(cr, uid)
        bom_properties = bom_properties or []

        bom_obj = self.pool['mrp.bom']

        res = {}
        ids = ids or []

        for product in self.browse(cr, uid, ids, context):
            bom_id = bom_obj._bom_find(cr,
                                       uid,
                                       product.id,
                                       product_uom=None,
                                       properties=bom_properties)
            # cr.execute("""SELECT id FROM mrp_bom WHERE product_id={product_id}""".format(product_id=product.id))
            # bom_id = cr.fetchall()
            if not bom_id:
                res[product.id] = False
            else:
                res[product.id] = True
        end_time = datetime.now()
        duration_seconds = (end_time - start_time)
        duration = '{sec}'.format(sec=duration_seconds)
        _logger.info(u'IS KIT get in {duration}'.format(duration=duration))
        return res

    """
    Inherit Product in order to add an "Bom Stock" field
    """

    def _bom_stock_mapping(self, cr, uid, context=None):
        return {
            'real': 'qty_available',
            'virtual': 'virtual_available',
            'immediately': 'immediately_usable_qty'
        }

    def _compute_bom_stock(self,
                           cr,
                           uid,
                           product,
                           quantities,
                           company,
                           context=None):
        context = context or self.pool['res.users'].context_get(cr, uid)
        bom_obj = self.pool['mrp.bom']
        uom_obj = self.pool['product.uom']
        mapping = self._bom_stock_mapping(cr, uid, context=context)
        stock_field = mapping[company.ref_stock]

        product_qty = quantities.get(stock_field, 0.0)
        # find a bom on the product
        bom_id = bom_obj._bom_find(cr,
                                   uid,
                                   product.id,
                                   product.uom_id.id,
                                   properties=[])

        if bom_id:
            prod_min_quantities = []
            bom = bom_obj.browse(cr, uid, bom_id, context=context)
            if bom.bom_lines:
                stop_compute_bom = False
                # Compute stock qty of each product used in the BoM and
                # get the minimal number of items we can produce with them
                for line in bom.bom_lines:
                    prod_min_quantity = 0.0
                    bom_qty = line.product_id[
                        stock_field]  # expressed in product UOM
                    # the reference stock of the component must be greater
                    # than the quantity of components required to
                    # build the bom
                    line_product_qty = uom_obj._compute_qty_obj(
                        cr,
                        uid,
                        line.product_uom,
                        line.product_qty,
                        line.product_id.uom_id,
                        context=context)

                    if line_product_qty and (bom_qty > line_product_qty):
                        prod_min_quantity = bom_qty / line_product_qty  # line.product_qty is always > 0
                    else:
                        # if one product has not enough stock,
                        # we do not need to compute next lines
                        # because the final quantity will be 0.0 in any case
                        stop_compute_bom = True

                    prod_min_quantities.append(prod_min_quantity)
                    if stop_compute_bom:
                        break
            produced_qty = uom_obj._compute_qty_obj(cr,
                                                    uid,
                                                    bom.product_uom,
                                                    bom.product_qty,
                                                    bom.product_id.uom_id,
                                                    context=context)
            if prod_min_quantities:
                product_qty += min(prod_min_quantities) * produced_qty
            else:
                product_qty += produced_qty
        return product_qty

    def _product_available(self,
                           cr,
                           uid,
                           ids,
                           field_names=[],
                           arg=False,
                           context=None):
        # We need available, virtual or immediately usable
        # quantity which is selected from company to compute Bom stock Value
        # so we add them in the calculation.
        context = context or self.pool['res.users'].context_get(cr, uid)
        start_time = datetime.now()
        user_obj = self.pool['res.users']
        comp_obj = self.pool['res.company']
        if 'bom_stock' in field_names:
            field_names.append('qty_available')
            field_names.append('immediately_usable_qty')
            field_names.append('virtual_available')

        res = super(product_product,
                    self)._product_available(cr, uid, ids, field_names, arg,
                                             context)

        if 'bom_stock' in field_names:
            company = user_obj.browse(cr, uid, uid, context=context).company_id
            if not company:
                company_id = comp_obj.search(cr, uid, [], context=context)[0]
                company = comp_obj.browse(cr, uid, company_id, context=context)

            for product_id, stock_qty in res.iteritems():
                product = self.browse(cr, uid, product_id, context=context)
                res[product_id]['bom_stock'] = self._compute_bom_stock(
                    cr, uid, product, stock_qty, company, context=context)
        end_time = datetime.now()
        duration_seconds = (end_time - start_time)
        duration = '{sec}'.format(sec=duration_seconds)
        _logger.info(
            u'_product_available get in {duration}'.format(duration=duration))
        return res

    def _get_boms(self, cr, uid, ids, field_name, arg, context):
        result = {}

        for product_id in ids:
            result[product_id] = self.pool['mrp.bom'].search(
                cr,
                uid, [('product_id', '=', product_id), ('bom_id', '=', False)],
                context=context)

        return result

    def price_get(self, cr, uid, ids, ptype='list_price', context=None):
        start_time = datetime.now()
        context = context or self.pool['res.users'].context_get(cr, uid)
        if 'currency_id' in context:
            pricetype_obj = self.pool['product.price.type']
            price_type_id = pricetype_obj.search(cr,
                                                 uid, [('field', '=', ptype)],
                                                 context=context)[0]
            price_type_currency_id = pricetype_obj.browse(
                cr, uid, price_type_id, context).currency_id.id

        res = {}
        product_uom_obj = self.pool['product.uom']
        for product in self.browse(cr, uid, ids, context=context):
            res[product.id] = product[ptype] or 0.0

            if ptype == 'standard_price' and product.is_kit:
                res[product.id] = product.cost_price or product.standard_price

            if ptype == 'list_price':
                res[product.id] = (
                    res[product.id] *
                    (product.price_margin or 1.0)) + product.price_extra
            if 'uom' in context:
                uom = product.uom_id or product.uos_id
                res[product.id] = product_uom_obj._compute_price(
                    cr, uid, uom.id, res[product.id], context['uom'])
            # Convert from price_type currency to asked one
            if 'currency_id' in context:
                # Take the price_type currency from the product field
                # This is right cause a field cannot be in more than one currency
                res[product.id] = self.pool['res.currency'].compute(
                    cr,
                    uid,
                    price_type_currency_id,
                    context['currency_id'],
                    res[product.id],
                    context=context)
        end_time = datetime.now()
        duration_seconds = (end_time - start_time)
        duration = '{sec}'.format(sec=duration_seconds)
        _logger.info(u'price_get get in {duration}'.format(duration=duration))
        return res

    _columns = {
        'date_inventory': fields.function(lambda *a, **k: {}, method=True, type='date', string="Date Inventory"),
        'cost_price': fields.function(_cost_price,
                                      method=True,
                                      string=_('Cost Price (incl. BoM)'),
                                      digits_compute=dp.get_precision('Purchase Price'),
                                      help="The cost price is the standard price or, if the product has a bom, "
                                      "the sum of all standard price of its components. it take also care of the "
                                      "bom costing like cost per cylce."),
        'prefered_supplier': fields.related('seller_ids', 'name', type='many2one', relation='res.partner', string='Prefered Supplier'),
        'is_kit': fields.function(_is_kit, fnct_search=_kit_filter, method=True, type="boolean", string="Kit"),
        'bom_lines': fields.function(_get_boms, relation='mrp.bom', string='Boms', type='one2many', method=True),
        'qty_available': fields.function(
            _product_available,
            multi='qty_available',
            type='float',
            digits_compute=dp.get_precision('Product UoM'),
            string='Quantity On Hand',
            help="Current quantity of products.\n"
                 "In a context with a single Stock Location, this includes "
                 "goods stored at this Location, or any of its children.\n"
                 "In a context with a single Warehouse, this includes "
                 "goods stored in the Stock Location of this Warehouse, "
                 "or any "
                 "of its children.\n"
                 "In a context with a single Shop, this includes goods "
                 "stored in the Stock Location of the Warehouse of this Shop, "
                 "or any of its children.\n"
                 "Otherwise, this includes goods stored in any Stock Location "
                 "typed as 'internal'."),
        'virtual_available': fields.function(
            _product_available,
            multi='qty_available',
            type='float',
            digits_compute=dp.get_precision('Product UoM'),
            string='Quantity Available',
            help="Forecast quantity (computed as Quantity On Hand "
                 "- Outgoing + Incoming)\n"
                 "In a context with a single Stock Location, this includes "
                 "goods stored at this Location, or any of its children.\n"
                 "In a context with a single Warehouse, this includes "
                 "goods stored in the Stock Location of this Warehouse, "
                 "or any "
                 "of its children.\n"
                 "In a context with a single Shop, this includes goods "
                 "stored in the Stock Location of the Warehouse of this Shop, "
                 "or any of its children.\n"
                 "Otherwise, this includes goods stored in any Stock Location "
                 "typed as 'internal'."),
        'incoming_qty': fields.function(
            _product_available,
            multi='qty_available',
            type='float',
            digits_compute=dp.get_precision('Product UoM'),
            string='Incoming',
            help="Quantity of products that are planned to arrive.\n"
                 "In a context with a single Stock Location, this includes "
                 "goods arriving to this Location, or any of its children.\n"
                 "In a context with a single Warehouse, this includes "
                 "goods arriving to the Stock Location of this Warehouse, or "
                 "any of its children.\n"
                 "In a context with a single Shop, this includes goods "
                 "arriving to the Stock Location of the Warehouse of this "
                 "Shop, or any of its children.\n"
                 "Otherwise, this includes goods arriving to any Stock "
                 "Location typed as 'internal'."),
        'outgoing_qty': fields.function(
            _product_available,
            multi='qty_available',
            type='float',
            digits_compute=dp.get_precision('Product UoM'),
            string='Outgoing',
            help="Quantity of products that are planned to leave.\n"
                 "In a context with a single Stock Location, this includes "
                 "goods leaving from this Location, or any of its children.\n"
                 "In a context with a single Warehouse, this includes "
                 "goods leaving from the Stock Location of this Warehouse, or "
                 "any of its children.\n"
                 "In a context with a single Shop, this includes goods "
                 "leaving from the Stock Location of the Warehouse of this "
                 "Shop, or any of its children.\n"
                 "Otherwise, this includes goods leaving from any Stock "
                 "Location typed as 'internal'."),
        'immediately_usable_qty': fields.function(
            _product_available,
            digits_compute=dp.get_precision('Product UoM'),
            type='float',
            string='Immediately Usable',
            multi='qty_available',
            help="Quantity of products really available for sale." \
                 "Computed as: Quantity On Hand - Outgoing."),
        'bom_stock': fields.function(
            _product_available,
            digits_compute=dp.get_precision('Product UoM'),
            type='float',
            string='Bill of Materials Stock',
            help="Quantities of products based on Bill of Materials, "
                 "useful to know how much of this "
                 "product you could produce. "
                 "Computed as:\n "
                 "Reference stock of this product + "
                 "how much could I produce of this product with the BoM"
                 "Components",
            multi='qty_available'),
    }

    def copy(self, cr, uid, product_id, default=None, context=None):
        """Copies the product and the BoM of the product"""
        context = context or self.pool['res.users'].context_get(cr, uid)
        copy_id = super(product_product, self).copy(cr, uid, product_id,
                                                    default, context)

        bom_obj = self.pool['mrp.bom']
        bom_ids = bom_obj.search(cr,
                                 uid, [('product_id', '=', product_id),
                                       ('bom_id', '=', False)],
                                 context=context)

        for bom_id in bom_ids:
            bom_obj.copy(cr,
                         uid,
                         bom_id, {'product_id': copy_id},
                         context=context)
        return copy_id

    def update_product_bom_price(self, cr, uid, ids, context=None):
        """
        This Function is call by scheduler.
        """
        context = context or self.pool['res.users'].context_get(cr, uid)
        for product in self.browse(cr, uid, ids, context):
            product.write({'standard_price': product.cost_price})
        return True

    def update_bom_price(self, cr, uid, context=None):
        """
        This Function is call by scheduler.
        """
        context = context or self.pool['res.users'].context_get(cr, uid)
        # search product with kit
        product_ids = self.search(cr,
                                  uid, [('is_kit', '=', True)],
                                  context=context)
        for product in self.browse(cr, uid, product_ids, context):
            product.write({'standard_price': product.cost_price})
        return True

    def write(self, cr, uid, ids, vals, context=None):
        context = context or self.pool['res.users'].context_get(cr, uid)

        if not isinstance(ids, (list, tuple)):
            ids = [ids]

        res = super(product_product, self).write(cr, uid, ids, vals, context)

        if ENABLE_CACHE:
            if 'standard_price' in vals:
                changed_product = ids
                bom_obj = self.pool['mrp.bom']
                bom_ids = bom_obj.search(cr,
                                         uid, [('product_id', 'in', ids)],
                                         context=context)
                for bom in bom_obj.browse(cr, uid, bom_ids, context):
                    bom_parent = bom.bom_id
                    while bom_parent:
                        changed_product.append(bom_parent.product_id.id)
                        bom_parent = bom_parent.bom_id

                for product_id in changed_product:
                    if product_id in self.product_cost_cache:
                        del self.product_cost_cache[product_id]
        return res
Example #35
0
class product_uom(osv.osv):
    _name = 'product.uom'
    _description = 'Product Unit of Measure'

    def _compute_factor_inv(self, factor):
        return factor and round(1.0 / factor, 6) or 0.0

    def _factor_inv(self, cursor, user, ids, name, arg, context=None):
        res = {}
        for uom in self.browse(cursor, user, ids, context=context):
            res[uom.id] = self._compute_factor_inv(uom.factor)
        return res

    def _factor_inv_write(self,
                          cursor,
                          user,
                          id,
                          name,
                          value,
                          arg,
                          context=None):
        return self.write(cursor,
                          user,
                          id, {'factor': self._compute_factor_inv(value)},
                          context=context)

    def create(self, cr, uid, data, context=None):
        if 'factor_inv' in data:
            if data['factor_inv'] <> 1:
                data['factor'] = self._compute_factor_inv(data['factor_inv'])
            del (data['factor_inv'])
        return super(product_uom, self).create(cr, uid, data, context)

    _columns = {
        'name': fields.char('Name', size=64, required=True, translate=True),
        'category_id': fields.many2one('product.uom.categ', 'UoM Category', required=True, ondelete='cascade',
            help="Quantity conversions may happen automatically between Units of Measure in the same category, according to their respective ratios."),
        'factor': fields.float('Ratio', required=True,digits=(12, 12),
            help='How many times this UoM is smaller than the reference UoM in this category:\n'\
                    '1 * (reference unit) = ratio * (this unit)'),
        'factor_inv': fields.function(_factor_inv, digits_compute=dp.get_precision('Product UoM'),
            fnct_inv=_factor_inv_write,
            method=True, string='Ratio',
            help='How many times this UoM is bigger than the reference UoM in this category:\n'\
                    '1 * (this unit) = ratio * (reference unit)', required=True),
        'rounding': fields.float('Rounding Precision', digits_compute=dp.get_precision('Product UoM'), required=True,
            help="The computed quantity will be a multiple of this value. "\
                 "Use 1.0 for a UoM that cannot be further split, such as a piece."),
        'active': fields.boolean('Active', help="By unchecking the active field you can disable a unit of measure without deleting it."),
        'uom_type': fields.selection([('bigger','Bigger than the reference UoM'),
                                      ('reference','Reference UoM for this category'),
                                      ('smaller','Smaller than the reference UoM')],'UoM Type', required=1),
    }

    _defaults = {
        'active': 1,
        'rounding': 0.01,
        'uom_type': 'reference',
    }

    _sql_constraints = [
        ('factor_gt_zero', 'CHECK (factor!=0)',
         'The conversion ratio for a unit of measure cannot be 0!'),
    ]

    def _compute_qty(self, cr, uid, from_uom_id, qty, to_uom_id=False):
        if not from_uom_id or not qty or not to_uom_id:
            return qty
        uoms = self.browse(cr, uid, [from_uom_id, to_uom_id])
        if uoms[0].id == from_uom_id:
            from_unit, to_unit = uoms[0], uoms[-1]
        else:
            from_unit, to_unit = uoms[-1], uoms[0]
        return self._compute_qty_obj(cr, uid, from_unit, qty, to_unit)

    def _compute_qty_obj(self, cr, uid, from_unit, qty, to_unit, context=None):
        if context is None:
            context = {}
        if from_unit.category_id.id <> to_unit.category_id.id:
            if context.get('raise-exception', True):
                raise osv.except_osv(
                    _('Error !'),
                    _('Conversion from Product UoM %s to Default UoM %s is not possible as they both belong to different Category!.'
                      ) % (
                          from_unit.name,
                          to_unit.name,
                      ))
            else:
                return qty
        amount = qty / from_unit.factor
        if to_unit:
            amount = rounding(amount * to_unit.factor, to_unit.rounding)
        return amount

    def _compute_price(self, cr, uid, from_uom_id, price, to_uom_id=False):
        if not from_uom_id or not price or not to_uom_id:
            return price
        uoms = self.browse(cr, uid, [from_uom_id, to_uom_id])
        if uoms[0].id == from_uom_id:
            from_unit, to_unit = uoms[0], uoms[-1]
        else:
            from_unit, to_unit = uoms[-1], uoms[0]
        if from_unit.category_id.id <> to_unit.category_id.id:
            return price
        amount = price * from_unit.factor
        if to_uom_id:
            amount = amount / to_unit.factor
        return amount

    def onchange_type(self, cursor, user, ids, value):
        if value == 'reference':
            return {'value': {'factor': 1, 'factor_inv': 1}}
        return {}
Example #36
0
class stock_move(osv.osv):
    _inherit = "stock.move"   

    # override copy and copy_data method to prevent copying landing cost when creating returns
    def copy(self, cr, uid, id, default=None, context=None):
        if default is None:
            default = {}
        default['landing_costs_line_ids'] = []
        res = super(stock_move, self).copy(cr, uid, id, default, context)
        return res
        
    def copy_data(self, cr, uid, id, default=None, context=None):
        res = super(stock_move, self).copy_data(cr, uid, id, default, context)

        if res.get('landing_costs_line_ids', False):
            res['landing_costs_line_ids'] = []

        if res.get('price_unit_without_costs', False):
            res['price_unit'] = res['price_unit_without_costs']
            res['price_unit_without_costs'] = False

        return res

    # per amount landing costs amount
    def _landing_costs_per_value(self, cr, uid, ids, name, args, context):
        if not ids:
            return {}        
        result = {}
        for line in self.browse(cr, uid, ids):
            per_value = 0.0
            if line.landing_costs_line_ids:
                for costs in line.landing_costs_line_ids:
                    if costs.distribution_type == 'per_value':
                        per_value += costs.amount
            result[line.id] = per_value
        return result

    # per unit landing costs amount
    def _landing_costs_per_unit(self, cr, uid, ids, name, args, context):
        if not ids:
            return {}        
        result = {}
        for line in self.browse(cr, uid, ids):
            per_unit = 0.0
            if line.landing_costs_line_ids:
                for costs in line.landing_costs_line_ids:
                    if costs.distribution_type == 'per_unit':
                        per_unit += costs.amount
            result[line.id] = per_unit
        return result

    # stock move quantity for cost calculation
    def _landing_costs_base_quantity(self, cr, uid, ids, name, args, context):
        if not ids:
            return {}
        result = {}
        base_quantity = 0.0
        for line in self.browse(cr, uid, ids):
            if line.product_id.landing_cost_calculate:
                base_quantity = line.product_qty
            result[line.id] = base_quantity
        return result
    
    # stock move amount for costs calculation
    def _landing_costs_base_amount(self, cr, uid, ids, name, args, context):
        if not ids:
            return {}
        result = {}
        base_amount = 0.0
        for line in self.browse(cr, uid, ids):
            if line.product_id.landing_cost_calculate:
                base_amount = line.price_unit * line.product_qty
            result[line.id] = base_amount
        return result

    def _landing_costs_price_unit_with_costs(self, cr, uid, ids, name, args, context):
        if not ids:
            return {}
        result = {}

        for line in self.browse(cr, uid, ids):
            if line.price_unit_without_costs and line.price_unit_without_costs <> 0.0:
                price_unit_with_costs = line.price_unit_without_costs
            else:
                price_unit_with_costs = line.price_unit or 0.0
            if line.product_id.landing_cost_calculate:
                if line.picking_id and (line.picking_id.landing_costs_per_value > 0.0 or line.picking_id.landing_costs_per_unit > 0.0):       
                    # landing costs - picking - amount
                    if line.picking_id.landing_costs_base_amount > 0.0 and line.product_qty > 0.0:
                        price_unit_with_costs += ((line.picking_id.landing_costs_per_value / line.picking_id.landing_costs_base_amount) * (line.price_unit * line.product_qty)) / line.product_qty
                    # landing costs - picking - quantity
                    if line.product_qty > 0.0:
                        price_unit_with_costs += line.picking_id.landing_costs_per_unit / line.picking_id.landing_costs_base_quantity
                                    
                # landing costs - move
                if line.product_qty > 0.0 and (line.landing_costs_per_value > 0.0 or line.landing_costs_per_unit > 0.0):
                    price_unit_with_costs += (line.landing_costs_per_value + line.landing_costs_per_unit) / line.product_qty                                     

            if line.price_unit != price_unit_with_costs:
                self.write(cr, uid, [line.id], {'price_unit': price_unit_with_costs})                 
            result[line.id] = price_unit_with_costs
            
        return result

    _columns = { 
          'price_unit_without_costs': fields.float('', digits_compute=dp.get_precision('Product Price'), ),
          'price_unit_with_costs': fields.function(_landing_costs_price_unit_with_costs, digits_compute=dp.get_precision('Product Price'), ),
          'landing_costs_line_ids': fields.one2many('purchase.landing.cost.position', 'move_line_id', 'Landing Costs'),
          'landing_costs_per_value': fields.function(_landing_costs_per_value, digits_compute=dp.get_precision('Product Price'), string='Landing Costs Amount Per Value For Average Price'),
          'landing_costs_per_unit': fields.function(_landing_costs_per_unit, digits_compute=dp.get_precision('Product Price'), string='Landing Costs Amount Per Unit For Average Price'),
          'landing_costs_base_quantity': fields.function(_landing_costs_base_quantity, digits_compute=dp.get_precision('Product Price'), string='Stock Move Quantity For Per Unit Calculation'),
          'landing_costs_base_amount': fields.function(_landing_costs_base_amount, digits_compute=dp.get_precision('Product Price'), string='Stock Move For Per Value Calculation'),
    }
class account_transfer(osv.osv):
    def _get_balance(self, src_journal, dst_journal, company):
        src_balance = dst_balance = 0.0
        #import pdb; pdb.set_trace()
        if src_journal.default_credit_account_id.id == src_journal.default_debit_account_id.id:
            if not src_journal.currency or company.currency_id.id == src_journal.currency.id:
                src_balance = src_journal.default_credit_account_id.balance
            else:
                src_balance = src_journal.default_credit_account_id.foreign_balance
        else:
            if not src_journal.currency or company.currency_id.id == src_journal.currency.id:
                src_balance = src_journal.default_debit_account_id.balance - src_journal.default_credit_account_id.balance
            else:
                src_balance = src_journal.default_debit_account_id.foreign_balance - src_journal.default_credit_account_id.foreign_balance
        if dst_journal.default_credit_account_id.id == dst_journal.default_debit_account_id.id:
            if not dst_journal.currency or company.currency_id.id == dst_journal.currency.id:
                dst_balance = dst_journal.default_credit_account_id.balance
            else:
                dst_balance = dst_journal.default_credit_account_id.foreign_balance
        else:
            if not dst_journal.currency or company.currency_id.id == dst_journal.currency.id:
                dst_balance = dst_journal.default_debit_account_id.balance - dst_journal.default_credit_account_id.balance
            else:
                dst_balance = dst_journal.default_debit_account_id.foreign_balance - dst_journal.default_credit_account_id.foreign_balance

        return (src_balance, dst_balance)

    def _balance(self, cr, uid, ids, field_name, arg, context=None):
        res = {}
        for trans in self.browse(cr, uid, ids, context=context):
            src_balance, dst_balance = self._get_balance(
                trans.src_journal_id, trans.dst_journal_id, trans.company_id)
            exchange = False
            if trans.dst_journal_id.currency.id != trans.src_journal_id.currency.id:
                exchange = True
            res[trans.id] = {
                'src_balance':
                src_balance,
                'dst_balance':
                dst_balance,
                'exchange':
                exchange,
                'exchange_inv':
                (trans.exchange_rate and 1.0 / trans.exchange_rate or 0.0)
            }
        return res

    STATE_SELECTION = [
        ('draft', 'Draft'),
        ('confirm', 'Confirm'),
        ('done', 'Done'),
        ('cancel', 'Cancel'),
    ]

    _columns = {
        'company_id':
        fields.many2one('res.company',
                        'Company',
                        required=True,
                        readonly=True,
                        states={'draft': [('readonly', False)]}),
        'name':
        fields.char('Number',
                    size=32,
                    required=True,
                    readonly=True,
                    states={'draft': [('readonly', False)]}),
        'date':
        fields.date('Date',
                    required=True,
                    readonly=True,
                    states={'draft': [('readonly', False)]}),
        'origin':
        fields.char('Origin',
                    size=128,
                    readonly=True,
                    states={'draft': [('readonly', False)]},
                    help="Origin Document"),
        'account_analytic_id':
        fields.many2one('account.analytic.account',
                        'Analytic Account',
                        readonly=True,
                        states={'draft': [('readonly', False)]}),
        'voucher_ids':
        fields.one2many('account.voucher',
                        'transfer_id',
                        string='Payments',
                        readonly=True,
                        states={
                            'draft': [('readonly', False)],
                            'confirm': [('readonly', False)]
                        }),
        'src_journal_id':
        fields.many2one('account.journal',
                        'Source Journal',
                        required=True,
                        domain=[('type', 'in', ['cash', 'bank'])],
                        select=True,
                        readonly=True,
                        states={'draft': [('readonly', False)]}),
        'src_partner_id':
        fields.many2one('res.partner', 'Source Partner', select=True),
        'src_balance':
        fields.function(
            _balance,
            digits_compute=dp.get_precision('Account'),
            string='Current Source Balance',
            type='float',
            readonly=True,
            multi='balance',
            help="Include all account moves in draft and confirmed state"),
        'src_amount':
        fields.float('Source Amount',
                     required=True,
                     readonly=True,
                     states={'draft': [('readonly', False)]}),
        'src_have_partner':
        fields.related('src_journal_id',
                       'have_partner',
                       type='boolean',
                       string='Have Partner',
                       readonly=True),
        'dst_journal_id':
        fields.many2one('account.journal',
                        'Destinity Journal',
                        required=True,
                        domain=[('type', 'in', ['cash', 'bank'])],
                        select=True,
                        readonly=True,
                        states={'draft': [('readonly', False)]}),
        'dst_partner_id':
        fields.many2one('res.partner', 'Destinity Partner', select=True),
        'dst_balance':
        fields.function(
            _balance,
            digits_compute=dp.get_precision('Account'),
            string='Current Destinity Balance',
            type='float',
            readonly=True,
            multi='balance',
            help="Include all account moves in draft and confirmed state"),
        'dst_amount':
        fields.float('Destinity Amount',
                     required=True,
                     readonly=True,
                     states={'draft': [('readonly', False)]}),
        'dst_have_partner':
        fields.related('dst_journal_id',
                       'have_partner',
                       type='boolean',
                       string='Have Partner',
                       readonly=True),
        'exchange_rate':
        fields.float('Exchange Rate',
                     digits_compute=dp.get_precision('Exchange'),
                     readonly=True,
                     states={'draft': [('readonly', False)]}),
        'exchange':
        fields.function(_balance,
                        string='Have Exchange',
                        type='boolean',
                        readonly=True,
                        multi='balance'),
        'exchange_inv':
        fields.function(_balance,
                        string='1 / Exchange Rate',
                        type='float',
                        digits_compute=dp.get_precision('Exchange'),
                        readonly=True,
                        multi='balance'),
        'adjust_move':
        fields.many2one(
            'account.move',
            'Adjust Move',
            readonly=True,
            help="Adjust move usually by difference in the money exchange"),
        'state':
        fields.selection(STATE_SELECTION, string='State', readonly=True),
    }
    _defaults = {
        'name':
        lambda s, cr, u, c: s.pool.get('ir.sequence').get(
            cr, u, 'account.transfer'),
        'company_id':
        lambda s, cr, u, c: s.pool.get('res.users').browse(cr, u, u).company_id
        .id,
        'date':
        lambda *a: time.strftime('%Y-%m-%d'),
        'exchange_rate':
        1.0,
        'exchange_inv':
        1.0,
        'state':
        'draft',
    }
    _sql_constraints = [('name_unique', 'unique(company_id,name)',
                         _('The number must be unique!'))]
    _name = 'account.transfer'
    _inherit = ['mail.thread', 'ir.needaction_mixin']
    _description = 'Account Cash and Bank Transfer'
    _order = 'name desc'

    def unlink(self, cr, uid, ids, context=None):
        for trans in self.browse(cr, uid, ids, context=context):
            if trans.state not in ('draft'):
                raise osv.except_osv(
                    _('User Error!'),
                    _('You cannot delete a not draft transfer "%s"') %
                    trans.name)
        return super(account_transfer, self).unlink(cr,
                                                    uid,
                                                    ids,
                                                    context=context)

    def copy(self, cr, uid, id, defaults, context=None):
        defaults['name'] = self.pool.get('ir.sequence').get(
            cr, uid, 'account.transfer')
        defaults['voucher_ids'] = []
        return super(account_transfer, self).copy(cr,
                                                  uid,
                                                  id,
                                                  defaults,
                                                  context=context)

    def onchange_amount(self, cr, uid, ids, field, src_amount, dst_amount,
                        exchange_rate):
        res = {'value': {}}
        if field == 'src_amount':
            res['value']['src_amount'] = src_amount
            res['value']['dst_amount'] = src_amount * exchange_rate
            res['value']['exchange_rate'] = exchange_rate
            res['value'][
                'exchange_inv'] = exchange_rate and 1.0 / exchange_rate or 0.0
        elif field == 'dst_amount':
            res['value'][
                'src_amount'] = exchange_rate and dst_amount / exchange_rate or 0.0
            res['value']['dst_amount'] = dst_amount
            res['value']['exchange_rate'] = exchange_rate
            res['value'][
                'exchange_inv'] = exchange_rate and 1.0 / exchange_rate or 0.0
        elif field == 'exchange_rate':
            res['value']['src_amount'] = src_amount
            res['value']['dst_amount'] = src_amount * exchange_rate
            res['value']['exchange_rate'] = exchange_rate
            res['value'][
                'exchange_inv'] = exchange_rate and 1.0 / exchange_rate or 0.0
        return res

    def onchange_journal(self, cr, uid, ids, src_journal_id, dst_journal_id,
                         date, exchange_rate, src_amount):
        res = {'value': {}}
        if not (src_journal_id and dst_journal_id):
            return res
        src_journal = self.pool.get('account.journal').browse(
            cr, uid, src_journal_id)
        dst_journal = self.pool.get('account.journal').browse(
            cr, uid, dst_journal_id)
        res['value']['src_balance'], res['value'][
            'dst_balance'] = self._get_balance(src_journal, dst_journal,
                                               src_journal.company_id)
        res['value']['exchange'] = (src_journal.currency.id !=
                                    dst_journal.currency.id)
        res['value']['src_have_partner'], res['value'][
            'dst_have_partner'] = src_journal.have_partner, dst_journal.have_partner
        res['value']['exchange_rate'] = exchange_rate
        if res['value']['exchange']:
            res['value']['exchange_rate'] = (
                src_journal.currency and src_journal.currency.rate
                or src_journal.company_id.currency_id.rate) and (
                    (dst_journal.currency and dst_journal.currency.rate
                     or dst_journal.company_id.currency_id.rate) /
                    (src_journal.currency and src_journal.currency.rate
                     or src_journal.company_id.currency_id.rate)) or 0.0
        else:
            res['value']['exchange_rate'] = 1.0
        res['value']['exchange_inv'] = res['value']['exchange_rate'] and (
            1.0 / res['value']['exchange_rate']) or 0.0
        res['value']['dst_amount'] = res['value']['exchange_rate'] * src_amount
        return res

    def action_confirm(self, cr, uid, ids, context=None):
        voucher_obj = self.pool.get('account.voucher')
        for trans in self.browse(cr, uid, ids, context=context):
            sval = {}
            dval = {}
            sval['transfer_id'] = trans.id
            dval['transfer_id'] = trans.id
            sval['type'] = 'transfer'
            dval['type'] = 'transfer'
            sval['company_id'] = trans.company_id.id
            dval['company_id'] = trans.company_id.id
            sval['reference'] = trans.name + str(trans.origin and
                                                 (' - ' + trans.origin) or '')
            dval['reference'] = trans.name + str(trans.origin and
                                                 (' - ' + trans.origin) or '')
            sval['line_ids'] = [(0, 0, {})]
            dval['line_ids'] = [(0, 0, {})]
            sval['line_ids'][0][2][
                'account_analytic_id'] = trans.account_analytic_id and trans.account_analytic_id.id or 0
            dval['line_ids'][0][2][
                'account_analytic_id'] = trans.account_analytic_id and trans.account_analytic_id.id or 0
            sval['line_ids'][0][2]['name'] = trans.origin
            dval['line_ids'][0][2]['name'] = trans.origin
            sval['journal_id'] = trans.src_journal_id.id
            dval['journal_id'] = trans.dst_journal_id.id
            sval[
                'account_id'] = trans.src_journal_id.default_credit_account_id.id
            dval[
                'account_id'] = trans.dst_journal_id.default_debit_account_id.id
            sval[
                'payment_rate'] = trans.src_journal_id.currency.id and trans.company_id.currency_id.id <> trans.src_journal_id.currency.id and trans.exchange_rate or 1.0
            dval[
                'payment_rate'] = trans.dst_journal_id.currency.id and trans.company_id.currency_id.id <> trans.dst_journal_id.currency.id and trans.exchange_inv or 1.0
            sval[
                'payment_rate_currency_id'] = trans.dst_journal_id.currency.id or trans.company_id.currency_id.id
            sval[
                'payment_rate_currency_id'] = trans.src_journal_id.currency.id or trans.company_id.currency_id.id
            #import pdb; pdb.set_trace()
            sval['line_ids'][0][2]['amount'] = sval[
                'amount'] = trans.src_amount
            dval['line_ids'][0][2]['amount'] = dval[
                'amount'] = trans.dst_amount
            sval['line_ids'][0][2]['type'] = 'dr'
            dval['line_ids'][0][2]['type'] = 'cr'
            sval['line_ids'][0][2][
                'account_id'] = trans.dst_journal_id.default_debit_account_id.id
            if trans.src_partner_id.id ^ trans.dst_partner_id.id:
                sval[
                    'partner_id'] = trans.src_have_partner and trans.src_partner_id.id or trans.dst_partner_id.id
            else:
                sval[
                    'partner_id'] = trans.src_have_partner and trans.src_partner_id.id or trans.company_id.partner_id.id
                dval[
                    'partner_id'] = trans.dst_have_partner and trans.dst_partner_id.id or trans.company_id.partner_id.id
                sval['line_ids'][0][2]['account_id'] = dval['line_ids'][0][2][
                    'account_id'] = trans.src_journal_id.account_transit.id
                voucher_obj.create(cr, uid, dval, context=context)
            voucher_obj.create(cr, uid, sval, context=context)
        return self.write(cr, uid, ids, {'state': 'confirm'}, context=context)

    def action_done(self, cr, uid, ids, context=None):
        voucher_obj = self.pool.get('account.voucher')
        move_obj = self.pool.get('account.move')
        for trans in self.browse(cr, uid, ids, context=context):
            paid_amount = []
            for voucher in trans.voucher_ids:
                voucher.state == 'draft' and voucher_obj.proforma_voucher(
                    cr, uid, [voucher.id], context=context)
                sign = (voucher.journal_id.id
                        == trans.src_journal_id.id) and 1 or -1
                paid_amount.append(
                    sign * voucher_obj._paid_amount_in_company_currency(
                        cr, uid, [voucher.id], '', '')[voucher.id])
                #paid_amount.append(sign * voucher.paid_amount_in_company_currency)
            sum_amount = sum(paid_amount)
            if len(paid_amount) > 1 and sum_amount != 0.0:
                periods = self.pool.get('account.period').find(cr, uid)
                move = {}
                move['journal_id'] = trans.dst_journal_id.id
                move['period_id'] = periods and periods[0] or False
                move['ref'] = trans.name + str(trans.origin and
                                               (' - ' + trans.origin) or '')
                move['date'] = trans.date
                move['line_id'] = [(0, 0, {}), (0, 0, {})]
                move['line_id'][0][2]['name'] = trans.name
                move['line_id'][1][2]['name'] = trans.name
                if sum_amount > 0:
                    move['line_id'][0][2][
                        'account_id'] = trans.dst_journal_id.default_debit_account_id.id
                    move['line_id'][1][2][
                        'account_id'] = trans.src_journal_id.account_transit.id  #trans.company_id.income_currency_exchange_account_id.id
                    move['line_id'][0][2]['debit'] = sum_amount
                    move['line_id'][1][2]['credit'] = sum_amount
                else:
                    move['line_id'][0][2][
                        'account_id'] = trans.dst_journal_id.default_credit_account_id.id
                    move['line_id'][1][2][
                        'account_id'] = trans.src_journal_id.account_transit.id  #trans.company_id.expense_currency_exchange_account_id.id
                    move['line_id'][1][2]['debit'] = -1 * sum_amount
                    move['line_id'][0][2]['credit'] = -1 * sum_amount
                move_id = move_obj.create(cr, uid, move, context=context)
                self.write(cr,
                           uid, [trans.id], {'adjust_move': move_id},
                           context=context)
        return self.write(cr, uid, ids, {'state': 'done'}, context=context)

    def action_cancel(self, cr, uid, ids, context=None):
        voucher_obj = self.pool.get('account.voucher')
        move_obj = self.pool.get('account.move')
        #import pdb; pdb.set_trace()
        for trans in self.browse(cr, uid, ids, context=context):
            for voucher in trans.voucher_ids:
                voucher_obj.unlink(cr, uid, [voucher.id], context=context)
            trans.adjust_move and move_obj.unlink(
                cr, uid, [trans.adjust_move.id], context=context)
        return self.write(cr, uid, ids, {'state': 'cancel'}, context=context)
Example #38
0
class account_analytic_line_plan(osv.osv):
    _name = 'account.analytic.line.plan'
    _description = 'Analytic planning line'

    def _get_company_currency(self, cr, uid, context=None):
        """
        Returns the default company currency
        """
        if context is None:
            context = {}

        company_obj = self.pool.get('res.company')
        company_id = self.pool.get('res.company')._company_default_get(
            cr, uid, 'account.analytic.line', context=context)
        company = company_obj.browse(cr, uid, company_id, context=context)
        return company.currency_id and company.currency_id.id or False

    _columns = {
        'name':
        fields.char('Activity description', size=256, required=True),
        'date':
        fields.date('Date', required=True, select=True),
        'amount':
        fields.float('Amount',
                     required=True,
                     help='Calculated by multiplying the quantity '
                     'and the price given in the Product\'s cost '
                     'price. Always expressed in the company main '
                     'currency.',
                     digits_compute=dp.get_precision('Account')),
        'unit_amount':
        fields.float('Quantity',
                     help='Specifies the amount of quantity to count.'),
        'amount_currency':
        fields.float(
            'Amount Currency',
            help="The amount expressed in an optional other currency."),
        'currency_id':
        fields.many2one('res.currency', 'Currency'),
        'account_id':
        fields.many2one('account.analytic.account',
                        'Analytic Account',
                        required=True,
                        ondelete='cascade',
                        select=True,
                        domain=[('type', '<>', 'view')]),
        'user_id':
        fields.many2one('res.users', 'User'),
        'company_id':
        fields.related('account_id',
                       'company_id',
                       type='many2one',
                       relation='res.company',
                       string='Company',
                       store=True,
                       readonly=True),
        'product_uom_id':
        fields.many2one('product.uom', 'UoM'),
        'product_id':
        fields.many2one('product.product', 'Product'),
        'general_account_id':
        fields.many2one('account.account',
                        'General Account',
                        required=False,
                        ondelete='restrict'),
        'journal_id':
        fields.many2one('account.analytic.plan.journal',
                        'Planning Analytic Journal',
                        required=True,
                        ondelete='restrict',
                        select=True),
        'code':
        fields.char('Code', size=8),
        'ref':
        fields.char('Ref.', size=64),
        'notes':
        fields.text('Notes'),
        'version_id':
        fields.many2one('account.analytic.plan.version',
                        'Planning Version',
                        required=True,
                        ondelete='cascade'),
    }

    _defaults = {
        'date':
        lambda *a: time.strftime('%Y-%m-%d'),
        'company_id':
        lambda self, cr, uid, c: self.pool.get('res.company').
        _company_default_get(cr, uid, 'account.analytic.line', context=c),
        'currency_id':
        _get_company_currency,
        'amount':
        0.00,
        'journal_id':
        lambda self, cr, uid, context: context['journal_id']
        if context and 'journal_id' in context else None,
        'version_id':
        lambda s, cr, uid, c: s.pool.get('account.analytic.plan.version').
        search(cr, uid, [('default_plan', '=', True)], context=None),
    }
    _order = 'date desc'

    def search(self,
               cr,
               uid,
               args,
               offset=0,
               limit=None,
               order=None,
               context=None,
               count=False):
        if context is None:
            context = {}
        if context.get('from_date', False):
            args.append(['date', '>=', context['from_date']])
        if context.get('to_date', False):
            args.append(['date', '<=', context['to_date']])
        return super(account_analytic_line_plan, self).search(cr,
                                                              uid,
                                                              args,
                                                              offset,
                                                              limit,
                                                              order,
                                                              context=context,
                                                              count=count)

    def _check_company(self, cr, uid, ids, context=None):
        lines = self.browse(cr, uid, ids, context=context)
        for l in lines:
            if l.move_id and not l.account_id.company_id.id == l.move_id.account_id.company_id.id:
                return False
        return True

    def on_change_amount_currency(self,
                                  cr,
                                  uid,
                                  id,
                                  amount_currency,
                                  currency_id,
                                  company_id,
                                  context=None):

        res = {}
        res['value'] = {}

        if context is None:
            context = {}

        currency_obj = self.pool.get('res.currency')
        company_obj = self.pool.get('res.company')

        company = company_obj.browse(cr, uid, company_id, context=context)

        company_currency_id = company.currency_id.id

        if amount_currency:
            amount_company_currency = currency_obj.compute(cr,
                                                           uid,
                                                           currency_id,
                                                           company_currency_id,
                                                           amount_currency,
                                                           context=context)
        else:
            amount_company_currency = 0.0

        res['value'].update({
            'amount': amount_company_currency,
        })

        return res

    def on_change_unit_amount(self,
                              cr,
                              uid,
                              id,
                              prod_id,
                              quantity,
                              currency_id,
                              company_id,
                              unit=False,
                              journal_id=False,
                              context=None):

        res = {}

        if context is None:
            context = {}

        product_obj = self.pool.get('product.product')
        analytic_journal_obj = self.pool.get('account.analytic.plan.journal')
        product_price_type_obj = self.pool.get('product.price.type')

        prod = False
        if prod_id:
            prod = product_obj.browse(cr, uid, prod_id, context=context)
            res['value'] = {}

        if not journal_id:
            j_ids = analytic_journal_obj.search(cr, uid,
                                                [('type', '=', 'purchase')])
            journal_id = j_ids and j_ids[0] or False
        if not journal_id or not prod_id:
            return res

        journal = analytic_journal_obj.browse(cr,
                                              uid,
                                              journal_id,
                                              context=context)

        if journal.type != 'sale' and prod:
            a = prod.product_tmpl_id.property_account_expense.id
            if not a:
                a = prod.categ_id.property_account_expense_categ.id
            if not a:
                raise osv.except_osv(
                    _('Error !'),
                    _('There is no expense account defined '
                      'for this product: "%s" (id:%d)') % (
                          prod.name,
                          prod.id,
                      ))
        else:
            a = prod.product_tmpl_id.property_account_income.id
            if not a:
                a = prod.categ_id.property_account_income_categ.id
            if not a:
                raise osv.except_osv(
                    _('Error !'),
                    _('There is no income account defined '
                      'for this product: "%s" (id:%d)') % (
                          prod.name,
                          prod_id,
                      ))

        flag = False
        # Compute based on pricetype
        product_price_type_ids = product_price_type_obj.search(
            cr, uid, [('field', '=', 'standard_price')], context=context)
        pricetype = product_price_type_obj.browse(cr,
                                                  uid,
                                                  product_price_type_ids,
                                                  context=context)[0]
        if journal_id:
            if journal.type == 'sale':
                product_price_type_ids = product_price_type_obj.search(
                    cr, uid, [('field', '=', 'list_price')], context)
                if product_price_type_ids:
                    pricetype = product_price_type_obj.browse(
                        cr, uid, product_price_type_ids, context=context)[0]
        # Take the company currency as the reference one
        if pricetype.field == 'list_price':
            flag = True
        ctx = context.copy()
        if unit:
            # price_get() will respect a 'uom' in its context, in order
            # to return a default price for those units
            ctx['uom'] = unit
        amount_unit = prod.price_get(pricetype.field, context=ctx)[prod.id]
        prec = self.pool.get('decimal.precision').precision_get(
            cr, uid, 'Account')
        amount = amount_unit * quantity or 1.0
        result = round(amount, prec)

        if not flag:
            if journal.type != 'sale':
                result *= -1

        res = self.on_change_amount_currency(cr, uid, id, result, currency_id,
                                             company_id, context)

        res['value'].update({
            'amount_currency': result,
            'general_account_id': a,
        })

        return res

    def on_change_product_id(self,
                             cr,
                             uid,
                             id,
                             prod_id,
                             quantity,
                             currency_id,
                             company_id,
                             unit=False,
                             journal_id=False,
                             context=None):

        res = self.on_change_unit_amount(cr, uid, id, prod_id, quantity,
                                         currency_id, company_id, unit,
                                         journal_id, context)

        prod = self.pool.get('product.product').browse(cr,
                                                       uid,
                                                       prod_id,
                                                       context=context)
        prod_uom_po = prod.uom_po_id.id

        res['value'].update({
            'product_uom_id': prod_uom_po,
        })

        return res

    def view_header_get(self, cr, user, view_id, view_type, context=None):
        if context is None:
            context = {}
        if context.get('account_id', False):
            # account_id in context may also be pointing to an account.account.id
            cr.execute('select name from account_analytic_account where id=%s',
                       (context['account_id'], ))
            res = cr.fetchone()
            if res:
                res = _('Entries: ') + (res[0] or '')
            return res

        return False
class tcv_label_request_print_prn_export(osv.osv_memory):

    _name = 'tcv.label.request.print.prn.export'

    _description = ''

    _sections = ('<header>', '<body>', '<nextlabel>', '<footer>')

    ##-------------------------------------------------------------------------

    def load_label_template(self, label_template):
        actual_key = ''
        res = {}
        for line in label_template.splitlines(True):
            line_tmp = line[:-2]
            if line_tmp in self._sections:
                actual_key = line_tmp
                res.update({actual_key: ''})
            elif actual_key:
                res[actual_key] = line if res[actual_key] == '' else '%s%s' % (
                    res[actual_key], line)
        return res

    def create_labels(self, label_list, label_template, params=None):
        params = params or {}
        res = label_template['<header>']
        for label in label_list:
            body = ''
            for l in label_template['<body>'].splitlines(True):
                label_number = '%s>6%s' % (
                    label[:-1], label[-1]) if len(label) > 6 else label

                params.update({
                    'label_number': label_number,
                    'label_number2': label,
                })
                t = l % params
                body += t
            res = ''.join([res, body])
            if label != label_list[-1]:
                res = ''.join((res, label_template['<nextlabel>']))
        res = ''.join((res, label_template['<footer>']))
        return res

    ##--------------------------------------------------------- function fields

    _columns = {
        'name':
        fields.char('Filename', 64, readonly=True),
        'prn_file':
        fields.binary('PRN file',
                      readonly=True,
                      filters='*.prn',
                      help="PRN file name"),
        'label_start':
        fields.char('Label start', size=16, required=False, readonly=True),
        'label_end':
        fields.char('Label end', size=16, required=False, readonly=True),
        'product_id':
        fields.many2one('product.product', 'Product', ondelete='restrict'),
        'block_ref':
        fields.char('block_ref', size=128, required=False, readonly=False),
        'price_1':
        fields.float('price_1', digits_compute=dp.get_precision('Account')),
        'tax_1':
        fields.float('tax_1', digits_compute=dp.get_precision('Account')),
        'price_2':
        fields.float('price_2', digits_compute=dp.get_precision('Account')),
        'label_date':
        fields.char('label_date', size=128, required=False, readonly=False),
        'label_template_id':
        fields.many2one('tcv.label.template',
                        'Gangsaw label template',
                        required=True,
                        readonly=False,
                        ondelete='restrict',
                        help="Default label template for gangsaw's labels"),
        'company_id':
        fields.many2one('res.company',
                        'Company',
                        required=True,
                        readonly=True,
                        ondelete='restrict'),
        'loaded':
        fields.boolean('loaded'),
    }

    _defaults = {
        'label_start':
        lambda *a: 0,
        'label_end':
        lambda *a: 0,
        'company_id':
        lambda self, cr, uid, c: self.pool.get('res.company').
        _company_default_get(cr, uid, self._name, context=c),
    }

    _sql_constraints = []

    ##-------------------------------------------------------------------------

    def button_generate_labels(self, cr, uid, ids, context=None):
        ids = isinstance(ids, (int, long)) and [ids] or ids
        buf = cStringIO.StringIO()
        for item in self.browse(cr, uid, ids, context={}):
            output_prd = item.product_id
            obj_lbl = self.pool.get('tcv.label.request.print.prn.export')
            template = item.label_template_id
            p_name = output_prd.name.split('/')[0].upper()
            for x in ('BLOQUES', '1RA', '2DA', '(POCO MOVIMIENTO)', 'LAMINAS',
                      'RESINADAS', 'PULIDAS', '20MM', '.'):
                p_name = p_name.replace(x, '')
                p_name = p_name.replace('  ', ' ')
            product_name = p_name.strip() if p_name != 'ROSA CARIBE ' \
                else 'CARIBE'
            if not item.label_start.isdigit() or \
                    not item.label_end.isdigit() or \
                    len(item.label_start) != 11 or \
                    len(item.label_end) != 11 or \
                    item.label_start[:-2] != item.label_end[:-2] or \
                    int(item.label_start) > int(item.label_end):
                raise osv.except_osv(_('Error!'), _('Invalid labels sequence'))
            label_list = range(int(item.label_start), int(item.label_end) + 1)
            label_list = map(lambda x: '%011d' % x, label_list)
            label_template = obj_lbl.load_label_template(template.template)
            block_ref = item.block_ref
            price_1 = item.price_1
            tax_1 = item.tax_1
            price_2 = item.price_2
            label_date = item.label_date
            labels = obj_lbl.create_labels(
                label_list, label_template, {
                    'product_name':
                    product_name,
                    'block_ref':
                    'Ref: %s' % block_ref,
                    'price_1': ('PMVP: %.2f | IVA: %.2f' %
                                (price_1, tax_1)).replace('.', ','),
                    'price_2':
                    ('A pagar Bs x m2:%.2f' % (price_2)).replace('.', ','),
                    'label_date':
                    label_date,
                })
            buf.write(labels)
            out = base64.encodestring(buf.getvalue())
            buf.close()
            file_name = '%s-%s.prn' % (label_list[0], label_list[-1][-2:])
            self.write(cr,
                       uid, [item.id], {
                           'prn_file': out,
                           'name': file_name,
                           'loaded': True
                       },
                       context=context)
            return True

    ##------------------------------------------------------------ on_change...

    def on_change_label(self, cr, uid, ids, label_start, label_end):
        res = {}
        res.update({'Name': None, 'prn_file': None, 'loaded': False})
        return {'value': res}
class account_invoice_line(osv.osv):
    _inherit = 'account.invoice.line'

    def _amount_line_single(self, cr, uid, ids, prop, unknow_none,
                            unknow_dict):
        """
        Provides 4 additional function fields to be used in 
        invoice reports. Note that the original invoice report uses
        price_unit, which may or may not include taxes according to
        product settings. These fields should unequivocally produce
        the price per units or per line, excluding and including taxes.

        Analogous to the standard method _amount_line in account/account_invoice.py
        """
        res = {}
        tax_obj = self.pool.get('account.tax')
        cur_obj = self.pool.get('res.currency')
        for line in self.browse(cr, uid, ids):
            price = line.price_unit * (1 - (line.discount or 0.0) / 100.0)
            taxes = tax_obj.compute_all(
                cr,
                uid,
                line.invoice_line_tax_id,
                price,
                1,
                product=line.product_id,
                address_id=line.invoice_id.address_invoice_id,
                partner=line.invoice_id.partner_id)
            res[line.id] = {
                'price_unit_incl': taxes['total_included'],
                'price_unit_excl': taxes['total']
            }
            taxes = tax_obj.compute_all(
                cr,
                uid,
                line.invoice_line_tax_id,
                price,
                line.quantity,
                product=line.product_id,
                address_id=line.invoice_id.address_invoice_id,
                partner=line.invoice_id.partner_id)
            res[line.id]['price_line_incl'] = taxes['total_included']
            res[line.id]['price_line_excl'] = taxes['total']
            if line.invoice_id:
                cur = line.invoice_id.currency_id
                res[line.id]['price_unit_incl'] = cur_obj.round(
                    cr, uid, cur, res[line.id]['price_unit_incl'])
                res[line.id]['price_unit_excl'] = cur_obj.round(
                    cr, uid, cur, res[line.id]['price_unit_excl'])
                res[line.id]['price_line_incl'] = cur_obj.round(
                    cr, uid, cur, res[line.id]['price_line_incl'])
                res[line.id]['price_line_excl'] = cur_obj.round(
                    cr, uid, cur, res[line.id]['price_line_excl'])
        return res

    _columns = {
        'price_unit_incl':
        fields.function(_amount_line_single,
                        string='Unit price incl. taxes',
                        type="float",
                        digits_compute=dp.get_precision('Account'),
                        multi='single',
                        store=False),
        'price_unit_excl':
        fields.function(_amount_line_single,
                        string='Unit price excl. taxes',
                        type="float",
                        digits_compute=dp.get_precision('Account'),
                        multi='single',
                        store=False),
        'price_line_incl':
        fields.function(_amount_line_single,
                        string='Line subtotal incl. taxes',
                        type="float",
                        digits_compute=dp.get_precision('Account'),
                        multi='single',
                        store=False),
        'price_line_excl':
        fields.function(_amount_line_single,
                        string='Line subtotal excl. taxes',
                        type="float",
                        digits_compute=dp.get_precision('Account'),
                        multi='single',
                        store=False),
    }
Example #41
0
class product_historical(osv.Model):
    """
    product_historical
    """
    def _get_historical_price(self, cr, uid, ids, field_name, field_value,
                              arg, context={}):
        res = {}
        product_hist = self.pool.get('product.historic.price')
        for id in ids:
            if self.browse(cr, uid, id).list_price != self.browse(cr, uid,
                                                                  id).\
                                                         list_price_historical:
                res[id] = self.browse(cr, uid, id).list_price
                product_hist.create(cr, uid, {
                    'product_id': id,
                    'name': time.strftime('%Y-%m-%d %H:%M:%S'),
                    'price': self.browse(cr, uid, id).list_price,
                }, context)
        return res

    def _get_historical_cost(self, cr, uid, ids, field_name, field_value,
                             arg, context={}):
        res = {}
        product_hist = self.pool.get('product.historic.cost')
        for id in ids:
            if self.browse(cr, uid, id).standard_price != self.browse(cr,
                                                  uid, id).cost_historical:
                res[id] = self.browse(cr, uid, id).standard_price
                product_hist.create(cr, uid, {
                    'product_id': id,
                    'name': time.strftime('%Y-%m-%d %H:%M:%S'),
                    'price': self.browse(cr, uid, id).standard_price,
                }, context)
        return res

    _inherit = 'product.product'
    _columns = {
        'list_price_historical':
           fields.function(_get_historical_price,
                                         method=True, string='Latest Price',
                                         type='float',
                                         digits_compute=dp.get_precision(
                                             'List_Price_Historical'),
                                         store={'product.product': ( lambda
                                             self, cr, uid, ids, c={}: ids, [
                                                 'list_price'], 50), },
                                             help="""Latest Recorded Historical
                                             Value"""),
        'cost_historical': fields.function(_get_historical_cost, method=True,
                                           string=' Latest Cost', type='float',
                                           digits_compute=dp.get_precision(
                                               'Cost_Historical'),
                                           store={'product.product': ( lambda
                                               self, cr, uid, ids, c={}: ids, [
                                                   'standard_price'], 50), },
                                               help="""Latest Recorded
                                               Historical Cost"""),
        'list_price_historical_ids': fields.one2many('product.historic.price',
                                                     'product_id',
                                                     'Historical Prices'),
        'cost_historical_ids': fields.one2many('product.historic.cost',
                                               'product_id',
                                               'Historical Prices'),

    }
Example #42
0
    def _link_invoice(self, cursor, uid, trans, move_lines,
                      partner_ids, bank_account_ids, log, linked_invoices):
        '''
        Find the invoice belonging to this reference - if there is one
        Use the sales journal to check.

        Challenges we're facing:
            1. The sending or receiving party is not necessarily the same as the
               partner the payment relates to.
            2. References can be messed up during manual encoding and inexact
               matching can link the wrong invoices.
            3. Amounts can or can not match the expected amount.
            4. Multiple invoices can be paid in one transaction.
            .. There are countless more, but these we'll try to address.

        Assumptions for matching:
            1. There are no payments for invoices not sent. These are dealt with
               later on.
            2. Debit amounts are either customer invoices or credited supplier
               invoices.
            3. Credit amounts are either supplier invoices or credited customer
               invoices.
            4. Payments are either below expected amount or only slightly above
               (abs).
            5. Payments from partners that are matched, pay their own invoices.
        
        Worst case scenario:
            1. No match was made.
               No harm done. Proceed with manual matching as usual.
            2. The wrong match was made.
               Statements are encoded in draft. You will have the opportunity to
               manually correct the wrong assumptions. 

        Return values:
            move_info: the move_line information belonging to the matched
                       invoice
            new_trans: the new transaction when the current one was split.
            This can happen when multiple invoices were paid with a single
            bank transaction.
        '''
        def eyecatcher(invoice):
            '''
            Return the eyecatcher for an invoice
            '''
            return invoice.type.startswith('in_') and invoice.name or \
                    invoice.number

        def has_id_match(invoice, ref, msg):
            '''
            Aid for debugging - way more comprehensible than complex
            comprehension filters ;-)

            Match on ID of invoice (reference, name or number, whatever
            available and sensible)
            '''
            if invoice.reference:
                # Reference always comes first, as it is manually set for a
                # reason.
                iref = invoice.reference.upper()
                if iref in ref or iref in msg:
                    return True
            if invoice.type.startswith('in_'):
                # Internal numbering, no likely match on number
                if invoice.name:
                    iname = invoice.name.upper()
                    if iname in ref or iname in msg:
                        return True
            elif invoice.type.startswith('out_'):
                # External id's possible and likely
                inum = invoice.number.upper()
                if inum in ref or inum in msg:
                    return True

            return False

        def _cached(move_line):
            '''Check if the move_line has been cached'''
            return move_line.id in linked_invoices

        def _cache(move_line, remaining=0.0):
            '''Cache the move_line'''
            linked_invoices[move_line.id] = remaining

        def _remaining(move_line):
            '''Return the remaining amount for a previously matched move_line
            '''
            return linked_invoices[move_line.id]

        def _sign(invoice):
            '''Return the direction of an invoice'''
            return {'in_invoice': -1, 
                    'in_refund': 1,
                    'out_invoice': 1,
                    'out_refund': -1
                   }[invoice.type]

        digits = dp.get_precision('Account')(cursor)[1]
        partial = False

        # Search invoice on partner
        if partner_ids:
            candidates = [x for x in move_lines
                          if x.partner_id.id in partner_ids and
                          str2date(x.date, '%Y-%m-%d') <= (trans.execution_date + payment_window)
                          and (not _cached(x) or _remaining(x))
                          ]
        else:
            candidates = []

        # Next on reference/invoice number. Mind that this uses the invoice
        # itself, as the move_line references have been fiddled with on invoice
        # creation. This also enables us to search for the invoice number in the
        # reference instead of the other way around, as most human interventions
        # *add* text.
        if len(candidates) > 1 or not candidates:
            ref = trans.reference.upper()
            msg = trans.message.upper()
            # The manual usage of the sales journal creates moves that
            # are not tied to invoices. Thanks to Stefan Rijnhart for
            # reporting this.
            candidates = [x for x in candidates or move_lines 
                          if x.invoice and has_id_match(x.invoice, ref, msg)
                              and str2date(x.invoice.date_invoice, '%Y-%m-%d')
                                <= (trans.execution_date + payment_window)
                              and (not _cached(x) or _remaining(x))
                         ]

        # Match on amount expected. Limit this kind of search to known
        # partners.
        if not candidates and partner_ids:
            candidates = [x for x in move_lines 
                          if round(abs(x.credit or x.debit), digits) == 
                                round(abs(trans.transferred_amount), digits)
                              and str2date(x.date, '%Y-%m-%d') <=
                                (trans.execution_date + payment_window)
                              and (not _cached(x) or _remaining(x))
                         ]

        move_line = False
        if candidates and len(candidates) > 0:
            # Now a possible selection of invoices has been found, check the
            # amounts expected and received.
            #
            # TODO: currency coercing
            best = [x for x in candidates
                    if round(abs(x.credit or x.debit), digits) == 
                          round(abs(trans.transferred_amount), digits)
                        and str2date(x.date, '%Y-%m-%d') <=
                          (trans.execution_date + payment_window)
                   ]
            if len(best) == 1:
                # Exact match
                move_line = best[0]
                invoice = move_line.invoice
                if _cached(move_line):
                    partial = True
                    expected = _remaining(move_line)
                else:
                    _cache(move_line)

            elif len(candidates) > 1:
                # Before giving up, check cache for catching duplicate
                # transfers first
                paid = [x for x in move_lines 
                        if x.invoice and has_id_match(x.invoice, ref, msg)
                            and str2date(x.invoice.date_invoice, '%Y-%m-%d')
                                <= trans.execution_date
                            and (_cached(x) and not _remaining(x))
                       ]
                if paid:
                    log.append(
                        _('Unable to link transaction id %(trans)s '
                          '(ref: %(ref)s) to invoice: '
                          'invoice %(invoice)s was already paid') % {
                              'trans': '%s.%s' % (trans.statement_id, trans.id),
                              'ref': trans.reference,
                              'invoice': eyecatcher(paid[0].invoice)
                          })
                else:
                    # Multiple matches
                    log.append(
                        _('Unable to link transaction id %(trans)s (ref: %(ref)s) to invoice: '
                          '%(no_candidates)s candidates found; can\'t choose.') % {
                              'trans': '%s.%s' % (trans.statement_id, trans.id),
                              'ref': trans.reference,
                              'no_candidates': len(best) or len(candidates)
                          })
                    log.append('    ' +
                        _('Candidates: %(candidates)s') % {
                              'candidates': ', '.join([x.invoice.number
                                                       for x in best or candidates
                                                      ])
                          })
                move_line = False
                partial = False

            elif len(candidates) == 1:
                # Mismatch in amounts
                move_line = candidates[0]
                invoice = move_line.invoice
                expected = round(_sign(invoice) * invoice.residual, digits)
                partial = True

            trans2 = None
            if move_line and partial:
                found = round(trans.transferred_amount, digits)
                if abs(expected) == abs(found):
                    partial = False
                    # Last partial payment will not flag invoice paid without
                    # manual assistence
                    invoice_obj = self.pool.get('account.invoice')
                    invoice_obj.write(cursor, uid, [invoice.id], {
                        'state': 'paid'
                    })
                elif abs(expected) > abs(found):
                    # Partial payment, reuse invoice
                    _cache(move_line, expected - found)
                elif abs(expected) < abs(found):
                    # Possible combined payments, need to split transaction to
                    # verify
                    _cache(move_line)
                    trans2 = trans.copy()
                    trans2.transferred_amount -= expected
                    trans.transferred_amount = expected
                    trans.id += 'a'
                    trans2.id += 'b'
                    # NOTE: the following is debatable. By copying the
                    # eyecatcher of the invoice itself, we enhance the
                    # tracability of the invoices, but we degrade the
                    # tracability of the bank transactions. When debugging, it
                    # is wise to disable this line.
                    trans.reference = eyecatcher(move_line.invoice)

        if move_line:
            account_ids = [
                x.id for x in bank_account_ids 
                if x.partner_id.id == move_line.partner_id.id
            ]

            return (
                self._get_move_info(cursor, uid, move_line, 
                    account_ids and account_ids[0] or False,
                    partial=(partial and not trans2)
                    ),
                trans2
            )


        return (False, False)
class account_analytic_account(orm.Model):

    _inherit = 'account.analytic.account'

    def _wip_report_fy(self, cr, uid, ids, fields, arg, context=None):
        res = self._wip_report(cr, uid, ids, fields, arg, context)
        if context is None:
            context = {}

        for account in self.browse(cr, uid, ids, context=context):
            all_ids = self.get_child_accounts(cr,
                                              uid, [account.id],
                                              context=context).keys()

            res[account.id].update({
                'fy_billings': 0,
                'fy_costs': 0,
                'fy_gross_profit': 0,
                'fy_actual_costs': 0,
                'fy_actual_material_cost': 0,
                'fy_actual_labor_cost': 0,
            })

            query_params = [tuple(all_ids)]
            where_date = ''

            if context.get('from_date_fy', False):
                fromdate = context.get('from_date_fy')
            else:
                raise orm.except_orm(
                    _('Error'),
                    _('The start date for the fiscal year has'
                      ' not been provided.'))
            if context.get('from_date_fy', False):
                todate = context.get('to_date_fy')
            else:
                raise orm.except_orm(
                    _('Error'),
                    _('The end date form the fiscal year has'
                      ' not been provided.'))

            where_date += " AND l.date >= %s"
            query_params += [fromdate]

            where_date += " AND l.date <= %s"
            query_params += [todate]

            # Actual billings for the fiscal year
            cr.execute(
                """SELECT amount, L.id
                FROM account_analytic_line L
                INNER JOIN account_account AC
                ON L.general_account_id = AC.id
                INNER JOIN account_account_type AT
                ON AT.id = AC.user_type
                WHERE AT.report_type = 'income'
                AND L.account_id IN %s
                """ + where_date + """
                """, query_params)
            res[account.id]['fy_billings_line_ids'] = []
            for (val, line_id) in cr.fetchall():
                res[account.id]['fy_billings'] += val
                res[account.id]['fy_billings_line_ids'].append(line_id)

            # Actual costs for the fiscal year
            cr.execute(
                """SELECT COALESCE(-1*sum(amount),0.0)
                FROM account_analytic_line L
                INNER JOIN account_account AC
                ON L.general_account_id = AC.id
                INNER JOIN account_account_type AT
                ON AT.id = AC.user_type
                WHERE AT.report_type = 'expense'
                AND L.account_id IN %s
                """ + where_date + """
                """, query_params)
            val = cr.fetchone()[0] or 0
            res[account.id]['fy_costs'] = val

            # Revenue (add the under over)
            res[account.id]['fy_revenue'] = res[account.id][
                'fy_billings'] + res[account.id]['under_billings'] - res[
                    account.id]['over_billings']
            # Gross margin
            res[account.id]['fy_gross_profit'] = \
                res[account.id]['fy_revenue'] - res[account.id]['fy_costs']

            # Actual costs to date
            cr.execute(
                """
                SELECT amount, L.id, AAJ.cost_type
                                FROM account_analytic_line L
                                INNER JOIN account_analytic_journal AAJ
                                ON AAJ.id = L.journal_id
                                INNER JOIN account_account AC
                                ON L.general_account_id = AC.id
                                INNER JOIN account_account_type AT
                                ON AT.id = AC.user_type
                                WHERE AT.report_type = 'expense'
                                AND L.account_id in %s
                """ + where_date + """
                """, query_params)
            res[account.id]['fy_actual_costs'] = 0
            res[account.id]['fy_actual_cost_line_ids'] = []
            res[account.id]['fy_actual_material_line_ids'] = []
            res[account.id]['fy_actual_labor_line_ids'] = []
            for (total, line_id, cost_type) in cr.fetchall():
                if cost_type in ('material', 'revenue'):
                    res[account.id]['fy_actual_material_cost'] -= total
                    res[account.id]['fy_actual_material_line_ids'].append(
                        line_id)
                elif cost_type == 'labor':
                    res[account.id]['fy_actual_labor_cost'] -= total
                    res[account.id]['fy_actual_labor_line_ids'].append(line_id)
                res[account.id]['fy_actual_costs'] -= total
                res[account.id]['fy_actual_cost_line_ids'].append(line_id)

        return res

    _columns = {
        'fy_revenue':
        fields.function(
            _wip_report_fy,
            method=True,
            type='float',
            string='Fiscal Year Revenue',
            multi='wip_report_fy',
            help="""Revenue for the provided Fiscal Year. This calculated
             by adding the billings for the fiscal year and the under/over 
             billed for the contract. Thus, it will include the billings in 
             excess of cost (under billed) and the costs in excess 
             of billings (over billed).""",
            digits_compute=dp.get_precision('Account')),
        'fy_billings':
        fields.function(_wip_report_fy,
                        method=True,
                        type='float',
                        string='Fiscal Year Billings',
                        multi='wip_report_fy',
                        help="Billings for the provided Fiscal Year",
                        digits_compute=dp.get_precision('Account')),
        'fy_costs':
        fields.function(_wip_report_fy,
                        method=True,
                        type='float',
                        string='Fiscal Year Costs',
                        multi='wip_report_fy',
                        help="Costs for the provided Fiscal Year",
                        digits_compute=dp.get_precision('Account')),
        'fy_gross_profit':
        fields.function(_wip_report_fy,
                        method=True,
                        type='float',
                        string='Fiscal Year Gross Profit',
                        multi='wip_report_fy',
                        digits_compute=dp.get_precision('Account')),
        'fy_actual_costs':
        fields.function(_wip_report_fy,
                        method=True,
                        type='float',
                        string='Fiscal Year Actual Costs',
                        multi='wip_report_fy',
                        digits_compute=dp.get_precision('Account')),
        'fy_actual_material_cost':
        fields.function(_wip_report_fy,
                        method=True,
                        type='float',
                        string='Fiscal Year Material Costs',
                        multi='wip_report_fy',
                        digits_compute=dp.get_precision('Account')),
        'fy_actual_labor_cost':
        fields.function(_wip_report_fy,
                        method=True,
                        type='float',
                        string='Fiscal Year Labor Costs',
                        multi='wip_report_fy',
                        digits_compute=dp.get_precision('Account')),
        'fy_actual_cost_line_ids':
        fields.function(_wip_report_fy,
                        method=True,
                        type='many2many',
                        relation="account.analytic.line",
                        string="Detail",
                        multi='wip_report'),
        'fy_actual_labor_line_ids':
        fields.function(_wip_report_fy,
                        method=True,
                        type='many2many',
                        relation="account.analytic.line",
                        string="Detail",
                        multi='wip_report'),
        'fy_actual_material_line_ids':
        fields.function(_wip_report_fy,
                        method=True,
                        type='many2many',
                        relation="account.analytic.line",
                        string="Detail",
                        multi='wip_report'),
        'fy_billings_line_ids':
        fields.function(_wip_report_fy,
                        method=True,
                        type='many2many',
                        relation="account.analytic.line",
                        string="Detail",
                        multi='wip_report'),
    }

    def action_open_fy_cost_lines(self, cr, uid, ids, context=None):
        """
        :return dict: dictionary value for created view
        """
        if context is None:
            context = {}
        line = self.browse(cr, uid, ids[0], context)
        bill_lines = [x.id for x in line.fy_actual_cost_line_ids]
        res = self.pool.get('ir.actions.act_window').for_xml_id(
            cr, uid, 'account', 'action_account_tree1', context)
        res['domain'] = "[('id', 'in', [" + ','.join(map(str,
                                                         bill_lines)) + "])]"
        return res

    def action_open_fy_material_lines(self, cr, uid, ids, context=None):
        """
        :return dict: dictionary value for created view
        """
        if context is None:
            context = {}
        line = self.browse(cr, uid, ids[0], context)
        bill_lines = [x.id for x in line.fy_actual_material_line_ids]
        res = self.pool.get('ir.actions.act_window').for_xml_id(
            cr, uid, 'account', 'action_account_tree1', context)
        res['domain'] = "[('id', 'in', [" + ','.join(map(str,
                                                         bill_lines)) + "])]"
        return res

    def action_open_fy_labor_lines(self, cr, uid, ids, context=None):
        """
        :return dict: dictionary value for created view
        """
        if context is None:
            context = {}
        line = self.browse(cr, uid, ids[0], context)
        bill_lines = [x.id for x in line.fy_actual_labor_line_ids]
        res = self.pool.get('ir.actions.act_window').for_xml_id(
            cr, uid, 'account', 'action_account_tree1', context)
        res['domain'] = "[('id', 'in', [" + ','.join(map(str,
                                                         bill_lines)) + "])]"
        return res

    def action_open_fy_billings_lines(self, cr, uid, ids, context=None):
        """
        :return dict: dictionary value for created view
        """
        if context is None:
            context = {}
        line = self.browse(cr, uid, ids[0], context)
        bill_lines = [x.id for x in line.fy_billings_line_ids]
        res = self.pool.get('ir.actions.act_window').for_xml_id(
            cr, uid, 'account', 'action_account_tree1', context)
        res['domain'] = "[('id', 'in', [" + ','.join(map(str,
                                                         bill_lines)) + "])]"
        return res
Example #44
0
class tcv_bank_deposit_line(osv.osv):

    _name = 'tcv.bank.deposit.line'

    _description = ''

    _rec_name = 'move_line'

    _columns = {
        'line_id':
        fields.many2one('tcv.bank.deposit',
                        'Deposit lines',
                        required=True,
                        ondelete='cascade'),
        'origin':
        fields.many2one('tcv.bank.config.detail',
                        'Origin',
                        required=True,
                        ondelete='restrict'),
        'rel_journal':
        fields.related('origin',
                       'journal_id',
                       type='many2one',
                       relation='account.journal',
                       string='Journal name',
                       store=False,
                       readonly=True),
        'rel_forced':
        fields.related('origin',
                       'force_detail',
                       type='boolean',
                       string='Forced',
                       store=False,
                       readonly=True),
        'rel_comission':
        fields.related('origin',
                       'bank_comission',
                       type='float',
                       string='Comission',
                       store=False,
                       readonly=True),
        'rel_prepaid_tax':
        fields.related('origin',
                       'prepaid_tax',
                       type='float',
                       string='Comission',
                       store=False,
                       readonly=True),
        'move_line':
        fields.many2one('account.move.line',
                        'Move',
                        ondelete='restrict',
                        domain="[('journal_id', '=', rel_journal), " +
                        "('debit','>', 0), ('reconcile_id', '=', 0)]"),
        'partner_id':
        fields.related('move_line',
                       'partner_id',
                       type='many2one',
                       relation='res.partner',
                       string='Partner',
                       store=False,
                       readonly=True),
        'amount_move':
        fields.related('move_line',
                       'debit',
                       type='float',
                       string='Move amount',
                       store=False),
        'amount':
        fields.float('Amount', digits_compute=dp.get_precision('Account')),
        'dep_date':
        fields.related('line_id',
                       'date',
                       string='Deposit date',
                       readonly=True,
                       type='date'),
    }

    _defaults = {}

    def name_get(self, cr, uid, ids, context=None):
        if not ids:
            return []
        so_brw = self.browse(cr, uid, ids, context={})
        res = []
        for record in so_brw:
            name = '%s: %s - %s' % (record.origin.name, record.move_line.ref,
                                    record.partner_id.name)
            res.append((record.id, name))
        return res

    def on_change_move_line(self, cr, uid, ids, move_line):
        res = {'value': {'amount_view': 0.0}}
        if move_line:
            move = self.pool.get('account.move.line').browse(cr,
                                                             uid,
                                                             move_line,
                                                             context=None)
            res = {
                'value': {
                    'amount_move': move.debit,
                    'amount': move.debit,
                    'partner_id': move.partner_id.id
                }
            }
        return res

    def on_change_origin(self, cr, uid, ids, origin):
        res = {}
        if origin:
            org = self.pool.get('tcv.bank.config.detail').browse(cr,
                                                                 uid,
                                                                 origin,
                                                                 context=None)
            res = {
                'value': {
                    'rel_journal': org.journal_id.id,
                    'rel_forced': org.force_detail,
                    'rel_comission': org.bank_comission,
                    'rel_prepaid_tax': org.prepaid_tax
                }
            }
        return res

    def create(self, cr, uid, vals, context=None):
        if 'amount' not in vals and 'amount_move' in vals:
            vals.update({'amount': vals['amount_move']})
        return super(tcv_bank_deposit_line,
                     self).create(cr, uid, vals, context)
Example #45
0
    def _link_costs(self, cursor, uid, trans, period_id, account_info, log):
        '''
        Get or create a costs invoice for the bank and return it with
        the payment as seen in the transaction (when not already done).
        '''
        if not account_info.costs_account_id:
            return []

        digits = dp.get_precision('Account')(cursor)[1]
        amount = round(abs(trans.transferred_amount), digits)
        # Make sure to be able to pinpoint our costs invoice for later
        # matching
        reference = '%s.%s: %s' % (trans.statement_id, trans.id, trans.reference)

        # search supplier invoice
        invoice_obj = self.pool.get('account.invoice')
        invoice_ids = invoice_obj.search(cursor, uid, [
            '&',
            ('type', '=', 'in_invoice'),
            ('partner_id', '=', account_info.bank_partner_id.id),
            ('company_id', '=', account_info.company_id.id),
            ('date_invoice', '=', date2str(trans.effective_date)),
            ('reference', '=', reference),
            ('amount_total', '=', amount),
            ]
        )
        if invoice_ids and len(invoice_ids) == 1:
            invoice = invoice_obj.browse(cursor, uid, invoice_ids)[0]
        elif not invoice_ids:
            # create supplier invoice
            partner_obj = self.pool.get('res.partner')
            invoice_lines = [(0,0,dict(
                amount = 1,
                price_unit = amount,
                name = trans.message or trans.reference,
                account_id = account_info.costs_account_id.id
            ))]
            invoice_address_id = partner_obj.address_get(
                cursor, uid, [account_info.bank_partner_id.id], ['invoice']
            )
            invoice_id = invoice_obj.create(cursor, uid, dict(
                type = 'in_invoice',
                company_id = account_info.company_id.id,
                partner_id = account_info.bank_partner_id.id,
                address_invoice_id = invoice_address_id['invoice'],
                period_id = period_id,
                journal_id = account_info.invoice_journal_id.id,
                account_id = account_info.bank_partner_id.property_account_payable.id,
                date_invoice = date2str(trans.effective_date),
                reference_type = 'none',
                reference = reference,
                name = trans.reference or trans.message,
                check_total = amount,
                invoice_line = invoice_lines,
            ))
            invoice = invoice_obj.browse(cursor, uid, invoice_id)
            # Create workflow
            invoice_obj.button_compute(cursor, uid, [invoice_id], 
                                       {'type': 'in_invoice'}, set_total=True)
            wf_service = netsvc.LocalService('workflow')
            # Move to state 'open'
            wf_service.trg_validate(uid, 'account.invoice', invoice.id,
                                    'invoice_open', cursor)

        # return move_lines to mix with the rest
        return [x for x in invoice.move_id.line_id if x.account_id.reconcile]
class sale_advance_payment_inv(osv.osv_memory):
    _name = "sale.advance.payment.inv"
    _description = "Sales Advance Payment Invoice"

    _columns = {
        'advance_payment_method':fields.selection(
            [('all', 'Invoice all the Sale Order'), ('percentage','Percentage'), ('fixed','Fixed Price'),
                ('lines', 'Some Order Lines')],
            'Type', required=True,
            help="""Use All to create the final invoice.
                Use Percentage to invoice a percentage of the total amount.
                Use Fixed Price to invoice a specific amound in advance.
                Use Some Order Lines to invoice a selection of the sale order lines."""),
        'qtty': fields.float('Quantity', digits=(16, 2), required=True),
        'product_id': fields.many2one('product.product', 'Advance Product',
            help="""Select a product of type service which is called 'Advance Product'.
                You may have to create it and set it as a default value on this field."""),
        'amount': fields.float('Advance Amount', digits_compute= dp.get_precision('Sale Price'),
            help="The amount to be invoiced in advance."),
    }

    def _get_advance_product(self, cr, uid, context=None):
        try:
            product = self.pool.get('ir.model.data').get_object(cr, uid, 'sale', 'advance_product_0')
        except ValueError:
            # a ValueError is returned if the xml id given is not found in the table ir_model_data
            return False
        return product.id

    _defaults = {
        'advance_payment_method': 'all',
        'qtty': 1.0,
        'product_id': _get_advance_product,
    }

    def onchange_method(self, cr, uid, ids, advance_payment_method, product_id, context=None):
        if advance_payment_method == 'percentage':
            return {'value': {'amount':0, 'product_id':False }}
        if product_id:
            product = self.pool.get('product.product').browse(cr, uid, product_id, context=context)
            return {'value': {'amount': product.list_price}}
        return {'value': {'amount': 0}}

    def create_invoices(self, cr, uid, ids, context=None):
        """ create invoices for the active sale orders """
        if context is None:
            context = {}
        wizard = self.browse(cr, uid, ids[0], context)
        sale_ids = context.get('active_ids', [])

        if wizard.advance_payment_method == 'all':
            # create the final invoices of the active sale orders
            res = self.pool.get('sale.order').manual_invoice(cr, uid, sale_ids, context)
            if context.get('open_invoices', False):
                return res
            return {'type': 'ir.actions.act_window_close'}

        if wizard.advance_payment_method == 'lines':
            # open the list view of sale order lines to invoice
            act_window = self.pool.get('ir.actions.act_window')
            res = act_window.for_xml_id(cr, uid, 'sale', 'action_order_line_tree2', context)
            res['context'] = {
                'search_default_uninvoiced': 1,
                'search_default_order_id': sale_ids and sale_ids[0] or False,
            }
            return res

        assert wizard.advance_payment_method in ('fixed', 'percentage')

        sale_obj = self.pool.get('sale.order')
        inv_obj = self.pool.get('account.invoice')
        inv_line_obj = self.pool.get('account.invoice.line')
        inv_ids = []

        for sale in sale_obj.browse(cr, uid, sale_ids, context=context):
            if sale.order_policy == 'postpaid':
                raise osv.except_osv(
                    _('Error'),
                    _("You cannot make an advance on a sales order \
                         that is defined as 'Automatic Invoice after delivery'."))

            val = inv_line_obj.product_id_change(cr, uid, [], wizard.product_id.id,
                    uom=False, partner_id=sale.partner_id.id, fposition_id=sale.fiscal_position.id)
            res = val['value']

            # determine and check income account
            if not wizard.product_id.id :
                prop = self.pool.get('ir.property').get(cr, uid,
                            'property_account_income_categ', 'product.category', context=context)
                prop_id = prop and prop.id or False
                account_id = self.pool.get('account.fiscal.position').map_account(cr, uid, sale.fiscal_position.id or False, prop_id)
                if not account_id:
                    raise osv.except_osv(_('Configuration Error !'),
                            _('There is no income account defined as global property.'))
                res['account_id'] = account_id
            if not res.get('account_id'):
                raise osv.except_osv(_('Configuration Error !'),
                        _('There is no income account defined for this product: "%s" (id:%d)') % \
                            (wizard.product_id.name, wizard.product_id.id,))

            # determine invoice amount
            if wizard.amount <= 0.00:
                raise osv.except_osv(_('Incorrect Data'),
                    _('The value of Advance Amount must be positive.'))
            if wizard.advance_payment_method == 'percentage':
                inv_amount = sale.amount_total * wizard.amount / 100
                if not res.get('name'):
                    res['name'] = _("Advance of %s %%") % (wizard.amount)
            else:
                inv_amount = wizard.amount
                if not res.get('name'):
                    #TODO: should find a way to call formatLang() from rml_parse
                    symbol = sale.pricelist_id.currency_id.symbol
                    if sale.pricelist_id.currency_id.position == 'after':
                        res['name'] = _("Advance of %s %s") % (inv_amount, symbol)
                    else:
                        res['name'] = _("Advance of %s %s") % (symbol, inv_amount)

            # determine taxes
            if res.get('invoice_line_tax_id'):
                res['invoice_line_tax_id'] = [(6, 0, res.get('invoice_line_tax_id'))]
            else:
                res['invoice_line_tax_id'] = False

            # create the invoice
            inv_line_values = {
                'name': res.get('name'),
                'account_id': res['account_id'],
                'price_unit': inv_amount,
                'quantity': wizard.qtty or 1.0,
                'discount': False,
                'uos_id': res.get('uos_id', False),
                'product_id': wizard.product_id.id,
                'invoice_line_tax_id': res.get('invoice_line_tax_id'),
                'account_analytic_id': sale.project_id.id or False,
            }
            inv_values = {
                'name': sale.client_order_ref or sale.name,
                'origin': sale.name,
                'type': 'out_invoice',
                'reference': False,
                'account_id': sale.partner_id.property_account_receivable.id,
                'partner_id': sale.partner_id.id,
                'invoice_line': [(0, 0, inv_line_values)],
                'currency_id': sale.pricelist_id.currency_id.id,
                'comment': '',
                'payment_term': sale.payment_term.id,
                'fiscal_position': sale.fiscal_position.id or sale.partner_id.property_account_position.id
            }
            inv_id = inv_obj.create(cr, uid, inv_values, context=context)
            inv_obj.button_reset_taxes(cr, uid, [inv_id], context=context)
            inv_ids.append(inv_id)

            # add the invoice to the sale order's invoices
            sale.write({'invoice_ids': [(4, inv_id)]})

            # If invoice on picking: add the cost on the SO
            # If not, the advance will be deduced when generating the final invoice
            if sale.order_policy == 'picking':
                vals = {
                    'order_id': sale.id,
                    'name': res.get('name'),
                    'price_unit': -inv_amount,
                    'product_uom_qty': wizard.qtty or 1.0,
                    'product_uos_qty': wizard.qtty or 1.0,
                    'product_uos': res.get('uos_id', False),
                    'product_uom': res.get('uom_id', False),
                    'product_id': wizard.product_id.id or False,
                    'discount': False,
                    'tax_id': res.get('invoice_line_tax_id'),
                }
                self.pool.get('sale.order.line').create(cr, uid, vals, context=context)

        if context.get('open_invoices', False):
            return self.open_invoices( cr, uid, ids, inv_ids, context=context)
        return {'type': 'ir.actions.act_window_close'}

    def open_invoices(self, cr, uid, ids, invoice_ids, context=None):
        """ open a view on one of the given invoice_ids """
        ir_model_data = self.pool.get('ir.model.data')
        form_res = ir_model_data.get_object_reference(cr, uid, 'account', 'invoice_form')
        form_id = form_res and form_res[1] or False
        tree_res = ir_model_data.get_object_reference(cr, uid, 'account', 'invoice_tree')
        tree_id = tree_res and tree_res[1] or False

        return {
            'name': _('Advance Invoice'),
            'view_type': 'form',
            'view_mode': 'form,tree',
            'res_model': 'account.invoice',
            'res_id': invoice_ids[0],
            'view_id': False,
            'views': [(form_id, 'form'), (tree_id, 'tree')],
            'context': "{'type': 'out_invoice'}",
            'type': 'ir.actions.act_window',
        }
Example #47
0
class tcv_bank_deposit(osv.osv):

    _name = 'tcv.bank.deposit'

    _description = 'Modulo de gestion de planillas de depositos bancarios'

    _order = 'date,ref desc'

    STATE_SELECTION = [('draft', 'Draft'), ('posted', 'Posted'),
                       ('cancel', 'Cancelled')]

    def copy(self,
             cr,
             uid,
             id,
             default={},
             context=None,
             done_list=[],
             local=False):
        item = self.browse(cr, uid, id, context=context)
        default = default or {}
        default = default.copy()
        default.update({
            'name': (item.name or '') + '(copy)',
            'ref': '/',
            'narration': '',
            'state': 'draft',
            'move_id': False,
        })
        return super(tcv_bank_deposit, self).copy(cr,
                                                  uid,
                                                  id,
                                                  default,
                                                  context=context)

    def _compute_comission(self, cr, uid, line, comission):
        total = (line.amount * comission) / 100
        res = round(
            total,
            self.pool.get('decimal.precision').precision_get(
                cr, uid, 'Account'))
        return res

    def _total_deposit_all(self, cr, uid, ids, field_name, arg, context=None):
        res = {}
        for dep in self.browse(cr, uid, ids, context=context):
            res[dep.id] = {
                'cash_total': 0.0,
                'cheq_total': 0.0,
                'debit_total': 0.0,
                'comission_total': 0.0,
                'prepaid_total': 0.0,
                'amount_total': 0.0,
            }
            for line in dep.line_ids:
                if line.origin.type == 'cash':
                    res[dep.id]['cash_total'] += line.amount
                elif line.origin.type == 'cheq':
                    res[dep.id]['cheq_total'] += line.amount
                elif line.origin.type == 'debit':
                    res[dep.id]['debit_total'] += line.amount
                    res[dep.id]['comission_total'] += self._compute_comission(
                        cr, uid, line, line.rel_comission)
                    res[dep.id]['prepaid_total'] += self._compute_comission(
                        cr, uid, line, line.rel_prepaid_tax)
            if res[dep.id]['comission_total']:
                res[dep.id]['comission_total'] += dep.comission_dif
            res[dep.id]['amount_total'] = res[dep.id]['cash_total'] + \
                res[dep.id]['cheq_total'] + res[dep.id]['debit_total'] - \
                res[dep.id]['comission_total'] - res[dep.id]['prepaid_total']
        return res

    def _get_account_balance(self, cr, uid, account_id, operator, date_balance,
                             context):
        cr.execute('''
            select sum(debit-credit) as balance_in_currency
            FROM account_move_line l
            left join account_move m on l.move_id = m.id
            WHERE l.account_id = %s AND
                  l.date %s '%s' AND
                  m.state = 'posted'
            ''' % (account_id, operator, date_balance))
        return cr.dictfetchone()['balance_in_currency'] or 0

    _columns = {
        'ref':
        fields.char('Reference', size=32, readonly=True),
        'name':
        fields.char('Document number',
                    size=32,
                    readonly=True,
                    states={'draft': [('readonly', False)]}),
        'bank_journal_id':
        fields.many2one('account.journal',
                        'Bank journal',
                        required=True,
                        readonly=True,
                        states={'draft': [('readonly', False)]},
                        ondelete='restrict'),
        'date':
        fields.date('Date',
                    required=True,
                    readonly=True,
                    states={'draft': [('readonly', False)]},
                    select=True),
        'company_id':
        fields.many2one('res.company',
                        'Company',
                        required=True,
                        readonly=True,
                        ondelete='restrict'),
        'currency_id':
        fields.many2one('res.currency',
                        'Currency',
                        required=True,
                        readonly=True,
                        ondelete='restrict',
                        states={'draft': [('readonly', False)]}),
        'move_id':
        fields.many2one('account.move',
                        'Account move',
                        ondelete='restrict',
                        help="The move of this entry line.",
                        select=2,
                        readonly=True),
        'state':
        fields.selection(STATE_SELECTION,
                         string='State',
                         required=True,
                         readonly=True),
        'check_total':
        fields.float('Total',
                     digits_compute=dp.get_precision('Account'),
                     readonly=True,
                     states={'draft': [('readonly', False)]}),
        'comission_dif':
        fields.float('Comission dif. (±1)',
                     digits_compute=dp.get_precision('Account'),
                     readonly=True,
                     states={'draft': [('readonly', False)]},
                     help="You can set here a small diference in calculated " +
                     "comission ammount."),
        'line_ids':
        fields.one2many('tcv.bank.deposit.line',
                        'line_id',
                        'Details',
                        readonly=True,
                        states={'draft': [('readonly', False)]},
                        ondelete='cascade'),
        'cash_total':
        fields.function(_total_deposit_all,
                        method=True,
                        digits_compute=dp.get_precision('Account'),
                        string='Cash total (+)',
                        store=False,
                        multi='all'),
        'cheq_total':
        fields.function(_total_deposit_all,
                        method=True,
                        digits_compute=dp.get_precision('Account'),
                        string='Cheq total (+)',
                        store=False,
                        multi='all'),
        'debit_total':
        fields.function(_total_deposit_all,
                        method=True,
                        digits_compute=dp.get_precision('Account'),
                        string='Debit/credit total (+)',
                        store=False,
                        multi='all'),
        'comission_total':
        fields.function(_total_deposit_all,
                        method=True,
                        digits_compute=dp.get_precision('Account'),
                        string='Comission total (-)',
                        store=False,
                        multi='all'),
        'prepaid_total':
        fields.function(_total_deposit_all,
                        method=True,
                        digits_compute=dp.get_precision('Account'),
                        string='Prepaid tax total (-)',
                        store=False,
                        multi='all'),
        'amount_total':
        fields.function(_total_deposit_all,
                        method=True,
                        digits_compute=dp.get_precision('Account'),
                        string='General total (=)',
                        store=False,
                        multi='all'),
        'narration':
        fields.text('Notes', readonly=False),
    }

    _defaults = {
        'ref':
        lambda *a: '/',
        'name':
        lambda *a: '',
        'check_total':
        lambda *a: 0.0,
        'date':
        lambda *a: time.strftime('%Y-%m-%d'),
        'company_id':
        lambda self, cr, uid, c: self.pool.get('res.company').
        _company_default_get(cr, uid, self._name, context=c),
        'currency_id':
        lambda self, cr, uid, c: self.pool.get('res.users').browse(
            cr, uid, uid, c).company_id.currency_id.id,
        'state':
        'draft',
    }

    _sql_constraints = [
        ('deposit_name_uniq', 'UNIQUE(name, bank_journal_id)',
         'The reference must be unique for this bank journal!'),
        ('max_comission_dif', 'CHECK(comission_dif between -1 and 1)',
         'The maximum difference comsion must be in -1 to 1 range'),
    ]

    def compute_dif(self, cr, uid, ids, context=None):
        ids = isinstance(ids, (int, long)) and [ids] or ids
        for item in self.browse(cr, uid, ids, context={}):
            if item.check_total != item.amount_total:
                dif = item.amount_total - item.check_total + item.comission_dif
                if abs(dif) > 1:
                    raise osv.except_osv(_('Error!'), _(u'Computed dif > ±1'))
                self.write(cr,
                           uid, [item.id], {'comission_dif': dif},
                           context=context)
        return True

    def button_draft(self, cr, uid, ids, context=None):
        obj = self.pool.get('tcv.bank.deposit')
        vals = {'state': 'draft'}
        return obj.write(cr, uid, ids, vals, context)

    def button_posted(self, cr, uid, ids, context=None):
        context = context or {}
        if len(ids) != 1:
            raise osv.except_osv(_('Error!'),
                                 _('Multiplies validations not allowed.'))
        for item in self.browse(cr, uid, ids, context={}):
            if not item.ref or item.ref == '/':
                ref = self.pool.get('ir.sequence').get(cr, uid, 'bank.deposit')
            else:
                ref = item.ref
        context.update({'deposit_reference': ref})
        obj = self.pool.get('tcv.bank.deposit')
        vals = {
            'state': 'posted',
            'ref': ref,
            'move_id': self._gen_account_move(cr, uid, ids, context)
        }
        return obj.write(cr, uid, ids, vals, context)

    def button_cancel(self, cr, uid, ids, context=None):
        ids = isinstance(ids, (int, long)) and [ids] or ids
        res = {}
        for dep in self.browse(cr, uid, ids, context={}):
            if dep.state == 'posted':
                if dep.move_id.id:
                    obj_move = self.pool.get('account.move')
                    move = obj_move.browse(cr,
                                           uid,
                                           dep.move_id.id,
                                           context=None)
                    if move.state == 'draft':
                        recon_id = 0
                        for line in dep.line_ids:
                            if line.move_line and not recon_id and \
                                    line.move_line.reconcile_id.id:
                                recon_id = line.move_line.reconcile_id.id
                        if recon_id:
                            obj_lines = self.pool.get('account.move.line')
                            rec_ids = obj_lines.search(
                                cr, uid, [('reconcile_id', '=', recon_id)])
                            obj_lines._remove_move_reconcile(cr,
                                                             uid,
                                                             rec_ids,
                                                             context=None)
                        obj = self.pool.get('tcv.bank.deposit')
                        vals = {'state': 'cancel', 'move_id': 0}
                        res = obj.write(cr, uid, ids, vals, context)
                        obj_move.unlink(cr, uid, [move.id])
            elif dep.state == 'draft':
                obj = self.pool.get('tcv.bank.deposit')
                vals = {'state': 'cancel', 'move_id': 0}
                res = obj.write(cr, uid, ids, vals, context)
        return res

    def test_draft(self, cr, uid, ids, *args):
        return True

    def test_posted(self, cr, uid, ids, *args):
        so_brw = self.browse(cr, uid, ids, context={})
        for dep in so_brw:
            if time.strptime(dep.date, '%Y-%m-%d') > time.localtime():
                raise osv.except_osv(_('Invalid date!'),
                                     _('The date must be <= today.'))
            if not dep.amount_total:
                raise osv.except_osv(_('No valid amount!'),
                                     _('The total must be > 0'))
            if abs(dep.amount_total - dep.check_total) > 0.0001:
                raise osv.except_osv(
                    _('Bad total !'),
                    _('Please verify the lines of the document ! The real ' +
                      'total does not match the computed total.'))
            if not dep.name:
                raise osv.except_osv(_('Error!'),
                                     _('You must set a document number.'))
            #~ lines checks
            chk_origin = {'cash_cheq': 0}
            chk_cash = {}
            chk_cash_info = []
            for line in dep.line_ids:
                config = self.pool.get('tcv.bank.config.detail').browse(
                    cr, uid, line.origin.id, context=None)
                #~ Validar grupo de medios de pagos seleccionados
                if config.type in ('cash', 'cheq'):
                    chk_origin['cash_cheq'] += 1
                    if config.type == 'cash':
                        #~ Acumulate cash total in chk_cash
                        if line.origin.id not in chk_cash:
                            chk_cash.update({line.origin.id: 0})
                            chk_cash_info.append({
                                'cash_acc':
                                line.rel_journal.default_debit_account_id.id,
                                'code':
                                line.origin.id,
                                'acc_name':
                                line.rel_journal.default_debit_account_id.name
                            })
                        chk_cash[line.origin.id] += line.amount
                else:  # debit and credit
                    if line.origin.id not in chk_origin:
                        chk_origin.update({line.origin.id: 1})
                    else:
                        chk_origin[line.origin.id] += 1

                if not line.rel_journal.default_debit_account_id.id or \
                        not line.rel_journal.default_credit_account_id.id:
                    raise osv.except_osv(
                        _('Error!'),
                        _('You must set a debit and credit account for ' +
                          'journal: %s.') % (line.rel_journal.name))
                if config.type == 'debit' and \
                        dep.bank_journal_id.id != config.bank_journal_id.id:
                    raise osv.except_osv(
                        _('Error!'),
                        _('The bank journal differs from bank journals ' +
                          'payment method. You must be select: %s journal') %
                        (config.bank_journal_id.name))
            if not chk_origin['cash_cheq']:
                chk_origin.pop('cash_cheq')
            if len(chk_origin) != 1:
                raise osv.except_osv(
                    _('Error!'),
                    _('You can not mix different types of payments.'))
            #~ Check if cash account balance < cash in deposit
            for cash in chk_cash_info:
                balance = self._get_account_balance(cr,
                                                    uid,
                                                    cash['cash_acc'],
                                                    '<=',
                                                    dep.date,
                                                    context={})
                if chk_cash[cash['code']] > balance:
                    raise osv.except_osv(
                        _('Error!'),
                        _('You can not deposit more cash than is in the ' +
                          'account: %s: %.2f') % (cash['acc_name'], balance))
        return True

    def test_cancel(self, cr, uid, ids, *args):
        for dep in self.browse(cr, uid, ids, context={}):
            if dep.move_id and dep.move_id.state == 'posted':
                raise osv.except_osv(
                    _('Error!'),
                    _('You can not cancel a deposit while the account ' +
                      'move is posted.'))
        return True

    def button_calculate_click(self, cr, uid, ids, context=None):
        return True

    def _gen_account_move_line(self, company_id, partner_id, account_id, name,
                               debit, credit):
        return (0, 0, {
            'auto': True,
            'company_id': company_id,
            'partner_id': partner_id,
            'account_id': account_id,
            'name': name,
            'debit': round(debit, 2),
            'credit': round(credit, 2),
            'reconcile': False,
        })

    def _gen_account_move(self, cr, uid, ids, context=None):
        need_reconcile = False
        so_brw = self.browse(cr, uid, ids, context={})
        obj_move = self.pool.get('account.move')
        obj_per = self.pool.get('account.period')
        move_id = None
        for dep in so_brw:
            obj_cfg = self.pool.get('tcv.bank.config')
            cfg_id = obj_cfg.search(
                cr, uid, [('company_id', '=', dep.company_id.id)])[0]
            config = obj_cfg.browse(cr, uid, cfg_id, None)
            move = {
                'ref':
                '%s - Nro %s' %
                (context.get('deposit_reference', 'dp'), dep.name),
                'journal_id':
                dep.bank_journal_id.id,
                'date':
                dep.date,
                'period_id':
                obj_per.find(cr, uid, dep.date)[0],
                'company_id':
                dep.company_id.id,
                'state':
                'draft',
                'to_check':
                False,
                'narration':
                '',
            }
            lines = []
            for line in dep.line_ids:  # move line for deposit lines
                lines.append(
                    self._gen_account_move_line(
                        dep.company_id.id, line.partner_id.id,
                        line.rel_journal.default_credit_account_id.id,
                        line.move_line.name or line.rel_journal.name, 0,
                        line.amount))
                need_reconcile = need_reconcile or line.move_line.id
            if dep.comission_total:  # move line for comission
                lines.append(
                    self._gen_account_move_line(dep.company_id.id, False,
                                                config.acc_bank_comis.id,
                                                move['ref'],
                                                dep.comission_total, 0))
            if dep.prepaid_total:  # move line for prepaid tax
                lines.append(
                    self._gen_account_move_line(dep.company_id.id, False,
                                                config.acc_prepaid_tax.id,
                                                move['ref'], dep.prepaid_total,
                                                0))
            # move line for deposit's bank credit
            lines.append(
                self._gen_account_move_line(
                    dep.company_id.id, False,
                    dep.bank_journal_id.default_debit_account_id.id,
                    move['ref'], dep.check_total, 0))
            move.update({'line_id': lines})
            move_id = obj_move.create(cr, uid, move, context)
            obj_move.post(cr, uid, [move_id], context=context)
            if need_reconcile and move_id:
                self.do_reconcile(cr, uid, dep, move_id, context)
        return move_id

    def unlink(self, cr, uid, ids, context=None):
        so_brw = self.browse(cr, uid, ids, context={})
        unlink_ids = []
        for dep in so_brw:
            if dep.state in ('draft', 'cancel'):
                unlink_ids.append(dep['id'])
            else:
                raise osv.except_osv(
                    _('Invalid action !'),
                    _('Cannot delete deposit(s) that are already postedd!'))
        super(tcv_bank_deposit, self).unlink(cr, uid, unlink_ids, context)
        return True

    def do_reconcile(self, cr, uid, dep, move_id, context):
        obj_mov = self.pool.get('account.move')
        move = obj_mov.browse(cr, uid, move_id, context=context)
        rec_ids = []
        for line in dep.line_ids:
            if line.move_line.id:
                rec_ids.append(line.move_line.id)
            for move_line in move.line_id:
                if line.amount == move_line.credit and \
                        line.move_line.account_id.id == \
                        move_line.account_id.id:
                    if move_line.id not in rec_ids:
                        rec_ids.append(move_line.id)
        if rec_ids:
            obj_move_line = self.pool.get('account.move.line')
            obj_move_line.reconcile(cr, uid, rec_ids, context=context)
        return True
Example #48
0
class sale_order(osv.osv):
    _inherit = 'sale.order'

    def onchange_partner_id(self,
                            cr,
                            uid,
                            ids,
                            part,
                            shop_id=False,
                            fiscal_operation_category_id=False):
        result = super(sale_order,
                       self).onchange_partner_id(cr, uid, ids, part)
        result['value']['fiscal_position'] = False

        if not part or not shop_id:
            return {
                'value': {
                    'partner_invoice_id': False,
                    'partner_shipping_id': False,
                    'partner_order_id': False,
                    'payment_term': False,
                    'fiscal_position': False,
                    'fiscal_operation_id': False
                }
            }

        obj_partner = self.pool.get('res.partner').browse(cr, uid, part)
        fiscal_position = obj_partner.property_account_position.id
        partner_fiscal_type = obj_partner.partner_fiscal_type_id.id

        if fiscal_position:
            result['value']['fiscal_position'] = fiscal_position
            result['value'][
                'fiscal_operation_id'] = obj_partner.property_account_position.fiscal_operation_id.id
            return result

        obj_shop = self.pool.get('sale.shop').browse(cr, uid, shop_id)

        company_addr = self.pool.get('res.partner').address_get(
            cr, uid, [obj_shop.company_id.partner_id.id], ['default'])
        company_addr_default = self.pool.get('res.partner.address').browse(
            cr, uid, [company_addr['default']])[0]

        from_country = company_addr_default.country_id.id
        from_state = company_addr_default.state_id.id

        partner_addr_default = self.pool.get('res.partner.address').browse(
            cr, uid, [result['value']['partner_invoice_id']])[0]

        to_country = partner_addr_default.country_id.id
        to_state = partner_addr_default.state_id.id

        fsc_pos_id = self.pool.get('account.fiscal.position.rule').search(
            cr, uid, [('company_id', '=', obj_shop.company_id.id),
                      ('from_country', '=', from_country),
                      ('from_state', '=', from_state),
                      ('to_country', '=', to_country),
                      ('to_state', '=', to_state), ('use_sale', '=', True),
                      ('fiscal_operation_category_id', '=',
                       fiscal_operation_category_id),
                      ('partner_fiscal_type_id', '=', partner_fiscal_type)])
        if not fsc_pos_id:
            fsc_pos_id = self.pool.get('account.fiscal.position.rule').search(
                cr, uid, [('company_id', '=', obj_shop.company_id.id),
                          ('from_country', '=', from_country),
                          ('from_state', '=', from_state),
                          ('to_country', '=', to_country),
                          ('to_state', '=', to_state), ('use_sale', '=', True),
                          ('fiscal_operation_category_id', '=',
                           fiscal_operation_category_id)])

        if fsc_pos_id:
            obj_fpo_rule = self.pool.get(
                'account.fiscal.position.rule').browse(cr, uid, fsc_pos_id)[0]
            result['value'][
                'fiscal_position'] = obj_fpo_rule.fiscal_position_id.id
            result['value'][
                'fiscal_operation_id'] = obj_fpo_rule.fiscal_position_id.fiscal_operation_id.id

        return result

    def onchange_partner_invoice_id(self, cr, uid, ids, ptn_invoice_id, ptn_id,
                                    shop_id, fiscal_operation_category_id):
        result = super(sale_order, self).onchange_partner_invoice_id(
            cr, uid, ids, ptn_invoice_id, ptn_id, shop_id)
        result['value']['fiscal_position'] = False

        if not shop_id or not ptn_invoice_id or not ptn_id or not fiscal_operation_category_id:
            return result

        partner = self.pool.get('res.partner').browse(cr, uid, ptn_id)
        fiscal_position = partner.property_account_position.id or False
        partner_fiscal_type = partner.partner_fiscal_type_id.id

        if fiscal_position:
            result['value']['fiscal_position'] = fiscal_position
            result['value'][
                'fiscal_operation_id'] = obj_partner.property_account_position.fiscal_operation_id.id
            return result

        obj_shop = self.pool.get('sale.shop').browse(cr, uid, shop_id)

        company_addr = self.pool.get('res.partner').address_get(
            cr, uid, [obj_shop.company_id.partner_id.id], ['default'])
        company_addr_default = self.pool.get('res.partner.address').browse(
            cr, uid, [company_addr['default']])[0]

        from_country = company_addr_default.country_id.id
        from_state = company_addr_default.state_id.id

        partner_addr_invoice = self.pool.get('res.partner.address').browse(
            cr, uid, [ptn_invoice_id])[0]

        to_country = partner_addr_invoice.country_id.id
        to_state = partner_addr_invoice.state_id.id

        fsc_pos_id = self.pool.get('account.fiscal.position.rule').search(
            cr, uid, [('company_id', '=', obj_shop.company_id.id),
                      ('from_country', '=', from_country),
                      ('from_state', '=', from_state),
                      ('to_country', '=', to_country),
                      ('to_state', '=', to_state), ('use_sale', '=', True),
                      ('fiscal_operation_category_id', '=',
                       fiscal_operation_category_id),
                      ('partner_fiscal_type_id', '=', partner_fiscal_type)])
        if not fsc_pos_id:
            fsc_pos_id = self.pool.get('account.fiscal.position.rule').search(
                cr, uid, [('company_id', '=', obj_shop.company_id.id),
                          ('from_country', '=', from_country),
                          ('from_state', '=', from_state),
                          ('to_country', '=', to_country),
                          ('to_state', '=', to_state), ('use_sale', '=', True),
                          ('fiscal_operation_category_id', '=',
                           fiscal_operation_category_id)])

        if fsc_pos_id:
            obj_fpo_rule = self.pool.get(
                'account.fiscal.position.rule').browse(cr, uid, fsc_pos_id)[0]
            result['value'][
                'fiscal_position'] = obj_fpo_rule.fiscal_position_id.id
            result['value'][
                'fiscal_operation_id'] = obj_fpo_rule.fiscal_position_id.fiscal_operation_id.id

        return result

    def onchange_shop_id(self,
                         cr,
                         uid,
                         ids,
                         shop_id,
                         ptn_id=False,
                         ptn_invoice_id=False):
        result = super(sale_order,
                       self).onchange_shop_id(cr, uid, ids, shop_id, ptn_id)
        result['value']['fiscal_position'] = False
        result['value']['fiscal_operation_id'] = False

        if not shop_id:
            result['value']['fiscal_operation_category_id'] = False
            return result

        obj_shop = self.pool.get('sale.shop').browse(cr, uid, shop_id)
        fiscal_operation_category_id = obj_shop.default_fo_category_id.id
        result['value'][
            'fiscal_operation_category_id'] = fiscal_operation_category_id

        if not ptn_id or not ptn_invoice_id:
            return result

        obj_partner = self.pool.get('res.partner').browse(cr, uid, ptn_id)
        fiscal_position = obj_partner.property_account_position.id
        partner_fiscal_type = obj_partner.partner_fiscal_type_id.id

        if fiscal_position:
            result['value']['fiscal_position'] = fiscal_position
            result['value'][
                'fiscal_operation_id'] = obj_partner.property_account_position.fiscal_operation_id.id
            return result

        obj_shop = self.pool.get('sale.shop').browse(cr, uid, shop_id)

        company_addr = self.pool.get('res.partner').address_get(
            cr, uid, [obj_shop.company_id.partner_id.id], ['default'])
        company_addr_default = self.pool.get('res.partner.address').browse(
            cr, uid, [company_addr['default']])[0]

        from_country = company_addr_default.country_id.id
        from_state = company_addr_default.state_id.id

        partner_addr_default = self.pool.get('res.partner.address').browse(
            cr, uid, [ptn_invoice_id])[0]

        to_country = partner_addr_default.country_id.id
        to_state = partner_addr_default.state_id.id

        fsc_pos_id = self.pool.get('account.fiscal.position.rule').search(
            cr, uid, [('company_id', '=', obj_shop.company_id.id),
                      ('from_country', '=', from_country),
                      ('from_state', '=', from_state),
                      ('to_country', '=', to_country),
                      ('to_state', '=', to_state), ('use_sale', '=', True),
                      ('fiscal_operation_category_id', '=',
                       fiscal_operation_category_id),
                      ('partner_fiscal_type_id', '=', partner_fiscal_type)])
        if not fsc_pos_id:
            fsc_pos_id = self.pool.get('account.fiscal.position.rule').search(
                cr, uid, [('company_id', '=', obj_shop.company_id.id),
                          ('from_country', '=', from_country),
                          ('from_state', '=', from_state),
                          ('to_country', '=', to_country),
                          ('to_state', '=', to_state), ('use_sale', '=', True),
                          ('fiscal_operation_category_id', '=',
                           fiscal_operation_category_id)])

        if fsc_pos_id:
            obj_fpo_rule = self.pool.get(
                'account.fiscal.position.rule').browse(cr, uid, fsc_pos_id)[0]
            result['value'][
                'fiscal_position'] = obj_fpo_rule.fiscal_position_id.id
            result['value'][
                'fiscal_operation_id'] = obj_fpo_rule.fiscal_position_id.fiscal_operation_id.id

        return result

    def action_invoice_create(self,
                              cr,
                              uid,
                              ids,
                              grouped=False,
                              states=['confirmed', 'done', 'exception'],
                              date_inv=False,
                              context=None):
        result = super(sale_order,
                       self).action_invoice_create(cr, uid, ids, grouped,
                                                   states, date_inv, context)

        if not result:
            return result

        for order in self.browse(cr, uid, ids):
            for order_line in order.order_line:
                for inv_line in order_line.invoice_lines:

                    invoice_id = inv_line.invoice_id

                    fiscal_operation_id = order_line.fiscal_operation_id or order.fiscal_operation_id
                    fiscal_operation_category_id = order_line.fiscal_operation_category_id or order.fiscal_operation_category_id

                    if invoice_id == inv_line.invoice_id:
                        for invoice in order.invoice_ids:

                            if invoice.state in ('draft'):
                                company_id = self.pool.get(
                                    'res.company').browse(
                                        cr, uid, order.company_id.id)
                                if not company_id.document_serie_product_ids:
                                    raise osv.except_osv(
                                        _('No fiscal document serie found !'),
                                        _("No fiscal document serie found for selected company %s and fiscal operation: '%s'"
                                          ) % (order.company_id.name,
                                               order.fiscal_operation_id.code))
                                comment = ''
                                if order_line.fiscal_operation_id.inv_copy_note:
                                    comment = order_line.fiscal_operation_id.note

                                if order.note:
                                    comment += ' - ' + order.note

                                journal_ids = [
                                    jou for jou in order.
                                    fiscal_operation_category_id.journal_ids
                                    if jou.company_id == invoice.company_id
                                ]

                                if journal_ids:
                                    journal_id = journal_ids[0].id
                                else:
                                    journal_id = invoice_id.journal_id.id

                                self.pool.get('account.invoice').write(
                                    cr, uid, invoice_id.id, {
                                        'fiscal_operation_category_id':
                                        fiscal_operation_category_id.id,
                                        'fiscal_operation_id':
                                        fiscal_operation_id.id,
                                        'cfop_id':
                                        fiscal_operation_id.cfop_id.id,
                                        'fiscal_document_id':
                                        fiscal_operation_id.fiscal_document_id.
                                        id,
                                        'document_serie_id':
                                        company_id.
                                        document_serie_product_ids[0].id,
                                        'comment':
                                        comment,
                                        'journal_id':
                                        journal_id
                                    })

                            invoice_id = inv_line.invoice_id

                    self.pool.get('account.invoice.line').write(
                        cr, uid, inv_line.id, {
                            'fiscal_operation_category_id':
                            fiscal_operation_category_id.id,
                            'fiscal_operation_id':
                            fiscal_operation_id.id,
                            'cfop_id':
                            fiscal_operation_id.cfop_id.id
                        })

        return result

    def action_ship_create(self, cr, uid, ids, *args):
        result = super(sale_order,
                       self).action_ship_create(cr, uid, ids, *args)

        for order in self.browse(cr, uid, ids, context={}):
            for picking in order.picking_ids:
                self.pool.get('stock.picking').write(
                    cr, uid, picking.id, {
                        'fiscal_operation_category_id':
                        order.fiscal_operation_category_id.id,
                        'fiscal_operation_id':
                        order.fiscal_operation_id.id,
                        'fiscal_position':
                        order.fiscal_position.id
                    })

        return result

    def _amount_line_tax(self, cr, uid, line, context=None):
        val = 0.0
        for c in self.pool.get('account.tax').compute_all(
                cr, uid, line.tax_id,
                line.price_unit * (1 - (line.discount or 0.0) / 100.0),
                line.product_uom_qty, line.order_id.partner_invoice_id.id,
                line.product_id, line.order_id.partner_id)['taxes']:
            tax_brw = self.pool.get('account.tax').browse(cr, uid, c['id'])
            if tax_brw.tax_add:
                val += c.get('amount', 0.0)
        return val

    def _amount_all(self, cr, uid, ids, field_name, arg, context):
        res = super(sale_order, self)._amount_all(cr, uid, ids, field_name,
                                                  arg, context)
        return res

    def _get_order(self, cr, uid, ids, context={}):
        result = super(sale_order, self)._get_order(cr, uid, ids, context)
        return result.keys()

    _columns = {
        'fiscal_operation_category_id':
        fields.many2one(
            'l10n_br_account.fiscal.operation.category',
            'Categoria',
            domain="[('type','=','output'),('use_sale','=',True)]"),
        'fiscal_operation_id':
        fields.many2one(
            'l10n_br_account.fiscal.operation',
            'Operação Fiscal',
            domain=
            "[('fiscal_operation_category_id','=',fiscal_operation_category_id),('type','=','output'),('use_sale','=',True)]"
        ),
        'amount_untaxed':
        fields.function(
            _amount_all,
            method=True,
            digits_compute=dp.get_precision('Sale Price'),
            string='Untaxed Amount',
            store={
                'sale.order':
                (lambda self, cr, uid, ids, c={}: ids, ['order_line'], 10),
                'sale.order.line':
                (_get_order,
                 ['price_unit', 'tax_id', 'discount', 'product_uom_qty'], 10)
            },
            multi='sums'),
        'amount_tax':
        fields.function(
            _amount_all,
            method=True,
            digits_compute=dp.get_precision('Sale Price'),
            string='Taxes',
            store={
                'sale.order':
                (lambda self, cr, uid, ids, c={}: ids, ['order_line'], 10),
                'sale.order.line':
                (_get_order,
                 ['price_unit', 'tax_id', 'discount', 'product_uom_qty'], 10),
            },
            multi='sums'),
        'amount_total':
        fields.function(
            _amount_all,
            method=True,
            digits_compute=dp.get_precision('Sale Price'),
            string='Total',
            store={
                'sale.order':
                (lambda self, cr, uid, ids, c={}: ids, ['order_line'], 10),
                'sale.order.line':
                (_get_order,
                 ['price_unit', 'tax_id', 'discount', 'product_uom_qty'], 10),
            },
            multi='sums'),
    }