odoo-addon-dms 16.0.1.8.0.5__py3-none-any.whl → 17.0.1.0.0.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (113) hide show
  1. odoo/addons/dms/README.rst +132 -78
  2. odoo/addons/dms/__manifest__.py +34 -16
  3. odoo/addons/dms/actions/file.xml +1 -3
  4. odoo/addons/dms/controllers/main.py +0 -34
  5. odoo/addons/dms/controllers/portal.py +178 -92
  6. odoo/addons/dms/data/onboarding_data.xml +77 -0
  7. odoo/addons/dms/demo/access_group.xml +3 -9
  8. odoo/addons/dms/i18n/de.po +332 -221
  9. odoo/addons/dms/i18n/dms.pot +137 -174
  10. odoo/addons/dms/i18n/es.po +355 -226
  11. odoo/addons/dms/i18n/fr.po +256 -342
  12. odoo/addons/dms/i18n/he_IL.po +208 -181
  13. odoo/addons/dms/i18n/it.po +369 -248
  14. odoo/addons/dms/i18n/nl.po +140 -168
  15. odoo/addons/dms/i18n/pt.po +352 -223
  16. odoo/addons/dms/i18n/pt_BR.po +358 -256
  17. odoo/addons/dms/i18n/ru.po +138 -172
  18. odoo/addons/dms/models/__init__.py +7 -1
  19. odoo/addons/dms/models/abstract_dms_mixin.py +1 -1
  20. odoo/addons/dms/models/access_groups.py +18 -11
  21. odoo/addons/dms/models/base.py +10 -2
  22. odoo/addons/dms/models/directory.py +46 -75
  23. odoo/addons/dms/models/{category.py → dms_category.py} +10 -42
  24. odoo/addons/dms/models/dms_file.py +125 -147
  25. odoo/addons/dms/models/dms_security_mixin.py +26 -22
  26. odoo/addons/dms/models/ir_attachment.py +0 -1
  27. odoo/addons/dms/models/ir_binary.py +19 -0
  28. odoo/addons/dms/models/mail_thread.py +2 -4
  29. odoo/addons/dms/models/mixins_thumbnail.py +13 -8
  30. odoo/addons/dms/models/onboarding_onboarding.py +16 -0
  31. odoo/addons/dms/models/onboarding_onboarding_step.py +50 -0
  32. odoo/addons/dms/models/res_company.py +22 -47
  33. odoo/addons/dms/models/res_config_settings.py +0 -1
  34. odoo/addons/dms/models/storage.py +4 -24
  35. odoo/addons/dms/models/tag.py +1 -1
  36. odoo/addons/dms/readme/CONFIGURE.md +59 -0
  37. odoo/addons/dms/readme/CONTRIBUTORS.md +14 -0
  38. odoo/addons/dms/readme/CREDITS.md +6 -0
  39. odoo/addons/dms/readme/DESCRIPTION.md +9 -0
  40. odoo/addons/dms/readme/INSTALL.md +4 -0
  41. odoo/addons/dms/readme/ROADMAP.md +19 -0
  42. odoo/addons/dms/readme/USAGE.md +11 -0
  43. odoo/addons/dms/security/security.xml +1 -0
  44. odoo/addons/dms/static/description/icon.png +0 -0
  45. odoo/addons/dms/static/description/icon.svg +4 -1
  46. odoo/addons/dms/static/description/index.html +133 -88
  47. odoo/addons/dms/static/description/portal_icon.svg +12 -0
  48. odoo/addons/dms/static/src/js/fields/{path_owl.esm.js → path_json/path_owl.esm.js} +22 -4
  49. odoo/addons/dms/static/src/js/fields/{path_owl.xml → path_json/path_owl.xml} +7 -4
  50. odoo/addons/dms/static/src/js/fields/preview_binary/preview_record.esm.js +47 -0
  51. odoo/addons/dms/static/src/js/{views/fields/binary → fields/preview_binary}/preview_record.xml +5 -4
  52. odoo/addons/dms/static/src/js/views/dms_file_upload.esm.js +155 -148
  53. odoo/addons/dms/static/src/js/views/file_kanban_controller.xml +0 -1
  54. odoo/addons/dms/static/src/js/views/file_kanban_record.esm.js +26 -27
  55. odoo/addons/dms/static/src/js/views/file_kanban_renderer.esm.js +1 -2
  56. odoo/addons/dms/static/src/js/views/file_kanban_renderer.xml +12 -16
  57. odoo/addons/dms/static/src/js/views/file_kanban_view.esm.js +11 -9
  58. odoo/addons/dms/static/src/js/views/file_list_controller.esm.js +1 -1
  59. odoo/addons/dms/static/src/js/views/file_list_renderer.xml +1 -7
  60. odoo/addons/dms/static/src/js/views/file_list_view.esm.js +11 -9
  61. odoo/addons/dms/static/src/js/views/search_panel.esm.js +9 -10
  62. odoo/addons/dms/static/src/models/attachment.esm.js +83 -82
  63. odoo/addons/dms/static/src/models/attachment_image.esm.js +30 -28
  64. odoo/addons/dms/static/src/models/attachment_viewer_viewable.esm.js +27 -25
  65. odoo/addons/dms/static/src/scss/directory_kanban.scss +28 -73
  66. odoo/addons/dms/static/src/scss/dms_common.scss +69 -0
  67. odoo/addons/dms/static/src/scss/file_kanban.scss +22 -34
  68. odoo/addons/dms/static/src/scss/portal.scss +12 -0
  69. odoo/addons/dms/static/tests/tours/dms_portal_tour.esm.js +46 -0
  70. odoo/addons/dms/{views/dms_portal_templates.xml → template/portal.xml} +13 -3
  71. odoo/addons/dms/tests/common.py +20 -4
  72. odoo/addons/dms/tests/data/mail01.eml +2 -2
  73. odoo/addons/dms/tests/data/mail02.eml +2 -2
  74. odoo/addons/dms/tests/test_benchmark.py +16 -21
  75. odoo/addons/dms/tests/test_directory.py +128 -40
  76. odoo/addons/dms/tests/test_file.py +112 -30
  77. odoo/addons/dms/tests/test_file_database.py +50 -24
  78. odoo/addons/dms/tests/test_portal.py +50 -37
  79. odoo/addons/dms/tests/test_storage_attachment.py +85 -63
  80. odoo/addons/dms/tests/test_storage_database.py +89 -35
  81. odoo/addons/dms/tools/file.py +63 -11
  82. odoo/addons/dms/views/dms_access_groups_views.xml +2 -17
  83. odoo/addons/dms/views/{category.xml → dms_category.xml} +4 -9
  84. odoo/addons/dms/views/{directory.xml → dms_directory.xml} +168 -176
  85. odoo/addons/dms/views/dms_file.xml +170 -191
  86. odoo/addons/dms/views/{tag.xml → dms_tag.xml} +50 -53
  87. odoo/addons/dms/views/menu.xml +52 -21
  88. odoo/addons/dms/views/res_config_settings.xml +31 -82
  89. odoo/addons/dms/views/storage.xml +7 -13
  90. odoo_addon_dms-17.0.1.0.0.3.dist-info/METADATA +257 -0
  91. {odoo_addon_dms-16.0.1.8.0.5.dist-info → odoo_addon_dms-17.0.1.0.0.3.dist-info}/RECORD +93 -95
  92. {odoo_addon_dms-16.0.1.8.0.5.dist-info → odoo_addon_dms-17.0.1.0.0.3.dist-info}/WHEEL +1 -1
  93. odoo_addon_dms-17.0.1.0.0.3.dist-info/top_level.txt +1 -0
  94. odoo/addons/dms/i18n/fa.po +0 -2277
  95. odoo/addons/dms/i18n/fa_IR.po +0 -2277
  96. odoo/addons/dms/readme/CONFIGURE.rst +0 -40
  97. odoo/addons/dms/readme/CONTRIBUTORS.rst +0 -16
  98. odoo/addons/dms/readme/CREDITS.rst +0 -6
  99. odoo/addons/dms/readme/DESCRIPTION.rst +0 -6
  100. odoo/addons/dms/readme/INSTALL.rst +0 -9
  101. odoo/addons/dms/readme/ROADMAP.rst +0 -8
  102. odoo/addons/dms/readme/USAGE.rst +0 -8
  103. odoo/addons/dms/static/src/js/components/path/path.esm.js +0 -0
  104. odoo/addons/dms/static/src/js/dms_portal_tour.js +0 -57
  105. odoo/addons/dms/static/src/js/fields/path.js +0 -81
  106. odoo/addons/dms/static/src/js/views/fields/binary/preview_record.esm.js +0 -35
  107. odoo/addons/dms/static/src/js/views/many_drop_target.js +0 -98
  108. odoo/addons/dms/static/src/scss/variables.scss +0 -9
  109. odoo/addons/dms/static/src/xml/views.xml +0 -72
  110. odoo/addons/dms/template/assets.xml +0 -44
  111. odoo/addons/dms/template/onboarding.xml +0 -97
  112. odoo_addon_dms-16.0.1.8.0.5.dist-info/METADATA +0 -203
  113. odoo_addon_dms-16.0.1.8.0.5.dist-info/top_level.txt +0 -1
@@ -1,15 +1,15 @@
1
1
  # Copyright 2017-2019 MuK IT GmbH.
2
2
  # Copyright 2020 Creu Blanca
3
+ # Copyright 2024 Subteno - Timothée Vannier (https://www.subteno.com).
3
4
  # License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl).
4
5
 
5
6
  import os
6
7
 
7
8
  from odoo import api, fields, models
8
- from odoo.modules.module import get_resource_path
9
+ from odoo.tools.misc import file_path
9
10
 
10
11
 
11
12
  class Thumbnail(models.AbstractModel):
12
-
13
13
  _name = "dms.mixins.thumbnail"
14
14
  _inherit = "image.mixin"
15
15
  _description = "DMS thumbnail and icon mixin"
@@ -17,11 +17,16 @@ class Thumbnail(models.AbstractModel):
17
17
  icon_url = fields.Char(string="Icon URL", compute="_compute_icon_url")
18
18
 
19
19
  def _get_icon_disk_path(self):
20
- """Obtain local disk path to record icon."""
21
- folders = ["static", "icons"]
20
+ """Get the local disk path to record icon."""
22
21
  name = self._get_icon_placeholder_name()
23
- path = get_resource_path("dms", *folders, name)
24
- return path or get_resource_path("dms", *folders, "file_unknown.svg")
22
+ folders = ["dms", "static", "icons"]
23
+
24
+ try:
25
+ path = file_path(os.path.join(*folders, name))
26
+ except FileNotFoundError:
27
+ return file_path(os.path.join(*folders, "file_unknown.svg"))
28
+
29
+ return path or file_path(os.path.join(*folders, "file_unknown.svg"))
25
30
 
26
31
  def _get_icon_placeholder_name(self):
27
32
  return "folder.svg"
@@ -38,7 +43,7 @@ class Thumbnail(models.AbstractModel):
38
43
  for one in self:
39
44
  # Get URL to thumbnail or to the default icon by file extension
40
45
  one.icon_url = (
41
- "/web/image/{}/{}/image_128/128x128?crop=1".format(one._name, one.id)
46
+ f"/web/image/{one._name}/{one.id}/image_128/128x128?crop=1"
42
47
  if one.image_128
43
- else one._get_icon_url()
48
+ else f"{one._get_icon_url()}?crop=1"
44
49
  )
@@ -0,0 +1,16 @@
1
+ # Copyright 2024 Subteno - Timothée Vannier (https://www.subteno.com).
2
+ # License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl).
3
+
4
+
5
+ from odoo import api, models
6
+
7
+
8
+ class OnboardingOnboarding(models.Model):
9
+ _inherit = "onboarding.onboarding"
10
+
11
+ # ----------------------------------------------------------
12
+ # Actions
13
+ # ----------------------------------------------------------
14
+ @api.model
15
+ def action_close_panel_dms_file(self):
16
+ self.action_close_panel("dms.onboarding_onboarding_dms_file")
@@ -0,0 +1,50 @@
1
+ # Copyright 2024 Subteno - Timothée Vannier (https://www.subteno.com).
2
+ # License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl).
3
+
4
+
5
+ from odoo import api, models
6
+
7
+
8
+ class OnboardingOnboardingStep(models.Model):
9
+ _inherit = "onboarding.onboarding.step"
10
+
11
+ # ----------------------------------------------------------
12
+ # Actions
13
+ # ----------------------------------------------------------
14
+ @api.model
15
+ def action_open_documents_onboarding_storage(self):
16
+ """
17
+ Open the form to create a new storage from the onboarding panel.
18
+ """
19
+ return self.env.ref("dms.action_dms_storage_new").read()[0]
20
+
21
+ @api.model
22
+ def action_open_documents_onboarding_directory(self):
23
+ """
24
+ Open the form to create a new directory from the onboarding panel.
25
+ """
26
+ storage = self.env["dms.storage"].search([], order="create_date desc", limit=1)
27
+ action = self.env.ref("dms.action_dms_directory_new").read()[0]
28
+ action["context"] = {
29
+ **self.env.context,
30
+ **{
31
+ "default_is_root_directory": True,
32
+ "default_storage_id": storage and storage.id,
33
+ },
34
+ }
35
+ return action
36
+
37
+ @api.model
38
+ def action_open_documents_onboarding_file(self):
39
+ """
40
+ Open the form to create a new file from the onboarding panel.
41
+ """
42
+ directory = self.env["dms.directory"].search(
43
+ [], order="create_date desc", limit=1
44
+ )
45
+ action = self.env.ref("dms.action_dms_file_new").read()[0]
46
+ action["context"] = {
47
+ **self.env.context,
48
+ **{"default_directory_id": directory and directory.id},
49
+ }
50
+ return action
@@ -1,5 +1,6 @@
1
1
  # Copyright 2020 Creu Blanca
2
2
  # Copyright 2017-2019 MuK IT GmbH
3
+ # Copyright 2024 Subteno - Timothée Vannier (https://www.subteno.com).
3
4
  # License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl).
4
5
 
5
6
  import logging
@@ -10,13 +11,8 @@ _logger = logging.getLogger(__name__)
10
11
 
11
12
 
12
13
  class ResCompany(models.Model):
13
-
14
14
  _inherit = "res.company"
15
15
 
16
- # ----------------------------------------------------------
17
- # Database
18
- # ----------------------------------------------------------
19
-
20
16
  documents_onboarding_state = fields.Selection(
21
17
  selection=[
22
18
  ("not_done", "Not done"),
@@ -26,7 +22,6 @@ class ResCompany(models.Model):
26
22
  ],
27
23
  default="not_done",
28
24
  )
29
-
30
25
  documents_onboarding_storage_state = fields.Selection(
31
26
  selection=[
32
27
  ("not_done", "Not done"),
@@ -36,7 +31,6 @@ class ResCompany(models.Model):
36
31
  ],
37
32
  default="not_done",
38
33
  )
39
-
40
34
  documents_onboarding_directory_state = fields.Selection(
41
35
  selection=[
42
36
  ("not_done", "Not done"),
@@ -46,7 +40,6 @@ class ResCompany(models.Model):
46
40
  ],
47
41
  default="not_done",
48
42
  )
49
-
50
43
  documents_onboarding_file_state = fields.Selection(
51
44
  selection=[
52
45
  ("not_done", "Not done"),
@@ -57,55 +50,37 @@ class ResCompany(models.Model):
57
50
  default="not_done",
58
51
  )
59
52
 
60
- # ----------------------------------------------------------
61
53
  # Functions
62
- # ----------------------------------------------------------
63
-
64
54
  def get_and_update_documents_onboarding_state(self):
65
- return self._get_and_update_onboarding_state(
66
- "documents_onboarding_state", self.get_documents_steps_states_names()
67
- )
68
-
69
- def get_documents_steps_states_names(self):
70
- return [
55
+ step_states = [
71
56
  "documents_onboarding_storage_state",
72
57
  "documents_onboarding_directory_state",
73
58
  "documents_onboarding_file_state",
74
59
  ]
60
+ onboarding_state = "documents_onboarding_state"
61
+ old_values = {}
62
+ all_done = True
75
63
 
76
- # ----------------------------------------------------------
77
- # Actions
78
- # ----------------------------------------------------------
64
+ for step_state in step_states:
65
+ old_values[step_state] = self[step_state]
66
+ if self[step_state] == "just_done":
67
+ self[step_state] = "done"
68
+ all_done = all_done and self[step_state] == "done"
79
69
 
80
- @api.model
81
- def action_open_documents_onboarding_storage(self):
82
- return self.env.ref("dms.action_dms_storage_new").read()[0]
70
+ if all_done:
71
+ old_values[onboarding_state] = (
72
+ "just_done" if self[onboarding_state] == "not_done" else "done"
73
+ )
74
+ self[onboarding_state] = "done"
83
75
 
84
- @api.model
85
- def action_open_documents_onboarding_directory(self):
86
- storage = self.env["dms.storage"].search([], order="create_date desc", limit=1)
87
- action = self.env.ref("dms.action_dms_directory_new").read()[0]
88
- action["context"] = {
89
- **self.env.context,
90
- **{
91
- "default_is_root_directory": True,
92
- "default_storage_id": storage and storage.id,
93
- },
94
- }
95
- return action
96
-
97
- @api.model
98
- def action_open_documents_onboarding_file(self):
99
- directory = self.env["dms.directory"].search(
100
- [], order="create_date desc", limit=1
101
- )
102
- action = self.env.ref("dms.action_dms_file_new").read()[0]
103
- action["context"] = {
104
- **self.env.context,
105
- **{"default_directory_id": directory and directory.id},
106
- }
107
- return action
76
+ return old_values
108
77
 
78
+ # Actions
109
79
  @api.model
110
80
  def action_close_documents_onboarding(self):
111
81
  self.env.user.company_id.documents_onboarding_state = "closed"
82
+
83
+ def set_onboarding_step_done(self, step):
84
+ self.ensure_one()
85
+ if self[step] == "not_done":
86
+ self[step] = "just_done"
@@ -6,7 +6,6 @@ from odoo import fields, models
6
6
 
7
7
 
8
8
  class ResConfigSettings(models.TransientModel):
9
-
10
9
  _inherit = "res.config.settings"
11
10
 
12
11
  documents_binary_max_size = fields.Integer(
@@ -12,16 +12,10 @@ _logger = logging.getLogger(__name__)
12
12
 
13
13
 
14
14
  class Storage(models.Model):
15
-
16
15
  _name = "dms.storage"
17
16
  _description = "Storage"
18
17
 
19
- # ----------------------------------------------------------
20
- # Database
21
- # ----------------------------------------------------------
22
-
23
18
  name = fields.Char(required=True)
24
-
25
19
  save_type = fields.Selection(
26
20
  selection=[
27
21
  ("database", _("Database")),
@@ -30,11 +24,10 @@ class Storage(models.Model):
30
24
  ],
31
25
  default="database",
32
26
  required=True,
33
- help="""The save type is used to determine how a file is saved by the
34
- system. If you change this setting, you can migrate existing files
35
- manually by triggering the action.""",
27
+ help="The save type is used to determine how a file is saved by the system. "
28
+ "If you change this setting, you can migrate existing files manually by "
29
+ "triggering the action.",
36
30
  )
37
-
38
31
  company_id = fields.Many2one(
39
32
  comodel_name="res.company",
40
33
  string="Company",
@@ -42,13 +35,11 @@ class Storage(models.Model):
42
35
  help="If set, directories and files will only be available for "
43
36
  "the selected company.",
44
37
  )
45
-
46
38
  is_hidden = fields.Boolean(
47
39
  string="Storage is Hidden",
48
40
  default=False,
49
41
  help="Indicates if directories and files are hidden by default.",
50
42
  )
51
-
52
43
  root_directory_ids = fields.One2many(
53
44
  comodel_name="dms.directory",
54
45
  inverse_name="storage_id",
@@ -57,7 +48,6 @@ class Storage(models.Model):
57
48
  readonly=False,
58
49
  copy=False,
59
50
  )
60
-
61
51
  storage_directory_ids = fields.One2many(
62
52
  comodel_name="dms.directory",
63
53
  inverse_name="storage_id",
@@ -66,7 +56,6 @@ class Storage(models.Model):
66
56
  readonly=True,
67
57
  copy=False,
68
58
  )
69
-
70
59
  storage_file_ids = fields.One2many(
71
60
  comodel_name="dms.file",
72
61
  inverse_name="storage_id",
@@ -75,22 +64,19 @@ class Storage(models.Model):
75
64
  readonly=True,
76
65
  copy=False,
77
66
  )
78
-
79
67
  count_storage_directories = fields.Integer(
80
68
  compute="_compute_count_storage_directories", string="Count Directories"
81
69
  )
82
-
83
70
  count_storage_files = fields.Integer(
84
71
  compute="_compute_count_storage_files", string="Count Files"
85
72
  )
86
-
87
73
  model_ids = fields.Many2many("ir.model", string="Linked Models")
88
74
  inherit_access_from_parent_record = fields.Boolean(
89
75
  string="Inherit permissions from related record",
90
76
  default=False,
91
77
  help="Indicate if directories and files access work only with "
92
78
  "related model access (for example, if some directories are related "
93
- "with any sale, only users with read access to these sale can acess)",
79
+ "with any sale, only users with read access to these sale can access)",
94
80
  )
95
81
  include_message_attachments = fields.Boolean(
96
82
  string="Create files from message attachments",
@@ -110,10 +96,7 @@ class Storage(models.Model):
110
96
  if record.save_type == "attachment":
111
97
  record.inherit_access_from_parent_record = True
112
98
 
113
- # ----------------------------------------------------------
114
99
  # Actions
115
- # ----------------------------------------------------------
116
-
117
100
  def action_storage_migrate(self):
118
101
  if self.save_type != "attachment":
119
102
  if not self.env.user.has_group("dms.group_dms_manager"):
@@ -132,10 +115,7 @@ class Storage(models.Model):
132
115
  "documents_onboarding_storage_state"
133
116
  )
134
117
 
135
- # ----------------------------------------------------------
136
118
  # Read, View
137
- # ----------------------------------------------------------
138
-
139
119
  @api.depends("storage_directory_ids")
140
120
  def _compute_count_storage_directories(self):
141
121
  for record in self:
@@ -20,7 +20,7 @@ class Tag(models.Model):
20
20
  )
21
21
  category_id = fields.Many2one(
22
22
  comodel_name="dms.category",
23
- context="{'dms_category_show_path': True}",
23
+ context={"dms_category_show_path": True},
24
24
  string="Category",
25
25
  ondelete="set null",
26
26
  )
@@ -0,0 +1,59 @@
1
+ # Configuration
2
+
3
+ To configure this module, you need to:
4
+
5
+ ## 1. Create a storage
6
+ 1. Go to *Documents -\> Configuration -\> Storages*.
7
+
8
+ 2. Create a new document storage. You can choose between three options on `Save Type`:
9
+ - `Database`: Store the files on the database as a field
10
+ - `Attachment`: Store the files as attachments
11
+ - `File`: Store the files on the file system
12
+
13
+ ## 2. Create an access group
14
+ 1. Next, create an administrative access group. Go to *Configuration -\> Access Groups*.
15
+ - Create a new group, name it appropriately, and turn on all three
16
+ permissions (Create, Write and Unlink. Read is implied and always
17
+ enabled).
18
+ - Add any other top-level administrative users to the group if
19
+ needed (your user should already be there).
20
+ - You can create other groups in here later for fine-grained access
21
+ control.
22
+
23
+ ## 3. Create a directory
24
+ 1. Afterward, go to *Documents -\> Directories*.
25
+
26
+ 2. Create a new directory, mark it as root and select the previously created setting.
27
+ - Select the *Groups* tab and add your administrative group created
28
+ above.
29
+ If your directory was already created before the group, you can also add it in the
30
+ access groups (*Configuration -\> Access Groups*).
31
+
32
+ 3. In the directory settings, you can also add other access groups (created above) that will be able to:
33
+ - read
34
+ - create
35
+ - write
36
+ - delete
37
+
38
+ # Migration
39
+
40
+ If you need to modify the storage `Save Type` you might want to migrate
41
+ the file data. To achieve it, you need to:
42
+
43
+ 1. Go to *Documents -\> Configuration -\> Storage* and select the
44
+ storage you want to modify
45
+ 2. Modify the save type
46
+ 3. Press the button Migrate files if you want to migrate all the files
47
+ at once
48
+ 4. Press the button Manual File Migration to specify files one by one
49
+
50
+ You can check all the files that still need to be migrated from all
51
+ storages and migrate them manually on *Documents -\> Configuration -\>
52
+ Migration*
53
+
54
+ # File Wizard Selection
55
+
56
+ There is an action called `action_dms_file_wizard_selector` to open a
57
+ wizard to list files in kanban view. This can be used (example
58
+ dms_attachment_link module) to add a button in kanban view with the
59
+ action we need.
@@ -0,0 +1,14 @@
1
+ - Mathias Markl \<<mathias.markl@mukit.at>\>
2
+ - Enric Tobella \<<etobella@creublanca.es>\>
3
+ - Antoni Romera
4
+ - Gelu Boros \<<gelu.boros@rgbconsulting.com>\>
5
+ - [Tecnativa](https://www.tecnativa.com):
6
+ - Víctor Martínez
7
+ - Pedro M. Baeza
8
+ - Jairo Llopis
9
+ - [Elego](https://www.elegosoft.com):
10
+ - Yu Weng \<<yweng@elegosoft.com>\>
11
+ - Philip Witte \<<phillip.witte@elegosoft.com>\>
12
+ - Khanh Bui \<<khanh.bui@mail.elegosoft.com>\>
13
+ - [Subteno](https://www.subteno.com):
14
+ - Timothée Vannier <<tva@subteno.com>>
@@ -0,0 +1,6 @@
1
+ Some pictures are based on or inspired by:
2
+
3
+ - [Roundicons](https://www.flaticon.com/authors/roundicons)
4
+ - [Smashicons](https://www.flaticon.com/authors/smashicons)
5
+ - [EmojiOne](https://github.com/EmojiTwo/emojitwo) : Portal DMS icon
6
+ - [GitHub Octicons](https://github.com/primer/octicons/) : The main DMS icon
@@ -0,0 +1,9 @@
1
+ DMS is a module for creating, managing and viewing document files
2
+ directly within Odoo. This module is only the basis for an entire
3
+ ecosystem of apps that extend and seamlessly integrate with the document
4
+ management system.
5
+
6
+ This module adds portal functionality for directories and files for
7
+ allowed users, both portal or internal users. You can get as well a
8
+ tokenized link from a directory or a file for sharing it with any
9
+ anonymous user.
@@ -0,0 +1,4 @@
1
+ ## Preview
2
+
3
+ `python-magic` library is recommended to be installed for having whole
4
+ support to get proper file types and file preview.
@@ -0,0 +1,19 @@
1
+ - Files preview in portal
2
+ - Allow to download folder in portal and create zip file with all
3
+ content
4
+ - Save in cache own_root directories and update in every
5
+ create/write/unlink function
6
+ - Add a migration procedure for converting an storage to attachment one
7
+ for populating existing records with attachments as folders
8
+ - Add a link from attachment view in chatter to linked documents
9
+ - If Inherit permissions from related record (the
10
+ inherit_access_from_parent_record field from storage) is changed when
11
+ directories already exist, inconsistencies may occur because groups
12
+ defined in the directories and subdirectories will still exist, all
13
+ groups in these directories should be removed before changing.
14
+ - Since portal users can read `dms.storage` records, if your module
15
+ extends this model to another storage backend that needs using
16
+ secrets, remember to forbid access to the secrets fields by other
17
+ means. It would be nice to be able to remove that rule at some point.
18
+ - Searchpanel in files: Highlight items (shading) without records when
19
+ filtering something (by name for example).
@@ -0,0 +1,11 @@
1
+ The best way to manage the documents is to switch to the Documents view.
2
+ Existing documents can be managed there and new documents can be
3
+ created.
4
+
5
+ ## Portal functionality
6
+
7
+ You can add any portal user to DMS access groups, and then allow that
8
+ group in directories, so they will see in the portal such directories
9
+ and their files. Another possibility is to click on "Share" button
10
+ inside a directory or a file for obtaining a tokenized link for single
11
+ access to that resource, no matter if logged or not.
@@ -4,6 +4,7 @@
4
4
  Copyright 2017-2019 MuK IT GmbH
5
5
  Copyright 2020 Creu Blanca
6
6
  Copyright 2021 Tecnativa - Víctor Martínez
7
+ Copyright 2024 Subteno - Timothée Vannier (https://www.subteno.com).
7
8
  License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl).
8
9
 
9
10
  -->
Binary file
@@ -1 +1,4 @@
1
- <?xml version="1.0" standalone="no"?><!-- Generator: Gravit.io --><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="isolation:isolate" viewBox="0 0 250 250" width="250" height="250"><defs><clipPath id="_clipPath_M77k6snJnD3BvTjxH0tJqBxZnrt5TSUJ"><rect width="250" height="250"/></clipPath></defs><g clip-path="url(#_clipPath_M77k6snJnD3BvTjxH0tJqBxZnrt5TSUJ)"><rect width="250" height="250" style="fill:rgb(0,0,0)" fill-opacity="0"/><defs><filter id="ut21eioDgedz5CWzXOUbRjLNasX8GLDS" x="-200%" y="-200%" width="400%" height="400%" filterUnits="objectBoundingBox" color-interpolation-filters="sRGB"><feOffset xmlns="http://www.w3.org/2000/svg" in="SourceGraphic" dx="0" dy="3"/><feGaussianBlur xmlns="http://www.w3.org/2000/svg" stdDeviation="2.146804531419514" result="pf_100_offsetBlur"/><feComposite xmlns="http://www.w3.org/2000/svg" in="SourceGraphic" in2="pf_100_offsetBlur" result="pf_100_inverse" operator="out"/><feFlood xmlns="http://www.w3.org/2000/svg" flood-color="#FFFFFF" flood-opacity="0.5" result="pf_100_color"/><feComposite xmlns="http://www.w3.org/2000/svg" in="pf_100_color" in2="pf_100_inverse" operator="in" result="pf_100_shadow"/><feComposite xmlns="http://www.w3.org/2000/svg" in="pf_100_shadow" in2="SourceGraphic" operator="over" result="_out_nTPDw1dPOE4dI1bI0U8DfzdsY3ERWsZA"/><feOffset xmlns="http://www.w3.org/2000/svg" in="_out_nTPDw1dPOE4dI1bI0U8DfzdsY3ERWsZA" dx="0" dy="-3"/><feGaussianBlur xmlns="http://www.w3.org/2000/svg" stdDeviation="2.146804531419514" result="pf_101_offsetBlur"/><feComposite xmlns="http://www.w3.org/2000/svg" in="_out_nTPDw1dPOE4dI1bI0U8DfzdsY3ERWsZA" in2="pf_101_offsetBlur" result="pf_101_inverse" operator="out"/><feFlood xmlns="http://www.w3.org/2000/svg" flood-color="#000000" flood-opacity="0.5" result="pf_101_color"/><feComposite xmlns="http://www.w3.org/2000/svg" in="pf_101_color" in2="pf_101_inverse" operator="in" result="pf_101_shadow"/><feComposite xmlns="http://www.w3.org/2000/svg" in="pf_101_shadow" in2="_out_nTPDw1dPOE4dI1bI0U8DfzdsY3ERWsZA" operator="over" result="_out_XeauSaJy413IM9SlDJsE762c4bfV03q3"/><feMerge><feMergeNode in="_out_XeauSaJy413IM9SlDJsE762c4bfV03q3"/></feMerge></filter></defs><g filter="url(#ut21eioDgedz5CWzXOUbRjLNasX8GLDS)"><path d="M 15 0 L 235 0 C 243.279 0 250 6.721 250 15 L 250 235 C 250 243.279 243.279 250 235 250 L 15 250 C 6.721 250 0 243.279 0 235 L 0 15 C 0 6.721 6.721 0 15 0 Z" style="stroke:none;fill:#C83737;stroke-miterlimit:10;"/></g><image xlink:href="data:image/png;base64,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" x="14.323" y="47.27" width="223.449" height="177.46" style=""/></g></svg>
1
+ <svg width="100" height="100" viewBox="0 0 100 100" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M10.6594 14.0094C12.443 12.2246 14.8624 11.2213 17.3856 11.22H36.4169C39.4075 11.22 42.235 12.6338 44.0294 15.0263L48.9231 21.5513C49.0498 21.7201 49.2139 21.8571 49.4027 21.9515C49.5915 22.0459 49.7996 22.095 50.0106 22.095H78.5575C79.9996 22.095 81.3827 22.6679 82.4024 23.6876C83.4221 24.7073 83.995 26.0904 83.995 27.5325V30.2513H22.8231C21.7415 30.2513 20.7043 30.6809 19.9395 31.4457C19.1747 32.2105 18.745 33.2478 18.745 34.3294C18.745 35.411 19.1747 36.4483 19.9395 37.213C20.7043 37.9778 21.7415 38.4075 22.8231 38.4075H87.9535C88.7217 38.4068 89.4812 38.5689 90.1822 38.8831C90.8832 39.1973 91.5096 39.6564 92.0203 40.2303C92.5309 40.8041 92.9142 41.4796 93.1448 42.2123C93.3755 42.945 93.4482 43.7183 93.3584 44.4812L89.4325 77.8294C89.4325 80.3531 88.43 82.7734 86.6454 84.5579C84.8609 86.3425 82.4406 87.345 79.9169 87.345H17.3856C14.8619 87.345 12.4416 86.3425 10.6571 84.5579C8.87254 82.7734 7.87 80.3531 7.87 77.8294V20.7356C7.87 18.2126 8.8705 15.7875 10.6594 14.0094Z" fill="#C83737"/>
3
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M42.5039 38.4075H22.8231C21.7415 38.4075 20.7043 37.9778 19.9395 37.213C19.1747 36.4482 18.745 35.411 18.745 34.3294C18.745 33.2478 19.1747 32.2105 19.9395 31.4457C20.7043 30.6809 21.7415 30.2513 22.8231 30.2513H83.995V27.5325C83.995 26.0904 83.4221 24.7073 82.4024 23.6876C81.3827 22.6679 79.9996 22.095 78.5575 22.095H50.0106C49.7996 22.095 49.5914 22.0459 49.4027 21.9515C49.2139 21.8571 49.0498 21.7201 48.9231 21.5513L44.0294 15.0263C42.235 12.6338 39.4075 11.22 36.4169 11.22H17.3856C14.8624 11.2213 12.443 12.2246 10.6594 14.0094C8.8705 15.7875 7.87 18.2126 7.87 20.7356V47.9602C16.6861 44.4618 28.757 40.875 42.5039 38.4075Z" fill="#EC8A8A"/>
4
+ </svg>