warning:
I just discovered that my solution actually breaks something and essentially makes it impossible for the user to change the contact's image. I am sorry, i'll look for a way to fix that.
EDIT:
I found an easier way to do this. The idea is essentially similar to the old answer and builds on some of its concepts, so i'd suggest to look at it first.
The differences with my initial approach are the following:
First of all, let's use a "object" type of button, defined as:
<xpath expr="//field[@name='image']" position="replace">
<button id="partner_id_button"
type="object"
name="dummy_method">
<field class="image_midsize" name="image" widget="image"></field>
</button>
</xpath>
So, essentially, instead of looking for an action defined in the xml (which we defined in the old answer but is useless now and can be deleted or commented out), this button calls a python method defined in the model.
We really do not need a method here, but we have to define a dummy one or else odoo will complain... so, in the model, add the method
def dummy_method(self):
return True
A very stupid thing... but at least now we have a clickable button which does not break!
Now, let us make an hand-made popup which will contain a bigger version of the image.
First of all, we need to import css and js in the mix. This is done by
1 - adding an asset file in the views folder (say: assets.xml)
2 - adding a reference to "views/assets.xml" in the "data" array in the __manifest__ file
3 - creating folders "static/src/js" and "static/src/css" for our client-side code to be put into (custom_partner.js and style.css in my examples).
In brief, the content of those files will be the following:
(1) assets.xml:
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<template id="custom_partner_assets" name="custom_partner_assets" inherit_id="web.assets_backend">
<xpath expr="." position="inside">
<link rel="stylesheet" type="text/css" href="/custom_partner/static/src/css/style.css"/>
<script type="text/javascript" src="/custom_partner/static/src/js/custom_partner.js"></script>
</xpath>
</template>
</data>
</odoo>
(2) manifest file (extract)
# always loaded
'data': [
# 'security/ir.model.access.csv',
'views/views.xml',
'views/templates.xml',
'views/assets.xml',
],
(3a) custom_partner.js
odoo.define('custom_partner.module', function (require) {
"use strict";
//catch all clicks in the document
$(document).on('click', function(event) {
//if the user clicked my button...
if(event.target.id==="partner_id_button"){
//finds the image source in the document
var elem = $('img[name="image"]')[0];
var my_src = elem.src;
//creates the popup div
var my_div = document.createElement("div");
my_div.className="custom_popup";
//creates the big image!!!1!
var img = document.createElement("img");
img.src = my_src;
my_div.appendChild(img);
//let us remove the popup when it is clicked
my_div.onclick = function()
{
my_div.parentNode.removeChild(my_div);
}
document.body.appendChild(my_div)
return;
}
});
});
(3b) style.css
.image_midsize > img {
width:64px;
height:64px;
}
.custom_popup {
position:fixed;
padding: 10px;
margin: 10px;
background-color:#FFFFFF;
border: 1px solid #777777;
}
That's it... at least now you can modify simple js or css in order to adapt the display and behaviour to your needs..!
OLD ANSWER
Ok, I'll try to give some kind of answer, but it's far from complete and surely is not very elegant.
Sorry for answering so late, but i'm still trying to learn the basics of odoo and i am quite baffled by the difficulty of getting easy stuff done.
I understand your difficulties and, as an exercise, I tried to find a solution to your problem but some help by users more expert than me may still be necessary for this stuff to work... I hope at least to helping you understanding some of the quirks I had an hard time understanding myself!
So...
First of all, if you did not do it already, create a custom module (you can use the scaffold command for that... you can find info online for that). Let's say the name of this custom module is "custom_partner".
Now, you want to define a model inheriting from "res.partner". So, in the models.py file, you can define it like this:
class CustomPartner(models.Model):
_inherit = 'res.partner'
_name = 'res.partner'
#here you can define custom fields and methods etc...
Ok. Now you need to change how stuff is displayed, so you have to modify the partner views.
You need to write something like this in the "views.xml" file:
<odoo>
<data>
<record id="custom_partner_view" model="ir.ui.view">
<field name="name">custom.partner.view</field>
<field name="model">res.partner</field>
<field name="inherit_id" ref="base.view_partner_form"/>
<field name="arch" type="xml">
<!-- here goes your customization -->
</field>
</record>
</data>
</odoo>
This essentially allows you to change how stuff work and are displayed in the view.
Now, the important stuff goes inside the "xml" field, where i wrote the comment "here goes your customization".
You can put the following snippet there:
<xpath expr="//field[@name='image']" position="replace">
<button
id="partner_id_button"
type="action"
name="%(custom_partner.image_wizard)d"
context="{'x_image': image}"
string="">
<field name="image" widget="image"></field>
</button>
</xpath>
This essentially means: "please replace the image field with the stuff i tell you". the command //field[@name='image'] is an xpath string. Xpath is a tool used to navigare and locate stuff in an xml file. The 'image' field is the one you want to change.
Now, the stuff inside the xpath tag is essentially a button who is wrapping your custom image field.
The button is an "action" odoo button (you may look for info on the web and hope to find some documentation who is not yet totally deprecated). This essentially means: when the user clicks the button, execute the action "custom_partner.image_wizard".
So you need to define the action.
In the views.xml file, you can add this (inside the "data" tag):
<record model="ir.ui.view" id="wizard_form_view">
<field name="name">wizard.form</field>
<field name="model">custom_partner.imagewizard</field>
<field name="arch" type="xml">
<form string="Image">
<field name="x_image" widget="image"/>
</form>
</field>
</record>
This means that this action, when executed, will open a window (called "wizard" in oddo terms), defined as a model "custom_partner.imagewizard".
Guess what? You need to define the bloody wizard. So, go back to models.py and define a wizard (wizard are also known as transient model):
class ImageWizard(models.TransientModel):
_name = 'custom_partner.imagewizard'
x_image = fields.Binary();
This means that the wizard will have an image of its own (i called it with a "x_" prefix because they told me its better for ensuring backward compatibilty and the like, but i'm not so sure...).
Now, did you notice that "context" attribute in the xml definition of the button? This essentially allows information to be passed from the "partner" object to the "wizard" object. It says: let the x_image field of my wizard be the same as the "image" field of the partner object.
Hopefully, if i didn't miss anything, now the picture is clickable and a wizard opens.
Now the problem is making the image appear in the wizard. I still could not find a good way to do so! Is anyone willing to fill this last gap? Thanks!!! I'll edit this answer if i find a way...
Hope to having been of some help! Cheers.