Files
repair/odoo/addons/dsrpt_address_book/models/dsrpt_contact.py

333 lines
13 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# -*- coding: utf-8 -*-
from odoo import models, fields, api
class Contact(models.Model):
_name = 'dsrpt.contact'
_description = 'Contact'
_inherit = ['mail.thread', 'mail.activity.mixin']
_rec_name = 'name'
_order = 'create_date desc, name'
name = fields.Char(string='Name', required=True, tracking=True)
display_name = fields.Char(string='Display Name') # Will be computed in realty_sales module
active = fields.Boolean(string='Active', default=True, tracking=True)
status = fields.Selection([
('awaiting_qualification', 'Awaiting Qualification'),
('not_customer', 'Not a Customer'),
('supplier', 'Supplier'),
('has_request', 'Has Request'),
('has_contract', 'Has Contract'),
('potential_investor', 'Potential Investor'),
('cancelled', 'Cancelled')
], string='Status', default='awaiting_qualification', tracking=True, help='Contact processing status for AI analysis')
user_id = fields.Many2one('res.users', string='Responsible', tracking=True)
source_id = fields.Many2one('contact.source', string='Source', tracking=True)
qualification_date = fields.Datetime(string='Qualification Date', tracking=True, help='When contact was qualified')
communication_ids = fields.One2many(
'dsrpt.contact.communication',
'contact_id',
string='Communications'
)
note = fields.Text(string='Note')
# Relations
event_ids = fields.One2many(
'contact.event',
'contact_id',
string='Events'
)
# call_ids moved to dsrpt_calls module to avoid circular dependencies
# Computed fields
event_count = fields.Integer(
string='Events',
compute='_compute_event_count'
)
phone_numbers = fields.Char(
string='Phone Numbers',
compute='_compute_phone_numbers',
store=True
)
next_contact = fields.Datetime(
string='Next Contact',
tracking=True,
help='Date of the nearest planned event'
)
# call_count moved to dsrpt_calls module
@api.depends('event_ids')
def _compute_event_count(self):
"""Counts the number of events"""
for record in self:
record.event_count = len(record.event_ids)
@api.depends('communication_ids.value', 'communication_ids.communication_type_id')
def _compute_phone_numbers(self):
"""Extracts all phone numbers for search functionality"""
for record in self:
phones = record.communication_ids.filtered(
lambda c: c.communication_type_id.code == 'phone'
).mapped('value')
record.phone_numbers = ', '.join(phones) if phones else ''
def _update_next_contact(self, date_value=None):
"""Update next_contact field with provided date"""
for record in self:
if date_value is not None:
record.next_contact = date_value
# _compute_call_count moved to dsrpt_calls module
def action_view_events(self):
"""Opens contact events"""
self.ensure_one()
return {
'name': 'Events',
'type': 'ir.actions.act_window',
'res_model': 'contact.event',
'view_mode': 'list,form',
'domain': [('contact_id', '=', self.id)],
'context': {'default_contact_id': self.id}
}
def action_qualify(self):
"""Action to trigger qualification for selected contacts"""
qualified_count = 0
no_calls_count = 0
already_qualified_count = 0
for contact in self:
# Skip if already qualified (status not 'awaiting_qualification')
if contact.status != 'awaiting_qualification':
already_qualified_count += 1
continue
# Find last call with transcription for this contact
last_call = self.env['dsrpt_calls.call'].search([
('contact_id', '=', contact.id),
('transcription', '!=', False)
], order='date_start desc', limit=1)
if last_call:
# Send on_need_qualification event directly to contact
contact._event('on_need_qualification').notify(contact)
qualified_count += 1
else:
no_calls_count += 1
# Build notification message
message_parts = []
if qualified_count:
message_parts.append(f"{qualified_count} contacts queued for qualification")
if no_calls_count:
message_parts.append(f"{no_calls_count} contacts have no calls with transcription")
if already_qualified_count:
message_parts.append(f"{already_qualified_count} contacts already qualified")
return {
'type': 'ir.actions.client',
'tag': 'display_notification',
'params': {
'title': 'Qualification Process',
'message': '. '.join(message_parts) if message_parts else 'No contacts to qualify',
'type': 'success' if qualified_count else 'info',
'sticky': False,
}
}
def action_view_calls(self):
"""Opens contact calls"""
self.ensure_one()
return {
'name': 'Calls',
'type': 'ir.actions.act_window',
'res_model': 'dsrpt_calls.call',
'view_mode': 'list,form',
'domain': [('contact_id', '=', self.id)],
'context': {'default_contact_id': self.id}
}
def name_get(self):
result = []
for record in self:
# Найти предпочитаемый способ связи
preferred = record.communication_ids.filtered('is_preferred')
if preferred:
name = f"{record.name} ({preferred[0].value})"
else:
name = record.name
result.append((record.id, name))
return result
def action_view_telegram_card(self):
"""Open telegram card editing form"""
self.ensure_one()
base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url', 'http://localhost:8069')
card_url = f"{base_url}/telegram/contact-card/{self.id}"
return {
'type': 'ir.actions.act_url',
'url': card_url,
'target': 'new',
}
def _process_name_suggestion_from_call(self, call_record):
"""Queue job method to process name suggestion from call transcription"""
import logging
_logger = logging.getLogger(__name__)
if not call_record.transcription:
_logger.warning(f"No transcription available for call {call_record.id}")
return
# Get AI collection and component
collection = self.env['dsrpt.ai.collection'].search([], limit=1)
if not collection:
_logger.error("No AI collection found")
return
work = collection.work_on(model_name='field.change.suggestion')
ai_component = work.component(usage='field.change.suggestion')
# Get suggested name from AI
suggested_name = ai_component.suggest_name_from_transcription(call_record.transcription)
# Only create suggestion if AI returned a valid name
if suggested_name and suggested_name not in ['Не определено', 'Undefined', '', False, 'Unknown']:
# Find telegram user for notification
telegram_user = self._find_telegram_user_for_suggestions()
# Create field suggestion with AI result
suggestion_vals = {
'res_model': 'dsrpt.contact',
'res_id': self.id,
'field_name': 'name',
'current_value': self.name,
'suggested_value': suggested_name,
'telegram_user_id': telegram_user.id if telegram_user else None
}
suggestion = self.env['field.change.suggestion'].create(suggestion_vals)
_logger.info(f"Created name suggestion {suggestion.id} with value '{suggested_name}' for contact {self.id}")
else:
_logger.info(f"AI did not return valid name suggestion for contact {self.id}, skipping")
def _find_telegram_user_for_suggestions(self):
"""Find telegram user for notifications"""
telegram_user = None
# Priority: contact owner > first admin user
if hasattr(self, 'user_id') and self.user_id:
telegram_user = self.env['telegram.user'].search([
('odoo_user_id', '=', self.user_id.id),
('active', '=', True)
], limit=1)
if not telegram_user:
# Find first active telegram admin user
telegram_user = self.env['telegram.user'].search([
('active', '=', True)
], limit=1)
return telegram_user
def _process_note_suggestion_from_context(self, context_record):
"""Queue job method to process note suggestion from contact history"""
import logging
_logger = logging.getLogger(__name__)
# Get AI collection and component
collection = self.env['dsrpt.ai.collection'].search([], limit=1)
if not collection:
_logger.error("No AI collection found")
return
work = collection.work_on(model_name='field.change.suggestion')
ai_component = work.component(usage='field.change.suggestion')
# Gather contact history for AI
history = self._gather_contact_history_for_ai()
# Get suggested summary from AI
suggested_summary = ai_component.suggest_summary_from_history(history)
# Only create suggestion if AI returned a valid summary
if suggested_summary and suggested_summary not in ['Не определено', 'Undefined', '', False]:
# Find telegram user for notification
telegram_user = self._find_telegram_user_for_suggestions()
# Create field suggestion with AI result
suggestion_vals = {
'res_model': 'dsrpt.contact',
'res_id': self.id,
'field_name': 'note',
'current_value': self.note or '',
'suggested_value': suggested_summary,
'telegram_user_id': telegram_user.id if telegram_user else None
}
suggestion = self.env['field.change.suggestion'].create(suggestion_vals)
_logger.info(f"Created note suggestion {suggestion.id} with summary for contact {self.id}")
else:
_logger.info(f"AI did not return valid note suggestion for contact {self.id}, skipping")
def _gather_contact_history_for_ai(self):
"""Gather contact history for summary generation"""
history_parts = []
# Add contact basic info
history_parts.append(f"Contact: {self.name}")
# Add communications
for comm in self.communication_ids:
history_parts.append(f"{comm.communication_type_id.name}: {comm.value}")
# Add recent calls if module is installed
if 'dsrpt_calls.call' in self.env:
calls = self.env['dsrpt_calls.call'].search([
('contact_id', '=', self.id)
], limit=5, order='date_start desc')
for call in calls:
history_parts.append(f"Call {call.date_start}: {call.duration} sec")
if call.transcription:
history_parts.append(f"Summary: {call.transcription[:200]}...")
return "\n".join(history_parts)
def recompute_next_contact_all(self):
"""Clear next_contact for all contacts (simplified logic)"""
all_contacts = self.env['dsrpt.contact'].search([])
all_contacts._update_next_contact(None)
return {
'type': 'ir.actions.client',
'tag': 'display_notification',
'params': {
'title': 'Reset Completed',
'message': f'"Next Contact" cleared for {len(all_contacts)} contacts',
'type': 'success',
'sticky': False,
}
}
def write(self, vals):
"""Override write to automatically set qualification_date when status changes"""
# Check if status is being changed
if 'status' in vals:
for record in self:
old_status = record.status
new_status = vals['status']
# If changing FROM awaiting_qualification TO any other status
if (old_status == 'awaiting_qualification' and
new_status != 'awaiting_qualification' and
not record.qualification_date):
# Set qualification date automatically
vals['qualification_date'] = fields.Datetime.now()
return super().write(vals)