In model
batch_id = fields.Many2one('ae.batch', 'Batch')
subject_ids = fields.Many2many('ae.subject', string="Subjects")
topic_ids = fields.Many2many('ae.topic', string="Topics")
subtopic_ids = fields.Many2many('ae.subtopic', string="Subtopics")
The goal is to pass context in order to filter(domain), picking a Batch filters Subjects, choose Subjects, could be one or more, to filter Topics, and filter Subtopics.
Batch (Many2one) to Subjects (Many2many)
Subjects (Many2many) to Topics (Many2many)
Topics (Many2many) to Subjects(Many2many)
Check view:
<group col="4" name="plan_detail" String='Choose t'>
<field name="batch_id"
context="{'batch_id':batch_id}"/>
<field name="subject_ids"
domain="[('batch_id', '=', batch_id)]"
context="{'subject_ids': subject_ids}"/>
<field name="topic_ids"
domain="[('subject_id', 'in', 'subject_ids')]"
context="{'topic_ids': topic_ids}" />
<field name="subtopic_ids" widget="many2many_checkboxes"
domain="[('topic_id', 'in', topic_ids)]" />
What is working, picking the Batch filters correctly all Subjects.
Stucked between Subjects and Topics, I think is a context or domain problem, I've tested changing the domain manually like so:
<field name="topic_ids"
domain="[('subject_id', 'in', '[1, 2]')]"
context="{'topic_ids': topic_ids}" />
And successfully gets Topic list. I guess I am wrong passing context or getting domain. Help.
Thanks in advance.
In your code, in the domain, the field that you mentioned subject_ids are in between quotes. Since its representing a field remove the quotes and do.
Try this
<field name="topic_ids" domain="[('subject_id', 'in', subject_ids)]"
context="{'topic_ids': topic_ids}" />
Related
I'm using on react-admin and try to add a filter options to a list.
My problem is how to add a filter input based on another filter input?
I want to filter the list by organization and by project bu project is associated to an organization so I want to enable select a project only after organization is selected and and only of projects associated tothe selected organization.
That is waht I try to do:
const ProjectInputs = () => {
const { values } = useFormState();
const translate = useTranslate();
const classes = useStyles();
return (
<ReferenceInput
label={translate("resources.projects.name", { smart_count: 1 })}
source="projectId"
reference="projects"
filter={{ organizationId: values.organizationId }}
disabled={!values.organizationId}
alwaysOn
variant="standard"
>
<SelectInput
optionText="name"
resettable
alwaysOn
/>
</ReferenceInput>
);
}
export const Paymentilter: FC<Omit<FilterProps, 'children'>> = props => {
const classes = useFilterStyles();
return (
<Filter {...props}>
<ReferenceInput
source="organizationId"
reference="organizations"
variant="standard"
>
<AutocompleteInput
optionText={(choice?: Organization) =>
choice?.id // the empty choice is { id: '' }
? `${choice.name}`
: ''
}
/>
</ReferenceInput>
<ProjectInputs />
</Filter>
);
};
It works but there are some problems:
I cant define the project input to be always on.
In the add filter button there is no name for this input only blank shrink space.
The position of the project input is unordered input is popping up.
after choosing this filter I cant close it.
Do you have an idea for me?
How to fix my problems?
Sholud I solve my issue in another way?
Thank you!
EDIT:
I did like #doctoragon way,
and that is ok. in this way the project input cant be choosen from the add filter button only when we choose an organization it apears and when we cancel it disaper.
That ok for me but the second input still looks different as you can see on the picture it is upper then al the others inputs, and the cancel button is overirded by the chosen option.
You might be able to solve this using a FormDataConsumer inside your Filter.
<Filter {...props}>
<ReferenceInput source="organizationId" ... />
<FormDataConsumer source="projects" alwaysOn>
{
({ formData, ...restOfTheProps }) => organizationId && <ProjectInputs />
}
</FormDataConsumer>
</Filter>
I've an issue with ReferenceArrayInput that I try to use for a group membership representation.
Here the code related to a group editing UI
export const UserGroupEdit = (props) => (
<Edit title={<UserGroupTitle />} {...props}>
<SimpleForm>
<TextInput label="Common Name" source="commonName" />
<TextInput label="E-mail" source="email" type="email" />
<TextInput label="Shortname (UNIX purpose)" source="shortname" />
<ReferenceArrayInput label="Members" source="members" reference="users">
<SelectArrayInput optionText="fullName" />
</ReferenceArrayInput>
<DisabledInput label="Record UUID" source="id" />
<DisabledInput label="Record ID" source="numericID" />
</SimpleForm>
</Edit>
);
I've two issue.
First, if the related property in the represented object is empty, the UI does not display the input field. It show the title of the field, a whitespace with no input possible and the next one. When I pass the mouse over the whitespace, I get the same icon attached to the mouse as a DisabledInput, the forbidden sign.
Second, if there is already one value, I can add new one, I've the text input available and the autocompletion is working well. However, once I select one value to add, it immediately disappear. It does not stay in memory until the save or cancel action.
And if in the second case, I remove existing values, they get properly removed and once I remove everything I'm back to the first issue.
Is there something I'm doing wrong?
About your first issue, you can try to add a allowEmpty prop to your ReferenceArrayInput :
<ReferenceArrayInput label="Members" source="members" reference="users" allowEmpty>
It's a bug indeed. This issue has been fixed on master which will be released soon as version 1.4.0.
We have a need where 3 different menu items perform CRUD operations to the same resource ("assets"), but with just the category_id being different on all CRUD operations (until you press again a different menu item).
In order to do this, we introduced a query param, called kind, which is the only practical difference among these 3 links:
<MenuItemLink
to={{
pathname: '/assets',
search: stringify({page: 1, perPage: 25}),
}}
primaryText="Assets"
onClick={onMenuTap}
leftIcon={<AssetsIcon />}
/>
<MenuItemLink
to={{
pathname: '/assets',
search: stringify({
page: 1,
perPage: 25,
kind: 'printers'
}),
}}
primaryText="Printers"
onClick={onMenuTap}
leftIcon={<AssetsIcon />}
/>
<MenuItemLink
to={{
pathname: '/assets',
search: stringify({
page: 1,
perPage: 25,
kind: 'vehicles'
}),
}}
primaryText="Vehicles"
onClick={onMenuTap}
leftIcon={<AssetsIcon />}
/>
Through the following code, the List fetches records only for these assets:
// NOTE: 'parsedKind' is parsed grom query params with previous code, it gets one of these values: '' OR 'printers' OR 'vehicles'
<List
title={<TitleList location={props.location} />}
{...props}
filters={<AssetFilter location={props.location} key={parsedKind} />}
perPage={15}
filter={{cat_id: dbIds[parsedKind]}}
sort={{field: 'name', order: 'ASC'}}
actions={<OurCustomListActions parsedKind={parsedKind} {...props} />}
key={parsedKind}
>
In order for this to work we had to customize the "actions" with custom Buttons, so that the parsedKindis following through. For example, the CreateButton now needs a prop ourQuery:
<FlatButton
primary
label={label && translate(label)}
icon={<ContentAdd />}
containerElement={<Link to={`${basePath}/create?${ourQuery}`} />}
style={styles.flat}
/>
I have 3 questions here:
This was a tedious work (all buttons have been customized) and I wonder if there was another solution to cover this need.
Still, the "SaveButton" causes headaches, because it uses a handleSubmitWithRedirect function that comes from props and the parameter is just the name of the view ('list' for example). So how can I add the query param on the final URL there? I used an ugly setTimeout to do this after 2 seconds (window.location.hash = window.location.hash + '?' + this.props.ourQuery;) but obviously this is very wrong. The DeleteButtonis also problematic because it redirects to a subview.
Using the above approach I get NaN-NaN from 19 in the List pagination. Why? Can this also be solved somehow?
Thank you!
So I think your best bet would have been to simply create three resources: Assets, Vehicles and Printers.
Than in your restClient/dataProvider, create logic to route these three resources to the assets endpoint with the correct parameter. I simple middleware would suffice, something in the line off:
// MyAssetResourceMiddleware.js
export default restClient => (type, resource, params) => {
switch(resource){
case 'Assets':
case 'Vehicles':
case 'Printers':
return restClient(type,'assets',{...params,kind:resource});
default:
return restClient(type,resource,params);
}
}
And wrap your provider with it
<Admin dataProvider={MyAssetResourceMiddleware(dataProvider)} .../>
I want to add a hyperlink in the website module in odoo using which I can download the attachments which consists of information of the product which was created.Please help with with this problem .
Thank you
It is too late to answer this question. Anyway it might be helpful to some one. I have googled more, since i didn't get any write solution.
Step 1:
Create hyperlink for download button. In that button you need to pass
model name
field
id
filename (optional)
For an example your link should be like this
<a t-attf-href="/web/binary/download_document?model=product.brand.files&field=file&id={{ file.id }}&file_name={{ file.file_name }}">
Step 2:
Create controller for above link. Ex
class Binary(http.Controller):
#http.route('/web/binary/download_document', type='http', auth="public")
#serialize_exception
def download_document(self,model,field,id,file_name=None, **kw):
""" Download link for files stored as binary fields.
:param str model: name of the model to fetch the binary from
:param str field: binary field
:param str id: id of the record from which to fetch the binary
:param str filename: field holding the file's name, if any
:returns: :class:`werkzeug.wrappers.Response`
"""
Model = request.env[model].sudo().search([('id', '=', int(id))])
filecontent = base64.b64decode(Model.file or '')
headers = werkzeug.datastructures.Headers()
if not filecontent:
return request.not_found()
else:
if not file_name:
filename = '%s_%s' % (model.replace('.', '_'), id)
headers.add('Content-Disposition', 'attachment', filename=filename)
return request.make_response(filecontent,headers)
else:
headers.add('Content-Disposition', 'attachment', filename=file_name)
return request.make_response(filecontent,headers)
It will work. Above code for Odoo 10. You can do the same for below versions also. I have got refer from this link
Cheers.
Here is a working example
return {
'type': 'ir.actions.act_url',
'url': '/web/content/%s/%s' % (attachment_id.id, shortname),
'target': 'self',
'nodestroy': False,
}
In short you just have to have a link that goes to /web/content/ir_attachment_id/the_name_you_want_the_file_to_have.
This works on Odoo V10 too.
this is work from odoo 10 you must try
<a t-attf-href="/web/content?model=website.support.ticket.message&field=attachment&id={{chat.id}}&filename={{chat.attachment_filename}}&download=true">Download</a>
If this is for a form you could do this entirely in the view. First add a record entry somewhere in the xml file:
<record id="module_name.http_link" model="ir.actions.act_url">
<field name="name">Button Name</field>
<field name="type">ir.actions.act_url</field>
<field name="target">new</field>
<field name="url">https://your-http-link</field>
</record>
And then in the form:
<button type="action" name="%(http_link)d" string="Name" class="oe_highlight"/>
well I have this code in a view
<Picker id="picker1" selectionIndicator="true" class="picker">
<!-- Picker shorthand notation -->
<Column id="column1" class="column">
<Row title="option1" />
<Row title="option2" />
<Row title="option3" />
</Column>
</Picker>
and I have been trying to change the rows on the controller, since I receive different options from the server, lets say for example:
( option4, option5, option6 )
I tried adding a row to the picker like this:
$.column1.addRow(Ti.UI.createPickerRow({title:'option4'}));
and had no success too, looking through the forums on appcelerator it wasn't possible before titanium SDK 5.1.0 GA to dynamically update the picker, but on another topic I've read that it is possible to do it but you have to reload the picker, so I tried it, but no success
var picker = $.picker1;
var column = $.column1;
column.addRow(Ti.UI.createPickerRow({title:'option4'}));
picker.reloadColumn(column);
how should be the right way to do it? adding a row and removing others, that is my question.
I am testing on an iphone(9+) and android(5+), using the Titanium SDK 5.1.2GA.
Solved, it was just a mistype, sorry, but you need to reload the column, or else it will not work.
var picker = $.picker1;
var column = $.column1;
column.addRow(Ti.UI.createPickerRow({title:'option4'}));
picker.reloadColumn(column);