Python - 覆盖继承的方法(更改内部方法代码的一部分)

时间:2014-09-11 10:44:54

标签: python override openerp odoo

有这么长的方法:

def get_payslip_lines(self, cr, uid, contract_ids, payslip_id, context):
    def _sum_salary_rule_category(localdict, category, amount):
        if category.parent_id:
            localdict = _sum_salary_rule_category(localdict, category.parent_id, amount)
        localdict['categories'].dict[category.code] = category.code in localdict['categories'].dict and localdict['categories'].dict[category.code] + amount or amount
        return localdict

    class BrowsableObject(object):
        def __init__(self, pool, cr, uid, employee_id, dict):
            self.pool = pool
            self.cr = cr
            self.uid = uid
            self.employee_id = employee_id
            self.dict = dict

        def __getattr__(self, attr):
            return attr in self.dict and self.dict.__getitem__(attr) or 0.0

    class InputLine(BrowsableObject):
        """a class that will be used into the python code, mainly for usability purposes"""
        def sum(self, code, from_date, to_date=None):
            if to_date is None:
                to_date = datetime.now().strftime('%Y-%m-%d')
            result = 0.0
            self.cr.execute("SELECT sum(amount) as sum\
                        FROM hr_payslip as hp, hr_payslip_input as pi \
                        WHERE hp.employee_id = %s AND hp.state = 'done' \
                        AND hp.date_from >= %s AND hp.date_to <= %s AND hp.id = pi.payslip_id AND pi.code = %s",
                       (self.employee_id, from_date, to_date, code))
            res = self.cr.fetchone()[0]
            return res or 0.0

    class WorkedDays(BrowsableObject):
        """a class that will be used into the python code, mainly for usability purposes"""
        def _sum(self, code, from_date, to_date=None):
            if to_date is None:
                to_date = datetime.now().strftime('%Y-%m-%d')
            result = 0.0
            self.cr.execute("SELECT sum(number_of_days) as number_of_days, sum(number_of_hours) as number_of_hours\
                        FROM hr_payslip as hp, hr_payslip_worked_days as pi \
                        WHERE hp.employee_id = %s AND hp.state = 'done'\
                        AND hp.date_from >= %s AND hp.date_to <= %s AND hp.id = pi.payslip_id AND pi.code = %s",
                       (self.employee_id, from_date, to_date, code))
            return self.cr.fetchone()

        def sum(self, code, from_date, to_date=None):
            res = self._sum(code, from_date, to_date)
            return res and res[0] or 0.0

        def sum_hours(self, code, from_date, to_date=None):
            res = self._sum(code, from_date, to_date)
            return res and res[1] or 0.0

    class Payslips(BrowsableObject):
        """a class that will be used into the python code, mainly for usability purposes"""

        def sum(self, code, from_date, to_date=None):
            if to_date is None:
                to_date = datetime.now().strftime('%Y-%m-%d')
            self.cr.execute("SELECT sum(case when hp.credit_note = False then (pl.total) else (-pl.total) end)\
                        FROM hr_payslip as hp, hr_payslip_line as pl \
                        WHERE hp.employee_id = %s AND hp.state = 'done' \
                        AND hp.date_from >= %s AND hp.date_to <= %s AND hp.id = pl.slip_id AND pl.code = %s",
                        (self.employee_id, from_date, to_date, code))
            res = self.cr.fetchone()
            return res and res[0] or 0.0

    #we keep a dict with the result because a value can be overwritten by another rule with the same code
    result_dict = {}
    rules = {}
    categories_dict = {}
    blacklist = []
    payslip_obj = self.pool.get('hr.payslip')
    inputs_obj = self.pool.get('hr.payslip.worked_days')
    obj_rule = self.pool.get('hr.salary.rule')
    payslip = payslip_obj.browse(cr, uid, payslip_id, context=context)
    worked_days = {}
    for worked_days_line in payslip.worked_days_line_ids:
        worked_days[worked_days_line.code] = worked_days_line
    inputs = {}
    for input_line in payslip.input_line_ids:
        inputs[input_line.code] = input_line

    categories_obj = BrowsableObject(self.pool, cr, uid, payslip.employee_id.id, categories_dict)
    input_obj = InputLine(self.pool, cr, uid, payslip.employee_id.id, inputs)
    worked_days_obj = WorkedDays(self.pool, cr, uid, payslip.employee_id.id, worked_days)
    payslip_obj = Payslips(self.pool, cr, uid, payslip.employee_id.id, payslip)
    rules_obj = BrowsableObject(self.pool, cr, uid, payslip.employee_id.id, rules)
    baselocaldict = {'categories': categories_obj, 'rules': rules_obj, 'payslip': payslip_obj, 'worked_days': worked_days_obj, 'inputs': input_obj}
    #get the ids of the structures on the contracts and their parent id as well
    structure_ids = self.pool.get('hr.contract').get_all_structures(cr, uid, contract_ids, context=context)
    #get the rules of the structure and thier children
    rule_ids = self.pool.get('hr.payroll.structure').get_all_rules(cr, uid, structure_ids, context=context)
    #run the rules by sequence
    sorted_rule_ids = [id for id, sequence in sorted(rule_ids, key=lambda x:x[1])]

    for contract in self.pool.get('hr.contract').browse(cr, uid, contract_ids, context=context):
        employee = contract.employee_id           
        localdict = dict(baselocaldict, employee=employee, contract=contract)
        for rule in obj_rule.browse(cr, uid, sorted_rule_ids, context=context):
            key = rule.code + '-' + str(contract.id)
            localdict['result'] = None
            localdict['result_qty'] = 1.0
            localdict['result_rate'] = 100
            #check if the rule can be applied
            if obj_rule.satisfy_condition(cr, uid, rule.id, localdict, context=context) and rule.id not in blacklist:
                #compute the amount of the rule
                amount, qty, rate = obj_rule.compute_rule(cr, uid, rule.id, localdict, context=context)
                #check if there is already a rule computed with that code
                previous_amount = rule.code in localdict and localdict[rule.code] or 0.0
                #set/overwrite the amount computed for this rule in the localdict
                tot_rule = amount * qty * rate / 100.0
                localdict[rule.code] = tot_rule
                rules[rule.code] = rule
                #sum the amount for its salary category
                localdict = _sum_salary_rule_category(localdict, rule.category_id, tot_rule - previous_amount)
                #create/overwrite the rule in the temporary results
                result_dict[key] = {
                    'salary_rule_id': rule.id,
                    'contract_id': contract.id,
                    'name': rule.name,
                    'code': rule.code,
                    'category_id': rule.category_id.id,
                    'sequence': rule.sequence,
                    'appears_on_payslip': rule.appears_on_payslip,
                    'condition_select': rule.condition_select,
                    'condition_python': rule.condition_python,
                    'condition_range': rule.condition_range,
                    'condition_range_min': rule.condition_range_min,
                    'condition_range_max': rule.condition_range_max,
                    'amount_select': rule.amount_select,
                    'amount_fix': rule.amount_fix,
                    'amount_python_compute': rule.amount_python_compute,
                    'amount_percentage': rule.amount_percentage,
                    'amount_percentage_base': rule.amount_percentage_base,
                    'register_id': rule.register_id.id,
                    'amount': amount,
                    'employee_id': contract.employee_id.id,
                    'quantity': qty,
                    'rate': rate,
                }
            else:
                #blacklist this rule and its children
                blacklist += [id for id, seq in self.pool.get('hr.salary.rule')._recursive_search_of_rules(cr, uid, [rule], context=context)]

    result = [value for code, value in result_dict.items()]
    return result

我需要覆盖该方法,为此方法添加一些修改。最简单的方法是复制一切,然后修改我需要的东西,但也许有更好的练习呢?如果我使用super,我将无法修改内部代码,只会在调用super方法之前添加一些修改,但我需要修改内部的内容(并且需要修改是与该方法的输入参数无关。)

确切地说,我需要添加以下代码:

duration = 0.0
tsheet_obj = self.pool.get('hr.analytic.timesheet')
timesheet_ids = tsheet_obj.search(cr, uid, [('employee_id', '=', employee.id), 
    ('date', '>=', payslip_obj.date_from), ('date', '<=', payslip_obj.date_to)])
for tsheet in tsheet_obj.browse(cr, uid, timesheet_ids):
    duration += tsheet.unit_amount

然后修改此行,添加键/值对(持续时间):

 localdict = dict(baselocaldict, employee=employee, contract=contract, duration=duration)

这个修改应该在这部分代码之后添加:

'''
for contract in self.pool.get('hr.contract').browse(cr, uid, contract_ids, context=context):
            employee = contract.employee_id
'''

P.S。而且我不能简单地修改原始方法,因为我需要使用OOP原则而不是直接修改基本方法。

1 个答案:

答案 0 :(得分:0)

我有替代解决方案。在工资规则中,您可以拥有不同的对象,如合同,员工,工资单等。因此,您需要做的是创建任何类(员工,工资单,合同等)的方法,并在规则内调用该方法。例如,您已在hr.employee中定义了一个名为calc_duration的方法,该方法返回持续时间。所以在工资规则中你需要把它称为employee.calc_duration(),如果你需要和除了cr,uid,id之外的其他参数,也可以传递。