Browse Source

Add module custom_image

12.0-mig-module_prototyper_last
Patrick Tombez 6 years ago
parent
commit
fc50991780
  1. 106
      base_conditional_image/README.rst
  2. 2
      base_conditional_image/__init__.py
  3. 20
      base_conditional_image/__manifest__.py
  4. 141
      base_conditional_image/i18n/custom_image.pot
  5. 3
      base_conditional_image/models/__init__.py
  6. 66
      base_conditional_image/models/abstract_image.py
  7. 64
      base_conditional_image/models/image.py
  8. 1
      base_conditional_image/readme/CONTRIBUTORS.rst
  9. 8
      base_conditional_image/readme/DESCRIPTION.rst
  10. 11
      base_conditional_image/readme/INSTALL.rst
  11. 7
      base_conditional_image/readme/USAGE.rst
  12. 3
      base_conditional_image/security/ir.model.access.csv
  13. 447
      base_conditional_image/static/description/index.html
  14. 53
      base_conditional_image/views/image_view.xml

106
base_conditional_image/README.rst

@ -0,0 +1,106 @@
==================
Conditional Images
==================
.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
:target: https://odoo-community.org/page/development-status
:alt: Beta
.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fserver--tools-lightgray.png?logo=github
:target: https://github.com/OCA/server-tools/tree/9.0/base_conditional_image
:alt: OCA/server-tools
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/server-tools-9-0/server-tools-9-0-base_conditional_image
:alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png
:target: https://runbot.odoo-community.org/runbot/149/9.0
:alt: Try me on Runbot
|badge1| |badge2| |badge3| |badge4| |badge5|
This module extends the functionality of any model to support conditional images
(based on the record attributes) and to manage them either globally or by company.
The main goal behind this module is to avoid storing the same image multiple times.
For example, for every partner, there is a related image (most of the time, it's the default one).
With this module properly set up, it will be stored only one time and you can change it whenever you want for all partners.
**WARNING**: this module cannot be used on the same objects using the module `base_multi_image`.
**Table of contents**
.. contents::
:local:
Installation
============
The sole purpose of this module is to add an abstract model to be inherited.
So, you will not notice any changes on install.
To develop using this module, you have to inherit the abstract model `abstract.conditional.image`
to the model that needs the conditional images::
class ResPartner(models.Model):
_inherit = ['res.partner', 'abstract.conditional.image']
_name = 'res.partner'
Then, configure how the images will be selected for each record.
Usage
=====
Go to *Technical Settings > Settings > Images* to configure all the images.
You can define images for specific objects, depending on the attributes and the company of the object.
The `selector` should return a boolean expression. All fields of the object are available to compute the result.
The system will first try to match an image with a company set up, then with the ones without a company.
If your object does not have a `company_id` field, this check will be ignored and only images without a company will be used.
Bug Tracker
===========
Bugs are tracked on `GitHub Issues <https://github.com/OCA/server-tools/issues>`_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us smashing it by providing a detailed and welcomed
`feedback <https://github.com/OCA/server-tools/issues/new?body=module:%20base_conditional_image%0Aversion:%209.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
Do not contact contributors directly about support or help with technical issues.
Credits
=======
Authors
~~~~~~~
* Camptocamp
Contributors
~~~~~~~~~~~~
* Patrick Tombez <patrick.tombez@camptocamp.com>
Maintainers
~~~~~~~~~~~
This module is maintained by the OCA.
.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: https://odoo-community.org
OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.
This module is part of the `OCA/server-tools <https://github.com/OCA/server-tools/tree/9.0/base_conditional_image>`_ project on GitHub.
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

2
base_conditional_image/__init__.py

@ -0,0 +1,2 @@
# -*- coding: utf-8 -*-
from . import models

20
base_conditional_image/__manifest__.py

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Copyright 2018 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html)
{
'name': 'Conditional Images',
'version': '12.0.1.0.0',
'author': 'Camptocamp, Odoo Community Association (OCA)',
'license': 'AGPL-3',
'category': 'Misc',
'depends': [
'base',
],
'website': 'http://github.com/OCA/server-tools',
'data': [
'views/image_view.xml',
'security/ir.model.access.csv',
],
'installable': True,
}

141
base_conditional_image/i18n/custom_image.pot

@ -0,0 +1,141 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * custom_image
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 9.0e\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-10-02 08:36+0000\n"
"PO-Revision-Date: 2018-10-02 08:36+0000\n"
"Last-Translator: <>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: custom_image
#: code:addons/custom_image/models/image.py:47
#, python-format
msgid "At least one image type must be specified"
msgstr ""
#. module: custom_image
#: model:ir.model.fields,field_description:custom_image.field_image_company_id
msgid "Company"
msgstr ""
#. module: custom_image
#: model:ir.model.fields,help:custom_image.field_image_company_id
msgid "Company related check. If inherited object does not have a `company_id` field, it will be ignored. The check will first take the records with a company then, if not match is found, the ones without a company."
msgstr ""
#. module: custom_image
#: model:ir.model.fields,field_description:custom_image.field_image_create_uid
msgid "Created by"
msgstr ""
#. module: custom_image
#: model:ir.model.fields,field_description:custom_image.field_image_create_date
msgid "Created on"
msgstr ""
#. module: custom_image
#: model:ir.model.fields,field_description:custom_image.field_abstract_custom_image_display_name
#: model:ir.model.fields,field_description:custom_image.field_image_display_name
msgid "Display Name"
msgstr ""
#. module: custom_image
#: model:ir.model.fields,field_description:custom_image.field_abstract_custom_image_id
#: model:ir.model.fields,field_description:custom_image.field_image_id
msgid "ID"
msgstr ""
#. module: custom_image
#: model:ir.model.fields,field_description:custom_image.field_abstract_custom_image_image
#: model:ir.model.fields,field_description:custom_image.field_abstract_custom_image_image_medium
#: model:ir.model.fields,field_description:custom_image.field_abstract_custom_image_image_small
#: model:ir.model.fields,field_description:custom_image.field_image_image
msgid "Image"
msgstr ""
#. module: custom_image
#: model:ir.actions.act_window,name:custom_image.image_action
#: model:ir.ui.menu,name:custom_image.image_menu
msgid "Images"
msgstr ""
#. module: custom_image
#: model:ir.model.fields,field_description:custom_image.field_abstract_custom_image___last_update
#: model:ir.model.fields,field_description:custom_image.field_image___last_update
msgid "Last Modified on"
msgstr ""
#. module: custom_image
#: model:ir.model.fields,field_description:custom_image.field_image_write_uid
msgid "Last Updated by"
msgstr ""
#. module: custom_image
#: model:ir.model.fields,field_description:custom_image.field_image_write_date
msgid "Last Updated on"
msgstr ""
#. module: custom_image
#: model:ir.model.fields,field_description:custom_image.field_image_image_medium
msgid "Medium-sized image"
msgstr ""
#. module: custom_image
#: model:ir.model.fields,help:custom_image.field_image_image_medium
msgid "Medium-sized image. It is automatically resized as a 128x128px image, with aspect ratio preserved. Use this field in form views or some kanban views."
msgstr ""
#. module: custom_image
#: model:ir.model.fields,field_description:custom_image.field_image_model_name
msgid "Model Name"
msgstr ""
#. module: custom_image
#: model:ir.model.fields,field_description:custom_image.field_image_name
msgid "Name"
msgstr ""
#. module: custom_image
#: model:ir.model.fields,help:custom_image.field_image_selector
msgid "Python expression used to distinguish the images for the same object. The variable `object` refer to the actual record on which the expression will be executed. An empty expression will always return `True`."
msgstr ""
#. module: custom_image
#: model:ir.model.fields,field_description:custom_image.field_image_selector
#: model:ir.ui.view,arch_db:custom_image.view_image_form
msgid "Selector"
msgstr ""
#. module: custom_image
#: model:ir.model.fields,field_description:custom_image.field_image_image_small
msgid "Small-sized image"
msgstr ""
#. module: custom_image
#: model:ir.model.fields,help:custom_image.field_image_image_small
msgid "Small-sized image. It is automatically resized as a 64x64px image, with aspect ratio preserved. Use this field anywhere a small image is required."
msgstr ""
#. module: custom_image
#: model:ir.model.fields,help:custom_image.field_image_image
msgid "This field holds the standard image, limited to 1024x1024px"
msgstr ""
#. module: custom_image
#: model:ir.model,name:custom_image.model_abstract_custom_image
msgid "abstract.custom.image"
msgstr ""
#. module: custom_image
#: model:ir.model,name:custom_image.model_image
msgid "image"
msgstr ""

3
base_conditional_image/models/__init__.py

@ -0,0 +1,3 @@
# -*- coding: utf-8 -*-
from . import image
from . import abstract_image

66
base_conditional_image/models/abstract_image.py

@ -0,0 +1,66 @@
# -*- coding: utf-8 -*-
# Copyright 2018 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html)
from openerp import fields, models
from openerp.tools.safe_eval import safe_eval
class AbstractImageStorage(models.AbstractModel):
_name = 'abstract.conditional.image'
image = fields.Binary(
compute='_compute_image', string="Image",
store=False, readonly=True
)
image_medium = fields.Binary(
compute='_compute_image', string="Image",
store=False, readonly=True
)
image_small = fields.Binary(
compute='_compute_image', string="Image",
store=False, readonly=True
)
@staticmethod
def _compute_selector_test_without_company(image_selector, record):
return bool(
safe_eval(image_selector.selector or "True", {'object': record})
)
@staticmethod
def _compute_selector_test_with_company(image_selector, record):
if (image_selector.company_id == record.company_id or
record.company_id and not image_selector.company_id):
return AbstractImageStorage._compute_selector_test_without_company(
image_selector, record
)
return False
def _compute_image(self):
if 'company_id' in self._fields:
search_clause = [('model_name', '=', self._name)]
test_method = self._compute_selector_test_with_company
else:
# If inherited object doesn't have a `company_id` field,
# remove the items with a company defined and the related checks
search_clause = [('model_name', '=', self._name),
('company_id', '=', False)]
test_method = self._compute_selector_test_without_company
image_selectors = self.env['image'].search(
search_clause, order='company_id, selector'
)
for rec in self:
found = None
for image_selector in image_selectors:
if test_method(image_selector, rec):
found = image_selector
break
rec.update({
'image': found and found.image,
'image_medium': found and found.image_medium,
'image_small': found and found.image_small,
})

64
base_conditional_image/models/image.py

@ -0,0 +1,64 @@
# -*- coding: utf-8 -*-
# Copyright 2018 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html)
from openerp import api, fields, models, tools, _
from openerp.exceptions import ValidationError
class Image(models.Model):
_name = 'image'
name = fields.Char('Name', required=True)
model_name = fields.Char('Model Name', required=True)
selector = fields.Text(
'Selector',
help='Python expression used as selector when multiple images are used'
'for the same object. The variable `object` refer '
'to the actual record on which the expression will be executed. '
'An empty expression will always return `True`.'
)
company_id = fields.Many2one(
'res.company', 'Company',
help='Company related check. If inherited object does not have a '
'`company_id` field, it will be ignored. '
'The check will first take the records with a company then, '
'if not match is found, the ones without a company.'
)
# image: all image fields are base64 encoded and PIL-supported
image = fields.Binary(
"Image", attachment=True,
help="This field holds the standard image, limited to 1024x1024px"
)
image_medium = fields.Binary(
"Medium-sized image", attachment=True,
help="Medium-sized image. It is automatically "
"resized as a 128x128px image, with aspect ratio preserved. "
"Use this field in form views or some kanban views."
)
image_small = fields.Binary(
"Small-sized image", attachment=True,
help="Small-sized image. It is automatically "
"resized as a 64x64px image, with aspect ratio preserved. "
"Use this field anywhere a small image is required."
)
@api.model
def _process_images(self, vals, required=False):
if set(['image', 'image_medium', 'image_small']) & set(vals.keys()):
tools.image_resize_images(vals)
elif required:
raise ValidationError(
_('At least one image type must be specified')
)
@api.model
def create(self, vals):
self._process_images(vals, required=True)
return super(Image, self).create(vals)
@api.multi
def write(self, vals):
self._process_images(vals)
return super(Image, self).write(vals)

1
base_conditional_image/readme/CONTRIBUTORS.rst

@ -0,0 +1 @@
* Patrick Tombez <patrick.tombez@camptocamp.com>

8
base_conditional_image/readme/DESCRIPTION.rst

@ -0,0 +1,8 @@
This module extends the functionality of any model to support conditional images
(based on the record attributes) and to manage them either globally or by company.
The main goal behind this module is to avoid storing the same image multiple times.
For example, for every partner, there is a related image (most of the time, it's the default one).
With this module properly set up, it will be stored only one time and you can change it whenever you want for all partners.
**WARNING**: this module cannot be used on the same objects using the module `base_multi_image`.

11
base_conditional_image/readme/INSTALL.rst

@ -0,0 +1,11 @@
The sole purpose of this module is to add an abstract model to be inherited.
So, you will not notice any changes on install.
To develop using this module, you have to inherit the abstract model `abstract.conditional.image`
to the model that needs the conditional images::
class ResPartner(models.Model):
_inherit = ['res.partner', 'abstract.conditional.image']
_name = 'res.partner'
Then, configure how the images will be selected for each record.

7
base_conditional_image/readme/USAGE.rst

@ -0,0 +1,7 @@
Go to *Technical Settings > Settings > Images* to configure all the images.
You can define images for specific objects, depending on the attributes and the company of the object.
The `selector` should return a boolean expression. All fields of the object are available to compute the result.
The system will first try to match an image with a company set up, then with the ones without a company.
If your object does not have a `company_id` field, this check will be ignored and only images without a company will be used.

3
base_conditional_image/security/ir.model.access.csv

@ -0,0 +1,3 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_conditional_image,Conditional Image,base_conditional_image.model_image,base.group_no_one,1,1,1,1
access_conditional_image_users,Conditional Image Users,base_conditional_image.model_image,base.group_user,1,0,0,0

447
base_conditional_image/static/description/index.html

@ -0,0 +1,447 @@
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils 0.14: http://docutils.sourceforge.net/" />
<title>Conditional Images</title>
<style type="text/css">
/*
:Author: David Goodger (goodger@python.org)
:Id: $Id: html4css1.css 7952 2016-07-26 18:15:59Z milde $
:Copyright: This stylesheet has been placed in the public domain.
Default cascading style sheet for the HTML output of Docutils.
See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to
customize this style sheet.
*/
/* used to remove borders from tables and images */
.borderless, table.borderless td, table.borderless th {
border: 0 }
table.borderless td, table.borderless th {
/* Override padding for "table.docutils td" with "! important".
The right padding separates the table cells. */
padding: 0 0.5em 0 0 ! important }
.first {
/* Override more specific margin styles with "! important". */
margin-top: 0 ! important }
.last, .with-subtitle {
margin-bottom: 0 ! important }
.hidden {
display: none }
.subscript {
vertical-align: sub;
font-size: smaller }
.superscript {
vertical-align: super;
font-size: smaller }
a.toc-backref {
text-decoration: none ;
color: black }
blockquote.epigraph {
margin: 2em 5em ; }
dl.docutils dd {
margin-bottom: 0.5em }
object[type="image/svg+xml"], object[type="application/x-shockwave-flash"] {
overflow: hidden;
}
/* Uncomment (and remove this text!) to get bold-faced definition list terms
dl.docutils dt {
font-weight: bold }
*/
div.abstract {
margin: 2em 5em }
div.abstract p.topic-title {
font-weight: bold ;
text-align: center }
div.admonition, div.attention, div.caution, div.danger, div.error,
div.hint, div.important, div.note, div.tip, div.warning {
margin: 2em ;
border: medium outset ;
padding: 1em }
div.admonition p.admonition-title, div.hint p.admonition-title,
div.important p.admonition-title, div.note p.admonition-title,
div.tip p.admonition-title {
font-weight: bold ;
font-family: sans-serif }
div.attention p.admonition-title, div.caution p.admonition-title,
div.danger p.admonition-title, div.error p.admonition-title,
div.warning p.admonition-title, .code .error {
color: red ;
font-weight: bold ;
font-family: sans-serif }
/* Uncomment (and remove this text!) to get reduced vertical space in
compound paragraphs.
div.compound .compound-first, div.compound .compound-middle {
margin-bottom: 0.5em }
div.compound .compound-last, div.compound .compound-middle {
margin-top: 0.5em }
*/
div.dedication {
margin: 2em 5em ;
text-align: center ;
font-style: italic }
div.dedication p.topic-title {
font-weight: bold ;
font-style: normal }
div.figure {
margin-left: 2em ;
margin-right: 2em }
div.footer, div.header {
clear: both;
font-size: smaller }
div.line-block {
display: block ;
margin-top: 1em ;
margin-bottom: 1em }
div.line-block div.line-block {
margin-top: 0 ;
margin-bottom: 0 ;
margin-left: 1.5em }
div.sidebar {
margin: 0 0 0.5em 1em ;
border: medium outset ;
padding: 1em ;
background-color: #ffffee ;
width: 40% ;
float: right ;
clear: right }
div.sidebar p.rubric {
font-family: sans-serif ;
font-size: medium }
div.system-messages {
margin: 5em }
div.system-messages h1 {
color: red }
div.system-message {
border: medium outset ;
padding: 1em }
div.system-message p.system-message-title {
color: red ;
font-weight: bold }
div.topic {
margin: 2em }
h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
margin-top: 0.4em }
h1.title {
text-align: center }
h2.subtitle {
text-align: center }
hr.docutils {
width: 75% }
img.align-left, .figure.align-left, object.align-left, table.align-left {
clear: left ;
float: left ;
margin-right: 1em }
img.align-right, .figure.align-right, object.align-right, table.align-right {
clear: right ;
float: right ;
margin-left: 1em }
img.align-center, .figure.align-center, object.align-center {
display: block;
margin-left: auto;
margin-right: auto;
}
table.align-center {
margin-left: auto;
margin-right: auto;
}
.align-left {
text-align: left }
.align-center {
clear: both ;
text-align: center }
.align-right {
text-align: right }
/* reset inner alignment in figures */
div.align-right {
text-align: inherit }
/* div.align-center * { */
/* text-align: left } */
.align-top {
vertical-align: top }
.align-middle {
vertical-align: middle }
.align-bottom {
vertical-align: bottom }
ol.simple, ul.simple {
margin-bottom: 1em }
ol.arabic {
list-style: decimal }
ol.loweralpha {
list-style: lower-alpha }
ol.upperalpha {
list-style: upper-alpha }
ol.lowerroman {
list-style: lower-roman }
ol.upperroman {
list-style: upper-roman }
p.attribution {
text-align: right ;
margin-left: 50% }
p.caption {
font-style: italic }
p.credits {
font-style: italic ;
font-size: smaller }
p.label {
white-space: nowrap }
p.rubric {
font-weight: bold ;
font-size: larger ;
color: maroon ;
text-align: center }
p.sidebar-title {
font-family: sans-serif ;
font-weight: bold ;
font-size: larger }
p.sidebar-subtitle {
font-family: sans-serif ;
font-weight: bold }
p.topic-title {
font-weight: bold }
pre.address {
margin-bottom: 0 ;
margin-top: 0 ;
font: inherit }
pre.literal-block, pre.doctest-block, pre.math, pre.code {
margin-left: 2em ;
margin-right: 2em }
pre.code .ln { color: grey; } /* line numbers */
pre.code, code { background-color: #eeeeee }
pre.code .comment, code .comment { color: #5C6576 }
pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold }
pre.code .literal.string, code .literal.string { color: #0C5404 }
pre.code .name.builtin, code .name.builtin { color: #352B84 }
pre.code .deleted, code .deleted { background-color: #DEB0A1}
pre.code .inserted, code .inserted { background-color: #A3D289}
span.classifier {
font-family: sans-serif ;
font-style: oblique }
span.classifier-delimiter {
font-family: sans-serif ;
font-weight: bold }
span.interpreted {
font-family: sans-serif }
span.option {
white-space: nowrap }
span.pre {
white-space: pre }
span.problematic {
color: red }
span.section-subtitle {
/* font-size relative to parent (h1..h6 element) */
font-size: 80% }
table.citation {
border-left: solid 1px gray;
margin-left: 1px }
table.docinfo {
margin: 2em 4em }
table.docutils {
margin-top: 0.5em ;
margin-bottom: 0.5em }
table.footnote {
border-left: solid 1px black;
margin-left: 1px }
table.docutils td, table.docutils th,
table.docinfo td, table.docinfo th {
padding-left: 0.5em ;
padding-right: 0.5em ;
vertical-align: top }
table.docutils th.field-name, table.docinfo th.docinfo-name {
font-weight: bold ;
text-align: left ;
white-space: nowrap ;
padding-left: 0 }
/* "booktabs" style (no vertical lines) */
table.docutils.booktabs {
border: 0px;
border-top: 2px solid;
border-bottom: 2px solid;
border-collapse: collapse;
}
table.docutils.booktabs * {
border: 0px;
}
table.docutils.booktabs th {
border-bottom: thin solid;
text-align: left;
}
h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
font-size: 100% }
ul.auto-toc {
list-style-type: none }
</style>
</head>
<body>
<div class="document" id="conditional-images">
<h1 class="title">Conditional Images</h1>
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<p><a class="reference external" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external" href="https://github.com/OCA/server-tools/tree/9.0/base_conditional_image"><img alt="OCA/server-tools" src="https://img.shields.io/badge/github-OCA%2Fserver--tools-lightgray.png?logo=github" /></a> <a class="reference external" href="https://translation.odoo-community.org/projects/server-tools-9-0/server-tools-9-0-base_conditional_image"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external" href="https://runbot.odoo-community.org/runbot/149/9.0"><img alt="Try me on Runbot" src="https://img.shields.io/badge/runbot-Try%20me-875A7B.png" /></a></p>
<p>This module extends the functionality of any model to support conditional images
(based on the record attributes) and to manage them either globally or by company.</p>
<p>The main goal behind this module is to avoid storing the same image multiple times.
For example, for every partner, there is a related image (most of the time, it’s the default one).
With this module properly set up, it will be stored only one time and you can change it whenever you want for all partners.</p>
<p><strong>WARNING</strong>: this module cannot be used on the same objects using the module <cite>base_multi_image</cite>.</p>
<p><strong>Table of contents</strong></p>
<div class="contents local topic" id="contents">
<ul class="simple">
<li><a class="reference internal" href="#installation" id="id1">Installation</a></li>
<li><a class="reference internal" href="#usage" id="id2">Usage</a></li>
<li><a class="reference internal" href="#bug-tracker" id="id3">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="id4">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="id5">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="id6">Contributors</a></li>
<li><a class="reference internal" href="#maintainers" id="id7">Maintainers</a></li>
</ul>
</li>
</ul>
</div>
<div class="section" id="installation">
<h1><a class="toc-backref" href="#id1">Installation</a></h1>
<p>The sole purpose of this module is to add an abstract model to be inherited.
So, you will not notice any changes on install.</p>
<p>To develop using this module, you have to inherit the abstract model <cite>abstract.conditional.image</cite>
to the model that needs the conditional images:</p>
<pre class="literal-block">
class ResPartner(models.Model):
_inherit = ['res.partner', 'abstract.conditional.image']
_name = 'res.partner'
</pre>
<p>Then, configure how the images will be selected for each record.</p>
</div>
<div class="section" id="usage">
<h1><a class="toc-backref" href="#id2">Usage</a></h1>
<p>Go to <em>Technical Settings &gt; Settings &gt; Images</em> to configure all the images.
You can define images for specific objects, depending on the attributes and the company of the object.</p>
<p>The <cite>selector</cite> should return a boolean expression. All fields of the object are available to compute the result.</p>
<p>The system will first try to match an image with a company set up, then with the ones without a company.
If your object does not have a <cite>company_id</cite> field, this check will be ignored and only images without a company will be used.</p>
</div>
<div class="section" id="bug-tracker">
<h1><a class="toc-backref" href="#id3">Bug Tracker</a></h1>
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/server-tools/issues">GitHub Issues</a>.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us smashing it by providing a detailed and welcomed
<a class="reference external" href="https://github.com/OCA/server-tools/issues/new?body=module:%20base_conditional_image%0Aversion:%209.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
<p>Do not contact contributors directly about support or help with technical issues.</p>
</div>
<div class="section" id="credits">
<h1><a class="toc-backref" href="#id4">Credits</a></h1>
<div class="section" id="authors">
<h2><a class="toc-backref" href="#id5">Authors</a></h2>
<ul class="simple">
<li>Camptocamp</li>
</ul>
</div>
<div class="section" id="contributors">
<h2><a class="toc-backref" href="#id6">Contributors</a></h2>
<ul class="simple">
<li>Patrick Tombez &lt;<a class="reference external" href="mailto:patrick.tombez&#64;camptocamp.com">patrick.tombez&#64;camptocamp.com</a>&gt;</li>
</ul>
</div>
<div class="section" id="maintainers">
<h2><a class="toc-backref" href="#id7">Maintainers</a></h2>
<p>This module is maintained by the OCA.</p>
<a class="reference external image-reference" href="https://odoo-community.org"><img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" /></a>
<p>OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.</p>
<p>This module is part of the <a class="reference external" href="https://github.com/OCA/server-tools/tree/9.0/base_conditional_image">OCA/server-tools</a> project on GitHub.</p>
<p>You are welcome to contribute. To learn how please visit <a class="reference external" href="https://odoo-community.org/page/Contribute">https://odoo-community.org/page/Contribute</a>.</p>
</div>
</div>
</div>
</body>
</html>

53
base_conditional_image/views/image_view.xml

@ -0,0 +1,53 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="view_image_tree" model="ir.ui.view">
<field name="name">image.tree</field>
<field name="model">image</field>
<field name="arch" type="xml">
<tree>
<field name="name" />
<field name="model_name" />
<field name="company_id" />
<field name="selector" />
</tree>
</field>
</record>
<record id="view_image_form" model="ir.ui.view">
<field name="name">image.form</field>
<field name="model">image</field>
<field name="arch" type="xml">
<form>
<group>
<group>
<field name="name"/>
<field name="model_name"/>
<field name="company_id"/>
</group>
<group>
<field name="image" widget='image' class="oe_avatar" options='{"preview_image": "image_medium"}' />
</group>
<group string="Selector">
<field name="selector" nolabel="True" widget="ace" options="{'mode': 'python'}"/>
</group>
</group>
</form>
</field>
</record>
<record id="image_action" model="ir.actions.act_window">
<field name="name">Images</field>
<field name="res_model">image</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
</record>
<menuitem
id="image_menu"
string="Images"
parent="base.menu_ir_property"
action="image_action"
sequence="99"/>
</data>
</openerp>
Loading…
Cancel
Save