as mentionned in the title, I need to open a report in a new window. I know that we can do so using target with act_window but I am stuck on how implement that to open a report.
<template id="myTemplate">
<!--template-->
</template>
<report
id="my_report_partner"
string="Graphe"
model="res.partner"
report_type="qweb-html"
file="myModule.myTemplate"
name="myModule.myTemplate"
/>
button:
<button name="%(myModule.my_report_partner)d" type='action' string="open graph"/>
Try this, It could help you to archive your task.
return {
'type': 'ir.actions.act_url',
'target': 'new',
'url': '/report/html/%s/%s?enable_editor' % ('event.event_event_report_template_badge', self.id),
}
Related
I have a client who loves to open new tabs for multiple records but doesn't want each tab to be in focus or active. Is there a way to achieve this? The parameter 'target': '_blank' seems to be the same as 'target':'new' in this instance and will open a new tab and activate the window. I'm working with odoo v10. Thanks!
def open_product_new_tab(self):
self.ensure_one()
act_id = self.env.ref('product.product_template_action').id
menu_id = self.env.ref('custom_module.custom_menu').id
return {
'name': 'Product Template View',
'type': 'ir.actions.act_url',
'target': '_blank', #open in a new tab but not active?
'url': '/web?#id=%s&view_type=form&model=product.template&action=%s&menu_id=%s' % (self.id, act_id, menu_id)
}
This seems like it should be pretty straight forward... within a stepper, you're collecting info, and you want to make sure an email is an email. But it seems like the shared 'form' tag causes some issues where the error checker gets messed up and doesn't work?
Further clarification... the issue seems to actually be in the following tag element...
formControlName="emailCtrl"
When I remove this line, and remove it's sibling line from the .ts (emailCtrl: ['', Validators.required],) the error check starts working. However, that means that the stepper can't verify that this step is required.
How can I make sure the stepper validates an entry and at the same time make sure that the ErrorStateMatcher works?
Here is my combined HTML...
<mat-step [stepControl]="infoFormGroup">
<form [formGroup]="infoFormGroup">
<ng-template matStepLabel>Profile Information</ng-template>
<div>
<!-- <form class="emailForm"> -->
<mat-form-field class="full-width">
<input matInput placeholder="Username" [formControl]="emailFormControl"
formControlName="emailCtrl"
[errorStateMatcher]="infoMatcher">
<mat-hint>Must be a valid email address</mat-hint>
<mat-error *ngIf="emailFormControl.hasError('email') && !emailFormControl.hasError('required')">
Please enter a valid email address for a username
</mat-error>
<mat-error *ngIf="emailFormControl.hasError('required')">
A username is <strong>required</strong>
</mat-error>
</mat-form-field>
<!-- </form> -->
</div>
<button mat-button matStepperPrevious>Back</button>
<button mat-button matStepperNext>Next</button>
</form>
</mat-step>
As you can see, I have commented out the nested 'form' for the email slot. In testing, I have tried it commented and not commented out. Either way, the error checking doesn't work right.
Here are some of the pertinent .ts snippets...
import { FormControl, FormGroupDirective, NgForm, Validators } from '#angular/forms';
import { FormBuilder, FormGroup } from '#angular/forms';
import { ErrorStateMatcher } from '#angular/material/core';
export class Pg2ErrorStateMatcher implements ErrorStateMatcher {
isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean {
const isSubmitted = form && form.submitted;
return !!(control && control.invalid && (control.dirty || control.touched || isSubmitted));
}
}
...
export class Pg2Dialog {
...
emailFormControl = new FormControl('', [
Validators.required,
Validators.email,
]);
infoMatcher = new Pg2ErrorStateMatcher();
...
this.infoFormGroup = this._formBuilder.group({
emailCtrl: ['', Validators.required],
});
I believe I figured this out. the ErrorStateMatcher requires a named form control. In this case, it's emailFormControl. This is declared as the following...
emailFormControl = new FormControl('', [
Validators.required,
Validators.email,
]);
Also, the stepper requires a named form group, that in itself declares a new form control. In this case, it was emailCtrl. It was declared as the following...
this.infoFormGroup = this._formBuilder.group({
emailCtrl: ['', Validators.required],
});
To have the stepper form control utilize the ErrorStateMatcher form control, simply drop the square brackets inside the .group assignment and assign emailFormControl to the emailCtrl. Like this...
this.infoFormGroup = this._formBuilder.group({
emailCtrl: this.emailFormControl
});
I tested this in a different code section with a similar problem and it worked in both places!
Background: I'm trying to create a form using Aurelia. I have a person object that I would like to be able to fill in data for. If the user knows some identifying information about the person's family, they can enter it in an input and a select box will be displayed to allow the user to select the individual from that family for this particular form. The form will then fill in any information it knows about that individual into input fields allowing the user to overwrite any of the information if necessary. The form also allows them to clear the selected person if they want to choose another one.
Most of the functionality seems to work as expected, but when I try to allow the user to clear out the selected person, I'm seeing some behavior that I wouldn't have expected.
I have created a GistRun. The bottom pane is working as I would expect, after the user gets data, selects a person and then clears their selection, they are provided with the select element again. If you uncomment the input element, you will see that the user now has to click the clear action twice before they see the select element again. Why?
How can I update the application so that the user will only need to clear out the person once and the select box will appear again to allow the user to make another selection?
If you have an Aurelia application, you should be able to reproduce this by replacing the app.html with the following:
<template>
<select value.bind="val2" if.bind="opts2 && !val2">
<option repeat.for="opt of opts2" model.bind="opt">${opt.firstName}</option>
</select>
<div if.bind="!opts2 || val2">
<span>${val2.firstName}</span>
<button click.delegate="clearVal2()" if.bind="val2">Clear</button>
</div>
<button click.delegate="getOpts2()">Get</button>
<div>${val2.blah}</div>
<!--<input type="text" value.bind="val2.blah"/>-->
</template>
An the app.js with this:
export class App {
opts2;
val2;
getOpts2(){
this.opts2 = [
undefined,
{
blah: 1,
firstName: 'foo',
address: {
line1: '123 Main St.'
}
},
{
blah: 2,
firstName: 'bar',
address: {
line1: '456 Other Wy.'
}
}
];
}
clearVal2(){
this.val2 = null;
}
}
Any help would be greatly appreciated. Thanks!
UPDATE
If I put the input in a custom element and bind to that, things seem to work as expected. The values that I'm putting into my form though aren't in one location that I could utilize a custom element for. I have updated the Gist with an example.
How can I achieve the same functionality without the need for a custom element?
In all honesty I'm not sure why, but if you add if.bind="val2"on the input element, it clears the value and the select button returns.
<input type="text" if.bind="val2" value.bind="val2.blah"/>
Hope this (slightly) helps
Give that you are allowing the user to either select a value from the list or create a completely new entry, I would tend towards separating the value selected in the list and the data backing up the text boxes. Whenever the value of the select changes, I would set the value of the object backing the text boxes to the value of the select. The way I chose to do this in my sample code is to use the observable decorator on the value the select is bound to.
Here's an example: https://gist.run?id=e4b594eaa452b47d9b3984e7f9b04109
app.html
<template>
<div>
<select value.bind="val" if.bind="opts && !val">
<option repeat.for="opt of opts" model.bind="opt">${opt.firstName}</option>
</select>
<button click.delegate="getOpts()">Get</button>
</div>
<div if.bind="!opts || person">
<span>First Name: ${person.firstName}</span>
<button click.delegate="resetForm()" if.bind="val">Clear Selection</button>
</div>
Address: <input type="text" value.bind="person.address.line1" />
<hr />
val
<pre><code>
${toJSON(val)}
</code></pre>
person
<pre><code>
${toJSON(person)}
</code></pre>
</template>
app.js
import {observable} from 'aurelia-framework';
export class App {
#observable val = null;
person = {};
getOpts(){
this.opts = [
null,
{
blah: 1,
firstName: 'foo',
address: {
line1: '123 Main St.'
}
},
{
blah: 2,
firstName: 'bar',
address: {
line1: '456 Other Wy.'
}
}
];
}
valChanged() {
this.person = this.val;
console.log("set person");
}
resetForm(){
this.val = null;
console.log("reset val");
}
toJSON(value) {
if(!(value === false) && !value) {
return '';
}
return JSON.stringify(value);
}
}
You can see something interesting is happening when I reset the form. Aurelia is creating the properties necessary for bindings to person (namely person.address.line1 when we set person = null. But it doesn't create a firstName property, b/c that property isn't being bound until person stops being falsey.
Another option here is to simply use the with attribute to scope the input.
https://gist.run/?id=7b9d230f7d3c6dc8c13cefdd7be50c7f
<template>
<template with.bind="val.address">
<input value.bind="line1" />
</template>
</template>
Although I agree that mixing the logic of selections and inputs like that is probably not the best idea :)
This is a sample method I use to print a report from a wizard:
def mymethod(self, cr, uid, ids, context=None):
"""
"""
return {
'type': 'ir.actions.report.xml',
'report_name': 'trescloud_ats_2013_report',
'datas': {
'model': 'sri.ats.2013',
'res_ids': ids
}
}
How do I also avoid the wizard being closed?
Call the report with a button with type="action" instead of type="object". Like this you don't need to call a python method. If you need to run some python code before as well, then you should open again the wizard with the proper elements in the return of the function.
<button name="%(module_name.report_id)d"
type="action" />
How can I show a message box in openerp? I was using raise like this:
raise osv.except_osv(_("Warning!"), _("Error"))
But this stops executing other code, I only want to display an informative message box.
Raising an osv.except_osv does a couple of things:
1) Interrupts the current processing (it is a python exception after all).
2) Causes OpenERP to roll back the current database transaction.
3) Causes OpenERP to display a dialog box to the user rather than dumping a stack trace and giving the user a "bad stuff happened" message.
For onchange we can return
warning = {
'title': 'Warning!',
'message' : 'Your message.'
}
return {'warning': warning}
But it will not work for other things like button.
For your case you can do
cr.commit()
raise osv.except_osv(_("Warning!"), _("Error"))
But calling cr.commit explicitly in business transaction will leads to severe issues.
The other way is you can return a wizard with warning message. This is what most people used.
return {
'name': 'Provide your popup window name',
'view_type': 'form',
'view_mode': 'form',
'view_id': [res and res[1] or False],
'res_model': 'your.popup.model.name',
'context': "{}",
'type': 'ir.actions.act_window',
'nodestroy': True,
'target': 'new',
'res_id': record_id or False,##please replace record_id and provide the id of the record to be opened
}
One way comes to my mind... You can use some on_change method that would return dict like this:
return {
'warning': {
'title':'Message title!',
'message':'Your message text goes here!'
}
}