I'm new to odoo and learning developing custom module. Trying to develop an contact management app for company and person. Following are the files and code structure:
#models.py
from odoo import models, fields, api
class company(models.Model):
_name = 'cs_contact.company'
_description = 'Model for create company profile.'
name = fields.Char('Company name', required=True)
country_id = fields.Many2one('res.country', string='Country', help='Select Country', ondelete='restrict', required=True)
ho_address = fields.Text('HO address')
website = fields.Char('Website')
courier_account = fields.Char('Courier Account')
email = fields.Char('Email')
class person(models.Model):
_name = 'cs_contact.person'
_description = 'Model for create person contact.'
name = fields.Char('Full Name', required=True)
country_id = fields.Many2one('res.country', string='Country', help='Select Country', ondelete='restrict', required=True)
email = fields.Char('Email')
im_id = name = fields.Char('Instant messaging ID (Skype/line)')
worked_before = fields.Selection([
('Yes', 'Yes'),
('No', 'No'),
], string="Worked Before?")
how_we_meet = fields.Selection([
('Fair', 'Fair'),
('Email', 'Email'),
('Agent', 'Agent'),
], string="How we meet?")
quantity = fields.Integer(string='Quantity')
note = fields.Text('Note')
Views looke like:
#views.xml
<odoo>
<data>
<!-- explicit list view definition -->
<record model="ir.ui.view" id="cs_contact.list">
<field name="name">cs_contact list</field>
<field name="model">cs_contact.person</field>
<field name="arch" type="xml">
<tree>
<field name="name"/>
<field name="country_id" />
<field name="email"/>
</tree>
</field>
</record>
<record id="view_cs_contactsearch" model="ir.ui.view">
<field name="name">cs_contact list</field>
<field name="model">cs_contact.person</field>
<field name="arch" type="xml">
<search string="Search contacts">
<field name="name"></field>
<field name="country_id"></field>
<field name="email"></field>
</search>
</field>
</record>
</data>
</odoo>
Menu looks like:
#menu.xml
<odoo>
<act_window id="action_company" name=" Company Contacts" res_model="cs_contact.company" view_mode="tree,form" />
<menuitem id="contact_root" name="Contacts" sequence='-1' />
<menuitem id="contact_company" name="Company" parent="contact_root" action="action_company" sequence="-1" />
</odoo>
It's working fine for company contact. Now I'm not getting how to create top menu for person and define view. This is the the design I want. I tried various method from blogs but didn't work. Please help me out.
You have added country_id in cs_contact.person view definition but the field does not exist. Remove it from the view definition or declare it in the corresponding model.
To add the Person menu item next to the Company menu item, you just need to use the same parent and higher sequence number then connect it to the corresponding action.
Example:
<act_window id="action_person" name="Persons" res_model="cs_contact.person" view_mode="tree,form"/>
<menuitem id="contact_person" name="Person" parent="contact_root" action="action_person" sequence="2"/>
Related
In the Sale Order form I added a one2many field named booking_ids which appears within an editable tree view
Within the tree of the order lines, I added a many2one column named booking_id so each orderline have a booking_id.
While in edit mode or create mode of the sale.order how is it possible to show the virtual records added in the booking_ids field within the many2one field which is only showing the records within the database without the virtual ones that are being created.
class SaleOrder(models.Model):
_inherit = 'sale.order'
booking_ids = fields.One2many('sale.booking', 'order_id', string='Bookings')
class SaleOrderLine(models.Model):
_inherit = 'sale.order.line'
booking_id = fields.Many2one('sale.booking', string="Booking")
class Booking(models.Model):
_name = 'sale.booking'
event_id = fields.Many2one('sale.event', String='Event', required=True,
states={'draft': [('readonly', False)], 'sent': [('readonly', False)]})
name = fields.Char(compute='_get_name')
event_date = fields.Date(string='Event Date')
order_id = fields.Many2one('sale.order', string='Order Reference', ondelete='cascade', index=True, copy=False, readonly=True)
order_line_ids = fields.One2many('sale.order.line', 'booking_id', string='Order Lines')
XML
<xpath expr="//field[#name='payment_term_id']/.." position="after">
<group>
<field name="booking_ids">
<tree editable="bottom">
<field name="event_id"/>
<field name="event_date" string="Date"/>
<field name="order_line_ids" widget="many2many_tags" readonly="1"/>
</tree>
</field>
</group>
</xpath>
<xpath expr="//tree//field[#name='product_id']" position="after">
<field name="order_id" invisible="1"/>
<field name="booking_id" domain="['|', ('order_id', '=', None), ('order_id', '=', order_id)]"/>
</xpath>
<xpath expr="//field[#name='order_line']//field[#name='product_id']/.." position="after">
<field name="order_id" invisible="1"/>
<field name="booking_id" domain="['|', ('order_id', '=', None), ('order_id', '=', order_id)]"/>
</xpath>
thank you
Use a preload in Python code. This will solve your problem.
So this is my mass mailing code for sale orders. But I just missing here one thing. it's that it should add a sale order report that I created to each of SO I'm generating e-mail for. any suggestions how can I make this work?
<data>
<act_window name="Mass Sale Order Email"
res_model="mail.compose.message"
src_model="sale.order"
view_mode="form"
multi="True"
target="new"
key2="client_action_multi"
id="action_send_mass_sale_order"
context="{
'default_composition_mode': 'mass_mail',
'default_email_to': '{($object.email or \'\')|safe}',
'mass_mark_sale_order_as_sent': True,
'default_model': 'sale.order',
}"
/>
</data>
class MailComposeMessage(models.TransientModel):
_inherit = 'mail.compose.message'
#api.multi
def send_mail(self, auto_commit=False):
context = self._context
sale_order = self.env['sale.order']
sale_order_ids = context.get('active_ids')
if context.get('mass_mark_sale_order_as_sent') and \
context.get('default_model') == 'sale.order':
for order in sale_order.browse(sale_order_ids):
order.sent = True
return super(MailComposeMessage, self).send_mail(auto_commit=auto_commit)
<report
id="report_htp_sale_order"
string="Htp Sale Order"
model="sale.order"
name="config_htp.htp_sale_order"
rml="config_htp/report/htp_sale_order.ods"
menu="True"
/>
<record model="ir.actions.report.xml" id="report_htp_sale_order">
<field name="report_type">aeroo</field>
<field name="parser_loc">config_htp/report/htp_sale_order.pyc</field>
<field name="tml_Source">file</field>
<field name="parser_state">loc</field>
<field name="out_format" ref="report_aeroo.report_mimetypes_ods_ods"/>
<field name="in_format">oo-ods</field>
<field name="auto" eval="True" />
</record>
In context, we need to add a default template and in that template, we can choose what report we want to attach to it.
'default_use_template': True,
'default_template_id': ref('sale.email_template_edi_sale'),
I have some problem with tree/form view in Odoo.
My model have such classes: https://yadi.sk/d/sCLVo3gHtbVEu
class URLList(models.Model):
_name = 'webvisitorcalc.url_list'
url = fields.Char(string="URL", required=True)
url_parametes = fields.Char(string="URL parameters") #пераметры URLб всё что идёт после ?
target_session_id = fields.One2many('webvisitorcalc.session_visitor', 'target_url_ids', string='Target URL')
site_trip_prevouse_id = fields.One2many('webvisitorcalc.site_trip', 'url_prevouse_ids', string='Prevouse URL')
site_trip_current_id = fields.One2many('webvisitorcalc.site_trip', 'url_current_ids', string='Current URL')
remote_sites_id = fields.One2many('webvisitorcalc.remote_sites', 'site_url_ids', string='Remote site page with URL')
remote_sites_target_url_id = fields.One2many('webvisitorcalc.remote_sites', 'target_url_ids', string='URL on remote site page')
#api.multi
def url_exist(self, cr, SUPERUSER_ID, urlForCheck):
_logger.error("Check URL exist in DB ")
result = False
if (self.search_count(cr, SUPERUSER_ID, [('url', '=', urlForCheck)])>0):
result = True
return result
class SiteTrip(models.Model):
_name = 'webvisitorcalc.site_trip'
session_ids = fields.Many2one('webvisitorcalc.session_visitor', string='Session ID', index=True)
url_prevouse_ids = fields.Many2one('webvisitorcalc.url_list', string='Prevouse URL', index=True)
url_current_ids = fields.Many2one('webvisitorcalc.url_list', string='Current URL', index=True)
Template for this model: https://yadi.sk/d/Ob0o65PutbVFA
<record model="ir.actions.act_window" id="site_trip_list_action">
<field name="name">Site trip</field>
<field name="res_model">webvisitorcalc.site_trip</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="help" type="html">
<p class="oe_view_nocontent_create">Create the first record for site trip
</p>
</field>
</record>
<record model="ir.actions.act_window" id="url_list_list_action">
<field name="name">URL list</field>
<field name="res_model">webvisitorcalc.url_list</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="help" type="html">
<p class="oe_view_nocontent_create">Create the first url
</p>
</field>
</record>
<record model="ir.ui.view" id="site_trip_tree_view">
<field name="name">site_trip.tree</field>
<field name="model">webvisitorcalc.site_trip</field>
<field name="arch" type="xml">
<tree string="URL list tree">
<field name="session_ids"/>
<field name="url_prevouse_ids" string="PrevURL">
</field>
<!--<field name="url_prevouse_ids"/>-->
<field name="url_current_ids"/>
</tree>
</field>
</record>
<record model="ir.ui.view" id="url_list_tree_view">
<field name="name">url_list.tree</field>
<field name="model">webvisitorcalc.url_list</field>
<field name="arch" type="xml">
<tree string="URL list tree">
<field name="url"/>
<field name="url_parametes"/>
</tree>
</field>
</record>
<menuitem id="site_trip_menu" name="Site trip" parent="webvisitorcalc_menu"
action="site_trip_list_action"/>
<menuitem id="url_list_menu" name="URL list" parent="webvisitorcalc_menu"
action="url_list_list_action"/>
Screenshots are here:
Tree view for class SiteTrip
http://i.stack.imgur.com/FjRDK.png
Form view for class SiteTrip
http://i.stack.imgur.com/uDbOp.png
Tree view for class URLList
http://i.stack.imgur.com/tXzqL.png
Form view for class URLList
http://i.stack.imgur.com/oVnqg.png
As you see URLList displayed fine. For class SiteTrip present problem. Field is displaying not data from URLList. This is field stored element such webvisitorcalc.url_list.ID (array?). How I can display real data in this field (for example URL: http://some-site.com/page.html)?
URL in URLList must be uniq. SiteTrip must have stored only ID of URLList record.
UPD:
class RemoteSites(models.Model):
_name = 'webvisitorcalc.remote_sites'
site_id = advert_company_id = fields.One2many('webvisitorcalc.site_list', 'remote_sites_ids', string='Site')
site_url_ids = fields.Many2one('webvisitorcalc.url_list', string='URL page ')
target_url_ids = fields.Many2one('webvisitorcalc.url_list', string='URL target page')
You obviously have no name field on your webvisitorcalc.url_list model. Odoo needs this to use it as name in webclient wherever you use this model as e.g. many2one field or in the breadcrumb navigation.
So either you define a name field or you set _name on your class with another field identifier.
You can also (re-)define the method display_name on your model (enough examples in Odoo code) where you can do more cool stuff with the record display name :-)
I'd like to show invoices adressed to child partner in the parent partner form view.
I've already a inherited res_partner model as follow :
class res_partner(osv.osv):
_inherit = 'res.partner'
_columns = {
'invoice_ids': fields.one2many('account.invoice', 'partner_id', 'Invoices'),
}
And a view displaying invoices as follow :
<?xml version="1.0"?>
<openerp>
<data>
<!-- Partners inherited form -->
<record id="view_history_partner_info_form" model="ir.ui.view">
<field name="name">res.partner.cap_history.form.inherit</field>
<field name="inherit_id" ref="base.view_partner_form"/>
<field name="model">res.partner</field>
<field name="arch" type="xml">
<page string="Accounting" position="after" version="7.0">
<page string="History" name="cap_history_tab">
<group name="grp_invoice_history" string="Invoices History">
<field name="invoice_ids" colspan="4" nolabel="1">
<tree string="Partner Invoices" create="false" delete="false">
<field name="number" readonly="True"/>
<field name="origin" readonly="True"/>
<field name="name" string="Reference" readonly="True"/>
<field name="date_invoice" readonly="True"/>
<field name="x_category" readonly="True"/>
<field name="state" readonly="True"/>
<field name="payment_term" readonly="True"/>
<field name="amount_total" readonly="True"/>
</tree>
</field>
</group>
</page>
</page>
</field>
</record>
With this code I can see invoices that are directly adressed to a company or a person on their respective form view.
But if an invoice is adressed to person, and none is adressed to the parent company, when I am on the company form view, I won't see the invoice adressed to the child contact.
Is there a way to make visible the contact's invoice in the parent partner form view ?
Thank you for your help !
Cheers
One way to do this is to add a new field, all_invoice_ids, as a function field, and then have the function return both the contents of invoice_ids, plus the contents of any child's invoice_ids.
Something like this (untested):
'all_invoice_ids': fields.function(
_get_invoice_ids,
type='one2many',
obj='account.invoice',
method=True,
string='Invoices',
),
and _get_invoice_ids (which should be defined before columns) like this (also untested):
def _get_invoice_ids(self, cr, uid, ids, field_name, arg, context=None):
res = {}
if isinstance(ids, (int, long)):
ids = [ids] # in case an id was passed in directly
for main_partner in self.browse(cr, uid, ids, context=context):
main_invoices = main_partner.invoice_ids or [] # in case it was False
invoices = [inv.id for inv in main_invoices]
for child_partner in main_partner.child_ids:
child_invoices = child_partner.invoice_ids or []
invoices.extend([inv.id for inv in child_invoices])
# at this point we should have all the invoice ids
# use a set to get rid of duplicates
invoices = list(set(invoices))
# and store in res to be returned
res[main_partner.id] = invoices
return res
I'm writing a warehouse management module and I came to the inventory step.
I need to make an inventory every now and then for each warehouse separately and each inventory operation will be kept in the database as a master-detail relation,
ie:
one record for the basic data such as id, date, warehouse_id etc. and
this will be recorded in a table created by (inventory) object.
many records will keep the details of the operation (one record for each material) recording the material id, inventory id, balance, etc. and this will be recorded in the table (inventory_lines).
During the data entry, when the user selects a material, I need to check its current balance and display it in the balance field. In order to do this, I'll need to know the warehouse id because every warehouse shall have separate inventories.
I have many materials stored in many warehouses.
For example: I can have a quantity of 5 pens in warehouse A and 10 pens in warehouse B and 6 pens in warehouse C.
First, I select the warehouse (A or B or C) --- let's say warehouse B
Then I select the material (Pen or notebook or whatever) --- let's say Pen
Now, I want to search the database to find the balance of (Pen) in (Warehouse B)
I can write something like this:
select balance from inventory_lines where material_id=mmmmmm and warehouse_id=wwwwww
So, I need to get the material id (mmmmm) and the warehouse id (wwwww)
And that will be done with each material I choose.
The warehouse id is in the column: inventory_id in the object: inventory
'warehouse_id' : fields.many2one('makhazen.warehouse', 'Warehouse Name',required=True),
The material id is in the column: material_id of the object inventory_line as in the picture in the question
'material_id' : fields.many2one('makhazen.material' ,'Material Name'),
I faced the following problem:
I could use the (on_change) method in the form view on the material_id field and could trigger a method to search for the balance in the database but I needed the warehouse_id which I couldn't get.
The questions are:
- How are this master-detail relationship is handled in openerp? how values are passed between the master table and the details table?
- How can we extend the scope of the warehouse_id so that it can be seen from any method in the module?
- I could change the values of the fields by calling a method and returning the desired values in a dictionary, but how to do the opposite (read them)?
It's very critical matter to me.
Firstly, you don't need the warehouse_id field in the wh_inventory_line class. You can always access it trough the the parent object:
inventory_line = self.pool.get('wh.inventory.line').browse(cr, uid, line_id)
wharehouse_id = inventory_line.inventory_id.warehouse_id.id
Secondly, in your case you can just pass the warehouse_id value as parameter to your onchange method. Something like this:
<field name="material_id"
on_change="onchange_material_id(material_id, warehouse_id)"/>
or, if you follow my first advice and remove the warehouse_id from wh_inventory_line:
<field name="material_id"
on_change="onchange_material_id(material_id, parent.warehouse_id)"/>
EDIT
After testing on OpenERP 6.0 I found some errors in your code. I'm just wondering how did you manage to run it.
First, you missed a quote (\') on the warehouse_id column definition of your wh.inventory model:
_columns = {
'date': fields.datetime('Date'),
'warehouse_id': fields.many2one('wh.warehouse', 'Warehouse Name, required=True),
Second, the fields.char() field definition takes at least size parameter additionally to the supplied Field Name. Again, you missed a quote on the following line:
'notes': fields.char('Notes),
Not an error but something you should consider too - you tagged your question with the openerp-7 tag. In OpenERP v7 inheriting from osv.osv is deprecated. Inherit from osv.Model instead.
If I insist on your errors it's because the solution I proposed to you is working fine on my side. So there must be some little error somewhere that prevents your code for doing what is expected.
Here is my test code. You can try it:
wh.py
# -*- encoding: utf-8 -*-
import netsvc
import pooler
from osv import fields, osv
class wh_warehouse(osv.osv):
_name = 'wh.warehouse'
_columns = {
'name': fields.char('Name', 128),
}
wh_warehouse()
class wh_material(osv.osv):
_name = 'wh.material'
_columns = {
'name': fields.char('Name', 128),
}
wh_material()
class wh_inventory(osv.osv):
_name = 'wh.inventory'
_columns = {
'date': fields.datetime('Date'),
'warehouse_id': fields.many2one('wh.warehouse', 'Warehouse Name', required=True),
'inventory_line_ids': fields.one2many('wh.inventory.line', 'inventory_id', 'Inventory'),
'notes': fields.char('Notes', 512),
'balance_track': fields.boolean('Balance Track'),
}
wh_inventory()
class wh_inventory_line(osv.osv):
_name = 'wh.inventory.line'
_columns = {
'inventory_id': fields.many2one('wh.inventory', 'Inventory'),
'material_id': fields.many2one('wh.material', 'Material'),
'balance': fields.float('Balance'),
'previous_balance': fields.float('Previous Balance'),
'notes': fields.char('Notes', 512),
}
def onchange_material_id(self, cr, uid, ids, material_id, warehouse_id):
return = {'value': {
'notes': 'Selected material {0} and warehouse {1}'.format(material_id, warehouse_id), }
}
wh_inventory_line()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
wh_view.xml
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="view_wh_inventory_form" model="ir.ui.view">
<field name="name">wh.inventory.form</field>
<field name="model">wh.inventory</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Warehouse Inventory">
<field name="date"/>
<field name="warehouse_id" widget="selection"/>
<field name="notes"/>
<field name="balance_track"/>
<field colspan="4" name="inventory_line_ids" widget="one2many_list">
<tree string="Details" editable="bottom">
<field name="material_id" widget="selection"
on_change="onchange_material_id(material_id, parent.warehouse_id)"/>
<field name="balance"/>
<field name="previous_balance"/>
<field name="notes"/>
</tree>
</field>
</form>
</field>
</record>
<record id="view_wh_inventory_tree" model="ir.ui.view">
<field name="name">wh.inventory.tree</field>
<field name="model">wh.inventory</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="Warehouse Inventory">
<field name="date"/>
<field name="warehouse_id" widget="selection"/>
<field name="notes"/>
<field name="balance_track"/>
</tree>
</field>
</record>
<record id="action_wh_inventory_form" model="ir.actions.act_window">
<field name="name">Warehouse Inventory</field>
<field name="res_model">wh.inventory</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="view_id" ref="view_wh_inventory_tree"/>
</record>
<menuitem
action="action_wh_inventory_form"
id="menu_wh_inventory_form"
parent="account.menu_finance"
/>
<!-- Sample data -->
<record id="warehouse_1" model="wh.warehouse">
<field name="name">Warehouse 1</field>
</record>
<record id="warehouse_2" model="wh.warehouse">
<field name="name">Warehouse 2</field>
</record>
<record id="warehouse_3" model="wh.warehouse">
<field name="name">Warehouse 3</field>
</record>
<record id="material_1" model="wh.material">
<field name="name">Material 1</field>
</record>
<record id="material_2" model="wh.material">
<field name="name">Material 2</field>
</record>
<record id="material_3" model="wh.material">
<field name="name">Material 3</field>
</record>
</data>
</openerp>