I am new to odoo and I am trying to get full URL in my own custom template. Please check my code and help to sort it out what I am doing wrong.
mail_template_view.xml
<?xml version="1.0" encoding="utf-8"?>
<data noupdate = "0">
<record id="example_email_template" model="mail.template">
<field name="name">Example e-mail template</field>
<field name="email_from">bhuwankhadka2052#greenit.com.np</field>
<field name="subject">Congratz khadka</field>
<field name="email_to">benkhadka143#gmail.com</field>
<field name="model_id" ref="model_tender_manage"/>
<field name="auto_delete" eval="True"/>
<field name="body_html">
<![CDATA[
<p>Dear ,<br/><br/>
Good job, you've just created your first e-mail template!<br/></p>
My name is Bhuwan Khadka. What about you man?
A new tender record has been created
<div>
<p>Please check the link below for more details:</p>
% set website_url = object.env['ir.config_parameter'].sudo().get_param('web.base.url')
Your Odoo domain is: <b>${website_url}</b><br>
</div>
Regards,<br/>
Bhuwan Khadka
]]>
</field>
</record>
</data>
tendermanage.py
#api.model
def create(self,vals):
res = super(TenderManage,self).create(vals)
self.task_send_mail()
return res
Above code create new record and trigger automate email function
#api.multi
def task_send_mail(self):
template_email = self.env["mail.template"].search([('name','=','Example e-mail template')]).id
self.env["mail.template"].browse(template_email).sudo().send_mail(self.id, force_send=True)
Above code send email
If I remove URL code from XML file, email is sent automatically without any error but when URL code is written in email-template I get following error.
Error Message:
Please help me with your suggestion and how to get full url in email template. In XML odoo element is removed as it is not shown in above code.
mail_template_view.xml
<div>
<p>Please check the link below for more details:
Your Odoo domain is: <b>Click Here</p>
</div>
tendermanage.py
#api.multi
def get_full_url(self):
self.ensure_one()
base_url = self.env["ir.config_parameter"].get_param("web.base.url")
url_params = {
'id': self.id,
'view_type': 'form',
'model': 'your_model',
'menu_id': self.env.ref('module_name.menu_record_id').id,
'action': self.env.ref('module_name.action_record_id').id,
}
params = '/web?#%s' % url_encode(url_params)
return base_url + params
Change the mail template div and create method like this in your model..
i hope it will helps..
Related
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>
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)
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
I am building a custom module in Magento 2 that has a custom discount. I am trying to copy the discount from quote, quote item to order and order item.
In Magento 1, I declare the config.xml like this:
<fieldsets>
<sales_convert_quote_address>
<custom_discount_amount><to_order>*</to_order></custome_discount_amount>
<base_custom_discount_amount><to_order>*</to_order></base_custome_discount_amount>
</sales_convert_quote_address>
<sales_convert_quote_item>
<custome_discount_amount><to_order_item>*</to_order_item></custome_discount_amount>
<base_custom_discount_amount><to_order_item>*</to_order_item></base_custom_discount_amount>
</sales_convert_quote_item>
</fieldsets>
and my custom discount amount was copied to tables: sales_flat_order and sales_flat_order_item as expected.
In Magento 2, I created a file named fieldset.xml with this code:
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../../../../../lib/internal/Magento/Framework/Object/etc/fieldset.xsd">
<scope id="global">
<fieldset id="sales_convert_quote_item">
<field name="custom_discount_amount">
<aspect name="to_order_item" />
</field>
<field name="base_custom_discount_amount">
<aspect name="to_order_item" />
</field>
</fieldset>
<fieldset id="sales_convert_quote_address">
<field name="custom_discount_amount">
<aspect name="to_order" />
</field>
<field name="base_custom_discount_amount">
<aspect name="to_order" />
</field>
</fieldset>
</scope>
</config>
but there is no success.
What else do I need to do in Magento 2 to make it work? Can you guys please help me?
In Magento 2 without using fieldset you can also copy custom data from quote item to order item by using plugin.
create di.xml in your module etc folder.
app/code/Vender/Yourmodule/etc/di.xml
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../lib/internal/Magento/Framework/ObjectManager/etc/config.xsd">
<type name="Magento\Quote\Model\Quote\Item\ToOrderItem">
<plugin name="cedapi_quote_to_order_item" type="Vender\Yourmodule\Model\Plugin\Quote\QuoteToOrderItem"/>
</type>
</config>
Create a class to your module and define a function. app/code/Vender/Yourmodule/Model/Plugin/Quote
Create QuoteToOrderItem.php file
<?php
namespace Vender\Yourmodule\Model\Plugin\Quote;
use Closure;
class QuoteToOrderItem
{
/**
* #param \Magento\Quote\Model\Quote\Item\ToOrderItem $subject
* #param callable $proceed
* #param \Magento\Quote\Model\Quote\Item\AbstractItem $item
* #param array $additional
* #return \Magento\Sales\Model\Order\Item
* #SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
public function aroundConvert(
\Magento\Quote\Model\Quote\Item\ToOrderItem $subject,
Closure $proceed,
\Magento\Quote\Model\Quote\Item\AbstractItem $item,
$additional = []
) {
/** #var $orderItem \Magento\Sales\Model\Order\Item */
$orderItem = $proceed($item, $additional);//result of function 'convert' in class 'Magento\Quote\Model\Quote\Item\ToOrderItem'
$orderItem->setCustomDesign($item->getCustomDesign());//set your required
return $orderItem;// return an object '$orderItem' which will replace result of function 'convert' in class 'Magento\Quote\Model\Quote\Item\ToOrderItem'
}
}
After spend some time and research issue, i stucked here:
Magento\Quote\Model\QuoteManagement.php
line 446
public function mergeDataObjects(
$interfaceName,
$firstDataObject,
$secondDataObject
) {
if (!$firstDataObject instanceof $interfaceName || !$secondDataObject instanceof $interfaceName) {
throw new \LogicException('Wrong prototype object given. It can only be of "' . $interfaceName . '" type.');
}
$secondObjectArray = $this->objectProcessor->buildOutputDataArray($secondDataObject, $interfaceName);
$this->_setDataValues($firstDataObject, $secondObjectArray, $interfaceName);
return $this;
}
Which ignores converted attributes because logic of merging based on presence getters and setters of target model\interface. So, if you converting attributes which haven't setters and getters in target model they will be ignored here:
Magento\Framework\Reflection\DataObjectProcessor.php line 75
public function buildOutputDataArray($dataObject, $dataObjectType)
{
$methods = $this->methodsMapProcessor->getMethodsMap($dataObjectType);
$outputData = [];
/** #var MethodReflection $method */
foreach (array_keys($methods) as $methodName) {
if (!$this->methodsMapProcessor->isMethodValidForDataField($dataObjectType, $methodName)) {
continue;
}
$value = $dataObject->{$methodName}();
$isMethodReturnValueRequired = $this->methodsMapProcessor->isMethodReturnValueRequired(
$dataObjectType,
$methodName
);
Maybe you might to use observer or plugin to avoid this problem. (issue encountered in 2.0.6 Magento version)
For anybody looking at this in the future, the fact that the fieldset XML doesn't work has been acknowledged by Magento as a bug. There is a core patch available in the ticket (not reproduced here since it may need to be tweaked with new Magento versions).
https://github.com/magento/magento2/issues/5823
I have a legacy application where an email.cfm file is used with a cfmail tag to send e-mail:
<cfmail from="abc#123.com" to="def#456.com" subject="New e-mail!">
// lots of HTML
</cfmail>
Now I'd like to update it for ColdFusion Model Glue 3. I want to send it using a mail object in the controller, and include in the body a CFM page:
var mail = new mail();
mail.setFrom("abc#123.com");
mail.setTo("def#456.com");
mail.setSubject("New e-mail!");
mail.setBody( ** SOME CFM FILE ** );
mail.send();
Does anybody have any idea how I can do this?
You can render the content you want to email in a cfsavecontent block and then use that in the email, like:
<cfsavecontent variable="myemail">
...add some HTML, include another file, whatever...
</cfsavecontent>
<cfscript>
mail.setBody( myemail );
</cfscript>
See http://help.adobe.com/en_US/ColdFusion/9.0/CFMLRef/WSc3ff6d0ea77859461172e0811cbec22c24-7d57.html
Call the CFC assigning it to a variable, like cfset request.emaiBody = cfc.function(). Then just put it in your setBody tag.
OP was convinced to use CFML, but to answer the question as it was initially asked:
var mail = new Mail();
mail.setFrom("abc#123.com");
mail.setTo("def#456.com");
mail.setSubject("New e-mail!");
mail.setType("html");
savecontent variable="mailBody" {
include "email.cfm";
}
mail.setBody(mailBody);
mail.send();
I ended up following Henry's advice in the comments and created a CFML-based CFC:
<cfcomponent>
<cffunction name="SendMail">
<cfargument name="from"/>
<cfargument name="to"/>
<cfargument name="subject"/>
<cfmail from="#from#" to="#to#" subject="#subject#">
<!--- HTML for e-mail body here --->
</cfmail>
</cffunction>
</cfcomponent>
Dave Long's suggestion is also good, which is to create components using <cfcomponent>, then wrapping the code in <cfscript> tags. This gives you the ability to fall back to CFML in case the there is no cfscript equivalent or it's easier to do with CFML:
<cfcomponent>
<cfscript>
void function GetData()
{
RunDbQuery();
}
</cfscript>
<cffunction name="RunDbQuery">
<cfquery name="data">
SELECT * FROM ABC;
</cfquery>
<cfreturn data>
</cffunction>
</cfcomponent>