Files
odoo_source/addons/mail/models/ir_attachment.py
T
Maximilien (malb) d6d468e5f1 [IMP] hr_expense: readability expense receipts
The goal of this PR is to improve the readability of expense receipts on
hr_expense and hr_expense_sheet.
This PR do the following:
- Add the expense name next to the filename
- Vertically center the receipt on both model (was previously done in hr_expense
 but not for the sheet)
- Make sure the title doesn't get hidden by the image (was previously done in
hr_expense but not for the sheet)

Also, to achieve the first point we had to modify the attachment so that we can
retrieve easily the information of which line the attachment is attached.

closes odoo/odoo#130181

Task: 3443067
Signed-off-by: William André (wan) <wan@odoo.com>
2023-09-07 16:16:04 +00:00

95 lines
4.3 KiB
Python

# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import contextlib
from odoo import _, api, models, SUPERUSER_ID
from odoo.exceptions import AccessError, MissingError, UserError
from odoo.http import request
from odoo.tools import consteq
class IrAttachment(models.Model):
_inherit = 'ir.attachment'
def _check_attachments_access(self, attachment_tokens):
"""This method relies on access rules/rights and therefore it should not be called from a sudo env."""
self = self.sudo(False)
attachment_tokens = attachment_tokens or ([None] * len(self))
if len(attachment_tokens) != len(self):
raise UserError(_("An access token must be provided for each attachment."))
for attachment, access_token in zip(self, attachment_tokens):
try:
attachment_sudo = attachment.with_user(SUPERUSER_ID).exists()
if not attachment_sudo:
raise MissingError(_("The attachment %s does not exist.", attachment.id))
try:
attachment.check('write')
except AccessError:
if not access_token or not attachment_sudo.access_token or not consteq(attachment_sudo.access_token, access_token):
message_sudo = self.env['mail.message'].sudo().search([('attachment_ids', 'in', attachment_sudo.ids)], limit=1)
if not message_sudo or not message_sudo.is_current_user_or_guest_author:
raise
except (AccessError, MissingError):
raise UserError(_("The attachment %s does not exist or you do not have the rights to access it.", attachment.id))
def _post_add_create(self, **kwargs):
""" Overrides behaviour when the attachment is created through the controller
"""
super(IrAttachment, self)._post_add_create(**kwargs)
for record in self:
record.register_as_main_attachment(force=False)
def register_as_main_attachment(self, force=True):
""" Registers this attachment as the main one of the model it is
attached to.
:param bool force: if set, the method always updates the existing main attachment
otherwise it only sets the main attachment if there is none.
"""
self.ensure_one()
if not self.res_model or not self.res_id:
return
related_record = self.env[self.res_model].browse(self.res_id)
if not related_record or \
not related_record.check_access_rights('write', raise_exception=False) or \
not hasattr(related_record, 'message_main_attachment_id'):
return
if force or not related_record.message_main_attachment_id:
with contextlib.suppress(AccessError):
related_record.message_main_attachment_id = self
def _delete_and_notify(self, message=None):
if message:
message.write({}) # to make sure write_date on the message is updated
self.env['bus.bus']._sendmany((attachment._bus_notification_target(), 'ir.attachment/delete', {
'id': attachment.id, 'message': {'id': message.id, 'write_date': message.write_date} if message else None
}) for attachment in self)
self.unlink()
def _bus_notification_target(self):
self.ensure_one()
return self.env.user.partner_id
def _attachment_format(self):
safari = request and request.httprequest.user_agent and request.httprequest.user_agent.browser == 'safari'
return [{
'checksum': attachment.checksum,
'create_date': attachment.create_date,
'id': attachment.id,
'filename': attachment.name,
'name': attachment.name,
"size": attachment.file_size,
'res_name': attachment.res_name,
'mimetype': 'application/octet-stream' if safari and attachment.mimetype and 'video' in attachment.mimetype else attachment.mimetype,
'originThread': [('insert', {
'id': attachment.res_id,
'model': attachment.res_model,
})],
} for attachment in self]
@api.model
def _get_upload_env(self, thread_model, thread_id):
return request.env