I have this calendar that is made with Javascript.
When you click in "Libre", a view opens, where you can create a reserve. I want the reservation line as default and look something like this. In this case I did it manually, and I want it to appear automatically. I know I need an on #api.onchange function.
The roomid field ("Room" in the image) has the ID of the room that I need to add in reservation.line. I get this from .js
I have something like this in my code and it's getting exactly the room I want, but I don't know how to make it appear automatically.
class HotelReservation(models.Model):
_name = "hotel.reservation"
room_id = fields.Many2one("hotel.room", string="Room", required=True)
roomid= fields.Integer(related='room_id.id', string="Room")
reservation_line = fields.One2many(
"hotel.reservation.line",
"line_id",
string="Reservation Line",
help="Hotel room reservation details.",
readonly=True,
states={"draft": [("readonly", False)]},
)
#api.onchange('roomid')
def onchange_reservation_line(self):
if self.roomid:
room = self.env['hotel.room'].search([('id' ,'=', self.roomid)])
# Some return here?
You can read in the write function documentation that the expected value of a One2many or Many2many relational field is a list of Command that manipulates the relation the implement. There are a total of 7 commands: create(), update(), delete(), unlink(), link(), clear(), and set().
roomid is related to room_id so you can use it in onchange function and avoid calling the search method to get the room record.
Example:
#api.onchange('room_id')
def onchange_reservation_line(self):
if self.room_id:
self.reservation_line = [
Command.clear(),
Command.create({
'field_name': field_value,
...
}),
]
Related
I want to update computed field records but it writes self record in all fields when I use write method.
the name field in product, template is non stored. now because of our business needs so I can't search it.
I make another stored field to move name records into it. so I can looking for instead of name.
I make a button to update data in that field from name field. but when I press the button it updates with self name not name of each product.
class autopart(models.Model):
_inherit = 'product.template'
#api.multi
def button_name(self):
for rec in self:
name=self.name
rec.search([]).write({'nameseacrh': self.name})
name = fields.Char(string="Name", required=False ,compute=compute_amount ,search=pro_search)
nameseacrh = fields.Char(string="", required=False,store=True, compute=compute_search )
button XML
<button name="button_name" type="object" string="name" class="oe_highlight" groups="base.group_system"/>
I don't fully understand what you are trying to do but here are already a few remarks:
#api.multi
def button_name(self):
for rec in self:
name=self.name # remark 1
rec.search([]).write({'nameseacrh': self.name}) # remark 2 and 3
1) You never use this variable
2) rec.search([]) is the same as self.env['product.template'].search([]): It takes all the product templates in the db. You probably didn't want to do that... Then you write your values on all the records.
3) you use self.name instead of rec.name. The first one will work only if self is a recordset of one element, which will not be the case most of the time in an #api.multi
4) I don't get why you would need to make a new field that does what you had before. You shouldn't have to do that.
I am working with odoo 10 and have created a few fields, and have the following problem:
I created my own field (x_order_bestelldatum) in the module sale.order. When I confirm an offer, I enter the effective order date in this field.
Now, when I create an invoice, I want to read the x_order_bestelldatum field of the module sale.order in module account.invoice so that I can print the order date on the invoice.
How can I read out the field x_order_bestelldatum from model sale.order in model account.invoice?
Here is my code in file models.py, but it does not work:
from odoo import models, fields, api
class felder_saleorder(models.Model):
_inherit = 'sale.order'
x_order_bestelldatum = fields.Date(string="Bestelldatum")
class felder_invoice(models.Model):
_inherit = 'account.invoice'
sale_order = fields.Many2one('sale.order','sale_order')
x_bestelldatum = fields.Date(string="Bestelldatum",related='sale_order.x_order_bestelldatum')
x_lieferdatum = fields.Date(string="Lieferdatum")
That does not work (the field x_bestelldatum remains empty):
sale_order = fields.Many2one('sale.order','sale_order')
x_bestelldatum = fields.Date(string="Bestelldatum",related='sale_order.x_order_bestelldatum')
Well lets not do it your way plus I can't get it how you are doing it.
So, I am suggesting some other possibilities which might help you.
First lets talk about the sale order field whom you named as 'sale_order'.
There are two possible options with which you are entering data in the sale_order field.
1). Automatically through python
2). Manually by selecting from the list.
In case of entering data Manually you should use onchange function:
#api.onchange('sale_order')
def get_order_date(self):
if self.sale_order:
self.x_bestelldatum = self.sale_order.x_order_bestelldatum
In Case if you are automatically entering data through python then you can use monetary or create function to fill the field.
Create function:
#api.model
def create(self, vals):
new_record = super(felder_invoice, self).create(vals)
if new_record.sale_order:
new_record.x_bestelldatum = new_record.sale_order.x_order_bestelldatum
return new_record
Compute Funtion:
First you need to amend your field deceleration in py file like that
x_bestelldatum = fields.Date(string="Bestelldatum",compute="get_order_date")
Then you need to create a compute function for that:
#api.one
#api.depends('sale_order')
def get_order_date(self):
if self.sale_order:
self.x_bestelldatum = self.sale_order.x_order_bestelldatum
You can get the order date by using above mentioned functions and willbe able to get its value in reports/prints.
Hope it helps.
Cheers!
Thank you for your answer.
I have tried a few variants, but it still does not work. The field 'x_bestelldatum' in the module 'account.invoice' will always be empty.
This is what my code looks like:
class felder_invoice(models.Model):
_inherit = 'account.invoice'
x_lieferdatum = fields.Date(string="Lieferdatum")
sale_order = fields.Many2one('sale.order','sale_order')
x_bestelldatum = fields.Date(string="Bestelldatum",compute="get_order_date")
#api.one
#api.depends('sale_order')
def get_order_date(self):
if self.sale_order:
self.x_bestelldatum = self.sale_order.x_order_bestelldatum
Is that right? Are all fields from 'sale.order' transferred to the new locale field 'sale_order'?
sale_order = fields.Many2one('sale.order','sale_order')
I've inherited the sale.order.line and I've added a wizard (sale.pack.wizard) accesible from a button of sale.order form. Besides, I have a field test (One2many type) in the wizard. Now, I want to get the test field IDs in a method of sale.order.line model. So, how can I do this?
class SaleOrderLine(models.Model):
_inherit = "sale.order.line"
#api.depends('product_uom_qty', 'discount', 'price_unit', 'tax_id', 'product_id','price_subtotal')
def _compute_amount(self):
active_id = self.env.context.get('active_ids', []) or []
new = self.env['sale.pack.wizard'].browse(active_id)
#Here i want to show 'test' field id from wizard
class SalePackWizard(models.TransientModel):
_name = "sale.pack.wizard"
_description = "Sale Pack Wizard"
product_id = fields.Many2one('product.product', string="Product Pack", required=True, domain="[('is_pack','=',True)]")
test = fields.One2many('product.gold','service',string="Pack Products",change_default=True, default=_onchange_action_product_add )
You cannot achieve your purpose in that way. You have to take into account that there is a scheduled action in Odoo (AutoVacuum osv_memory objects) which removes every transient model record each 30 minutes (by default). This means that if you were able to get the wizard test field value, even so, it would only return any value the 30 minutes after the wizard was opened for the first time.
So, what I'd do in your case, is to create a new field in sale.order.line model which stores the info you need of the wizard. Then, I'd create a button in the wizard, and when you click on this button, execute a method which fills in the new sale.order.line field with the info you need.
I can't figure out how to populate choice form from db. I know about ModelChoiceForm but the problem seems to be slightly different.
I want user to choose which sector does he work in. For example: 'Finance','Electronics' etc. which I would do simple:
SECTOR_CHOICES = (('finance',_('Finance'),
'electronics',_('Electronics')...
))
But the problem is that I want admin of the web to be able to add new choices, remove choice etc.
What came to my mind is to create a simple Model called Sector:
class Sector(models.Model):
name = models.CharField(max_length=40)
and User would have new attribute sector = models.ModelChoice(Sector).
But I'm scared what would happend when admin changes or removes a sector which is already used, and more, what if he removes it and the sector attribute is required?
How to solve this problem?
I would just override the delete_model as custom action and there check if the selected sector object is in use.
def delete_model(modeladmin, request, queryset):
for obj in queryset:
if UserModel.objects.filter(sector=obj).exists():
# do not delete, just add some message warning the admin about it
else:
obj.delete()
class UserModelAdmin(admin.ModelAdmin):
actions = [delete_model]
# ...
EDIT:
I've decided to change my question to this, in hope that a more general question will be more appealing...
so I have a model, it has a M2M field which is not translated in the server, but it is in the client side. Can I sort this field in the admin-ui, especially every time I add a new instance of the model?
This was my last attempt:
The models of interest are:
class Recipe(models.Model):
name = models.CharField(max_length=200,verbose_name=_("name"))
ingredient_list = models.ManyToManyField(IngredientType, through='Ingredient')
class IngredientType(models.Model):
name = models.CharField(max_length=25)
class Ingredient(models.Model):
ingredient_type =models.ForeignKey(IngredientType,verbose_name=_("IngredientType"))
recipe = models.ForeignKey(Recipe)
recipe_admin.py:
class IngredientInline(admin.TabularInline):
model = Ingredient
extra = 1
class RecipeAdmin(admin.ModelAdmin):
inlines = [IngredientInline]
form = RecipeForm
class RecipeForm(forms.ModelForm):
class Meta:
model = Recipe
I've added a long list of IngredientType objects in my initial_data.json file.
Now, each time a person adds a new ingredient to his recipe, he selects an ingredient_type from the long drop-down list that opens up.
EDIT:
When looking at the form's html in the browser I have these lines for my drop-down list.
as you can see, underneath the field's there's a line responsible for adding another row to the inline using the showAddAnotherPopup(this) function:
(I would like to somehow hook into that function, and every time it's called, to call my sorting function)
<select id="id_ingredient_set-0-ingredient_type" name="ingredient_set-0-ingredient_type">
<option value="" selected="selected">---------</option>
<option value="42">אבוקדו</option>
<option value="80">אבטיח</option>
....
</select>
<img src="/static/admin/img/icon_addlink.gif" width="10" height="10" alt="Add another">
My problem is, that dynamically added Ingredient rows that the user adds to his recipe form, results in the drop-down ingredient_type names list to be unsorted. I am able to sort by the Hebrew alphabetical order, but i've managed to do so only for the lines already apparent when the page loads.
I've done the above by migrating the django's tabular.html file into my project file system, and adding some js that sorts it:
function sortAlpha(a,b){
return a.innerHTML.toLowerCase() > b.innerHTML.toLowerCase() ? 1 : -1;
};
and I'm calling it like so:
('#id_ingredient_set-0-ingredient_type option').sort(sortAlpha).appendTo('#id_ingredient_set-0-ingredient_type');
Inside the function that fires when the page is loaded.
but this approach obviously does not deal with all dynamically added Ingredient rows that the user adds to his recipe form, that results in the drop-down ingredient_type names list to be unsorted. (It hooks on the present id in the )
This is django's showAddAnotherPopup method which I also added to my project's file system:
function showAddAnotherPopup(triggeringLink) {
var name = triggeringLink.id.replace(/^add_/, '');
name = id_to_windowname(name);
href = triggeringLink.href
if (href.indexOf('?') == -1) {
href += '?_popup=1';
} else {
href += '&_popup=1';
}
var win = window.open(href, name, 'height=500,width=800,resizable=yes,scrollbars=yes');
win.focus();
return false;
}
I'm a django noob, so I still lack knowledge in all the AJAX/js/templatetag buzz-words...
Help will be much appreciated.
tnx
Nitzan
It's not clear in your example how you are triggering the sort function on the initial page load, but it seems you need to call the function again after each new item is added. Add an onclick, onblur, or other event trigger to the ingredient addition method that will call your sorting function again.
If you are trying to order the displayed list of items as created by the modelform, you can use the meta options order or order_with_respect_to. See https://docs.djangoproject.com/en/dev/ref/models/options/#ordering for more info.