Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions dms/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
# Wizard
"wizards/wizard_dms_file_move_views.xml",
"wizards/wizard_dms_share_views.xml",
"wizards/wizard_dms_dir_record_view.xml",
],
"assets": {
"web.assets_backend": [
Expand Down
17 changes: 13 additions & 4 deletions dms/models/directory.py
Original file line number Diff line number Diff line change
Expand Up @@ -540,10 +540,6 @@
raise ValidationError(
_("A directory has to have model in attachment storage.")
)
if not record.is_root_directory and not record.res_id:
raise ValidationError(
_("This directory needs to be associated to a record.")
)

@api.constrains("is_root_directory", "storage_id")
def _check_directory_storage(self):
Expand Down Expand Up @@ -767,3 +763,16 @@
searchpanel_default_directory_id=self.id,
)
return action

def button_add_res_id(self):
self.ensure_one()
return {

Check warning on line 769 in dms/models/directory.py

View check run for this annotation

Codecov / codecov/patch

dms/models/directory.py#L768-L769

Added lines #L768 - L769 were not covered by tests
# context since 17.0 will be dropped in views
# unless we suffix it's key with _view_ref
"context": {"directory_id_view_ref": self.id},
"name": _("Linked attachments record ID Wizard"),
"view_mode": "form",
"res_model": "wizard.directory.record",
"type": "ir.actions.act_window",
"target": "new",
}
2 changes: 2 additions & 0 deletions dms/security/ir.model.access.csv
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,5 @@ access_security_access_groups_dms_user,access_security_access_groups_dms_user,mo

access_wizard_dms_file_move,access_wizard_dms_file_move,model_wizard_dms_file_move,group_dms_user,1,1,1,1
access_wizard_dms_share,access_wizard_dms_share,model_wizard_dms_share,group_dms_manager,1,1,1,0
access_wizard_directory_record,access_wizard_directory_record,model_wizard_directory_record,group_dms_user,1,1,1,1
access_record_placeholder,access_record_placeholder,model_record_placeholder,group_dms_user,1,1,1,1
10 changes: 10 additions & 0 deletions dms/views/dms_directory.xml
Original file line number Diff line number Diff line change
Expand Up @@ -506,10 +506,20 @@
required="storage_id_save_type == 'attachment'"
/>
<field name="res_model" invisible="1" force_save="1" />
<button
name="button_add_res_id"
type="object"
string="Load Linked attachments record ID"
class="btn btn-link p-0"
invisible="not model_id or
storage_id_save_type != 'attachment' or
(model_id and count_total_files > 0)"
/>
<field
name="res_id"
readonly="True"
invisible="storage_id_save_type != 'attachment'"
required="model_id and not is_root_directory"
/>
<field
name="record_ref"
Expand Down
1 change: 1 addition & 0 deletions dms/wizards/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
from . import wizard_dms_file_move
from . import wizard_dms_share
from . import wizard_dms_dir_record
85 changes: 85 additions & 0 deletions dms/wizards/wizard_dms_dir_record.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# Copyright 2025 Kencove - Mohamed Alkobrosli (https://kencove.com).
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl).

from lxml import etree

from odoo import api, fields, models


class RecordPlaceholder(models.TransientModel):
_name = "record.placeholder"
_description = "A placeholder model to enable virtual relational field res_id"


class WizardDmsDirRecord(models.TransientModel):
_name = "wizard.directory.record"
_description = "Wizard Dms Directory Record ID"

directory_id = fields.Many2one(
comodel_name="dms.directory",
required=True,
string="Directory",
default=lambda self: self.env.context.get("directory_id_view_ref", False),
)
# Just a placeholder field
res_id = fields.Many2one(
"record.placeholder",
string="Linked attachments record ID",
)

def validate(self):
return True

Check warning on line 31 in dms/wizards/wizard_dms_dir_record.py

View check run for this annotation

Codecov / codecov/patch

dms/wizards/wizard_dms_dir_record.py#L31

Added line #L31 was not covered by tests

@api.model_create_multi
def create(self, vals_list):
dir_obj = self.env["dms.directory"]

Check warning on line 35 in dms/wizards/wizard_dms_dir_record.py

View check run for this annotation

Codecov / codecov/patch

dms/wizards/wizard_dms_dir_record.py#L35

Added line #L35 was not covered by tests
for vals in vals_list:
res_id = vals.get("res_id")
dir_id = dir_obj.browse(vals["directory_id"])

Check warning on line 38 in dms/wizards/wizard_dms_dir_record.py

View check run for this annotation

Codecov / codecov/patch

dms/wizards/wizard_dms_dir_record.py#L37-L38

Added lines #L37 - L38 were not covered by tests
# Todo as we can expand with more models for subscribtion like hr etc...
if dir_id.res_model in ["res.partner"]:
if dir_id.res_id and dir_id.res_id != res_id:
dir_id.message_unsubscribe([dir_id.res_id])
subscribers = (

Check warning on line 43 in dms/wizards/wizard_dms_dir_record.py

View check run for this annotation

Codecov / codecov/patch

dms/wizards/wizard_dms_dir_record.py#L42-L43

Added lines #L42 - L43 were not covered by tests
[res_id]
if res_id not in dir_id.sudo().message_partner_ids.ids
else None
)
dir_id.message_subscribe(subscribers)

Check warning on line 48 in dms/wizards/wizard_dms_dir_record.py

View check run for this annotation

Codecov / codecov/patch

dms/wizards/wizard_dms_dir_record.py#L48

Added line #L48 was not covered by tests
# Add the ID for the model
dir_id.write({"res_id": res_id})

Check warning on line 50 in dms/wizards/wizard_dms_dir_record.py

View check run for this annotation

Codecov / codecov/patch

dms/wizards/wizard_dms_dir_record.py#L50

Added line #L50 was not covered by tests
# As the placeholder model is empty
# we should remove its relational virtual field from creation.
del vals["res_id"]
return super().create(vals_list)

Check warning on line 54 in dms/wizards/wizard_dms_dir_record.py

View check run for this annotation

Codecov / codecov/patch

dms/wizards/wizard_dms_dir_record.py#L53-L54

Added lines #L53 - L54 were not covered by tests

@api.model
def get_views(self, views, options=None):
context = self.env.context
res = super().get_views(views, options=options)

Check warning on line 59 in dms/wizards/wizard_dms_dir_record.py

View check run for this annotation

Codecov / codecov/patch

dms/wizards/wizard_dms_dir_record.py#L58-L59

Added lines #L58 - L59 were not covered by tests
if (
"views" in res
and "form" in res["views"]
and context
and context.get("directory_id_view_ref")
):
dir_obj = self.env["dms.directory"]
dir_id = dir_obj.browse(context.get("directory_id_view_ref"))
model = dir_id.model_id
relation = model.model
res["models"][self._name]["fields"].update(

Check warning on line 70 in dms/wizards/wizard_dms_dir_record.py

View check run for this annotation

Codecov / codecov/patch

dms/wizards/wizard_dms_dir_record.py#L66-L70

Added lines #L66 - L70 were not covered by tests
{
"res_id": {
"string": "Linked attachments record ID",
"type": "many2one",
"relation": relation,
"required": True,
}
}
)
eview = etree.fromstring(res["views"]["form"]["arch"])
options = etree.Element("field", name="res_id")
placeholder = eview.xpath("//separator[@string='options_placeholder']")[0]
placeholder.getparent().replace(placeholder, options)
res["views"]["form"]["arch"] = etree.tostring(eview, pretty_print=True)
return res

Check warning on line 85 in dms/wizards/wizard_dms_dir_record.py

View check run for this annotation

Codecov / codecov/patch

dms/wizards/wizard_dms_dir_record.py#L80-L85

Added lines #L80 - L85 were not covered by tests
24 changes: 24 additions & 0 deletions dms/wizards/wizard_dms_dir_record_view.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<record id="attribute_option_wizard_form_view" model="ir.ui.view">
<field name="name">wizard.directory.record</field>
<field name="model">wizard.directory.record</field>
<field name="arch" type="xml">
<form string="Options Wizard">
<field name="directory_id" invisible="1" />
<group>
<separator string="options_placeholder" />
</group>
<footer>
<button
name="validate"
string="Validate"
type="object"
class="oe_highlight"
/>
<button string="Cancel" class="oe_link" special="cancel" />
</footer>
</form>
</field>
</record>
</odoo>