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>
95 lines
4.3 KiB
Python
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
|