class RetailMachine(geo_model.GeoModel):
    """GEO OSV SAMPLE"""

    _name = "geoengine.demo.automatic.retailing.machine"

    the_point = geo_fields.GeoPoint('Coordinate')
    the_line = geo_fields.GeoLine('Power supply line', index=True)
    total_sales = fields.Float('Total sale', index=True)
    money_level = fields.Char('Money level', size=32, index=True)
    state = fields.Selection([('hs', 'HS'),
                              ('ok', 'OK')],
                             'State',
                             index=True)
    name = fields.Char('Serial number', size=64, required=True)
    zip_id = fields.Many2one('dummy.zip')

    @api.onchange('the_point')
    def onchange_geo_point(self):
        """ Exemple of on change on the point
        Lookup in zips if the code is within an area.
        Change the zip_id field accordingly
        """
        if self.the_point:
            zip_match = self.env['dummy.zip'].geo_search(
                geo_domain=[('the_geom', 'geo_contains', self.the_point)],
                limit=1
            )
            if zip_match:
                self.zip_id = zip_match[0]
Beispiel #2
0
class ProjectProject(geo_model.GeoModel):
    """Add geo_point to project.project"""

    _inherit = 'project.project'

    geo_point = fields.GeoPoint('Addresses coordinate',
                                related='partner_id.geo_point')
Beispiel #3
0
class ResPartner(geo_model.GeoModel):
    """Add geo_point to partner using a function field"""
    _inherit = "res.partner"

    @api.one
    def geocode_address(self):
        """Get the latitude and longitude by requesting "mapquestapi"
        see http://open.mapquestapi.com/geocoding/
        """
        url = 'http://nominatim.openstreetmap.org/search'
        pay_load = {
            'limit': 1,
            'format': 'json',
            'street': self.street or '',
            'postalCode': self.zip or '',
            'city': self.city or '',
            'state':  self.state_id and self.state_id.name or '',
            'country': self.country_id and self.country_id.name or '',
            'countryCodes': self.country_id and self.country_id.code or ''}

        request_result = requests.get(url, params=pay_load)
        try:
            request_result.raise_for_status()
        except Exception as e:
            _logger.exception('Geocoding error')
            raise exceptions.Warning(_(
                'Geocoding error. \n %s') % e.message)
        vals = request_result.json()
        vals = vals and vals[0] or {}
        self.write({
            'partner_latitude': vals.get('lat'),
            'partner_longitude': vals.get('lon'),
            'date_localization': fields.Date.today()})

    @api.one
    def geo_localize(self):
        self.geocode_address()
        return True

    @api.one
    @api.depends('partner_latitude', 'partner_longitude')
    def _get_geo_point(self):
        """
        Set the `geo_point` of the partner depending of its `partner_latitude`
        and its `partner_longitude`
        **Notes**
        If one of those parameters is not set then reset the partner's
        geo_point and do not recompute it
        """
        if not self.partner_latitude or not self.partner_longitude:
            self.geo_point = False
        else:
            self.geo_point = geo_fields.GeoPoint.from_latlon(
                self.env.cr, self.partner_latitude, self.partner_longitude)

    geo_point = geo_fields.GeoPoint(
        readonly=True, store=True, compute='_get_geo_point')
Beispiel #4
0
class company(geo_model.GeoModel):
    _name = 'bedit_ecoles.company'
    _order = 'name asc'
    _description = 'Company'

    name = fields.Char(string='Name', required=True)
    address = fields.Char(string='Address', required=False)
    polnum = fields.Char(string='Polnum', required=False)
    the_geom = geo_fields.GeoPoint(required=True, srid=31370, gist_index=True)
    postcode_id = fields.Many2one('bedit_ecoles.postcode', string="Postcode")
    municipality_id = fields.Many2one('bedit_ecoles.municipality',
                                      string="Municipality")
Beispiel #5
0
class activity(geo_model.GeoModel):
    _name = 'bedit_ecoles.activity'
    _order = 'name asc'
    _description = 'Activity'

    description = fields.Char(string='Description', size=50)

    @api.model
    def _year_between(self):
        years = []
        year_min = 2010
        year_max = (date.today().year) + 1
        for x in range(year_min, year_max):
            years.append((str(x), str(x)))
        return years

    def _get_this_year(self):
        return str(date.today().year)

    year = fields.Selection('_year_between',
                            string="Year",
                            default=lambda self: self._get_this_year(),
                            required=True)  #TODO add min/max val
    school_id = fields.Many2one('bedit_ecoles.school',
                                string="School",
                                required=True)
    company_id = fields.Many2one('bedit_ecoles.company',
                                 string="Company",
                                 required=True)
    number = fields.Integer(string='Number of participant')

    @api.depends('school_id', 'company_id', 'year')
    def _get_name(self):
        for record in self:
            name = ''
            if (record.year and record.school_id and record.company_id):
                name = '%s / %s (%s)' % (record.school_id.name,
                                         record.company_id.name, record.year)
            record.name = name

    name = fields.Char(compute='_get_name')

    school_name = fields.Char(related='school_id.name', store=False)
    school_muni = fields.Char(related='school_id.municipality_id.name',
                              store=False)
    school_adr = fields.Char(related='school_id.address', store=False)
    school_type = fields.Char(related='school_id.stype_id.name', store=False)

    the_geom = geo_fields.GeoPoint(related='school_id.the_geom', store=False)
Beispiel #6
0
        class DummyModel(GeoModel):
            _name = 'test.dummy'

            name = fields.Char(string="Zip", size=64, required=True)
            the_geom = geo_fields.GeoMultiPolygon(string="NPA Shape")
            geo_point = geo_fields.GeoPoint(string="Point")
Beispiel #7
0
class ResPartner(geo_model.GeoModel):
    """Auto geo coding of addresses"""
    _inherit = "res.partner"

    geo_point = fields.GeoPoint('Addresses coordinate', readonly=True)

    def _can_geocode(self):
        usr = self.env['res.users']
        return usr.browse(self.env.uid).company_id.enable_geocoding

    def _get_point_from_reply(self, answer):
        """Parse geoname answer code inspired by geopy library"""
        def get_first_text(node, tag_names, strip=None):
            """Get the text value of the first child of ``node`` with tag
            ``tag_name``. The text is stripped using the value of ``strip``."""
            if isinstance(tag_names, basestring):
                tag_names = [tag_names]
            if node:
                while tag_names:
                    nodes = node.getElementsByTagName(tag_names.pop(0))
                    if nodes:
                        child = nodes[0].firstChild
                        return child and child.nodeValue.strip(strip)

        def parse_code(code):
            latitude = get_first_text(code, 'lat') or None
            longitude = get_first_text(code, 'lng') or None
            latitude = latitude and float(latitude)
            longitude = longitude and float(longitude)
            return latitude, longitude

        res = answer.read()
        if not isinstance(res, basestring):
            return False
        doc = xml.dom.minidom.parseString(res)
        codes = doc.getElementsByTagName('code')
        if len(codes) < 1:
            return False
        latitude, longitude = parse_code(codes[0])
        return fields.GeoPoint.from_latlon(self.env.cr, latitude, longitude)

    @api.multi
    def geocode_from_geonames(self, srid='900913', strict=True, context=None):
        context = context or {}
        base_url = u'http://ws.geonames.org/postalCodeSearch?'
        config_parameter_obj = self.env['ir.config_parameter']
        username = config_parameter_obj.get_param(
            'geoengine_geonames_username')
        if not username:
            raise ValidationError(
                _('A username is required to access '
                  'http://ws.geonames.org/ \n'
                  'Please provides a valid one by setting a '
                  'value in System Paramter for the key '
                  '"geoengine_geonames_username"'))
        filters = {}
        for add in self:
            logger.info('geolocalize %s', add.name)
            if add.country_id.code and (add.city or add.zip):
                filters[u'country'] = add.country_id.code.encode('utf-8')
                filters[u'username'] = username.encode('utf-8')
                if add.city:
                    filters[u'placename'] = add.city.encode('utf-8')
                if add.zip:
                    filters[u'postalcode'] = add.zip.encode('utf-8')
                filters[u'maxRows'] = u'1'
                try:
                    url = base_url + urlencode(filters)
                    answer = urlopen(url)
                    add.geo_point = self._get_point_from_reply(answer)
                except Exception, exc:
                    logger.exception('error while updating geocodes')
                    if strict:
                        raise except_orm(_('Geoencoding fails'), str(exc))
Beispiel #8
0
class TmsPlace(geo_model.GeoModel):
    _name = 'tms.place'
    _description = 'Cities / Places'

    name = fields.Char('Place', size=64, required=True, index=True)
    complete_name = fields.Char(compute='_compute_complete_name')
    state_id = fields.Many2one('res.country.state', string='State Name')
    country_id = fields.Many2one('res.country',
                                 related='state_id.country_id',
                                 string='Country')
    latitude = fields.Float(required=False,
                            digits=(20, 10),
                            help='GPS Latitude')
    longitude = fields.Float(required=False,
                             digits=(20, 10),
                             help='GPS Longitude')
    point = geo_fields.GeoPoint(
        string='Coordinate',
        compute='_compute_point',
        inverse='_set_lat_long',
    )

    @api.multi
    def get_coordinates(self):
        for rec in self:
            address = (rec.name + "," + rec.state_id.name + "," +
                       rec.country_id.name)
            google_url = ('http://maps.googleapis.com/maps/api/geocode/json?' +
                          'address=' + address.encode('utf-8') +
                          '&sensor=false')
            try:
                result = json.load(my_urllib.urlopen(google_url))
                if result['status'] == 'OK':
                    location = result['results'][0]['geometry']['location']
                    self.latitude = location['lat']
                    self.longitude = location['lng']
            except:
                raise UserError(_("Google Maps is not available."))

    @api.multi
    def open_in_google(self):
        for place in self:
            url = ("/tms/static/src/googlemaps/get_place_from_coords.html?" +
                   str(place.latitude) + ',' + str(place.longitude))
        return {
            'type': 'ir.actions.act_url',
            'url': url,
            'nodestroy': True,
            'target': 'new'
        }

    @api.depends('name', 'state_id')
    def _compute_complete_name(self):
        for rec in self:
            if rec.state_id:
                rec.complete_name = rec.name + ', ' + rec.state_id.name
            else:
                rec.complete_name = rec.name

    @api.depends('latitude', 'longitude')
    def _compute_point(self):
        for rec in self:
            rec.point = geo_fields.GeoPoint.from_latlon(
                self.env.cr, rec.latitude, rec.longitude).wkb_hex

    def set_lang_long(self):
        point_x, point_y = geojson.loads(self.point).coordinates
        inproj = Proj(init='epsg:3857')
        outproj = Proj(init='epsg:4326')
        longitude, latitude = transform(inproj, outproj, point_x, point_y)
        self.latitude = latitude
        self.longitude = longitude

    @api.onchange('point')
    def onchange_geo_point(self):
        if self.point:
            self.set_lang_long()

    @api.depends('point')
    def _set_lat_long(self):
        for rec in self:
            rec.set_lang_long()
Beispiel #9
0
class FSMLocation(geo_model.GeoModel):
    _name = 'fsm.location'
    _inherits = {'res.partner': 'partner_id'}
    _description = 'Field Service Location'

    @api.model
    def _tz_get(self):
        return [(tz, tz)
                for tz in sorted(pytz.all_timezones,
                                 key=lambda tz: tz
                                 if not tz.startswith('Etc/') else '_')]

    ref = fields.Char(string='Internal Reference')
    direction = fields.Char(string='Directions')
    partner_id = fields.Many2one('res.partner',
                                 string='Related Partner',
                                 required=True,
                                 ondelete='restrict',
                                 delegate=True,
                                 auto_join=True)
    owner_id = fields.Many2one('res.partner',
                               string='Related Owner',
                               required=True,
                               ondelete='restrict',
                               auto_join=True)
    customer_id = fields.Many2one('res.partner',
                                  string='Billed Customer',
                                  required=True,
                                  ondelete='restrict',
                                  auto_join=True)
    contact_id = fields.Many2one('res.partner',
                                 string='Primary Contact',
                                 domain="[('is_company', '=', False),"
                                 " ('fsm_location', '=', False)]",
                                 index=True)
    tag_ids = fields.Many2many('fsm.tag', string='Tags')
    description = fields.Char(string='Description')
    territory_id = fields.Many2one('fsm.territory', string='Territory')
    branch_id = fields.Many2one('fsm.branch', string='Branch')
    district_id = fields.Many2one('fsm.district', string='District')
    region_id = fields.Many2one('fsm.region', string='Region')
    territory_manager_id = fields.Many2one(string='Primary Assignment',
                                           related='territory_id.person_id')
    district_manager_id = fields.Many2one(string='District Manager',
                                          related='district_id.partner_id')
    region_manager_id = fields.Many2one(string='Region Manager',
                                        related='region_id.partner_id')
    branch_manager_id = fields.Many2one(string='Branch Manager',
                                        related='branch_id.partner_id')

    timezone = fields.Selection(_tz_get, string='Timezone')

    parent_id = fields.Many2one('fsm.location', string='Parent')
    notes = fields.Text(string="Notes")
    person_ids = fields.Many2many('fsm.person',
                                  'partner_id',
                                  string='Preferred Workers')

    # Geometry Field
    shape = geo_fields.GeoPoint(string='Coordinate')

    _sql_constraints = [('fsm_location_ref_uniq', 'unique (ref)',
                         'This internal reference already exists!')]

    @api.model
    def create(self, vals):
        vals.update({'fsm_location': True})
        return super(FSMLocation, self).create(vals)

    @api.onchange('territory_id')
    def _onchange_territory_id(self):
        if self.territory_id:
            # assign manager
            self.territory_manager_id = self.territory_id.person_id
            # get territory preffered person list if available
            self.person_ids = self.territory_id.person_ids
            if self.territory_id.branch_id:
                self.branch_id = self.territory_id.branch_id
                self.branch_manager_id = self.territory_id.branch_id.partner_id

    @api.onchange('branch_id')
    def _onchange_branch_id(self):
        if self.branch_id and self.branch_id.district_id:
            self.district_id = self.branch_id.district_id
            self.district_manager_id = self.branch_id.district_id.partner_id

    @api.onchange('district_id')
    def _onchange_district_id(self):
        if self.district_id and self.district_id.region_id:
            self.region_id = self.district_id.region_id
            self.region_manager_id = self.district_id.region_id.partner_id

    @api.multi
    def name_get(self):
        return [
            (location.id, '%s%s' %
             (location.ref and '[%s] ' % location.ref or '', location.name))
            for location in self
        ]
Beispiel #10
0
class FSMOrder(geo_model.GeoModel):
    _name = 'fsm.order'
    _description = 'Field Service Order'
    _inherit = ['mail.thread', 'mail.activity.mixin']

    def _default_stage_id(self):
        return self.env.ref('fieldservice.fsm_stage_new')

    stage_id = fields.Many2one('fsm.stage',
                               string='Stage',
                               track_visibility='onchange',
                               index=True,
                               group_expand='_read_group_stage_ids',
                               default=lambda self: self._default_stage_id())
    priority = fields.Selection(fsm_stage.AVAILABLE_PRIORITIES,
                                string='Priority',
                                index=True,
                                default=fsm_stage.AVAILABLE_PRIORITIES[0][0])
    tag_ids = fields.Many2many('fsm.tag',
                               'fsm_order_tag_rel',
                               'fsm_order_id',
                               'tag_id',
                               string='Tags',
                               help="Classify and analyze your orders")
    color = fields.Integer('Color Index', default=0)

    # Request
    name = fields.Char(string='Name',
                       required=True,
                       default=lambda self: _('New'))
    customer_id = fields.Many2one('res.partner',
                                  string='Customer',
                                  domain=[('customer', '=', True)],
                                  change_default=True,
                                  index=True,
                                  track_visibility='always')
    location_id = fields.Many2one('fsm.location',
                                  string='Location',
                                  index=True)
    request_early = fields.Datetime(string='Earliest Request Date')
    request_late = fields.Datetime(string='Latest Request Date')

    description = fields.Text(string='Description')

    person_ids = fields.Many2many('fsm.person', string='Field Service Workers')

    # Planning
    person_id = fields.Many2one('fsm.person', string='Assigned To', index=True)
    route_id = fields.Many2one('fsm.route', string='Route', index=True)
    scheduled_date_start = fields.Datetime(string='Scheduled Start (ETA)')
    scheduled_duration = fields.Float(string='Duration in hours',
                                      help='Scheduled duration of the work in'
                                      ' hours')
    scheduled_date_end = fields.Datetime(string="Scheduled End")
    sequence = fields.Integer(string='Sequence', default=10)
    todo = fields.Text(string='Instructions')

    # Execution
    log = fields.Text(string='Log')
    date_start = fields.Datetime(string='Actual Start')
    date_end = fields.Datetime(string='Actual End')

    # Location
    branch_id = fields.Many2one('fsm.branch', string='Branch')
    district_id = fields.Many2one('fsm.district', string='District')
    region_id = fields.Many2one('fsm.region', string='Region')

    # Geometry Field
    shape = geo_fields.GeoPoint(string='Coordinate')

    # Fields for Geoengine Identify
    display_name = fields.Char(related="location_id.display_name",
                               string="Location")
    street = fields.Char(related="location_id.street")
    street2 = fields.Char(related="location_id.street2")
    zip = fields.Char(related="location_id.zip")
    city = fields.Char(related="location_id.city")
    state_name = fields.Char(related="location_id.state_id.name",
                             string='State',
                             ondelete='restrict')
    country_name = fields.Char(related="location_id.country_id.name",
                               string='Country',
                               ondelete='restrict')
    phone = fields.Char(related="location_id.phone")
    mobile = fields.Char(related="location_id.mobile")

    stage_name = fields.Char(related="stage_id.name", string="Stage")

    # Template
    template_id = fields.Many2one('fsm.template', string="Template")
    category_ids = fields.Many2many('fsm.category', string="Categories")

    @api.model
    def _read_group_stage_ids(self, stages, domain, order):
        stage_ids = self.env['fsm.stage'].search([])
        return stage_ids

    @api.model
    def create(self, vals):
        if vals.get('name', _('New')) == _('New'):
            vals['name'] = self.env['ir.sequence'].next_by_code('fsm.order') \
                or _('New')
        return super(FSMOrder, self).create(vals)

    @api.multi
    def write(self, vals):
        if 'scheduled_date_end' in vals:
            date_to_with_delta = fields.Datetime.from_string(
                vals.get('scheduled_date_end')) -\
                timedelta(hours=self.scheduled_duration)
            vals['scheduled_date_start'] = str(date_to_with_delta)
        if 'scheduled_duration' in vals:
            date_to_with_delta = fields.Datetime.from_string(
                vals.get('scheduled_date_start', self.scheduled_date_start)) +\
                timedelta(hours=vals.get('scheduled_duration'))
            vals['scheduled_date_end'] = str(date_to_with_delta)
        if 'scheduled_date_end' not in vals and 'scheduled_date_start' in vals:
            date_to_with_delta = fields.Datetime.from_string(
                vals.get('scheduled_date_start')) +\
                timedelta(hours=self.scheduled_duration)
            vals['scheduled_date_end'] = str(date_to_with_delta)
        return super(FSMOrder, self).write(vals)

    def action_confirm(self):
        return self.write(
            {'stage_id': self.env.ref('fieldservice.fsm_stage_confirmed').id})

    def action_schedule(self):
        return self.write(
            {'stage_id': self.env.ref('fieldservice.fsm_stage_scheduled').id})

    def action_assign(self):
        return self.write(
            {'stage_id': self.env.ref('fieldservice.fsm_stage_assigned').id})

    def action_plan(self):
        return self.write(
            {'stage_id': self.env.ref('fieldservice.fsm_stage_planned').id})

    def action_enroute(self):
        return self.write(
            {'stage_id': self.env.ref('fieldservice.fsm_stage_enroute').id})

    def action_start(self):
        return self.write(
            {'stage_id': self.env.ref('fieldservice.fsm_stage_started').id})

    def action_complete(self):
        return self.write(
            {'stage_id': self.env.ref('fieldservice.fsm_stage_completed').id})

    def action_cancel(self):
        return self.write(
            {'stage_id': self.env.ref('fieldservice.fsm_stage_cancelled').id})

    @api.onchange('scheduled_date_start')
    def onchange_scheduled_date_start(self):
        if self.person_id and self.scheduled_date_start:
            print(self.person_id)
            print(self.person_id)
            print("person")
            # self.stage_id = 'Planned'
            self.stage_id = 5
        elif not self.person_id and self.scheduled_date_start:
            print("hello")
            # self.stage_id = 'Scheduled'
            self.stage_id = 3

    @api.onchange('person_id')
    def onchange_person_id(self):
        if self.person_id and self.scheduled_date_start:
            print(self.scheduled_date_start)
            print("date")
            # self.stage_id = 'Planned'
            self.stage_id = 5
        elif self.person_id and not self.scheduled_date_start:
            print("hello")
            # self.stage_id = 'Assigned'
            self.stage_id = 4

    @api.onchange('scheduled_date_end')
    def onchange_scheduled_date_end(self):
        if self.scheduled_date_end:
            date_to_with_delta = fields.Datetime.from_string(
                self.scheduled_date_end) -\
                timedelta(hours=self.scheduled_duration)
            self.date_start = str(date_to_with_delta)

    @api.onchange('scheduled_duration')
    def onchange_scheduled_duration(self):
        if self.scheduled_duration:
            date_to_with_delta = fields.Datetime.from_string(
                self.scheduled_date_start) +\
                timedelta(hours=self.scheduled_duration)
            self.scheduled_date_end = str(date_to_with_delta)

    @api.onchange('location_id')
    def onchange_location_id(self):
        if self.location_id:
            self.branch_id = self.location_id.branch_id or False
            self.district_id = self.location_id.district_id or False
            self.region_id = self.location_id.region_id or False

    @api.onchange('template_id')
    def _onchange_template_id(self):
        if self.template_id:
            self.category_ids = self.template_id.category_ids

    def geo_localize(self):
        for order in self:
            if order.location_id.partner_id:
                order.location_id.partner_id.geo_localize()
            lat = order.location_id.partner_latitude
            lng = order.location_id.partner_longitude
            point = geo_fields.GeoPoint.from_latlon(cr=order.env.cr,
                                                    latitude=lat,
                                                    longitude=lng)
            order.shape = point
Beispiel #11
0
class FSMOrder(geo_model.GeoModel):
    _name = 'fsm.order'
    _description = 'Field Service Order'
    _inherit = ['mail.thread', 'mail.activity.mixin']

    def _default_stage_id(self):
        return self.env.ref('fieldservice.fsm_stage_new')

    def _default_team_id(self):
        return self.env.ref('fieldservice.fsm_team_default')

    @api.depends('date_start', 'date_end')
    def _compute_duration(self):
        if self.date_start and self.date_end:
            start = fields.Datetime.from_string(self.date_start)
            end = fields.Datetime.from_string(self.date_end)
            delta = end - start
            self.duration = delta.total_seconds() / 3600

    @api.depends('stage_id')
    def _get_stage_color(self):
        """ Get stage color"""
        self.custom_color = self.stage_id.custom_color or '#FFFFFF'

    stage_id = fields.Many2one('fsm.stage',
                               string='Stage',
                               track_visibility='onchange',
                               index=True,
                               copy=False,
                               group_expand='_read_group_stage_ids',
                               default=lambda self: self._default_stage_id())
    priority = fields.Selection(fsm_stage.AVAILABLE_PRIORITIES,
                                string='Priority',
                                index=True,
                                default=fsm_stage.AVAILABLE_PRIORITIES[0][0])
    tag_ids = fields.Many2many('fsm.tag',
                               'fsm_order_tag_rel',
                               'fsm_order_id',
                               'tag_id',
                               string='Tags',
                               help="Classify and analyze your orders")
    color = fields.Integer('Color Index', default=0)
    team_id = fields.Many2one('fsm.team',
                              string='Team',
                              default=_default_team_id,
                              index=True,
                              required=True,
                              track_visibility='onchange')

    # Request
    name = fields.Char(string='Name',
                       required=True,
                       index=True,
                       copy=False,
                       default=lambda self: _('New'))
    customer_id = fields.Many2one('res.partner',
                                  string='Contact',
                                  domain=[('customer', '=', True)],
                                  change_default=True,
                                  index=True,
                                  track_visibility='always')
    location_id = fields.Many2one('fsm.location',
                                  string='Location',
                                  index=True,
                                  required=True)
    request_early = fields.Datetime(string='Earliest Request Date',
                                    default=datetime.now())
    request_late = fields.Datetime(string='Latest Request Date',
                                   compute='_compute_request_late')

    def _compute_request_late(self):
        if not self.request_late:
            if self.priority == '0':
                if self.request_early:
                    self.request_late = fields.Datetime.from_string(
                        self.request_early) + timedelta(days=3)
                else:
                    self.request_late = datetime.now() + timedelta(days=3)
            elif self.priority == '1':
                self.request_late = fields.Datetime.from_string(
                    self.request_early) + timedelta(days=2)
            elif self.priority == '2':
                self.request_late = fields.Datetime.from_string(
                    self.request_early) + timedelta(days=1)
            elif self.priority == '3':
                self.request_late = fields.Datetime.from_string(
                    self.request_early) + timedelta(hours=8)

    description = fields.Text(string='Description')

    person_ids = fields.Many2many('fsm.person', string='Field Service Workers')

    @api.onchange('location_id')
    def _onchange_location_id_customer(self):
        if self.location_id:
            return {
                'domain': {
                    'customer_id':
                    [('service_location_id', '=', self.location_id.name)]
                }
            }
        else:
            return {'domain': {'customer_id': [('id', '!=', None)]}}

    @api.onchange('customer_id')
    def _onchange_customer_id_location(self):
        if self.customer_id:
            self.location_id = self.customer_id.service_location_id

    # Planning
    person_id = fields.Many2one('fsm.person', string='Assigned To', index=True)
    route_id = fields.Many2one('fsm.route', string='Route', index=True)
    scheduled_date_start = fields.Datetime(string='Scheduled Start (ETA)')
    scheduled_duration = fields.Float(string='Scheduled duration',
                                      help='Scheduled duration of the work in'
                                      ' hours')
    scheduled_date_end = fields.Datetime(string="Scheduled End")
    sequence = fields.Integer(string='Sequence', default=10)
    todo = fields.Text(string='Instructions')

    # Execution
    resolution = fields.Text(string='Resolution',
                             placeholder="Resolution of the order")
    date_start = fields.Datetime(string='Actual Start')
    date_end = fields.Datetime(string='Actual End')
    duration = fields.Float(string='Actual duration',
                            compute=_compute_duration,
                            help='Actual duration in hours')

    # Location
    branch_id = fields.Many2one('fsm.branch', string='Branch')
    district_id = fields.Many2one('fsm.district', string='District')
    region_id = fields.Many2one('fsm.region', string='Region')

    # Geometry Field
    shape = geo_fields.GeoPoint(string='Coordinate')

    # Fields for Geoengine Identify
    display_name = fields.Char(related="name", string="Order")
    street = fields.Char(related="location_id.street")
    street2 = fields.Char(related="location_id.street2")
    zip = fields.Char(related="location_id.zip")
    city = fields.Char(related="location_id.city")
    state_name = fields.Char(related="location_id.state_id.name",
                             string='State',
                             ondelete='restrict')
    country_name = fields.Char(related="location_id.country_id.name",
                               string='Country',
                               ondelete='restrict')
    phone = fields.Char(related="location_id.phone")
    mobile = fields.Char(related="location_id.mobile")

    stage_name = fields.Char(related="stage_id.name", string="Stage")
    # Field for Stage Color
    custom_color = fields.Char(related="stage_id.custom_color",
                               string='Stage Color')

    # Template
    template_id = fields.Many2one('fsm.template', string="Template")
    category_ids = fields.Many2many('fsm.category', string="Categories")

    # Equipment
    equipment_id = fields.Many2one('fsm.equipment', string='Equipment')
    type = fields.Selection([], string='Type')

    @api.model
    def _read_group_stage_ids(self, stages, domain, order):
        stage_ids = self.env['fsm.stage'].search([('stage_type', '=', 'order')
                                                  ])
        return stage_ids

    @api.model
    def create(self, vals):
        if vals.get('name', _('New')) == _('New'):
            vals['name'] = self.env['ir.sequence'].next_by_code('fsm.order') \
                or _('New')
        if vals['request_early'] is not False and\
                vals['scheduled_date_start'] is False:
            req_date = fields.Datetime.from_string(vals['request_early'])
            # Round scheduled date start
            req_date = req_date.replace(minute=0, second=0)
            vals.update({
                'scheduled_date_start': str(req_date),
                'request_early': str(req_date)
            })
        res = super(FSMOrder, self).create(vals)
        res.create_geometry()
        return res

    @api.multi
    def write(self, vals):
        if 'scheduled_date_end' in vals:
            date_to_with_delta = fields.Datetime.from_string(
                vals.get('scheduled_date_end')) - \
                timedelta(hours=self.scheduled_duration)
            vals['scheduled_date_start'] = str(date_to_with_delta)
        if 'scheduled_duration' in vals:
            date_to_with_delta = fields.Datetime.from_string(
                vals.get('scheduled_date_start', self.scheduled_date_start))\
                + timedelta(hours=vals.get('scheduled_duration'))
            vals['scheduled_date_end'] = str(date_to_with_delta)
        if 'scheduled_date_end' not in vals and 'scheduled_date_start' in vals:
            date_to_with_delta = fields.Datetime.from_string(
                vals.get('scheduled_date_start')) + \
                timedelta(hours=self.scheduled_duration)
            vals['scheduled_date_end'] = str(date_to_with_delta)
        if 'customer_id' not in vals:
            vals['customer_id'] = self.location_id.customer_id.id
        return super(FSMOrder, self).write(vals)

    def action_confirm(self):
        return self.write(
            {'stage_id': self.env.ref('fieldservice.fsm_stage_confirmed').id})

    def action_request(self):
        return self.write(
            {'stage_id': self.env.ref('fieldservice.fsm_stage_requested').id})

    def action_assign(self):
        if self.person_id:
            return self.write({
                'stage_id':
                self.env.ref('fieldservice.fsm_stage_assigned').id
            })
        else:
            raise ValidationError(
                _("Cannot move to Assigned " +
                  "until 'Assigned To' is filled in"))

    def action_schedule(self):
        return self.write(
            {'stage_id': self.env.ref('fieldservice.fsm_stage_scheduled').id})

    def action_enroute(self):
        return self.write(
            {'stage_id': self.env.ref('fieldservice.fsm_stage_enroute').id})

    def action_start(self):
        return self.write(
            {'stage_id': self.env.ref('fieldservice.fsm_stage_started').id})

    def action_complete(self):
        return self.write(
            {'stage_id': self.env.ref('fieldservice.fsm_stage_completed').id})

    def action_cancel(self):
        return self.write(
            {'stage_id': self.env.ref('fieldservice.fsm_stage_cancelled').id})

    @api.onchange('scheduled_date_end')
    def onchange_scheduled_date_end(self):
        if self.scheduled_date_end:
            date_to_with_delta = fields.Datetime.from_string(
                self.scheduled_date_end) - \
                timedelta(hours=self.scheduled_duration)
            self.date_start = str(date_to_with_delta)

    @api.onchange('scheduled_duration')
    def onchange_scheduled_duration(self):
        if (self.scheduled_duration and self.scheduled_date_start):
            date_to_with_delta = fields.Datetime.from_string(
                self.scheduled_date_start) + \
                timedelta(hours=self.scheduled_duration)
            self.scheduled_date_end = str(date_to_with_delta)

    def copy_notes(self):
        self.description = ""
        if self.equipment_id:
            if self.equipment_id.notes is not False:
                if self.description is not False:
                    self.description = (self.description +
                                        self.equipment_id.notes + '\n ')
                else:
                    self.description = (self.equipment_id.notes + '\n ')
        if self.location_id:
            if self.location_id.direction is not False:
                if self.description is not False:
                    self.description = (self.description +
                                        self.location_id.direction + '\n ')
                else:
                    self.description = (self.location_id.direction + '\n ')

    @api.onchange('location_id')
    def onchange_location_id(self):
        if self.location_id:
            self.branch_id = self.location_id.branch_id or False
            self.district_id = self.location_id.district_id or False
            self.region_id = self.location_id.region_id or False
            self.create_geometry()
            self.copy_notes()

    @api.onchange('equipment_id')
    def onchange_equipment_id(self):
        self.copy_notes()

    @api.onchange('template_id')
    def _onchange_template_id(self):
        if self.template_id:
            self.category_ids = self.template_id.category_ids
            self.scheduled_duration = self.template_id.hours
            self.todo = (self.todo or '') + \
                        ('<p>' + self.template_id.instructions or '' + '</p>')

    def create_geometry(self):
        for order in self:
            lat = order.location_id.partner_latitude
            lng = order.location_id.partner_longitude
            point = geo_fields.GeoPoint.from_latlon(cr=order.env.cr,
                                                    latitude=lat,
                                                    longitude=lng)
            order.shape = point
Beispiel #12
0
class SaleOrder(geo_model.GeoModel):
    """Add geo_point to sale.order"""
    _inherit = "sale.order"

    geo_point = fields.GeoPoint('Addresses coordinate',
                                related='partner_invoice_id.geo_point')
class AdvocateDetails(models.Model, geo_model.GeoModel):
    _name = "advocate.details"
    _description = "Advocate Details"
    _rec_name = "partner_id"
    _inherit = "mail.thread"

    partner_id = fields.Many2one(
        'res.partner', 'Partner', required=True, ondelete='cascade')
    description = fields.Text(translate=False)
    quote = fields.Text(translate=False)
    picture_large = fields.Binary(
        string='Large picture', attachment=True,
        help='Optional large picture for your profile page'
    )
    picture_filename = fields.Char(compute='_compute_filename')
    thank_you_quote = fields.Html(
        compute='_compute_thank_you_quote',
        help='Used in thank you letters for donations linked to an event '
             'and to this partner.',
    )
    mail_copy_when_donation = fields.Boolean()
    number_surveys = fields.Integer(related='partner_id.survey_input_count')

    # Advocacy fields
    #################
    active_since = fields.Date()
    end_date = fields.Date()
    last_event = fields.Date(compute='_compute_events')
    state = fields.Selection([
        ('new', 'New advocate'),
        ('active', 'Active'),
        ('on_break', 'On break'),
        ('inactive', 'Inactive'),
    ], default='new', required=True, track_visibility='onchange')
    break_end = fields.Date()
    advocacy_source = fields.Text(
        help='Describe how this advocate has partnered with us.'
    )
    has_car = fields.Selection('_yes_no_selection', 'Has a car')
    formation_ids = fields.Many2many(
        'calendar.event', string='Formation taken',
        compute='_compute_formation', inverse='_inverse_formation',
        groups="base.group_user"
    )
    engagement_ids = fields.Many2many(
        'advocate.engagement', 'advocate_engagement_rel',
        'advocate_details_id', 'engagement_id', 'Engagement type'
    )
    t_shirt_size = fields.Selection([
        ('S', 'S'), ('M', 'M'), ('L', 'L'), ('XL', 'XL'),
        ('XXL', 'XXL')
    ])
    t_shirt_type = fields.Selection([
        ('shirt', 'Shirt'),
        ('bikeshirt', 'Bikeshirt'),
    ])
    event_ids = fields.Many2many(
        'crm.event.compassion', string='Events', compute='_compute_events'
    )
    event_type_formation = fields.Integer(compute='_compute_formation')
    number_events = fields.Integer(compute='_compute_events')

    # Partner related fields
    ########################
    birthdate = fields.Date(
        related='partner_id.birthdate_date', store=True, readonly=True)
    lang = fields.Selection(
        related='partner_id.lang', store=True, readonly=True)
    zip = fields.Char(
        related='partner_id.zip', store=True, readonly=True)
    city = fields.Char(
        related='partner_id.city', store=True, readonly=True)
    email = fields.Char(
        related='partner_id.email', store=True, readonly=True)
    geo_point = geo_fields.GeoPoint(readonly=True)

    _sql_constraints = [
        ('details_unique', 'unique(partner_id)',
         'Only one details per ambassador is allowed!')
    ]

    @api.model
    def _yes_no_selection(self):
        return [
            ('yes', 'Yes'),
            ('no', 'No')
        ]

    @api.multi
    def _compute_filename(self):
        for details in self:
            partner_name = details.display_name
            details.picture_filename = partner_name + '-large.jpg'

    @api.multi
    def _compute_thank_you_quote(self):
        html_file = file_open(
            'partner_compassion/static/src/html/thank_you_quote_template.html')
        template_html = unicode(html_file.read())
        for details in self:
            html_vals = {
                u'img_alt': details.display_name,
                u'image_data': details.partner_id.with_context(
                    bin_size=False).image,
                u'text': details.quote or '',
                u'attribution': _('Quote from {firstname} {lastname}').format(
                    firstname=details.partner_id.firstname,
                    lastname=details.partner_id.lastname)
                if details.quote else '',
            }
            details.thank_you_quote = template_html.format(**html_vals)

    @api.multi
    def _compute_events(self):
        for details in self:
            details.event_ids = self.env['crm.event.compassion'].search([
                ('staff_ids', '=', details.partner_id.id),
                ('end_date', '<', fields.Datetime.now())
            ])
            details.number_events = len(details.event_ids)
            details.last_event = details.event_ids[:1].end_date

    @api.multi
    def _compute_formation(self):
        formation_cated_id = self.env.ref(
            'partner_compassion.event_type_formation').id
        for details in self:
            details.formation_ids = self.env['calendar.event'].search([
                ('partner_ids', '=', details.partner_id.id),
                ('categ_ids', '=', formation_cated_id)
            ])
            details.event_type_formation = formation_cated_id

    @api.multi
    def _inverse_formation(self):
        # Allows to create formation event from ambassador details
        return True

    @api.multi
    def set_geo_point(self):
        for advocate in self:
            advocate.geo_point = advocate.partner_id.geo_point

    @api.model
    def create(self, vals):
        # Link partner to the advocate details
        advocate = super(AdvocateDetails, self).create(vals)
        advocate.partner_id.advocate_details_id = advocate
        advocate.set_geo_point()
        return advocate

    @api.multi
    def open_events(self):
        return {
            'name': _('Events'),
            'type': 'ir.actions.act_window',
            'view_type': 'form',
            'view_mode': 'tree,form',
            'res_model': 'crm.event.compassion',
            'target': 'current',
            'domain': [('id', 'in', self.event_ids.ids)],
        }

    @api.multi
    def open_surveys(self):
        return {
            'name': _('Surveys'),
            'type': 'ir.actions.act_window',
            'view_type': 'form',
            'view_mode': 'tree,form',
            'res_model': 'survey.user_input',
            'target': 'current',
            'domain': [('partner_id', '=', self.partner_id.id)],
        }

    def set_on_break(self):
        self.env.user.notify_info(
            _("Please don't forget to put a break end date"), sticky=True)
        return self.write({'state': 'on_break'})

    def set_inactive(self):
        return self.write({
            'state': 'inactive',
            'end_date': fields.Date.today()
        })

    def set_active(self):
        return self.write({
            'state': 'active',
            'end_date': False,
            'break_end': False
        })

    @api.model
    def advocate_cron(self):
        three_open_days = datetime.today() + BDay(3)
        birthday_advocates = self.search([
            ('state', 'in', ['active', 'on_break']),
            ('birthdate', 'like', three_open_days.strftime('%m-%d'))
        ])
        birthday_advocates = birthday_advocates.filtered(
            lambda a: a.engagement_ids != self.env.ref(
                "partner_compassion.engagement_sport"))
        for advocate in birthday_advocates:
            notify_partner_id = self.env['staff.notification.settings'].\
                get_param(
                'advocate_birthday_{}_id'.format(advocate.partner_id.lang[:2])
                )
            advocate.message_post(
                body=_(u"This is a reminder that {} will have birthday on {}.")
                .format(advocate.partner_id.preferred_name,
                        advocate.partner_id.get_date(
                            'birthdate_date', '%d %B')),
                subject=_(u"[{}] Advocate birthday reminder").format(
                    advocate.display_name),
                partner_ids=[notify_partner_id],
                type='comment',
                subtype='mail.mt_comment',
                content_subtype='html'
            )
        break_advocates = self.search([
            ('state', '=', 'on_break'),
            ('break_end', '<', fields.Date.today()),
            ('break_end', '!=', False)
        ])
        break_advocates.set_active()
class FSMLocation(geo_model.GeoModel):
    _name = 'fsm.location'
    _inherits = {'res.partner': 'partner_id'}
    _description = 'Field Service Location'

    @api.model
    def _tz_get(self):
        return [(tz, tz)
                for tz in sorted(pytz.all_timezones,
                                 key=lambda tz: tz
                                 if not tz.startswith('Etc/') else '_')]

    ref = fields.Char(string='Internal Reference')
    direction = fields.Char(string='Directions')
    partner_id = fields.Many2one('res.partner',
                                 string='Related Partner',
                                 required=True,
                                 ondelete='restrict',
                                 delegate=True,
                                 auto_join=True)
    owner_id = fields.Many2one('res.partner',
                               string='Related Owner',
                               required=True,
                               ondelete='restrict',
                               auto_join=True)
    customer_id = fields.Many2one('res.partner',
                                  string='Billed Customer',
                                  required=True,
                                  ondelete='restrict',
                                  auto_join=True)
    contact_id = fields.Many2one('res.partner',
                                 string='Primary Contact',
                                 domain="[('is_company', '=', False),"
                                 " ('fsm_location', '=', False)]",
                                 index=True)
    tag_ids = fields.Many2many('fsm.tag', string='Tags')
    description = fields.Char(string='Description')
    territory_id = fields.Many2one('fsm.territory', string='Territory')
    branch_id = fields.Many2one('fsm.branch', string='Branch')
    district_id = fields.Many2one('fsm.district', string='District')
    region_id = fields.Many2one('fsm.region', string='Region')
    territory_manager_id = fields.Many2one(string='Primary Assignment',
                                           related='territory_id.person_id')
    district_manager_id = fields.Many2one(string='District Manager',
                                          related='district_id.partner_id')
    region_manager_id = fields.Many2one(string='Region Manager',
                                        related='region_id.partner_id')
    branch_manager_id = fields.Many2one(string='Branch Manager',
                                        related='branch_id.partner_id')

    timezone = fields.Selection(_tz_get, string='Timezone')

    parent_id = fields.Many2one('fsm.location', string='Parent')
    notes = fields.Text(string="Notes")
    person_ids = fields.Many2many('fsm.person',
                                  'partner_id',
                                  string='Preferred Workers')

    contact_count = fields.Integer(string='Contacts',
                                   compute='_compute_contact_ids')
    equipment_count = fields.Integer(string='Equipment',
                                     compute='_compute_equipment_ids')

    # Geometry Field
    shape = geo_fields.GeoPoint(string='Coordinate')

    _sql_constraints = [('fsm_location_ref_uniq', 'unique (ref)',
                         'This internal reference already exists!')]

    @api.model
    def create(self, vals):
        vals.update({'fsm_location': True})
        res = super(FSMLocation, self).create(vals)
        lat = self.partner_id.partner_latitude
        lng = self.partner_id.partner_longitude
        if lat == 0.0 and lng == 0.0:
            res.geo_localize()
        else:
            point = geo_fields.GeoPoint.from_latlon(cr=self.env.cr,
                                                    latitude=lat,
                                                    longitude=lng)
            self.shape = point
        return res

    @api.onchange('territory_id')
    def _onchange_territory_id(self):
        if self.territory_id:
            # assign manager
            self.territory_manager_id = self.territory_id.person_id
            # get territory preffered person list if available
            self.person_ids = self.territory_id.person_ids
            if self.territory_id.branch_id:
                self.branch_id = self.territory_id.branch_id
                self.branch_manager_id = self.territory_id.branch_id.partner_id

    @api.onchange('branch_id')
    def _onchange_branch_id(self):
        if self.branch_id and self.branch_id.district_id:
            self.district_id = self.branch_id.district_id
            self.district_manager_id = self.branch_id.district_id.partner_id

    @api.onchange('district_id')
    def _onchange_district_id(self):
        self.region_id = self.district_id.region_id

    def comp_count(self, contact, equipment, loc):
        if equipment:
            for child in loc:
                child_locs = self.env['fsm.location'].\
                    search([('parent_id', '=', child.id)])
                equip = self.env['fsm.equipment'].\
                    search_count([('location_id',
                                 '=', child.id)])
            if child_locs:
                for loc in child_locs:
                    equip += loc.comp_count(0, 1, loc)
            return equip
        elif contact:
            for child in loc:
                child_locs = self.env['fsm.location'].\
                    search([('parent_id', '=', child.id)])
                con = self.env['res.partner'].\
                    search_count([('service_location_id',
                                 '=', child.id)])
            if child_locs:
                for loc in child_locs:
                    con += loc.comp_count(1, 0, loc)
            return con

    def get_action_views(self, contact, equipment, loc):
        if equipment:
            for child in loc:
                child_locs = self.env['fsm.location'].\
                    search([('parent_id', '=', child.id)])
                equip = self.env['fsm.equipment'].\
                    search([('location_id', '=', child.id)])
            if child_locs:
                for loc in child_locs:
                    equip += loc.get_action_views(0, 1, loc)
            return equip
        elif contact:
            for child in loc:
                child_locs = self.env['fsm.location'].\
                    search([('parent_id', '=', child.id)])
                con = self.env['res.partner'].\
                    search([('service_location_id', '=', child.id)])
            if child_locs:
                for loc in child_locs:
                    con += loc.get_action_views(1, 0, loc)
            return con

    @api.multi
    def action_view_contacts(self):
        '''
        This function returns an action that display existing contacts
        of given fsm location id and its child locations. It can
        either be a in a list or in a form view, if there is only one
        contact to show.
        '''
        for location in self:
            action = self.env.ref('contacts.action_contacts').\
                read()[0]
            contacts = self.get_action_views(1, 0, location)
            if len(contacts) > 1:
                action['domain'] = [('id', 'in', contacts.ids)]
            elif contacts:
                action['views'] = [(self.env.ref('base.view_partner_form').id,
                                    'form')]
                action['res_id'] = contacts.id
            return action

    @api.multi
    def _compute_contact_ids(self):
        for loc in self:
            contacts = self.comp_count(1, 0, loc)
            loc.contact_count = contacts

    @api.multi
    def action_view_equipment(self):
        '''
        This function returns an action that display existing
        equipment of given fsm location id. It can either be a in
        a list or in a form view, if there is only one equipment to show.
        '''
        for location in self:
            action = self.env.ref('fieldservice.action_fsm_equipment').\
                read()[0]
            equipment = self.get_action_views(0, 1, location)
            if len(equipment) > 1:
                action['domain'] = [('id', 'in', equipment.ids)]
            elif equipment:
                action['views'] = [(self.env.ref('fieldservice.' +
                                                 'fsm_equipment_form_view').id,
                                    'form')]
                action['res_id'] = equipment.id
            return action

    @api.multi
    def _compute_equipment_ids(self):
        for loc in self:
            equipment = self.comp_count(0, 1, loc)
            loc.equipment_count = equipment
        for location in self:
            child_locs = self.env['fsm.location'].\
                search([('parent_id', '=', location.id)])
            equipment = (self.env['fsm.equipment'].search_count([
                ('location_id', 'in', child_locs.ids)
            ]) + self.env['fsm.equipment'].search_count(
                [('location_id', '=', location.id)]))
            location.equipment_count = equipment or 0

    def geo_localize(self):
        for loc in self:
            if loc.partner_id:
                loc.partner_id.geo_localize()
            lat = loc.partner_latitude
            lng = loc.partner_longitude
            point = geo_fields.GeoPoint.from_latlon(cr=loc.env.cr,
                                                    latitude=lat,
                                                    longitude=lng)
            loc.shape = point

    def _update_order_geometries(self):
        for loc in self:
            orders = loc.env['fsm.order'].search([('location_id', '=', loc.id)
                                                  ])
            for order in orders:
                order.create_geometry()

    @api.multi
    def write(self, vals):
        res = super(FSMLocation, self).write(vals)
        if ('partner_latitude' in vals) and ('partner_longitude' in vals):
            self.shape = geo_fields.GeoPoint.from_latlon(
                cr=self.env.cr,
                latitude=vals['partner_latitude'],
                longitude=vals['partner_longitude'])
            self._update_order_geometries()
        return res
Beispiel #15
0
class FSMLocation(geo_model.GeoModel):
    _name = 'fsm.location'
    _inherits = {'res.partner': 'partner_id'}
    _description = 'Field Service Location'

    @api.model
    def _tz_get(self):
        return [(tz, tz)
                for tz in sorted(pytz.all_timezones,
                                 key=lambda tz: tz
                                 if not tz.startswith('Etc/') else '_')]

    ref = fields.Char(string='Internal Reference', copy=False)
    direction = fields.Char(string='Directions')
    partner_id = fields.Many2one('res.partner',
                                 string='Related Partner',
                                 required=True,
                                 ondelete='restrict',
                                 delegate=True,
                                 auto_join=True)
    owner_id = fields.Many2one('res.partner',
                               string='Related Owner',
                               required=True,
                               ondelete='restrict',
                               auto_join=True)
    customer_id = fields.Many2one('res.partner',
                                  string='Billed Customer',
                                  required=True,
                                  ondelete='restrict',
                                  auto_join=True)
    contact_id = fields.Many2one('res.partner',
                                 string='Primary Contact',
                                 domain="[('is_company', '=', False),"
                                 " ('fsm_location', '=', False)]",
                                 index=True)
    tag_ids = fields.Many2many('fsm.tag', string='Tags')
    description = fields.Char(string='Description')
    territory_id = fields.Many2one('fsm.territory', string='Territory')
    branch_id = fields.Many2one('fsm.branch', string='Branch')
    district_id = fields.Many2one('fsm.district', string='District')
    region_id = fields.Many2one('fsm.region', string='Region')
    territory_manager_id = fields.Many2one(string='Primary Assignment',
                                           related='territory_id.person_id')
    district_manager_id = fields.Many2one(string='District Manager',
                                          related='district_id.partner_id')
    region_manager_id = fields.Many2one(string='Region Manager',
                                        related='region_id.partner_id')
    branch_manager_id = fields.Many2one(string='Branch Manager',
                                        related='branch_id.partner_id')

    timezone = fields.Selection(_tz_get, string='Timezone')

    fsm_parent_id = fields.Many2one('fsm.location', string='Parent')
    notes = fields.Text(string="Notes")
    person_ids = fields.Many2many('fsm.person',
                                  'fsm_person_location_rel',
                                  'fsm_location_id',
                                  'fsm_person_id',
                                  string='Preferred Workers')
    contact_count = fields.Integer(string='Contacts',
                                   compute='_compute_contact_ids')
    equipment_count = fields.Integer(string='Equipment',
                                     compute='_compute_equipment_ids')
    sublocation_count = fields.Integer(string='Sub Locations',
                                       compute='_compute_sublocation_ids')
    complete_name = fields.Char(string='Complete Name',
                                compute='_compute_complete_name',
                                stored='_compute_complete_name')
    stage_id = fields.Many2one('fsm.stage',
                               string='Stage',
                               track_visibility='onchange',
                               index=True,
                               copy=False,
                               group_expand='_read_group_stage_ids',
                               default=lambda self: self._default_stage_id())
    hide = fields.Boolean(default=False)
    company_id = fields.Many2one('res.company',
                                 'Company',
                                 default=lambda self: self.env.user.company_id)

    @api.depends('name', 'fsm_parent_id.complete_name')
    def _compute_complete_name(self):
        for loc in self:
            if loc.fsm_parent_id:
                loc.complete_name = '%s / %s' % (
                    loc.fsm_parent_id.complete_name, loc.name)
            else:
                loc.complete_name = loc.name

    @api.multi
    def name_get(self):
        results = []
        for rec in self:
            results.append((rec.id, rec.complete_name))
        return results

    # Geometry Field
    shape = geo_fields.GeoPoint(string='Coordinate')

    _sql_constraints = [('fsm_location_ref_uniq', 'unique (ref)',
                         'This internal reference already exists!')]

    @api.model
    def _read_group_stage_ids(self, stages, domain, order):
        stage_ids = self.env['fsm.stage'].search([('stage_type', '=',
                                                   'location')])
        return stage_ids

    def _default_stage_id(self):
        return self.env['fsm.stage'].search([('stage_type', '=', 'location'),
                                             ('sequence', '=', '1')])

    def advance_stage(self):
        seq = self.stage_id.sequence
        next_stage = self.env['fsm.stage'].search([('stage_type', '=',
                                                    'location'),
                                                   ('sequence', '=', seq + 1)])
        self.stage_id = next_stage
        self._onchange_stage_id()

    @api.onchange('stage_id')
    def _onchange_stage_id(self):
        # get last stage
        heighest_stage = self.env['fsm.stage'].search(
            [('stage_type', '=', 'location')], order='sequence desc', limit=1)
        if self.stage_id.name == heighest_stage.name:
            self.hide = True
        else:
            self.hide = False

    @api.model
    def create(self, vals):
        vals.update({'fsm_location': True})
        res = super(FSMLocation, self).create(vals)
        lat = self.partner_id.partner_latitude
        lng = self.partner_id.partner_longitude
        if lat == 0.0 and lng == 0.0:
            res.geo_localize()
        else:
            point = geo_fields.GeoPoint.from_latlon(cr=self.env.cr,
                                                    latitude=lat,
                                                    longitude=lng)
            self.shape = point
        return res

    @api.onchange('fsm_parent_id')
    def _onchange_fsm_parent_id(self):
        self.owner_id = self.fsm_parent_id.owner_id or False
        self.customer_id = self.fsm_parent_id.customer_id or False
        self.contact_id = self.fsm_parent_id.contact_id or False
        self.direction = self.fsm_parent_id.direction or False
        self.street = self.fsm_parent_id.street or False
        self.street2 = self.fsm_parent_id.street2 or False
        self.city = self.fsm_parent_id.city or False
        self.zip = self.fsm_parent_id.zip or False
        self.state_id = self.fsm_parent_id.state_id or False
        self.country_id = self.fsm_parent_id.country_id or False
        self.timezone = self.fsm_parent_id.timezone or False
        self.territory_id = self.fsm_parent_id.territory_id or False

    @api.onchange('territory_id')
    def _onchange_territory_id(self):
        self.territory_manager_id = self.territory_id.person_id or False
        self.person_ids = self.territory_id.person_ids or False
        self.branch_id = self.territory_id.branch_id or False

    @api.onchange('branch_id')
    def _onchange_branch_id(self):
        self.branch_manager_id = \
            self.territory_id.branch_id.partner_id or False
        self.district_id = self.branch_id.district_id or False

    @api.onchange('district_id')
    def _onchange_district_id(self):
        self.district_manager_id = \
            self.branch_id.district_id.partner_id or False
        self.region_id = self.district_id.region_id or False

    @api.onchange('region_id')
    def _onchange_region_id(self):
        self.region_manager_id = self.region_id.partner_id or False

    def comp_count(self, contact, equipment, loc):
        if equipment:
            for child in loc:
                child_locs = self.env['fsm.location'].\
                    search([('fsm_parent_id', '=', child.id)])
                equip = self.env['fsm.equipment'].\
                    search_count([('location_id',
                                 '=', child.id)])
            if child_locs:
                for loc in child_locs:
                    equip += loc.comp_count(0, 1, loc)
            return equip
        elif contact:
            for child in loc:
                child_locs = self.env['fsm.location'].\
                    search([('fsm_parent_id', '=', child.id)])
                con = self.env['res.partner'].\
                    search_count([('service_location_id',
                                 '=', child.id)])
            if child_locs:
                for loc in child_locs:
                    con += loc.comp_count(1, 0, loc)
            return con
        else:
            for child in loc:
                child_locs = self.env['fsm.location'].\
                    search([('fsm_parent_id', '=', child.id)])
                subloc = self.env['fsm.location'].\
                    search_count([('fsm_parent_id', '=', child.id)])
            if child_locs:
                for loc in child_locs:
                    subloc += loc.comp_count(0, 0, loc)
            return subloc

    def get_action_views(self, contact, equipment, loc):
        if equipment:
            for child in loc:
                child_locs = self.env['fsm.location'].\
                    search([('fsm_parent_id', '=', child.id)])
                equip = self.env['fsm.equipment'].\
                    search([('location_id', '=', child.id)])
            if child_locs:
                for loc in child_locs:
                    equip += loc.get_action_views(0, 1, loc)
            return equip
        elif contact:
            for child in loc:
                child_locs = self.env['fsm.location'].\
                    search([('fsm_parent_id', '=', child.id)])
                con = self.env['res.partner'].\
                    search([('service_location_id', '=', child.id)])
            if child_locs:
                for loc in child_locs:
                    con += loc.get_action_views(1, 0, loc)
            return con
        else:
            for child in loc:
                child_locs = self.env['fsm.location'].\
                    search([('fsm_parent_id', '=', child.id)])
                subloc = child_locs
            if child_locs:
                for loc in child_locs:
                    subloc += loc.get_action_views(0, 0, loc)
            return subloc

    @api.multi
    def action_view_contacts(self):
        '''
        This function returns an action that display existing contacts
        of given fsm location id and its child locations. It can
        either be a in a list or in a form view, if there is only one
        contact to show.
        '''
        for location in self:
            action = self.env.ref('contacts.action_contacts').\
                read()[0]
            contacts = self.get_action_views(1, 0, location)
            if len(contacts) > 1:
                action['domain'] = [('id', 'in', contacts.ids)]
            elif contacts:
                action['views'] = [(self.env.ref('base.view_partner_form').id,
                                    'form')]
                action['res_id'] = contacts.id
            return action

    @api.multi
    def _compute_contact_ids(self):
        for loc in self:
            contacts = self.comp_count(1, 0, loc)
            loc.contact_count = contacts

    @api.multi
    def action_view_equipment(self):
        '''
        This function returns an action that display existing
        equipment of given fsm location id. It can either be a in
        a list or in a form view, if there is only one equipment to show.
        '''
        for location in self:
            action = self.env.ref('fieldservice.action_fsm_equipment').\
                read()[0]
            equipment = self.get_action_views(0, 1, location)
            if len(equipment) == 0 or len(equipment) > 1:
                action['domain'] = [('id', 'in', equipment.ids)]
            elif equipment:
                action['views'] = [(self.env.ref('fieldservice.' +
                                                 'fsm_equipment_form_view').id,
                                    'form')]
                action['res_id'] = equipment.id
            return action

    @api.multi
    def _compute_sublocation_ids(self):
        for loc in self:
            sublocation = self.comp_count(0, 0, loc)
            loc.sublocation_count = sublocation

    @api.multi
    def action_view_sublocation(self):
        '''
        This function returns an action that display existing
        sub-locations of a given fsm location id. It can either be a in
        a list or in a form view, if there is only one sub-location to show.
        '''
        for location in self:
            action = self.env.ref('fieldservice.action_fsm_location').read()[0]
            sublocation = self.get_action_views(0, 0, location)
            if len(sublocation) > 1 or len(sublocation) == 0:
                action['domain'] = [('id', 'in', sublocation.ids)]
            elif sublocation:
                action['views'] = [(self.env.ref('fieldservice.' +
                                                 'fsm_location_form_view').id,
                                    'form')]
                action['res_id'] = sublocation.id
            return action

    @api.multi
    def _compute_equipment_ids(self):
        for loc in self:
            equipment = self.comp_count(0, 1, loc)
            loc.equipment_count = equipment
        for location in self:
            child_locs = self.env['fsm.location']. \
                search([('fsm_parent_id', '=', location.id)])
            equipment = (self.env['fsm.equipment'].search_count([
                ('location_id', 'in', child_locs.ids)
            ]) + self.env['fsm.equipment'].search_count(
                [('location_id', '=', location.id)]))
            location.equipment_count = equipment or 0

    def geo_localize(self):
        for loc in self:
            if loc.partner_id:
                loc.partner_id.geo_localize()
            lat = loc.partner_latitude
            lng = loc.partner_longitude
            point = geo_fields.GeoPoint.from_latlon(cr=loc.env.cr,
                                                    latitude=lat,
                                                    longitude=lng)
            loc.shape = point

    def _update_order_geometries(self):
        for loc in self:
            orders = loc.env['fsm.order'].search([('location_id', '=', loc.id)
                                                  ])
            for order in orders:
                order.create_geometry()

    @api.multi
    def write(self, vals):
        res = super(FSMLocation, self).write(vals)
        if ('partner_latitude' in vals) and ('partner_longitude' in vals):
            self.shape = geo_fields.GeoPoint.from_latlon(
                cr=self.env.cr,
                latitude=vals['partner_latitude'],
                longitude=vals['partner_longitude'])
            self._update_order_geometries()
        return res
Beispiel #16
0
class ResPartner(models.Model):
    """ This class upgrade the partners to match Compassion needs.
        It also synchronize all changes with the MySQL server of GP.
    """
    _inherit = 'res.partner'

    def _get_receipt_types(self):
        """ Display values for the receipt selection fields. """
        return [
            ('no', _('No receipt')),
            ('default', _('Default')),
            ('only_email', _('Only email')),
            ('paper', _('On paper'))]

    ##########################################################################
    #                        NEW PARTNER FIELDS                              #
    ##########################################################################
    lang = fields.Selection(default=False)
    total_invoiced = fields.Monetary(groups=False)
    street3 = fields.Char("Street3", size=128)
    invalid_mail = fields.Char("Invalid mail")
    church_unlinked = fields.Char(
        "Church (N/A)",
        help="Use this field if the church of the partner"
             " can not correctly be determined and linked.")
    deathdate = fields.Date('Death date', track_visibility='onchange')
    nbmag = fields.Integer('Number of Magazines', size=2,
                           required=True, default=1)
    tax_certificate = fields.Selection(
        _get_receipt_types, required=True, default='default')
    thankyou_letter = fields.Selection(
        _get_receipt_types, 'Thank you letter',
        required=True, default='default')
    calendar = fields.Boolean(
        help="Indicates if the partner wants to receive the Compassion "
             "calendar.", default=True)
    christmas_card = fields.Boolean(
        help="Indicates if the partner wants to receive the "
             "christmas card.", default=True)
    birthday_reminder = fields.Boolean(
        help="Indicates if the partner wants to receive a birthday "
             "reminder of his child.", default=True)
    photo_delivery_preference = fields.Selection(
        selection='_get_delivery_preference',
        default='both',
        required=True,
        help='Delivery preference for Child photo')

    partner_duplicate_ids = fields.Many2many(
        'res.partner', 'res_partner_duplicates', 'partner_id',
        'duplicate_id', readonly=True)

    advocate_details_id = fields.Many2one(
        'advocate.details', 'Advocate details', copy=False)
    engagement_ids = fields.Many2many(
        'advocate.engagement', related='advocate_details_id.engagement_ids'
    )
    other_contact_ids = fields.One2many(string='Linked Partners',
                                        domain=['|', ('active', '=', False),
                                                ('active', '=', True)])
    state = fields.Selection([
        ('pending', 'Waiting for validation'),
        ('active', 'Active')
    ], default='active', track_visibility='onchange')

    email_copy = fields.Boolean(string='CC e-mails sent to main partner')
    type = fields.Selection(selection_add=[
        ('email_alias', 'Email alias')
    ])

    uuid = fields.Char(default=lambda self: self._get_uuid(), copy=False,
                       index=True)

    has_agreed_child_protection_charter = fields.Boolean(
        help="Indicates if the partner has agreed to the child protection"
             "charter.", default=False)
    date_agreed_child_protection_charter = fields.Datetime(
        help="The date and time when the partner has agreed to the child"
             "protection charter."
    )
    geo_point = geo_fields.GeoPoint(copy=False)

    # add track on fields from module base
    email = fields.Char(track_visibility='onchange')
    title = fields.Many2one(track_visibility='onchange')
    lang = fields.Selection(track_visibility='onchange')
    # module from partner_firstname
    firstname = fields.Char(track_visibility='onchange')
    lastname = fields.Char(track_visibility='onchange')
    # module mail
    opt_out = fields.Boolean(track_visibility='onchange')

    ##########################################################################
    #                             FIELDS METHODS                             #
    ##########################################################################
    def _get_uuid(self):
        return str(uuid.uuid4())

    @api.multi
    def agree_to_child_protection_charter(self):
        return self.write({
            'has_agreed_child_protection_charter': True,
            'date_agreed_child_protection_charter': fields.Datetime.now()
        })

    @api.multi
    def validate_partner(self):
        return self.write({
            'state': 'active'
        })

    @api.multi
    def get_unreconciled_amount(self):
        """Returns the amount of unreconciled credits in Account 1050"""
        self.ensure_one()
        mv_line_obj = self.env['account.move.line']
        move_line_ids = mv_line_obj.search([
            ('partner_id', '=', self.id),
            ('account_id.code', '=', '1050'),
            ('credit', '>', '0'),
            ('full_reconcile_id', '=', False)])
        res = 0
        for move_line in move_line_ids:
            res += move_line.credit
        return res

    @api.multi
    def update_number_sponsorships(self):
        """
        Update the sponsorship number for the related church as well.
        """
        return super(
            ResPartner,
            self + self.mapped('church_id')).update_number_sponsorships()

    ##########################################################################
    #                              ORM METHODS                               #
    ##########################################################################
    @api.model
    def create(self, vals):
        """
        Lookup for duplicate partners and notify.
        """
        email = vals.get('email')
        if email:
            vals['email'] = email.strip()
        duplicate = self.search(
            ['|',
             '&',
             ('email', '=', vals.get('email')),
             ('email', '!=', False),
             '&', '&',
             ('firstname', 'ilike', vals.get('firstname')),
             ('lastname', 'ilike', vals.get('lastname')),
             ('zip', '=', vals.get('zip'))
             ])
        duplicate_ids = [(4, itm.id) for itm in duplicate]
        vals.update({'partner_duplicate_ids': duplicate_ids})
        vals['ref'] = self.env['ir.sequence'].get('partner.ref')
        # Never subscribe someone to res.partner record
        partner = super(ResPartner, self.with_context(
            mail_create_nosubscribe=True)).create(vals)
        partner.compute_geopoint()
        if partner.contact_type == 'attached' and not vals.get('active'):
            partner.active = False

        return partner

    @api.multi
    def write(self, vals):
        email = vals.get('email')
        if email:
            vals['email'] = email.strip()
        res = super(ResPartner, self).write(vals)
        if set(('country_id', 'city', 'zip')).intersection(vals):
            self.geo_localize()
            self.compute_geopoint()
        return res

    @api.model
    def name_search(self, name, args=None, operator='ilike', limit=80):
        """Extends to use trigram search."""
        if args is None:
            args = []
        if name:
            # First find by reference
            res = self.search([('ref', 'like', name)], limit=limit)
            if not res:
                res = self.search(
                    ['|', ('name', '%', name), ('name', 'ilike', name)],
                    order=u"similarity(res_partner.name, '%s') DESC" % name,
                    limit=limit)
            # Search by e-mail
            if not res:
                res = self.search([('email', 'ilike', name)], limit=limit)
        else:
            res = self.search(args, limit=limit)
        return res.name_get()

    @api.model
    def search(self, args, offset=0, limit=None, order=None, count=False):
        """ Order search results based on similarity if name search is used."""
        fuzzy_search = False
        for arg in args:
            if arg[0] == 'name' and arg[1] == '%':
                fuzzy_search = arg[2]
                break
        if fuzzy_search:
            order = self.env.cr.mogrify(
                u"similarity(res_partner.name, %s) DESC", [fuzzy_search])
        return super(ResPartner, self).search(
            args, offset, limit, order, count)

    ##########################################################################
    #                             ONCHANGE METHODS                           #
    ##########################################################################
    @api.onchange('lastname', 'firstname', 'zip', 'email')
    def _onchange_partner(self):
        if ((self.lastname and self.firstname and self.zip) or self.email)\
                and self.contact_type != 'attached':
            partner_duplicates = self.search([
                ('id', '!=', self._origin.id),
                '|',
                '&',
                ('email', '=', self.email),
                ('email', '!=', False),
                '&', '&',
                ('firstname', 'ilike', self.firstname),
                ('lastname', 'ilike', self.lastname),
                ('zip', '=', self.zip)
            ])
            if partner_duplicates:
                self.partner_duplicate_ids = partner_duplicates
                # Commit the found duplicates
                with api.Environment.manage():
                    with registry(self.env.cr.dbname).cursor() as new_cr:
                        new_env = api.Environment(new_cr, self.env.uid, {})
                        self._origin.with_env(new_env).write({
                            'partner_duplicate_ids': [(6, 0,
                                                       partner_duplicates.ids)]
                        })
                return {
                    'warning': {
                        'title': _("Possible existing partners found"),
                        'message': _('The partner you want to add may '
                                     'already exist. Please use the "'
                                     'Check duplicates" button to review it.')
                    },
                }

    ##########################################################################
    #                             PUBLIC METHODS                             #
    ##########################################################################
    @api.multi
    def compute_geopoint(self):
        """ Compute geopoints. """
        self.filtered(lambda p: not p.partner_latitude or not
                      p.partner_longitude).geo_localize()
        for partner in self.filtered(lambda p: p.partner_latitude and
                                     p.partner_longitude):
            geo_point = GeoPoint.from_latlon(
                self.env.cr,
                partner.partner_latitude,
                partner.partner_longitude)
            vals = {'geo_point': geo_point.wkt}
            partner.write(vals)
            partner.advocate_details_id.write(vals)
        return True

    @api.multi
    def generate_bvr_reference(self, product):
        """
        Generates a bvr reference for a donation to the fund given by
        the product.
        :param product: fund product with a fund_id
        :return: bvr reference for the partner
        """
        self.ensure_one()
        if isinstance(product, int):
            product = self.env['product.product'].browse(product)
        ref = self.ref
        bvr_reference = '0' * (9 + (7 - len(ref))) + ref
        bvr_reference += '0' * 5
        bvr_reference += '6'    # Fund donation
        bvr_reference += '0' * (4 - len(str(product.fund_id))) + str(
            product.fund_id)
        if len(bvr_reference) == 26:
            return mod10r(bvr_reference)

    ##########################################################################
    #                             VIEW CALLBACKS                             #
    ##########################################################################
    @api.multi
    def onchange_type(self, is_company):
        """ Put title 'Friends of Compassion for companies. """
        res = super(ResPartner, self).onchange_type(is_company)
        if is_company:
            res['value']['title'] = self.env.ref(
                'partner_compassion.res_partner_title_friends').id
        return res

    @api.model
    def get_lang_from_phone_number(self, phone):
        record = self.env['phone.common'].get_record_from_phone_number(phone)
        if record:
            partner = self.browse(record[1])
        return record and partner.lang

    @api.multi
    def forget_me(self):
        # Store information in CSV, inside encrypted zip file.
        self._secure_save_data()

        super(ResPartner, self).forget_me()
        # Delete other objects and custom CH fields
        self.write({
            'church_id': False,
            'church_unlinked': False,
            'street3': False,
            'firstname': False,
            'deathdate': False,
            'geo_point': False,
            'partner_latitude': False,
            'partner_longitude': False
        })
        self.advocate_details_id.unlink()
        self.survey_inputs.unlink()
        self.env['mail.tracking.email'].search([
            ('partner_id', '=', self.id)]).unlink()
        self.env['auditlog.log'].search([
            ('model_id.model', '=', 'res.partner'),
            ('res_id', '=', self.id)
        ]).unlink()
        self.env['partner.communication.job'].search([
            ('partner_id', '=', self.id)
        ]).unlink()
        self.message_ids.unlink()
        return True

    @api.multi
    def open_duplicates(self):
        partner_wizard = self.env['res.partner.check.double'].create({
            'partner_id': self.id,
        })
        return {
            "type": "ir.actions.act_window",
            "res_model": "res.partner.check.double",
            "res_id": partner_wizard.id,
            "view_type": "form",
            "view_mode": "form",
            "target": "new",
        }

    ##########################################################################
    #                             PRIVATE METHODS                            #
    ##########################################################################
    @api.model
    def _address_fields(self):
        """ 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 _secure_save_data(self):
        """
        Stores partner name and address in a CSV file on NAS,
        inside a password-protected ZIP file.
        :return: None
        """
        smb_conn = self._get_smb_connection()
        if smb_conn and smb_conn.connect(SmbConfig.smb_ip, SmbConfig.smb_port):
            config_obj = self.env['ir.config_parameter']
            share_nas = config_obj.get_param('partner_compassion.share_on_nas')
            store_path = config_obj.get_param('partner_compassion.store_path')
            src_zip_file = tempfile.NamedTemporaryFile()
            attrs = smb_conn.retrieveFile(share_nas, store_path, src_zip_file)
            file_size = attrs[1]
            if file_size:
                src_zip_file.flush()
                zip_dir = tempfile.mkdtemp()
                pyminizip.uncompress(
                    src_zip_file.name, SmbConfig.file_pw, zip_dir, 0)
                csv_path = zip_dir + '/partner_data.csv'
                with open(csv_path, 'ab') as csv_file:
                    csv_writer = csv.writer(csv_file)
                    csv_writer.writerow([
                        str(self.id), self.ref, self.contact_address,
                        fields.Date.today()
                    ])
                dst_zip_file = tempfile.NamedTemporaryFile()
                pyminizip.compress(
                    csv_path, '', dst_zip_file.name, SmbConfig.file_pw, 5)
                try:
                    smb_conn.storeFile(share_nas, store_path, dst_zip_file)
                except OperationFailure:
                    logger.error(
                        "Couldn't store secure partner data on NAS. "
                        "Please do it manually by replicating the following "
                        "file: " + dst_zip_file.name)

    def _get_smb_connection(self):
        """" Retrieve configuration SMB """
        if not (SmbConfig.smb_user and SmbConfig.smb_pass and
                SmbConfig.smb_ip and SmbConfig.smb_port):
            return False
        else:
            return SMBConnection(
                SmbConfig.smb_user, SmbConfig.smb_pass, 'odoo', 'nas')

    def _get_active_sponsorships_domain(self):
        """
        Include sponsorships of church members
        :return: search domain for recurring.contract
        """
        domain = super(ResPartner, self)._get_active_sponsorships_domain()
        domain.insert(0, '|')
        domain.insert(3, ('partner_id', 'in', self.mapped('member_ids').ids))
        domain.insert(4, '|')
        domain.insert(6, ('correspondent_id', 'in', self.mapped(
            'member_ids').ids))
        return domain

    @api.model
    def _notify_prepare_email_values(self, message):
        """
        Always put reply_to value in mail notifications.
        :param message: the message record
        :return: mail values
        """
        mail_values = super(ResPartner,
                            self)._notify_prepare_email_values(message)

        # Find reply-to in mail template.
        base_template = None
        if message.model and self._context.get('custom_layout', False):
            base_template = self.env.ref(self._context['custom_layout'],
                                         raise_if_not_found=False)
        if not base_template:
            base_template = self.env.ref(
                'mail.mail_template_data_notification_email_default')

        if base_template.reply_to:
            mail_values['reply_to'] = base_template.reply_to

        return mail_values
Beispiel #17
0
class ResPartner(geo_model.GeoModel):
    """Add geo_point to partner using a function field"""
    _inherit = "res.partner"

    @api.multi
    def geocode_address(self):
        """Get the latitude and longitude by requesting the "Nominatim"
        search engine from "openstreetmap". See:
        https://nominatim.org/release-docs/latest/api/Overview/
        """
        url = 'http://nominatim.openstreetmap.org/search'
        headers = {'User-Agent': 'Odoobot/11.0.1.0.0 (OCA-geospatial)'}

        for partner in self:
            pay_load = {
                'limit':
                1,
                'format':
                'json',
                'street':
                partner.street or '',
                'postalCode':
                partner.zip or '',
                'city':
                partner.city or '',
                'state':
                partner.state_id and partner.state_id.name or '',
                'country':
                partner.country_id and partner.country_id.name or '',
                'countryCodes':
                partner.country_id and partner.country_id.code or ''
            }

            request_result = requests.get(url,
                                          params=pay_load,
                                          headers=headers)
            try:
                request_result.raise_for_status()
            except Exception as e:
                _logger.exception('Geocoding error')
                raise exceptions.Warning(
                    _('Geocoding error. \n %s') % e.message)
            vals = request_result.json()
            vals = vals and vals[0] or {}
            partner.write({
                'partner_latitude': vals.get('lat'),
                'partner_longitude': vals.get('lon'),
                'date_localization': fields.Date.today()
            })

    @api.multi
    def geo_localize(self):
        self.geocode_address()
        return True

    @api.multi
    @api.depends('partner_latitude', 'partner_longitude')
    def _get_geo_point(self):
        """
        Set the `geo_point` of the partner depending of its `partner_latitude`
        and its `partner_longitude`
        **Notes**
        If one of those parameters is not set then reset the partner's
        geo_point and do not recompute it
        """
        for partner in self:
            if not partner.partner_latitude or not partner.partner_longitude:
                partner.geo_point = False
            else:
                partner.geo_point = geo_fields.GeoPoint.from_latlon(
                    partner.env.cr, partner.partner_latitude,
                    partner.partner_longitude)

    geo_point = geo_fields.GeoPoint(readonly=True,
                                    store=True,
                                    compute='_get_geo_point')
Beispiel #18
0
class luminarias(geo_model.GeoModel):
    _name = 'alumbrado.luminarias'
    _rec_name = 'xap_comp'

    xap_comp = fields.Char(string="Código compuesto")
    xap = fields.Integer(string="Código de la luminaría")
    cvecol = fields.Many2one('alumbrado.colonias',string="Clave de la colonia")
    cvecalle = fields.Char(string="Codigo de la calle")
    calle = fields.Char(string="Calle")
    tipo_c = fields.Char(string="tipo de calle")
    entre = fields.Char(string="entre que calles")
    t_piso = fields.Char(string="tipo de piso")
    nivel_c = fields.Char(string="nivel de la calle")
    ancho_c = fields.Char(string="ancho de la calle")
    mod_lam = fields.Char(string="modelo de la lampara")
    tecno = fields.Char(string="tecnologia led, vs, fluoresente")
    capac_pot = fields.Char(string="capacidad de potencia watts")
    marca_foco = fields.Char(string="marca de foco")
    marca_bala = fields.Char(string="marca de balastra")
    #perdidas = fields.Integer(string="datod e perdidas de energia")
    tension = fields.Char(string="tension baja o alta")
    #tipodeilum = fields.Char(string="tipo de iluminacion")
    zona_cfe = fields.Char(string="zona de cfe")
    tipoposte = fields.Char(string="tipo de poste")
    no_lum = fields.Float(string="numero de luminarios en el poste")
    altura_p = fields.Float(string="altura del poste")
    altura_lum = fields.Char(string="altura del luminario")
    brazo = fields.Char(string="numero de brazos en el poste")
    #jefe_cua = fields.Char(string="jefe de cuadrilla")
    #unidad = fields.Integer(string="numero de vehiculo")
    fecha_cens = fields.Date(string="fecha del censo")
    imagen = fields.Char(string="imagen de los luminarios")
    x = fields.Float(string="Coordenada X")
    y = fields.Float(string="Coordenada Y")
    observ = fields.Char(string="observaciones del poste, poda o limunario")
    servicio = fields.Char(string="tipo de servicio de cfe medido o estimado")
    rpu = fields.Char(string="numero de rpu cfe")
    medidor = fields.Char(string="numero de medidor cfe")
    geom = geo_fields.GeoPoint(string='Punto', srid=4326)
    name = fields.Char('Serial number', size=64, required=True)

    def genera_cod_comp(self):
        self.xap_comp = self.cvecol + self.xap

    def ConvertGeoJson(self, gjson, from_srid=4326, to_srid=3857):
        """
        H.Stivalet 2019-09-25
        Convierte el tipo de proyección en formato GeoJson usando funciones de PostGis. Requiere que la Base de datos de Odoo tenga instalada la estención de PosyGis
        params:
            gjson(str): GeoJson de un Point, Line o Polygon
            from_srid(int): SRID de entrada
            to_srid(int): SRID de salida
        returns: (str) GeoJson con la nueva proyección del Point, Line o Polygon
        """
        if not isinstance(gjson, str) or gjson == '':
            return ''
        query = "select ST_AsGeoJSON(st_transform(st_setsrid(st_geomfromgeojson('" + gjson + "')," + str(from_srid) + ")," + str(to_srid) + "))"
        self._cr.execute(query)
        data = self._cr.fetchone()
        if data:
            gjson = data[0]
        return gjson

    @api.model#necesita hacer algo en el nivel del modelo en sí, no solo algunos registros. #api.model para estructuras de modelos, métodos auxiliares, etc.
    def create(self, values):
        if 'geom' in values and values['geom'] != '':
            values['geom'] = self.ConvertGeoJson(values['geom'], 3857, 4326)
        return super(luminarias, self).create(values)

    @api.multi#api.multi se usa para funciones en las que desea realizar alguna operación en uno o varios registros. Un ejemplo aquí puede ser establecer un campo en múltiples registros:
    def write(self, values):
        if 'geom' in values and values['aggeomeb_polygon'] != '':
            values['geom'] = self.ConvertGeoJson(values['geom'], 3857, 4326)
        return super(luminarias, self).write(values)

    @api.multi
    def read(self, fields=None, load='_classic_read'):
        record = super(luminarias, self).read(fields, load=load)
        if len(record) == 1 and 'geom' in record[0] and record[0]['ageb_polygon'] != '':
            record[0]['geom'] = self.ConvertGeoJson(record[0]['geom'])
        return record
Beispiel #19
0
class FSMLocation(geo_model.GeoModel):
    _name = 'fsm.location'
    _inherits = {'res.partner': 'partner_id'}
    _description = 'Field Service Location'

    @api.model
    def _tz_get(self):
        return [(tz, tz)
                for tz in sorted(pytz.all_timezones,
                                 key=lambda tz: tz
                                 if not tz.startswith('Etc/') else '_')]

    direction = fields.Char(string='Directions')
    partner_id = fields.Many2one('res.partner',
                                 string='Related Partner',
                                 required=True,
                                 ondelete='restrict',
                                 delegate=True,
                                 auto_join=True)
    owner_id = fields.Many2one('res.partner',
                               string='Related Owner',
                               required=True,
                               ondelete='restrict',
                               auto_join=True)
    customer_id = fields.Many2one('res.partner',
                                  string='Billed Customer',
                                  required=True,
                                  ondelete='restrict',
                                  auto_join=True)
    contact_id = fields.Many2one('res.partner',
                                 string='Primary Contact',
                                 ondelete='restrict',
                                 auto_join=True)
    tag_ids = fields.Many2many('fsm.tag', string='Tags')
    description = fields.Char(string='Description')
    territory_id = fields.Many2one('fsm.territory', string='Territory')
    branch_id = fields.Many2one('fsm.branch', string='Branch')
    district_id = fields.Many2one('fsm.district', string='District')
    region_id = fields.Many2one('fsm.region', string='Region')
    territory_manager_id = fields.Many2one(string='Primary Assignment',
                                           related='territory_id.person_id')
    district_manager_id = fields.Many2one(string='District Manager',
                                          related='district_id.partner_id')
    region_manager_id = fields.Many2one(string='Region Manager',
                                        related='region_id.partner_id')
    branch_manager_id = fields.Many2one(string='Branch Manager',
                                        related='branch_id.partner_id')

    timezone = fields.Selection(_tz_get, string='Timezone')

    parent_id = fields.Many2one('fsm.location', string='Parent')
    notes = fields.Text(string="Notes")
    person_ids = fields.Many2many('fsm.person',
                                  'partner_id',
                                  string='Preferred Workers')

    # Geometry Field
    shape = geo_fields.GeoPoint(string='Coordinate')

    @api.model
    def create(self, vals):
        vals.update({'fsm_location': True})
        return super(FSMLocation, self).create(vals)

    @api.onchange('territory_id')
    def _onchange_territory_id(self):
        self.branch_id = self.territory_id.branch_id

    @api.onchange('branch_id')
    def _onchange_branch_id(self):
        self.district_id = self.branch_id.district_id

    @api.onchange('district_id')
    def _onchange_district_id(self):
        self.region_id = self.district_id.region_id
Beispiel #20
0
class ResPartner(geo_model.GeoModel):
    """Add geo_point to partner using a function filed"""
    _inherit = "res.partner"

    geo_point = fields.GeoPoint("Address coordinates")