Example #1
0
    def test_2_related_related(self):
        """ test a related field referring to a related field """
        # add a related field on a related field on res.partner
        old_columns = self.partner._columns
        self.partner._columns = dict(old_columns)
        self.partner._columns.update({
            'single_related_company_id': fields.related('company_id', type='many2one', obj='res.company'),
            'related_related_company_id': fields.related('single_related_company_id', type='many2one', obj='res.company'),
        })

        self.do_test_company_field('related_related_company_id')

        # restore res.partner fields
        self.partner._columns = old_columns
Example #2
0
    def test_3_read_write(self):
        """ write on a related field """
        # add a related field test_related_company_id on res.partner
        old_columns = self.partner._columns
        self.partner._columns = dict(old_columns)
        self.partner._columns.update({
            'related_company_partner_id': fields.related('company_id', 'partner_id', type='many2one', obj='res.partner'),
        })

        # find a company with a non-null partner_id
        company_ids = self.company.search(self.cr, self.uid, [('partner_id', '!=', False)], limit=1)
        company = self.company.browse(self.cr, self.uid, company_ids[0])

        # find partners that satisfy [('partner_id.company_id', '=', company.id)]
        partner_ids = self.partner.search(self.cr, self.uid, [('related_company_partner_id', '=', company.id)])
        partner = self.partner.browse(self.cr, self.uid, partner_ids[0])

        # create a new partner, and assign it to company
        new_partner_id = self.partner.create(self.cr, self.uid, {'name': 'Foo'})
        partner.write({'related_company_partner_id': new_partner_id})

        company = self.company.browse(self.cr, self.uid, company_ids[0])
        self.assertEqual(company.partner_id.id, new_partner_id)

        partner = self.partner.browse(self.cr, self.uid, partner_ids[0])
        self.assertEqual(partner.related_company_partner_id.id, new_partner_id)

        # restore res.partner fields
        self.partner._columns = old_columns
Example #3
0
    def test_2_related_related(self):
        """ test a related field referring to a related field """
        # add a related field on a related field on res.partner
        # and simulate a _inherits_reload() to populate _all_columns.
        old_columns = self.partner._columns
        old_all_columns = self.partner._all_columns
        self.partner._columns = dict(old_columns)
        self.partner._all_columns = dict(old_all_columns)
        self.partner._columns.update({
            'single_related_company_id': fields.related('company_id', type='many2one', obj='res.company'),
            'related_related_company_id': fields.related('single_related_company_id', type='many2one', obj='res.company'),
        })
        self.partner._all_columns.update({
            'single_related_company_id': fields.column_info('single_related_company_id', self.partner._columns['single_related_company_id'], None, None, None),
            'related_related_company_id': fields.column_info('related_related_company_id', self.partner._columns['related_related_company_id'], None, None, None)
        })

        self.do_test_company_field('related_related_company_id')

        # restore res.partner fields
        self.partner._columns = old_columns
        self.partner._all_columns = old_all_columns
Example #4
0
    def test_1_single_related(self):
        """ test a related field with a single indirection like fields.related('foo') """
        # add a related field test_related_company_id on res.partner
        old_columns = self.partner._columns
        self.partner._columns = dict(old_columns)
        self.partner._columns.update({
            'single_related_company_id': fields.related('company_id', type='many2one', obj='res.company'),
        })

        self.do_test_company_field('single_related_company_id')

        # restore res.partner fields
        self.partner._columns = old_columns
Example #5
0
    def test_1_single_related(self):
        """ test a related field with a single indirection like fields.related('foo') """
        # add a related field test_related_company_id on res.partner
        # and simulate a _inherits_reload() to populate _all_columns.
        old_columns = self.partner._columns
        old_all_columns = self.partner._all_columns
        self.partner._columns = dict(old_columns)
        self.partner._all_columns = dict(old_all_columns)
        self.partner._columns.update({
            'single_related_company_id': fields.related('company_id', type='many2one', obj='res.company'),
        })
        self.partner._all_columns.update({
            'single_related_company_id': fields.column_info('single_related_company_id', self.partner._columns['single_related_company_id'], None, None, None)
        })

        self.do_test_company_field('single_related_company_id')

        # restore res.partner fields
        self.partner._columns = old_columns
        self.partner._all_columns = old_all_columns
Example #6
0
    def test_0_related(self):
        """ test an usual related field """
        # add a related field test_related_company_id on res.partner
        old_columns = self.partner._columns
        self.partner._columns = dict(old_columns)
        self.partner._columns.update({
            'related_company_partner_id': fields.related('company_id', 'partner_id', type='many2one', obj='res.partner'),
        })

        # find a company with a non-null partner_id
        ids = self.company.search(self.cr, self.uid, [('partner_id', '!=', False)], limit=1)
        id = ids[0]

        # find partners that satisfy [('partner_id.company_id', '=', id)]
        company_ids = self.company.search(self.cr, self.uid, [('partner_id', '=', id)])
        partner_ids1 = self.partner.search(self.cr, self.uid, [('company_id', 'in', company_ids)])
        partner_ids2 = self.partner.search(self.cr, self.uid, [('related_company_partner_id', '=', id)])
        self.assertEqual(partner_ids1, partner_ids2)

        # restore res.partner fields
        self.partner._columns = old_columns
 def __init__(self, pool, cr):
     super(AbstractConfigSettings, self).__init__(pool, cr)
     if self._companyObject:
         for field_key in self._companyObject._columns:
             # allows to exclude some field
             if self._filter_field(field_key):
                 args = ('company_id', field_key)
                 kwargs = {
                     'string': self._companyObject._columns[field_key].string,
                     'help': self._companyObject._columns[field_key].help,
                     'type': self._companyObject._columns[field_key]._type,
                 }
                 if '_obj' in self._companyObject._columns[field_key].__dict__.keys():
                     kwargs['relation'] = \
                         self._companyObject._columns[field_key]._obj
                 if '_domain' in \
                         self._companyObject._columns[field_key].__dict__.keys():
                     kwargs['domain'] = \
                         self._companyObject._columns[field_key]._domain
                 field_key = re.sub('^' + self._prefix, '', field_key)
                 self._columns[field_key] = \
                     fields.related(*args, **kwargs)
Example #8
0
    def _total_margin(self, cr, uid, ids, name, arg, context=None):
        res = {}
        for line in self.browse(cr, uid, ids):
            res[line.id] = line.product_qty * line.target_margin
        return res

    _columns = {
        #'standard_price': fields.related('product_id','standard_price',type='float',relation='product.product', string='Cost Price', readonly=True),
        'standard_price':fields.function(
            _standard_price,
            string='Cost Price',
            type='float',
            digits=(16,2),
            ), #Issue 173
        'volume_per_pallet': fields.related('product_id','volume_per_pallet',type='integer',relation='product.product', string='Pallet Quantity', readonly=True),
        'product_uom': fields.related('product_id', 'uom_id', string='Unit of Measure', type='many2one', relation='product.uom', store=True, readonly=True),
        'target_selling': fields.char('Target Selling Price'), #Issue322
        'target_margin': fields.char('Target Margin'), #Issue322
        'total_margin':fields.function(
            _total_margin,
            string='Total Margin',
            type='float'), #Issue322
    }

    _defaults = {
        'product_uom' : _get_uom_id,
        }

    def onchange_product_id(self, cr, uid, ids, pricelist_id, product_id, qty, uom_id,
            partner_id, date_order=False, fiscal_position_id=False, date_planned=False,
Example #9
0
class crm_lead(base_stage, format_address, osv.osv):
    """ CRM Lead Case """
    _name = "crm.lead"
    _description = "Lead/Opportunity"
    _order = "priority,date_action,id desc"
    _inherit = ['mail.thread', 'ir.needaction_mixin']

    _track = {
        'state': {
            'crm.mt_lead_create': lambda self, cr, uid, obj, ctx=None: obj['state'] == 'new',
            'crm.mt_lead_won': lambda self, cr, uid, obj, ctx=None: obj['state'] == 'done',
            'crm.mt_lead_lost': lambda self, cr, uid, obj, ctx=None: obj['state'] == 'cancel',
        },
        'stage_id': {
            'crm.mt_lead_stage': lambda self, cr, uid, obj, ctx=None: obj['state'] not in ['new', 'cancel', 'done'],
        },
    }

    def create(self, cr, uid, vals, context=None):
        if context is None:
            context = {}
        if not vals.get('stage_id'):
            ctx = context.copy()
            if vals.get('section_id'):
                ctx['default_section_id'] = vals['section_id']
            if vals.get('type'):
                ctx['default_type'] = vals['type']
            vals['stage_id'] = self._get_default_stage_id(cr, uid, context=ctx)
        return super(crm_lead, self).create(cr, uid, vals, context=context)

    def _get_default_section_id(self, cr, uid, context=None):
        """ Gives default section by checking if present in the context """
        return self._resolve_section_id_from_context(cr, uid, context=context) or False

    def _get_default_stage_id(self, cr, uid, context=None):
        """ Gives default stage_id """
        section_id = self._get_default_section_id(cr, uid, context=context)
        return self.stage_find(cr, uid, [], section_id, [('state', '=', 'draft')], context=context)

    def _resolve_section_id_from_context(self, cr, uid, context=None):
        """ Returns ID of section based on the value of 'section_id'
            context key, or None if it cannot be resolved to a single
            Sales Team.
        """
        if context is None:
            context = {}
        if type(context.get('default_section_id')) in (int, long):
            return context.get('default_section_id')
        if isinstance(context.get('default_section_id'), basestring):
            section_name = context['default_section_id']
            section_ids = self.pool.get('crm.case.section').name_search(cr, uid, name=section_name, context=context)
            if len(section_ids) == 1:
                return int(section_ids[0][0])
        return None

    def _resolve_type_from_context(self, cr, uid, context=None):
        """ Returns the type (lead or opportunity) from the type context
            key. Returns None if it cannot be resolved.
        """
        if context is None:
            context = {}
        return context.get('default_type')

    def _read_group_stage_ids(self, cr, uid, ids, domain, read_group_order=None, access_rights_uid=None, context=None):
        access_rights_uid = access_rights_uid or uid
        stage_obj = self.pool.get('crm.case.stage')
        order = stage_obj._order
        # lame hack to allow reverting search, should just work in the trivial case
        if read_group_order == 'stage_id desc':
            order = "%s desc" % order
        # retrieve section_id from the context and write the domain
        # - ('id', 'in', 'ids'): add columns that should be present
        # - OR ('case_default', '=', True), ('fold', '=', False): add default columns that are not folded
        # - OR ('section_ids', '=', section_id), ('fold', '=', False) if section_id: add section columns that are not folded
        search_domain = []
        section_id = self._resolve_section_id_from_context(cr, uid, context=context)
        if section_id:
            search_domain += ['|', ('section_ids', '=', section_id)]
            search_domain += [('id', 'in', ids)]
        else:
            search_domain += ['|', ('id', 'in', ids), ('case_default', '=', True)]
        # retrieve type from the context (if set: choose 'type' or 'both')
        type = self._resolve_type_from_context(cr, uid, context=context)
        if type:
            search_domain += ['|', ('type', '=', type), ('type', '=', 'both')]
        # perform search
        stage_ids = stage_obj._search(cr, uid, search_domain, order=order, access_rights_uid=access_rights_uid, context=context)
        result = stage_obj.name_get(cr, access_rights_uid, stage_ids, context=context)
        # restore order of the search
        result.sort(lambda x,y: cmp(stage_ids.index(x[0]), stage_ids.index(y[0])))

        fold = {}
        for stage in stage_obj.browse(cr, access_rights_uid, stage_ids, context=context):
            fold[stage.id] = stage.fold or False
        return result, fold

    def fields_view_get(self, cr, user, view_id=None, view_type='form', context=None, toolbar=False, submenu=False):
        res = super(crm_lead,self).fields_view_get(cr, user, view_id, view_type, context, toolbar=toolbar, submenu=submenu)
        if view_type == 'form':
            res['arch'] = self.fields_view_get_address(cr, user, res['arch'], context=context)
        return res

    _group_by_full = {
        'stage_id': _read_group_stage_ids
    }

    def _compute_day(self, cr, uid, ids, fields, args, context=None):
        """
        :return dict: difference between current date and log date
        """
        cal_obj = self.pool.get('resource.calendar')
        res_obj = self.pool.get('resource.resource')

        res = {}
        for lead in self.browse(cr, uid, ids, context=context):
            for field in fields:
                res[lead.id] = {}
                duration = 0
                ans = False
                if field == 'day_open':
                    if lead.date_open:
                        date_create = datetime.strptime(lead.create_date, "%Y-%m-%d %H:%M:%S")
                        date_open = datetime.strptime(lead.date_open, "%Y-%m-%d %H:%M:%S")
                        ans = date_open - date_create
                        date_until = lead.date_open
                elif field == 'day_close':
                    if lead.date_closed:
                        date_create = datetime.strptime(lead.create_date, "%Y-%m-%d %H:%M:%S")
                        date_close = datetime.strptime(lead.date_closed, "%Y-%m-%d %H:%M:%S")
                        date_until = lead.date_closed
                        ans = date_close - date_create
                if ans:
                    resource_id = False
                    if lead.user_id:
                        resource_ids = res_obj.search(cr, uid, [('user_id','=',lead.user_id.id)])
                        if len(resource_ids):
                            resource_id = resource_ids[0]

                    duration = float(ans.days)
                    if lead.section_id and lead.section_id.resource_calendar_id:
                        duration =  float(ans.days) * 24
                        new_dates = cal_obj.interval_get(cr,
                            uid,
                            lead.section_id.resource_calendar_id and lead.section_id.resource_calendar_id.id or False,
                            datetime.strptime(lead.create_date, '%Y-%m-%d %H:%M:%S'),
                            duration,
                            resource=resource_id
                        )
                        no_days = []
                        date_until = datetime.strptime(date_until, '%Y-%m-%d %H:%M:%S')
                        for in_time, out_time in new_dates:
                            if in_time.date not in no_days:
                                no_days.append(in_time.date)
                            if out_time > date_until:
                                break
                        duration =  len(no_days)
                res[lead.id][field] = abs(int(duration))
        return res

    def _history_search(self, cr, uid, obj, name, args, context=None):
        res = []
        msg_obj = self.pool.get('mail.message')
        message_ids = msg_obj.search(cr, uid, [('email_from','!=',False), ('subject', args[0][1], args[0][2])], context=context)
        lead_ids = self.search(cr, uid, [('message_ids', 'in', message_ids)], context=context)

        if lead_ids:
            return [('id', 'in', lead_ids)]
        else:
            return [('id', '=', '0')]

    _columns = {
        'partner_id': fields.many2one('res.partner', 'Partner', ondelete='set null', track_visibility='onchange',
            select=True, help="Linked partner (optional). Usually created when converting the lead."),

        'id': fields.integer('ID', readonly=True),
        'name': fields.char('Subject', size=64, required=True, select=1),
        'active': fields.boolean('Active', required=False),
        'date_action_last': fields.datetime('Last Action', readonly=1),
        'date_action_next': fields.datetime('Next Action', readonly=1),
        'email_from': fields.char('Email', size=128, help="Email address of the contact", select=1),
        'section_id': fields.many2one('crm.case.section', 'Sales Team',
                        select=True, track_visibility='onchange', help='When sending mails, the default email address is taken from the sales team.'),
        'create_date': fields.datetime('Creation Date' , readonly=True),
        'email_cc': fields.text('Global CC', size=252 , help="These email addresses will be added to the CC field of all inbound and outbound emails for this record before being sent. Separate multiple email addresses with a comma"),
        'description': fields.text('Notes'),
        'write_date': fields.datetime('Update Date' , readonly=True),
        'categ_ids': fields.many2many('crm.case.categ', 'crm_lead_category_rel', 'lead_id', 'category_id', 'Categories', \
            domain="['|',('section_id','=',section_id),('section_id','=',False), ('object_id.model', '=', 'crm.lead')]"),
        'type_id': fields.many2one('crm.case.resource.type', 'Campaign', \
            domain="['|',('section_id','=',section_id),('section_id','=',False)]", help="From which campaign (seminar, marketing campaign, mass mailing, ...) did this contact come from?"),
        'channel_id': fields.many2one('crm.case.channel', 'Channel', help="Communication channel (mail, direct, phone, ...)"),
        'contact_name': fields.char('Contact Name', size=64),
        'partner_name': fields.char("Customer Name", size=64,help='The name of the future partner company that will be created while converting the lead into opportunity', select=1),
        'opt_out': fields.boolean('Opt-Out', oldname='optout', help="If opt-out is checked, this contact has refused to receive emails or unsubscribed to a campaign."),
        'type':fields.selection([ ('lead','Lead'), ('opportunity','Opportunity'), ],'Type', help="Type is used to separate Leads and Opportunities"),
        'priority': fields.selection(crm.AVAILABLE_PRIORITIES, 'Priority', select=True),
        'date_closed': fields.datetime('Closed', readonly=True),
        'stage_id': fields.many2one('crm.case.stage', 'Stage', track_visibility='onchange',
                        domain="['&', '&', ('fold', '=', False), ('section_ids', '=', section_id), '|', ('type', '=', type), ('type', '=', 'both')]"),
        'user_id': fields.many2one('res.users', 'Salesperson', select=True, track_visibility='onchange'),
        'referred': fields.char('Referred By', size=64),
        'date_open': fields.datetime('Opened', readonly=True),
        'day_open': fields.function(_compute_day, string='Days to Open', \
                                multi='day_open', type="float", store=True),
        'day_close': fields.function(_compute_day, string='Days to Close', \
                                multi='day_close', type="float", store=True),
        'state': fields.related('stage_id', 'state', type="selection", store=True,
                selection=crm.AVAILABLE_STATES, string="Status", readonly=True,
                help='The Status is set to \'Draft\', when a case is created. If the case is in progress the Status is set to \'Open\'. When the case is over, the Status is set to \'Done\'. If the case needs to be reviewed then the Status is  set to \'Pending\'.'),

        # Only used for type opportunity
        'probability': fields.float('Success Rate (%)',group_operator="avg"),
        'planned_revenue': fields.float('Expected Revenue', track_visibility='always'),
        'ref': fields.reference('Reference', selection=crm._links_get, size=128),
        'ref2': fields.reference('Reference 2', selection=crm._links_get, size=128),
        'phone': fields.char("Phone", size=64),
        'date_deadline': fields.date('Expected Closing', help="Estimate of the date on which the opportunity will be won."),
        'date_action': fields.date('Next Action Date', select=True),
        'title_action': fields.char('Next Action', size=64),
        'color': fields.integer('Color Index'),
        'partner_address_name': fields.related('partner_id', 'name', type='char', string='Partner Contact Name', readonly=True),
        'partner_address_email': fields.related('partner_id', 'email', type='char', string='Partner Contact Email', readonly=True),
        'company_currency': fields.related('company_id', 'currency_id', type='many2one', string='Currency', readonly=True, relation="res.currency"),
        'user_email': fields.related('user_id', 'email', type='char', string='User Email', readonly=True),
        'user_login': fields.related('user_id', 'login', type='char', string='User Login', readonly=True),

        # Fields for address, due to separation from crm and res.partner
        'street': fields.char('Street', size=128),
        'street2': fields.char('Street2', size=128),
        'zip': fields.char('Zip', change_default=True, size=24),
        'city': fields.char('City', size=128),
        'state_id': fields.many2one("res.country.state", 'State'),
        'country_id': fields.many2one('res.country', 'Country'),
        'phone': fields.char('Phone', size=64),
        'fax': fields.char('Fax', size=64),
        'mobile': fields.char('Mobile', size=64),
        'function': fields.char('Function', size=128),
        'title': fields.many2one('res.partner.title', 'Title'),
        'company_id': fields.many2one('res.company', 'Company', select=1),
        'payment_mode': fields.many2one('crm.payment.mode', 'Payment Mode', \
                            domain="[('section_id','=',section_id)]"),
        'planned_cost': fields.float('Planned Costs'),
    }

    _defaults = {
        'active': 1,
        'type': 'lead',
        'user_id': lambda s, cr, uid, c: s._get_default_user(cr, uid, c),
        'email_from': lambda s, cr, uid, c: s._get_default_email(cr, uid, c),
        'stage_id': lambda s, cr, uid, c: s._get_default_stage_id(cr, uid, c),
        'section_id': lambda s, cr, uid, c: s._get_default_section_id(cr, uid, c),
        'company_id': lambda s, cr, uid, c: s.pool.get('res.company')._company_default_get(cr, uid, 'crm.lead', context=c),
        'priority': lambda *a: crm.AVAILABLE_PRIORITIES[2][0],
        'color': 0,
    }

    _sql_constraints = [
        ('check_probability', 'check(probability >= 0 and probability <= 100)', 'The probability of closing the deal should be between 0% and 100%!')
    ]

    def onchange_stage_id(self, cr, uid, ids, stage_id, context=None):
        if not stage_id:
            return {'value':{}}
        stage = self.pool.get('crm.case.stage').browse(cr, uid, stage_id, context)
        if not stage.on_change:
            return {'value':{}}
        return {'value':{'probability': stage.probability}}

    def on_change_partner(self, cr, uid, ids, partner_id, context=None):
        result = {}
        values = {}
        if partner_id:
            partner = self.pool.get('res.partner').browse(cr, uid, partner_id, context=context)
            values = {
                'partner_name' : partner.name,
                'street' : partner.street,
                'street2' : partner.street2,
                'city' : partner.city,
                'state_id' : partner.state_id and partner.state_id.id or False,
                'country_id' : partner.country_id and partner.country_id.id or False,
                'email_from' : partner.email,
                'phone' : partner.phone,
                'mobile' : partner.mobile,
                'fax' : partner.fax,
            }
        return {'value' : values}

    def _check(self, cr, uid, ids=False, context=None):
        """ Override of the base.stage method.
            Function called by the scheduler to process cases for date actions
            Only works on not done and cancelled cases
        """
        cr.execute('select * from crm_case \
                where (date_action_last<%s or date_action_last is null) \
                and (date_action_next<=%s or date_action_next is null) \
                and state not in (\'cancel\',\'done\')',
                (time.strftime("%Y-%m-%d %H:%M:%S"),
                    time.strftime('%Y-%m-%d %H:%M:%S')))

        ids2 = map(lambda x: x[0], cr.fetchall() or [])
        cases = self.browse(cr, uid, ids2, context=context)
        return self._action(cr, uid, cases, False, context=context)

    def stage_find(self, cr, uid, cases, section_id, domain=None, order='sequence', context=None):
        """ Override of the base.stage method
            Parameter of the stage search taken from the lead:
            - type: stage type must be the same or 'both'
            - section_id: if set, stages must belong to this section or
              be a default stage; if not set, stages must be default
              stages
        """
        if isinstance(cases, (int, long)):
            cases = self.browse(cr, uid, cases, context=context)
        # collect all section_ids
        section_ids = []
        types = ['both']
        if not cases :
            type = context.get('default_type')
            types += [type]
        if section_id:
            section_ids.append(section_id)
        for lead in cases:
            if lead.section_id:
                section_ids.append(lead.section_id.id)
            if lead.type not in types:
                types.append(lead.type)
        # OR all section_ids and OR with case_default
        search_domain = []
        if section_ids:
            search_domain += [('|')] * len(section_ids)
            for section_id in section_ids:
                search_domain.append(('section_ids', '=', section_id))
        else:
            search_domain.append(('case_default', '=', True))
        # AND with cases types
        search_domain.append(('type', 'in', types))
        # AND with the domain in parameter
        search_domain += list(domain)
        # perform search, return the first found
        stage_ids = self.pool.get('crm.case.stage').search(cr, uid, search_domain, order=order, context=context)
        if stage_ids:
            return stage_ids[0]
        return False

    def case_cancel(self, cr, uid, ids, context=None):
        """ Overrides case_cancel from base_stage to set probability """
        res = super(crm_lead, self).case_cancel(cr, uid, ids, context=context)
        self.write(cr, uid, ids, {'probability' : 0.0}, context=context)
        return res

    def case_reset(self, cr, uid, ids, context=None):
        """ Overrides case_reset from base_stage to set probability """
        res = super(crm_lead, self).case_reset(cr, uid, ids, context=context)
        self.write(cr, uid, ids, {'probability': 0.0}, context=context)
        return res

    def case_mark_lost(self, cr, uid, ids, context=None):
        """ Mark the case as lost: state=cancel and probability=0 """
        for lead in self.browse(cr, uid, ids):
            stage_id = self.stage_find(cr, uid, [lead], lead.section_id.id or False, [('probability', '=', 0.0),('on_change','=',True)], context=context)
            if stage_id:
                self.case_set(cr, uid, [lead.id], values_to_update={'probability': 0.0}, new_stage_id=stage_id, context=context)
        return True

    def case_mark_won(self, cr, uid, ids, context=None):
        """ Mark the case as won: state=done and probability=100 """
        for lead in self.browse(cr, uid, ids):
            stage_id = self.stage_find(cr, uid, [lead], lead.section_id.id or False, [('probability', '=', 100.0),('on_change','=',True)], context=context)
            if stage_id:
                self.case_set(cr, uid, [lead.id], values_to_update={'probability': 100.0}, new_stage_id=stage_id, context=context)
        return True

    def set_priority(self, cr, uid, ids, priority):
        """ Set lead priority
        """
        return self.write(cr, uid, ids, {'priority' : priority})

    def set_high_priority(self, cr, uid, ids, context=None):
        """ Set lead priority to high
        """
        return self.set_priority(cr, uid, ids, '1')

    def set_normal_priority(self, cr, uid, ids, context=None):
        """ Set lead priority to normal
        """
        return self.set_priority(cr, uid, ids, '3')

    def _merge_get_result_type(self, cr, uid, opps, context=None):
        """
        Define the type of the result of the merge.  If at least one of the
        element to merge is an opp, the resulting new element will be an opp.
        Otherwise it will be a lead.

        We'll directly use a list of browse records instead of a list of ids
        for performances' sake: it will spare a second browse of the
        leads/opps.

        :param list opps: list of browse records containing the leads/opps to process
        :return string type: the type of the final element
        """
        for opp in opps:
            if (opp.type == 'opportunity'):
                return 'opportunity'

        return 'lead'

    def _merge_data(self, cr, uid, ids, oldest, fields, context=None):
        """
        Prepare lead/opp data into a dictionary for merging.  Different types
        of fields are processed in different ways:
        - text: all the values are concatenated
        - m2m and o2m: those fields aren't processed
        - m2o: the first not null value prevails (the other are dropped)
        - any other type of field: same as m2o

        :param list ids: list of ids of the leads to process
        :param list fields: list of leads' fields to process
        :return dict data: contains the merged values
        """
        opportunities = self.browse(cr, uid, ids, context=context)

        def _get_first_not_null(attr):
            for opp in opportunities:
                if hasattr(opp, attr) and bool(getattr(opp, attr)):
                    return getattr(opp, attr)
            return False

        def _get_first_not_null_id(attr):
            res = _get_first_not_null(attr)
            return res and res.id or False

        def _concat_all(attr):
            return '\n\n'.join(filter(lambda x: x, [getattr(opp, attr) or '' for opp in opportunities if hasattr(opp, attr)]))

        # Process the fields' values
        data = {}
        for field_name in fields:
            field_info = self._all_columns.get(field_name)
            if field_info is None:
                continue
            field = field_info.column
            if field._type in ('many2many', 'one2many'):
                continue
            elif field._type == 'many2one':
                data[field_name] = _get_first_not_null_id(field_name)  # !!
            elif field._type == 'text':
                data[field_name] = _concat_all(field_name)  #not lost
            else:
                data[field_name] = _get_first_not_null(field_name)  #not lost

        # Define the resulting type ('lead' or 'opportunity')
        data['type'] = self._merge_get_result_type(cr, uid, opportunities, context)
        return data

    def _mail_body(self, cr, uid, lead, fields, title=False, context=None):
        body = []
        if title:
            body.append("%s\n" % (title))

        for field_name in fields:
            field_info = self._all_columns.get(field_name)
            if field_info is None:
                continue
            field = field_info.column
            value = ''

            if field._type == 'selection':
                if hasattr(field.selection, '__call__'):
                    key = field.selection(self, cr, uid, context=context)
                else:
                    key = field.selection
                value = dict(key).get(lead[field_name], lead[field_name])
            elif field._type == 'many2one':
                if lead[field_name]:
                    value = lead[field_name].name_get()[0][1]
            elif field._type == 'many2many':
                if lead[field_name]:
                    for val in lead[field_name]:
                        field_value = val.name_get()[0][1]
                        value += field_value + ","
            else:
                value = lead[field_name]

            body.append("%s: %s" % (field.string, value or ''))
        return "<br/>".join(body + ['<br/>'])

    def _merge_notify(self, cr, uid, opportunity_id, opportunities, context=None):
        """
        Create a message gathering merged leads/opps information.
        """
        #TOFIX: mail template should be used instead of fix body, subject text
        details = []
        result_type = self._merge_get_result_type(cr, uid, opportunities, context)
        if result_type == 'lead':
            merge_message = _('Merged leads')
        else:
            merge_message = _('Merged opportunities')
        subject = [merge_message]
        for opportunity in opportunities:
            subject.append(opportunity.name)
            title = "%s : %s" % (opportunity.type == 'opportunity' and _('Merged opportunity') or _('Merged lead'), opportunity.name)
            fields = list(CRM_LEAD_FIELDS_TO_MERGE)
            details.append(self._mail_body(cr, uid, opportunity, fields, title=title, context=context))

        # Chatter message's subject
        subject = subject[0] + ": " + ", ".join(subject[1:])
        details = "\n\n".join(details)
        return self.message_post(cr, uid, [opportunity_id], body=details, subject=subject, context=context)

    def _merge_opportunity_history(self, cr, uid, opportunity_id, opportunities, context=None):
        message = self.pool.get('mail.message')
        for opportunity in opportunities:
            for history in opportunity.message_ids:
                message.write(cr, uid, history.id, {
                        'res_id': opportunity_id,
                        'subject' : _("From %s : %s") % (opportunity.name, history.subject)
                }, context=context)

        return True

    def _merge_opportunity_attachments(self, cr, uid, opportunity_id, opportunities, context=None):
        attachment = self.pool.get('ir.attachment')

        # return attachments of opportunity
        def _get_attachments(opportunity_id):
            attachment_ids = attachment.search(cr, uid, [('res_model', '=', self._name), ('res_id', '=', opportunity_id)], context=context)
            return attachment.browse(cr, uid, attachment_ids, context=context)

        count = 1
        first_attachments = _get_attachments(opportunity_id)
        for opportunity in opportunities:
            attachments = _get_attachments(opportunity.id)
            for first in first_attachments:
                for attachment in attachments:
                    if attachment.name == first.name:
                        values = dict(
                            name = "%s (%s)" % (attachment.name, count,),
                            res_id = opportunity_id,
                        )
                        attachment.write(values)
                        count+=1

        return True

    def merge_opportunity(self, cr, uid, ids, context=None):
        """
        Different cases of merge:
        - merge leads together = 1 new lead
        - merge at least 1 opp with anything else (lead or opp) = 1 new opp

        :param list ids: leads/opportunities ids to merge
        :return int id: id of the resulting lead/opp
        """
        if context is None:
            context = {}

        if len(ids) <= 1:
            raise osv.except_osv(_('Warning!'), _('Please select more than one element (lead or opportunity) from the list view.'))

        opportunities = self.browse(cr, uid, ids, context=context)
        sequenced_opps = []
        for opportunity in opportunities:
            sequenced_opps.append((opportunity.stage_id and opportunity.stage_id.state != 'cancel' and opportunity.stage_id.sequence or 0, opportunity))
        sequenced_opps.sort(key=lambda tup: tup[0], reverse=True)
        opportunities = [opportunity for sequence, opportunity in sequenced_opps]
        ids = [opportunity.id for opportunity in opportunities]
        highest = opportunities[0]
        opportunities_rest = opportunities[1:]

        tail_opportunities = opportunities_rest

        fields = list(CRM_LEAD_FIELDS_TO_MERGE)
        merged_data = self._merge_data(cr, uid, ids, highest, fields, context=context)

        # Merge messages and attachements into the first opportunity
        self._merge_opportunity_history(cr, uid, highest.id, tail_opportunities, context=context)
        self._merge_opportunity_attachments(cr, uid, highest.id, tail_opportunities, context=context)

        # Merge notifications about loss of information
        opportunities = [highest]
        opportunities.extend(opportunities_rest)
        self._merge_notify(cr, uid, highest, opportunities, context=context)
        # Check if the stage is in the stages of the sales team. If not, assign the stage with the lowest sequence
        if merged_data.get('type') == 'opportunity' and merged_data.get('section_id'):
            section_stages = self.pool.get('crm.case.section').read(cr, uid, merged_data['section_id'], ['stage_ids'], context=context)
            if merged_data.get('stage_id') not in section_stages['stage_ids']:
                stages_sequences = self.pool.get('crm.case.stage').search(cr, uid, [('id','in',section_stages['stage_ids'])], order='sequence', limit=1, context=context)
                merged_data['stage_id'] = stages_sequences[0]
        # Write merged data into first opportunity
        self.write(cr, uid, [highest.id], merged_data, context=context)
        # Delete tail opportunities
        self.unlink(cr, uid, [x.id for x in tail_opportunities], context=context)

        return highest.id

    def _convert_opportunity_data(self, cr, uid, lead, customer, section_id=False, context=None):
        crm_stage = self.pool.get('crm.case.stage')
        contact_id = False
        if customer:
            contact_id = self.pool.get('res.partner').address_get(cr, uid, [customer.id])['default']
        if not section_id:
            section_id = lead.section_id and lead.section_id.id or False
        val = {
            'planned_revenue': lead.planned_revenue,
            'probability': lead.probability,
            'name': lead.name,
            'partner_id': customer and customer.id or False,
            'user_id': (lead.user_id and lead.user_id.id),
            'type': 'opportunity',
            'date_action': fields.datetime.now(),
            'date_open': fields.datetime.now(),
            'email_from': customer and customer.email or lead.email_from,
            'phone': customer and customer.phone or lead.phone,
        }
        if not lead.stage_id or lead.stage_id.type=='lead':
            val['stage_id'] = self.stage_find(cr, uid, [lead], section_id, [('state', '=', 'draft'),('type', 'in', ('opportunity','both'))], context=context)
        return val

    def convert_opportunity(self, cr, uid, ids, partner_id, user_ids=False, section_id=False, context=None):
        customer = False
        if partner_id:
            partner = self.pool.get('res.partner')
            customer = partner.browse(cr, uid, partner_id, context=context)
        for lead in self.browse(cr, uid, ids, context=context):
            if lead.state in ('done', 'cancel'):
                continue
            vals = self._convert_opportunity_data(cr, uid, lead, customer, section_id, context=context)
            self.write(cr, uid, [lead.id], vals, context=context)
        self.message_post(cr, uid, ids, body=_("Lead <b>converted into an Opportunity</b>"), subtype="crm.mt_lead_convert_to_opportunity", context=context)

        if user_ids or section_id:
            self.allocate_salesman(cr, uid, ids, user_ids, section_id, context=context)

        return True

    def _lead_create_contact(self, cr, uid, lead, name, is_company, parent_id=False, context=None):
        partner = self.pool.get('res.partner')
        vals = {'name': name,
            'user_id': lead.user_id.id,
            'comment': lead.description,
            'section_id': lead.section_id.id or False,
            'parent_id': parent_id,
            'phone': lead.phone,
            'mobile': lead.mobile,
            'email': lead.email_from and tools.email_split(lead.email_from)[0],
            'fax': lead.fax,
            'title': lead.title and lead.title.id or False,
            'function': lead.function,
            'street': lead.street,
            'street2': lead.street2,
            'zip': lead.zip,
            'city': lead.city,
            'country_id': lead.country_id and lead.country_id.id or False,
            'state_id': lead.state_id and lead.state_id.id or False,
            'is_company': is_company,
            'type': 'contact'
        }
        partner = partner.create(cr, uid, vals, context=context)
        return partner

    def _create_lead_partner(self, cr, uid, lead, context=None):
        partner_id = False
        if lead.partner_name and lead.contact_name:
            partner_id = self._lead_create_contact(cr, uid, lead, lead.partner_name, True, context=context)
            partner_id = self._lead_create_contact(cr, uid, lead, lead.contact_name, False, partner_id, context=context)
        elif lead.partner_name and not lead.contact_name:
            partner_id = self._lead_create_contact(cr, uid, lead, lead.partner_name, True, context=context)
        elif not lead.partner_name and lead.contact_name:
            partner_id = self._lead_create_contact(cr, uid, lead, lead.contact_name, False, context=context)
        elif lead.email_from and self.pool.get('res.partner')._parse_partner_name(lead.email_from, context=context)[0]:
            contact_name = self.pool.get('res.partner')._parse_partner_name(lead.email_from, context=context)[0]
            partner_id = self._lead_create_contact(cr, uid, lead, contact_name, False, context=context)
        else:
            raise osv.except_osv(
                _('Warning!'),
                _('No customer name defined. Please fill one of the following fields: Company Name, Contact Name or Email ("Name <email@address>")')
            )
        return partner_id

    def _lead_set_partner(self, cr, uid, lead, partner_id, context=None):
        """
        Assign a partner to a lead.

        :param object lead: browse record of the lead to process
        :param int partner_id: identifier of the partner to assign
        :return bool: True if the partner has properly been assigned
        """
        res = False
        res_partner = self.pool.get('res.partner')
        if partner_id:
            res_partner.write(cr, uid, partner_id, {'section_id': lead.section_id and lead.section_id.id or False})
            contact_id = res_partner.address_get(cr, uid, [partner_id])['default']
            res = lead.write({'partner_id': partner_id}, context=context)
            message = _("<b>Partner</b> set to <em>%s</em>." % (lead.partner_id.name))
            self.message_post(cr, uid, [lead.id], body=message, context=context)
        return res

    def handle_partner_assignation(self, cr, uid, ids, action='create', partner_id=False, context=None):
        """
        Handle partner assignation during a lead conversion.
        if action is 'create', create new partner with contact and assign lead to new partner_id.
        otherwise assign lead to the specified partner_id

        :param list ids: leads/opportunities ids to process
        :param string action: what has to be done regarding partners (create it, assign an existing one, or nothing)
        :param int partner_id: partner to assign if any
        :return dict: dictionary organized as followed: {lead_id: partner_assigned_id}
        """
        #TODO this is a duplication of the handle_partner_assignation method of crm_phonecall
        partner_ids = {}
        # If a partner_id is given, force this partner for all elements
        force_partner_id = partner_id
        for lead in self.browse(cr, uid, ids, context=context):
            # If the action is set to 'create' and no partner_id is set, create a new one
            if action == 'create':
                partner_id = force_partner_id or self._create_lead_partner(cr, uid, lead, context)
            self._lead_set_partner(cr, uid, lead, partner_id, context=context)
            partner_ids[lead.id] = partner_id
        return partner_ids

    def allocate_salesman(self, cr, uid, ids, user_ids=None, team_id=False, context=None):
        """
        Assign salesmen and salesteam to a batch of leads.  If there are more
        leads than salesmen, these salesmen will be assigned in round-robin.
        E.g.: 4 salesmen (S1, S2, S3, S4) for 6 leads (L1, L2, ... L6).  They
        will be assigned as followed: L1 - S1, L2 - S2, L3 - S3, L4 - S4,
        L5 - S1, L6 - S2.

        :param list ids: leads/opportunities ids to process
        :param list user_ids: salesmen to assign
        :param int team_id: salesteam to assign
        :return bool
        """
        index = 0

        for lead_id in ids:
            value = {}
            if team_id:
                value['section_id'] = team_id
            if user_ids:
                value['user_id'] = user_ids[index]
                # Cycle through user_ids
                index = (index + 1) % len(user_ids)
            if value:
                self.write(cr, uid, [lead_id], value, context=context)
        return True

    def schedule_phonecall(self, cr, uid, ids, schedule_time, call_summary, desc, phone, contact_name, user_id=False, section_id=False, categ_id=False, action='schedule', context=None):
        """
        :param string action: ('schedule','Schedule a call'), ('log','Log a call')
        """
        phonecall = self.pool.get('crm.phonecall')
        model_data = self.pool.get('ir.model.data')
        phonecall_dict = {}
        if not categ_id:
            res_id = model_data._get_id(cr, uid, 'crm', 'categ_phone2')
            if res_id:
                categ_id = model_data.browse(cr, uid, res_id, context=context).res_id
        for lead in self.browse(cr, uid, ids, context=context):
            if not section_id:
                section_id = lead.section_id and lead.section_id.id or False
            if not user_id:
                user_id = lead.user_id and lead.user_id.id or False
            vals = {
                'name': call_summary,
                'opportunity_id': lead.id,
                'user_id': user_id or False,
                'categ_id': categ_id or False,
                'description': desc or '',
                'date': schedule_time,
                'section_id': section_id or False,
                'partner_id': lead.partner_id and lead.partner_id.id or False,
                'partner_phone': phone or lead.phone or (lead.partner_id and lead.partner_id.phone or False),
                'partner_mobile': lead.partner_id and lead.partner_id.mobile or False,
                'priority': lead.priority,
            }
            new_id = phonecall.create(cr, uid, vals, context=context)
            phonecall.case_open(cr, uid, [new_id], context=context)
            if action == 'log':
                phonecall.case_close(cr, uid, [new_id], context=context)
            phonecall_dict[lead.id] = new_id
            self.schedule_phonecall_send_note(cr, uid, [lead.id], new_id, action, context=context)
        return phonecall_dict

    def redirect_opportunity_view(self, cr, uid, opportunity_id, context=None):
        models_data = self.pool.get('ir.model.data')

        # Get opportunity views
        dummy, form_view = models_data.get_object_reference(cr, uid, 'crm', 'crm_case_form_view_oppor')
        dummy, tree_view = models_data.get_object_reference(cr, uid, 'crm', 'crm_case_tree_view_oppor')
        return {
            'name': _('Opportunity'),
            'view_type': 'form',
            'view_mode': 'tree, form',
            'res_model': 'crm.lead',
            'domain': [('type', '=', 'opportunity')],
            'res_id': int(opportunity_id),
            'view_id': False,
            'views': [(form_view or False, 'form'),
                    (tree_view or False, 'tree'),
                    (False, 'calendar'), (False, 'graph')],
            'type': 'ir.actions.act_window',
        }

    def redirect_lead_view(self, cr, uid, lead_id, context=None):
        models_data = self.pool.get('ir.model.data')

        # Get lead views
        dummy, form_view = models_data.get_object_reference(cr, uid, 'crm', 'crm_case_form_view_leads')
        dummy, tree_view = models_data.get_object_reference(cr, uid, 'crm', 'crm_case_tree_view_leads')
        return {
            'name': _('Lead'),
            'view_type': 'form',
            'view_mode': 'tree, form',
            'res_model': 'crm.lead',
            'domain': [('type', '=', 'lead')],
            'res_id': int(lead_id),
            'view_id': False,
            'views': [(form_view or False, 'form'),
                      (tree_view or False, 'tree'),
                      (False, 'calendar'), (False, 'graph')],
            'type': 'ir.actions.act_window',
        }

    def action_makeMeeting(self, cr, uid, ids, context=None):
        """
        Open meeting's calendar view to schedule meeting on current opportunity.
        :return dict: dictionary value for created Meeting view
        """
        opportunity = self.browse(cr, uid, ids[0], context)
        res = self.pool.get('ir.actions.act_window').for_xml_id(cr, uid, 'base_calendar', 'action_crm_meeting', context)
        res['context'] = {
            'default_opportunity_id': opportunity.id,
            'default_partner_id': opportunity.partner_id and opportunity.partner_id.id or False,
            'default_partner_ids' : opportunity.partner_id and [opportunity.partner_id.id] or False,
            'default_user_id': uid,
            'default_section_id': opportunity.section_id and opportunity.section_id.id or False,
            'default_email_from': opportunity.email_from,
            'default_name': opportunity.name,
        }
        return res

    def write(self, cr, uid, ids, vals, context=None):
        if vals.get('stage_id') and not vals.get('probability'):
            # change probability of lead(s) if required by stage
            stage = self.pool.get('crm.case.stage').browse(cr, uid, vals['stage_id'], context=context)
            if stage.on_change:
                vals['probability'] = stage.probability
        return super(crm_lead, self).write(cr, uid, ids, vals, context=context)

    def new_mail_send(self, cr, uid, ids, context=None):
        '''
        This function opens a window to compose an email, with the edi sale template message loaded by default
        '''
        assert len(ids) == 1, 'This option should only be used for a single id at a time.'
        ir_model_data = self.pool.get('ir.model.data')
        try:
            template_id = ir_model_data.get_object_reference(cr, uid, 'crm', 'email_template_opportunity_mail')[1]
        except ValueError:
            template_id = False
        try:
            compose_form_id = ir_model_data.get_object_reference(cr, uid, 'mail', 'email_compose_message_wizard_form')[1]
        except ValueError:
            compose_form_id = False 
        if context is None:
            context = {}
        ctx = context.copy()
        ctx.update({
            'default_model': 'crm.lead',
            'default_res_id': ids[0],
            'default_use_template': bool(template_id),
            'default_template_id': template_id,
            'default_composition_mode': 'comment',
        })
        return {
            'type': 'ir.actions.act_window',
            'view_type': 'form',
            'view_mode': 'form',
            'res_model': 'mail.compose.message',
            'views': [(compose_form_id, 'form')],
            'view_id': compose_form_id,
            'target': 'new',
            'context': ctx,
        }

    # ----------------------------------------
    # Mail Gateway
    # ----------------------------------------

    def message_get_reply_to(self, cr, uid, ids, context=None):
        """ Override to get the reply_to of the parent project. """
        return [lead.section_id.message_get_reply_to()[0] if lead.section_id else False
                    for lead in self.browse(cr, uid, ids, context=context)]

    def message_new(self, cr, uid, msg, custom_values=None, context=None):
        """ Overrides mail_thread message_new that is called by the mailgateway
            through message_process.
            This override updates the document according to the email.
        """
        if custom_values is None: custom_values = {}

        desc = html2plaintext(msg.get('body')) if msg.get('body') else ''
        defaults = {
            'name':  msg.get('subject') or _("No Subject"),
            'description': desc,
            'email_from': msg.get('from'),
            'email_cc': msg.get('cc'),
            'partner_id': msg.get('author_id', False),
            'user_id': False,
        }
        if msg.get('author_id'):
            defaults.update(self.on_change_partner(cr, uid, None, msg.get('author_id'), context=context)['value'])
        if msg.get('priority') in dict(crm.AVAILABLE_PRIORITIES):
            defaults['priority'] = msg.get('priority')
        defaults.update(custom_values)
        return super(crm_lead, self).message_new(cr, uid, msg, custom_values=defaults, context=context)

    def message_update(self, cr, uid, ids, msg, update_vals=None, context=None):
        """ Overrides mail_thread message_update that is called by the mailgateway
            through message_process.
            This method updates the document according to the email.
        """
        if isinstance(ids, (str, int, long)):
            ids = [ids]
        if update_vals is None: update_vals = {}

        if msg.get('priority') in dict(crm.AVAILABLE_PRIORITIES):
            update_vals['priority'] = msg.get('priority')
        maps = {
            'cost':'planned_cost',
            'revenue': 'planned_revenue',
            'probability':'probability',
        }
        for line in msg.get('body', '').split('\n'):
            line = line.strip()
            res = tools.command_re.match(line)
            if res and maps.get(res.group(1).lower()):
                key = maps.get(res.group(1).lower())
                update_vals[key] = res.group(2).lower()

        return super(crm_lead, self).message_update(cr, uid, ids, msg, update_vals=update_vals, context=context)

    # ----------------------------------------
    # OpenChatter methods and notifications
    # ----------------------------------------

    def schedule_phonecall_send_note(self, cr, uid, ids, phonecall_id, action, context=None):
        phonecall = self.pool.get('crm.phonecall').browse(cr, uid, [phonecall_id], context=context)[0]
        if action == 'log': prefix = 'Logged'
        else: prefix = 'Scheduled'
        message = _("<b>%s a call</b> for the <em>%s</em>.") % (prefix, phonecall.date)
        return self.message_post(cr, uid, ids, body=message, context=context)

    def onchange_state(self, cr, uid, ids, state_id, context=None):
        if state_id:
            country_id=self.pool.get('res.country.state').browse(cr, uid, state_id, context).country_id.id
            return {'value':{'country_id':country_id}}
        return {}
class base_action_rule(osv.osv):
    """ Base Action Rules """

    _name = 'base.action.rule'
    _description = 'Action Rules'
    _order = 'sequence'

    _columns = {
        'name':  fields.char('Rule Name', required=True),
        'model_id': fields.many2one('ir.model', 'Related Document Model',
            required=True, domain=[('transient', '=', False)]),
        'model': fields.related('model_id', 'model', type="char", string='Model'),
        'create_date': fields.datetime('Create Date', readonly=1),
        'active': fields.boolean('Active',
            help="When unchecked, the rule is hidden and will not be executed."),
        'sequence': fields.integer('Sequence',
            help="Gives the sequence order when displaying a list of rules."),
        'kind': fields.selection(
            [('on_create', 'On Creation'),
             ('on_write', 'On Update'),
             ('on_create_or_write', 'On Creation & Update'),
             ('on_unlink', 'On Deletion'),
             ('on_change', 'Based on Form Modification'),
             ('on_time', 'Based on Timed Condition')],
            string='When to Run'),
        'trg_date_id': fields.many2one('ir.model.fields', string='Trigger Date',
            help="When should the condition be triggered. If present, will be checked by the scheduler. If empty, will be checked at creation and update.",
            domain="[('model_id', '=', model_id), ('ttype', 'in', ('date', 'datetime'))]"),
        'trg_date_range': fields.integer('Delay after trigger date',
            help="Delay after the trigger date." \
            "You can put a negative number if you need a delay before the" \
            "trigger date, like sending a reminder 15 minutes before a meeting."),
        'trg_date_range_type': fields.selection([('minutes', 'Minutes'), ('hour', 'Hours'),
                                ('day', 'Days'), ('month', 'Months')], 'Delay type'),
        'trg_date_calendar_id': fields.many2one(
            'resource.calendar', 'Use Calendar',
            help='When calculating a day-based timed condition, it is possible to use a calendar to compute the date based on working days.',
            ondelete='set null',
        ),
        'act_user_id': fields.many2one('res.users', 'Set Responsible'),
        'act_followers': fields.many2many("res.partner", string="Add Followers"),
        'server_action_ids': fields.many2many('ir.actions.server', string='Server Actions',
            domain="[('model_id', '=', model_id)]",
            help="Examples: email reminders, call object service, etc."),
        'filter_pre_id': fields.many2one(
            'ir.filters', string='Before Update Filter',
            ondelete='restrict', domain="[('model_id', '=', model_id.model)]",
            help="If present, this condition must be satisfied before the update of the record."),
        'filter_pre_domain': fields.char(string='Before Update Domain', help="If present, this condition must be satisfied before the update of the record."),
        'filter_id': fields.many2one(
            'ir.filters', string='Filter',
            ondelete='restrict', domain="[('model_id', '=', model_id.model)]",
            help="If present, this condition must be satisfied before executing the action rule."),
        'filter_domain': fields.char(string='Domain', help="If present, this condition must be satisfied before executing the action rule."),
        'last_run': fields.datetime('Last Run', readonly=1, copy=False),
        'on_change_fields': fields.char(string="On Change Fields Trigger",
            help="Comma-separated list of field names that triggers the onchange."),
    }

    # which fields have an impact on the registry
    CRITICAL_FIELDS = ['model_id', 'active', 'kind', 'on_change_fields']

    _defaults = {
        'active': True,
        'trg_date_range_type': 'day',
    }

    def onchange_kind(self, cr, uid, ids, kind, context=None):
        clear_fields = []
        if kind in ['on_create', 'on_create_or_write', 'on_unlink']:
            clear_fields = [
                'filter_pre_id', 'filter_pre_domain', 'trg_date_id',
                'trg_date_range', 'trg_date_range_type'
            ]
        elif kind in ['on_write', 'on_create_or_write']:
            clear_fields = [
                'trg_date_id', 'trg_date_range', 'trg_date_range_type'
            ]
        elif kind == 'on_time':
            clear_fields = ['filter_pre_id', 'filter_pre_domain']
        return {'value': dict.fromkeys(clear_fields, False)}

    def onchange_filter_pre_id(self,
                               cr,
                               uid,
                               ids,
                               filter_pre_id,
                               context=None):
        ir_filter = self.pool['ir.filters'].browse(cr,
                                                   uid,
                                                   filter_pre_id,
                                                   context=context)
        return {'value': {'filter_pre_domain': ir_filter.domain}}

    def onchange_filter_id(self, cr, uid, ids, filter_id, context=None):
        ir_filter = self.pool['ir.filters'].browse(cr,
                                                   uid,
                                                   filter_id,
                                                   context=context)
        return {'value': {'filter_domain': ir_filter.domain}}

    @openerp.api.model
    def _get_actions(self, records, kinds):
        """ Return the actions of the given kinds for records' model. The
        returned actions' context contain an object to manage processing.
        """
        if '__action_done' not in self._context:
            self = self.with_context(__action_done={})
        domain = [('model', '=', records._name), ('kind', 'in', kinds)]
        actions = self.with_context(active_test=True).search(domain)
        return actions.with_env(self.env)

    @openerp.api.model
    def _get_eval_context(self):
        """ Prepare the context used when evaluating python code
        :returns: dict -- evaluation context given to (safe_)eval """
        return {
            'datetime': DT,
            'dateutil': dateutil,
            'time': time,
            'uid': self.env.uid,
            'user': self.env.user,
        }

    @openerp.api.model
    def _filter_pre(self, records):
        """ Filter the records that satisfy the precondition of action ``self``. """
        if self.filter_pre_id and records:
            eval_context = self._get_eval_context()
            domain = [('id', 'in', records.ids)] + eval(
                self.filter_pre_id.domain, eval_context)
            ctx = eval(self.filter_pre_id.context)
            return records.with_context(**ctx).search(domain).with_env(
                records.env)
        elif self.filter_pre_domain and records:
            eval_context = self._get_eval_context()
            domain = [('id', 'in', records.ids)] + eval(
                self.filter_pre_domain, eval_context)
            return records.search(domain)
        else:
            return records

    @openerp.api.model
    def _filter_post(self, records):
        """ Filter the records that satisfy the postcondition of action ``self``. """
        if self.filter_id and records:
            eval_context = self._get_eval_context()
            domain = [('id', 'in', records.ids)] + eval(
                self.filter_id.domain, eval_context)
            ctx = eval(self.filter_id.context)
            return records.with_context(**ctx).search(domain).with_env(
                records.env)
        elif self.filter_domain and records:
            eval_context = self._get_eval_context()
            domain = [('id', 'in', records.ids)] + eval(
                self.filter_domain, eval_context)
            return records.search(domain)
        else:
            return records

    @openerp.api.multi
    def _process(self, records):
        """ Process action ``self`` on the ``records`` that have not been done yet. """
        # filter out the records on which self has already been done, then mark
        # remaining records as done (to avoid recursive processing)
        action_done = self._context['__action_done']
        records -= action_done.setdefault(self, records.browse())
        if not records:
            return
        action_done[self] |= records

        # modify records
        values = {}
        if 'date_action_last' in records._fields:
            values['date_action_last'] = openerp.fields.Datetime.now()
        if self.act_user_id and 'user_id' in records._fields:
            values['user_id'] = self.act_user_id.id
        if values:
            records.write(values)

        # subscribe followers
        if self.act_followers and hasattr(records, 'message_subscribe'):
            records.message_subscribe(self.act_followers.ids)

        # execute server actions
        if self.server_action_ids:
            for record in records:
                ctx = {
                    'active_model': record._name,
                    'active_ids': record.ids,
                    'active_id': record.id
                }
                self.server_action_ids.with_context(**ctx).run()

    def _register_hook(self, cr):
        """ Patch models that should trigger action rules based on creation,
        modification, deletion of records and form onchanges.
        """

        #
        # Note: the patched methods must be defined inside another function,
        # otherwise their closure may be wrong. For instance, the function
        # create refers to the outer variable 'create', which you expect to be
        # bound to create itself. But that expectation is wrong if create is
        # defined inside a loop; in that case, the variable 'create' is bound to
        # the last function defined by the loop.
        #

        def make_create():
            """ Instanciate a create method that processes action rules. """
            @openerp.api.model
            def create(self, vals, **kw):
                # retrieve the action rules to possibly execute
                actions = self.env['base.action.rule']._get_actions(
                    self, ['on_create', 'on_create_or_write'])

                # call original method
                record = create.origin(self.with_env(actions.env), vals, **kw)

                # check postconditions, and execute actions on the records that satisfy them
                for action in actions.with_context(old_values=None):
                    action._process(action._filter_post(record))

                return record.with_env(self.env)

            return create

        def make_write():
            """ Instanciate a _write method that processes action rules. """
            #
            # Note: we patch method _write() instead of write() in order to
            # catch updates made by field recomputations.
            #
            @openerp.api.multi
            def _write(self, vals, **kw):
                # retrieve the action rules to possibly execute
                actions = self.env['base.action.rule']._get_actions(
                    self, ['on_write', 'on_create_or_write'])
                records = self.with_env(actions.env)

                # check preconditions on records
                pre = {
                    action: action._filter_pre(records)
                    for action in actions
                }

                # read old values before the update
                old_values = {
                    old_vals.pop('id'): old_vals
                    for old_vals in records.read(list(vals))
                }

                # call original method
                _write.origin(records, vals, **kw)

                # check postconditions, and execute actions on the records that satisfy them
                for action in actions.with_context(old_values=old_values):
                    action._process(action._filter_post(pre[action]))
                return True

            return _write

        def make_unlink():
            """ Instanciate an unlink method that processes action rules. """
            @openerp.api.multi
            def unlink(self, **kwargs):
                # retrieve the action rules to possibly execute
                actions = self.env['base.action.rule']._get_actions(
                    self, ['on_unlink'])
                records = self.with_env(actions.env)

                # check conditions, and execute actions on the records that satisfy them
                for action in actions:
                    action._process(action._filter_post(pre[action]))

                # call original method
                return unlink.origin(self, **kwargs)

            return unlink

        def make_onchange(action_rule_id):
            """ Instanciate an onchange method for the given action rule. """
            def base_action_rule_onchange(self):
                action_rule = self.env['base.action.rule'].browse(
                    action_rule_id)
                server_actions = action_rule.server_action_ids.with_context(
                    active_model=self._name, onchange_self=self)
                result = {}
                for server_action in server_actions:
                    res = server_action.run()
                    if res and 'value' in res:
                        res['value'].pop('id', None)
                        self.update(
                            self._convert_to_cache(res['value'],
                                                   validate=False))
                    if res and 'domain' in res:
                        result.setdefault('domain', {}).update(res['domain'])
                    if res and 'warning' in res:
                        result['warning'] = res['warning']
                return result

            return base_action_rule_onchange

        patched_models = defaultdict(set)

        def patch(model, name, method):
            """ Patch method `name` on `model`, unless it has been patched already. """
            if model not in patched_models[name]:
                patched_models[name].add(model)
                model._patch_method(name, method)

        # retrieve all actions, and patch their corresponding model
        ids = self.search(cr, SUPERUSER_ID, [])
        for action_rule in self.browse(cr, SUPERUSER_ID, ids):
            model = action_rule.model_id.model
            model_obj = self.pool.get(model)
            if not model_obj:
                continue

            if action_rule.kind == 'on_create':
                patch(model_obj, 'create', make_create())

            elif action_rule.kind == 'on_create_or_write':
                patch(model_obj, 'create', make_create())
                patch(model_obj, '_write', make_write())

            elif action_rule.kind == 'on_write':
                patch(model_obj, '_write', make_write())

            elif action_rule.kind == 'on_unlink':
                patch(model_obj, 'unlink', make_unlink())

            elif action_rule.kind == 'on_change':
                # register an onchange method for the action_rule
                method = make_onchange(action_rule.id)
                for field_name in action_rule.on_change_fields.split(","):
                    field_name = field_name.strip()
                    model_obj._onchange_methods[field_name].append(method)

    def _update_cron(self, cr, uid, context=None):
        """ Activate the cron job depending on whether there exists action rules
        based on time conditions. """
        try:
            cron = self.pool['ir.model.data'].get_object(cr,
                                                         uid,
                                                         'base_action_rule',
                                                         'ir_cron_crm_action',
                                                         context=context)
        except ValueError:
            return False

        return cron.toggle(model=self._name, domain=[('kind', '=', 'on_time')])

    def _update_registry(self, cr, uid, context=None):
        """ Update the registry after a modification on action rules. """
        if self.pool.ready:
            # for the sake of simplicity, simply force the registry to reload
            cr.commit()
            openerp.api.Environment.reset()
            RegistryManager.new(cr.dbname)
            RegistryManager.signal_registry_change(cr.dbname)

    def create(self, cr, uid, vals, context=None):
        res_id = super(base_action_rule, self).create(cr,
                                                      uid,
                                                      vals,
                                                      context=context)
        self._update_cron(cr, uid, context=context)
        self._update_registry(cr, uid, context=context)
        return res_id

    def write(self, cr, uid, ids, vals, context=None):
        super(base_action_rule, self).write(cr,
                                            uid,
                                            ids,
                                            vals,
                                            context=context)
        if set(vals) & set(self.CRITICAL_FIELDS):
            self._update_cron(cr, uid, context=context)
            self._update_registry(cr, uid, context=context)
        return True

    def unlink(self, cr, uid, ids, context=None):
        res = super(base_action_rule, self).unlink(cr,
                                                   uid,
                                                   ids,
                                                   context=context)
        self._update_cron(cr, uid, context=context)
        self._update_registry(cr, uid, context=context)
        return res

    def onchange_model_id(self, cr, uid, ids, model_id, context=None):
        data = {'model': False, 'filter_pre_id': False, 'filter_id': False}
        if model_id:
            model = self.pool.get('ir.model').browse(cr,
                                                     uid,
                                                     model_id,
                                                     context=context)
            data.update({'model': model.model})
        return {'value': data}

    def _check_delay(self, cr, uid, action, record, record_dt, context=None):
        if action.trg_date_calendar_id and action.trg_date_range_type == 'day':
            start_dt = get_datetime(record_dt)
            action_dt = self.pool['resource.calendar'].schedule_days_get_date(
                cr,
                uid,
                action.trg_date_calendar_id.id,
                action.trg_date_range,
                day_date=start_dt,
                compute_leaves=True,
                context=context)
        else:
            delay = DATE_RANGE_FUNCTION[action.trg_date_range_type](
                action.trg_date_range)
            action_dt = get_datetime(record_dt) + delay
        return action_dt

    def _check(self,
               cr,
               uid,
               automatic=False,
               use_new_cursor=False,
               context=None):
        """ This Function is called by scheduler. """
        context = context or {}
        if '__action_done' not in context:
            context = dict(context, __action_done={})
        # retrieve all the action rules to run based on a timed condition
        action_dom = [('kind', '=', 'on_time')]
        action_ids = self.search(cr,
                                 uid,
                                 action_dom,
                                 context=dict(context, active_test=True))
        eval_context = self._get_eval_context(cr, uid, context=context)
        for action in self.browse(cr, uid, action_ids, context=context):
            now = datetime.now()
            if action.last_run:
                last_run = get_datetime(action.last_run)
            else:
                last_run = datetime.utcfromtimestamp(0)
            # retrieve all the records that satisfy the action's condition
            model = self.pool[action.model_id.model]
            domain = []
            ctx = dict(context)
            if action.filter_domain is not False:
                domain = eval(action.filter_domain, eval_context)
            elif action.filter_id:
                domain = eval(action.filter_id.domain, eval_context)
                ctx.update(eval(action.filter_id.context))
                if 'lang' not in ctx:
                    # Filters might be language-sensitive, attempt to reuse creator lang
                    # as we are usually running this as super-user in background
                    [filter_meta] = action.filter_id.get_metadata()
                    user_id = filter_meta['write_uid'] and filter_meta['write_uid'][0] or \
                                    filter_meta['create_uid'][0]
                    ctx['lang'] = self.pool['res.users'].browse(
                        cr, uid, user_id).lang
            record_ids = model.search(cr, uid, domain, context=ctx)

            # determine when action should occur for the records
            date_field = action.trg_date_id.name
            if date_field == 'date_action_last' and 'create_date' in model._fields:
                get_record_dt = lambda record: record[date_field
                                                      ] or record.create_date
            else:
                get_record_dt = lambda record: record[date_field]

            # process action on the records that should be executed
            for record in model.browse(cr, uid, record_ids, context=context):
                record_dt = get_record_dt(record)
                if not record_dt:
                    continue
                action_dt = self._check_delay(cr,
                                              uid,
                                              action,
                                              record,
                                              record_dt,
                                              context=context)
                if last_run <= action_dt < now:
                    try:
                        action._process(record)
                    except Exception:
                        import traceback
                        _logger.error(traceback.format_exc())

            action.write(
                {'last_run': now.strftime(DEFAULT_SERVER_DATETIME_FORMAT)})

            if automatic:
                # auto-commit for batch processing
                cr.commit()
Example #11
0
                except Exception, e:
                    stack = traceback.format_exc()
                    self.pool.get('checklist.exception').create(cr, uid, {'checklist_task_id': instance.checklist_task_id.id,
                                                                          'exception_type': 'field', 'res_id': instance.res_id,
                                                                          'field_id': field.id, 'exception': e, 'stack': stack})
                    continue
        return res

    def _get_checklist_task_instance_ids(self, cr, uid, ids, context={}):
        if isinstance(ids, (int, long)):
            ids = [ids]
        return self.pool.get('checklist.task.instance').search(cr, uid, [('checklist_task_id', 'in', ids)])

    _columns = {
        'checklist_task_id': fields.many2one('checklist.task', 'Checklist Task', required=True, ondelete='cascade'),
        'checklist_id': fields.related('checklist_task_id', 'checklist_id', type='many2one', relation='checklist', string='Checklist'),
        'model_id': fields.related('checklist_id', 'model_id', type='many2one', relation='ir.model', string='Model'),
        'name': fields.related('checklist_task_id', 'name', type='char', size=128, string='Name'),
        'mandatory': fields.related('checklist_task_id', 'mandatory', type='boolean', string='Mandatory', help='Required to make active object'),
        'res_id': fields.integer('Resource ID', select=True, required=True),
        'active': fields.function(_get_activity, type='boolean', string='Active', store=False, multi='activity'),
        'sequence': fields.function(_get_activity, type='integer', string='Priority', store={
            'checklist.task': (_get_checklist_task_instance_ids, ['sequence'], 10),
        }, multi='activity'),
        'field_ids_to_fill': fields.function(_get_activity, type='one2many', relation='checklist.task.field',
                                             string='Fields to fill', store=False, multi='activity'),
        'field_ids_filled': fields.function(_get_activity, type='one2many', relation='checklist.task.field',
                                            string='Filled fields', store=False, multi='activity'),
        'progress_rate': fields.float('Progress Rate', digits=(16, 2)),
    }
Example #12
0
class hon_issue(orm.Model):

    _name = "hon.issue"

    def _invoiced_rate(self, cursor, user, ids, name, arg, context=None):
        res = {}
        for issue in self.browse(cursor, user, ids, context=context):
            if issue.invoiced:
                res[issue.id] = 100.0
                continue
            tot = 0.0
            for invoice in issue.invoice_ids:
                if invoice.state not in ('draft', 'cancel'):
                    tot += invoice.amount_untaxed
            if tot:
                res[issue.id] = min(100.0, tot * 100.0 / (issue.amount_untaxed or 1.00))
            else:
                res[issue.id] = 0.0
        return res

    def _invoice_exists(self, cursor, user, ids, name, arg, context=None):
        res = {}
        for issue in self.browse(cursor, user, ids, context=context):
            res[issue.id] = False
            if issue.invoice_ids:
                res[issue.id] = True
        return res

    def _invoiced(self, cursor, user, ids, name, arg, context=None):
        res = {}
        for issue in self.browse(cursor, user, ids, context=context):
            res[issue.id] = True
            for line in issue.hon_issue_line:
                if not line.invoice_line_id and not line.employee and not line.gratis:
                    res[issue.id] = False
        return res

    def _invoiced_search(self, cursor, user, obj, name, args, context=None):
        if not len(args):
            return []
        clause = ''
        issue_clause = ''
        no_invoiced = False
        for arg in args:
            if (arg[1] == '=' and arg[2]) or (arg[1] == '!=' and not arg[2]):
                clause += 'AND inv.state = \'paid\''
            else:
                clause += 'AND inv.state != \'cancel\' AND issue.state != \'cancel\'  AND inv.state <> \'paid\'  AND rel.issue_id = issue.id '
                issue_clause = ',  hon_issue AS issue '
                no_invoiced = True

        cursor.execute('SELECT rel.issue_id ' \
                       'FROM hon_issue_invoice_rel AS rel, account_invoice AS inv '+ issue_clause + \
                       'WHERE rel.invoice_id = inv.id ' + clause)
        res = cursor.fetchall()
        if no_invoiced:
            cursor.execute('SELECT issue.id ' \
                           'FROM hon_issue AS issue ' \
                           'WHERE issue.id NOT IN ' \
                           '(SELECT rel.issue_id ' \
                           'FROM hon_issue_invoice_rel AS rel) and issue.state != \'cancel\'')
            res.extend(cursor.fetchall())
        if not res:
            return [('id', '=', 0)]
        return [('id', 'in', [x[0] for x in res])]


    _columns = {
        # 'account_analytic_id': fields.many2one('account.analytic.account', 'Title/Issue',
        #                                        required=True, readonly=True, states = {'draft': [('readonly', False)]},
        #                                         domain=[('type','!=','view'), ('portal_sub', '=', True), ('parent_id.is_hon', '=', True)]),
        'account_analytic_id': fields.many2one('account.analytic.account', 'Title/Issue',
                                               required=True, readonly=True, states = {'draft': [('readonly', False)]},
                                                domain=[('portal_sub', '=', True)]),
        'date_publish': fields.related('account_analytic_id','date_publish',type='date',
                                       relation='account.analytic.account',string='Publishing Date', store=True, readonly=True),
        'name': fields.related('account_analytic_id', 'name', type='char',
                                       relation='account.analytic.account', string='Name', store=True,
                                       readonly=True),
        'company_id': fields.many2one('res.company', 'Company', required=True, change_default=True, readonly=True, states={'draft':[('readonly',False)]}),
        'hon_issue_line': fields.one2many('hon.issue.line', 'issue_id', 'Hon Lines', readonly=False, states={'draft':[('readonly',False)]}),
        'state': fields.selection([
            ('cancel', 'Cancelled'),
            ('draft','Draft'),
            ('open','Open'),
            ('done', 'Done'),
            ],'Status', select=True, readonly=True,
            help=' * The \'Draft\' status is used when a user is encoding a new and unconfirmed Honorarium Issue. \
            \n* The \'Open\' status is used when user create invoice.\
            \n* The \'Cancelled\' status is used when user cancel Honorarium Issue.'),
        'comment': fields.text('Additional Information'),
        'invoice_ids': fields.many2many('account.invoice', 'hon_issue_invoice_rel', 'issue_id', 'invoice_id',
                                        'Invoices', readonly=True,
                                        help="This is the list of invoices that have been generated for this issue. "
                                             "The same issue may have been invoiced several times (by line for example)."),
        'invoiced_rate': fields.function(_invoiced_rate, string='Invoiced Ratio', type='float'),
        'invoiced': fields.function(_invoiced, string='Invoiced',
                                    fnct_search=_invoiced_search, type='boolean',
                                    help="It indicates that all issue lines have been invoiced."),
        'invoice_exists': fields.function(_invoice_exists, string='Invoiced',
                                          fnct_search=_invoiced_search, type='boolean',
                                          help="It indicates that hon issue has at least one invoice."),
    }

    _defaults = {
        'company_id': lambda self,cr,uid,c:
            self.pool.get('res.company')._company_default_get(cr, uid, 'hon.issue', context=c),
        'state': 'draft',
        'account_analytic_id': False,
    }
    _sql_constraints = [
        ('account_analytic_company_uniq', 'unique (account_analytic_id, company_id)', 'The Issue must be unique per company !'),
    ]


    def onchange_analytic_ac(self, cr, uid, ids, analytic, context={}):
        res = {}
        if not ids and not analytic :
            return res
        war = {}

        analytic_account = self.pool['account.analytic.account'].browse(cr, uid, analytic, context)
        res['name'] = analytic_account.name
        res['date_publish'] = analytic_account.date_publish
        llist = []
        if ids:
            iss_obj = self.browse(cr,uid,ids)
            if iss_obj[0].hon_issue_line:
                for line in iss_obj[0].hon_issue_line:
                    if line.activity_id:
                        llist.append((1, line.id, {'activity_id': [],}))
                        res['hon_issue_line'] = llist
                        war['title'] = 'Let op!'
                        war['message'] = 'U heeft de Titel/Nummer aangepast. Nu moet u opnieuw Redacties selecteren in de HONregel(s)'
        return {'value': res, 'warning': war}

    def manual_invoice(self, cr, uid, ids, context=None):
        '''
        create invoices for the given hon issues (ids), and open the form
        view of one of the newly created invoices
        '''

        mod_obj = self.pool.get('ir.model.data')

        inv_ids0 = set(inv.id for issue in self.browse(cr, uid, ids, context) for inv in issue.invoice_ids)
        self.action_invoice_create(cr, uid, ids, date_invoice=False, context=None)
        inv_ids1 = set(inv.id for issue in self.browse(cr, uid, ids, context) for inv in issue.invoice_ids)

        # determine newly created invoices
        new_inv_ids = list(inv_ids1 - inv_ids0)
        res = mod_obj.get_object_reference(cr, uid, 'account', 'invoice_supplier_form')
        res_id = res and res[1] or False,

        return {
           'name': _('Supplier Invoices'),
           'view_type': 'form',
           'view_mode': 'form',
           'view_id': [res_id],
           'res_model': 'account.invoice',
           'context': "{'type':'in_invoice'}",
           'type': 'ir.actions.act_window',
           'nodestroy': True,
           'target': 'current',
           'res_id': new_inv_ids and new_inv_ids[0] or False,
            }

    def action_view_invoice(self, cr, uid, ids, context=None):
        '''
        This function returns an action that display existing invoices of given hon issue ids. It can either be a in a list or in a form view, if there is only one invoice to show.
        '''
        mod_obj = self.pool.get('ir.model.data')
        act_obj = self.pool.get('ir.actions.act_window')

        result = mod_obj.get_object_reference(cr, uid, 'account', 'action_invoice_tree2')
        id = result and result[1] or False
        result = act_obj.read(cr, uid, [id], context=context)[0]
        #compute the number of invoices to display
        inv_ids = []
        for so in self.browse(cr, uid, ids, context=context):
            inv_ids += [invoice.id for invoice in so.invoice_ids]
        #choose the view_mode accordingly
        if len(inv_ids)>1:
            result['domain'] = "[('id','in',["+','.join(map(str, inv_ids))+"])]"
        else:
            res = mod_obj.get_object_reference(cr, uid, 'account', 'invoice_supplier_form')
            result['views'] = [(res and res[1] or False, 'form')]
            result['res_id'] = inv_ids and inv_ids[0] or False
        return result

    def action_invoice_create(self, cr, uid, ids, date_invoice=False, context=None):
        if context is None:
            context = {}
        # If date was specified, use it as date invoiced, useful when invoices are generated this month and put the
        # last day of the last month as invoice date
        if date_invoice:
            context['date_invoice'] = date_invoice
        if ids:
            context['active_ids'] = ids
        himi = self.pool['hon.issue.make.invoice']
        himi.make_invoices_from_issues(cr, uid, ids, context=context)
        return True


    def action_button_confirm(self, cr, uid, ids, context=None):
        assert len(ids) == 1, 'This option should only be used for a single id at a time.'
        wf_service = netsvc.LocalService('workflow')
        wf_service.trg_validate(uid, 'hon.issue', ids[0], 'issue_confirm', cr)
        return True

    def unlink(self, cr, uid, ids, context=None):
        issues = self.read(cr, uid, ids, ['state'], context=context)
        unlink_ids = []
        for s in issues:
            if s['state'] in ['draft', 'cancel']:
                unlink_ids.append(s['id'])
            else:
                raise osv.except_osv(_('Invalid Action!'), _('In order to delete a confirmed issue, you must cancel it before!'))

        return osv.osv.unlink(self, cr, uid, unlink_ids, context=context)

    def action_wait(self, cr, uid, ids, context=None):
        context = context or {}
        for o in self.browse(cr, uid, ids):
            if not o.hon_issue_line:
                raise osv.except_osv(_('Error!'),_('You cannot confirm a hon issue which has no line.'))
            self.write(cr, uid, [o.id], {'state': 'open', })
            self.pool.get('hon.issue.line').button_confirm(cr, uid, [x.id for x in o.hon_issue_line])
        return True

    def action_unwait(self, cr, uid, ids, context=None):
        context = context or {}
        for o in self.browse(cr, uid, ids):
            if not o.hon_issue_line:
                raise osv.except_osv(_('Error!'),_('You cannot unconfirm a hon issue which has no line.'))
            self.write(cr, uid, [o.id], {'state': 'draft', })
            self.pool.get('hon.issue.line').button_unconfirm(cr, uid, [x.id for x in o.hon_issue_line])
        return True

    def action_cancel(self, cr, uid, ids, context=None):
        wf_service = netsvc.LocalService("workflow")
        if context is None:
            context = {}
        hon_issue_line_obj = self.pool.get('hon.issue.line')
        for issue in self.browse(cr, uid, ids, context=context):
            for inv in issue.invoice_ids:
                if inv.state not in ('draft', 'cancel'):
                    raise osv.except_osv(
                        _('Cannot cancel this issue!'),
                        _('First cancel all invoices attached to this issue.'))
            for r in self.read(cr, uid, ids, ['invoice_ids']):
                for inv in r['invoice_ids']:
                    wf_service.trg_validate(uid, 'account.invoice', inv, 'invoice_cancel', cr)
                    cr.execute('delete from hon_issue_invoice_rel where issue_id=%s and invoice_id=%s',
                               (issue.id, inv))
            hon_issue_line_obj.write(cr, uid, [l.id for l in issue.hon_issue_line],
                    {'state': 'cancel','invoice_line_id': False})

        self.write(cr, uid, ids, {'state': 'cancel'})
        return True

    # go from canceled state to draft state
    def action_cancel_draft(self, cr, uid, ids, *args):
        self.write(cr, uid, ids, {'state':'draft'})
        wf_service = netsvc.LocalService("workflow")
        for issue_id in ids:
            wf_service.trg_delete(uid, 'hon.issue', issue_id, cr)
            wf_service.trg_create(uid, 'hon.issue', issue_id, cr)
        return True

    def action_done(self, cr, uid, ids, context=None):
        data_hon = self.browse(cr, uid, ids, context=context)
        a = []
        for issue in data_hon:
            if issue.invoiced:
                a.append(issue.id)
            else:
                raise osv.except_osv(
                        _('Cannot finalise this issue!'),
                        _('First invoice all hon_lines attached to this issue.'))
        return self.write(cr, uid, a, {'state': 'done'}, context=context)
Example #13
0
#but WITHOUT ANY WARRANTY; without even the implied warranty of               #
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                #
#GNU Affero General Public License for more details.                          #
#                                                                             #
#You should have received a copy of the GNU Affero General Public License     #
#along with this program.  If not, see <http://www.gnu.org/licenses/>.        #
###############################################################################

from openerp.osv import orm, fields

FISCAL_POSITION_COLUMNS = {
    'name': fields.char('Fiscal Position', size=128, required=True),
    'fiscal_category_id': fields.many2one(
        'l10n_br_account.fiscal.category', 'Categoria Fiscal'),
    'fiscal_category_fiscal_type': fields.related(
        'fiscal_category_id', 'fiscal_type', type='char', readonly=True,
        relation='l10n_br_account.fiscal.category', store=True,
        string='Fiscal Type'),
    'type': fields.selection([('input', 'Entrada'), ('output', 'Saida')],
                             'Tipo'),
    'type_tax_use': fields.selection(
        [('sale', 'Sale'), ('purchase', 'Purchase'), ('all', 'All')],
        'Tax Application'),
    'inv_copy_note': fields.boolean(u'Copiar Observação na Nota Fiscal'),
    'asset_operation': fields.boolean(u'Operação de Aquisição de Ativo',
        help=u"""Caso seja marcada essa opção, será incluido o IPI na base de
            calculo do ICMS."""),
    'state': fields.selection([('draft', u'Rascunho'),
            ('review', u'Revisão'), ('approved', u'Aprovada'),
            ('unapproved', u'Não Aprovada')], 'Status', readonly=True,
            track_visibility='onchange', select=True),
}
Example #14
0
        '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([
Example #15
0
class stock_move(osv.osv):
    _inherit = "stock.move" 
    def _get_rec_info(self, cr, uid, ids, fields, args, context=None):
        result = {}
        for id in ids:
            result[id] = {'return_qty':0,}
        for m in self.browse(cr,uid,ids,context=context):
            return_qty = 0
            if m.state == 'done':
                for rec in m.move_history_ids2:
                    # only take into account 'product return' moves, ignoring any other
                    # kind of upstream moves, such as internal procurements, etc.
                    # a valid return move will be the exact opposite of ours:
                    #     (src location, dest location) <=> (dest location, src location))
                    if rec.state != 'cancel' \
                        and rec.location_dest_id.id == m.location_id.id \
                        and rec.location_id.id == m.location_dest_id.id:
                        return_qty += self.pool.get('product.uom')._compute_qty(cr, uid, m.product_uom.id, rec.product_qty, rec.product_uom.id)
            #calculate the product base uom quantity
            product_uom_base_qty = m.product_qty
            if m.product_uom.id != m.product_id.uom_id.id:
                product_uom_base_qty = self.pool.get('product.uom')._compute_qty_obj(cr, uid, m.product_uom, m.product_qty, m.product_id.uom_id)
            
            result[m.id].update({'return_qty':return_qty,'product_uom_base_qty':product_uom_base_qty})
        return result    
    _columns = {
        'type': fields.related('picking_id', 'type', type='selection', selection=[('out', 'Sending Goods'), ('in', 'Getting Goods'), ('internal', 'Internal'), ('mr', 'Material Request'), ('mrr', 'Material Return')], string='Shipping Type'),
        'create_uid': fields.many2one('res.users', 'Creator',readonly=True),
        'supplier_prod_name': fields.related('purchase_line_id', 'supplier_prod_name',string='Supplier Product Name',type="char",readonly=True,store=True),
        'return_qty': fields.function(_get_rec_info, type='float', string='Return Quantity', multi="rec_info", digits_compute=dp.get_precision('Product Price')),
        #make the price's decimal precision as the 'Product Price'
        'price_unit': fields.float('Unit Price', digits_compute= dp.get_precision('Product Price'), help="Technical field used to record the product cost set by the user during a picking confirmation (when average price costing method is used)"),
        'product_qty': fields.float('Quantity', digits_compute=dp.get_precision('Product Price'),
            required=True,states={'done': [('readonly', True)]},
            help="This is the quantity of products from an inventory "
                "point of view. For moves in the state 'done', this is the "
                "quantity of products that were actually moved. For other "
                "moves, this is the quantity of product that is planned to "
                "be moved. Lowering this quantity does not generate a "
                "backorder. Changing this quantity on assigned moves affects "
                "the product reservation, and should be done with care."
        ),                
        'product_uom_base': fields.related('product_id','uom_id',type='many2one',relation='product.uom', string='Base UOM',readonly=True),
        'product_uom_base_qty': fields.function(_get_rec_info, type='float', string='Base Quantity', multi="rec_info", digits_compute=dp.get_precision('Product Unit of Measure'),readonly=True),
        'mfg_ids': fields.related('purchase_line_id','mfg_ids',type='many2many',relation='sale.product',string="MFG IDs"),      
    }

    def search(self, cr, user, args, offset=0, limit=None, order=None, context=None, count=False):
        #deal the 'date' datetime field query
        new_args = deal_args(self,args)
        return super(stock_move,self).search(cr, user, new_args, offset, limit, order, context, count)  

    def action_done(self, cr, uid, ids, context=None):
        resu = super(stock_move,self).action_done(cr, uid, ids, context) 
        move_ids = []
        for move in self.browse(cr, uid, ids, context=context):
            if move.state == 'done':
                move_ids.append(move.id)     
        self.write(cr, uid, move_ids, {'date': datetime.datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S')}, context=context)
        return resu  
    def _create_account_move_line(self, cr, uid, move, matches, src_account_id, dest_account_id, reference_amount, reference_currency_id, type='', context=None):
        val = super(stock_move,self)._create_account_move_line(cr, uid, move, matches, src_account_id, dest_account_id, reference_amount, reference_currency_id, type, context)
        #check if this move is a material request line move 
        mr_line = self.pool.get('material.request.line').browse(cr, uid, move.id, context=context)
        if mr_line.mr_sale_prod_id:
            #set the analytic_account_id to debit_line, the detail data ref _create_account_move_line() in product_fifo_lifo.stock.py
            if mr_line.mr_sale_prod_id.analytic_account_id and val and val[0]:
                if mr_line.pick_type == 'mr':
                    #debit dict data 
                    mline_data = val[0][2]
                else:
                    #credit dict data 
                    mline_data = val[1][2]
                mline_data.update({'analytic_account_id':mr_line.mr_sale_prod_id.analytic_account_id.id})
        return val
Example #16
0
class address_address(orm.Model):

    _name = 'address.address'
    _inherit = ['mozaik.abstract.model']
    _description = 'Address'

    # private methods

    def _get_technical_name(self, cr, uid, values, context=None):
        """
        This method produces a technical name with the content of values.
        :type values: dictionary
        :param values: used to create a technical address name
            ``country_id``
            ``address_local_zip``
            ``zip_man``
            ``town_man``
            ``address_local_street_id``
            ``street_man``
            ``number``
            ``box``
        :rparam: formated values of ``values`` join wit a `#`.
                0 if value is null
        """
        technical_value = []
        for field in values.keys():
            value = values[field] or u'0'
            technical_value.append(format_value(value))
        return '#'.join(technical_value)

    def _get_linked_coordinates(self, cr, uid, ids, context=None):
        return self.pool['postal.coordinate'].search(
            cr, uid, [('address_id', 'in', ids)], context=context)

    def _get_integral_address(self, cr, uid, ids, name, args, context=None):
        result = {
            i: {key: False
                for key in ['name', 'technical_name']}
            for i in ids
        }
        adrs_recs = self.browse(cr, uid, ids, context=context)
        for adrs in adrs_recs:
            elts = [
                adrs.street or False,
                adrs.sequence and '[%s]' % adrs.sequence or False,
                adrs.street and '-' or adrs.sequence and '-' or False,
                (adrs.country_code == 'BE') and adrs.zip or False,
                adrs.city or False,
                (adrs.country_code != 'BE') and '-' or False,
                (adrs.country_code != 'BE') and adrs.country_id.name or False,
            ]
            adr = ' '.join([el for el in elts if el])

            values = KEY_FIELDS.copy()
            for field in KEY_FIELDS.keys():
                to_evaluate = field if not KEY_FIELDS[field] else '%s.%s' % (
                    field, KEY_FIELDS[field])
                real_value = eval('adrs.%s' % to_evaluate)
                values[field] = real_value
            technical_name = self._get_technical_name(cr,
                                                      uid,
                                                      values,
                                                      context=context)

            result[adrs.id] = {
                'name': adr or False,
                'technical_name': technical_name or False,
            }
        return result

    def _get_street(self, cr, uid, ids, name, args, context=None):
        result = {i: False for i in ids}
        adrs_recs = self.browse(cr, uid, ids, context=context)
        for adrs in adrs_recs:
            number = adrs.number or '-'
            number = adrs.box and '%s/%s' % (number, adrs.box) or \
                adrs.number or False
            if adrs.address_local_street_id:
                street = adrs.select_alternative_address_local_street and \
                    adrs.address_local_street_id.local_street_alternative or \
                    adrs.address_local_street_id.local_street
            else:
                street = adrs.street_man or False
            result[adrs.id] = ' '.join([el for el in [street, number] if el])

        return result

    def _get_zip(self, cr, uid, ids, name, args, context=None):
        result = {i: {key: False
                      for key in [
                          'zip',
                          'city',
                      ]}
                  for i in ids}
        adrs_recs = self.browse(cr, uid, ids, context=context)
        for adrs in adrs_recs:
            result[adrs.id] = {
                'zip':
                adrs.address_local_zip_id
                and adrs.address_local_zip_id.local_zip or adrs.zip_man
                or False,
                'city':
                adrs.address_local_zip_id and adrs.address_local_zip_id.town
                or adrs.town_man or False,
            }

        return result

    _address_store_triggers = {
        # this MUST be executed in last for consistency: sequence is greater
        # than other
        'address.address':
        (lambda self, cr, uid, ids, context=None: ids, TRIGGER_FIELDS, 20),
        'address.local.zip':
        (lambda self, cr, uid, ids, context=None: self.pool[
            'address.local.zip']._get_linked_addresses(
                cr, uid, ids, context=context).ids, ['local_zip', 'town'], 15),
        'address.local.street':
        (lambda self, cr, uid, ids, context=None: self.pool[
            'address.local.street']._get_linked_addresses(
                cr, uid, ids, context=context),
         ['local_street', 'local_street_alternative'], 15),
        'res.country':
        (lambda self, cr, uid, ids, context=None: self.pool['res.country'].
         _get_linked_addresses(cr, uid, ids, context=context), ['name'], 15),
    }
    _zip_store_triggers = {
        'address.address': (lambda self, cr, uid, ids, context=None: ids,
                            ['address_local_zip_id', 'zip_man',
                             'town_man'], 10),
        'address.local.zip':
        (lambda self, cr, uid, ids, context=None: self.pool[
            'address.local.zip']._get_linked_addresses(
                cr, uid, ids, context=context).ids, ['local_zip', 'town'], 10),
    }
    _street_store_triggers = {
        'address.address': (lambda self, cr, uid, ids, context=None: ids, [
            'address_local_street_id',
            'select_alternative_address_local_street', 'street_man', 'number',
            'box'
        ], 10),
        'address.local.street':
        (lambda self, cr, uid, ids, context=None: self.pool[
            'address.local.street']._get_linked_addresses(
                cr, uid, ids, context=context),
         ['local_street', 'local_street_alternative'], 10),
    }

    _columns = {
        'id':
        fields.integer('ID', readonly=True),
        'name':
        fields.function(_get_integral_address,
                        string='Address',
                        type='char',
                        select=True,
                        multi='display_and_technical',
                        store=_address_store_triggers),
        'technical_name':
        fields.function(_get_integral_address,
                        string='Technical Name',
                        type='char',
                        select=True,
                        multi='display_and_technical',
                        store=_address_store_triggers),
        'country_id':
        fields.many2one('res.country',
                        'Country',
                        required=True,
                        select=True,
                        track_visibility='onchange'),
        'country_code':
        fields.related('country_id',
                       'code',
                       string='Country Code',
                       type='char'),
        'zip':
        fields.function(_get_zip,
                        string='Zip',
                        type='char',
                        multi='ZipAndCity',
                        store=_zip_store_triggers),
        'address_local_zip_id':
        fields.many2one('address.local.zip',
                        string='City',
                        track_visibility='onchange'),
        'zip_man':
        fields.char(string='Zip', track_visibility='onchange'),
        'city':
        fields.function(_get_zip,
                        string='City',
                        type='char',
                        multi='ZipAndCity',
                        store=_zip_store_triggers),
        'town_man':
        fields.char(string='Town', track_visibility='onchange'),
        'street':
        fields.function(_get_street,
                        string='Street',
                        type='char',
                        store=_street_store_triggers),
        'address_local_street_id':
        fields.many2one('address.local.street',
                        string='Reference Street',
                        track_visibility='onchange'),
        'select_alternative_address_local_street':
        fields.boolean('Use Alternative Reference Street',
                       track_visibility='onchange'),
        'street_man':
        fields.char(string='Street', track_visibility='onchange'),
        'street2':
        fields.char(string='Street2', track_visibility='onchange'),
        'number':
        fields.char(string='Number', track_visibility='onchange'),
        'box':
        fields.char(string='Box', track_visibility='onchange'),
        'sequence':
        fields.integer('Sequence',
                       track_visibility='onchange',
                       group_operator='min'),
        'postal_coordinate_ids':
        fields.one2many('postal.coordinate',
                        'address_id',
                        string='Postal Coordinates',
                        domain=[('active', '=', True)],
                        context={'force_recompute': True}),
        'postal_coordinate_inactive_ids':
        fields.one2many('postal.coordinate',
                        'address_id',
                        string='Postal Coordinates',
                        domain=[('active', '=', False)]),
    }

    _defaults = {
        'country_id':
        lambda self, cr, uid, c: self.pool.get('res.country').
        _country_default_get(cr, uid, COUNTRY_CODE, context=c),
        'country_code':
        COUNTRY_CODE,
        'sequence':
        0,
    }

    _order = 'country_id, zip, name'

    # constraints

    _unicity_keys = 'technical_name, sequence'

    # orm methods

    def copy_data(self, cr, uid, ids, default=None, context=None):
        """
        Increase sequence value when duplicating address
        """
        adr_id = isinstance(ids, (long, int)) and [ids] or ids
        technical_name = self.read(cr,
                                   uid,
                                   adr_id[0], ['technical_name'],
                                   context=context)['technical_name']
        cr.execute(
            'SELECT MAX(sequence) FROM %s WHERE technical_name=%%s' %
            (self._table, ), (technical_name, ))
        sequence = cr.fetchone()
        sequence = sequence and sequence[0] or False
        if not sequence:
            raise orm.except_orm(
                _('Error'),
                _('An Address without sequence number cannot be duplicated!'))

        default = dict(default or {})
        default.update({
            'sequence': sequence + 1,
            'postal_coordinate_ids': [],
            'postal_coordinate_inactive_ids': [],
        })
        res = super(address_address, self).copy_data(cr,
                                                     uid,
                                                     ids,
                                                     default=default,
                                                     context=context)
        return res

# view methods: onchange, button

    def onchange_country_id(self, cr, uid, ids, country_id, context=None):
        return {
            'value': {
                'country_code':
                self.pool.get('res.country').read(
                    cr, uid, [country_id], ['code'],
                    context=context)[0]['code'] if country_id else False,
                'address_local_zip_id':
                False,
            }
        }

    def onchange_local_zip_id(self, cr, uid, ids, local_zip_id, context=None):
        _zip, city = False, False
        if local_zip_id:
            zip_city = self.pool.get('address.local.zip').read(
                cr, uid, [local_zip_id], [], context=context)[0]
            _zip, city = zip_city['local_zip'], zip_city['town']
        return {
            'value': {
                'zip': _zip,
                'city': city,
                'zip_man': False,
                'town_man': False,
            }
        }

    def onchange_zip(self, cr, uid, ids, _zip, context=None):
        return {
            'value': {
                'address_local_street_id': False,
            }
        }

    def onchange_local_street_id(self,
                                 cr,
                                 uid,
                                 ids,
                                 local_street_id,
                                 context=None):
        vals = {} if local_street_id else {
            'select_alternative_address_local_street': False
        }
        vals.update({'street_man': False})
        return {'value': vals}


# public methods

    def get_linked_partners(self, cr, uid, ids, context=None):
        """
        Return all partners ids linked to addresses ids
        :param: ids
        :type: list of addresses ids
        :rparam: partner_ids
        :rtype: list of ids
        """
        coord_ids = self._get_linked_coordinates(cr, uid, ids, context=context)
        return self.pool['postal.coordinate'].get_linked_partners(
            cr, uid, coord_ids, context=context)
Example #17
0
class wiz_modificacion_regularizacion_siif(osv.osv_memory):
    _name = 'wiz.modificacion_regularizacion_siif'
    _description = "Wizard modificacion de regularizacion clearing SIIF"
    _columns = {
        'regularizacion_id':
        fields.integer('regularizacion id', invisible=False),
        'tipo':
        fields.selection(
            (('A', 'A - Aumento'), ('R', u'R - Reducción')),
            # ('C', u'C - Corrección'),
            # ('N', u'N - Anulación'),
            # ('D', u'D - Devolución')),
            'Tipo',
            required=True),
        'fecha':
        fields.date('Fecha', required=True),
        'importe':
        fields.integer('Importe', required=True),
        'motivo':
        fields.char('Motivo', required=True),
        'financiamiento':
        fields.related('fin_id',
                       'ff',
                       type='char',
                       string='Fin related',
                       store=True,
                       readonly=True),
        'programa':
        fields.related('programa_id',
                       'programa',
                       type='char',
                       string='Programa related',
                       store=True,
                       readonly=True),
        'proyecto':
        fields.related('proyecto_id',
                       'proyecto',
                       type='char',
                       string='Proyecto related',
                       store=True,
                       readonly=True),
        'objeto_gasto':
        fields.related('odg_id',
                       'odg',
                       type='char',
                       string='ODG related',
                       store=True,
                       readonly=True),
        'auxiliar':
        fields.related('auxiliar_id',
                       'aux',
                       type='char',
                       string='Auxiliar related',
                       store=True,
                       readonly=True),
        'moneda':
        fields.related('mon_id',
                       'moneda',
                       type='char',
                       string='Mon related',
                       store=True,
                       readonly=True),
        'tipo_credito':
        fields.related('tc_id',
                       'tc',
                       type='char',
                       string='TC related',
                       store=True,
                       readonly=True),
        'ue_id':
        fields.many2one('grp.estruc_pres.ue', 'Unidad ejecutora'),
        'fin_id':
        fields.many2one('grp.estruc_pres.ff', 'Fin', required=True),
        'programa_id':
        fields.many2one('grp.estruc_pres.programa', 'Programa', required=True),
        'proyecto_id':
        fields.many2one('grp.estruc_pres.proyecto', 'Proyecto', required=True),
        'odg_id':
        fields.many2one('grp.estruc_pres.odg', 'ODG', required=True),
        'auxiliar_id':
        fields.many2one('grp.estruc_pres.aux', 'Auxiliar', required=True),
        'mon_id':
        fields.many2one('grp.estruc_pres.moneda', 'Mon', required=True),
        'tc_id':
        fields.many2one('grp.estruc_pres.tc', 'TC', required=True),
    }

    _defaults = {
        'fecha': fields.date.context_today,
    }

    #Consumir SIIF aca
    def send_modif(self, cr, uid, ids, context=None):
        data = self.read(cr, uid, ids, [], context=context)[0]
        regularizacion_obj = self.pool.get("regularizacion.clearing")

        ctx = dict(context)
        ctx.update({
            'es_modif':
            True,
            'regularizacion_id':
            data['regularizacion_id'],
            'tipo_modificacion':
            data['tipo'],
            'fecha':
            data['fecha'],
            'programa':
            data['programa'],
            'proyecto':
            data['proyecto'],
            'moneda':
            data['moneda'],
            'tipo_credito':
            data['tipo_credito'],
            'financiamiento':
            data['financiamiento'],
            'objeto_gasto':
            data['objeto_gasto'],
            'auxiliar':
            data['auxiliar'],
            'importe':
            data['importe'] if data['tipo'] == 'A' else data['importe'] * -1,
            'motivo':
            data['motivo'],
        })
        raise Warning(_('Integración con SIIF'))
Example #18
0
class material_request_line(osv.osv):
    _name = "material.request.line"
    _inherit = "stock.move"
    _table = "stock_move"
    _description = "Material Request Line"
    def _amount_line(self, cr, uid, ids, prop, arg, context=None):
        res = {}
        for line in self.browse(cr, uid, ids, context=context):
            res[line.id] = line.product_qty * line.price_unit
        return res    
    _columns = {
        'picking_id': fields.many2one('material.request', 'MR#', select=True,states={'done': [('readonly', True)]}),
        'mr_emp_id': fields.many2one('hr.employee','Employee'),
        'mr_sale_prod_id': fields.many2one('sale.product','Sale Product ID', ondelete="restrict"),
        'mr_notes': fields.text('Reason and use'),
        'mr_dept_id': fields.related('picking_id','mr_dept_id',string='Department',type='many2one',relation='hr.department',select=True),
        'mr_date_order': fields.related('picking_id','date',string='Order Date',type='datetime'),
        'pick_type': fields.related('picking_id','type',string='Picking Type',type='char'),
        'create_uid': fields.many2one('res.users', 'Creator',readonly=True),
        'price_subtotal': fields.function(_amount_line, string='Subtotal', digits_compute= dp.get_precision('Account')),
        #make the price's decimal precision as the 'Product Price'
        'price_unit': fields.float('Unit Price', digits_compute= dp.get_precision('Product Price'), help="Technical field used to record the product cost set by the user during a picking confirmation (when average price costing method is used)"),
        'product_qty': fields.float('Quantity', digits_compute=dp.get_precision('Product Price'),
            required=True,states={'done': [('readonly', True)]},
            help="This is the quantity of products from an inventory "
                "point of view. For moves in the state 'done', this is the "
                "quantity of products that were actually moved. For other "
                "moves, this is the quantity of product that is planned to "
                "be moved. Lowering this quantity does not generate a "
                "backorder. Changing this quantity on assigned moves affects "
                "the product reservation, and should be done with care."
        ),
        'prod_categ_id': fields.related('product_id','categ_id',string='Product Category Type',type='many2one',relation="product.category",select=True),
    }
    _order = 'id'
    def default_mr_loc(self, cr, uid, context=None):
        if context is None:
            context = {}
        #material_request.type: mr or mrr
        req_type = context.get('req_type')
        if not req_type:
            req_type = 'mr'
        loc_stock_id = None
        loc_prod_id = None
        #get the default stock location
        cr.execute('select c.id \n'+
                    'from res_users a  \n'+
                    'left join stock_warehouse b on a.company_id = b.company_id  \n'+
                    'left join stock_location c on b.lot_stock_id = c.id \n'
                    'where a.id = %s', (uid,))
        loc_src = cr.fetchone()
        if loc_src:
            loc_stock_id = loc_src[0]           
        #get the default production location
        loc_obj = self.pool.get('stock.location')
        prod_loc_ids = loc_obj.search(cr,uid,[('usage','=','production')],context=context)
        if prod_loc_ids and prod_loc_ids[0]:
            prod_loc = loc_obj.browse(cr,uid,prod_loc_ids[0],context=context)
            loc_prod_id = prod_loc.id
        #set the locations by the request type
        loc_from_id = 0
        loc_to_id = 0
        if req_type == 'mr':
            if loc_stock_id:
                loc_from_id = loc_stock_id
            if loc_prod_id:
                loc_to_id = loc_prod_id
        if req_type == 'mrr':
            if loc_prod_id:
                loc_from_id = loc_prod_id
            if loc_stock_id:
                loc_to_id = loc_stock_id
        return loc_from_id, loc_to_id
                       
    def default_get(self, cr, uid, fields_list, context=None):
        resu = super(material_request_line,self).default_get(cr, uid, fields_list, context)
        loc_from_id, loc_to_id = self.default_mr_loc(cr, uid, context=context)
        resu.update({'location_id':loc_from_id, 'location_dest_id':loc_to_id})
        return resu
    
    def onchange_product_id(self, cr, uid, ids, prod_id=False, loc_id=False,
                            loc_dest_id=False, ):
        """ On change of product id, if finds UoM, UoS, quantity and UoS quantity.
        @param prod_id: Changed Product id
        @param loc_id: Source location id
        @param loc_dest_id: Destination location id
        @param partner_id: Address id of partner
        @return: Dictionary of values
        """
        if not prod_id:
            return {}
        user = self.pool.get("res.users").browse(cr,uid,uid)
        
        ctx = {'lang': user.lang,'location':loc_id}

        product = self.pool.get('product.product').browse(cr, uid, [prod_id], context=ctx)[0]
        uos_id  = product.uos_id and product.uos_id.id or False
        result = {
            'product_uom': product.uom_id.id,
            'product_uos': uos_id,
            'product_qty': product.qty_available,
            'product_uos_qty' : self.pool.get('stock.move').onchange_quantity(cr, uid, ids, prod_id, 1.00, product.uom_id.id, uos_id)['value']['product_uos_qty'],
            'prodlot_id' : False,
        }
        if not ids:
            result['name'] = product.partner_ref
        if loc_id:
            result['location_id'] = loc_id
        if loc_dest_id:
            result['location_dest_id'] = loc_dest_id
            
        #update the price_unit the and price_currency_id
        #default is the product's cost price
        price_unit = product.standard_price
        price_currency_id = None
        #get the final purchase price
        move_obj = self.pool.get('stock.move')
        #get the final purchase price
        move_ids = move_obj.search(cr,uid,[('product_id','=',prod_id),('state','=','done'),('type','=','in')],limit=1,order='create_date desc')
        if move_ids:
            move_price = move_obj.read(cr,uid,move_ids[0],['price_unit','price_currency_id'],context=ctx)
            price_unit = move_price['price_unit']
            price_currency_id = move_price['price_currency_id']
        result['price_unit'] = price_unit
        result['price_currency_id'] = price_currency_id
        
        return {'value': result}
    def check_access_rights(self, cr, uid, operation, raise_exception=True):
        #override in order to redirect the check of acces rights on the stock.picking object
        return self.pool.get('stock.move').check_access_rights(cr, uid, operation, raise_exception=raise_exception)

    def check_access_rule(self, cr, uid, ids, operation, context=None):
        #override in order to redirect the check of acces rules on the stock.picking object
        return self.pool.get('stock.move').check_access_rule(cr, uid, ids, operation, context=context)

    def _workflow_trigger(self, cr, uid, ids, trigger, context=None):
        #override in order to trigger the workflow of stock.picking at the end of create, write and unlink operation
        #instead of it's own workflow (which is not existing)
        return self.pool.get('stock.move')._workflow_trigger(cr, uid, ids, trigger, context=context)

    def _workflow_signal(self, cr, uid, ids, signal, context=None):
        #override in order to fire the workflow signal on given stock.picking workflow instance
        #instead of it's own workflow (which is not existing)
        return self.pool.get('stock.move')._workflow_signal(cr, uid, ids, signal, context=context)  
    
    def search(self, cr, user, args, offset=0, limit=None, order=None, context=None, count=False):
        #deal the 'date' datetime field query
        new_args = deal_args(self,args)
        return super(material_request_line,self).search(cr, user, new_args, offset, limit, order, context, count)   
    def create(self, cr, user, vals, context=None):
        #add the procut_uom set by product's purchase uom
        if 'product_uom' not in vals:
            prod = self.pool.get('product.product').browse(cr, user, vals['product_id'], context=context)
            vals.update({'product_uom':prod.uom_id.id})            
        resu = super(material_request_line,self).create(cr, user, vals, context=context)
        return resu            
Example #19
0
class marketing_campaign_workitem(osv.osv):
    _name = "marketing.campaign.workitem"
    _description = "Campaign Workitem"

    def _res_name_get(self, cr, uid, ids, field_name, arg, context=None):
        res = dict.fromkeys(ids, '/')
        for wi in self.browse(cr, uid, ids, context=context):
            if not wi.res_id:
                continue

            proxy = self.pool[wi.object_id.model]
            if not proxy.exists(cr, uid, [wi.res_id]):
                continue
            ng = proxy.name_get(cr, uid, [wi.res_id], context=context)
            if ng:
                res[wi.id] = ng[0][1]
        return res

    def _resource_search(self,
                         cr,
                         uid,
                         obj,
                         name,
                         args,
                         domain=None,
                         context=None):
        """Returns id of workitem whose resource_name matches  with the given name"""
        if not len(args):
            return []

        condition_name = None
        for domain_item in args:
            # we only use the first domain criterion and ignore all the rest including operators
            if isinstance(domain_item, (list, tuple)) and len(
                    domain_item) == 3 and domain_item[0] == 'res_name':
                condition_name = [None, domain_item[1], domain_item[2]]
                break

        assert condition_name, "Invalid search domain for marketing_campaign_workitem.res_name. It should use 'res_name'"

        cr.execute("""select w.id, w.res_id, m.model  \
                                from marketing_campaign_workitem w \
                                    left join marketing_campaign_activity a on (a.id=w.activity_id)\
                                    left join marketing_campaign c on (c.id=a.campaign_id)\
                                    left join ir_model m on (m.id=c.object_id)
                                    """)
        res = cr.fetchall()
        workitem_map = {}
        matching_workitems = []
        for id, res_id, model in res:
            workitem_map.setdefault(model, {}).setdefault(res_id,
                                                          set()).add(id)
        for model, id_map in workitem_map.iteritems():
            model_pool = self.pool[model]
            condition_name[0] = model_pool._rec_name
            condition = [('id', 'in', id_map.keys()), condition_name]
            for res_id in model_pool.search(cr,
                                            uid,
                                            condition,
                                            context=context):
                matching_workitems.extend(id_map[res_id])
        return [('id', 'in', list(set(matching_workitems)))]

    _columns = {
        'segment_id':
        fields.many2one('marketing.campaign.segment', 'Segment',
                        readonly=True),
        'activity_id':
        fields.many2one('marketing.campaign.activity',
                        'Activity',
                        required=True,
                        readonly=True),
        'campaign_id':
        fields.related('activity_id',
                       'campaign_id',
                       type='many2one',
                       relation='marketing.campaign',
                       string='Campaign',
                       readonly=True,
                       store=True),
        'object_id':
        fields.related('activity_id',
                       'campaign_id',
                       'object_id',
                       type='many2one',
                       relation='ir.model',
                       string='Resource',
                       select=1,
                       readonly=True,
                       store=True),
        'res_id':
        fields.integer('Resource ID', select=1, readonly=True),
        'res_name':
        fields.function(_res_name_get,
                        string='Resource Name',
                        fnct_search=_resource_search,
                        type="char",
                        size=64),
        'date':
        fields.datetime(
            'Execution Date',
            help='If date is not set, this workitem has to be run manually',
            readonly=True),
        'partner_id':
        fields.many2one('res.partner', 'Partner', select=1, readonly=True),
        'state':
        fields.selection([
            ('todo', 'To Do'),
            ('cancelled', 'Cancelled'),
            ('exception', 'Exception'),
            ('done', 'Done'),
        ],
                         'Status',
                         readonly=True,
                         copy=False),
        'error_msg':
        fields.text('Error Message', readonly=True)
    }
    _defaults = {
        'state': lambda *a: 'todo',
        'date': False,
    }

    @api.cr_uid_ids_context
    def button_draft(self, cr, uid, workitem_ids, context=None):
        for wi in self.browse(cr, uid, workitem_ids, context=context):
            if wi.state in ('exception', 'cancelled'):
                self.write(cr,
                           uid, [wi.id], {'state': 'todo'},
                           context=context)
        return True

    @api.cr_uid_ids_context
    def button_cancel(self, cr, uid, workitem_ids, context=None):
        for wi in self.browse(cr, uid, workitem_ids, context=context):
            if wi.state in ('todo', 'exception'):
                self.write(cr,
                           uid, [wi.id], {'state': 'cancelled'},
                           context=context)
        return True

    def _process_one(self, cr, uid, workitem, context=None):
        if workitem.state != 'todo':
            return False

        activity = workitem.activity_id
        proxy = self.pool[workitem.object_id.model]
        object_id = proxy.browse(cr, uid, workitem.res_id, context=context)

        eval_context = {
            'activity': activity,
            'workitem': workitem,
            'object': object_id,
            'resource': object_id,
            'transitions': activity.to_ids,
            're': re,
        }
        try:
            condition = activity.condition
            campaign_mode = workitem.campaign_id.mode
            if condition:
                if not eval(condition, eval_context):
                    if activity.keep_if_condition_not_met:
                        workitem.write({'state': 'cancelled'})
                    else:
                        workitem.unlink()
                    return
            result = True
            if campaign_mode in ('manual', 'active'):
                Activities = self.pool.get('marketing.campaign.activity')
                result = Activities.process(cr,
                                            uid,
                                            activity.id,
                                            workitem.id,
                                            context=context)

            values = dict(state='done')
            if not workitem.date:
                values['date'] = datetime.now().strftime(DT_FMT)
            workitem.write(values)

            if result:
                # process _chain
                workitem.refresh()  # reload
                date = datetime.strptime(workitem.date, DT_FMT)

                for transition in activity.to_ids:
                    if transition.trigger == 'cosmetic':
                        continue
                    launch_date = False
                    if transition.trigger == 'auto':
                        launch_date = date
                    elif transition.trigger == 'time':
                        launch_date = date + transition._delta()

                    if launch_date:
                        launch_date = launch_date.strftime(DT_FMT)
                    values = {
                        'date': launch_date,
                        'segment_id': workitem.segment_id.id,
                        'activity_id': transition.activity_to_id.id,
                        'partner_id': workitem.partner_id.id,
                        'res_id': workitem.res_id,
                        'state': 'todo',
                    }
                    wi_id = self.create(cr, uid, values, context=context)

                    # Now, depending on the trigger and the campaign mode
                    # we know whether we must run the newly created workitem.
                    #
                    # rows = transition trigger \ colums = campaign mode
                    #
                    #           test    test_realtime     manual      normal (active)
                    # time       Y            N             N           N
                    # cosmetic   N            N             N           N
                    # auto       Y            Y             N           Y
                    #

                    run = (transition.trigger == 'auto' \
                            and campaign_mode != 'manual') \
                          or (transition.trigger == 'time' \
                              and campaign_mode == 'test')
                    if run:
                        new_wi = self.browse(cr, uid, wi_id, context)
                        self._process_one(cr, uid, new_wi, context)

        except Exception:
            tb = "".join(format_exception(*exc_info()))
            workitem.write({'state': 'exception', 'error_msg': tb})

    @api.cr_uid_ids_context
    def process(self, cr, uid, workitem_ids, context=None):
        for wi in self.browse(cr, uid, workitem_ids, context=context):
            self._process_one(cr, uid, wi, context=context)
        return True

    def process_all(self, cr, uid, camp_ids=None, context=None):
        camp_obj = self.pool.get('marketing.campaign')
        if camp_ids is None:
            camp_ids = camp_obj.search(cr,
                                       uid, [('state', '=', 'running')],
                                       context=context)
        for camp in camp_obj.browse(cr, uid, camp_ids, context=context):
            if camp.mode == 'manual':
                # manual states are not processed automatically
                continue
            while True:
                domain = [('campaign_id', '=', camp.id),
                          ('state', '=', 'todo'), ('date', '!=', False)]
                if camp.mode in ('test_realtime', 'active'):
                    domain += [('date', '<=',
                                time.strftime('%Y-%m-%d %H:%M:%S'))]

                workitem_ids = self.search(cr, uid, domain, context=context)
                if not workitem_ids:
                    break

                self.process(cr, uid, workitem_ids, context=context)
        return True

    def preview(self, cr, uid, ids, context=None):
        res = {}
        wi_obj = self.browse(cr, uid, ids[0], context=context)
        if wi_obj.activity_id.type == 'email':
            view_id = self.pool.get('ir.model.data').get_object_reference(
                cr, uid, 'email_template', 'email_template_preview_form')
            res = {
                'name':
                _('Email Preview'),
                'view_type':
                'form',
                'view_mode':
                'form,tree',
                'res_model':
                'email_template.preview',
                'view_id':
                False,
                'context':
                context,
                'views': [(view_id and view_id[1] or 0, 'form')],
                'type':
                'ir.actions.act_window',
                'target':
                'new',
                'nodestroy':
                True,
                'context':
                "{'template_id':%d,'default_res_id':%d}" %
                (wi_obj.activity_id.email_template_id.id, wi_obj.res_id)
            }

        elif wi_obj.activity_id.type == 'report':
            datas = {'ids': [wi_obj.res_id], 'model': wi_obj.object_id.model}
            res = {
                'type': 'ir.actions.report.xml',
                'report_name': wi_obj.activity_id.report_id.report_name,
                'datas': datas,
            }
        else:
            raise osv.except_osv(
                _('No preview'),
                _('The current step for this item has no email or report to preview.'
                  ))
        return res
Example #20
0
class marketing_campaign_activity(osv.osv):
    _name = "marketing.campaign.activity"
    _order = "name"
    _description = "Campaign Activity"

    _action_types = [
        ('email', 'Email'),
        ('report', 'Report'),
        ('action', 'Custom Action'),
        # TODO implement the subcampaigns.
        # TODO implement the subcampaign out. disallow out transitions from
        # subcampaign activities ?
        #('subcampaign', 'Sub-Campaign'),
    ]

    _columns = {
        'name':
        fields.char('Name', required=True),
        'campaign_id':
        fields.many2one('marketing.campaign',
                        'Campaign',
                        required=True,
                        ondelete='cascade',
                        select=1),
        'object_id':
        fields.related('campaign_id',
                       'object_id',
                       type='many2one',
                       relation='ir.model',
                       string='Object',
                       readonly=True),
        'start':
        fields.boolean(
            'Start',
            help="This activity is launched when the campaign starts.",
            select=True),
        'condition':
        fields.text(
            'Condition',
            size=256,
            required=True,
            help=
            "Python expression to decide whether the activity can be executed, otherwise it will be deleted or cancelled."
            "The expression may use the following [browsable] variables:\n"
            "   - activity: the campaign activity\n"
            "   - workitem: the campaign workitem\n"
            "   - resource: the resource object this campaign item represents\n"
            "   - transitions: list of campaign transitions outgoing from this activity\n"
            "...- re: Python regular expression module"),
        'type':
        fields.selection(
            _action_types,
            'Type',
            required=True,
            help=
            """The type of action to execute when an item enters this activity, such as:
   - Email: send an email using a predefined email template
   - Report: print an existing Report defined on the resource item and save it into a specific directory
   - Custom Action: execute a predefined action, e.g. to modify the fields of the resource record
  """),
        'email_template_id':
        fields.many2one(
            'email.template',
            "Email Template",
            help='The email to send when this activity is activated'),
        'report_id':
        fields.many2one(
            'ir.actions.report.xml',
            "Report",
            help='The report to generate when this activity is activated',
        ),
        'report_directory_id':
        fields.many2one(
            'document.directory',
            'Directory',
            help="This folder is used to store the generated reports"),
        'server_action_id':
        fields.many2one(
            'ir.actions.server',
            string='Action',
            help="The action to perform when this activity is activated"),
        'to_ids':
        fields.one2many('marketing.campaign.transition', 'activity_from_id',
                        'Next Activities'),
        'from_ids':
        fields.one2many('marketing.campaign.transition', 'activity_to_id',
                        'Previous Activities'),
        'variable_cost':
        fields.float(
            'Variable Cost',
            help=
            "Set a variable cost if you consider that every campaign item that has reached this point has entailed a certain cost. You can get cost statistics in the Reporting section",
            digits_compute=dp.get_precision('Product Price')),
        'revenue':
        fields.float(
            'Revenue',
            help=
            "Set an expected revenue if you consider that every campaign item that has reached this point has generated a certain revenue. You can get revenue statistics in the Reporting section",
            digits_compute=dp.get_precision('Account')),
        'signal':
        fields.char(
            'Signal',
            help=
            'An activity with a signal can be called programmatically. Be careful, the workitem is always created when a signal is sent'
        ),
        'keep_if_condition_not_met':
        fields.boolean(
            "Don't Delete Workitems",
            help=
            "By activating this option, workitems that aren't executed because the condition is not met are marked as cancelled instead of being deleted."
        )
    }

    _defaults = {
        'type': lambda *a: 'email',
        'condition': lambda *a: 'True',
    }

    def search(self,
               cr,
               uid,
               args,
               offset=0,
               limit=None,
               order=None,
               context=None,
               count=False):
        if context == None:
            context = {}
        if 'segment_id' in context and context['segment_id']:
            segment_obj = self.pool.get('marketing.campaign.segment').browse(
                cr, uid, context['segment_id'])
            act_ids = []
            for activity in segment_obj.campaign_id.activity_ids:
                act_ids.append(activity.id)
            return act_ids
        return super(marketing_campaign_activity,
                     self).search(cr, uid, args, offset, limit, order, context,
                                  count)

    #dead code
    def _process_wi_report(self, cr, uid, activity, workitem, context=None):
        report_data, format = render_report(cr,
                                            uid, [],
                                            activity.report_id.report_name, {},
                                            context=context)
        attach_vals = {
            'name':
            '%s_%s_%s' % (activity.report_id.report_name, activity.name,
                          workitem.partner_id.name),
            'datas_fname':
            '%s.%s' %
            (activity.report_id.report_name, activity.report_id.report_type),
            'parent_id':
            activity.report_directory_id.id,
            'datas':
            base64.encodestring(report_data),
            'file_type':
            format
        }
        self.pool.get('ir.attachment').create(cr, uid, attach_vals)
        return True

    def _process_wi_email(self, cr, uid, activity, workitem, context=None):
        return self.pool.get('email.template').send_mail(
            cr,
            uid,
            activity.email_template_id.id,
            workitem.res_id,
            context=context)

    #dead code
    def _process_wi_action(self, cr, uid, activity, workitem, context=None):
        if context is None:
            context = {}
        server_obj = self.pool.get('ir.actions.server')

        action_context = dict(context,
                              active_id=workitem.res_id,
                              active_ids=[workitem.res_id],
                              active_model=workitem.object_id.model,
                              workitem=workitem)
        server_obj.run(cr,
                       uid, [activity.server_action_id.id],
                       context=action_context)
        return True

    def process(self, cr, uid, act_id, wi_id, context=None):
        activity = self.browse(cr, uid, act_id, context=context)
        method = '_process_wi_%s' % (activity.type, )
        action = getattr(self, method, None)
        if not action:
            raise NotImplementedError(
                'Method %r is not implemented on %r object.' % (method, self))

        workitem_obj = self.pool.get('marketing.campaign.workitem')
        workitem = workitem_obj.browse(cr, uid, wi_id, context=context)
        return action(cr, uid, activity, workitem, context=context)
Example #21
0
class marketing_campaign_segment(osv.osv):
    _name = "marketing.campaign.segment"
    _description = "Campaign Segment"
    _order = "name"

    def _get_next_sync(self, cr, uid, ids, fn, args, context=None):
        # next auto sync date is same for all segments
        sync_job = self.pool.get('ir.model.data').get_object(
            cr,
            uid,
            'marketing_campaign',
            'ir_cron_marketing_campaign_every_day',
            context=context)
        next_sync = sync_job and sync_job.nextcall or False
        return dict.fromkeys(ids, next_sync)

    _columns = {
        'name': fields.char('Name', required=True),
        'campaign_id': fields.many2one('marketing.campaign', 'Campaign', required=True, select=1, ondelete="cascade"),
        'object_id': fields.related('campaign_id','object_id', type='many2one', relation='ir.model', string='Resource'),
        'ir_filter_id': fields.many2one('ir.filters', 'Filter', ondelete="restrict",
                            help="Filter to select the matching resource records that belong to this segment. "\
                                 "New filters can be created and saved using the advanced search on the list view of the Resource. "\
                                 "If no filter is set, all records are selected without filtering. "\
                                 "The synchronization mode may also add a criterion to the filter."),
        'sync_last_date': fields.datetime('Last Synchronization', help="Date on which this segment was synchronized last time (automatically or manually)"),
        'sync_mode': fields.selection([('create_date', 'Only records created after last sync'),
                                      ('write_date', 'Only records modified after last sync (no duplicates)'),
                                      ('all', 'All records (no duplicates)')],
                                      'Synchronization mode',
                                      help="Determines an additional criterion to add to the filter when selecting new records to inject in the campaign. "\
                                           '"No duplicates" prevents selecting records which have already entered the campaign previously.'\
                                           'If the campaign has a "unique field" set, "no duplicates" will also prevent selecting records which have '\
                                           'the same value for the unique field as other records that already entered the campaign.'),
        'state': fields.selection([('draft', 'New'),
                                   ('cancelled', 'Cancelled'),
                                   ('running', 'Running'),
                                   ('done', 'Done')],
                                   'Status', copy=False),
        'date_run': fields.datetime('Launch Date', help="Initial start date of this segment."),
        'date_done': fields.datetime('End Date', help="Date this segment was last closed or cancelled."),
        'date_next_sync': fields.function(_get_next_sync, string='Next Synchronization', type='datetime', help="Next time the synchronization job is scheduled to run automatically"),
    }

    _defaults = {
        'state': lambda *a: 'draft',
        'sync_mode': lambda *a: 'create_date',
    }

    def _check_model(self, cr, uid, ids, context=None):
        for obj in self.browse(cr, uid, ids, context=context):
            if not obj.ir_filter_id:
                return True
            if obj.campaign_id.object_id.model != obj.ir_filter_id.model_id:
                return False
        return True

    _constraints = [
        (_check_model,
         'Model of filter must be same as resource model of Campaign ',
         ['ir_filter_id,campaign_id']),
    ]

    def onchange_campaign_id(self, cr, uid, ids, campaign_id):
        res = {'domain': {'ir_filter_id': []}}
        campaign_pool = self.pool.get('marketing.campaign')
        if campaign_id:
            campaign = campaign_pool.browse(cr, uid, campaign_id)
            model_name = self.pool.get('ir.model').read(
                cr, uid, [campaign.object_id.id], ['model'])
            if model_name:
                mod_name = model_name[0]['model']
                res['domain'] = {'ir_filter_id': [('model_id', '=', mod_name)]}
        else:
            res['value'] = {'ir_filter_id': False}
        return res

    def state_running_set(self, cr, uid, ids, *args):
        segment = self.browse(cr, uid, ids[0])
        vals = {'state': 'running'}
        if not segment.date_run:
            vals['date_run'] = time.strftime('%Y-%m-%d %H:%M:%S')
        self.write(cr, uid, ids, vals)
        return True

    def state_done_set(self, cr, uid, ids, *args):
        wi_ids = self.pool.get("marketing.campaign.workitem").search(
            cr, uid, [('state', '=', 'todo'), ('segment_id', 'in', ids)])
        self.pool.get("marketing.campaign.workitem").write(
            cr, uid, wi_ids, {'state': 'cancelled'})
        self.write(cr, uid, ids, {
            'state': 'done',
            'date_done': time.strftime('%Y-%m-%d %H:%M:%S')
        })
        return True

    def state_cancel_set(self, cr, uid, ids, *args):
        wi_ids = self.pool.get("marketing.campaign.workitem").search(
            cr, uid, [('state', '=', 'todo'), ('segment_id', 'in', ids)])
        self.pool.get("marketing.campaign.workitem").write(
            cr, uid, wi_ids, {'state': 'cancelled'})
        self.write(cr, uid, ids, {
            'state': 'cancelled',
            'date_done': time.strftime('%Y-%m-%d %H:%M:%S')
        })
        return True

    def synchroniz(self, cr, uid, ids, *args):
        self.process_segment(cr, uid, ids)
        return True

    @api.cr_uid_ids_context
    def process_segment(self, cr, uid, segment_ids=None, context=None):
        Workitems = self.pool.get('marketing.campaign.workitem')
        Campaigns = self.pool.get('marketing.campaign')
        if not segment_ids:
            segment_ids = self.search(cr,
                                      uid, [('state', '=', 'running')],
                                      context=context)

        action_date = time.strftime('%Y-%m-%d %H:%M:%S')
        campaigns = set()
        for segment in self.browse(cr, uid, segment_ids, context=context):
            if segment.campaign_id.state != 'running':
                continue

            campaigns.add(segment.campaign_id.id)
            act_ids = self.pool.get('marketing.campaign.activity').search(
                cr,
                uid, [('start', '=', True),
                      ('campaign_id', '=', segment.campaign_id.id)],
                context=context)

            model_obj = self.pool[segment.object_id.model]
            criteria = []
            if segment.sync_last_date and segment.sync_mode != 'all':
                criteria += [(segment.sync_mode, '>', segment.sync_last_date)]
            if segment.ir_filter_id:
                criteria += eval(segment.ir_filter_id.domain)
            object_ids = model_obj.search(cr, uid, criteria, context=context)

            # XXX TODO: rewrite this loop more efficiently without doing 1 search per record!
            for record in model_obj.browse(cr,
                                           uid,
                                           object_ids,
                                           context=context):
                # avoid duplicate workitem for the same resource
                if segment.sync_mode in ('write_date', 'all'):
                    if Campaigns._find_duplicate_workitems(cr,
                                                           uid,
                                                           record,
                                                           segment.campaign_id,
                                                           context=context):
                        continue

                wi_vals = {
                    'segment_id': segment.id,
                    'date': action_date,
                    'state': 'todo',
                    'res_id': record.id
                }

                partner = self.pool.get('marketing.campaign')._get_partner_for(
                    segment.campaign_id, record)
                if partner:
                    wi_vals['partner_id'] = partner.id

                for act_id in act_ids:
                    wi_vals['activity_id'] = act_id
                    Workitems.create(cr, uid, wi_vals, context=context)

            self.write(cr,
                       uid,
                       segment.id, {'sync_last_date': action_date},
                       context=context)
        Workitems.process_all(cr, uid, list(campaigns), context=context)
        return True
Example #22
0
     clock_ids_exist = []
     try:
         for order in self.browse(cr, uid, ids, context=context):
             emp_code = order.employee_id.emp_code
             for clock_id in clock_ids:
                 emps_clock = clock_sync_obj.clock_emps_get(cr, uid, clock_id, [emp_code], context=context)
                 if emps_clock:
                     clock_ids_exist.append(clock_id)
             resu[order.id] = clock_ids_exist
     except Exception,e:
         traceback.print_exc()
         pass 
     return resu
 _columns = {
     'employee_id': fields.many2one('hr.employee',  'Employee', required=True, select=True),
     'department_id':fields.related('employee_id','department_id', type='many2one', relation='hr.department', string='Department', store=True),
     'job_id':fields.related('employee_id','job_id', type='many2one', relation='hr.job', string='Title', store=True),
     'emp_code':fields.related('employee_id','emp_code', type='char', string='Employee Code', store=True),
     'mobile_phone':fields.related('employee_id','mobile_phone', type='char', string='Work Mobile', store=True),
     'borrow_money_residual':fields.related('employee_id','money_residual', type='float', string='Borrowed residual', readonly=True),
     
     'dimmission_reason':fields.text('Dimission Reason', required=True),
     'advice_to_company':fields.text('Advice to company'),
     'employment_start':fields.date('Employment Started'),
     'date_request':fields.date('Request Date', required=True),
     'date_done':fields.date('Done Date', required=False, readonly=True),
     
     'approve_ids': fields.one2many('hr.dimission.item', 'dimission_id', 'Approvals', domain=[('type','=','approve')]),
     'transfer_ids': fields.one2many('hr.dimission.item', 'dimission_id', 'Transfers', domain=[('type','=','transfer')]),
     
     'payslip_id': fields.many2many('hr.emppay', string='Payslip'),
Example #23
0
class social_programs_direction(osv.osv):
    _description = "Direcciones de programas sociales"
    _name = 'social.programs.direction'

    def onchange_state(self, cr, uid, ids, state_id, context=None):
        """
            Obtiene la informacion del pais en base a el estado seleccioando
        """
        if state_id:
            country_id = self.pool.get('res.country.state').browse(
                cr, uid, state_id, context).country_id.id
            return {'value': {'country_id': country_id}}
        return {}

    def onchange_settlement(self, cr, uid, ids, settlement_id, context=None):
        """
            Obtiene la informacion de ciudad, estado, pais, CP, etc... en base a la colonia seleccionada
        """
        if settlement_id:
            settlement = self.pool.get(
                'social.programs.res.settlement').browse(
                    cr, uid, settlement_id, context)
            if settlement.id:
                state = self.pool.get('res.country.state').browse(
                    cr, uid, settlement.city_id.state_id.id, context)
                return {
                    'value': {
                        'country_id': state.country_id.id,
                        'state_id': state.id,
                        'city_id': settlement.city_id.id,
                        'city': settlement.city_id.name,
                        'area_id': settlement.area_id.id,
                        'sector_id': settlement.sector_id.id,
                        'zip': settlement.zip
                    }
                }
        return {}

    _columns = {
        'name':
        fields.char('Nombre', size=128, required=True, select=True),
        # Datos de ubicacion
        'state_id':
        fields.many2one('res.country.state', 'Estado'),
        'country_id':
        fields.related('state_id',
                       'country_id',
                       type="many2one",
                       relation="res.country",
                       string="Country",
                       store=True),
        'city_id':
        fields.many2one("social.programs.res.city", 'Ciudad'),
        'settlement_id':
        fields.many2one('social.programs.res.settlement', 'Colonia'),
        'area_id':
        fields.related('settlement_id',
                       'area_id',
                       type="many2one",
                       relation="social.programs.res.area",
                       string="Area",
                       readonly=True),
        'sector_id':
        fields.related('settlement_id',
                       'sector_id',
                       type="many2one",
                       relation="social.programs.res.sector",
                       string="Sector",
                       readonly=True),
        'street':
        fields.char('Calle', size=128),
        'zip':
        fields.char('C.P.', change_default=True, size=24),
        'email':
        fields.char('Email', size=240),
        'phone':
        fields.char('Phone', size=64),
        'fax':
        fields.char('Fax', size=64),
        'mobile':
        fields.char('Mobile', size=64),
        # Datos complemento
        'user_id':
        fields.many2one('res.users',
                        'Director',
                        help='Encargado de la direccion.'),
        'comment':
        fields.text('Notas'),
        'active':
        fields.boolean('Active'),
    }
    _order = 'name'
Example #24
0
		'price_subtotal': fields.function(_amount_line, string='Subtotal', digits_compute= dp.get_precision('Account')),
		'tax_id': fields.many2many('account.tax', 'sale_order_tax', 'order_line_id', 'tax_id', 'Taxes', readonly=True, states={'draft': [('readonly', False)]}),
		'address_allotment_id': fields.many2one('res.partner', 'Allotment Partner',help="A partner to whom the particular product needs to be allotted."),
		'product_uom_qty': fields.float('Quantity', digits_compute= dp.get_precision('Product UoS'), required=True, readonly=True, states={'draft': [('readonly', False)]}),
		'product_uom': fields.many2one('product.uom', 'Unit of Measure ', required=True, readonly=True, states={'draft': [('readonly', False)]}),
		'product_uos_qty': fields.float('Quantity (UoS)' ,digits_compute= dp.get_precision('Product UoS'), readonly=True, states={'draft': [('readonly', False)]}),
		'product_uos': fields.many2one('product.uom', 'Product UoS'),
		'discount': fields.float('Discount (%)', digits_compute= dp.get_precision('Discount'), readonly=True, states={'draft': [('readonly', False)]}),
		'th_weight': fields.float('Weight', readonly=True, states={'draft': [('readonly', False)]}),
		'state': fields.selection([('cancel', 'Cancelled'),('draft', 'Draft'),('confirmed', 'Confirmed'),('exception', 'Exception'),('done', 'Done')], 'Status', required=True, readonly=True,
				help='* The \'Draft\' status is set when the related sales order in draft status. \
					\n* The \'Confirmed\' status is set when the related sales order is confirmed. \
					\n* The \'Exception\' status is set when the related sales order is set as exception. \
					\n* The \'Done\' status is set when the sales order line has been picked. \
					\n* The \'Cancelled\' status is set when a user cancel the sales order related.'),
		'order_partner_id': fields.related('order_id', 'partner_id', type='many2one', relation='res.partner', store=True, string='Customer'),
		'salesman_id':fields.related('order_id', 'user_id', type='many2one', relation='res.users', store=True, string='Salesperson'),
		'company_id': fields.related('order_id', 'company_id', type='many2one', relation='res.company', string='Company', store=True, readonly=True),
	}
	_order = 'order_id desc, sequence, id'
	_defaults = {
		'product_uom' : _get_uom_id,
		'discount': 0.0,
		'product_uom_qty': 1,
		'product_uos_qty': 1,
		'sequence': 10,
		'state': 'draft',
		'type': 'make_to_stock',
		'price_unit': 0.0,
	}
Example #25
0
class social_programs_program_delivery(osv.osv, format_address):
    _description = "Entrega Programas sociales"
    _name = 'social.programs.program.delivery'

    def action_delivery_product(self, cr, uid, ids, context=None):
        """
            Muestra una ventana con la informacion del documento a entregar
        """

        partner_id = self.browse(cr, uid, ids[0],
                                 context=context).partner_id.id

        mod_obj = self.pool.get('ir.model.data')
        res = mod_obj.get_object_reference(
            cr, uid, 'social_programs',
            'view_social_programs_program_delivery_form')
        res_id = res and res[1] or False

        #~ Redirecciona al formulario de Entrega
        return {
            'name': "Entrega",
            'view_type': 'form',
            'view_mode': 'form',
            'view_id': [res_id],
            'res_model': 'social.programs.program.delivery',  # object name
            'type': 'ir.actions.act_window',
            'nodestroy': True,
            'target': 'new',
            'res_id': ids[0],  # id of the object to which to redirected
        }

    def action_delivery(self, cr, uid, ids, context=None):
        """
            Pone el documento como entregado
        """
        date = fields.date.context_today(self, cr, uid, context=context)
        self.write(cr,
                   uid,
                   ids, {
                       'delivery': True,
                       'date': date
                   },
                   context=context)
        print "*************** cambio de estado **************** "

        #~ Cierra la ventana
        return {'type': 'ir.actions.act_window_close'}

    def action_delivery_and_print(self, cr, uid, ids, context=None):
        """
            Entrega el documento e imprime el reporte
        """
        self.action_delivery(cr, uid, ids, context=context)
        res = self.action_print_report(cr, uid, ids, context=context)
        return res

    def action_print_report(self, cr, uid, ids, context=None):
        datas = {}
        if context is None:
            context = {}
        print "************** active_ids ************* ", context.get(
            'active_ids', [])

        data = self.read(cr, uid, ids)[0]
        datas = {
            'ids': ids,
            'model': 'social.programs.program.delivery',
            'form': data
        }
        return {
            'type': 'ir.actions.report.xml',
            'report_name': 'report.social.programs.program.delivery.webkit',
            'datas': datas,
        }

    def onchange_delivery(self, cr, uid, ids, delivery, context=None):
        """
            Cierra la ventana si cambia el estado a entregado
        """
        if delivery == True:
            return {'type': 'ir.actions.act_window_close'}
        return True

    _columns = {
        'program_id':
        fields.many2one('social.programs.program', 'Programa', readonly=True),
        'partner_id':
        fields.many2one('res.partner', 'Beneficiario', readonly=True),
        'product_id':
        fields.many2one('product.product', 'Producto', readonly=True),
        'qty':
        fields.float('Cantidad a entregar', readonly=True),
        'date':
        fields.date('Entregado', readonly=True),
        'delivery':
        fields.boolean('Entregado', readonly=True),
        # Campos relacionados con el beneficiario
        'name':
        fields.related('partner_id',
                       'name',
                       type="char",
                       string="Nombre",
                       readonly=True),
        'curp':
        fields.related('partner_id',
                       'curp',
                       type="char",
                       string="curp",
                       readonly=True),
        'image':
        fields.related('partner_id',
                       'image',
                       type="binary",
                       string="Image",
                       readonly=True),
        'image_medium':
        fields.related('partner_id',
                       'image_medium',
                       type="binary",
                       string="Image medium",
                       readonly=True),
        'category_id':
        fields.many2many("res.partner.category",
                         'partner_id',
                         'category_id',
                         string="Etiquetas",
                         readonly=True),
        'street':
        fields.related('partner_id',
                       'street',
                       type="char",
                       string="Calle",
                       readonly=True),
        'settlement_id':
        fields.related('partner_id',
                       'settlement_id',
                       type='many2one',
                       relation='social.programs.res.settlement',
                       string='Colonia',
                       readonly=True),
        'city_id':
        fields.related('partner_id',
                       'city_id',
                       type='many2one',
                       relation='social.programs.res.city',
                       string='Ciudad',
                       readonly=True),
        'state_id':
        fields.related('partner_id',
                       'state_id',
                       type='many2one',
                       relation='res.country.state',
                       string='Estado',
                       readonly=True),
        'zip':
        fields.related('partner_id',
                       'zip',
                       type="char",
                       string="C.P.",
                       readonly=True),
        'sector_id':
        fields.related('partner_id',
                       'sector_id',
                       type='many2one',
                       relation='social.programs.res.sector',
                       string='Sector',
                       readonly=True),
        'area_id':
        fields.related('partner_id',
                       'area_id',
                       type='many2one',
                       relation='social.programs.res.area',
                       string='Area',
                       readonly=True),
        'country_id':
        fields.related('partner_id',
                       'country_id',
                       type='many2one',
                       relation='res.country',
                       string='Estado',
                       readonly=True),
        'phone':
        fields.related('partner_id',
                       'phone',
                       type="char",
                       string="Telefono",
                       readonly=True),
        'mobile':
        fields.related('partner_id',
                       'mobile',
                       type="char",
                       string="Celular",
                       readonly=True),
        'email':
        fields.related('partner_id',
                       'email',
                       type="char",
                       string="Correo",
                       readonly=True),
    }

    _defaults = {'delivery': False}

    _order = 'delivery,program_id,partner_id,product_id,qty'
    #
    #             #else:
    #             #    logging.getLogger(self._name).info("Este activo ya esta asentado!")


    _columns = {
    'department_id' : fields.many2one('hr.department', 'Departament'),
    'life_expectancy' : fields.float('Life Expectancy', help="""Life expectancy
     of the asset in years."""),
    'life_expectancy_percentage': fields.float('Life Expectancy Percentage'),
    'stage_id': fields.many2one('account.asset.stage', 'Stage',
        help="""The stage of the asset indicate in wich point of his life is
        at the moment. You can add new stages in configuration."""),
    'code': fields.char("Code", size=9, required=True),
    'model_id': fields.many2one('account.asset.model', 'Model'),
    'brand_id': fields.related('model_id', 'brand_id', string='Brand',
        type="many2one", relation="account.asset.model", readonly=True),
    'category': fields.selection((
        ('administrative', 'Administrative'),
        ('scholarly', 'Scholarly'),
        ('none', 'None')), 'Type of asset', help="""The type of
    asset, scholarly or administrative."""),
    'asset_move_ids': fields.one2many('account.asset.move', 'asset_id',
        'Movements')
    }
    _defaults = {
    'category': 'administrative',
    }

class AccountCategory(orm.Model):

    _name = 'account.asset.category'
class account_followup_print(osv.osv_memory):
    _name = 'account_followup.print'
    _description = 'Print Follow-up & Send Mail to Customers'
    _columns = {
        'date':
        fields.date(
            'Follow-up Sending Date',
            required=True,
            help=
            "This field allow you to select a forecast date to plan your follow-ups"
        ),
        'followup_id':
        fields.many2one('account_followup.followup',
                        'Follow-Up',
                        required=True,
                        readonly=True),
        'partner_ids':
        fields.many2many('account_followup.stat.by.partner',
                         'partner_stat_rel',
                         'osv_memory_id',
                         'partner_id',
                         'Partners',
                         required=True),
        'company_id':
        fields.related('followup_id',
                       'company_id',
                       type='many2one',
                       relation='res.company',
                       store=True,
                       readonly=True),
        'email_conf':
        fields.boolean('Send Email Confirmation'),
        'email_subject':
        fields.char('Email Subject', size=64),
        'partner_lang':
        fields.boolean(
            'Send Email in Partner Language',
            help=
            'Do not change message text, if you want to send email in partner language, or configure from company'
        ),
        'email_body':
        fields.text('Email Body'),
        'summary':
        fields.text('Summary', readonly=True),
        'test_print':
        fields.boolean(
            'Test Print',
            help=
            'Check if you want to print follow-ups without changing follow-up level.'
        ),
    }

    def _get_followup(self, cr, uid, context=None):
        if context is None:
            context = {}
        if context.get('active_model',
                       'ir.ui.menu') == 'account_followup.followup':
            return context.get('active_id', False)
        company_id = self.pool.get('res.users').browse(
            cr, uid, uid, context=context).company_id.id
        followp_id = self.pool.get('account_followup.followup').search(
            cr, uid, [('company_id', '=', company_id)], context=context)
        return followp_id and followp_id[0] or False

    def process_partners(self, cr, uid, partner_ids, data, context=None):
        partner_obj = self.pool.get('res.partner')
        partner_ids_to_print = []
        nbmanuals = 0
        manuals = {}
        nbmails = 0
        nbunknownmails = 0
        nbprints = 0
        resulttext = " "
        for partner in self.pool.get(
                'account_followup.stat.by.partner').browse(cr,
                                                           uid,
                                                           partner_ids,
                                                           context=context):
            if partner.max_followup_id.manual_action:
                partner_obj.do_partner_manual_action(cr,
                                                     uid,
                                                     [partner.partner_id.id],
                                                     context=context)
                nbmanuals = nbmanuals + 1
                key = partner.partner_id.payment_responsible_id.name or _(
                    "Anybody")
                if not key in manuals.keys():
                    manuals[key] = 1
                else:
                    manuals[key] = manuals[key] + 1
            if partner.max_followup_id.send_email:
                nbunknownmails += partner_obj.do_partner_mail(
                    cr, uid, [partner.partner_id.id], context=context)
                nbmails += 1
            if partner.max_followup_id.send_letter:
                partner_ids_to_print.append(partner.id)
                nbprints += 1
                message = _(
                    "Follow-up letter of "
                ) + "<I> " + partner.partner_id.latest_followup_level_id_without_lit.name + "</I>" + _(
                    " will be sent")
                partner_obj.message_post(cr,
                                         uid, [partner.partner_id.id],
                                         body=message,
                                         context=context)
        if nbunknownmails == 0:
            resulttext += str(nbmails) + _(" email(s) sent")
        else:
            resulttext += str(nbmails) + _(
                " email(s) should have been sent, but ") + str(
                    nbunknownmails) + _(
                        " had unknown email address(es)") + "\n <BR/> "
        resulttext += "<BR/>" + str(nbprints) + _(
            " letter(s) in report") + " \n <BR/>" + str(nbmanuals) + _(
                " manual action(s) assigned:")
        needprinting = False
        if nbprints > 0:
            needprinting = True
        resulttext += "<p align=\"center\">"
        for item in manuals:
            resulttext = resulttext + "<li>" + item + ":" + str(
                manuals[item]) + "\n </li>"
        resulttext += "</p>"
        result = {}
        action = partner_obj.do_partner_print(cr,
                                              uid,
                                              partner_ids_to_print,
                                              data,
                                              context=context)
        result['needprinting'] = needprinting
        result['resulttext'] = resulttext
        result['action'] = action or {}
        return result

    def do_update_followup_level(self,
                                 cr,
                                 uid,
                                 to_update,
                                 partner_list,
                                 date,
                                 context=None):
        #update the follow-up level on account.move.line
        for id in to_update.keys():
            if to_update[id]['partner_id'] in partner_list:
                self.pool.get('account.move.line').write(
                    cr, uid, [int(id)], {
                        'followup_line_id': to_update[id]['level'],
                        'followup_date': date
                    })

    def clear_manual_actions(self, cr, uid, partner_list, context=None):
        # Partnerlist is list to exclude
        # Will clear the actions of partners that have no due payments anymore
        partner_list_ids = [
            partner.partner_id.id
            for partner in self.pool.get('account_followup.stat.by.partner').
            browse(cr, uid, partner_list, context=context)
        ]
        ids = self.pool.get('res.partner').search(
            cr,
            uid, [
                '&', ('id', 'not in', partner_list_ids), '|',
                ('payment_responsible_id', '!=', False),
                ('payment_next_action_date', '!=', False)
            ],
            context=context)

        partners_to_clear = []
        for part in self.pool.get('res.partner').browse(cr,
                                                        uid,
                                                        ids,
                                                        context=context):
            if not part.unreconciled_aml_ids:
                partners_to_clear.append(part.id)
        self.pool.get('res.partner').action_done(cr,
                                                 uid,
                                                 partners_to_clear,
                                                 context=context)
        return len(partners_to_clear)

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

        #Get partners
        tmp = self._get_partners_followp(cr, uid, ids, context=context)
        partner_list = tmp['partner_ids']
        to_update = tmp['to_update']
        date = self.browse(cr, uid, ids, context=context)[0].date
        data = self.read(cr, uid, ids, [], context=context)[0]
        data['followup_id'] = data['followup_id'][0]

        #Update partners
        self.do_update_followup_level(cr,
                                      uid,
                                      to_update,
                                      partner_list,
                                      date,
                                      context=context)
        #process the partners (send mails...)
        restot = self.process_partners(cr,
                                       uid,
                                       partner_list,
                                       data,
                                       context=context)
        #clear the manual actions if nothing is due anymore
        nbactionscleared = self.clear_manual_actions(cr,
                                                     uid,
                                                     partner_list,
                                                     context=context)
        if nbactionscleared > 0:
            restot['resulttext'] = restot['resulttext'] + "<li>" + _(
                "%s partners have no credits and as such the action is cleared"
            ) % (str(nbactionscleared)) + "</li>"
        res = restot['action']

        #return the next action
        mod_obj = self.pool.get('ir.model.data')
        model_data_ids = mod_obj.search(
            cr,
            uid, [('model', '=', 'ir.ui.view'),
                  ('name', '=', 'view_account_followup_sending_results')],
            context=context)
        resource_id = mod_obj.read(cr,
                                   uid,
                                   model_data_ids,
                                   fields=['res_id'],
                                   context=context)[0]['res_id']
        context.update({
            'description': restot['resulttext'],
            'needprinting': restot['needprinting'],
            'report_data': res
        })
        return {
            'name': _('Send Letters and Emails: Actions Summary'),
            'view_type': 'form',
            'context': context,
            'view_mode': 'tree,form',
            'res_model': 'account_followup.sending.results',
            'views': [(resource_id, 'form')],
            'type': 'ir.actions.act_window',
            'target': 'new',
        }

    def _get_msg(self, cr, uid, context=None):
        return self.pool.get('res.users').browse(
            cr, uid, uid, context=context).company_id.follow_up_msg

    _defaults = {
        'date': lambda *a: time.strftime('%Y-%m-%d'),
        'followup_id': _get_followup,
        'email_body': "",
        'email_subject': _('Invoices Reminder'),
        'partner_lang': True,
    }

    def _get_partners_followp(self, cr, uid, ids, context=None):
        data = {}
        data = self.browse(cr, uid, ids, context=context)[0]
        company_id = data.company_id.id

        cr.execute(
            "SELECT l.partner_id, l.followup_line_id,l.date_maturity, l.date, l.id "\
            "FROM account_move_line AS l "\
                "LEFT JOIN account_account AS a "\
                "ON (l.account_id=a.id) "\
            "WHERE (l.reconcile_id IS NULL) "\
                "AND (a.type='receivable') "\
                "AND (l.state<>'draft') "\
                "AND (l.partner_id is NOT NULL) "\
                "AND (a.active) "\
                "AND (l.debit > 0) "\
                "AND (l.company_id = %s) " \
                "AND (l.blocked = False)" \
            "ORDER BY l.date", (company_id,))  #l.blocked added to take litigation into account and it is not necessary to change follow-up level of account move lines without debit
        move_lines = cr.fetchall()
        old = None
        fups = {}
        fup_id = 'followup_id' in context and context[
            'followup_id'] or data.followup_id.id
        date = 'date' in context and context['date'] or data.date

        current_date = datetime.date(*time.strptime(date, '%Y-%m-%d')[:3])
        cr.execute(
            "SELECT * "\
            "FROM account_followup_followup_line "\
            "WHERE followup_id=%s "\
            "ORDER BY delay", (fup_id,))

        #Create dictionary of tuples where first element is the date to compare with the due date and second element is the id of the next level
        for result in cr.dictfetchall():
            delay = datetime.timedelta(days=result['delay'])
            fups[old] = (current_date - delay, result['id'])
            old = result['id']

        partner_list = []
        to_update = {}

        #Fill dictionary of accountmovelines to_update with the partners that need to be updated
        for partner_id, followup_line_id, date_maturity, date, id in move_lines:
            if not partner_id:
                continue
            if followup_line_id not in fups:
                continue
            stat_line_id = partner_id * 10000 + company_id
            if date_maturity:
                if date_maturity <= fups[followup_line_id][0].strftime(
                        '%Y-%m-%d'):
                    if stat_line_id not in partner_list:
                        partner_list.append(stat_line_id)
                    to_update[str(id)] = {
                        'level': fups[followup_line_id][1],
                        'partner_id': stat_line_id
                    }
            elif date and date <= fups[followup_line_id][0].strftime(
                    '%Y-%m-%d'):
                if stat_line_id not in partner_list:
                    partner_list.append(stat_line_id)
                to_update[str(id)] = {
                    'level': fups[followup_line_id][1],
                    'partner_id': stat_line_id
                }
        return {'partner_ids': partner_list, 'to_update': to_update}
Example #28
0
class hr_evaluation_interview(osv.Model):
    _name = 'hr.evaluation.interview'
    _inherit = ['mail.thread']
    _rec_name = 'user_to_review_id'
    _description = 'Appraisal Interview'
    _columns = {
        'request_id': fields.many2one('survey.user_input', 'Survey Request', ondelete='cascade', readonly=True),
        'evaluation_id': fields.many2one('hr_evaluation.evaluation', 'Appraisal Plan', required=True),
        'phase_id': fields.many2one('hr_evaluation.plan.phase', 'Appraisal Phase', required=True),
        'user_to_review_id': fields.related('evaluation_id', 'employee_id', type="many2one", relation="hr.employee", string="Employee to evaluate"),
        'user_id': fields.many2one('res.users', 'Interviewer'),
        'state': fields.selection([('draft', "Draft"),
                                   ('waiting_answer', "In progress"),
                                   ('done', "Done"),
                                   ('cancel', "Cancelled")],
                                  string="State", required=True, copy=False),
        'survey_id': fields.related('phase_id', 'survey_id', string="Appraisal Form", type="many2one", relation="survey.survey"),
        'deadline': fields.related('request_id', 'deadline', type="datetime", string="Deadline"),
    }
    _defaults = {
        'state': 'draft'
    }

    def create(self, cr, uid, vals, context=None):
        phase_obj = self.pool.get('hr_evaluation.plan.phase')
        survey_id = phase_obj.read(cr, uid, vals.get('phase_id'), fields=['survey_id'], context=context)['survey_id'][0]

        if vals.get('user_id'):
            user_obj = self.pool.get('res.users')
            partner_id = user_obj.read(cr, uid, vals.get('user_id'), fields=['partner_id'], context=context)['partner_id'][0]
        else:
            partner_id = None

        user_input_obj = self.pool.get('survey.user_input')

        if not vals.get('deadline'):
            vals['deadline'] = (datetime.now() + timedelta(days=28)).strftime(DF)

        ret = user_input_obj.create(cr, uid, {'survey_id': survey_id,
                                              'deadline': vals.get('deadline'),
                                              'type': 'link',
                                              'partner_id': partner_id}, context=context)
        vals['request_id'] = ret
        return super(hr_evaluation_interview, self).create(cr, uid, vals, context=context)

    def name_get(self, cr, uid, ids, context=None):
        if not ids:
            return []
        reads = self.browse(cr, uid, ids, context=context)
        res = []
        for record in reads:
            name = record.survey_id.title
            res.append((record['id'], name))
        return res

    def survey_req_waiting_answer(self, cr, uid, ids, context=None):
        request_obj = self.pool.get('survey.user_input')
        for interview in self.browse(cr, uid, ids, context=context):
            if interview.request_id:
                request_obj.action_survey_resent(cr, uid, [interview.request_id.id], context=context)
            self.write(cr, uid, interview.id, {'state': 'waiting_answer'}, context=context)
        return True

    def survey_req_done(self, cr, uid, ids, context=None):
        for id in self.browse(cr, uid, ids, context=context):
            flag = False
            wating_id = 0
            if not id.evaluation_id.id:
                raise UserError(_("You cannot start evaluation without Appraisal."))
            records = id.evaluation_id.survey_request_ids
            for child in records:
                if child.state == "draft":
                    wating_id = child.id
                    continue
                if child.state != "done":
                    flag = True
            if not flag and wating_id:
                self.survey_req_waiting_answer(cr, uid, [wating_id], context=context)
        self.write(cr, uid, ids, {'state': 'done'}, context=context)
        return True

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

    def action_print_survey(self, cr, uid, ids, context=None):
        """ If response is available then print this response otherwise print survey form (print template of the survey) """
        context = dict(context or {})
        interview = self.browse(cr, uid, ids, context=context)[0]
        survey_obj = self.pool.get('survey.survey')
        response_obj = self.pool.get('survey.user_input')
        response = response_obj.browse(cr, uid, interview.request_id.id, context=context)
        context.update({'survey_token': response.token})
        return survey_obj.action_print_survey(cr, uid, [interview.survey_id.id], context=context)

    def action_start_survey(self, cr, uid, ids, context=None):
        context = dict(context or {})
        interview = self.browse(cr, uid, ids, context=context)[0]
        survey_obj = self.pool.get('survey.survey')
        response_obj = self.pool.get('survey.user_input')
        # grab the token of the response and start surveying
        response = response_obj.browse(cr, uid, interview.request_id.id, context=context)
        context.update({'survey_token': response.token})
        return survey_obj.action_start_survey(cr, uid, [interview.survey_id.id], context=context)
class IrAttachment(osv.Model):
    """ Update partner to add a field about notification preferences """
    _name = "ir.attachment"
    _inherit = 'ir.attachment'

    _fileext_to_type = {
        '7z': 'archive',
        'aac': 'audio',
        'ace': 'archive',
        'ai': 'vector',
        'aiff': 'audio',
        'apk': 'archive',
        'app': 'binary',
        'as': 'script',
        'asf': 'video',
        'ass': 'text',
        'avi': 'video',
        'bat': 'script',
        'bin': 'binary',
        'bmp': 'image',
        'bzip2': 'archive',
        'c': 'script',
        'cab': 'archive',
        'cc': 'script',
        'ccd': 'disk',
        'cdi': 'disk',
        'cdr': 'vector',
        'cer': 'certificate',
        'cgm': 'vector',
        'cmd': 'script',
        'coffee': 'script',
        'com': 'binary',
        'cpp': 'script',
        'crl': 'certificate',
        'crt': 'certificate',
        'cs': 'script',
        'csr': 'certificate',
        'css': 'html',
        'csv': 'spreadsheet',
        'cue': 'disk',
        'd': 'script',
        'dds': 'image',
        'deb': 'archive',
        'der': 'certificate',
        'djvu': 'image',
        'dmg': 'archive',
        'dng': 'image',
        'doc': 'document',
        'docx': 'document',
        'dvi': 'print',
        'eot': 'font',
        'eps': 'vector',
        'exe': 'binary',
        'exr': 'image',
        'flac': 'audio',
        'flv': 'video',
        'gif': 'webimage',
        'gz': 'archive',
        'gzip': 'archive',
        'h': 'script',
        'htm': 'html',
        'html': 'html',
        'ico': 'image',
        'icon': 'image',
        'img': 'disk',
        'iso': 'disk',
        'jar': 'archive',
        'java': 'script',
        'jp2': 'image',
        'jpe': 'webimage',
        'jpeg': 'webimage',
        'jpg': 'webimage',
        'jpx': 'image',
        'js': 'script',
        'key': 'presentation',
        'keynote': 'presentation',
        'lisp': 'script',
        'lz': 'archive',
        'lzip': 'archive',
        'm': 'script',
        'm4a': 'audio',
        'm4v': 'video',
        'mds': 'disk',
        'mdx': 'disk',
        'mid': 'audio',
        'midi': 'audio',
        'mkv': 'video',
        'mng': 'image',
        'mp2': 'audio',
        'mp3': 'audio',
        'mp4': 'video',
        'mpe': 'video',
        'mpeg': 'video',
        'mpg': 'video',
        'nrg': 'disk',
        'numbers': 'spreadsheet',
        'odg': 'vector',
        'odm': 'document',
        'odp': 'presentation',
        'ods': 'spreadsheet',
        'odt': 'document',
        'ogg': 'audio',
        'ogm': 'video',
        'otf': 'font',
        'p12': 'certificate',
        'pak': 'archive',
        'pbm': 'image',
        'pdf': 'print',
        'pem': 'certificate',
        'pfx': 'certificate',
        'pgf': 'image',
        'pgm': 'image',
        'pk3': 'archive',
        'pk4': 'archive',
        'pl': 'script',
        'png': 'webimage',
        'pnm': 'image',
        'ppm': 'image',
        'pps': 'presentation',
        'ppt': 'presentation',
        'ps': 'print',
        'psd': 'image',
        'psp': 'image',
        'py': 'script',
        'r': 'script',
        'ra': 'audio',
        'rar': 'archive',
        'rb': 'script',
        'rpm': 'archive',
        'rtf': 'text',
        'sh': 'script',
        'sub': 'disk',
        'svg': 'vector',
        'sxc': 'spreadsheet',
        'sxd': 'vector',
        'tar': 'archive',
        'tga': 'image',
        'tif': 'image',
        'tiff': 'image',
        'ttf': 'font',
        'txt': 'text',
        'vbs': 'script',
        'vc': 'spreadsheet',
        'vml': 'vector',
        'wav': 'audio',
        'webp': 'image',
        'wma': 'audio',
        'wmv': 'video',
        'woff': 'font',
        'xar': 'vector',
        'xbm': 'image',
        'xcf': 'image',
        'xhtml': 'html',
        'xls': 'spreadsheet',
        'xlsx': 'spreadsheet',
        'xml': 'html',
        'zip': 'archive'
    }

    def get_attachment_type(self, cr, uid, ids, name, args, context=None):
        result = {}
        for attachment in self.browse(cr, uid, ids, context=context):
            fileext = os.path.splitext(attachment.datas_fname or '')[1].lower()[1:]
            result[attachment.id] = self._fileext_to_type.get(fileext, 'unknown')
        return result

    _columns = {
        'file_type_icon': fields.function(get_attachment_type, type='char', string='File Type Icon'),
        'file_type': fields.related('file_type_icon', type='char'),     # FIXME remove in trunk
    }
Example #30
0
class procurement_rule(osv.osv):
    _inherit = 'procurement.rule'

    def _get_action(self, cr, uid, context=None):
        result = super(procurement_rule, self)._get_action(cr,
                                                           uid,
                                                           context=context)
        return result + [('move', _('Move From Another Location'))]

    def _get_rules(self, cr, uid, ids, context=None):
        res = []
        for route in self.browse(cr, uid, ids):
            res += [x.id for x in route.pull_ids]
        return res

    _columns = {
        'location_id':
        fields.many2one('stock.location', 'Procurement Location'),
        'location_src_id':
        fields.many2one('stock.location',
                        'Source Location',
                        help="Source location is action=move"),
        'route_id':
        fields.many2one('stock.location.route',
                        'Route',
                        help="If route_id is False, the rule is global"),
        'procure_method':
        fields.selection(
            [('make_to_stock', 'Take From Stock'),
             ('make_to_order', 'Create Procurement')],
            'Move Supply Method',
            required=True,
            help=
            """Determines the procurement method of the stock move that will be generated: whether it will need to 'take from the available stock' in its source location or needs to ignore its stock and create a procurement over there."""
        ),
        'route_sequence':
        fields.related('route_id',
                       'sequence',
                       string='Route Sequence',
                       store={
                           'stock.location.route':
                           (_get_rules, ['sequence'], 10),
                           'procurement.rule':
                           (lambda self, cr, uid, ids, c={}: ids, ['route_id'],
                            10),
                       }),
        'picking_type_id':
        fields.many2one(
            'stock.picking.type',
            'Picking Type',
            help=
            "Picking Type determines the way the picking should be shown in the view, reports, ..."
        ),
        'delay':
        fields.integer('Number of Days'),
        'partner_address_id':
        fields.many2one('res.partner', 'Partner Address'),
        'propagate':
        fields.boolean(
            'Propagate cancel and split',
            help=
            'If checked, when the previous move of the move (which was generated by a next procurement) is cancelled or split, the move generated by this move will too'
        ),
        'warehouse_id':
        fields.many2one('stock.warehouse',
                        'Served Warehouse',
                        help='The warehouse this rule is for'),
        'propagate_warehouse_id':
        fields.many2one(
            'stock.warehouse',
            'Warehouse to Propagate',
            help=
            "The warehouse to propagate on the created move/procurement, which can be different of the warehouse this rule is for (e.g for resupplying rules from another warehouse)"
        ),
    }

    _defaults = {
        'procure_method': 'make_to_stock',
        'propagate': True,
        'delay': 0,
    }
Example #31
0
class account_asset_depreciation_line(osv.osv):
    _name = 'account.asset.depreciation.line'
    _description = 'Asset depreciation line'

    def _get_move_check(self, cr, uid, ids, name, args, context=None):
        res = {}
        for line in self.browse(cr, uid, ids, context=context):
            res[line.id] = bool(line.move_id)
        return res

    _columns = {
        'name':
        fields.char('Depreciation Name', size=64, required=True, select=1),
        'sequence':
        fields.integer('Sequence', required=True),
        'asset_id':
        fields.many2one('account.asset.asset',
                        'Asset',
                        required=True,
                        ondelete='cascade'),
        'parent_state':
        fields.related('asset_id',
                       'state',
                       type='char',
                       string='State of Asset'),
        'amount':
        fields.float('Current Depreciation',
                     digits_compute=dp.get_precision('Account'),
                     required=True),
        'remaining_value':
        fields.float('Next Period Depreciation',
                     digits_compute=dp.get_precision('Account'),
                     required=True),
        'depreciated_value':
        fields.float('Amount Already Depreciated', required=True),
        'depreciation_date':
        fields.date('Depreciation Date', select=1),
        'move_id':
        fields.many2one('account.move', 'Depreciation Entry'),
        'move_check':
        fields.function(_get_move_check,
                        method=True,
                        type='boolean',
                        string='Posted',
                        store=True)
    }

    def create_move(self, cr, uid, ids, context=None):
        can_close = False
        if context is None:
            context = {}
        asset_obj = self.pool.get('account.asset.asset')
        period_obj = self.pool.get('account.period')
        move_obj = self.pool.get('account.move')
        move_line_obj = self.pool.get('account.move.line')
        currency_obj = self.pool.get('res.currency')
        created_move_ids = []
        asset_ids = []
        for line in self.browse(cr, uid, ids, context=context):
            depreciation_date = context.get(
                'depreciation_date') or time.strftime('%Y-%m-%d')
            period_ids = period_obj.find(cr,
                                         uid,
                                         depreciation_date,
                                         context=context)
            company_currency = line.asset_id.company_id.currency_id.id
            current_currency = line.asset_id.currency_id.id
            context.update({'date': depreciation_date})
            amount = currency_obj.compute(cr,
                                          uid,
                                          current_currency,
                                          company_currency,
                                          line.amount,
                                          context=context)
            sign = (line.asset_id.category_id.journal_id.type == 'purchase'
                    and 1) or -1
            asset_name = line.asset_id.name
            reference = line.name
            move_vals = {
                'name': asset_name,
                'date': depreciation_date,
                'ref': reference,
                'period_id': period_ids and period_ids[0] or False,
                'journal_id': line.asset_id.category_id.journal_id.id,
            }
            move_id = move_obj.create(cr, uid, move_vals, context=context)
            journal_id = line.asset_id.category_id.journal_id.id
            partner_id = line.asset_id.partner_id.id
            move_line_obj.create(
                cr, uid, {
                    'name':
                    asset_name,
                    'ref':
                    reference,
                    'move_id':
                    move_id,
                    'account_id':
                    line.asset_id.category_id.account_depreciation_id.id,
                    'debit':
                    0.0,
                    'credit':
                    amount,
                    'period_id':
                    period_ids and period_ids[0] or False,
                    'journal_id':
                    journal_id,
                    'partner_id':
                    partner_id,
                    'currency_id':
                    company_currency != current_currency and current_currency
                    or False,
                    'amount_currency':
                    company_currency != current_currency
                    and -sign * line.amount or 0.0,
                    'date':
                    depreciation_date,
                })
            move_line_obj.create(
                cr, uid, {
                    'name':
                    asset_name,
                    'ref':
                    reference,
                    'move_id':
                    move_id,
                    'account_id':
                    line.asset_id.category_id.account_expense_depreciation_id.
                    id,
                    'credit':
                    0.0,
                    'debit':
                    amount,
                    'period_id':
                    period_ids and period_ids[0] or False,
                    'journal_id':
                    journal_id,
                    'partner_id':
                    partner_id,
                    'currency_id':
                    company_currency != current_currency and current_currency
                    or False,
                    'amount_currency':
                    company_currency != current_currency and sign * line.amount
                    or 0.0,
                    'analytic_account_id':
                    line.asset_id.category_id.account_analytic_id.id,
                    'date':
                    depreciation_date,
                    'asset_id':
                    line.asset_id.id
                })
            self.write(cr, uid, line.id, {'move_id': move_id}, context=context)
            created_move_ids.append(move_id)
            asset_ids.append(line.asset_id.id)
        # we re-evaluate the assets to determine whether we can close them
        for asset in asset_obj.browse(cr,
                                      uid,
                                      list(set(asset_ids)),
                                      context=context):
            if currency_obj.is_zero(cr, uid, asset.currency_id,
                                    asset.value_residual):
                asset.write({'state': 'close'})
        return created_move_ids
Example #32
0
class hon_issue_line(orm.Model):

    _name = "hon.issue.line"

    def _amount_line(self, cr, uid, ids, prop, unknow_none, unknow_dict):
        res = {}
        for line in self.browse(cr, uid, ids):
            price = line.price_unit * line.quantity
            res[line.id] = price
        return res

    _columns = {
        'sequence': fields.integer('Sequence', help="Gives the sequence of this line when displaying the honorarium issue."),
        'name': fields.char('Description', required=True, size=64),
        'page_number': fields.char('Pgnr', size=32),
        'nr_of_columns': fields.float('#Cols', digits_compute= dp.get_precision('Number of Columns'), required=True),
        'issue_id': fields.many2one('hon.issue', 'Issue Reference', ondelete='cascade', select=True),
        'partner_id': fields.many2one('res.partner', 'Partner', required=True),
        'employee': fields.boolean('Employee',  help="It indicates that the partner is an employee."),
        'product_category_id': fields.many2one('product.category', 'T/B',required=True, domain=[('parent_id.supportal', '=', True)]),
        'product_id': fields.many2one('product.product', 'Product', required=True,),
        'account_id': fields.many2one('account.account', 'Account', required=True, domain=[('type','<>','view'), ('type', '<>', 'closed')],
                                      help="The income or expense account related to the selected product."),
        'uos_id': fields.many2one('product.uom', 'Unit of Measure', ondelete='set null', select=True),
        'price_unit': fields.float('Unit Price', required=True, digits_compute= dp.get_precision('Product Price')),
        'quantity': fields.float('Quantity', digits_compute= dp.get_precision('Product Unit of Measure'), required=True),
        'account_analytic_id': fields.related('issue_id','account_analytic_id',type='many2one', relation='account.analytic.account', string='Issue',store=True, readonly=True ),
        # 'parent_analytic_id': fields.related('account_analytic_id', 'parent_id', type='many2one',
        #                                       relation='account.analytic.account', string='Title', store=True,
        #                                       readonly=True),
        'date_publish': fields.related('account_analytic_id', 'date_publish', type='date',
                                       relation='account.analytic.account', string='Publishing Date', store=True,
                                       readonly=True),
        'activity_id': fields.many2one('project.activity_al', 'Page Type',  ondelete='set null', select=True),
        'company_id': fields.related('issue_id','company_id',type='many2one',relation='res.company',string='Company', store=True, readonly=True),
        'price_subtotal': fields.function(_amount_line, string='Amount', type="float",
            digits_compute= dp.get_precision('Account'), store=True),
        'estimated_price': fields.float('Estimate',),
        'invoice_line_id': fields.many2one('account.invoice.line', 'Invoice Line', readonly=True),
        'invoice_id': fields.related('invoice_line_id', 'invoice_id', type='many2one', relation='account.invoice', string='Invoice', readonly=True),
        'state': fields.selection(
            [('cancel', 'Cancelled'),
             ('draft', 'Draft'),
             ('confirmed', 'Confirmed'),
             ('exception', 'Exception'),
             ('done', 'Done')],
            'Status', required=True, readonly=True,
            help='* The \'Draft\' status is set when the related hon issue in draft status. \
                        \n* The \'Confirmed\' status is set when the related hon issue is confirmed. \
                        \n* The \'Exception\' status is set when the related hon issue is set as exception. \
                        \n* The \'Done\' status is set when the hon line has been picked. \
                        \n* The \'Cancelled\' status is set when a user cancel the hon issue related.'),
        'gratis': fields.boolean('Gratis',  help="It indicates that no letter/invoice is generated.")
    }

    def _default_account_id(self, cr, uid, context=None):
        # XXX this gets the default account for the user's company,
        # it should get the default account for the invoice's company
        # however, the invoice's company does not reach this point
        if context is None:
            context = {}
        prop = self.pool.get('ir.property').get(cr, uid, 'property_account_expense_categ', 'product.category', context=context)
        print "pop ", prop

        return prop and prop.id or False

    _defaults = {
        'quantity': 1,
        'sequence': 10,
        'account_id': _default_account_id,
        'state': 'draft',
        'price_unit': 0.0,
        'employee': False,
    }



    def _prepare_hon_issue_line_invoice_line(self, cr, uid, line, account_id=False, context=None):
        """Prepare the dict of values to create the new invoice line for a
           honorarium line. This method may be overridden to implement custom
           invoice generation (making sure to call super() to establish
           a clean extension chain).

           :param browse_record line: hon.issue.line record to invoice
           :param int account_id: optional ID of a G/L account to force
               (this is used for returning products including service)
           :return: dict of values to create() the invoice line
        """
        res = {}
        if not line.invoice_line_id:
            if not account_id:
                if line.product_id:
                    account_id = line.product_id.property_account_expense_id.id
                    if not account_id:
                        account_id = line.product_id.categ_id.property_account_expense_categ_id.id
                    if not account_id:
                        raise osv.except_osv(_('Error!'),
                                _('Please define expense account for this product: "%s" (id:%d).') % \
                                    (line.product_id.name, line.product_id.id,))
                else:
                    prop = self.pool.get('ir.property').get(cr, uid,
                            'property_account_expense_categ_id', 'product.category',
                            context=context)
                    account_id = prop and prop.id or False
            qty = line.quantity
            fpos = line.partner_id.property_account_position_id or False
            account_id = self.pool.get('account.fiscal.position').map_account(cr, uid, fpos, account_id)
            if not account_id:
                raise osv.except_osv(_('Error!'),
                            _('There is no Fiscal Position defined or Expense category account defined for default properties of Product categories.'))
            res = {
                'hon_issue_line_id': line.id,
                'account_analytic_id': line.account_analytic_id and line.account_analytic_id.id or False,
                'name': line.name,
                'sequence': line.sequence,
                'origin': line.issue_id.name,
                'account_id': account_id,
                'price_unit': line.price_unit,
                'quantity': qty,
                'uos_id': line.uos_id,
                'product_id': line.product_id.id or False,
                'activity_id': line.activity_id and line.activity_id.id or False,
            }

        return res

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

        create_ids = []
        hon = set()
        for line in self.browse(cr, uid, ids, context=context):
            vals = self._prepare_hon_issue_line_invoice_line(cr, uid, line, False, context)
            if vals:
                inv_id = self.pool.get('account.invoice.line').create(cr, uid, vals, context=context)
                self.write(cr, uid, [line.id], {'invoice_line_id': inv_id }, context=context)
                hon.add(line.issue_id.id)
                create_ids.append(inv_id)
        # Trigger workflow events
        wf_service = netsvc.LocalService("workflow")
        for issue_id in hon:
            wf_service.trg_write(uid, 'hon.issue', issue_id, cr)
        return create_ids

    def button_cancel(self, cr, uid, ids, context=None):
        for line in self.browse(cr, uid, ids, context=context):
            if line.invoice_line_id:
                raise osv.except_osv(_('Invalid Action!'), _('You cannot cancel a Hon line that has already been invoiced.'))
        return self.write(cr, uid, ids, {'state': 'cancel'})

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

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

    def button_done(self, cr, uid, ids, context=None):
        wf_service = netsvc.LocalService("workflow")
        res = self.write(cr, uid, ids, {'state': 'done'})
        for line in self.browse(cr, uid, ids, context=context):
            wf_service.trg_write(uid, 'hon.issue', line.issue_id.id, cr)
        return res

    def unlink(self, cr, uid, ids, context=None):
        if context is None:
            context = {}
        """Allows to delete hon lines in draft,cancel states"""
        for rec in self.browse(cr, uid, ids, context=context):
            if rec.state not in ['draft', 'cancel']:
                raise osv.except_osv(_('Invalid Action!'), _('Cannot delete a hon line which is in state \'%s\'.') %(rec.state,))
        return super(hon_issue_line, self).unlink(cr, uid, ids, context=context)

    def partner_id_change(self, cr, uid, ids, partner_id=False,  context=None):
        if context is None:
            context = {}
        if not partner_id :
            # raise osv.except_osv(_('No Partner Defined!'),_("You must first select a partner!") )
            return {'value':{}}

        part = self.pool.get('res.partner').browse(cr, uid, partner_id, context=context)
        result = {}
        if part.employee :
            result['employee'] = True
        else:
            result['employee'] = False
        if part.product_category_ids:
            result['product_category_id'] = part.product_category_ids[0].id
        res_final = {'value':result}
        return res_final

    def product_category_change(self, cr, uid, ids, product_category=False, product=False, context=None):
        result = {}
        if product:
            prod_obj = self.pool['product.product'].browse(cr, uid, product, context=context)
        if product_category is not prod_obj.categ_id:
            result['product_id'] = []
        else:
            result['product_id'] = product
        return {'value': result}


    def price_quantity_change(self, cr, uid, ids, partner_id=False, price_unit=False, quantity=False, price_subtotal=False, context=None):
        if context is None:
            context = {}

        result = {}
        if price_unit :
            if quantity :
                price = price_unit * quantity
            result['price_subtotal'] = price
        else:
            result['price_subtotal'] = price_subtotal
        res_final = {'value':result,}
        return res_final


    def product_id_change(self, cr, uid, ids, product,  partner_id=False, price_unit=False, context=None ):
        if context is None:
            context = {}
        user = self.pool.get('res.users').browse(cr, uid, uid, context=context)
        company_id = context.get('company_id', user.company_id.id)
        context = dict(context)
        context.update({'company_id': company_id, 'force_company': company_id})
        if not partner_id :
            # raise osv.except_osv(_('No Partner Defined!'),_("You must first select a partner!") )
            return {'value':{}}

        if not product:
            # raise osv.except_osv(_('No Product Defined!'),_("You must first select a Product!") )
            return {'value':{}}

        print "............ca,e"

        part = self.pool.get('res.partner').browse(cr, uid, partner_id, context=context)
        if part.lang:
            context.update({'lang': part.lang})
        result = {}
        res = self.pool.get('product.product').browse(cr, uid, product, context=context)
        a = res.property_account_expense_id.id
        if not a:
            a = res.categ_id.property_account_expense_categ_id.id
        if a:
            result['account_id'] = a
        pricelist = self.pool.get('partner.product.price').search(cr, uid, [('product_id','=',product),
                                 ('partner_id','=', partner_id), ('company_id','=', company_id )], context=context)
        if len(pricelist) >= 1 :
            price = self.pool.get('partner.product.price').browse(cr, uid, pricelist, context=context )
            if price :
                result.update( {'price_unit': price[0].price_unit} )
        else:
            result.update( {'price_unit': 0 } )

        res_final = {'value':result,}

        return res_final
class nh_activity(orm.Model):
    """
    Extends class :class:`nh_activity<activity.nh_activity>`.
    """

    _name = 'nh.activity'
    _inherit = 'nh.activity'

    _columns = {
        'user_ids':
        fields.many2many('res.users',
                         'activity_user_rel',
                         'activity_id',
                         'user_id',
                         'Users',
                         readonly=True),
        'patient_id':
        fields.many2one('nh.clinical.patient', 'Patient', readonly=True),
        'location_id':
        fields.many2one('nh.clinical.location', 'Location', readonly=True),
        'location_name':
        fields.related('location_id',
                       'full_name',
                       type='char',
                       size=150,
                       string='Location Name'),
        'pos_id':
        fields.many2one('nh.clinical.pos', 'POS', readonly=True),
        'spell_activity_id':
        fields.many2one('nh.activity', 'Spell Activity', readonly=True),
        'cancel_reason_id':
        fields.many2one('nh.cancel.reason', 'Cancellation Reason'),
        'ward_manager_id':
        fields.many2one('res.users',
                        'Ward Manager of the ward on Complete/Cancel')
    }

    def create(self, cr, uid, vals, context=None):
        """
        Extends Odoo's `create()` method.

        Writes ``user_ids`` for responsible users of the activities`
        location.

        :param vals: values to create record
        :type vals: doct
        :returns: :class:`nh_activity<activity.nh_activity>` id
        :rtype: int
        """
        res = super(nh_activity, self).create(cr, uid, vals, context=context)
        if vals.get('location_id'):
            user_ids = self.pool['nh.activity.data'].get_activity_user_ids(
                cr, uid, res, context=context)
            if vals.get('data_model') == 'nh.clinical.spell':
                self.update_users(cr, uid, user_ids)
            else:
                self.write(cr, uid, res, {'user_ids': [[6, False, user_ids]]})
        return res

    def write(self, cr, uid, ids, values, context=None):
        """
        Extends Odoo's `write()` method.

        Also writes ``user_ids`` for responsible users of the
        activities' location. See class
        :mod:`nh_clinical_location<base.nh_clinical_location>`.

        :param ids: :class:`nh_activity<activity.nh_activity>`
            record ids
        :type ids: list
        :param vals: values to update records (may include
            ``location_id``)
        :type vals: dict
        :returns: ``True``
        :rtype: bool
        """

        if not values:
            values = {}
        res = super(nh_activity, self).write(cr,
                                             uid,
                                             ids,
                                             values,
                                             context=context)
        if 'location_id' in values:
            location_pool = self.pool['nh.clinical.location']
            location = location_pool.read(cr,
                                          uid,
                                          values['location_id'], ['user_ids'],
                                          context=context)
            if location:
                self.write(cr,
                           uid,
                           ids,
                           {'user_ids': [[6, False, location['user_ids']]]},
                           context=context)
        return res

    def cancel_open_activities(self, cr, uid, parent_id, model, context=None):
        """
        Cancels all open activities of parent activity.

        :param parent_id: id of the parent activity
        :type parent_id: int
        :param model: model (type) of activity
        :type model: str
        :returns: ``True`` if all open activities are cancelled or if
            there are no open activities. Otherwise, ``False``
        :rtype: bool
        """

        domain = [('parent_id', '=', parent_id), ('data_model', '=', model),
                  ('state', 'not in', ['completed', 'cancelled'])]
        open_activity_ids = self.search(cr, uid, domain, context=context)
        return all([
            self.cancel(cr, uid, a, context=context) for a in open_activity_ids
        ])

    def update_users(self, cr, uid, user_ids):
        """
        Updates activities with the user_ids of users responsible for
        the activities' locations.

        :param user_ids: user ids. See class
            :class:`res_users<base.res_users>`
        :type user_ids: list
        :returns: ``True``
        :rtype: bool
        """

        if not user_ids:
            return True

        where_clause = "where user_id in (%s)" % list2sqlstr(user_ids)

        sql = """
            delete from activity_user_rel {where_clause};
            insert into activity_user_rel
            select activity_id, user_id from
                (select distinct on (activity.id, ulr.user_id)
                        activity.id as activity_id,
                        ulr.user_id
                from user_location_rel ulr
                inner join res_groups_users_rel gur on ulr.user_id = gur.uid
                inner join ir_model_access access on access.group_id = gur.gid
                  and access.perm_responsibility = true
                inner join ir_model model on model.id = access.model_id
                inner join nh_activity activity
                  on model.model = activity.data_model
                  and activity.location_id = ulr.location_id
                  and activity.state not in ('completed','cancelled')
                where not exists
                  (select 1 from activity_user_rel
                    where activity_id=activity.id
                    and user_id=ulr.user_id )) pairs
            {where_clause}
        """.format(where_clause=where_clause)
        cr.execute(sql)
        self.update_spell_users(cr, uid, user_ids)

        return True

    def update_spell_users(self, cr, uid, user_ids=None):
        """
        Updates spell activities with the user_ids of users
        responsible for parent locations of spell location.

        :param user_ids: user ids. See class
            :class:`res_users<base.res_users>`
        :type user_ids: list
        :returns: ``True``
        :rtype: bool
        """

        if not user_ids:
            return True

        where_clause = "where user_id in (%s)" % list2sqlstr(user_ids)

        sql = """
            with
               recursive route(level, path, parent_id, id) as (
                       select 0, id::text, parent_id, id
                       from nh_clinical_location
                       where parent_id is null
                   union
                       select level + 1, path||','||location.id,
                        location.parent_id, location.id
                       from nh_clinical_location location
                       join route on location.parent_id = route.id
               ),
               parent_location as (
                   select
                       id as location_id,
                       ('{'||path||'}')::int[] as ids
                   from route
                   order by path
               )
           insert into activity_user_rel
           select activity_id, user_id from (
               select distinct on (activity.id, ulr.user_id)
                   activity.id as activity_id,
                   ulr.user_id
               from user_location_rel ulr
               inner join res_groups_users_rel gur on ulr.user_id = gur.uid
               inner join ir_model_access access
                on access.group_id = gur.gid
                and access.perm_responsibility = true
               inner join ir_model model
                on model.id = access.model_id
                and model.model = 'nh.clinical.spell'
               inner join parent_location
                on parent_location.ids  && array[ulr.location_id]
               inner join nh_activity activity
                on model.model = activity.data_model
                and activity.location_id = parent_location.location_id
               where not exists
                (select 1 from activity_user_rel
                where activity_id=activity.id and user_id=ulr.user_id )) pairs
           %s
        """ % where_clause

        cr.execute(sql)
        return True
Example #34
0
class wh_move_line(osv.osv):
    _name = 'wh.move.line'

    MOVE_LINE_TYPE = [
        ('out', u'出库'),
        ('in', u'入库'),
    ]

    MOVE_LINE_STATE = [
        ('draft', u'草稿'),
        ('done', u'已审核'),
    ]

    def default_get(self, cr, uid, fields, context=None):
        res = super(wh_move_line, self).default_get(cr,
                                                    uid,
                                                    fields,
                                                    context=context)
        context = context or {}
        if context.get('goods_id') and context.get('warehouse_id'):
            res.update({
                'goods_id': context.get('goods_id'),
                'warehouse_id': context.get('warehouse_id')
            })

        return res

    def get_real_price(self, cr, uid, ids, context=None):
        for line in self.browse(cr, uid, ids, context=context):
            return safe_division(line.subtotal, line.goods_qty)

    def name_get(self, cr, uid, ids, context=None):
        context = context or {}
        res = []
        for line in self.browse(cr, uid, ids, context=context):
            if context.get('lot'):
                res.append((line.id, '%s-%s' % (line.lot, line.qty_remaining)))
            else:
                res.append((line.id, '%s-%s->%s(%s, %s%s)' %
                            (line.move_id.name, line.warehouse_id.name,
                             line.warehouse_dest_id.name, line.goods_id.name,
                             str(line.goods_qty), line.uom_id.name)))
        return res

    def check_availability(self, cr, uid, ids, context=None):
        for line in self.browse(cr, uid, ids, context=context):
            if line.warehouse_dest_id.id == line.warehouse_id.id:
                raise osv.except_osv(u'错误', u'调出仓库不可以和调入仓库一样')

        return True

    def prev_action_done(self, cr, uid, ids, context=None):
        pass

    def action_done(self, cr, uid, ids, context=None):
        for line in self.browse(cr, uid, ids, context=context):
            line.check_availability()
            line.prev_action_done()
            line.write({
                'state': 'done',
                'date': fields.datetime.now(cr, uid),
            })

    def check_cancel(self, cr, uid, ids, context=None):
        pass

    def prev_action_cancel(self, cr, uid, ids, context=None):
        pass

    def action_cancel(self, cr, uid, ids, context=None):
        for line in self.browse(cr, uid, ids, context=context):
            line.check_cancel()
            line.prev_action_cancel()
            line.write({
                'state': 'draft',
                'date': False,
            })

    def _get_default_warehouse(self, cr, uid, context=None):
        context = context or {}
        if context.get('warehouse_type'):
            return self.pool.get('warehouse').get_warehouse_by_type(
                cr, uid, context.get('warehouse_type'))

        return False

    def _get_default_warehouse_dest(self, cr, uid, context=None):
        context = context or {}
        if context.get('warehouse_dest_type'):
            return self.pool.get('warehouse').get_warehouse_by_type(
                cr, uid, context.get('warehouse_dest_type'))

        return False

    def _get_subtotal_util(self, cr, uid, goods_qty, price, context=None):
        return goods_qty * price

    def onchange_price_by_out(self,
                              cr,
                              uid,
                              ids,
                              goods_id,
                              warehouse_id,
                              goods_qty,
                              context=None):
        if goods_id and warehouse_id and goods_qty:
            subtotal, price = self.pool.get(
                'goods').get_suggested_cost_by_warehouse(cr,
                                                         uid,
                                                         goods_id,
                                                         warehouse_id,
                                                         goods_qty,
                                                         context=context)

            return {
                'value': {
                    'price': price,
                    'subtotal': subtotal,
                }
            }

        return {}

    def onchange_price_by_in(self,
                             cr,
                             uid,
                             ids,
                             goods_qty,
                             price,
                             context=None):
        if goods_qty and price:
            return {
                'value': {
                    'subtotal':
                    self._get_subtotal_util(cr,
                                            uid,
                                            goods_qty,
                                            price,
                                            context=context)
                }
            }

        return {'value': {'subtotal': 0}}

    def onchange_goods_by_in(self,
                             cr,
                             uid,
                             ids,
                             goods_id,
                             goods_qty,
                             context=None):
        # TODO 需要计算保质期
        if goods_id:
            goods = self.pool.get('goods').browse(cr,
                                                  uid,
                                                  goods_id,
                                                  context=context)
            return {
                'value': {
                    'uom_id': goods.uom_id.id,
                    'using_batch': goods.using_batch,
                    'force_batch_one': goods.force_batch_one,
                    'goods_qty': goods.force_batch_one and 1 or goods_qty,
                }
            }

        return {}

    def onchange_lot_out(self, cr, uid, ids, lot_id, context=None):
        if lot_id:
            lot = self.browse(cr, uid, lot_id, context=context)
            return {
                'value': {
                    'warehouse_id': lot.warehouse_dest_id.id,
                    'goods_qty': lot.qty_remaining,
                    'lot_qty': lot.qty_remaining
                }
            }

        return {}

    def onchange_goods_by_out(self,
                              cr,
                              uid,
                              ids,
                              goods_id,
                              warehouse_id,
                              lot_id,
                              goods_qty,
                              compute_price=True,
                              context=None):
        res = {}
        lot_domain = [('goods_id', '=', goods_id), ('state', '=', 'done'),
                      ('lot', '!=', False), ('qty_remaining', '>', 0)]

        if goods_id:
            goods = self.pool.get('goods').browse(cr,
                                                  uid,
                                                  goods_id,
                                                  context=context)
            res.update({
                'uom_id': goods.uom_id.id,
                'using_batch': goods.using_batch,
                'force_batch_one': goods.force_batch_one,
            })

            if warehouse_id:
                if compute_price and goods_qty:
                    subtotal, price = self.pool.get(
                        'goods').get_suggested_cost_by_warehouse(
                            cr,
                            uid,
                            goods_id,
                            warehouse_id,
                            goods_qty,
                            context=context)

                    res.update({
                        'price': price,
                        'subtotal': subtotal,
                    })

                lot_domain.append(('warehouse_dest_id', '=', warehouse_id))

        if lot_id:
            lot = self.browse(cr, uid, lot_id, context=context)
            if warehouse_id and lot.warehouse_dest_id.id != warehouse_id:
                res.update({'lot_id': False})

            if goods_id and lot.goods_id.id != goods_id:
                res.update({'lot_id': False})

        return {'value': res, 'domain': {'lot_id': lot_domain}}

    def onchange_goods_by_internal(self,
                                   cr,
                                   uid,
                                   ids,
                                   goods_id,
                                   goods_qty,
                                   context=None):
        return self.onchange_goods_by_in(cr,
                                         uid,
                                         ids,
                                         goods_id,
                                         goods_qty,
                                         context=context)

    def unlink(self, cr, uid, ids, context=None):
        for line in self.browse(cr, uid, ids, context=context):
            if line.state == 'done':
                raise osv.except_osv(u'错误', u'不可以删除已经完成的明细')

        return super(wh_move_line, self).unlink(cr, uid, ids, context=context)

    _columns = {
        'move_id':
        fields.many2one('wh.move', string=u'移库单', ondelete='cascade'),
        'date':
        fields.datetime(u'完成日期', copy=False),
        'type':
        fields.selection(MOVE_LINE_TYPE, u'类型'),
        'state':
        fields.selection(MOVE_LINE_STATE, u'状态', copy=False),
        'goods_id':
        fields.many2one('goods', string=u'产品', required=True, index=True),
        'using_batch':
        fields.related('goods_id',
                       'using_batch',
                       type='boolean',
                       string=u'批次管理'),
        'force_batch_one':
        fields.related('goods_id',
                       'force_batch_one',
                       type='boolean',
                       string=u'每批次数量为1'),
        'lot':
        fields.char(u'序列号'),
        'lot_id':
        fields.many2one('wh.move.line', u'序列号'),
        'lot_qty':
        fields.related('lot_id',
                       'qty_remaining',
                       type='float',
                       string=u'序列号数量'),
        'production_date':
        fields.date(u'生产日期'),
        'shelf_life':
        fields.integer(u'保质期(天)'),
        'valid_date':
        fields.date(u'有效期至'),
        'uom_id':
        fields.many2one('uom', string=u'单位'),
        'warehouse_id':
        fields.many2one('warehouse', string=u'调出仓库', required=True),
        'warehouse_dest_id':
        fields.many2one('warehouse', string=u'调入仓库', required=True),
        'goods_qty':
        fields.float(u'数量', digits_compute=dp.get_precision('Goods Quantity')),
        'price':
        fields.float(u'单价', digits_compute=dp.get_precision('Accounting')),
        'subtotal':
        fields.float(u'金额', digits_compute=dp.get_precision('Accounting')),
        'note':
        fields.text(u'备注'),
    }

    _defaults = {
        'type': lambda self, cr, uid, ctx=None: ctx.get('type'),
        'goods_qty': lambda self, cr, uid, ctx=None: 1,
        'state': 'draft',
        'production_date': fields.date.context_today,
        'warehouse_id': _get_default_warehouse,
        'warehouse_dest_id': _get_default_warehouse_dest,
    }
Example #35
0
class res_company(osv.osv):
    _name = "res.company"
    _description = 'Companies'
    _order = 'name'

    def _get_address_data(self, cr, uid, ids, field_names, arg, context=None):
        """ Read the 'address' functional fields. """
        result = {}
        part_obj = self.pool.get('res.partner')
        for company in self.browse(cr, uid, ids, context=context):
            result[company.id] = {}.fromkeys(field_names, False)
            if company.partner_id:
                address_data = part_obj.address_get(cr, openerp.SUPERUSER_ID, [company.partner_id.id], adr_pref=['default'])
                if address_data['default']:
                    address = part_obj.read(cr, openerp.SUPERUSER_ID, address_data['default'], field_names, context=context)
                    for field in field_names:
                        result[company.id][field] = address[field] or False
        return result

    def _set_address_data(self, cr, uid, company_id, name, value, arg, context=None):
        """ Write the 'address' functional fields. """
        company = self.browse(cr, uid, company_id, context=context)
        if company.partner_id:
            part_obj = self.pool.get('res.partner')
            address_data = part_obj.address_get(cr, uid, [company.partner_id.id], adr_pref=['default'])
            address = address_data['default']
            if address:
                part_obj.write(cr, uid, [address], {name: value or False})
            else:
                part_obj.create(cr, uid, {name: value or False, 'parent_id': company.partner_id.id}, context=context)
        return True

    def _get_logo_web(self, cr, uid, ids, _field_name, _args, context=None):
        result = dict.fromkeys(ids, False)
        for record in self.browse(cr, uid, ids, context=context):
            size = (180, None)
            result[record.id] = image_resize_image(record.partner_id.image, size)
        return result

    def _get_companies_from_partner(self, cr, uid, ids, context=None):
        return self.pool['res.company'].search(cr, uid, [('partner_id', 'in', ids)], context=context)

    _columns = {
        'name': fields.related('partner_id', 'name', string='Company Name', size=128, required=True, store=True, type='char'),
        'parent_id': fields.many2one('res.company', 'Parent Company', select=True),
        'child_ids': fields.one2many('res.company', 'parent_id', 'Child Companies'),
        'partner_id': fields.many2one('res.partner', 'Partner', required=True),
        'rml_header': fields.text('RML Header', required=True),
        'rml_header1': fields.char('Company Tagline', size=200, help="Appears by default on the top right corner of your printed documents (report header)."),
        'rml_header2': fields.text('RML Internal Header', required=True),
        'rml_header3': fields.text('RML Internal Header for Landscape Reports', required=True),
        'rml_footer': fields.text('Report Footer', help="Footer text displayed at the bottom of all reports."),
        'rml_footer_readonly': fields.related('rml_footer', type='text', string='Report Footer', readonly=True),
        'custom_footer': fields.boolean('Custom Footer', help="Check this to define the report footer manually.  Otherwise it will be filled in automatically."),
        'logo': fields.related('partner_id', 'image', string="Logo", type="binary"),
        'logo_web': fields.function(_get_logo_web, string="Logo Web", type="binary", store={
            'res.company': (lambda s, c, u, i, x: i, ['partner_id'], 10),
            'res.partner': (_get_companies_from_partner, ['image'], 10),
        }),
        'currency_id': fields.many2one('res.currency', 'Currency', required=True),
        'currency_ids': fields.one2many('res.currency', 'company_id', 'Currency'),
        'user_ids': fields.many2many('res.users', 'res_company_users_rel', 'cid', 'user_id', 'Accepted Users'),
        'account_no':fields.char('Account No.', size=64),
        'street': fields.function(_get_address_data, fnct_inv=_set_address_data, size=128, type='char', string="Street", multi='address'),
        'street2': fields.function(_get_address_data, fnct_inv=_set_address_data, size=128, type='char', string="Street2", multi='address'),
        'zip': fields.function(_get_address_data, fnct_inv=_set_address_data, size=24, type='char', string="Zip", multi='address'),
        'city': fields.function(_get_address_data, fnct_inv=_set_address_data, size=24, type='char', string="City", multi='address'),
        'state_id': fields.function(_get_address_data, fnct_inv=_set_address_data, type='many2one', domain="[('country_id', '=', country_id)]", relation='res.country.state', string="Fed. State", multi='address'),
        'bank_ids': fields.one2many('res.partner.bank','company_id', 'Bank Accounts', help='Bank accounts related to this company'),
        'country_id': fields.function(_get_address_data, fnct_inv=_set_address_data, type='many2one', relation='res.country', string="Country", multi='address'),
        'email': fields.function(_get_address_data, fnct_inv=_set_address_data, size=64, type='char', string="Email", multi='address'),
        'phone': fields.function(_get_address_data, fnct_inv=_set_address_data, size=64, type='char', string="Phone", multi='address'),
        'fax': fields.function(_get_address_data, fnct_inv=_set_address_data, size=64, type='char', string="Fax", multi='address'),
        'website': fields.related('partner_id', 'website', string="Website", type="char", size=64),
        'vat': fields.related('partner_id', 'vat', string="Tax ID", type="char", size=32),
        'company_registry': fields.char('Company Registry', size=64),
        'paper_format': fields.selection([('a4', 'A4'), ('us_letter', 'US Letter')], "Paper Format", required=True),
    }
    _sql_constraints = [
        ('name_uniq', 'unique (name)', 'The company name must be unique !')
    ]

    def onchange_footer(self, cr, uid, ids, custom_footer, phone, fax, email, website, vat, company_registry, bank_ids, context=None):
        if custom_footer:
            return {}

        # first line (notice that missing elements are filtered out before the join)
        res = ' | '.join(filter(bool, [
            phone            and '%s: %s' % (_('Phone'), phone),
            fax              and '%s: %s' % (_('Fax'), fax),
            email            and '%s: %s' % (_('Email'), email),
            website          and '%s: %s' % (_('Website'), website),
            vat              and '%s: %s' % (_('TIN'), vat),
            company_registry and '%s: %s' % (_('Reg'), company_registry),
        ]))
        # second line: bank accounts
        res_partner_bank = self.pool.get('res.partner.bank')
        account_data = self.resolve_2many_commands(cr, uid, 'bank_ids', bank_ids, context=context)
        account_names = res_partner_bank._prepare_name_get(cr, uid, account_data, context=context)
        if account_names:
            title = _('Bank Accounts') if len(account_names) > 1 else _('Bank Account')
            res += '\n%s: %s' % (title, ', '.join(name for id, name in account_names))

        return {'value': {'rml_footer': res, 'rml_footer_readonly': res}}

    def on_change_country(self, cr, uid, ids, country_id, context=None):
        currency_id = self._get_euro(cr, uid, context=context)
        if country_id:
            currency_id = self.pool.get('res.country').browse(cr, uid, country_id, context=context).currency_id.id
        return {'value': {'currency_id': currency_id}}

    def _search(self, cr, uid, args, offset=0, limit=None, order=None,
            context=None, count=False, access_rights_uid=None):
        if context is None:
            context = {}
        if context.get('user_preference'):
            # We browse as superuser. Otherwise, the user would be able to
            # select only the currently visible companies (according to rules,
            # which are probably to allow to see the child companies) even if
            # she belongs to some other companies.
            user = self.pool.get('res.users').browse(cr, SUPERUSER_ID, uid, context=context)
            cmp_ids = list(set([user.company_id.id] + [cmp.id for cmp in user.company_ids]))
            return cmp_ids
        return super(res_company, self)._search(cr, uid, args, offset=offset, limit=limit, order=order,
            context=context, count=count, access_rights_uid=access_rights_uid)

    def _company_default_get(self, cr, uid, object=False, field=False, context=None):
        """
        Check if the object for this company have a default value
        """
        if not context:
            context = {}
        proxy = self.pool.get('multi_company.default')
        args = [
            ('object_id.model', '=', object),
            ('field_id', '=', field),
        ]

        ids = proxy.search(cr, uid, args, context=context)
        user = self.pool.get('res.users').browse(cr, SUPERUSER_ID, uid, context=context)
        for rule in proxy.browse(cr, uid, ids, context):
            if eval(rule.expression, {'context': context, 'user': user}):
                return rule.company_dest_id.id
        return user.company_id.id

    @tools.ormcache()
    def _get_company_children(self, cr, uid=None, company=None):
        if not company:
            return []
        ids =  self.search(cr, uid, [('parent_id','child_of',[company])])
        return ids

    def _get_partner_hierarchy(self, cr, uid, company_id, context=None):
        if company_id:
            parent_id = self.browse(cr, uid, company_id)['parent_id']
            if parent_id:
                return self._get_partner_hierarchy(cr, uid, parent_id.id, context)
            else:
                return self._get_partner_descendance(cr, uid, company_id, [], context)
        return []

    def _get_partner_descendance(self, cr, uid, company_id, descendance, context=None):
        descendance.append(self.browse(cr, uid, company_id).partner_id.id)
        for child_id in self._get_company_children(cr, uid, company_id):
            if child_id != company_id:
                descendance = self._get_partner_descendance(cr, uid, child_id, descendance)
        return descendance

    #
    # This function restart the cache on the _get_company_children method
    #
    def cache_restart(self, cr):
        self._get_company_children.clear_cache(self)

    def create(self, cr, uid, vals, context=None):
        if not vals.get('name', False) or vals.get('partner_id', False):
            self.cache_restart(cr)
            return super(res_company, self).create(cr, uid, vals, context=context)
        obj_partner = self.pool.get('res.partner')
        partner_id = obj_partner.create(cr, uid, {'name': vals['name'], 'is_company':True, 'image': vals.get('logo', False)}, context=context)
        vals.update({'partner_id': partner_id})
        self.cache_restart(cr)
        company_id = super(res_company, self).create(cr, uid, vals, context=context)
        obj_partner.write(cr, uid, partner_id, {'company_id': company_id}, context=context)
        return company_id

    def write(self, cr, uid, ids, values, context=None):
        self.cache_restart(cr)
        return super(res_company, self).write(cr, uid, ids, values, context=context)

    def _get_euro(self, cr, uid, context=None):
        rate_obj = self.pool.get('res.currency.rate')
        rate_id = rate_obj.search(cr, uid, [('rate', '=', 1)], context=context)
        return rate_id and rate_obj.browse(cr, uid, rate_id[0], context=context).currency_id.id or False

    def _get_logo(self, cr, uid, ids):
        return open(os.path.join( tools.config['root_path'], 'addons', 'base', 'res', 'res_company_logo.png'), 'rb') .read().encode('base64')

    _header = """
<header>
<pageTemplate>
    <frame id="first" x1="28.0" y1="28.0" width="%s" height="%s"/>
    <pageGraphics>
        <fill color="black"/>
        <stroke color="black"/>
        <setFont name="DejaVu Sans" size="8"/>
        <drawString x="%s" y="%s"> [[ formatLang(time.strftime("%%Y-%%m-%%d"), date=True) ]]  [[ time.strftime("%%H:%%M") ]]</drawString>
        <setFont name="DejaVu Sans Bold" size="10"/>
        <drawCentredString x="%s" y="%s">[[ company.partner_id.name ]]</drawCentredString>
        <stroke color="#000000"/>
        <lines>%s</lines>
    </pageGraphics>
</pageTemplate>
</header>"""

    _header2 = _header % (539, 772, "1.0cm", "28.3cm", "11.1cm", "28.3cm", "1.0cm 28.1cm 20.1cm 28.1cm")

    _header3 = _header % (786, 525, 25, 555, 440, 555, "25 550 818 550")

    def _get_header(self,cr,uid,ids):
        try :
            header_file = tools.file_open(os.path.join('base', 'report', 'corporate_rml_header.rml'))
            try:
                return header_file.read()
            finally:
                header_file.close()
        except:
            return self._header_a4

    _header_main = """
<header>
    <pageTemplate>
        <frame id="first" x1="1.3cm" y1="3.0cm" height="%s" width="19.0cm"/>
         <stylesheet>
            <paraStyle name="main_footer"  fontName="DejaVu Sans" fontSize="8.0" alignment="CENTER"/>
            <paraStyle name="main_header"  fontName="DejaVu Sans" fontSize="8.0" leading="10" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/>
         </stylesheet>
        <pageGraphics>
            <!-- You Logo - Change X,Y,Width and Height -->
            <image x="1.3cm" y="%s" height="40.0" >[[ company.logo or removeParentNode('image') ]]</image>
            <setFont name="DejaVu Sans" size="8"/>
            <fill color="black"/>
            <stroke color="black"/>

            <!-- page header -->
            <lines>1.3cm %s 20cm %s</lines>
            <drawRightString x="20cm" y="%s">[[ company.rml_header1 ]]</drawRightString>
            <drawString x="1.3cm" y="%s">[[ company.partner_id.name ]]</drawString>
            <place x="1.3cm" y="%s" height="1.8cm" width="15.0cm">
                <para style="main_header">[[ display_address(company.partner_id) or  '' ]]</para>
            </place>
            <drawString x="1.3cm" y="%s">Phone:</drawString>
            <drawRightString x="7cm" y="%s">[[ company.partner_id.phone or '' ]]</drawRightString>
            <drawString x="1.3cm" y="%s">Mail:</drawString>
            <drawRightString x="7cm" y="%s">[[ company.partner_id.email or '' ]]</drawRightString>
            <lines>1.3cm %s 7cm %s</lines>

            <!-- left margin -->
            <rotate degrees="90"/>
            <fill color="grey"/>
            <drawString x="2.65cm" y="-0.4cm">generated by OpenERP.com</drawString>
            <fill color="black"/>
            <rotate degrees="-90"/>

            <!--page bottom-->
            <lines>1.2cm 2.65cm 19.9cm 2.65cm</lines>
            <place x="1.3cm" y="0cm" height="2.55cm" width="19.0cm">
                <para style="main_footer">[[ company.rml_footer ]]</para>
                <para style="main_footer">Contact : [[ user.name ]] - Page: <pageNumber/></para>
            </place>
        </pageGraphics>
    </pageTemplate>
</header>"""

    _header_a4 = _header_main % ('21.7cm', '27.7cm', '27.7cm', '27.7cm', '27.8cm', '27.3cm', '25.3cm', '25.0cm', '25.0cm', '24.6cm', '24.6cm', '24.5cm', '24.5cm')
    _header_letter = _header_main % ('20cm', '26.0cm', '26.0cm', '26.0cm', '26.1cm', '25.6cm', '23.6cm', '23.3cm', '23.3cm', '22.9cm', '22.9cm', '22.8cm', '22.8cm')

    def onchange_paper_format(self, cr, uid, ids, paper_format, context=None):
        if paper_format == 'us_letter':
            return {'value': {'rml_header': self._header_letter}}
        return {'value': {'rml_header': self._header_a4}}

    _defaults = {
        'currency_id': _get_euro,
        'paper_format': 'a4',
        'rml_header':_get_header,
        'rml_header2': _header2,
        'rml_header3': _header3,
        'logo':_get_logo
    }

    _constraints = [
        (osv.osv._check_recursion, 'Error! You can not create recursive companies.', ['parent_id'])
    ]
Example #36
0
			if store['website']['is_default'] == '1':				
				store_info['website_id'] = int(store['website']['website_id'])
				store_info['store_id'] = view_pool._get_store_view(cr, uid, store, context)
				break;
		return store_info


	_columns = {
		'name': fields.char('Base URL', required=True, size=255 ,select=True),
		'instance_name': fields.char("Instance Name",size=64,select=True),
		'user':fields.char('API User Name', required=True, size=100),
		'pwd':fields.char('API Password',required=True, size=100),
		'status':fields.char('Connection Status',readonly=True, size=255),
		'active':fields.boolean('Active'),
		'store_id':fields.many2one('magento.store.view', 'Default Magento Store'),
		'group_id':fields.related('store_id', 'group_id', type="many2one", relation="magento.store", string="Default Store", readonly=True, store=True),
		'website_id':fields.related('group_id', 'website_id', type="many2one", relation="magento.website", string="Default Magento Website", readonly=True),
		'credential':fields.boolean('Show/Hide Credentials Tab', 
							help="If Enable, Credentials tab will be displayed, "
							"And after filling the details you can hide the Tab."),
		'auto_invoice':fields.boolean('Auto Invoice',
							help="If Enabled, Order will automatically Invoiced on Magento "
								" when Odoo order Get invoiced."),
		'auto_ship':fields.boolean('Auto Shipment', 
							help="If Enabled, Order will automatically shipped on Magento" 
								" when Odoo order Get Delivered."),
		'notify':fields.boolean('Notify Customer By Email', 
							help="If True, customer will be notify" 
								"during order shipment and invoice, else it won't."),
		'language':fields.selection(_lang_get, "Default Language", help="Selected language is loaded in the system, "
							"all documents related to this contact will be synched in this language."),
Example #37
0
class Message(osv.Model):
    #TODO: turn off for data import only
    _log_access = True
    _name = "message.message"
    _order = "write_date desc,sequence"
    _description = 'UPDIS Message'
    _inherit = ['mail.thread', 'ir.needaction_mixin']

    def _default_fbbm(self, cr, uid, context=None):
        employee_ids = self.pool.get('hr.employee').search(cr, uid, [('user_id', '=', uid)])
        if employee_ids:
            return self.pool.get('hr.employee').browse(cr, uid, employee_ids[0]).department_id.name

    def _default_department(self, cr, uid, context=None):
        employee_ids = self.pool.get('hr.employee').search(cr, uid, [('user_id', '=', uid)])
        if employee_ids:
            return self.pool.get('hr.employee').browse(cr, uid, employee_ids[0]).department_id.id

    def _get_image(self, cr, uid, ids, name, args, context=None):
        result = dict.fromkeys(ids, False)
        for obj in self.browse(cr, uid, ids, context=context):
            result[obj.id] = tools.image_get_resized_images(obj.image)
        return result

    def _set_image(self, cr, uid, id, field_name, value, args, context=None):
        return self.write(cr, uid, [id], {'image': tools.image_resize_image_big(value)}, context=context)

    def _get_name_display(self, cr, uid, ids, field_name, args, context=None):
        result = dict.fromkeys(ids, False)
        for obj in self.browse(cr, uid, ids, context=context):
            result[obj.id] = obj.is_display_name and obj.create_uid.name or u'匿名用户'
        return result

    def _get_message_meta_display(self, cr, uid, ids, field_name, args, context=None):
        result = dict.fromkeys(ids, False)
        for obj in self.browse(cr, uid, ids, context=context):
            message_meta = ''
            if obj.category_id.message_meta:
                env = Env(cr, uid, 'message.message', [obj.id])
                message_meta = eval(obj.category_id.message_meta, env, nocopy=True)
            result[obj.id] = message_meta
        return result

    def _get_category_message_title_meta_display(self, cr, uid, ids, field_name, args, context=None):
        result = dict.fromkeys(ids, False)
        for obj in self.browse(cr, uid, ids, context=context):
            category_message_title_meta = ''
            if obj.category_id.category_message_title_meta:
                env = Env(cr, uid, 'message.message', [obj.id])
                category_message_title_meta = eval(obj.category_id.category_message_title_meta, env, nocopy=True)
            result[obj.id] = category_message_title_meta
        return result


    def _get_create_date_display(self, cr, uid, ids, field_name, args, context=None):
        result = dict.fromkeys(ids, False)
        for obj in self.browse(cr, uid, ids, context=context):

            if obj.create_date:
                create_date_display = datetime.datetime.strptime(obj.create_date,
                                                                 '%Y-%m-%d %H:%M:%S') + datetime.timedelta(hours=8)
                result[obj.id] = create_date_display.strftime('%Y-%m-%d %H:%M:%S')
        return result

    def _get_write_date_display(self, cr, uid, ids, field_name, args, context=None):
        result = dict.fromkeys(ids, False)
        for obj in self.browse(cr, uid, ids, context=context):

            if obj.write_date:
                write_date_display = datetime.datetime.strptime(obj.write_date,
                                                                '%Y-%m-%d %H:%M:%S') + datetime.timedelta(hours=8)
                result[obj.id] = write_date_display.strftime('%Y-%m-%d %H:%M:%S')
        return result

    def _get_shorten_name(self, cr, uid, ids, field_name, args, context=None):
        result = dict.fromkeys(ids, False)
        for obj in self.browse(cr, uid, ids, context=context):
            size = obj.category_id.category_message_title_size
            title = len(obj.name) > size and obj.name[:size] + '...' or obj.name
            result[obj.id] = title
        return result

    def _get_message_list_meta_display(self, cr, uid, ids, field_name, args, context=None):
        result = dict.fromkeys(ids, False)
        for obj in self.browse(cr, uid, ids, context=context):
            message_meta = ''
            if obj.category_id.message_meta:
                env = Env(cr, uid, 'message.message', [obj.id])
                message_meta = eval(obj.category_id.phone_message_list_meta, env, nocopy=True)
            result[obj.id] = message_meta
        return result

    def _get_message_detail_meta_display(self, cr, uid, ids, field_name, args, context=None):
        result = dict.fromkeys(ids, False)
        for obj in self.browse(cr, uid, ids, context=context):
            category_message_title_meta = ''
            if obj.category_id.category_message_title_meta:
                env = Env(cr, uid, 'message.message', [obj.id])
                category_message_title_meta = eval(obj.category_id.phone_message_detail_meta, env, nocopy=True)
            result[obj.id] = category_message_title_meta
        return result

    def _get_vote_count(self, cr, uid, ids, field_name, args, context=None):
        """
            Either way, it must return a dictionary of values of the form
            {'id_1_': 'value_1_', 'id_2_': 'value_2_',...}.

            If multi is set, then field_name is replaced by field_names:
            a list of the field names that should be calculated.
            Each value in the returned dictionary is also a dictionary from field name to value.
            For example, if the fields 'name', and 'age' are both based on the vital_statistics function,
            then the return value of vital_statistics might look like this when ids is [1, 2, 5]:
            {
                1: {'name': 'Bob', 'age': 23},
                2: {'name': 'Sally', 'age', 19},
                5: {'name': 'Ed', 'age': 62}
            }
        """
        result = dict.fromkeys(ids, False)
        message_vote_obj = self.pool.get('message.vote')
        for message in self.browse(cr, uid, ids, context=context):
            vote_like_count = len(message_vote_obj.search(cr, SUPERUSER_ID, [('message_id', '=', message.id), ('up', '=', True)], context))
            vote_unlike_count = len(message_vote_obj.search(cr, SUPERUSER_ID, [('message_id', '=', message.id), ('up', '=', False)], context))
            result[message.id] = {
                'vote_like': vote_like_count,
                'vote_unlike': vote_unlike_count,
            }
        return result

    _columns = {
        'name': fields.char("Title", size=128, required=True),
        'shorten_name': fields.function(_get_shorten_name, type="char", size=256, string="Shorten title"),
        'message_meta_display': fields.function(_get_message_meta_display, type="char", size=256, string="Meta"),
        'category_message_title_meta_display': fields.function(_get_category_message_title_meta_display, type="char",
                                                               size=256, string="Category meta"),


        'message_list_meta_display': fields.function(_get_message_list_meta_display, type="char", size=256,
                                                     string="Phone Message List Meta"),
        'message_detail_meta_display': fields.function(_get_message_detail_meta_display, type="char",
                                                       size=256, string="Phone Message Detail meta"),
        'category_id': fields.many2one('message.category', 'Category', required=True, change_default=True),
        'content': fields.text("Content"),
        'sequence': fields.integer("Display Sequence"),
        'is_display_name': fields.boolean('Display name?'),
        'fbbm': fields.char('Publisher', size=128),
        'read_times': fields.integer("Read Times"),
        'expire_date': fields.date('Expire Date'),
        'create_date': fields.datetime('Created on', select=True ,readonly=True),
        'department_id': fields.many2one("hr.department", "Department", domain=[('deleted', '=', False)]),
        'create_uid': fields.many2one('res.users', 'Author', select=True, readonly=True),
        'write_date': fields.datetime('Modification date', select=True , readonly=True),
        'write_uid': fields.many2one('res.users', 'Last Contributor', select=True , readonly=True),
        'source': fields.char("Message Source", size=128),
        'name_for_display': fields.function(_get_name_display, type="char", size=64, string="Name"),
        'sms_receiver_ids': fields.many2many("hr.employee", "message_hr_employee_rel", "message_id", "hr_employee_id",
                                             "SMS Receiver"),
        'sms': fields.text('SMS', size=140),
        'is_allow_send_sms': fields.related('category_id', 'is_allow_send_sms', type="boolean",
                                            string="Allow send SMS?"),
        'is_allow_sms_receiver': fields.related('category_id', 'is_allow_send_sms', type="boolean",
                                                string="Allow specify sms receiver?"),
        'category_id_name': fields.related('category_id', 'name', type="char",
                                           string="category name"),
        'category_id_is_anonymous_allowed': fields.related('category_id', 'is_anonymous_allowed', type="boolean",
                                                           string="category is anonymous allowed"),
        'category_id_is_allowed_edit_sms_text': fields.related('category_id', 'is_allowed_edit_sms_text',
                                                               type="boolean",
                                                               string="category is allowed edit sms text"),
        'create_date_display': fields.function(_get_create_date_display, type="datetime", string="Create Date Display",
                                               readonly=True),
        'write_date_display': fields.function(_get_write_date_display, type="datetime", string="Write Date Display",
                                              readonly=True),
        'vote_user_ids': fields.many2many('res.users', 'message_vote', 'message_id', 'user_id', string='Votes',
                                          help='Users that voted for this message'),
        'vote_like': fields.function(_get_vote_count, type="integer", string='Like', multi='vote'),
        'vote_unlike': fields.function(_get_vote_count, type='integer', string='Unlike', multi='vote'),
    }
    _defaults = {
        'fbbm': _default_fbbm,
        'department_id': _default_department,
        'is_display_name': True,
    }

    def onchange_category(self, cr, uid, ids, category_id, context=None):
        ret = {'value': {}}
        if category_id:
            message_category = self.pool.get('message.category').browse(cr, uid, category_id)
            sms_vals = {
                'is_allow_send_sms': message_category.is_allow_send_sms,
                'is_allow_sms_receiver': message_category.is_allow_sms_receiver,
                'sms_receiver_ids': [x.id for x in message_category.default_sms_receiver_ids],
                'category_id_name': message_category.name,
                'category_id_is_anonymous_allowed': message_category.is_anonymous_allowed,
                'category_id_is_allowed_edit_sms_text': message_category.is_allowed_edit_sms_text,
            }
            ret['value'].update(sms_vals)
        return ret

    #abandon
    def onchange_name(self, cr, uid, ids, name, sms, context=None):
        ret = {'value': {}}
        if not sms:
            name_vals = {
                'sms': name,
            }
            if not len(ids):
                ret['value'].update(name_vals)
        return ret

    def create(self, cr, uid, vals, context=None):
        if context is None:
            context = {'mail_create_nolog': True}
        else:
            context.update({'mail_create_nolog': True})
        if self._log_access is True:
            if not vals['category_id_is_allowed_edit_sms_text']:
                vals['sms'] = vals['name']
            mid = super(Message, self).create(cr, uid, vals, context)
            sms = self.pool.get('sms.sms')
            message = self.pool.get('message.message').browse(cr, uid, mid, context=context)
            if message.is_allow_send_sms:
                to = ','.join(
                    [rid.mobile_phone.strip() for rid in message.sms_receiver_ids if rid.mobile_phone and rid.mobile_phone.strip()])
                if to:
                    content = message.sms and message.category_id.name + ':' + message.sms or message.category_id.name + ':' + message.name
                    sid = sms.create(cr, uid, {'to': to, 'content': content, 'model': 'message.message', 'res_id': mid},
                                     context=context)
        else:
            mid = super(Message, self).create(cr, uid, vals, context)
        return mid

    def write(self, cr, uid, ids, vals, context=None):
        #get message old position
        if self._log_access is True:
            TYPE = []
            if not (len(vals) == 1 and 'read_times' in vals.keys()):
                messages_old = self.pool.get('message.message').browse(cr, 1, ids, context=context)
                for message_old in messages_old:
                    if message_old.category_id.display_position == 'shortcut':
                        TYPE.append('0')
                    if message_old.category_id.display_position == 'content_left':
                        TYPE.append('1')
                    if message_old.category_id.display_position == 'content_right':
                        TYPE.append('2')
                TYPE = set(TYPE)

            super(Message, self).write(cr, uid, ids, vals, context=context)
            NEW_TYPE = []
            #refresh cms page
            if not (len(vals) == 1 and 'read_times' in vals.keys()):
                #get message new position
                messages = self.pool.get('message.message').browse(cr, 1, ids, context=context)
                for message in messages:
                    if message.category_id.display_position == 'shortcut':
                        NEW_TYPE.append('0')
                    if message.category_id.display_position == 'content_left':
                        NEW_TYPE.append('1')
                    if message.category_id.display_position == 'content_right':
                        NEW_TYPE.append('2')
                NEW_TYPE = set(NEW_TYPE)

                #if old and new position is different refresh both.
                for v in (TYPE | NEW_TYPE):
                    fresh_old = CMSFresh(v)
                    fresh_old.start()
        else:
            super(Message, self).write(cr, uid, ids, vals, context=context)

        return True


    def unlink(self, cr, uid, ids, context=None):
        #get old position
        TYPE = []
        messages_old = self.pool.get('message.message').browse(cr, 1, ids, context=context)
        for message_old in messages_old:
            if message_old.category_id.display_position == 'shortcut':
                TYPE.append('0')
            if message_old.category_id.display_position == 'content_left':
                TYPE.append('1')
            if message_old.category_id.display_position == 'content_right':
                TYPE.append('2')
        super(Message, self).unlink(cr, uid, ids, context=None)
        TYPE = set(TYPE)
        #refresh
        for v in TYPE:
            fresh_old = CMSFresh(v)
            fresh_old.start()
        return True

    def vote_like(self, cr, uid, user_id, message_id, context=None):
        message_vote_obj = self.pool.get('message.vote')
        message = self.read(cr, SUPERUSER_ID, int(message_id), ['vote_user_ids'], context=context)
        new_has_voted = not (user_id in message.get('vote_user_ids'))
        if new_has_voted:
            message_vote_obj.create(cr, SUPERUSER_ID, {'message_id': message.get('id'), 'user_id': user_id, 'up': True})
        else:
            self.write(cr, SUPERUSER_ID, [message.get('id')], {'vote_user_ids': [(3, user_id)]}, context=context)
            message_vote_obj.create(cr, SUPERUSER_ID, {'message_id': message.get('id'), 'user_id': user_id, 'up': True})
        return new_has_voted or False

    def vote_unlike(self, cr, uid, user_id, message_id, context=None):
        message_vote_obj = self.pool.get('message.vote')
        message = self.read(cr, SUPERUSER_ID, int(message_id), ['vote_user_ids'], context=context)
        new_has_voted = not (user_id in message.get('vote_user_ids'))
        if new_has_voted:
            message_vote_obj.create(cr, SUPERUSER_ID, {'message_id': message.get('id'), 'user_id': user_id, 'up': False})
        else:
            self.write(cr, SUPERUSER_ID, [message.get('id')], {'vote_user_ids': [(3, user_id)]}, context=context)
            message_vote_obj.create(cr, SUPERUSER_ID, {'message_id': message.get('id'), 'user_id': user_id, 'up': False})
        return new_has_voted or False
Example #38
0
        'name':fields.char('Memo', size=256),
        'log_ref': fields.char('Check-log Ref', size=128),
<<<<<<< HEAD
#        'origin' : fields.char('Origin', size=128),
        'check_status' :fields.selection([('void','Voided'),('print','Printed'),('re_print','Re-Printed'),('clear','Cleared')]),
        'chk_seq': fields.char("Check Number", size=64, readonly=True),
        'invoice_ids': fields.one2many('account.invoice', 'voucher_id', 'Invoices', ondelete='cascade'),
        'jtype':fields.related('journal_id','type', string="Journal Type", type='selection', selection=[('sale', 'Sale'),('sale_refund','Sale Refund'), ('purchase', 'Purchase'), ('purchase_refund','Purchase Refund'), ('cash', 'Cash'), ('bank', 'Bank and Checks'), ('general', 'General'), ('situation', 'Opening/Closing Situation')],),
    }                                                                                                    
=======
#         'origin' : fields.char('Origin', size=128),
        'check_status' :fields.selection([('void','Voided'),('print','Printed'),('re_print','Re-Printed'),('clear','Cleared')]),
        'chk_seq': fields.char("Check Number", size=64, readonly=True),
        'invoice_ids': fields.one2many('account.invoice', 'voucher_id', 'Invoices', ondelete='cascade'),
        'reference': fields.char('Origin', size=64, readonly=True, states={'draft':[('readonly',False)]}, help="Source document which generated the payment."),
        'jtype':fields.related('journal_id','type', string="Journal Type", type='selection', selection=[('sale', 'Sale'),('sale_refund','Sale Refund'), ('purchase', 'Purchase'), ('purchase_refund','Purchase Refund'), ('cash', 'Cash'), ('bank', 'Bank and Checks'), ('general', 'General'), ('situation', 'Opening/Closing Situation')],),
    }
>>>>>>> c1979f64b3360c86d60e00c92be0271d89f97f2d

    def print_checks(self, cr, uid, ids, context=None):
        check_state = self.browse(cr, uid, ids[0],context=None).check_status
        view_ref = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'account_check_writing', 'view_account_check_write')
        view_id = view_ref and view_ref[1] or False,
        context.update({'active_ids':ids, 'check_state': check_state})
        return {
               'type': 'ir.actions.act_window',
               'name': 'Print Checks',
               'view_mode': 'form',
               'view_type': 'form',
               'view_id': view_id,
               'res_model': 'account.check.write',
Example #39
0
class hr_so_project(osv.osv_memory):
    _name = 'hr.sign.out.project'
    _description = 'Sign Out By Project'
    _columns = {
        'account_id':
        fields.many2one('account.analytic.account',
                        'Project / Analytic Account',
                        domain=[('type', 'in', ['normal', 'contract'])]),
        'info':
        fields.char('Work Description', required=True),
        'date_start':
        fields.datetime('Starting Date', readonly=True),
        'date':
        fields.datetime('Closing Date'),
        'analytic_amount':
        fields.float('Minimum Analytic Amount'),
        'name':
        fields.char('Employee\'s Name', required=True, readonly=True),
        'state':
        fields.related('emp_id',
                       'state',
                       string='Current Status',
                       type='selection',
                       selection=[('present', 'Present'),
                                  ('absent', 'Absent')],
                       required=True,
                       readonly=True),
        'server_date':
        fields.datetime('Current Date', required=True, readonly=True),
        'emp_id':
        fields.many2one('hr.employee', 'Employee ID')
    }

    def _get_empid(self, cr, uid, context=None):
        emp_obj = self.pool.get('hr.employee')
        emp_ids = emp_obj.search(cr,
                                 uid, [('user_id', '=', uid)],
                                 context=context)
        if emp_ids:
            for employee in emp_obj.browse(cr, uid, emp_ids, context=context):
                return {
                    'name': employee.name,
                    'state': employee.state,
                    'emp_id': emp_ids[0],
                    'server_date': time.strftime('%Y-%m-%d %H:%M:%S')
                }

    def _get_empid2(self, cr, uid, context=None):
        res = self._get_empid(cr, uid, context=context)
        cr.execute(
            'select name,action from hr_attendance where employee_id=%s order by name desc limit 1',
            (res['emp_id'], ))

        res['server_date'] = time.strftime('%Y-%m-%d %H:%M:%S')
        date_start = cr.fetchone()

        if date_start:
            res['date_start'] = date_start[0]
        return res

    def default_get(self, cr, uid, fields_list, context=None):
        res = super(hr_so_project, self).default_get(cr,
                                                     uid,
                                                     fields_list,
                                                     context=context)
        res.update(self._get_empid2(cr, uid, context=context))
        return res

    def _write(self, cr, uid, data, emp_id, context=None):
        timesheet_obj = self.pool.get('hr.analytic.timesheet')
        emp_obj = self.pool.get('hr.employee')
        if context is None:
            context = {}
        hour = (time.mktime(
            time.strptime(data['date'] or time.strftime('%Y-%m-%d %H:%M:%S'),
                          '%Y-%m-%d %H:%M:%S')) - time.mktime(
                              time.strptime(data['date_start'],
                                            '%Y-%m-%d %H:%M:%S'))) / 3600.0
        minimum = data['analytic_amount']
        if minimum:
            hour = round(round((hour + minimum / 2) / minimum) * minimum, 2)
        res = timesheet_obj.default_get(cr,
                                        uid, ['product_id', 'product_uom_id'],
                                        context=context)

        if not res['product_uom_id']:
            raise osv.except_osv(
                _('User Error!'),
                _('Please define cost unit for this employee.'))
        up = timesheet_obj.on_change_unit_amount(
            cr, uid, False, res['product_id'], hour, False,
            res['product_uom_id'])['value']

        res['name'] = data['info']
        res['account_id'] = data['account_id'].id
        res['unit_amount'] = hour
        emp_journal = emp_obj.browse(cr, uid, emp_id,
                                     context=context).journal_id
        res['journal_id'] = emp_journal and emp_journal.id or False
        res.update(up)
        up = timesheet_obj.on_change_account_id(cr, uid, [],
                                                res['account_id']).get(
                                                    'value', {})
        res.update(up)
        return timesheet_obj.create(cr, uid, res, context=context)

    def sign_out_result_end(self, cr, uid, ids, context=None):
        emp_obj = self.pool.get('hr.employee')
        for data in self.browse(cr, uid, ids, context=context):
            emp_id = data.emp_id.id
            emp_obj.attendance_action_change(cr, uid, [emp_id], {
                'action': 'sign_out',
                'action_date': data.date
            })
            self._write(cr, uid, data, emp_id, context=context)
        return {'type': 'ir.actions.act_window_close'}

    def sign_out_result(self, cr, uid, ids, context=None):
        emp_obj = self.pool.get('hr.employee')
        for data in self.browse(cr, uid, ids, context=context):
            emp_id = data.emp_id.id
            emp_obj.attendance_action_change(cr, uid, [emp_id], {
                'action': 'action',
                'action_date': data.date
            })
            self._write(cr, uid, data, emp_id, context=context)
        return {'type': 'ir.actions.act_window_close'}
    def _setup_bound_dimension(cls, dimension, columns, defaults, orm_name, name, bases, nmspc):
        """Bind a dimension to the model, creating a code for each record."""

        if dimension is True:
            dimension = {}
        elif isinstance(dimension, basestring):
            dimension = {"name": dimension}

        dimension_name = dimension.get("name", None)
        if dimension_name is None:
            dimension_name = nmspc.get("_description", False) or orm_name

        column = dimension.get("column", "analytic_id")

        ref_module = dimension.get("ref_module", "")

        ref_id = dimension.get("ref_id", None)
        if ref_id is None:
            ref_id = orm_name.replace(".", "_") + "_analytic_dimension_id"

        # To use an inherited, renamed parent field, you have to give its name.
        sync_parent = dimension.get("sync_parent", False)
        if sync_parent is True:
            sync_parent = nmspc.get("_parent_name", "parent_id")

        rel_name = dimension.get("rel_name", tuple())
        if rel_name is True:
            rel_name = u"Name"
        if isinstance(rel_name, basestring):
            rel_name = (rel_name, "name")

        rel_description = dimension.get("rel_description", tuple())
        if rel_description is True:
            rel_description = u"Description"
        if isinstance(rel_description, basestring):
            rel_description = (rel_description, "description")

        rel_active = dimension.get("rel_active", tuple())
        if rel_active is True:
            rel_active = u"Active"
        if isinstance(rel_active, basestring):
            rel_active = (rel_active, "active")

        rel_view_type = dimension.get("rel_view_type", tuple())
        if rel_view_type is True:
            rel_view_type = u"View type"
        if isinstance(rel_view_type, basestring):
            rel_view_type = (rel_view_type, "view_type")

        rel_disabled_per_company = dimension.get("rel_disabled_per_company", tuple())
        if rel_disabled_per_company is True:
            rel_disabled_per_company = u"Disabled in my company"
        if isinstance(rel_disabled_per_company, basestring):
            rel_disabled_per_company = (rel_disabled_per_company, "disabled_per_company")

        # By default, only use inherits if we can be sure there is no conflict
        # on the required fields 'name' and 'nd_id'.
        # There can still be conflicts on analytic_code's optional fields.
        use_inherits = dimension.get("use_inherits", None)
        if use_inherits is None:
            use_inherits = not (
                any(col in columns for col in ("name", "nd_id"))
                or nmspc.get("_inherits", False)
                or nmspc.get("_inherit", False)
            )

        use_code_name_methods = dimension.get("use_code_name_methods", False)

        code_ref_ids = dimension.get("code_ref_ids", False)
        if code_ref_ids is True:
            code_ref_ids = ref_id

        code_ref_module = dimension.get("code_ref_module", "")

        if use_inherits:
            inherits = nmspc.get("_inherits", {})
            inherits["analytic.code"] = column
            nmspc["_inherits"] = inherits

        # Default column for the underlying analytic code.
        if column not in columns:
            columns[column] = fields.many2one(
                "analytic.code", u"Bound Analytic Code", required=True, ondelete="restrict"
            )

        rel_cols = [
            cols
            for cols in [
                rel_name + ("name", "char", True, ""),
                rel_description + ("description", "char", False, ""),
                rel_active + ("active", "boolean", False, True),
                rel_view_type + ("view_type", "boolean", False, False),
            ]
            if len(cols) == 6
        ]

        if rel_cols:
            # NOT a method nor a class member. 'self' is the analytic_code OSV.
            def _record_from_code_id(self, cr, uid, ids, context=None):
                """Get the entries to update from the modified codes."""
                osv = self.pool.get(orm_name)
                domain = [(column, "in", ids)]
                return osv.search(cr, uid, domain, context=context)

            for string, model_col, code_col, dtype, req, default in rel_cols:
                columns[model_col] = fields.related(
                    column,
                    code_col,
                    string=string,
                    type=dtype,
                    relation="analytic.code",
                    required=req,
                    store={"analytic.code": (_record_from_code_id, [code_col], 10)},
                )
                if model_col not in defaults:
                    defaults[model_col] = default

        # In order to preserve inheritance, possible overrides, and OEMetaSL's
        # expected behavior, work on a new class that inherits the given bases,
        # then make our model class inherit from this class.
        superclass_name = "_{name}_SuperDimension".format(name=name)
        # Set _register to False in order to prevent its instantiation.
        superclass = type(superclass_name, bases, {"_register": False})

        @AddMethod(superclass)
        def __init__(self, pool, cr):
            """Load or create the analytic dimension bound to the model."""

            super(superclass, self).__init__(pool, cr)

            data_osv = self.pool["ir.model.data"]
            try:
                self._bound_dimension_id = data_osv.get_object_reference(cr, SUPERUSER_ID, ref_module, ref_id)[1]
            except ValueError:
                vals = {"name": dimension_name, "validated": True}
                self._bound_dimension_id = data_osv._update(
                    cr, SUPERUSER_ID, "analytic.dimension", ref_module, vals, xml_id=ref_id, noupdate=True
                )

        if code_ref_ids:
            prefix = config.get_misc("analytic", "code_ref_prefix", False)

            # This function is called as a method and can be overridden.
            @AddMethod(superclass)
            def _generate_code_ref_id(self, cr, uid, ids, context=None):
                data_osv = self.pool["ir.model.data"]
                records = self.browse(cr, uid, ids, context=None)
                if not isinstance(records, list):
                    records = [records]

                for record in records:
                    code = record[column]
                    code_ref_id_builder = [prefix] if prefix else []
                    if "company_id" in record and record.company_id:
                        code_ref_id_builder.append(record.company_id.code)
                    code_ref_id_builder.append("ANC")
                    code_ref_id_builder.append(code_ref_ids)
                    code_ref_id_builder.append(code.name)

                    vals = {
                        "name": "_".join(code_ref_id_builder),
                        "module": code_ref_module,
                        "model": "analytic.code",
                        "res_id": code.id,
                    }
                    data_osv.create(cr, uid, vals, context=context)

        @AddMethod(superclass)
        def create(self, cr, uid, vals, context=None):
            """Create the analytic code."""

            code_vals = {}

            if sync_parent:
                cp = self._get_code_parent(cr, uid, vals, context=context)
                if cp is not None:
                    code_vals["code_parent_id"] = cp

            # Direct changes to the 'bound analytic code' field are ignored
            # unless the 'force_code_id' context key is passed as True.
            force_code_id = vals.pop(column, False)

            if context and context.get("force_code_id", False) == True:
                self._force_code(cr, uid, force_code_id, code_vals, context)
                vals[column] = force_code_id

            else:
                if use_inherits:
                    code_vals.update(vals)
                else:
                    code_vals["name"] = vals.get("name")

                # OpenERP bug: related fields do not work properly on creation.
                for rel in rel_cols:
                    model_col, code_col = rel[1:3]
                    if model_col in vals:
                        code_vals[code_col] = vals[model_col]
                    elif model_col in self._defaults:
                        code_vals[code_col] = self._defaults[model_col]

                # We have to create the code separately, even with inherits.
                code_osv = self.pool["analytic.code"]
                code_vals["nd_id"] = self._bound_dimension_id
                code_id = code_osv.create(cr, uid, code_vals, context=context)
                vals[column] = code_id

            res = super(superclass, self).create(cr, uid, vals, context=context)

            if code_ref_ids:
                self._generate_code_ref_id(cr, uid, res, context=context)

            return res

        @AddMethod(superclass)
        def write(self, cr, uid, ids, vals, context=None):
            """Update the analytic code's name if it is not inherited,
            and its parent code if parent-child relations are synchronized.
            """

            code_vals = {}
            new = False

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

            if sync_parent:
                cp = self._get_code_parent(cr, uid, vals, context=context)
                if cp is not None:
                    code_vals["code_parent_id"] = cp

            # Direct changes to the 'bound analytic code' field are ignored
            # unless the 'force_code_id' context key is passed as True.
            force_code_id = vals.pop(column, False)

            if context and context.get("force_code_id", False) == True:
                self._force_code(cr, uid, force_code_id, code_vals, context)
                vals[column] = force_code_id

            elif use_inherits:
                vals.update(code_vals)

            else:
                name_col = rel_name[1] if rel_name else "name"
                if name_col in vals:
                    code_vals["name"] = vals[name_col]
                records = self.browse(cr, uid, ids, context=context)
                code_ids = [getattr(rec, column).id for rec in records]

                # If updating a single record with no code, create it.
                code_osv = self.pool["analytic.code"]
                if code_ids == [False]:
                    new = ids[0]
                    code_vals["nd_id"] = self._bound_dimension_id
                    if "name" not in code_vals:
                        code_vals["name"] = self.read(cr, uid, new, [name_col], context=context)[name_col]
                    vals[column] = code_osv.create(cr, uid, code_vals, context=context)
                elif code_vals:
                    code_osv.write(cr, uid, code_ids, code_vals, context=context)

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

            if code_ref_ids and new is not False:
                self._generate_code_ref_id(cr, uid, new, context=context)

            return res

        @AddMethod(superclass)
        def _force_code(self, cr, uid, force_code_id, code_vals, context=None):

            code_osv = self.pool["analytic.code"]

            if not force_code_id:
                raise ValueError(
                    "An analytic code ID MUST be specified if the " "force_code_id key is enabled in the context"
                )
            force_code_dim = code_osv.read(cr, uid, force_code_id, ["nd_id"], context=context)["nd_id"][0]
            if force_code_dim != self._bound_dimension_id:
                raise ValueError(
                    "If specified, codes must belong to the bound " "analytic dimension {}".format(dimension_name)
                )
            if code_vals:
                code_osv.write(cr, uid, force_code_id, code_vals, context=context)

        if sync_parent:
            # This function is called as a method and can be overridden.
            @AddMethod(superclass)
            def _get_code_parent(self, cr, uid, vals, context=None):
                """If parent_id is in the submitted values, return the analytic
                code of this parent, to be used as the child's code's parent.
                """
                parent_id = vals.get(sync_parent, None)
                if parent_id is not None:
                    if parent_id:
                        res = self.read(cr, uid, parent_id, [column], context=context)[column]
                        return res[0] if res else False
                    else:
                        return False
                return None

        if use_code_name_methods:

            @AddMethod(superclass)
            def name_get(self, cr, uid, ids, context=None):
                """Return the analytic code's name."""

                code_osv = self.pool.get("analytic.code")
                code_reads = self.read(cr, uid, ids, [column], context=context)
                c2m = {  # Code IDs to model IDs
                    code_read[column][0]: code_read["id"] for code_read in code_reads if code_read[column] is not False
                }
                names = code_osv.name_get(cr, uid, c2m.keys(), context=context)
                return [(c2m[cid], name) for cid, name in names if cid in c2m]

            @AddMethod(superclass)
            def name_search(self, cr, uid, name, args=None, operator="ilike", context=None, limit=100):
                """Return the records whose analytic code matches the name."""

                code_osv = self.pool.get("analytic.code")
                args.append(("nd_id", "=", self._bound_dimension_id))
                names = code_osv.name_search(cr, uid, name, args, operator, context, limit)
                if not names:
                    return []
                dom = [(column, "in", zip(*names)[0])]
                ids = self.search(cr, uid, dom, context=context)
                code_reads = self.read(cr, uid, ids, [column], context=context)
                c2m = {  # Code IDs to model IDs
                    code_read[column][0]: code_read["id"] for code_read in code_reads if code_read[column] is not False
                }
                return [(c2m[cid], cname) for cid, cname in names if cid in c2m]

        return (superclass,)
Example #41
0
class event_registration(orm.Model):

    _name = "event.registration"
    _inherit = ['event.registration', 'mozaik.abstract.model']
    _description = "Event Registration"

    # private methods

    def _get_coordinates(self, cr, uid, vals, context=None):
        '''
        if `partner_id`` in vals then set `email' and `phone` with
        email coordinate and phone.coordinate of the partner
        '''
        r_fields = [
            'email_coordinate_id', 'mobile_coordinate_id', 'fix_coordinate_id',
            'display_name'
        ]
        p_obj = self.pool['res.partner']
        p_id = vals['partner_id']

        p_value = p_obj.read(cr, uid, p_id, r_fields, context=context)
        vals['name'] = p_value['display_name']
        # select mobile id or fix id of no phone
        phone_id = p_value['mobile_coordinate_id'] and \
            p_value['mobile_coordinate_id'][0] or \
            p_value['fix_coordinate_id'] and \
            p_value['fix_coordinate_id'][0] or False
        if phone_id:
            ph_obj = self.pool['phone.coordinate']
            vals['phone'] = ph_obj.browse(cr, uid, phone_id,
                                          context=context).phone_id.name
        email_id = p_value['email_coordinate_id'] and \
            p_value['email_coordinate_id'][0] or False
        if email_id:
            e_obj = self.pool['email.coordinate']
            vals['email'] = e_obj.read(cr,
                                       uid,
                                       email_id, ['email'],
                                       context=context)['email']
            vals['email_coordinate_id'] = email_id

# constraints

    _int_instance_store_trigger = {
        'event.registration':
        (lambda self, cr, uid, ids, context=None: ids, ['partner_id'], 10),
        'res.partner':
        (lambda self, cr, uid, ids, context=None: self.
         pool['event.registration'].search(
             cr, SUPERUSER_ID, [('partner_id', 'in', ids)], context=context),
         ['int_instance_id'], 10),
    }

    _columns = {
        'email_coordinate_id':
        fields.many2one('email.coordinate', string='Email Coordinate'),
        'partner_instance_id':
        fields.related('partner_id',
                       'int_instance_id',
                       string='Partner Internal Instance',
                       type='many2one',
                       relation='int.instance',
                       select=True,
                       readonly=True,
                       store=_int_instance_store_trigger),
    }

    _unicity_keys = 'event_id, partner_id'

    # orm methods

    def create(self, cr, uid, vals, context=None):
        '''
        recompute email and phone field
        '''
        if vals.get('event_id', False):
            event = self.pool['event.event'].browse(cr,
                                                    uid,
                                                    vals['event_id'],
                                                    context=context)
            if event.int_instance_id:
                ia_obj = self.pool['int.assembly']
                followers_ids = ia_obj.get_followers_assemblies(
                    cr, uid, event.int_instance_id.id, context=context)
                vals['message_follower_ids'] = [(6, 0, followers_ids)]
        if vals.get('partner_id', False):
            self._get_coordinates(cr, uid, vals, context=context)
        return super(event_registration, self).create(cr,
                                                      uid,
                                                      vals,
                                                      context=context)

# public methods

    def update_coordinates(self, cr, uid, reg_id, context=None):
        reg_vals = self.read(cr, uid, reg_id, ['partner_id'])
        partner_id = reg_vals['partner_id'][0]
        vals = {
            'partner_id': partner_id,
        }
        self._get_coordinates(cr, uid, vals, context=context)
        return self.write(cr, uid, reg_id, vals, context=context)

    def button_reg_cancel(self, cr, uid, ids, context=None):
        '''
        deactivate registration if canceled
        '''
        res = super(event_registration,
                    self).button_reg_cancel(cr, uid, ids, context=context)
        self.action_invalidate(cr, uid, ids, context=context)

        return res
Example #42
0
        "move_ids": fields.one2many("stock.move", "rent_line_id", "Inventory Moves", readonly=True),
        "state": fields.selection(
            [
                ("draft", "Draft"),
                ("cancel", "Cancelled"),
                ("confirmed", "Waiting Approval"),
                ("accepted", "Approved"),
                ("returned", "Returned"),
                ("done", "Done"),
            ],
            "Status",
            required=True,
            readonly=True,
        ),
        "order_partner_id": fields.related(
            "order_id", "partner_id", type="many2one", relation="res.partner", store=True, string="Customer"
        ),
        "salesman_id": fields.related(
            "order_id", "user_id", type="many2one", relation="res.users", store=True, string="Salesperson"
        ),
        "company_id": fields.related(
            "order_id",
            "company_id",
            type="many2one",
            relation="res.company",
            string="Company",
            store=True,
            readonly=True,
        ),
    }
Example #43
0
class sale_order(orm.Model):
    _inherit = "sale.order"

    def default_get(self, cr, uid, fields, context=None):
        context = context or self.pool['res.users'].context_get(cr, uid)
        # sale_order_obj = self.pool['sale.order']
        # sale_order_line_obj = self.pool['sale.order.line']
        res = super(sale_order, self).default_get(cr, uid, fields, context=context)
        if not res.get('shop_id', False):
            shop_ids = self.pool['sale.order'].search(cr, uid, [], limit=1, context=context)
            if shop_ids:
                res['shop_id'] = shop_ids[0]
        if not res.get('section_id', False):
            section_ids = self.pool['crm.case.section'].search(cr, uid, [('user_id', '=', uid)], context=context)
            if section_ids:
                res['section_id'] = section_ids[0]
        return res

    def service_only(self, cr, uid, ids, context):
        context = context or self.pool['res.users'].context_get(cr, uid)
        service = True
        if not isinstance(ids, (list, tuple)):
            ids = [ids]

        for order in self.browse(cr, uid, ids, context):
            if order.order_line:
                for order_line in order.order_line:
                    if order_line.product_id and order_line.product_id.type != 'service':
                        return False
            elif not service:
                    return False
        return True

    def hook_sale_state(self, cr, uid, orders, vals, context):
        context = context or self.pool['res.users'].context_get(cr, uid)
        # function call if change state the sale order
        return True

    def adaptative_function(self, cr, uid, ids, vals, context):
        context = context or self.pool['res.users'].context_get(cr, uid)
        if not isinstance(ids, (list, tuple)):
            ids = [ids]
        if vals.get('section_id', False) or vals.get('carrier_id', False) or vals.get('payment_term'):
            for order in self.browse(cr, uid, ids, context):
                partner_vals = {}
                if not order.partner_id.section_id:
                    partner_vals['section_id'] = vals.get('section_id')
                if not order.partner_id.property_delivery_carrier:
                    partner_vals['property_delivery_carrier'] = vals.get('carrier_id')
                if not order.partner_id.property_payment_term:
                    partner_vals['property_payment_term'] = vals.get('payment_term')
                if partner_vals:
                    self.pool['res.partner'].write(cr, uid, [order.partner_id.id], partner_vals, context)
        return True

    def create(self, cr, uid, vals, context=None):
        context = context or self.pool['res.users'].context_get(cr, uid)
        ids = super(sale_order, self).create(cr, uid, vals, context=context)
        self.adaptative_function(cr, uid, ids, vals, context)
        return ids

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

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

        orders = self.browse(cr, uid, ids, context)

        self.adaptative_function(cr, uid, ids, vals, context)
        if vals.get('state', False):
            self.hook_sale_state(cr, uid, orders, vals, context)

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

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

        for order in self.browse(cr, uid, ids, context):
            company = self.pool['res.users'].browse(cr, uid, uid).company_id

            if self.service_only(cr, uid, [order.id], context) and order.order_policy and order.order_policy == 'picking':
                if company.auto_order_policy:
                    order.write({'order_policy': 'manual'})
                else:
                    raise orm.except_orm(_('Warning'), _(
                        "You can't create an order with Invoicing being based on Picking if there are only service products"))
            else:
                if company.auto_order_policy:
                    default = self.default_get(cr, uid, ['order_policy'], context)
                    order.write({'order_policy': default.get('order_policy')})

        return super(sale_order, self).action_wait(cr, uid, ids, context)

    def copy(self, cr, uid, ids, default, context=None):
        context = context or self.pool['res.users'].context_get(cr, uid)
        default.update(
            {
                'tech_validation': False,
                'manager_validation': False,
                'customer_validation': False,
                'email_sent_validation': False,
                'supervisor_validation': False,
                'date_order': fields.date.context_today,
            }
        )
        default.update(self.default_get(cr, uid, ['order_policy', 'picking_policy', 'invoice_quantity'], context))
        return super(sale_order, self).copy(cr, uid, ids, default, context)

    def action_cancel_draft(self, cr, uid, ids, *args):
        self.write(cr, uid, ids, {
                'tech_validation': False,
                'manager_validation': False,
                'customer_validation': False,
                'email_sent_validation': False,
                'supervisor_validation': False,
        })
        super(sale_order, self).action_cancel_draft(cr, uid, ids, *args)
        return True

    def onchange_invoice_type_id(self, cr, uid, ids, invoice_type_id, context=None):
        if context is None:
            context = self.pool['res.users'].context_get(cr, uid)
        res = {}
        if invoice_type_id:
            invoice_type_obj = self.pool['sale_journal.invoice.type']
            invoice_type = invoice_type_obj.browse(cr, uid, invoice_type_id, context)
            if invoice_type.invoicing_method == 'grouped':
                res['order_policy'] = 'picking'
        return {'value': res}

    def onchange_partner_id(self, cr, uid, ids, part, context=None):
        context = context or self.pool['res.users'].context_get(cr, uid)
        res = super(sale_order, self).onchange_partner_id(cr, uid, ids, part)
        if res.get('value', False) and part:
            if not res['value'].get('fiscal_position', False):
                company_id = self.pool['res.users'].browse(cr, uid, uid, context=context).company_id.id
                company = self.pool['res.company'].browse(cr, uid, company_id, context)
                if company.default_property_account_position:
                    res['value']['fiscal_position'] = company.default_property_account_position and company.default_property_account_position.id
        return res

    def _credit_limit(self, cr, uid, ids, field_name, arg, context):
        context = context or self.pool['res.users'].context_get(cr, uid)
        res = dict.fromkeys(ids, 0.0)
        for order in self.browse(cr, uid, ids, context=context):

            if order.order_policy == 'prepaid':
                res[order.id] = 0
                continue
            partner = order.partner_id
            credit = partner.credit
            # We sum from all the sale orders that are aproved, the sale order lines that are not yet invoiced
            order_obj = self.pool['sale.order']
            approved_invoices_ids = order_obj.search(cr, uid, [('partner_id', '=', partner.id), ('state', 'not in', ['draft', 'cancel', 'done'])], context=context)
            approved_invoices_amount = 0.0
            for orders in order_obj.browse(cr, uid, approved_invoices_ids, context=context):
                for order_line in orders.order_line:
                    if not order_line.invoiced:
                        approved_invoices_amount += order_line.price_subtotal

            # We sum from all the invoices that are in draft the total amount
            invoice_obj = self.pool['account.invoice']
            draft_invoices_ids = invoice_obj.search(cr, uid, [('partner_id', '=', partner.id), ('state', '=', 'draft')], context=context)
            draft_invoices_amount = 0.0
            for invoice in invoice_obj.browse(cr, uid, draft_invoices_ids, context=context):
                draft_invoices_amount += invoice.amount_total
            available_credit = partner.credit_limit - credit - approved_invoices_amount - draft_invoices_amount
            res[order.id] = available_credit - order.amount_total
        return res

    def partner_overdue_check(self, cr, uid, company, partner, context):
        # return True if there are same overdue payment
        account_move_line_obj = self.pool['account.move.line']
        overdue_date = (datetime.today() - relativedelta(days=company.date_max_overdue or 0.0)).strftime(DEFAULT_SERVER_DATE_FORMAT)

        account_move_ids = account_move_line_obj.search(cr, uid, [
            ('partner_id', '=', partner.id),
            ('account_id.type', 'in', ['receivable', 'payable']),
            ('stored_invoice_id', '!=', False),
            ('reconcile_id', '=', False),
            ('date_maturity', '<', overdue_date)], context=context)

        if account_move_ids:
            return True

        return False

    def check_limit(self, cr, uid, ids, context=None):
        context = context or self.pool['res.users'].context_get(cr, uid)
        for order in self.browse(cr, uid, ids, context=context):
            if order.credit_limit < 0 and order.company_id and order.company_id.check_credit_limit:
                title = _(u'Credit Over Limit')
                msg = _(u'Is not possible to confirm because customer exceed the credit limit. \n Is Possible change the Order Policy \"Pay Before Delivery\" \n on tab \"Other Information\"')
                raise orm.except_orm(_(title), _(msg))
                return False

            if order.visible_minimum and order.sale_order_minimun > order.amount_untaxed:
                if order.shop_id.user_allow_minimun_id and order.shop_id.user_allow_minimun_id.id == uid:  # if user can validate
                    return True
                # test if on line there are the product
                if order.shop_id.product_allow_minimun_id:
                    for line in order.order_line:
                        if line.product_id and line.product_id == order.shop_id.product_allow_minimun_id:
                            return True

                title = _(u'Minimum Amount Billable')
                if order.shop_id.user_allow_minimun_id:
                    msg = _(u'Is not possible to confirm because is not reached the minimum billable {amount} {currency} \n Only {user} can do it').format(amount=order.sale_order_minimun, currency=order.pricelist_id.currency_id.symbol, user=order.shop_id.user_allow_minimun_id.name)
                else:
                    msg = _(u'Is not possible to confirm because is not reached the minimum billable {amount} {currency}').format(amount=order.sale_order_minimun, currency=order.pricelist_id.currency_id.symbol)

                if order.shop_id.product_allow_minimun_id:
                    msg += _(u'\n\n or add the product \'{product}\'').format(product=order.shop_id.product_allow_minimun_id.name_get()[0][1])

                raise orm.except_orm(_(title), _(msg))
                return False

            if order.company_id and order.company_id.check_overdue:
                if self.partner_overdue_check(cr, uid, order.company_id, order.partner_id, context):
                    title = _(u'Overdue Limit')
                    msg = _(u'Is not possible to confirm because customer have a overdue payment')
                    raise orm.except_orm(_(title), _(msg))
                return False
        return True

    def name_get(self, cr, uid, ids, context=None):
        context = context or self.pool['res.users'].context_get(cr, uid)
        if not len(ids):
            return []
        res = []
        for sale in self.browse(cr, uid, ids, context=context):
            name = u'[{sale_name}] {partner_name}'.format(sale_name=sale.name, partner_name=sale.partner_id.name)
            res.append((sale.id, name))
        return res

    def name_search(self, cr, uid, name='', args=None, operator='ilike', context=None, limit=10):
        context = context or self.pool['res.users'].context_get(cr, uid)
        if not args:
            args = []
        if name:
            ids = self.search(cr, uid, [('name', operator, name)] + args, limit=limit, context=context)
            if not len(ids):
                ids = self.search(cr, uid, [('partner_id', 'ilike', name)] + args, limit=limit, context=context)
                ids = list(set(ids))
            if not len(ids):
                ptrn = re.compile('(\[(.*?)\])')
                res = ptrn.search(name)
                if res:
                    ids = self.search(
                        cr, uid, [('name', '=', res.group(2))] + args, limit=limit, context=context)
        else:
            ids = self.search(cr, uid, args, limit=limit, context=context)

        result = self.name_get(cr, uid, ids, context=context)
        return result

    def __init__(self, registry, cr):
        """
            Add state "Suspended"
        """
        super(sale_order, self).__init__(registry, cr)
        options = [('wait_technical_validation', _('Technical Validation')),
                   ('wait_manager_validation', _('Manager Validation')),
                   ('send_to_customer', _('Send To Customer')),
                   ('wait_customer_validation', _('Customer Validation')),
                   ('wait_supervisor_validation', _('Supervisor Validation'))]

        type_selection = self._columns['state'].selection
        for option in options:
            if option not in type_selection:
                type_selection.append(option)

    def _get_shop_id(self, cr, uid, context):
        shop_ids = self.pool['sale.shop'].search(cr, uid, [], context=context, limit=1)
        return shop_ids and shop_ids[0] or False

    _columns = {
        'create_uid': fields.many2one('res.users', 'Created by', readonly=True),
        'credit_limit': fields.function(_credit_limit, string="Remaining Credit Limit", type='float', readonly=True, method=True),
        'sale_order_minimun': fields.related('shop_id', 'sale_order_minimun', type='float', string='Minimun Invoice', store=False, readonly=True),
        'visible_minimum': fields.related('shop_id', 'sale_order_have_minimum', type='boolean', string=_('Minimun Amount'), store=False, readonly=True),
        'visible_credit_limit': fields.related('company_id', 'check_credit_limit', type='boolean', string=_('Fido Residuo Visibile'), store=False, readonly=True),
        'validity': fields.date('Validity'),
        'order_line': fields.one2many('sale.order.line', 'order_id', 'Order Lines', readonly=True, states={
            'draft': [('readonly', False)],
            'wait_technical_validation': [('readonly', False)],
            'wait_manager_validation': [('readonly', False)]}
        ),
        'project_id': fields.many2one('account.analytic.account', 'Contract/Analytic Account', readonly=True, states={
            'draft': [('readonly', False)],
            'wait_technical_validation': [('readonly', False)],
            'wait_manager_validation': [('readonly', False)],
            'send_to_customer': [('readonly', False)],
            'wait_customer_validation': [('readonly', False)],
        }, help="The analytic account related to a sales order."),
        'required_tech_validation': fields.related('company_id', 'need_tech_validation', type='boolean', string=_('Required Technical Validation'), store=False, readonly=True),
        'need_tech_validation': fields.boolean("Technical Validation", readonly=True),
        'tech_validation': fields.boolean("Tech Validated ?", readonly=True),
        'required_manager_validation': fields.related('company_id', 'need_manager_validation', type='boolean', string=_('Required Manager Validation'), store=False, readonly=True),
        'need_manager_validation': fields.boolean("Manager Validation", readonly=True),
        'manager_validation': fields.boolean("Manager Validated ?", readonly=True),
        'email_sent_validation': fields.boolean("Email Sent to Customer ?", readonly=True),
        'customer_validation': fields.boolean("Customer Validated ?", readonly=True),
        # A validation after customer confirmation:
        'required_supervisor_validation': fields.related('company_id', 'need_supervisor_validation', type='boolean', string=_('Required Supervisor Validation'), store=False, readonly=True),
        'skip_supervisor_validation_onstandard_product': fields.related('company_id', 'skip_supervisor_validation_onstandard_product',
                                                                        type='boolean',
                                                                        string=_(
                                                                            'Skip Supervisor Verification if there are only standard product'),
                                                                        store=False,
                                                                        readonly=True),
        'supervisor_validation': fields.boolean(_("Supervisor Validated?"), readonly=True),
        'product_id': fields.related('order_line', 'product_id', type='many2one', relation='product.product', string='Product'),
        'revision_note': fields.char('Reason', size=256, select=True),
        'lost_reason_id': fields.many2one('crm.lost.reason', string='Lost Reason'),
        'last_revision_note': fields.related('sale_version_id', 'revision_note', type='char', string="Last Revision Note", store=True),
    }

    _defaults = {
        'need_tech_validation': lambda self, cr, uid, context: self.pool['res.users'].browse(cr, uid, uid, context).company_id.need_tech_validation,
        'need_manager_validation': lambda self, cr, uid, context: self.pool['res.users'].browse(cr, uid, uid, context).company_id.need_manager_validation,
        'skip_supervisor_validation_onstandard_product': lambda self, cr, uid, context: self.pool['res.users'].browse(cr, uid, uid, context).company_id.skip_supervisor_validation_onstandard_product,
        'required_tech_validation': lambda self, cr, uid, context: self.pool['res.users'].browse(cr, uid, uid, context).company_id.need_tech_validation,
        'required_manager_validation': lambda self, cr, uid, context: self.pool['res.users'].browse(cr, uid, uid, context).company_id.need_manager_validation,
        'required_supervisor_validation': lambda self, cr, uid, context: self.pool['res.users'].browse(cr, uid, uid, context).company_id.need_supervisor_validation,
        'validity': lambda self, cr, uid, context: (datetime.today() + relativedelta(days=self.pool['res.users'].browse(cr, uid, uid, context).company_id.default_sale_order_validity or 0.0)).strftime(DEFAULT_SERVER_DATE_FORMAT),
        'shop_id': lambda self, cr, uid, context: self._get_shop_id(cr, uid, context),
    }

    def action_reopen(self, cr, uid, ids, context=None):
        context = context or self.pool['res.users'].context_get(cr, uid)
        result = super(sale_order, self).action_reopen(cr, uid, ids, context=context)

        for order in self.browse(cr, uid, ids, context):
            if order.state == 'draft':
                self.write(cr, uid, ids, {
                    'tech_validation': False,
                    'manager_validation': False,
                    'email_sent_validation': False,
                    'customer_validation': False,
                }, context)
        return result

    def check_direct_order_confirm(self, cr, uid, ids, context=None):
        context = context or self.pool['res.users'].context_get(cr, uid)
        for order in self.browse(cr, uid, ids, context):
            if order.state == 'draft' and order.pricelist_id and order.pricelist_id.contract:
                return True
            else:
                return False

    def check_tech_validation(self, cr, uid, ids, context=None):
        context = context or self.pool['res.users'].context_get(cr, uid)
        for order in self.browse(cr, uid, ids, context):
            if order.shop_id.user_tech_validation_id:
                if order.shop_id.user_tech_validation_id.id == uid:
                    return True
                else:
                    title = _('Technical Validation')
                    msg = _(u"It's not possible to confirm, for shop {shop} only user '{user}' can do it".format(shop=order.shop_id.name, user=order.shop_id.user_tech_validation_id.name))
                    raise orm.except_orm(_(title), _(msg))
                    return False

            else:
                return True

    def check_manager_validation(self, cr, uid, ids, context=None):
        context = context or self.pool['res.users'].context_get(cr, uid)
        for order in self.browse(cr, uid, ids, context):
            if order.shop_id.user_manager_validation_id:
                if order.shop_id.user_manager_validation_id.id == uid:
                    return True
                else:
                    title = _('Manager Validation')
                    msg = _(u"It's not possible to confirm, for shop {shop} only user '{user}' can do it".format(shop=order.shop_id.name, user=order.shop_id.user_manager_validation_id.name))
                    raise orm.except_orm(_(title), _(msg))
                    return False
            else:
                return True

    def check_supervisor_validation(self, cr, uid, ids, context=None):
        context = context or self.pool['res.users'].context_get(cr, uid)
        for order in self.browse(cr, uid, ids, context):
            if order.shop_id.user_supervisor_validation_id:
                if order.shop_id.user_supervisor_validation_id.id == uid:
                    return True
                else:
                    title = _('Supervisor Validation')
                    msg = _(u"It's not possible to confirm, for shop {shop} only user '{user}' can do it".format(shop=order.shop_id.name, user=order.shop_id.user_supervisor_validation_id.name))
                    raise orm.except_orm(_(title), _(msg))
                    return False
            else:
                return True

    def required_tech_validation(self, order):
        if order.company_id.tech_validation_if_no_product:
            for line in order.order_line:
                if not line.product_id:
                    order.write({'need_tech_validation': True})
                    return True
        return False

    def check_discount(self, order):
        if order.company_id.enable_discount_validation:
            max_discount = order.company_id.max_discount
            for line in order.order_line:
                if line.discount > max_discount:
                    order.write({'need_manager_validation': True})
                    return True
        return False

    def action_validate(self, cr, uid, ids, context=None):
        context = context or self.pool['res.users'].context_get(cr, uid)
        for order in self.browse(cr, uid, ids, context):
            if not order.partner_id.validate and order.company_id.enable_partner_validation:
                title = _('Partner To Validate')
                msg = _("It's not possible to confirm because customer must be validated")
                raise orm.except_orm(_(title), _(msg))
                return False

            if order.need_tech_validation and not order.tech_validation or self.required_tech_validation(order):
                vals = {
                    'state': 'wait_technical_validation',
                }
            elif self.check_discount(order):
                vals = {
                    'state': 'wait_manager_validation',
                }
            elif order.company_id.enable_margin_validation and order.amount_untaxed and (order.margin / order.amount_untaxed) * 100 < order.company_id.minimum_margin and not order.manager_validation:
                vals = {
                    'state': 'wait_manager_validation',
                }
            elif order.need_manager_validation and not order.manager_validation:
                vals = {
                    'state': 'wait_manager_validation',
                }
            elif not order.email_sent_validation:
                vals = {
                    'state': 'send_to_customer',
                }
            elif not order.customer_validation:
                vals = {
                    'state': 'wait_customer_validation',
                }
            elif order.required_supervisor_validation and not order.supervisor_validation:
                vals = {
                    'state': 'wait_supervisor_validation',
                }
            else:
                vals = {
                    'state': 'draft',
                    'tech_validation': False,
                    'manager_validation': False,
                    'customer_validation': False,
                    'email_sent_validation': False,
                    'supervisor_validation': False
                }
            order.write(vals)

        return True

    def check_validate(self, cr, uid, ids, context=None):
        context = context or self.pool['res.users'].context_get(cr, uid)
        for order in self.browse(cr, uid, ids, context):
            res = True
            if order.need_tech_validation and not order.tech_validation:
                res = False
            elif order.need_manager_validation and not order.manager_validation:
                res = False
            elif order.required_supervisor_validation and not order.supervisor_validation:
                if order.skip_supervisor_validation_onstandard_product:
                    for line in order.order_line:
                        if line.product_id and line.product_id.is_kit:
                            return False
                    res = True
                else:
                    res = False
            return res and order.email_sent_validation and order.customer_validation
        return True

    def check_direct_confirm(self, cr, uid, ids, context=None):
        context = context or self.pool['res.users'].context_get(cr, uid)
        if self.check_limit(cr, uid, ids, context):
            for order in self.browse(cr, uid, ids, context):
                values = {
                    'state': 'wait_customer_validation',
                    'customer_validation': True
                }
                if order.need_tech_validation:
                    values['tech_validation'] = True

                if (order.company_id.enable_margin_validation and order.amount_untaxed and (order.margin / order.amount_untaxed) < order.company_id.minimum_margin) or order.need_manager_validation:
                    values['manager_validation'] = True

                if order.required_supervisor_validation:
                    values['supervisor_validation'] = True

                self.write(cr, uid, [order.id], values, context)

            return self.action_validate(cr, uid, ids, context)
        else:
            return False

    def copy(self, cr, uid, ids, default={}, context=None):
        default = default or {}
        context = context or self.pool['res.users'].context_get(cr, uid)
        default.update({
            'validity': (datetime.today() + relativedelta(days=self.pool['res.users'].browse(cr, uid, uid, context).company_id.default_sale_order_validity or 0.0)).strftime(DEFAULT_SERVER_DATE_FORMAT),
            'tech_validation': False,
            'manager_validation': False,
            'customer_validation': False,
            'email_sent_validation': False,
            'supervisor_validation': False,
            'lost_reason_id': False
        })
        return super(sale_order, self).copy(cr, uid, ids, default, context=context)
Example #44
0
class hr_si_project(osv.osv_memory):

    _name = 'hr.sign.in.project'
    _description = 'Sign In By Project'
    _columns = {
        'name':
        fields.char('Employee\'s Name', readonly=True),
        'state':
        fields.related('emp_id',
                       'state',
                       string='Current Status',
                       type='selection',
                       selection=[('present', 'Present'),
                                  ('absent', 'Absent')],
                       required=True,
                       readonly=True),
        'date':
        fields.datetime('Starting Date'),
        'server_date':
        fields.datetime('Current Date', readonly=True),
        'emp_id':
        fields.many2one('hr.employee', 'Employee ID')
    }

    def view_init(self, cr, uid, fields, context=None):
        """
        This function checks for precondition before wizard executes
        @param self: The object pointer
        @param cr: the current row, from the database cursor,
        @param uid: the current user’s ID for security checks,
        @param fields: List of fields for default value
        @param context: A standard dictionary for contextual values
        """
        emp_obj = self.pool.get('hr.employee')
        emp_id = emp_obj.search(cr,
                                uid, [('user_id', '=', uid)],
                                context=context)
        if not emp_id:
            raise osv.except_osv(_('User Error!'),
                                 _('Please define employee for your user.'))
        return False

    def check_state(self, cr, uid, ids, context=None):
        obj_model = self.pool.get('ir.model.data')
        emp_id = self.default_get(cr, uid, ['emp_id'], context)['emp_id']
        # get the latest action (sign_in or out) for this employee
        cr.execute(
            'select action from hr_attendance where employee_id=%s and action in (\'sign_in\',\'sign_out\') order by name desc limit 1',
            (emp_id, ))
        res = (cr.fetchone() or ('sign_out', ))[0]
        in_out = (res == 'sign_out') and 'in' or 'out'
        #TODO: invert sign_in et sign_out
        model_data_ids = obj_model.search(
            cr,
            uid, [('model', '=', 'ir.ui.view'),
                  ('name', '=', 'view_hr_timesheet_sign_%s' % in_out)],
            context=context)
        resource_id = obj_model.read(cr,
                                     uid,
                                     model_data_ids,
                                     fields=['res_id'],
                                     context=context)[0]['res_id']
        return {
            'name': _('Sign in / Sign out'),
            'view_type': 'form',
            'view_mode': 'tree,form',
            'res_model': 'hr.sign.%s.project' % in_out,
            'views': [(resource_id, 'form')],
            'type': 'ir.actions.act_window',
            'target': 'new'
        }

    def sign_in_result(self, cr, uid, ids, context=None):
        emp_obj = self.pool.get('hr.employee')
        for data in self.browse(cr, uid, ids, context=context):
            emp_id = data.emp_id.id
            emp_obj.attendance_action_change(cr, uid, [emp_id], {
                'action': 'sign_in',
                'action_date': data.date
            })
        return {'type': 'ir.actions.act_window_close'}

    def default_get(self, cr, uid, fields_list, context=None):
        res = super(hr_si_project, self).default_get(cr,
                                                     uid,
                                                     fields_list,
                                                     context=context)
        emp_obj = self.pool.get('hr.employee')
        emp_id = emp_obj.search(cr,
                                uid, [('user_id', '=', uid)],
                                context=context)
        if emp_id:
            for employee in emp_obj.browse(cr, uid, emp_id, context=context):
                res.update({
                    'name': employee.name,
                    'state': employee.state,
                    'emp_id': emp_id[0],
                    'server_date': time.strftime('%Y-%m-%d %H:%M:%S')
                })
        return res
Example #45
0
class pos_session_opening(osv.osv_memory):
    _name = 'pos.session.opening'

    _columns = {
        'pos_config_id':
        fields.many2one('pos.config', 'Point of Sale', required=True),
        'pos_session_id':
        fields.many2one('pos.session', 'PoS Session'),
        'pos_state':
        fields.related('pos_session_id',
                       'state',
                       type='selection',
                       selection=pos_session.POS_SESSION_STATE,
                       string='Session Status',
                       readonly=True),
        'pos_state_str':
        fields.char('Status', 32, readonly=True),
        'show_config':
        fields.boolean('Show Config', readonly=True),
        'pos_session_name':
        fields.related('pos_session_id',
                       'name',
                       type='char',
                       size=64,
                       readonly=True),
        'pos_session_username':
        fields.related('pos_session_id',
                       'user_id',
                       'name',
                       type='char',
                       size=64,
                       readonly=True)
    }

    def open_ui(self, cr, uid, ids, context=None):
        context = context or {}
        data = self.browse(cr, uid, ids[0], context=context)
        context['active_id'] = data.pos_session_id.id or False
        print "******CONTEXT['active_id']*****: ", context['active_id']
        return {
            'type': 'ir.actions.client',
            'name': _('Start Point Of Sale'),
            'tag': 'pos.ui',
            'context': context
        }

    def open_existing_session_cb_close(self, cr, uid, ids, context=None):
        wf_service = netsvc.LocalService("workflow")
        wizard = self.browse(cr, uid, ids[0], context=context)
        wf_service.trg_validate(uid, 'pos.session', wizard.pos_session_id.id,
                                'cashbox_control', cr)
        return self.open_session_cb(cr, uid, ids, context)

    def open_session_cb(self, cr, uid, ids, context=None):
        assert len(ids) == 1, "you can open only one session at a time"
        proxy = self.pool.get('pos.session')
        wizard = self.browse(cr, uid, ids[0], context=context)
        if not wizard.pos_session_id:
            values = {
                'user_id': uid,
                'config_id': wizard.pos_config_id.id,
            }
            session_id = proxy.create(cr, uid, values, context=context)
            s = proxy.browse(cr, uid, session_id, context=context)
            if s.state == 'opened':
                return self.open_ui(cr, uid, ids, context=context)
            return self._open_session(session_id)
        return self._open_session(wizard.pos_session_id.id)

    def open_existing_session_cb(self, cr, uid, ids, context=None):
        assert len(ids) == 1
        wizard = self.browse(cr, uid, ids[0], context=context)
        return self._open_session(wizard.pos_session_id.id)

    def _open_session(self, session_id):
        return {
            'name': _('Session'),
            'view_type': 'form',
            'view_mode': 'form,tree',
            'res_model': 'pos.session',
            'res_id': session_id,
            'view_id': False,
            'type': 'ir.actions.act_window',
        }

    def on_change_config(self, cr, uid, ids, config_id, context=None):
        result = {
            'pos_session_id': False,
            'pos_state': False,
            'pos_state_str': '',
            'pos_session_username': False,
            'pos_session_name': False,
        }
        if not config_id:
            return {'value': result}
        proxy = self.pool.get('pos.session')
        session_ids = proxy.search(cr,
                                   uid, [
                                       ('state', '!=', 'closed'),
                                       ('config_id', '=', config_id),
                                   ],
                                   context=context)
        if session_ids:
            session = proxy.browse(cr, uid, session_ids[0], context=context)
            result['pos_state'] = str(session.state)
            result['pos_state_str'] = dict(pos_session.POS_SESSION_STATE).get(
                session.state, '')
            result['pos_session_id'] = session.id
            result['pos_session_name'] = session.name
            result['pos_session_username'] = session.user_id.name

        return {'value': result}

    def default_get(self, cr, uid, fieldnames, context=None):
        so = self.pool.get('pos.session')
        session_ids = so.search(cr,
                                uid, [('state', '<>', 'closed'),
                                      ('user_id', '=', uid)],
                                context=context)
        if session_ids:
            result = so.browse(cr, uid, session_ids[0],
                               context=context).config_id.id
        else:
            current_user = self.pool.get('res.users').browse(cr,
                                                             uid,
                                                             uid,
                                                             context=context)
            result = current_user.pos_config and current_user.pos_config.id or False
        if not result:
            r = self.pool.get('pos.config').search(cr,
                                                   uid, [],
                                                   context=context)
            result = r and r[0] or False

        count = self.pool.get('pos.config').search_count(
            cr, uid, [('state', '=', 'active')], context=context)
        show_config = bool(count > 1)
        return {
            'pos_config_id': result,
            'show_config': show_config,
        }
Example #46
0
import xml2dic
<<<<<<< HEAD
from openerp.tools.translate import _

class res_partner(osv.osv):
=======
from tools.translate import _

class res_partner(osv.Model):
>>>>>>> c1979f64b3360c86d60e00c92be0271d89f97f2d
    _inherit = 'res.partner'
    _rec_name = 'payment_profile_id'
    _columns = {
        'payment_profile_id': fields.many2one('cust.profile', 'Payment Profiles', help='Store customers payment profile id', readonly='True'),
#        'payment_profile_ids':fields.one2many('cust.payment.profile', 'partner_id','Payment Profiles' ,help='Store customers payment profile id',readonly=True),
        'payment_profile_ids': fields.related('payment_profile_id', 'payment_profile_ids', type='one2many', relation='cust.payment.profile', string='Payment Profiles', readonly=True),
    }

    def request_to_server(self, Request_string, url, url_path):
        ''' Sends a POST request to url and returns the response from the server'''
        if ('http' or 'https') in url[:5]:
            raise osv.except_osv(_('Configuration Error!'), _('Request URL should not start with http or https.\nPlease check Authorization Configuration in Company.'))
        conn = httplib.HTTPSConnection(url)
        conn.putrequest('POST', url_path)
        conn.putheader('content-type', 'text/xml')
        conn.putheader('content-length', len(Request_string))
        conn.endheaders()
        conn.send(Request_string)
        response = conn.getresponse()
        create_CustomerProfile_response_xml = response.read()
        return create_CustomerProfile_response_xml
Example #47
0
class sale_order_line(orm.Model):
    _inherit = "sale.order.line"

    def _prepare_order_line_invoice_line(self, cr, uid, line, account_id=False, context=None):
        context = context or self.pool['res.users'].context_get(cr, uid)
        vals = super(sale_order_line, self)._prepare_order_line_invoice_line(cr, uid, line, account_id, context)
        if vals:
            vals.update({'origin_document': 'sale.order.line, {line_id}'.format(line_id=line.id)})
        return vals

    def _delivered_qty(self, cr, uid, ids, field_name, arg, context=None):
        context = context or self.pool['res.users'].context_get(cr, uid)
        res = {}
        for line in self.browse(cr, uid, ids, context=context):
            qty = 0

            for move in line.move_ids:
                if move.state == 'done':
                    qty += move.product_qty

            res[line.id] = qty
        return res

    def _product_available(self, cr, uid, ids, field_names=None, arg=False, context=None):
        """ Finds the incoming and outgoing quantity of product.
        @return: Dictionary of values
        """
        context = context or self.pool['res.users'].context_get(cr, uid)
        res = {}
        # if line.order_id:
        #     context['warehouse'] = self.order_id.shop_id.warehouse_id.id

        for line in self.browse(cr, uid, ids, context):
            res[line.id] = {
                'qty_available': line.product_id and line.product_id.type != 'service' and line.product_id.qty_available or False,
                'virtual_available': line.product_id and line.product_id.type != 'service' and line.product_id.virtual_available or False}
        return res

    # overwrite of a funcion inside sale_margin
    def product_id_change(self, cr, uid, ids, pricelist, product_id, qty=0,
                          uom=False, qty_uos=0, uos=False, name='', partner_id=False,
                          lang=False, update_tax=True, date_order=False, packaging=False, fiscal_position=False,
                          flag=False, context=None):
        context = context or self.pool['res.users'].context_get(cr, uid)
        context.update(error_on_available=False)
        res = super(sale_order_line, self).product_id_change(cr, uid, ids, pricelist, product_id, qty=qty,
                                                             uom=uom, qty_uos=qty_uos, uos=uos, name=name,
                                                             partner_id=partner_id,
                                                             lang=lang, update_tax=update_tax, date_order=date_order,
                                                             packaging=packaging, fiscal_position=fiscal_position,
                                                             flag=flag, context=context)
        if not pricelist:
            return res

        frm_cur = self.pool['res.users'].browse(cr, uid, uid, context).company_id.currency_id.id
        to_cur = self.pool['product.pricelist'].browse(cr, uid, [pricelist], context)[0].currency_id.id
        if product_id:
            product = self.pool['product.product'].browse(cr, uid, product_id, context)
            price = self.pool['res.currency'].compute(cr, uid, frm_cur, to_cur, product.cost_price, round=False)
            res['value'].update({
                'purchase_price': price,
                'product_type': product.type
            })

        return res

    _columns = {
        'order_id': fields.many2one('sale.order', 'Order Reference', ondelete='cascade', select=True, readonly=True,
                                    states={'draft': [('readonly', False)]}),
        'readonly_price_unit': fields.related('order_id', 'company_id', 'readonly_price_unit', type='boolean',
                                              string=_('Readonly Price Unit'), store=False, readonly=True),
        'delivered_qty': fields.function(_delivered_qty, digits_compute=dp.get_precision('Product UoM'),
                                         string='Delivered Qty'),
        'qty_available': fields.function(_product_available, multi='qty_available',
                                         type='float', digits_compute=dp.get_precision('Product UoM'),
                                         string='Quantity On Hand'),
        'virtual_available': fields.function(_product_available, multi='qty_available',
                                             type='float', digits_compute=dp.get_precision('Product UoM'),
                                             string='Quantity Available'),
        'product_type': fields.char('Product type', size=64),
    }

    _defaults = {
        'readonly_price_unit': lambda self, cr, uid, context: self.pool['res.users'].browse(cr, uid, uid,
                                                                                            context).company_id.readonly_price_unit,
        'order_id': lambda self, cr, uid, context: context.get('default_sale_order', False) or False
    }

    def default_get(self, cr, uid, fields, context=None):
        """
        """
        if not context:
            context = self.pool['res.users'].context_get(cr, uid)
        res = super(sale_order_line, self).default_get(cr, uid, fields, context=context)
        if not res.get('tax_id', False):
            fpos_obj = self.pool['account.fiscal.position']
            product_default_get = self.pool['product.product'].default_get(cr, uid, ['taxes_id', 'uom_id'])
            taxes = product_default_get.get('taxes_id', False)
            if taxes:
                taxes = self.pool['account.tax'].browse(cr, uid, taxes, context)

                if context.get('fiscal_position', False):
                    fpos = fpos_obj.browse(cr, uid, context['fiscal_position'], context)
                    if taxes:
                        tax_id = fpos_obj.map_tax(cr, uid, fpos, taxes)
                    else:
                        tax_id = []
                else:
                    if taxes:
                        tax_id = [line.id for line in taxes]
                    else:
                        tax_id = []

                res.update({
                    'tax_id': [(6, 0, tax_id)],
                })
        uom_id = product_default_get.get('uom_id', False)
        if uom_id:
            res.update({
                    'product_uom': uom_id
            })
        return res
Example #48
0
class membership_line(osv.osv):
    _name = 'membership.membership_line'
    _description = __doc__

    def _get_partners(self, cr, uid, ids, context=None):
        list_membership_line = []
        member_line_obj = self.pool.get('membership.membership_line')
        for partner in self.pool.get('res.partner').browse(cr,
                                                           uid,
                                                           ids,
                                                           context=context):
            if partner.member_lines:
                list_membership_line += member_line_obj.search(
                    cr,
                    uid, [('id', 'in', [l.id for l in partner.member_lines])],
                    context=context)
        return list_membership_line

    def _get_membership_lines(self, cr, uid, ids, context=None):
        list_membership_line = []
        member_line_obj = self.pool.get('membership.membership_line')
        for invoice in self.pool.get('account.invoice').browse(
                cr, uid, ids, context=context):
            if invoice.invoice_line_ids:
                list_membership_line += member_line_obj.search(
                    cr,
                    uid, [('account_invoice_line', 'in',
                           [l.id for l in invoice.invoice_line_ids])],
                    context=context)
        return list_membership_line

    def _check_membership_date(self, cr, uid, ids, context=None):
        """Check if membership product is not in the past """

        cr.execute(
            '''
         SELECT MIN(ml.date_to - ai.date_invoice)
             FROM membership_membership_line ml
             JOIN account_invoice_line ail ON (
                ml.account_invoice_line = ail.id
                )
            JOIN account_invoice ai ON (
            ai.id = ail.invoice_id)
            WHERE ml.id IN %s''', (tuple(ids), ))
        res = cr.fetchall()
        for r in res:
            if r[0] and r[0] < 0:
                return False
        return True

    def _state(self, cr, uid, ids, name, args, context=None):
        """Compute the state lines """
        res = {}
        inv_obj = self.pool.get('account.invoice')
        for line in self.browse(cr, uid, ids, context=context):
            cr.execute(
                '''
            SELECT i.state, i.id FROM
            account_invoice i
            WHERE
            i.id = (
                SELECT l.invoice_id FROM
                account_invoice_line l WHERE
                l.id = (
                    SELECT  ml.account_invoice_line FROM
                    membership_membership_line ml WHERE
                    ml.id = %s
                    )
                )
            ''', (line.id, ))
            fetched = cr.fetchone()
            if not fetched:
                res[line.id] = 'canceled'
                continue
            istate = fetched[0]
            state = 'none'
            if (istate == 'draft') | (istate == 'proforma'):
                state = 'waiting'
            elif istate == 'open':
                state = 'invoiced'
            elif istate == 'paid':
                state = 'paid'
                inv = inv_obj.browse(cr, uid, fetched[1], context=context)
                for payment in inv.payment_ids:
                    if payment.invoice_ids and any(
                            inv.type == 'out_refund'
                            for inv in payment.invoice_ids):
                        state = 'canceled'
            elif istate == 'cancel':
                state = 'canceled'
            res[line.id] = state
        return res

    _columns = {
        'partner':
        fields.many2one('res.partner', 'Partner', ondelete='cascade',
                        select=1),
        'membership_id':
        fields.many2one('product.product', string="Membership", required=True),
        'date_from':
        fields.date('From', readonly=True),
        'date_to':
        fields.date('To', readonly=True),
        'date_cancel':
        fields.date('Cancel date'),
        'date':
        fields.date('Join Date',
                    help="Date on which member has joined the membership"),
        'member_price':
        fields.float('Membership Fee',
                     digits_compute=dp.get_precision('Product Price'),
                     required=True,
                     help='Amount for the membership'),
        'account_invoice_line':
        fields.many2one('account.invoice.line',
                        'Account Invoice line',
                        readonly=True),
        'account_invoice_id':
        fields.related('account_invoice_line',
                       'invoice_id',
                       type='many2one',
                       relation='account.invoice',
                       string='Invoice',
                       readonly=True),
        'state':
        fields.function(_state,
                        string='Membership Status',
                        type='selection',
                        selection=STATE,
                        store={
                            'account.invoice':
                            (_get_membership_lines, ['state'], 10),
                            'res.partner':
                            (_get_partners, ['membership_state'], 12),
                        },
                        help="""It indicates the membership status.
                        -Non Member: A member who has not applied for any membership.
                        -Cancelled Member: A member who has cancelled his membership.
                        -Old Member: A member whose membership date has expired.
                        -Waiting Member: A member who has applied for the membership and whose invoice is going to be created.
                        -Invoiced Member: A member whose invoice has been created.
                        -Paid Member: A member who has paid the membership amount."""
                        ),
        'company_id':
        fields.related('account_invoice_line',
                       'invoice_id',
                       'company_id',
                       type="many2one",
                       relation="res.company",
                       string="Company",
                       readonly=True,
                       store=True)
    }
    _rec_name = 'partner'
    _order = 'id desc'
    _constraints = [(_check_membership_date,
                     'Error, this membership product is out of date', [])]
Example #49
0
class res_partner(osv.Model, format_address):
    _description = 'Partner'
    _name = "res.partner"

    def _address_display(self, cr, uid, ids, name, args, context=None):
        res = {}
        for partner in self.browse(cr, uid, ids, context=context):
            res[partner.id] = self._display_address(cr,
                                                    uid,
                                                    partner,
                                                    context=context)
        return res

    @api.multi
    def _get_tz_offset(self, name, args):
        return dict((
            p.id,
            datetime.datetime.now(pytz.timezone(p.tz or 'GMT')).strftime('%z'))
                    for p in self)

    def _commercial_partner_compute(self,
                                    cr,
                                    uid,
                                    ids,
                                    name,
                                    args,
                                    context=None):
        """ Returns the partner that is considered the commercial
        entity of this partner. The commercial entity holds the master data
        for all commercial fields (see :py:meth:`~_commercial_fields`) """
        result = dict.fromkeys(ids, False)
        for partner in self.browse(cr, uid, ids, context=context):
            current_partner = partner
            while not current_partner.is_company and current_partner.parent_id:
                current_partner = current_partner.parent_id
            result[partner.id] = current_partner.id
        return result

    def _display_name_compute(self, cr, uid, ids, name, args, context=None):
        context = dict(context or {})
        context.pop('show_address', None)
        context.pop('show_address_only', None)
        context.pop('show_email', None)
        return dict(self.name_get(cr, uid, ids, context=context))

    # indirections to avoid passing a copy of the overridable method when declaring the function field
    _commercial_partner_id = lambda self, *args, **kwargs: self._commercial_partner_compute(
        *args, **kwargs)
    _display_name = lambda self, *args, **kwargs: self._display_name_compute(
        *args, **kwargs)

    _commercial_partner_store_triggers = {
        'res.partner': (lambda self, cr, uid, ids, context=None: self.search(
            cr,
            uid, [('id', 'child_of', ids)],
            context=dict(active_test=False)), ['parent_id', 'is_company'], 10)
    }
    _display_name_store_triggers = {
        'res.partner': (lambda self, cr, uid, ids, context=None: self.search(
            cr,
            uid, [('id', 'child_of', ids)],
            context=dict(active_test=False)),
                        ['parent_id', 'is_company', 'name'], 10)
    }

    _order = "display_name"
    _columns = {
        'name':
        fields.char('Name', select=True),
        'display_name':
        fields.function(_display_name,
                        type='char',
                        string='Name',
                        store=_display_name_store_triggers,
                        select=True),
        'date':
        fields.date('Date', select=1),
        'title':
        fields.many2one('res.partner.title', 'Title'),
        'parent_id':
        fields.many2one('res.partner', 'Related Company', select=True),
        'parent_name':
        fields.related('parent_id',
                       'name',
                       type='char',
                       readonly=True,
                       string='Parent name'),
        'child_ids':
        fields.one2many(
            'res.partner',
            'parent_id',
            'Contacts',
            domain=[
                ('active', '=', True)
            ]),  # force "active_test" domain to bypass _search() override
        'ref':
        fields.char('Internal Reference', select=1),
        'lang':
        fields.selection(
            _lang_get,
            'Language',
            help=
            "If the selected language is loaded in the system, all documents related to this contact will be printed in this language. If not, it will be English."
        ),
        'tz':
        fields.selection(
            _tz_get,
            'Timezone',
            size=64,
            help=
            "The partner's timezone, used to output proper date and time values inside printed reports. "
            "It is important to set a value for this field. You should use the same timezone "
            "that is otherwise used to pick and render date and time values: your computer's timezone."
        ),
        'tz_offset':
        fields.function(_get_tz_offset,
                        type='char',
                        size=5,
                        string='Timezone offset',
                        invisible=True),
        'user_id':
        fields.many2one(
            'res.users',
            'Salesperson',
            help=
            'The internal user that is in charge of communicating with this contact if any.'
        ),
        'vat':
        fields.char(
            'TIN',
            help=
            "Tax Identification Number. Fill it if the company is subjected to taxes. Used by the some of the legal statements."
        ),
        'bank_ids':
        fields.one2many('res.partner.bank', 'partner_id', 'Banks'),
        'website':
        fields.char('Website', help="Website of Partner or Company"),
        'comment':
        fields.text('Notes'),
        'category_id':
        fields.many2many('res.partner.category',
                         id1='partner_id',
                         id2='category_id',
                         string='Tags'),
        'credit_limit':
        fields.float(string='Credit Limit'),
        'barcode':
        fields.char('Barcode', oldname='ean13'),
        'active':
        fields.boolean('Active'),
        'customer':
        fields.boolean('Is a Customer',
                       help="Check this box if this contact is a customer."),
        'supplier':
        fields.boolean(
            'Is a Vendor',
            help=
            "Check this box if this contact is a vendor. If it's not checked, purchase people will not see it when encoding a purchase order."
        ),
        'employee':
        fields.boolean('Employee',
                       help="Check this box if this contact is an Employee."),
        'function':
        fields.char('Job Position'),
        'type':
        fields.selection(
            [('contact', 'Contact'), ('invoice', 'Invoice address'),
             ('delivery', 'Shipping address'), ('other', 'Other address')],
            'Address Type',
            help=
            "Used to select automatically the right address according to the context in sales and purchases documents."
        ),
        'street':
        fields.char('Street'),
        'street2':
        fields.char('Street2'),
        'zip':
        fields.char('Zip', size=24, change_default=True),
        'city':
        fields.char('City'),
        'state_id':
        fields.many2one("res.country.state", 'State', ondelete='restrict'),
        'country_id':
        fields.many2one('res.country', 'Country', ondelete='restrict'),
        'email':
        fields.char('Email'),
        'phone':
        fields.char('Phone'),
        'fax':
        fields.char('Fax'),
        'mobile':
        fields.char('Mobile'),
        'birthdate':
        fields.char('Birthdate'),
        'is_company':
        fields.boolean(
            'Is a Company',
            help="Check if the contact is a company, otherwise it is a person"
        ),
        'company_type':
        fields.selection(
            selection=[('person', 'Individual'), ('company', 'Company')],
            string='Company Type',
            help='Technical field, used only to display a boolean using a radio '
            'button. As for Odoo v9 RadioButton cannot be used on boolean '
            'fields, this one serves as interface. Due to the old API '
            'limitations with interface function field, we implement it '
            'by hand instead of a true function field. When migrating to '
            'the new API the code should be simplified.'),
        'use_parent_address':
        fields.boolean(
            'Use Company Address',
            help=
            "Select this if you want to set company's address information  for this contact"
        ),
        'company_id':
        fields.many2one('res.company', 'Company', select=1),
        'color':
        fields.integer('Color Index'),
        'user_ids':
        fields.one2many('res.users', 'partner_id', 'Users', auto_join=True),
        'contact_address':
        fields.function(_address_display,
                        type='char',
                        string='Complete Address'),

        # technical field used for managing commercial fields
        'commercial_partner_id':
        fields.function(_commercial_partner_id,
                        type='many2one',
                        relation='res.partner',
                        string='Commercial Entity',
                        store=_commercial_partner_store_triggers)
    }

    # image: all image fields are base64 encoded and PIL-supported
    image = openerp.fields.Binary(
        "Image",
        attachment=True,
        help=
        "This field holds the image used as avatar for this contact, limited to 1024x1024px",
        default=lambda self: self._get_default_image(False, True))
    image_medium = openerp.fields.Binary("Medium-sized image", attachment=True,
        help="Medium-sized image of this contact. It is automatically "\
             "resized as a 128x128px image, with aspect ratio preserved. "\
             "Use this field in form views or some kanban views.")
    image_small = openerp.fields.Binary("Small-sized image", attachment=True,
        help="Small-sized image of this contact. It is automatically "\
             "resized as a 64x64px image, with aspect ratio preserved. "\
             "Use this field anywhere a small image is required.")

    @api.model
    def _default_category(self):
        category_id = self.env.context.get('category_id', False)
        return [category_id] if category_id else False

    @api.model
    def _get_default_image(self, is_company, colorize=False):
        if getattr(threading.currentThread(), 'testing',
                   False) or self.env.context.get('install_mode'):
            return False

        if self.env.context.get('partner_type') == 'delivery':
            img_path = openerp.modules.get_module_resource(
                'base', 'static/src/img', 'truck.png')
        elif self.env.context.get('partner_type') == 'invoice':
            img_path = openerp.modules.get_module_resource(
                'base', 'static/src/img', 'money.png')
        else:
            img_path = openerp.modules.get_module_resource(
                'base', 'static/src/img',
                'company_image.png' if is_company else 'avatar.png')
        with open(img_path, 'rb') as f:
            image = f.read()

        # colorize user avatars
        if not is_company and colorize:
            image = tools.image_colorize(image)

        return tools.image_resize_image_big(image.encode('base64'))

    def fields_view_get(self,
                        cr,
                        user,
                        view_id=None,
                        view_type='form',
                        context=None,
                        toolbar=False,
                        submenu=False):
        if (not view_id) and (view_type == 'form') and context and context.get(
                'force_email', False):
            view_id = self.pool['ir.model.data'].get_object_reference(
                cr, user, 'base', 'view_partner_simple_form')[1]
        res = super(res_partner, self).fields_view_get(cr,
                                                       user,
                                                       view_id=view_id,
                                                       view_type=view_type,
                                                       context=context,
                                                       toolbar=toolbar,
                                                       submenu=submenu)
        if view_type == 'form':
            res['arch'] = self.fields_view_get_address(cr,
                                                       user,
                                                       res['arch'],
                                                       context=context)
        return res

    @api.model
    def _default_company(self):
        return self.env['res.company']._company_default_get('res.partner')

    _defaults = {
        'active': True,
        'lang': api.model(lambda self: self.env.lang),
        'tz': api.model(lambda self: self.env.context.get('tz', False)),
        'customer': True,
        'category_id': _default_category,
        'company_id': _default_company,
        'color': 0,
        'is_company': False,
        'company_type': 'person',
        'type': 'contact',
        'image': False,
    }

    _constraints = [
        (osv.osv._check_recursion,
         'You cannot create recursive Partner hierarchies.', ['parent_id']),
    ]

    _sql_constraints = [
        ('check_name',
         "CHECK( (type='contact' AND name IS NOT NULL) or (type!='contact') )",
         'Contacts require a name.'),
    ]

    @api.one
    def copy(self, default=None):
        default = dict(default or {})
        default['name'] = _('%s (copy)') % self.name
        return super(res_partner, self).copy(default)

    def onchange_parent_id(self, cr, uid, ids, parent_id, context=None):
        def value_or_id(val):
            """ return val or val.id if val is a browse record """
            return val if isinstance(val, (bool, int, long, float,
                                           basestring)) else val.id

        if not parent_id or not ids:
            return {'value': {}}
        if parent_id:
            result = {}
            partner = self.browse(cr, uid, ids[0], context=context)
            if partner.parent_id and partner.parent_id.id != parent_id:
                result['warning'] = {
                    'title':
                    _('Warning'),
                    'message':
                    _('Changing the company of a contact should only be done if it '
                      'was never correctly set. If an existing contact starts working for a new '
                      'company then a new contact should be created under that new '
                      'company. You can use the "Discard" button to abandon this change.'
                      )
                }
            # for contacts: copy the parent address, if set (aka, at least
            # one value is set in the address: otherwise, keep the one from
            # the contact)
            if partner.type == 'contact':
                parent = self.browse(cr, uid, parent_id, context=context)
                address_fields = self._address_fields(cr, uid, context=context)
                if any(parent[key] for key in address_fields):
                    result['value'] = dict((key, value_or_id(parent[key]))
                                           for key in address_fields)
        return result

    @api.multi
    def onchange_state(self, state_id):
        if state_id:
            state = self.env['res.country.state'].browse(state_id)
            return {'value': {'country_id': state.country_id.id}}
        return {'value': {}}

    @api.multi
    def on_change_company_type(self, company_type):
        return {'value': {'is_company': company_type == 'company'}}

    def _update_fields_values(self, cr, uid, partner, fields, context=None):
        """ Returns dict of write() values for synchronizing ``fields`` """
        values = {}
        for fname in fields:
            field = self._fields[fname]
            if field.type == 'one2many':
                raise AssertionError(
                    'One2Many fields cannot be synchronized as part of `commercial_fields` or `address fields`'
                )
            if field.type == 'many2one':
                values[fname] = partner[fname].id if partner[fname] else False
            elif field.type == 'many2many':
                values[fname] = [(6, 0, [r.id for r in partner[fname] or []])]
            else:
                values[fname] = partner[fname]
        return values

    def _address_fields(self, cr, uid, context=None):
        """ Returns the list of address fields that are synced from the parent
        when the `use_parent_address` flag is set. """
        return list(ADDRESS_FIELDS)

    def update_address(self, cr, uid, ids, vals, context=None):
        address_fields = self._address_fields(cr, uid, context=context)
        addr_vals = dict(
            (key, vals[key]) for key in address_fields if key in vals)
        if addr_vals:
            return super(res_partner, self).write(cr, uid, ids, addr_vals,
                                                  context)

    def _commercial_fields(self, cr, uid, context=None):
        """ Returns the list of fields that are managed by the commercial entity
        to which a partner belongs. These fields are meant to be hidden on
        partners that aren't `commercial entities` themselves, and will be
        delegated to the parent `commercial entity`. The list is meant to be
        extended by inheriting classes. """
        return ['vat', 'credit_limit']

    def _commercial_sync_from_company(self, cr, uid, partner, context=None):
        """ Handle sync of commercial fields when a new parent commercial entity is set,
        as if they were related fields """
        commercial_partner = partner.commercial_partner_id
        if not commercial_partner:
            # On child partner creation of a parent partner,
            # the commercial_partner_id is not yet computed
            commercial_partner_id = self._commercial_partner_compute(
                cr,
                uid, [partner.id],
                'commercial_partner_id', [],
                context=context)[partner.id]
            commercial_partner = self.browse(cr,
                                             uid,
                                             commercial_partner_id,
                                             context=context)
        if commercial_partner != partner:
            commercial_fields = self._commercial_fields(cr,
                                                        uid,
                                                        context=context)
            sync_vals = self._update_fields_values(cr,
                                                   uid,
                                                   commercial_partner,
                                                   commercial_fields,
                                                   context=context)
            partner.write(sync_vals)

    def _commercial_sync_to_children(self, cr, uid, partner, context=None):
        """ Handle sync of commercial fields to descendants """
        commercial_fields = self._commercial_fields(cr, uid, context=context)
        commercial_partner = partner.commercial_partner_id
        if not commercial_partner:
            # On child partner creation of a parent partner,
            # the commercial_partner_id is not yet computed
            commercial_partner_id = self._commercial_partner_compute(
                cr,
                uid, [partner.id],
                'commercial_partner_id', [],
                context=context)[partner.id]
            commercial_partner = self.browse(cr,
                                             uid,
                                             commercial_partner_id,
                                             context=context)
        sync_vals = self._update_fields_values(cr,
                                               uid,
                                               commercial_partner,
                                               commercial_fields,
                                               context=context)
        sync_children = [c for c in partner.child_ids if not c.is_company]
        for child in sync_children:
            self._commercial_sync_to_children(cr, uid, child, context=context)
        return self.write(cr,
                          uid, [c.id for c in sync_children],
                          sync_vals,
                          context=context)

    def _fields_sync(self, cr, uid, partner, update_values, context=None):
        """ Sync commercial fields and address fields from company and to children after create/update,
        just as if those were all modeled as fields.related to the parent """
        # 1. From UPSTREAM: sync from parent
        if update_values.get('parent_id') or update_values.get(
                'type', 'contact'
        ):  # TDE/ fp change to check, get default value not sure
            # 1a. Commercial fields: sync if parent changed
            if update_values.get('parent_id'):
                self._commercial_sync_from_company(cr,
                                                   uid,
                                                   partner,
                                                   context=context)
            # 1b. Address fields: sync if parent or use_parent changed *and* both are now set
            if partner.parent_id and partner.type == 'contact':
                onchange_vals = self.onchange_parent_id(
                    cr,
                    uid, [partner.id],
                    parent_id=partner.parent_id.id,
                    context=context).get('value', {})
                partner.update_address(onchange_vals)

        # 2. To DOWNSTREAM: sync children
        if partner.child_ids:
            # 2a. Commercial Fields: sync if commercial entity
            if partner.commercial_partner_id == partner:
                commercial_fields = self._commercial_fields(cr,
                                                            uid,
                                                            context=context)
                if any(field in update_values for field in commercial_fields):
                    self._commercial_sync_to_children(cr,
                                                      uid,
                                                      partner,
                                                      context=context)
            # 2b. Address fields: sync if address changed
            address_fields = self._address_fields(cr, uid, context=context)
            if any(field in update_values for field in address_fields):
                domain_children = [('parent_id', '=', partner.id),
                                   ('type', '=', 'contact')]
                update_ids = self.search(cr,
                                         uid,
                                         domain_children,
                                         context=context)
                self.update_address(cr,
                                    uid,
                                    update_ids,
                                    update_values,
                                    context=context)

    def _handle_first_contact_creation(self, cr, uid, partner, context=None):
        """ On creation of first contact for a company (or root) that has no address, assume contact address
        was meant to be company address """
        parent = partner.parent_id
        address_fields = self._address_fields(cr, uid, context=context)
        if parent and (parent.is_company or not parent.parent_id) and len(parent.child_ids) == 1 and \
            any(partner[f] for f in address_fields) and not any(parent[f] for f in address_fields):
            addr_vals = self._update_fields_values(cr,
                                                   uid,
                                                   partner,
                                                   address_fields,
                                                   context=context)
            parent.update_address(addr_vals)

    def _clean_website(self, website):
        (scheme, netloc, path, params, query,
         fragment) = urlparse.urlparse(website)
        if not scheme:
            if not netloc:
                netloc, path = path, ''
            website = urlparse.urlunparse(
                ('http', netloc, path, params, query, fragment))
        return website

    @api.multi
    def write(self, vals):
        # res.partner must only allow to set the company_id of a partner if it
        # is the same as the company of all users that inherit from this partner
        # (this is to allow the code from res_users to write to the partner!) or
        # if setting the company_id to False (this is compatible with any user
        # company)
        if vals.get('website'):
            vals['website'] = self._clean_website(vals['website'])
        if vals.get('company_id'):
            company = self.env['res.company'].browse(vals['company_id'])
            for partner in self:
                if partner.user_ids:
                    companies = set(user.company_id
                                    for user in partner.user_ids)
                    if len(companies) > 1 or company not in companies:
                        raise UserError(
                            _("You can not change the company as the partner/user has multiple user linked with different companies."
                              ))
        # function field implemented by hand -> remove my when migrating
        c_type = vals.get('company_type')
        is_company = vals.get('is_company')
        if c_type:
            vals['is_company'] = c_type == 'company'
        elif 'is_company' in vals:
            vals['company_type'] = is_company and 'company' or 'person'
        tools.image_resize_images(vals)

        result = super(res_partner, self).write(vals)
        for partner in self:
            if any(
                    u.has_group('base.group_user') for u in partner.user_ids
                    if u != self.env.user):
                self.env['res.users'].check_access_rights('write')
            self._fields_sync(partner, vals)
        return result

    @api.model
    def create(self, vals):
        if vals.get('type') in ['delivery', 'invoice'
                                ] and not vals.get('image'):
            # force no colorize for images with no transparency
            vals['image'] = self.with_context(
                partner_type=vals['type'])._get_default_image(False, False)
        if vals.get('website'):
            vals['website'] = self._clean_website(vals['website'])
        # function field not correctly triggered at create -> remove me when
        # migrating to the new API
        c_type = vals.get('company_type',
                          self._context.get('default_company_type'))
        is_company = vals.get('is_company',
                              self._context.get('default_is_company'))
        if c_type:
            vals['is_company'] = c_type == 'company'
        else:
            vals['company_type'] = is_company and 'company' or 'person'
        tools.image_resize_images(vals)
        partner = super(res_partner, self).create(vals)
        self._fields_sync(partner, vals)
        self._handle_first_contact_creation(partner)
        return partner

    def open_commercial_entity(self, cr, uid, ids, context=None):
        """ Utility method used to add an "Open Company" button in partner views """
        partner = self.browse(cr, uid, ids[0], context=context)
        return {
            'type': 'ir.actions.act_window',
            'res_model': 'res.partner',
            'view_mode': 'form',
            'res_id': partner.commercial_partner_id.id,
            'target': 'current',
            'flags': {
                'form': {
                    'action_buttons': True
                }
            }
        }

    def open_parent(self, cr, uid, ids, context=None):
        """ Utility method used to add an "Open Parent" button in partner views """
        partner = self.browse(cr, uid, ids[0], context=context)
        address_form_id = self.pool['ir.model.data'].xmlid_to_res_id(
            cr, uid, 'base.view_partner_address_form')
        return {
            'type': 'ir.actions.act_window',
            'res_model': 'res.partner',
            'view_mode': 'form',
            'views': [(address_form_id, 'form')],
            'res_id': partner.parent_id.id,
            'target': 'new',
            'flags': {
                'form': {
                    'action_buttons': True
                }
            }
        }

    def name_get(self, cr, uid, ids, context=None):
        if context is None:
            context = {}
        if isinstance(ids, (int, long)):
            ids = [ids]
        res = []
        types_dict = dict(
            self.fields_get(cr, uid, context=context)['type']['selection'])
        for record in self.browse(cr, uid, ids, context=context):
            name = record.name or ''
            if record.parent_id and not record.is_company:
                if not name and record.type in [
                        'invoice', 'delivery', 'other'
                ]:
                    name = types_dict[record.type]
                name = "%s, %s" % (record.parent_name, name)
            if context.get('show_address_only'):
                name = self._display_address(cr,
                                             uid,
                                             record,
                                             without_company=True,
                                             context=context)
            if context.get('show_address'):
                name = name + "\n" + self._display_address(
                    cr, uid, record, without_company=True, context=context)
            name = name.replace('\n\n', '\n')
            name = name.replace('\n\n', '\n')
            if context.get('show_email') and record.email:
                name = "%s <%s>" % (name, record.email)
            if context.get('html_format'):
                name = name.replace('\n', '<br/>')
            res.append((record.id, name))
        return res

    def _parse_partner_name(self, text, context=None):
        """ Supported syntax:
            - 'Raoul <*****@*****.**>': will find name and email address
            - otherwise: default, everything is set as the name """
        emails = tools.email_split(text.replace(' ', ','))
        if emails:
            email = emails[0]
            name = text[:text.index(email)].replace('"',
                                                    '').replace('<',
                                                                '').strip()
        else:
            name, email = text, ''
        return name, email

    def name_create(self, cr, uid, name, context=None):
        """ Override of orm's name_create method for partners. The purpose is
            to handle some basic formats to create partners using the
            name_create.
            If only an email address is received and that the regex cannot find
            a name, the name will have the email value.
            If 'force_email' key in context: must find the email address. """
        if context is None:
            context = {}
        name, email = self._parse_partner_name(name, context=context)
        if context.get('force_email') and not email:
            raise UserError(
                _("Couldn't create contact without email address!"))
        if not name and email:
            name = email
        rec_id = self.create(cr,
                             uid, {
                                 self._rec_name: name or email,
                                 'email': email or False
                             },
                             context=context)
        return self.name_get(cr, uid, [rec_id], context)[0]

    def _search(self,
                cr,
                user,
                args,
                offset=0,
                limit=None,
                order=None,
                context=None,
                count=False,
                access_rights_uid=None):
        """ Override search() to always show inactive children when searching via ``child_of`` operator. The ORM will
        always call search() with a simple domain of the form [('parent_id', 'in', [ids])]. """
        # a special ``domain`` is set on the ``child_ids`` o2m to bypass this logic, as it uses similar domain expressions
        if len(args) == 1 and len(args[0]) == 3 and args[0][:2] == ('parent_id','in') \
                and args[0][2] != [False]:
            context = dict(context or {}, active_test=False)
        return super(res_partner,
                     self)._search(cr,
                                   user,
                                   args,
                                   offset=offset,
                                   limit=limit,
                                   order=order,
                                   context=context,
                                   count=count,
                                   access_rights_uid=access_rights_uid)

    def name_search(self,
                    cr,
                    uid,
                    name,
                    args=None,
                    operator='ilike',
                    context=None,
                    limit=100):
        if not args:
            args = []
        if name and operator in ('=', 'ilike', '=ilike', 'like', '=like'):

            self.check_access_rights(cr, uid, 'read')
            where_query = self._where_calc(cr, uid, args, context=context)
            self._apply_ir_rules(cr, uid, where_query, 'read', context=context)
            from_clause, where_clause, where_clause_params = where_query.get_sql(
            )
            where_str = where_clause and (" WHERE %s AND " %
                                          where_clause) or ' WHERE '

            # search on the name of the contacts and of its company
            search_name = name
            if operator in ('ilike', 'like'):
                search_name = '%%%s%%' % name
            if operator in ('=ilike', '=like'):
                operator = operator[1:]

            unaccent = get_unaccent_wrapper(cr)

            query = """SELECT id
                         FROM res_partner
                      {where} ({email} {operator} {percent}
                           OR {display_name} {operator} {percent}
                           OR {reference} {operator} {percent})
                           -- don't panic, trust postgres bitmap
                     ORDER BY {display_name} {operator} {percent} desc,
                              {display_name}
                    """.format(where=where_str,
                               operator=operator,
                               email=unaccent('email'),
                               display_name=unaccent('display_name'),
                               reference=unaccent('ref'),
                               percent=unaccent('%s'))

            where_clause_params += [search_name] * 4
            if limit:
                query += ' limit %s'
                where_clause_params.append(limit)
            cr.execute(query, where_clause_params)
            ids = map(lambda x: x[0], cr.fetchall())

            if ids:
                return self.name_get(cr, uid, ids, context)
            else:
                return []
        return super(res_partner, self).name_search(cr,
                                                    uid,
                                                    name,
                                                    args,
                                                    operator=operator,
                                                    context=context,
                                                    limit=limit)

    def find_or_create(self, cr, uid, email, context=None):
        """ Find a partner with the given ``email`` or use :py:method:`~.name_create`
            to create one

            :param str email: email-like string, which should contain at least one email,
                e.g. ``"Raoul Grosbedon <*****@*****.**>"``"""
        assert email, 'an email is required for find_or_create to work'
        emails = tools.email_split(email)
        if emails:
            email = emails[0]
        ids = self.search(cr,
                          uid, [('email', '=ilike', email)],
                          context=context)
        if not ids:
            return self.name_create(cr, uid, email, context=context)[0]
        return ids[0]

    def _email_send(self,
                    cr,
                    uid,
                    ids,
                    email_from,
                    subject,
                    body,
                    on_error=None):
        partners = self.browse(cr, uid, ids)
        for partner in partners:
            if partner.email:
                tools.email_send(email_from, [partner.email], subject, body,
                                 on_error)
        return True

    def email_send(self, cr, uid, ids, email_from, subject, body, on_error=''):
        while len(ids):
            self.pool['ir.cron'].create(
                cr, uid, {
                    'name': 'Send Partner Emails',
                    'user_id': uid,
                    'model': 'res.partner',
                    'function': '_email_send',
                    'args': repr(
                        [ids[:16], email_from, subject, body, on_error])
                })
            ids = ids[16:]
        return True

    def address_get(self, cr, uid, ids, adr_pref=None, context=None):
        """ Find contacts/addresses of the right type(s) by doing a depth-first-search
        through descendants within company boundaries (stop at entities flagged ``is_company``)
        then continuing the search at the ancestors that are within the same company boundaries.
        Defaults to partners of type ``'default'`` when the exact type is not found, or to the
        provided partner itself if no type ``'default'`` is found either. """
        adr_pref = set(adr_pref or [])
        if 'contact' not in adr_pref:
            adr_pref.add('contact')
        result = {}
        visited = set()
        if isinstance(ids, (int, long)):
            ids = [ids]
        for partner in self.browse(cr, uid, filter(None, ids),
                                   context=context):
            current_partner = partner
            while current_partner:
                to_scan = [current_partner]
                # Scan descendants, DFS
                while to_scan:
                    record = to_scan.pop(0)
                    visited.add(record)
                    if record.type in adr_pref and not result.get(record.type):
                        result[record.type] = record.id
                    if len(result) == len(adr_pref):
                        return result
                    to_scan = [
                        c for c in record.child_ids if c not in visited
                        if not c.is_company
                    ] + to_scan

                # Continue scanning at ancestor if current_partner is not a commercial entity
                if current_partner.is_company or not current_partner.parent_id:
                    break
                current_partner = current_partner.parent_id

        # default to type 'contact' or the partner itself
        default = result.get('contact', ids and ids[0] or False)
        for adr_type in adr_pref:
            result[adr_type] = result.get(adr_type) or default
        return result

    def view_header_get(self, cr, uid, view_id, view_type, context):
        res = super(res_partner, self).view_header_get(cr, uid, view_id,
                                                       view_type, context)
        if res: return res
        if not context.get('category_id', False):
            return False
        return _('Partners: ') + self.pool['res.partner.category'].browse(
            cr, uid, context['category_id'], context).name

    @api.model
    @api.returns('self')
    def main_partner(self):
        ''' Return the main partner '''
        return self.env.ref('base.main_partner')

    def _display_address(self,
                         cr,
                         uid,
                         address,
                         without_company=False,
                         context=None):
        '''
        The purpose of this function is to build and return an address formatted accordingly to the
        standards of the country where it belongs.

        :param address: browse record of the res.partner to format
        :returns: the address formatted in a display that fit its country habits (or the default ones
            if not country is specified)
        :rtype: string
        '''

        # get the information that will be injected into the display format
        # get the address format
        address_format = address.country_id.address_format or \
              "%(street)s\n%(street2)s\n%(city)s %(state_code)s %(zip)s\n%(country_name)s"
        args = {
            'state_code': address.state_id.code or '',
            'state_name': address.state_id.name or '',
            'country_code': address.country_id.code or '',
            'country_name': address.country_id.name or '',
            'company_name': address.parent_name or '',
        }
        for field in self._address_fields(cr, uid, context=context):
            args[field] = getattr(address, field) or ''
        if without_company:
            args['company_name'] = ''
        elif address.parent_id:
            address_format = '%(company_name)s\n' + address_format
        return address_format % args