Odoo One2many relation with VIEW table in postgresql - postgresql

I have the following report model:
class crm_purchased_products(models.Model):
_name = "crm.purchased_products"
_description = "Most purchased products report"
_auto = False
partner_id = fields.Many2one('res.partner', string='Customer')
product_id = fields.Many2one('product.product', string='Product')
invoice_qty = fields.Integer('Number of invoices')
quantity = fields.Integer('Quantity')
total_amount_untaxed = fields.Float(string='Total amount', digits=dp.get_precision('Account'))
def init(self, cr):
tools.drop_view_if_exists(cr, self._table)
_query = """CREATE OR REPLACE VIEW crm_purchased_products AS (
SELECT ail.partner_id AS partner_id, ail.product_id AS product_id,
COUNT(ail.invoice_id) AS invoice_qty, SUM(ail.quantity) AS quantity,
SUM(ail.price_subtotal) AS total_amount_untaxed, MAX(ai.date_invoice) AS last_purchase,
(MAX(ai.date_invoice) - MIN(ai.date_invoice))/COUNT(ail.invoice_id) AS days_between_purchases
FROM account_invoice_line AS ail
JOIN account_invoice AS ai ON ail.invoice_id = ai.id
WHERE ai.type = 'out_invoice' AND ai.state IN ('open','paid')
GROUP BY ail.partner_id, ail.product_id HAVING ail.product_id > 0 ORDER BY ail.partner_id ASC
);
"""
def search(self, cr, uid, args, offset=0, limit=None, order=None,context=None, count=False):
return super(crm_purchased_products, self).search(cr, uid, args=args, offset=offset, limit=limit, order=order,
context=context, count=count)
crm_purchased_products()
I want to insert as a tree field in res.partner form view to show only the products associated to the contact:
<page name="internal_notes" string="Internal Notes">
<field name="purchased_products">
<tree string="Most purchased products">
<field name="partner_id" invisible="1"/>
<field name="product_id"/>
<field name="invoice_qty"/>
<field name="quantity"/>
<field name="total_amount_untaxed"/>
</tree>
</field>
</page>
But, when I try to relate it from res.partner:
purchased_products = fields.One2many('crm.purchased_products', 'partner_id', string='Purchased products', readonly=True, copy=True)
I get this error:
ProgrammingError: relation "crm_purchased_products" does not exist
LINE 1: SELECT "crm_purchased_products".id FROM "crm_purchased_produ...

ID field is auto added to all models from models.Model, so you must get it. Try this:
def init(self, cr):
tools.drop_view_if_exists(cr, self._table)
_query = """CREATE OR REPLACE VIEW crm_purchased_products AS (
SELECT row_number() OVER () AS id, ail.partner_id AS partner_id, ail.product_id AS product_id,
COUNT(ail.invoice_id) AS invoice_qty, SUM(ail.quantity) AS quantity,
SUM(ail.price_subtotal) AS total_amount_untaxed, MAX(ai.date_invoice) AS last_purchase,
(MAX(ai.date_invoice) - MIN(ai.date_invoice))/COUNT(ail.invoice_id) AS days_between_purchases
FROM account_invoice_line AS ail
JOIN account_invoice AS ai ON ail.invoice_id = ai.id
WHERE ai.type = 'out_invoice' AND ai.state IN ('open','paid')
GROUP BY row_number() OVER (), ail.partner_id, ail.product_id HAVING ail.product_id > 0 ORDER BY ail.partner_id ASC
);
"""

Related

Odoo domain_filter not working (always enforcing JOIN)

I am having a problem creating a filter on Odoo 11.0 Community Edition.
On my domain class I have a self-relationship with a column called parent_id. I am trying to make a search filter, but even if I add one condition to avoid make the join, it's still not working.
Here is my domain definition:
class Subscription(models.Model):
_name = "subscription"
_rec_name = 'name'
parent_id = fields.Many2one(
'subscription',
string="Derived From",
index=True,
readonly=True
)
code = fields.Char(
string="Reference",
required=True,
index=True,
readonly=True,
copy=False
)
# other field definitions ...
and here is the filter that I am trying to do:
<record id="search_view_subscription" model="ir.ui.view">
<field name="name">subscription.search</field>
<field name="model">subscription</field>
<field name="arch" type="xml">
<search string="Subscriptions">
<field name="code" string="Subscription"
filter_domain="[
'|',
'&',
('parent_id', '=', False),
('code', 'ilike', self),
'&',
('parent_id', '!=', False),
('parent_id.code', 'ilike', self)
]"
/>
<!-- ... other filters working -->
</search>
<field>
</record>
I am not sure if the prefix notation is correct to do what I want, but essentially what I am trying to do is to recover from the database all the records that match the condition:
code ilike '%CERTAIN_VALUE%' OR parent_id.code ilike '%CERTAIN_VALUE%'
Where CERTAIN_VALUE is the user input from the treeview screen.
It seems the condition ('parent_id', '=', False) is being ignored
The filter_domain attribute can contain an arbitrary domain, so you're restricted neither to searching for the same field you named in the name attribute nor to using only one term. The self variable is what the user filled in, and also the only variable that you can use here. Here's a more elaborate example from the default search view for partners:
<search >
<field name="name"
filter_domain="[ '|', '|',
('display_name', 'ilike', self),
('ref', '=', self),
('email', 'ilike', self)]"/>
</search>
pay attention
Works in search tags <search> </search>

computed field that does not compute and default that does not work (odoo-12)

I have this field with a method in my model which aims to detect the changes in the many2one:
manytoone = fields.Many2one(comodel_name="product.template", string="Many to One",
required=False, )
cambio_realizado = fields.Boolean(string="Cambios en Many to One", default=False)
#api.onchange('manytoone')
def _detectar_cambio(self):
self.cambio_realizado = True
No works the default=False in Boolean Field. Always start in True.
And the other problem is that no works a computed field:
#api.multi
def computer_function(self):
self.computation = 243+234
computation = fields.Float(string="Result: ", compute=computer_function, readonly=True)
The result is zero... always in the view.
identation ok, and the model is inherited
My Class and my view with the tips:
class CustomModule(models.Model):
_inherit = 'sale.order'
name = fields.Char('campos relacionales, decoradores onchange y funcion computar')
manytoone = fields.Many2one(comodel_name="product.template", string="Many to One",
required=False, )
cambio_realizado = fields.Boolean(string="Cambios en Many to One")
#api.onchange('manytoone')
def _detectar_cambio(self):
self.cambio_realizado = True
onetomany = fields.One2many(comodel_name="sale.order", inverse_name="manytoone",
string="One to Many", required=False, )
manytomany = fields.Many2many(comodel_name="sale.order",
relation="sale_handler",
column1="order_id", column2="order_handler_id",
string="Many to Many", )
#api.depends('computation')
def computer_function(self):
for record in self:
record.computation = 300
computation = fields.Float(string="Result: ", compute=computer_function, readonly=True)
<odoo>
<!-- Inherit Form View to Modify it -->
<record id="custom_view_custom" model="ir.ui.view">
<field name="name">custom.view.custom</field>
<field name="model">sale.order</field>
<field name="inherit_id" ref="sale.view_order_form"/>
<field name="arch" type="xml">
<xpath expr="//sheet" position="inside">
<group>
<field name="manytoone"/>
<field name="onetomany"/>
<field name="manytomany"/>
</group>
<group>
<field name="computation"/>
<field name="cambio_realizado"/>
</group>
</xpath>
</field>
</record>
</odoo>
#api.one
def computer_function(self):
self.computation = 243+234
computation = fields.Float(string="Result: ", compute=computer_function, readonly=True)
use #api.one in your code
1- onchnage, when you try to create a new record, the onchange called automatically then cambio_realizado set to true
#api.onchange('manytoone')
def _detectar_cambio(self):
for o in self:
if o.manytoone:
o.cambio_realizado = True
2- in compute it's preferally to use api.depends('somefield'), but the code bellow may be work for you, use a loop and don't use readonly
#api.multi
def computer_function(self):
for o in self:
o.computation = 243+234
computation2 = fields.Float(string="Result: ", compute=computer_function)

Odoo 10 : Failed to render mail template

I have created an mail template in Odoo 10, and call it with a cron task. The problem is that it doesn't work and give me error, here is the log : https://pastebin.com/c7zCXbxF. Could you help me?
Here is the mail template:
<odoo>
<data>
<record id="crm_lead_reminder" model="mail.template">
<field name="name">Rappel sur le pipeline</field>
<field name="email_from">admin#example.com</field>
<field name="subject">Rappel ${object.type} ${object.name} </field>
<field name="email_to">${object.user_id.partner_id.email}</field>
<field name="model_id" ref="sale_cron.model_crm_lead"/>
<field name="auto_delete" eval="True"/>
<field name="body_html">
<![CDATA[
<p>
hello world
</p>
]]>
</field>
</record>
</data>
And here is the methode that call it:
class sale_cron(models.Model):
_inherit = 'crm.lead'
def _trigger_action(self, date_action, current_date):
date_action = [int(date) for date in date_action.split('-')]
if date_action[0] == current_date.year:
if date_action[1] == current_date.month:
if date_action[2] == current_date.day or date_action[2] == current_date.day + 1:
return 0
return -1
def _check_crm_lead(self):
current_date = datetime.datetime.now()
for crm_lead_id in self.search([('stage_id', '!=', 4)]):
i = self._trigger_action(crm_lead_id.date_action, current_date)
if i == -1:
return 0
template = self.env.ref('sale_cron.crm_lead_reminder')
template.send_mail(self.user_id.id, force_send=True, raise_exception=True)
return 1
ps: the module name is sale_cron.
Try changing your code like this
template.send_mail(crm_lead_id.id, force_send=True, raise_exception=True)
def _check_crm_lead(self):
current_date = datetime.datetime.now()
for crm_lead_id in self.search([('stage_id', '!=', 4)]):
i = self._trigger_action(crm_lead_id.date_action, current_date)
if i == -1:
return 0
template = self.env.ref('sale_cron.crm_lead_reminder')
template.send_mail(crm_lead_id.id, force_send=True, raise_exception=True)
return 1

How to send email notification when Project Issue was created? Odoo 9

Hi I have created new issue but I cannot get email notification.
How do you do that?
Edited
I've add some code below but I cannot get message_follower_ids from self to send emails.
class project_issue(osv.osv):
_inherit = 'project.issue'
_columns = {}
def create(self, cr, uid, vals, context=None):
res = super(project_issue, self).create(cr, uid, vals, context=context)
return res
Updated
I updated the code to get followers email address and successfully sent the mails but they go to one email.
And Its object.name is partner's name but I want it to be issue name.
def create(self, cr, uid, vals, context=None):
res = super(project_issue, self).create(cr, uid, vals, context=context)
issue = self.pool.get('project.issue').browse(cr, uid, res, context=context)
template = self.pool.get('ir.model.data').get_object(cr, uid, 'customized_project', 'email_template_customer_auto')
for follower in issue.message_partner_ids:
self.pool.get('mail.template').send_mail(cr, uid, template.id, follower.id, force_send=True, raise_exception=True, context=context)
here is a email template
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data noupdate="1">
<!--Email template-->
<record id="email_template_customer_auto" model="mail.template">
<field name="name">Send email notification for issue creation</field>
<field name="email_from">${object.company_id and object.company_id.email or ''}</field>
<field name="subject">New Issue created ${object.name}</field>
<field name="email_to">${object.email|safe}</field>
<field name="model_id" ref="model_project_issue"/>
<field name="auto_delete" eval="True"/>
<field name="lang">${object.lang}</field>
<field name="body_html"><![CDATA[
"""
Write here a body of email using HTML tag.....
"""
]]>
</field>
</record>
</data>
</openerp>
I found the solution to send email when an issue is created
from openerp.osv import osv, fields
import logging
class project_issue(osv.osv):
_inherit = 'project.issue'
_columns = {}
issue = ''
templtate = ''
def create(self, cr, uid, vals, context=None):
res = super(project_issue, self).create(cr, uid, vals, context=context)
self.issue = self.pool.get('project.issue').browse(cr, uid, res, context=context)
manager = self.issue.project_id.user_id.partner_id.id
assignTo = self.issue.user_id.partner_id.id
post_vars = {
'subject': ("Issue {} has been created".format(self.issue.name)),
'body': ("Issue {} has been created".format(self.issue.name)),
'partner_ids': [(4, manager)],
}
thread_pool = self.pool.get('mail.thread')
thread_pool.message_post(cr, uid, False,
context=context,
**post_vars)
return res

optional include with entity framework

I'm working on a manager. Depending on the conditions some include must be enforced in order to get eager loading. But sometime I don't want all the data so the includes should not be applied.
This is what I've got so far.
//INFO : public partial class Entities : DbContext
var Database = new Entities();
var result = Database.Department;
if (includeHospitalEmployee) { result.Include(a => a.HospitalEmployee); }
if (includeQuickScans) { result.Include(a => a.QuickScan); }
return result;
This doesn't work. The includes aren't loaded, although the includebooleans are set to true. Query results in;
SELECT
[Extent1].[Code] AS [Code],
[Extent1].[Discipline] AS [Discipline],
[Extent1].[FinancialCode] AS [FinancialCode],
[Extent1].[Name] AS [Name],
[Extent1].[DepartmentManagerId] AS [DepartmentManagerId],
[Extent1].[Show] AS [Show],
[Extent1].[Id] AS [Id]
FROM [dbo].[Department] AS [Extent1]
But strange enough if i do this, all include are working
//INFO : public partial class Entities : DbContext
var Database = new Entities();
var result = this.businessManagersFactory.Database.Department.Include(a => a.QuickScan);;
if (includeHospitalEmployee) { result.Include(a => a.HospitalEmployee); }
if (includeQuickScans) { result.Include(a => a.QuickScan); }
return result;
see the query
SELECT
[Project1].[C1] AS [C1],
[Project1].[Code] AS [Code],
[Project1].[Discipline] AS [Discipline],
[Project1].[FinancialCode] AS [FinancialCode],
[Project1].[Name] AS [Name],
[Project1].[DepartmentManagerId] AS [DepartmentManagerId],
[Project1].[Show] AS [Show],
[Project1].[Id] AS [Id],
[Project1].[C2] AS [C2],
[Project1].[Id1] AS [Id1],
[Project1].[StartDateTime] AS [StartDateTime],
[Project1].[EndDateTime] AS [EndDateTime],
[Project1].[Shared] AS [Shared],
[Project1].[ScanStatus] AS [ScanStatus],
[Project1].[Title] AS [Title],
[Project1].[Count] AS [Count],
[Project1].[Comment] AS [Comment],
[Project1].[HospitalEmployeeId] AS [HospitalEmployeeId],
[Project1].[DepartmentId] AS [DepartmentId]
FROM ( SELECT
[Extent1].[Code] AS [Code],
[Extent1].[Discipline] AS [Discipline],
[Extent1].[FinancialCode] AS [FinancialCode],
[Extent1].[Name] AS [Name],
[Extent1].[DepartmentManagerId] AS [DepartmentManagerId],
[Extent1].[Show] AS [Show],
[Extent1].[Id] AS [Id],
1 AS [C1],
[Extent2].[Id] AS [Id1],
[Extent2].[StartDateTime] AS [StartDateTime],
[Extent2].[EndDateTime] AS [EndDateTime],
[Extent2].[Shared] AS [Shared],
[Extent2].[ScanStatus] AS [ScanStatus],
[Extent2].[Title] AS [Title],
[Extent2].[Count] AS [Count],
[Extent2].[Comment] AS [Comment],
[Extent2].[HospitalEmployeeId] AS [HospitalEmployeeId],
[Extent2].[DepartmentId] AS [DepartmentId],
CASE WHEN ([Extent2].[Id] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C2]
FROM [dbo].[Department] AS [Extent1]
LEFT OUTER JOIN [dbo].[QuickScan] AS [Extent2] ON [Extent1].[Code] = [Extent2].[DepartmentId]
) AS [Project1]
ORDER BY [Project1].[Code] ASC, [Project1].[C2] ASC
Why is this behaviour and how to get it working properly?
regards
I don't have access to Visual Studio to confirm but you will probably find that assigning the return from the call to Include will sort it - it will be something like a QueryObject that implements IQueryable
var Database = new Entities();
IQueryable<Department> result = Database.Departments;
if (includeHospitalEmployee) { result = result.Include(a => a.HospitalEmployee); }
if (includeQuickScans) { result = result.Include(a => a.QuickScan); }
return result;