##############################################################################
import addons
-import io
import logging
from osv import fields, osv
-from PIL import Image
-import StringIO
+import tools
_logger = logging.getLogger(__name__)
class hr_employee_category(osv.osv):
},
multi='no_of_employee'),
'no_of_recruitment': fields.float('Expected in Recruitment', help='Number of new employees you expect to recruit.'),
- 'employee_ids': fields.one2many('hr.employee', 'job_id', 'Employees'),
+ 'employee_ids': fields.one2many('hr.employee', 'job_id', 'Employees', groups='base.group_user'),
'description': fields.text('Job Description'),
'requirements': fields.text('Requirements'),
'department_id': fields.many2one('hr.department', 'Department'),
_description = "Employee"
_inherits = {'resource.resource': "resource_id"}
- def onchange_photo(self, cr, uid, ids, value, context=None):
- if not value:
- return {'value': {'photo_big': value, 'photo': value} }
- return {'value': {'photo_big': self._photo_resize(cr, uid, value, 540, 450, context=context), 'photo': self._photo_resize(cr, uid, value, context=context)} }
-
- def _set_photo(self, cr, uid, id, name, value, args, context=None):
- if not value:
- vals = {'photo_big': value}
- else:
- vals = {'photo_big': self._photo_resize(cr, uid, value, 540, 450, context=context)}
- return self.write(cr, uid, [id], vals, context=context)
-
- def _photo_resize(self, cr, uid, photo, heigth=180, width=150, context=None):
- image_stream = io.BytesIO(photo.decode('base64'))
- img = Image.open(image_stream)
- img.thumbnail((heigth, width), Image.ANTIALIAS)
- img_stream = StringIO.StringIO()
- img.save(img_stream, "JPEG")
- return img_stream.getvalue().encode('base64')
-
- def _get_photo(self, cr, uid, ids, name, args, context=None):
+ def _get_image(self, cr, uid, ids, name, args, context=None):
result = dict.fromkeys(ids, False)
- for hr_empl in self.browse(cr, uid, ids, context=context):
- if hr_empl.photo_big:
- result[hr_empl.id] = self._photo_resize(cr, uid, hr_empl.photo_big, context=context)
+ for obj in self.browse(cr, uid, ids, context=context):
+ resized_image_dict = tools.get_resized_images(obj.image)
+ result[obj.id] = {
+ 'image_medium': resized_image_dict['image_medium'],
+ 'image_small': resized_image_dict['image_small'],
+ }
return result
+ def _set_image(self, cr, uid, id, name, value, args, context=None):
+ return self.write(cr, uid, [id], {'image': tools.resize_image_big(value)}, context=context)
+
+ def onchange_image(self, cr, uid, ids, value, context=None):
+ return {'value': tools.get_resized_images(value)}
+
_columns = {
'country_id': fields.many2one('res.country', 'Nationality'),
'birthday': fields.date("Date of Birth"),
'resource_id': fields.many2one('resource.resource', 'Resource', ondelete='cascade', required=True),
'coach_id': fields.many2one('hr.employee', 'Coach'),
'job_id': fields.many2one('hr.job', 'Job'),
- 'photo_big': fields.binary('Big-sized employee photo', help="This field holds the photo of the employee. The photo field is used as an interface to access this field. The image is base64 encoded, and PIL-supported. Full-sized photo are however resized to 540x450 px."),
- 'photo': fields.function(_get_photo, fnct_inv=_set_photo, string='Employee photo', type="binary",
+ 'image': fields.binary("Photo",
+ help="This field holds the image used as a photo for the "\
+ "employee. The image is base64 encoded, and PIL-supported. "\
+ "It is limited to a 12024x1024 px image."),
+ 'image_medium': fields.function(_get_image, fnct_inv=_set_image,
+ string="Medium-sized photo", type="binary", multi="_get_image",
+ store = {
+ 'hr.employee': (lambda self, cr, uid, ids, c={}: ids, ['image'], 10),
+ },
+ help="Medium-sized photo of the employee. It is automatically "\
+ "resized as a 180x180px image, with aspect ratio kept. "\
+ "Use this field in form views or some kanban views."),
+ 'image_small': fields.function(_get_image, fnct_inv=_set_image,
+ string="Smal-sized photo", type="binary", multi="_get_image",
store = {
- 'hr.employee': (lambda self, cr, uid, ids, c={}: ids, ['photo_big'], 10),
- }, help="Image used as photo for the employee. It is automatically resized as a 180x150 px image. A larger photo is stored inside the photo_big field."),
+ 'hr.employee': (lambda self, cr, uid, ids, c={}: ids, ['image'], 10),
+ },
+ help="Small-sized photo of the employee. It is automatically "\
+ "resized as a 50x50px image, with aspect ratio keps. "\
+ "Use this field anywhere a small image is required."),
+ 'active': fields.boolean('Active'),
'passport_id':fields.char('Passport No', size=64),
'color': fields.integer('Color Index'),
'city': fields.related('address_id', 'city', type='char', string='City'),
return {'value': {'work_email' : work_email}}
def _get_photo(self, cr, uid, context=None):
- photo_path = addons.get_module_resource('hr','images','photo.png')
- return self._photo_resize(cr, uid, open(photo_path, 'rb').read().encode('base64'), context=context)
+ image_path = addons.get_module_resource('hr', 'images', 'photo.png')
+ return tools.resize_image_big(open(image_path, 'rb').read().encode('base64'))
_defaults = {
'active': 1,
- 'photo': _get_photo,
+ 'image': _get_photo,
'marital': 'single',
'color': 0,
}
<menuitem id="menu_hr_configuration" name="Configuration" parent="hr.menu_hr_root" groups="base.group_hr_manager" sequence="50"/>
<menuitem id="menu_hr_management" name="Human Resources" parent="hr.menu_hr_configuration" sequence="25"/>
- <!--
- ==========
- Employee
- ==========
- -->
+ <!--Employee form view -->
<record id="view_employee_form" model="ir.ui.view">
<field name="name">hr.employee.form</field>
<field name="model">hr.employee</field>
<div class="oe_right oe_button_box">
<!-- Put here related buttons -->
</div>
- <field class="oe_right" name="photo" widget='image' on_change="onchange_photo(photo)"/>
+ <field class="oe_right" name="image_small" widget='image' on_change="onchange_image(image_small)"/>
<div class="oe_title">
<label for="name" class="oe_edit_only"/>
<h1><field name="name"/></h1>
<group string="General">
<field name="user_id" on_change="onchange_user(user_id)"/>
<field name="active"/>
- <field name="parent_id" />
+ <field name="parent_id"/>
</group>
<group groups="base.group_hr_user" string="Social IDs">
<field name="identification_id"/>
</group>
<group string="Contact Information">
<field name="address_home_id"/>
- <field name="address_id" on_change="onchange_address_id(address_id)" />
+ <field name="address_id" on_change="onchange_address_id(address_id)"/>
<field name="work_phone"/>
<field name="mobile_phone"/>
- <field name="work_email" widget="email" />
+ <field name="work_email" widget="email"/>
<field name="work_location"/>
</group>
<group string="Job Information">
<field name="job_id" domain="[('state','!=','old')]" context="{'form_view_ref': 'hr.view_hr_job_employee_form'}"/>
- <field name="coach_id" />
+ <field name="coach_id"/>
</group>
</group>
</page>
<field name="department_id"/>
<field name="job_id"/>
<field name="parent_id"/>
- <field name="coach_id" invisible="1" />
+ <field name="coach_id" invisible="1"/>
</tree>
</field>
</record>
<t t-name="kanban-box">
<div class="oe_employee_vignette">
<div class="oe_employee_image">
- <a type="edit"><img t-att-src="kanban_image('hr.employee', 'photo', record.id.value)" class="oe_employee_picture"/></a>
+ <a type="edit"><img t-att-src="kanban_image('hr.employee', 'image_medium', record.id.value)" class="oe_employee_picture"/></a>
</div>
<div class="oe_employee_details">
<h4><a type="edit"><field name="name"/> (<field name="login"/>)</a></h4>
<field name="company_id" groups="base.group_multi_company"/>
<field name="department_id"/>
<field name="job_id"/>
- <field name="coach_id" invisible="1" />
+ <field name="coach_id" invisible="1"/>
</tree>
</field>
</record>
<field name="arch" type="xml">
<form string="Employee Category" version="7.0">
<group>
- <field name="name" />
- <field name="parent_id" />
+ <field name="name"/>
+ <field name="parent_id"/>
</group>
</form>
</field>
<field name="arch" type="xml">
<form string="Job" version="7.0">
<header>
- <button name="job_recruitement" string="In Recruitement" states="open" type="object"/>
- <button name="job_open" string="Recruitment Done" states="recruit" type="object"/>
+ <span groups="base.group_user">
+ <button name="job_recruitement" string="In Recruitement" states="open" type="object"/>
+ <button name="job_open" string="Recruitment Done" states="recruit" type="object"/>
+ </span>
<field name="state" widget="statusbar" statusbar_visible="recruit,open"/>
</header>
<sheet>
<group>
<group>
- <field name="name" />
- <field name="department_id" />
+ <field name="name"/>
+ <field name="department_id"/>
<field name="company_id" widget="selection" groups="base.group_multi_company"/>
</group>
<group>
<label for="requirements"/>
<field name="requirements"/>
</page>
- <page string="Employees">
+ <page string="Employees" groups="base.group_user">
<field name="employee_ids" widget="many2many" mode="tree,form"/>
</page>
</notebook>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="Job">
- <field name="name" />
- <field name="department_id" />
+ <field name="name"/>
+ <field name="department_id"/>
<field name="company_id" groups="base.group_multi_company"/>
<field name="expected_employees"/>
<field name="no_of_employee"/>
<field name="arch" type="xml">
<form string="Job" version="7.0">
<group col="4">
- <field name="name" />
- <field name="department_id" />
+ <field name="name"/>
+ <field name="department_id"/>
</group>
<label for="description"/>
<field name="description"/>
import math
from _common import rounding
import re
+import tools
from tools.translate import _
def is_pair(x):
'rental': fields.boolean('Can be Rent'),
'categ_id': fields.many2one('product.category','Category', required=True, change_default=True, domain="[('type','=','normal')]" ,help="Select category for the current product"),
'list_price': fields.float('Sale Price', digits_compute=dp.get_precision('Sale Price'), help="Base price for computing the customer price. Sometimes called the catalog price."),
- 'standard_price': fields.float('Cost Price', required=True, digits_compute=dp.get_precision('Purchase Price'), help="Product's cost for accounting stock valuation. It is the base price for the supplier price."),
+ 'standard_price': fields.float('Cost Price', required=True, digits_compute=dp.get_precision('Purchase Price'), help="Product's cost for accounting stock valuation. It is the base price for the supplier price.", groups="base.group_user"),
'volume': fields.float('Volume', help="The volume in m3."),
'weight': fields.float('Gross Weight', digits_compute=dp.get_precision('Stock Weight'), help="The gross weight in Kg."),
'weight_net': fields.float('Net Weight', digits_compute=dp.get_precision('Stock Weight'), help="The net weight in Kg."),
(data['name'] or '') + (data['variants'] and (' - '+data['variants']) or '')
return res
+ def _get_image(self, cr, uid, ids, name, args, context=None):
+ result = dict.fromkeys(ids, False)
+ for obj in self.browse(cr, uid, ids, context=context):
+ resized_image_dict = tools.get_resized_images(obj.image)
+ result[obj.id] = {
+ 'image_medium': resized_image_dict['image_medium'],
+ 'image_small': resized_image_dict['image_small'],
+ }
+ return result
+
+ def _set_image(self, cr, uid, id, name, value, args, context=None):
+ return self.write(cr, uid, [id], {'image': tools.resize_image_big(value)}, context=context)
+
+ def onchange_image(self, cr, uid, ids, value, context=None):
+ return {'value': tools.get_resized_images(value)}
+
_defaults = {
'active': lambda *a: 1,
'price_extra': lambda *a: 0.0,
'pricelist_id': fields.dummy(string='Pricelist', relation='product.pricelist', type='many2one'),
'name_template': fields.related('product_tmpl_id', 'name', string="Name", type='char', size=128, store=True, select=True),
'color': fields.integer('Color Index'),
- 'product_image': fields.binary('Image'),
+ 'image': fields.binary("Image",
+ help="This field holds the image used for the product. "\
+ "The image is base64 encoded, and PIL-supported. "\
+ "It is limited to a 12024x1024 px image."),
+ 'image_medium': fields.function(_get_image, fnct_inv=_set_image,
+ string="Medium-sized image", type="binary", multi="_get_image",
+ store = {
+ 'product.product': (lambda self, cr, uid, ids, c={}: ids, ['image'], 10),
+ },
+ help="Medium-sized image of the product. It is automatically "\
+ "resized as a 180x180px image, with aspect ratio kept. "\
+ "Use this field in form views or some kanban views."),
+ 'image_small': fields.function(_get_image, fnct_inv=_set_image,
+ string="Smal-sized image", type="binary", multi="_get_image",
+ store = {
+ 'product.product': (lambda self, cr, uid, ids, c={}: ids, ['image'], 10),
+ },
+ help="Small-sized image of the product. It is automatically "\
+ "resized as a 50x50px image, with aspect ratio keps. "\
+ "Use this field anywhere a small image is required."),
}
def create(self, cr, uid, vals, context=None):
<filter string="Services" icon="terp-accessories-archiver" domain="[('type','=','service')]"/>
<filter string="Products" icon="terp-accessories-archiver" domain="['|',('type','=','product'),('type','=','consu')]" help="Both stockable and consumable products"/>
<filter string="To Sell" name="filter_to_sell" icon="terp-accessories-archiver-minus" domain="[('sale_ok','=',1)]"/>
- <filter name="filter_to_purchase" string="To Purchase" icon="terp-accessories-archiver+" domain="[('purchase_ok', '=', 1)]" />
+ <filter name="filter_to_purchase" string="To Purchase" icon="terp-accessories-archiver+" domain="[('purchase_ok', '=', 1)]"/>
<separator orientation="vertical"/>
<field name="categ_id" widget="selection" operator="child_of"/>
<group expand="0" string="Context...">
<field name="pricelist_id" widget="selection" context="{'pricelist': self}" groups="product.group_sale_pricelist"/>
- <separator orientation="vertical" groups="base.group_multi_company" />
- <field name="company_id" widget="selection" groups="base.group_multi_company" />
+ <separator orientation="vertical" groups="base.group_multi_company"/>
+ <field name="company_id" widget="selection" groups="base.group_multi_company"/>
</group>
<newline/>
<group expand='0' string='Group by...'>
<filter string='Category' icon="terp-stock_symbol-selection" domain="[]" context="{'group_by' : 'categ_id'}"/>
<separator orientation="vertical"/>
- <filter string='Default Unit of Measure' icon="terp-mrp" domain="[]" context="{'group_by' : 'uom_id'}" />
+ <filter string='Default Unit of Measure' icon="terp-mrp" domain="[]" context="{'group_by' : 'uom_id'}"/>
<separator orientation="vertical"/>
- <filter string='Type' icon="terp-stock_symbol-selection" domain="[]" context="{'group_by' : 'type'}" />
+ <filter string='Type' icon="terp-stock_symbol-selection" domain="[]" context="{'group_by' : 'type'}"/>
<separator orientation="vertical" groups="base.group_multi_company"/>
- <filter string='Company' icon="terp-go-home" domain="[]" context="{'group_by' : 'company_id'}" groups="base.group_multi_company" />
+ <filter string='Company' icon="terp-go-home" domain="[]" context="{'group_by' : 'company_id'}" groups="base.group_multi_company"/>
</group>
</search>
</tree>
</field>
</record>
+
<record id="product_normal_form_view" model="ir.ui.view">
<field name="name">product.normal.form</field>
<field name="model">product.product</field>
<field name="arch" type="xml">
<form string="Product" layout="auto" version="7.0">
<sheet>
- <field name="product_image" widget="image" class="oe_avatar oe_right"/>
+ <field name="image_small" widget="image" class="oe_avatar oe_right" on_change="onchange_image(image_small"/>
<div class="oe_title">
<div class="oe_edit_only">
- <label for="name" string="Product Name" />
+ <label for="name" string="Product Name"/>
</div>
<h1>
<field name="name"/>
</h1>
- <label for="categ_id" class="oe_edit_only" />
- <h2><field name="categ_id" /></h2>
+ <label for="categ_id" class="oe_edit_only"/>
+ <h2><field name="categ_id"/></h2>
</div>
<notebook>
<page string="Information">
<group>
<group>
<field name="default_code"/>
- <field name="ean13" placeholder="5901234123457" />
- <field groups="product.group_product_variant" name="variants" />
+ <field name="ean13" placeholder="5901234123457"/>
+ <field groups="product.group_product_variant" name="variants"/>
</group>
- <group>
+ <group groups="base.group_user">
<field name="sale_ok"/>
<field name="purchase_ok"/>
</group>
<group string="Procurement">
<field name="type"/>
<field name="procure_method"/>
- <field name="supply_method"/>
+ <field name="supply_method" groups="base.group_user"/>
</group>
<group string="Prices">
<field name="list_price"/>
</group>
</page>
- <page string="Procurement & Locations">
+ <page string="Procurement & Locations" groups="base.group_user">
<group>
<group name="delay" string="Delays">
<field name="sale_delay" attrs="{'readonly':[('sale_ok','=',0)]}"/>
<field name="warranty"/>
</group>
<group name="store" string="Storage Localisation">
- <field name="loc_rack" attrs="{'readonly':[('type','=','service')]}" />
+ <field name="loc_rack" attrs="{'readonly':[('type','=','service')]}"/>
<field name="loc_row" attrs="{'readonly':[('type','=','service')]}"/>
<field name="loc_case" attrs="{'readonly':[('type','=','service')]}"/>
</group>
</group>
</page>
- <page string="Suppliers">
+ <page string="Suppliers" groups="base.group_user">
<field name="seller_ids" context="{'uom_id': uom_id}"/>
</page>
- <page string="Descriptions">
- <separator string="Internal Description"/>
+ <page string="Descriptions" groups="base.group_user">
+ <separator string="Description"/>
<field name="description"/>
<separator string="Sale Description"/>
<field name="description_sale" placeholder="This note will be displayed on quotations..."/>
<kanban>
<field name="color"/>
<field name="type"/>
- <field name="product_image"/>
<field name="list_price"/>
<templates>
<t t-name="kanban-box">
<field name="name"/>
</div>
<div class="oe_kanban_box_content oe_kanban_color_bglight oe_kanban_box_show_onclick_trigger">
- <img t-att-src="kanban_image('product.product', 'product_image', record.id.value)" width="48" style="float: left; padding: 0 4px 4px 0"/>
+ <img t-att-src="kanban_image('product.product', 'image_medium', record.id.value)" width="48" style="float: left; padding: 0 4px 4px 0"/>
Code: <field name="code"/>
<div t-if="record.type.raw_value == 'service'">No Stock</div>
<t t-if="record.type.raw_value != 'service'">
<div>Stock: <field name="qty_available"/> on hand, <field name="virtual_available"/> available</div>
<div t-if="record.list_price.raw_value != 0">Public Price: <field name="lst_price"/></div>
- <div>Cost : <field name="standard_price"/></div>
+ <!-- TODO would deserve to be hidden at the field level -->
+ <div groups="base.group_user">Cost : <field name="standard_price"/></div>
</t>
<div class="oe_kanban_clear"/>
</div>
<field name="arch" type="xml">
<form string="Packaging" version="7.0">
<group>
- <field name="name" />
- <field name="type" />
+ <field name="name"/>
+ <field name="type"/>
</group>
</form>
</field>
<group>
<group string="Administration">
<field name="planned_hours" widget="float_time"/>
- <field name="effective_hours" widget="float_time" />
+ <field name="effective_hours" widget="float_time"/>
<field name="resource_calendar_id"/>
</group>
<group string="Miscellaneous" name="misc">
</group>
<newline />
<group expand="0" string="Group By...">
- <filter string="Manager" name="Manager" icon="terp-personal" domain = "[]" context="{'group_by':'user_id'}"/>
- <filter string="Partner" name="Partner" icon="terp-partner" domain = "[]" context="{'group_by':'partner_id'}"/>
+ <filter string="Manager" name="Manager" icon="terp-personal" domain="[]" context="{'group_by':'user_id'}"/>
+ <filter string="Partner" name="Partner" icon="terp-partner" domain="[]" context="{'group_by':'partner_id'}"/>
<separator orientation="vertical"/>
- <filter string="Parent" name="Parent" help="Parent" icon="terp-folder-blue" domain = "[]" context="{'group_by':'parent_id'}"/>
+ <filter string="Parent" name="Parent" help="Parent" icon="terp-folder-blue" domain = "[]" context="{'group_by':'parent_id'}"/>
</group>
</search>
</field>
<div class="oe_kanban_project_avatars">
<t t-foreach="record.members.raw_value" t-as="member">
- <img t-att-src="kanban_image('res.users', 'avatar', member)" t-att-data-member_id="member"/>
+ <img t-att-src="kanban_image('res.users', 'image_small', member)" t-att-data-member_id="member"/>
</t>
</div>
</div>
<field name="arch" type="xml">
<form string="Project" version="7.0">
<header>
- <!--
- <button name="do_open" string="Start Task" type="object"
- states="draft,pending"/>
- <button name="do_draft" string="Draft" type="object"
- states="cancel,done"/>
- -->
- <button name="%(action_project_task_reevaluate)d" string="Reactivate" type="action"
- states="done,cancelled" context="{'button_reactivate':True}"/>
- <button name="action_close" string="Done" type="object"
- states="draft,open,pending"/>
- <button name="do_pending" string="Pending" type="object"
- states="open"/>
- <button name="%(action_project_task_delegate)d" string="Delegate" type="action"
- states="pending,open,draft" groups="project.group_delegate_task"/>
- <button name="do_cancel" string="Cancel" type="object"
- states="draft,open,pending" />
- <button name="stage_previous" string="Previous Stage" type="object"
- states="open,pending" icon="gtk-go-back" attrs="{'invisible': [('stage_id','=', False)]}"/>
- <button name="stage_next" string="Next Stage" type="object"
- states="open,pending" icon="gtk-go-forward" attrs="{'invisible': [('stage_id','=', False)]}"/>
+ <span groups="base.group_user">
+ <!--
+ <button name="do_open" string="Start Task" type="object"
+ states="draft,pending"/>
+ <button name="do_draft" string="Draft" type="object"
+ states="cancel,done"/>
+ -->
+ <button name="%(action_project_task_reevaluate)d" string="Reactivate" type="action"
+ states="done,cancelled" context="{'button_reactivate':True}"/>
+ <button name="action_close" string="Done" type="object"
+ states="draft,open,pending"/>
+ <button name="do_pending" string="Pending" type="object"
+ states="open"/>
+ <button name="%(action_project_task_delegate)d" string="Delegate" type="action"
+ states="pending,open,draft" groups="project.group_delegate_task"/>
+ <button name="do_cancel" string="Cancel" type="object"
+ states="draft,open,pending"/>
+ <button name="stage_previous" string="Previous Stage" type="object"
+ states="open,pending" icon="gtk-go-back" attrs="{'invisible': [('stage_id','=', False)]}"/>
+ <button name="stage_next" string="Next Stage" type="object"
+ states="open,pending" icon="gtk-go-forward" attrs="{'invisible': [('stage_id','=', False)]}"/>
+ </span>
<field name="stage_id" widget="statusbar"/>
</header>
<sheet string="Task">
</group>
<notebook>
<page string="Description">
- <field name="description" attrs="{'readonly':[('state','=','done')]}" placeholder="Add a Description..." />
+ <field name="description" attrs="{'readonly':[('state','=','done')]}" placeholder="Add a Description..."/>
<field name="work_ids" groups="project.group_tasks_work_on_tasks">
<tree string="Task Work" editable="top">
<field name="date"/>
</page>
<page string="Extra Info" attrs="{'readonly':[('state','=','done')]}">
<group col="4">
- <field name="priority"/>
+ <field name="priority" groups="base.group_user"/>
<field name="sequence"/>
- <field name="partner_id" />
+ <field name="partner_id"/>
<field name="state" groups="base.group_no_one"/>
</group>
</page>
<field name="arch" type="xml">
<kanban default_group_by="stage_id" >
<field name="color"/>
- <field name="priority"/>
+ <field name="priority" groups="base.group_user"/>
<field name="stage_id"/>
<field name="user_id"/>
<field name="user_email"/>
<field name="name"/>
</td>
<td valign="top" width="22">
- <img t-att-src="kanban_image('res.users', 'avatar', record.user_id.raw_value[0])" t-att-title="record.user_id.value"
+ <img t-att-src="kanban_image('res.users', 'image_small', record.user_id.raw_value[0])" t-att-title="record.user_id.value"
width="22" height="22" class="oe_kanban_gravatar"/>
</td>
</tr>
<field name="inherit_id" ref="product.product_normal_form_view"/>
<field name="arch" type="xml">
<field name="standard_price" position="replace" version="7.0">
- <label string="Cost Price" for="standard_price" align="1.0"/>
- <div>
+ <label string="Cost Price" for="standard_price" align="1.0" groups="base.group_user"/>
+ <div groups="base.group_user">
<field name="standard_price" attrs="{'readonly':[('cost_method','=','average')]}" nolabel="1"/>
<button name="%(action_view_change_standard_price)d" string="Update"
type="action" icon="gtk-execute" attrs="{'invisible':[('cost_method','<>','average')]}"/>
<group string="Stock and Expected Variations">
<field name="qty_available"/>
<field name="incoming_qty"/>
- <label for="virtual_available" />
+ <label for="virtual_available"/>
<div>
- <field name="virtual_available" class="oe_inline" />
+ <field name="virtual_available" class="oe_inline"/>
<button name="%(action_view_change_product_quantity)d" string="Update" attrs="{'invisible': [('type', '=', 'service')]}"
- type="action" icon="gtk-execute" groups="stock.group_stock_manager,stock.group_stock_user" class="oe_inline" />
+ type="action" icon="gtk-execute" groups="stock.group_stock_manager,stock.group_stock_user" class="oe_inline"/>
</div>
<field name="outgoing_qty"/>
</group>
<kanban>
<field name="color"/>
<field name="type"/>
- <field name="product_image"/>
+ <field name="image"/>
<field name="list_price"/>
<field name="reception_count"/>
<field name="delivery_count"/>
<t t-name="kanban-box">
<div class="oe_product_vignette">
<div class="oe_product_img">
- <a type="edit"><img t-att-src="kanban_image('product.product', 'product_image', record.id.value)" class="oe_product_photo"/></a>
+ <a type="edit"><img t-att-src="kanban_image('product.product', 'image_medium', record.id.value)" class="oe_product_photo"/></a>
</div>
<div class="oe_product_desc">
<h4><a type="edit"><field name="name"></field></a></h4>
<li t-if="record.type.raw_value != 'service'">Stock on hand: <field name="qty_available"/> <field name="uom_id"/></li>
<li t-if="record.type.raw_value != 'service'">Stock available: <field name="virtual_available"/> <field name="uom_id"/></li>
<li>Price: <field name="lst_price"></field></li>
- <li>Cost: <field name="standard_price"></field></li>
+ <!-- TODO the 'groups' attribute doesn't work in kanban views -->
+ <li groups="base.group_user">Cost: <field name="standard_price"></field></li>
</ul>
- <a name="%(action_receive_move)d" type="action">
- <t t-if="record.reception_count.value">Receptions(<t t-esc="record.reception_count.value"/>)</t>
- </a>
- <a name="%(action_deliver_move)d" type="action">
- <t t-if="record.delivery_count.value">Deliveries(<t t-esc="record.delivery_count.value"/>)</t>
- </a>
+ <div groups="base.group_user">
+ <a name="%(action_receive_move)d" type="action">
+ <t t-if="record.reception_count.value">Receptions(<t t-esc="record.reception_count.value"/>)</t>
+ </a>
+ <a name="%(action_deliver_move)d" type="action">
+ <t t-if="record.delivery_count.value">Deliveries(<t t-esc="record.delivery_count.value"/>)</t>
+ </a>
+ </div>
</div>
</div>
<script>