903 lines
38 KiB
Python
903 lines
38 KiB
Python
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
|
|
from odoo import http, _
|
|
from odoo.http import request
|
|
from odoo.addons.portal.controllers.portal import CustomerPortal, pager as portal_pager
|
|
from odoo.exceptions import AccessError, ValidationError
|
|
from odoo.osv import expression
|
|
import logging
|
|
|
|
_logger = logging.getLogger(__name__)
|
|
|
|
class PortalPartnerController(CustomerPortal):
|
|
|
|
def _log_portal_activity(self, record, action, details, user_id=None):
|
|
"""
|
|
Méthode utilitaire pour journaliser les activités du portail avec l'adresse IP
|
|
|
|
:param record: Enregistrement sur lequel journaliser l'activité
|
|
:param action: Type d'action (view, edit, create, etc.)
|
|
:param details: Détails de l'action
|
|
:param user_id: ID de l'utilisateur (par défaut, l'utilisateur connecté)
|
|
:return: L'entrée de journal créée
|
|
"""
|
|
if not user_id:
|
|
user_id = request.env.user.id
|
|
|
|
# Récupérer l'adresse IP
|
|
ip = request.httprequest.remote_addr
|
|
|
|
return record.sudo().log_portal_activity(
|
|
user_id=user_id,
|
|
action=action,
|
|
details=details,
|
|
ip=ip
|
|
)
|
|
|
|
def _prepare_portal_layout_values(self):
|
|
"""
|
|
Add values to the portal layout
|
|
"""
|
|
values = super(PortalPartnerController, self)._prepare_portal_layout_values()
|
|
|
|
# Get the connected user's partner
|
|
partner = request.env.user.partner_id
|
|
|
|
# Add a variable to know if the user has a parent company
|
|
values['has_company'] = bool(partner.parent_id)
|
|
|
|
# Check if the partner has a parent company
|
|
parent_company = partner.parent_id
|
|
if parent_company and parent_company.is_company:
|
|
values['parent_company'] = parent_company
|
|
|
|
# Count the number of contacts
|
|
contact_count = len(parent_company.get_portal_children())
|
|
values['contact_count'] = contact_count
|
|
|
|
Partner = request.env['res.partner']
|
|
|
|
return values
|
|
|
|
@http.route(['/my/company'], type='http', auth="user", website=True)
|
|
def portal_my_company(self, **kw):
|
|
"""
|
|
Display the parent company information
|
|
"""
|
|
values = self._prepare_portal_layout_values()
|
|
|
|
# Check if the user has a parent company
|
|
partner = request.env.user.partner_id
|
|
parent_company = partner.parent_id
|
|
|
|
if not parent_company or not parent_company.is_company:
|
|
return request.redirect('/my')
|
|
|
|
# Check if the user has the right to edit the company
|
|
can_edit = parent_company.allow_portal_parent_edit
|
|
values['can_edit'] = can_edit
|
|
|
|
# Get the company information
|
|
values['company'] = parent_company
|
|
|
|
# Get countries for the selection fields
|
|
countries = request.env['res.country'].sudo().search([])
|
|
# Get ALL states (will be filtered in the template by country)
|
|
states = request.env['res.country.state'].sudo().search([])
|
|
# Log country for debugging
|
|
if parent_company.country_id:
|
|
_logger.info("%s found: %r ", parent_company.country_id.name, parent_company.country_id)
|
|
# Also log the provinces of that country
|
|
provinces = states.filtered(lambda s: s.country_id == parent_company.country_id)
|
|
_logger.info("Provinces found: %r", provinces)
|
|
values.update({
|
|
'countries': countries,
|
|
'states': states,
|
|
})
|
|
|
|
# Get contacts for the kanban view (including archived ones)
|
|
Contact = request.env['res.partner']
|
|
base_domain = [('parent_id', '=', parent_company.id)]
|
|
|
|
# Include archived contacts
|
|
base_domain = expression.AND([base_domain, ['|', ('active', '=', True), ('active', '=', False)]])
|
|
|
|
# Get contacts (type='contact')
|
|
contact_domain = expression.AND([base_domain, [('type', '=', 'contact')]])
|
|
contacts = Contact.search(contact_domain, order='name asc')
|
|
|
|
# Get other addresses (type != 'contact')
|
|
address_domain = expression.AND([base_domain, [('type', '!=', 'contact')]])
|
|
addresses = Contact.search(address_domain, order='name asc')
|
|
|
|
values.update({
|
|
'contacts': contacts,
|
|
'addresses': addresses,
|
|
})
|
|
|
|
# Journaliser l'accès à la société directement sur l'objet partenaire
|
|
self._log_portal_activity(
|
|
record=parent_company,
|
|
action='view',
|
|
details='User viewed company information via portal'
|
|
)
|
|
|
|
return request.render("portal_partner_manager.portal_my_company", values)
|
|
|
|
@http.route(['/my/company/edit'], type='http', auth="user", website=True)
|
|
def portal_my_company_edit(self, **kw):
|
|
"""
|
|
Display the parent company edit form
|
|
"""
|
|
values = self._prepare_portal_layout_values()
|
|
|
|
# Check if the user has a parent company
|
|
partner = request.env.user.partner_id
|
|
parent_company = partner.parent_id
|
|
|
|
if not parent_company or not parent_company.is_company:
|
|
return request.redirect('/my')
|
|
|
|
# Check if the user has the right to edit the company
|
|
if not parent_company.allow_portal_parent_edit:
|
|
return request.redirect('/my/company')
|
|
|
|
# Get the company information
|
|
values['company'] = parent_company
|
|
|
|
# Get countries for the selection fields
|
|
countries = request.env['res.country'].sudo().search([])
|
|
# Get ALL states (will be filtered in the template by country)
|
|
states = request.env['res.country.state'].sudo().search([])
|
|
# Log country for debugging
|
|
if parent_company.country_id:
|
|
_logger.info("%s found: %r ", parent_company.country_id.name, parent_company.country_id)
|
|
# Also log the provinces of that country
|
|
provinces = states.filtered(lambda s: s.country_id == parent_company.country_id)
|
|
_logger.info("Provinces found: %r", provinces)
|
|
values.update({
|
|
'countries': countries,
|
|
'states': states,
|
|
})
|
|
|
|
return request.render("portal_partner_manager.portal_my_company_edit", values)
|
|
|
|
@http.route(['/my/company/update'], type='http', auth="user", methods=['POST'], website=True)
|
|
def portal_my_company_update(self, **kw):
|
|
"""
|
|
Update the parent company information
|
|
"""
|
|
# Check if the user has a parent company
|
|
partner = request.env.user.partner_id
|
|
parent_company = partner.parent_id
|
|
|
|
if not parent_company or not parent_company.is_company:
|
|
return request.redirect('/my')
|
|
|
|
# Check if the user has the right to edit the company
|
|
if not parent_company.allow_portal_parent_edit:
|
|
return request.redirect('/my/company')
|
|
|
|
# Prepare the values to update
|
|
vals = {}
|
|
allowed_fields = parent_company._get_portal_allowed_fields()
|
|
|
|
for field in allowed_fields:
|
|
if field in kw:
|
|
# Special handling for many2one fields
|
|
if field in ['state_id', 'country_id']:
|
|
if kw[field] and kw[field].isdigit():
|
|
vals[field] = int(kw[field])
|
|
else:
|
|
vals[field] = kw[field]
|
|
|
|
# Update the company
|
|
try:
|
|
parent_company.write(vals)
|
|
|
|
# Journaliser la modification directement sur l'objet partenaire
|
|
details = ', '.join([f"{field}: {vals[field]}" for field in vals])
|
|
self._log_portal_activity(
|
|
record=parent_company,
|
|
action='edit',
|
|
details=f"Company information updated: {', '.join([f'{field}: {vals[field]}' for field in vals])}"
|
|
)
|
|
|
|
return request.redirect('/my/company?update=success')
|
|
except Exception as e:
|
|
_logger.error("Error while updating company: %s", str(e))
|
|
return request.redirect('/my/company/edit?error=1')
|
|
|
|
@http.route(['/my/contacts', '/my/contacts/page/<int:page>'], type='http', auth="user", website=True)
|
|
def portal_my_contacts(self, page=1, date_begin=None, date_end=None, sortby=None, **kw):
|
|
"""
|
|
Display the list of contacts for the parent company
|
|
"""
|
|
values = self._prepare_portal_layout_values()
|
|
|
|
# Check if the user has a parent company
|
|
partner = request.env.user.partner_id
|
|
parent_company = partner.parent_id
|
|
|
|
if not parent_company or not parent_company.is_company:
|
|
return request.redirect('/my')
|
|
|
|
# Get contacts (including archived ones)
|
|
Contact = request.env['res.partner']
|
|
domain = [('parent_id', '=', parent_company.id)]
|
|
|
|
# Include archived contacts
|
|
domain = expression.AND([domain, ['|', ('active', '=', True), ('active', '=', False)]])
|
|
|
|
# Count the total number of contacts
|
|
contact_count = Contact.search_count(domain)
|
|
|
|
# Pagination
|
|
pager = portal_pager(
|
|
url="/my/contacts",
|
|
url_args={'date_begin': date_begin, 'date_end': date_end, 'sortby': sortby},
|
|
total=contact_count,
|
|
page=page,
|
|
step=self._items_per_page
|
|
)
|
|
|
|
# Sorting
|
|
if sortby == 'name':
|
|
order = 'name asc'
|
|
elif sortby == 'date':
|
|
order = 'create_date desc'
|
|
else:
|
|
order = 'name asc'
|
|
|
|
# Search contacts with pagination
|
|
contacts = Contact.search(
|
|
domain,
|
|
order=order,
|
|
limit=self._items_per_page,
|
|
offset=pager['offset']
|
|
)
|
|
|
|
values.update({
|
|
'contacts': contacts,
|
|
'page_name': 'contacts',
|
|
'pager': pager,
|
|
'default_url': '/my/contacts',
|
|
'sortby': sortby,
|
|
'can_add_contact': parent_company.allow_portal_parent_edit,
|
|
})
|
|
|
|
return request.render("portal_partner_manager.portal_my_contacts", values)
|
|
|
|
@http.route(['/my/contacts/add'], type='http', auth="user", website=True)
|
|
def portal_my_contacts_add(self, **kw):
|
|
"""
|
|
Display the form to add a new contact
|
|
"""
|
|
values = self._prepare_portal_layout_values()
|
|
|
|
# Check if the user has a parent company
|
|
partner = request.env.user.partner_id
|
|
parent_company = partner.parent_id
|
|
|
|
if not parent_company or not parent_company.is_company:
|
|
return request.redirect('/my')
|
|
|
|
# Check if the user has the right to add contacts
|
|
if not parent_company.allow_portal_parent_edit:
|
|
return request.redirect('/my/contacts')
|
|
|
|
# Get countries for selection fields
|
|
countries = request.env['res.country'].sudo().search([])
|
|
|
|
# Get only Canadian provinces
|
|
canada = request.env['res.country'].sudo().search([('code', '=', 'CA')], limit=1)
|
|
_logger.info('Canada found: %s', canada)
|
|
canadian_provinces = request.env['res.country.state'].sudo().search([('country_id', '=', canada.id)])
|
|
_logger.info('Provinces found: %s', canadian_provinces)
|
|
|
|
values.update({
|
|
'countries': countries,
|
|
'canadian_provinces': canadian_provinces,
|
|
'company': parent_company,
|
|
})
|
|
|
|
return request.render("portal_partner_manager.portal_my_contacts_add", values)
|
|
|
|
@http.route(['/my/contacts/create'], type='http', auth="user", methods=['POST'], website=True)
|
|
def portal_my_contacts_create(self, **kw):
|
|
"""
|
|
Create a new contact for the parent company
|
|
"""
|
|
# Check if the user has a parent company
|
|
partner = request.env.user.partner_id
|
|
parent_company = partner.parent_id
|
|
|
|
if not parent_company or not parent_company.is_company:
|
|
return request.redirect('/my')
|
|
|
|
# Check if the user has the right to add contacts
|
|
if not parent_company.allow_portal_parent_edit:
|
|
return request.redirect('/my/contacts')
|
|
|
|
# Check if email is provided
|
|
if not kw.get('email'):
|
|
return request.redirect('/my/contacts/add?error=email_required')
|
|
|
|
# Prepare values for creation
|
|
vals = {}
|
|
allowed_fields = parent_company._get_portal_allowed_fields()
|
|
|
|
for field in allowed_fields:
|
|
if field in kw:
|
|
# Special handling for many2one fields
|
|
if field in ['state_id', 'country_id']:
|
|
if kw[field] and kw[field].isdigit():
|
|
vals[field] = int(kw[field])
|
|
else:
|
|
vals[field] = kw[field]
|
|
|
|
# Handle contact type
|
|
if 'type' in kw and kw.get('type') in ['contact', 'invoice', 'delivery', 'origin', 'other']:
|
|
vals['type'] = kw.get('type')
|
|
else:
|
|
vals['type'] = 'contact' # Default type
|
|
|
|
# Validate email for contact type
|
|
if vals.get('type') == 'contact' and not vals.get('email'):
|
|
return request.redirect('/my/company?error_message=' + _('Email is required for Contact type'))
|
|
|
|
# Create the contact
|
|
try:
|
|
new_contact = parent_company.create_portal_contact(parent_company.id, vals)
|
|
|
|
# Journaliser l'ajout directement sur la société parente
|
|
details = f"New contact: {new_contact.name} ({new_contact.email})"
|
|
self._log_portal_activity(
|
|
record=parent_company,
|
|
action='create',
|
|
details=details
|
|
)
|
|
|
|
# Journaliser également sur le nouveau contact
|
|
self._log_portal_activity(
|
|
record=new_contact,
|
|
action='create',
|
|
details=f"Contact created under {parent_company.name}"
|
|
)
|
|
|
|
return request.redirect('/my/company?create=success')
|
|
except Exception as e:
|
|
_logger.error("Error while creating contact: %s", str(e))
|
|
return request.redirect('/my/contacts/add?error=1')
|
|
|
|
@http.route(['/my/contacts/edit/<int:contact_id>'], type='http', auth="user", website=True)
|
|
def portal_my_contacts_edit(self, contact_id, **kw):
|
|
"""
|
|
Display the form to edit an existing contact
|
|
"""
|
|
values = self._prepare_portal_layout_values()
|
|
|
|
# Check if the user has a parent company
|
|
partner = request.env.user.partner_id
|
|
parent_company = partner.parent_id
|
|
|
|
if not parent_company or not parent_company.is_company:
|
|
return request.redirect('/my')
|
|
|
|
# Check if the user has the right to edit contacts
|
|
if not parent_company.allow_portal_parent_edit:
|
|
return request.redirect('/my/contacts')
|
|
|
|
# Get the contact to edit
|
|
Contact = request.env['res.partner']
|
|
contact = Contact.sudo().browse(contact_id)
|
|
|
|
# Check that the contact belongs to the parent company
|
|
if not contact.exists() or contact.parent_id.id != parent_company.id:
|
|
return request.redirect('/my/contacts')
|
|
|
|
# Get countries for selection fields
|
|
countries = request.env['res.country'].sudo().search([])
|
|
|
|
# Get only Canadian provinces
|
|
canada = request.env['res.country'].sudo().search([('code', '=', 'CA')], limit=1)
|
|
_logger.info('Canada found: %s', canada)
|
|
canadian_provinces = request.env['res.country.state'].sudo().search([('country_id', '=', canada.id)])
|
|
_logger.info('Provinces found: %s', canadian_provinces)
|
|
|
|
values.update({
|
|
'contact': contact,
|
|
'countries': countries,
|
|
'canadian_provinces': canadian_provinces,
|
|
'company': parent_company,
|
|
})
|
|
|
|
return request.render("portal_partner_manager.portal_my_contacts_edit", values)
|
|
|
|
# Helper method to check contact management rights
|
|
def _check_contact_management_rights(self):
|
|
"""Check if the user has the right to manage contacts"""
|
|
partner = request.env.user.partner_id
|
|
parent_company = partner.commercial_partner_id
|
|
|
|
if not parent_company.allow_portal_parent_edit:
|
|
return False
|
|
return parent_company
|
|
|
|
@http.route(['/my/contacts/grant_access/<int:contact_id>'], type='http', auth="user", website=True)
|
|
def portal_my_contacts_grant_access(self, contact_id=None, **kw):
|
|
"""Grant portal access to a contact"""
|
|
if not contact_id:
|
|
return request.redirect('/my/company')
|
|
|
|
# Check management rights
|
|
parent_company = self._check_contact_management_rights()
|
|
if not parent_company:
|
|
return request.redirect('/my/company?error_message=' + _('You do not have permission to manage contacts'))
|
|
|
|
contact = request.env['res.partner'].sudo().browse(contact_id)
|
|
if not contact.exists() or contact.parent_id != request.env.user.partner_id.commercial_partner_id:
|
|
return request.redirect('/my/company')
|
|
|
|
# Check if this is a contact (not an address)
|
|
if contact.type != 'contact':
|
|
return request.redirect('/my/company?error_message=' + _('Only contacts can be granted portal access'))
|
|
|
|
# Check if user already has portal access
|
|
if contact.user_ids:
|
|
# Reset password instead
|
|
try:
|
|
contact.user_ids[0].action_reset_password()
|
|
return request.redirect('/my/company?success_message=' + _('Password reset email sent'))
|
|
except Exception as e:
|
|
_logger.error("Error while resetting password: %s", str(e))
|
|
return request.redirect('/my/company?error_message=' + _('Failed to reset password'))
|
|
|
|
# Create portal user
|
|
try:
|
|
# Generate a random password
|
|
password = self._generate_password()
|
|
|
|
# Check if a user with this email already exists
|
|
Users = request.env['res.users']
|
|
existing_user = Users.sudo().search([('login', '=', contact.email)], limit=1)
|
|
archived_user = Users.sudo().search([('login', '=', contact.email), ('active', '=', False)], limit=1)
|
|
|
|
if existing_user and existing_user.active:
|
|
# Active user with same login exists
|
|
return request.redirect('/my/company?error_message=' + _('A user with this email already exists'))
|
|
elif archived_user:
|
|
# Reactivate the archived user and reassign it to this partner
|
|
user = archived_user
|
|
user.sudo().write({
|
|
'active': True,
|
|
'partner_id': contact.id,
|
|
'email': contact.email,
|
|
'name': contact.name,
|
|
'groups_id': [(6, 0, [request.env.ref('base.group_portal').id])]
|
|
})
|
|
else:
|
|
# Create a new portal user
|
|
user_values = {
|
|
'partner_id': contact.id,
|
|
'login': contact.email,
|
|
'email': contact.email,
|
|
'name': contact.name,
|
|
'groups_id': [(6, 0, [request.env.ref('base.group_portal').id])]
|
|
}
|
|
user = Users.sudo().create(user_values)
|
|
|
|
# Journaliser l'action sur le contact
|
|
details = f"Portal access granted to: {contact.name} ({contact.email})"
|
|
self._log_portal_activity(
|
|
record=contact,
|
|
action='grant_access',
|
|
details=details
|
|
)
|
|
|
|
# Journaliser également sur la société parente
|
|
self._log_portal_activity(
|
|
record=parent_company,
|
|
action='grant_access',
|
|
details=f"Granted portal access to contact: {contact.name}"
|
|
)
|
|
|
|
# Ajouter des détails supplémentaires dans le log du contact pour inclure l'information sur l'utilisateur
|
|
self._log_portal_activity(
|
|
record=contact,
|
|
action='create_user',
|
|
details=f"Portal user {user.login} created/updated for this contact"
|
|
)
|
|
|
|
# For new users, send an invitation email
|
|
# For reactivated users, redirect to set password page
|
|
is_new_user = not archived_user
|
|
|
|
if is_new_user:
|
|
# Send invitation email for new users
|
|
try:
|
|
user.sudo().with_context(create_user=True).action_reset_password()
|
|
return request.redirect('/my/contacts?success=invitation_sent')
|
|
except Exception as e:
|
|
_logger.error("Error sending invitation email: %s", str(e))
|
|
return request.redirect('/my/contacts?error=invitation_failed')
|
|
else:
|
|
# Redirect to set password page for reactivated users
|
|
return request.redirect(f'/my/contacts/set_password_form/{contact_id}')
|
|
except Exception as e:
|
|
_logger.error("Error while granting portal access: %s", str(e))
|
|
return request.redirect('/my/contacts?error=grant_access')
|
|
|
|
@http.route(['/my/contacts/set_password_form/<int:contact_id>'], type='http', auth="user", website=True)
|
|
def portal_my_contacts_set_password_form(self, contact_id, **kw):
|
|
"""
|
|
Display the form to set a password for a contact's portal user
|
|
"""
|
|
values = self._prepare_portal_layout_values()
|
|
|
|
# Check if the user has a parent company
|
|
partner = request.env.user.partner_id
|
|
parent_company = partner.parent_id
|
|
|
|
if not parent_company or not parent_company.is_company:
|
|
return request.redirect('/my')
|
|
|
|
# Check if the user has the right to manage contacts
|
|
if not parent_company.allow_portal_parent_edit:
|
|
return request.redirect('/my/contacts')
|
|
|
|
# Get the contact
|
|
Contact = request.env['res.partner']
|
|
contact = Contact.sudo().browse(contact_id)
|
|
|
|
# Check that the contact belongs to the parent company
|
|
if not contact.exists() or contact.parent_id.id != parent_company.id:
|
|
return request.redirect('/my/contacts')
|
|
|
|
# Check if the contact has a user
|
|
if not contact.user_ids:
|
|
return request.redirect('/my/contacts?error=no_user')
|
|
|
|
values.update({
|
|
'contact': contact,
|
|
'company': parent_company,
|
|
})
|
|
|
|
return request.render("portal_partner_manager.portal_set_password", values)
|
|
|
|
@http.route(['/my/contacts/set_password'], type='http', auth="user", methods=['POST'], website=True)
|
|
def portal_my_contacts_set_password(self, **kw):
|
|
"""
|
|
Set a password for a contact's portal user
|
|
"""
|
|
# Check if the user has a parent company
|
|
partner = request.env.user.partner_id
|
|
parent_company = partner.parent_id
|
|
|
|
if not parent_company or not parent_company.is_company:
|
|
return request.redirect('/my')
|
|
|
|
# Check if the user has the right to manage contacts
|
|
if not parent_company.allow_portal_parent_edit:
|
|
return request.redirect('/my/contacts')
|
|
|
|
# Get the contact ID from the form
|
|
contact_id = int(kw.get('contact_id', 0))
|
|
if not contact_id:
|
|
return request.redirect('/my/contacts')
|
|
|
|
# Get the contact
|
|
Contact = request.env['res.partner']
|
|
contact = Contact.sudo().browse(contact_id)
|
|
|
|
# Check that the contact belongs to the parent company
|
|
if not contact.exists() or contact.parent_id.id != parent_company.id:
|
|
return request.redirect('/my/contacts')
|
|
|
|
# Check if the contact has a user
|
|
if not contact.user_ids:
|
|
return request.redirect('/my/contacts?error=no_user')
|
|
|
|
# Get the passwords from the form
|
|
password = kw.get('password')
|
|
confirm_password = kw.get('confirm_password')
|
|
|
|
# Validate the passwords
|
|
if not password or len(password) < 8:
|
|
return request.redirect(f'/my/contacts/set_password_form/{contact_id}?error=password_too_short')
|
|
|
|
if password != confirm_password:
|
|
return request.redirect(f'/my/contacts/set_password_form/{contact_id}?error=password_mismatch')
|
|
|
|
try:
|
|
# Set the password
|
|
user = contact.user_ids[0]
|
|
user.sudo().write({'password': password})
|
|
|
|
# Journaliser l'action sur le contact
|
|
self._log_portal_activity(
|
|
record=contact,
|
|
action='edit',
|
|
details=f"Password set for associated user account"
|
|
)
|
|
|
|
return request.redirect('/my/contacts?password_set=success')
|
|
except Exception as e:
|
|
_logger.error("Error while setting password: %s", str(e))
|
|
return request.redirect(f'/my/contacts/set_password_form/{contact_id}?error=general')
|
|
|
|
@http.route(['/my/contacts/change_status/<int:contact_id>'], type='http', auth="user", website=True)
|
|
def portal_my_contacts_change_status(self, contact_id, status=None, **kw):
|
|
"""
|
|
Change the status of a contact (Portal Access, No Access, Archived)
|
|
|
|
:param contact_id: ID of the contact to change status
|
|
:param status: New status (portal, no_access, archived)
|
|
"""
|
|
# Check if the user has a parent company
|
|
partner = request.env.user.partner_id
|
|
parent_company = partner.parent_id
|
|
|
|
if not parent_company or not parent_company.is_company:
|
|
return request.redirect('/my')
|
|
|
|
# Check if the user has the right to manage contacts
|
|
if not parent_company.allow_portal_parent_edit:
|
|
return request.redirect('/my/contacts')
|
|
|
|
# Get the contact
|
|
Contact = request.env['res.partner']
|
|
contact = Contact.sudo().browse(contact_id)
|
|
|
|
# Check that the contact belongs to the parent company
|
|
if not contact.exists() or contact.parent_id.id != parent_company.id:
|
|
return request.redirect('/my/contacts')
|
|
|
|
# Validate the requested status
|
|
if status not in ['portal', 'no_access', 'archived']:
|
|
return request.redirect('/my/contacts')
|
|
|
|
try:
|
|
# Handle the status change based on the requested status
|
|
# Initialize variables for action details and redirect parameters
|
|
action_details = ""
|
|
redirect_params = ""
|
|
|
|
if status == 'portal':
|
|
# Grant portal access if not already granted
|
|
if not contact.user_ids:
|
|
# Check if email is available
|
|
if not contact.email:
|
|
return request.redirect('/my/contacts?error=email_required')
|
|
|
|
# Check if a user with this email already exists
|
|
Users = request.env['res.users']
|
|
existing_user = Users.sudo().search([('login', '=', contact.email)], limit=1)
|
|
if existing_user:
|
|
return request.redirect('/my/contacts?error=user_exists')
|
|
|
|
# Create the portal user
|
|
user_values = {
|
|
'partner_id': contact.id,
|
|
'login': contact.email,
|
|
'email': contact.email,
|
|
'name': contact.name,
|
|
'groups_id': [(6, 0, [request.env.ref('base.group_portal').id])]
|
|
}
|
|
user = Users.sudo().create(user_values)
|
|
|
|
# Always send an invitation email for new portal users
|
|
try:
|
|
user.sudo().with_context(create_user=True).action_reset_password()
|
|
redirect_params = "status_change=portal_granted&invitation_sent=true"
|
|
except Exception as e:
|
|
_logger.error("Error sending invitation email: %s", str(e))
|
|
redirect_params = "status_change=portal_granted&invitation_failed=true"
|
|
|
|
# Ensure the contact is active
|
|
if not contact.active:
|
|
contact.sudo().write({'active': True})
|
|
|
|
# Log the action
|
|
action_details = "Portal access granted"
|
|
if not redirect_params:
|
|
redirect_params = "status_change=portal_granted"
|
|
|
|
elif status == 'no_access':
|
|
# Remove portal access if granted
|
|
if contact.user_ids:
|
|
# Only handle portal users, not internal users
|
|
portal_users = contact.sudo().user_ids.filtered(
|
|
lambda u: u.has_group('base.group_portal') and not u.has_group('base.group_user'))
|
|
if portal_users:
|
|
# Deactivate the users instead of deleting them to preserve history
|
|
portal_users.sudo().write({'active': False})
|
|
|
|
# Ensure the contact is active
|
|
if not contact.active:
|
|
contact.sudo().write({'active': True})
|
|
|
|
# Log the action
|
|
action_details = "Portal access removed"
|
|
redirect_params = "status_change=access_removed"
|
|
|
|
elif status == 'archived':
|
|
# Check if the contact has active users
|
|
if contact.user_ids:
|
|
active_users = contact.sudo().user_ids.filtered(lambda u: u.active)
|
|
if active_users:
|
|
# Deactivate the users
|
|
portal_users = active_users.filtered(
|
|
lambda u: u.has_group('base.group_portal') and not u.has_group('base.group_user'))
|
|
if portal_users:
|
|
portal_users.sudo().write({'active': False})
|
|
|
|
# Archive the contact
|
|
contact.sudo().write({'active': False})
|
|
|
|
# Log the action
|
|
action_details = "Contact archived"
|
|
redirect_params = "status_change=archived"
|
|
|
|
# Journaliser l'action sur le contact
|
|
details = f"{action_details}: {contact.name} ({contact.email})"
|
|
self._log_portal_activity(
|
|
record=contact,
|
|
action=status,
|
|
details=details
|
|
)
|
|
|
|
# Journaliser également sur la société parente
|
|
self._log_portal_activity(
|
|
record=parent_company,
|
|
action=status,
|
|
details=f"Contact status changed: {contact.name} to {status}"
|
|
)
|
|
|
|
# Si le statut est 'archived', vérifier et journaliser la désactivation des utilisateurs du portail
|
|
if status == 'archived':
|
|
# Rechercher directement les utilisateurs du portail qui ont été affectés
|
|
# sans dépendre de la variable portal_users définie ailleurs
|
|
affected_users = contact.sudo().user_ids.filtered(
|
|
lambda u: not u.active and u.has_group('base.group_portal') and not u.has_group('base.group_user')
|
|
)
|
|
|
|
# Journaliser pour chaque utilisateur affecté
|
|
for affected_user in affected_users:
|
|
contact.sudo().log_portal_activity(
|
|
user_id=request.env.user.id,
|
|
action='archive',
|
|
details=f"User {affected_user.name} deactivated due to contact archival"
|
|
)
|
|
|
|
return request.redirect(f'/my/contacts?{redirect_params}')
|
|
|
|
except Exception as e:
|
|
_logger.error("Error while changing contact status: %s", str(e))
|
|
return request.redirect('/my/contacts?error=status_change')
|
|
|
|
@http.route(['/my/contacts/archive/<int:contact_id>'], type='http', auth="user", website=True)
|
|
def portal_my_contacts_archive(self, contact_id, archive_user=None, **kw):
|
|
"""
|
|
Archive or unarchive a contact (Legacy route, redirects to change_status)
|
|
"""
|
|
# Redirect to the new change_status route
|
|
if archive_user == '1':
|
|
return request.redirect(f'/my/contacts/change_status/{contact_id}?status=archived')
|
|
else:
|
|
# Check the current status to determine the redirect
|
|
Contact = request.env['res.partner']
|
|
contact = Contact.sudo().browse(contact_id)
|
|
|
|
if contact.exists():
|
|
if contact.active:
|
|
return request.redirect(f'/my/contacts/change_status/{contact_id}?status=archived')
|
|
else:
|
|
return request.redirect(f'/my/contacts/change_status/{contact_id}?status=no_access')
|
|
|
|
return request.redirect('/my/contacts')
|
|
|
|
@http.route(['/my/contacts/update'], type='http', auth="user", methods=['POST'], website=True)
|
|
def portal_my_contacts_update(self, **kw):
|
|
"""
|
|
Update an existing contact
|
|
"""
|
|
# Check if the user has a parent company
|
|
partner = request.env.user.partner_id
|
|
parent_company = partner.parent_id
|
|
|
|
if not parent_company or not parent_company.is_company:
|
|
return request.redirect('/my')
|
|
|
|
# Check if the user has the right to edit contacts
|
|
if not parent_company.allow_portal_parent_edit:
|
|
return request.redirect('/my/contacts')
|
|
|
|
# Get the ID of the contact to update
|
|
contact_id = kw.get('contact_id')
|
|
if not contact_id or not contact_id.isdigit():
|
|
return request.redirect('/my/contacts')
|
|
|
|
contact_id = int(contact_id)
|
|
Contact = request.env['res.partner']
|
|
contact = Contact.sudo().browse(contact_id)
|
|
|
|
# Check that the contact belongs to the parent company
|
|
if not contact.exists() or contact.parent_id.id != parent_company.id:
|
|
return request.redirect('/my/contacts')
|
|
|
|
# Prepare the values to update
|
|
vals = {}
|
|
allowed_fields = parent_company._get_portal_allowed_fields()
|
|
|
|
for field in allowed_fields:
|
|
if field in kw:
|
|
# Special handling for many2one fields
|
|
if field in ['state_id', 'country_id']:
|
|
if kw[field] and kw[field].isdigit():
|
|
vals[field] = int(kw[field])
|
|
else:
|
|
vals[field] = kw[field]
|
|
|
|
# Handle contact type
|
|
if 'type' in kw and kw.get('type') in ['contact', 'invoice', 'delivery', 'origin', 'other']:
|
|
vals['type'] = kw.get('type')
|
|
else:
|
|
vals['type'] = 'contact' # Default type
|
|
|
|
# Check if email is being updated
|
|
old_email = contact.email
|
|
email_changed = 'email' in vals and vals['email'] != old_email
|
|
|
|
# Validate email for contact type
|
|
if vals.get('type') == 'contact' and not vals.get('email'):
|
|
return request.redirect('/my/company?error_message=' + _('Email is required for Contact type'))
|
|
|
|
# Update the contact
|
|
try:
|
|
contact.write(vals)
|
|
|
|
# If email changed and contact has a portal user, update the login
|
|
if email_changed and contact.user_ids:
|
|
for user in contact.sudo().user_ids:
|
|
# Only update users in the portal group (not internal users)
|
|
if user.has_group('base.group_portal') and not user.has_group('base.group_user'):
|
|
user.sudo().write({'login': vals['email']})
|
|
_logger.info(f"Updated login for user {user.id} from {old_email} to {vals['email']}")
|
|
|
|
# Journaliser la modification directement sur le contact
|
|
details = ', '.join([f"{field}: {vals[field]}" for field in vals])
|
|
contact.sudo().log_portal_activity(
|
|
user_id=request.env.user.id,
|
|
action='edit',
|
|
details=f"Contact updated via portal: {details}"
|
|
)
|
|
|
|
# Si l'email a changé et qu'un utilisateur a été mis à jour, journaliser l'action pour les utilisateurs affectés
|
|
if email_changed and contact.user_ids:
|
|
# Récupérer tous les utilisateurs du portail associés à ce contact
|
|
portal_users = contact.sudo().user_ids.filtered(
|
|
lambda u: u.has_group('base.group_portal') and not u.has_group('base.group_user')
|
|
)
|
|
# Pour chaque utilisateur affecté, créer une entrée de log sur le contact
|
|
for portal_user in portal_users:
|
|
contact.sudo().log_portal_activity(
|
|
user_id=request.env.user.id,
|
|
action='edit_user',
|
|
details=f"Portal user login updated from {old_email} to {vals['email']} for user {portal_user.name}"
|
|
)
|
|
|
|
return request.redirect('/my/company?update=success')
|
|
except Exception as e:
|
|
_logger.error("Error while updating contact: %s", str(e))
|
|
return request.redirect(f'/my/contacts/edit/{contact_id}?error=1')
|
|
|
|
|
|
|
|
def _generate_password(self, length=12):
|
|
"""Generate a random password"""
|
|
import random
|
|
import string
|
|
chars = string.ascii_letters + string.digits + '!@#$%^&*()'
|
|
return ''.join(random.choice(chars) for _ in range(length))
|