Onchange issue on the Date / Datetime field - odoo

Impacted versions: 12
Steps to reproduce: If we set a onchange function for a Date field and if that onchange function has some code to raise a ValidationError or UserError.
Current behavior: Then the onchange function keeps executing if you click on the Date field to select, means without changing the date, it executes. So the error popup appear again and again. So not able to change the date.
Expected behavior: As I checked with Char field it works fine. So the onchange function has to be only executed for the Date field when the current value in the field is different from the last value.
Sample code:
#api.onchange('today_date')
def change_date(self):
if self.today_date == datetime.datetime.today().date():
raise ValidationError("Selected today's Date >>>>>>>>>>>>>>")
When I select todays date in the field, it raise the error. Now I want to select some other date and clicked the field to change, before I change it gives the error again and again.
I faced this issue with Odoo ver 12.
Odoo 13 and 14 don't have this type of issue.
Odoo github Issue

Just make a small change in your code
#api.onchange('today_date')
def change_date(self):
if self.today_date != self.check_date:
self.check_date = self.today_date
if self.today_date == datetime.datetime.today().date():
raise ValidationError("Selected today's Date >>>>>>>>>>>>>>")
Here I'm supposing another datetime field to store last datetime for future validation.

Since you mentioned Odoo v12 only has this issue. I would put the check in the write method. I highly recommend that you check and use the fields.Date or fields.Datetime methods. So you don't have to try to match the format importing datetime, etc.
def write(self, vals):
if 'today_date' in vals:
if fields.Date.to_date(vals['today_date']) == fields.Date.today:
raise ValidationError("Selected today's Date >>>>>>>>>>>>>>")
return super(ClassName, self).write(vals)

Related

Recordset is empty regardless of decorator

I'm trying to get the ID of the currency in a Journal Item but I get a False boolean value for some reason.
Here's the relevant code:
class JournalItem(models.Model):
_name = "account.move.line"
_inherit = "account.move.line"
def _get_current_rate(self):
...
print(self.currency_id.id)
#currency_id is a Many2one field of comodel res.currency.
rate = fields.Float(string="Rate", digits=(12, 6),
default=_get_current_rate)
Which outputs:
False
I toyed around with the #api.multi and #api.one decorators but noticed no changes. Feels like I'm missing something crucial.
Update 1:
self is account.move.line() when checked
This should be like account.move.line(1, 2, 3, 4, ...) maybe it's something to do with the default attribute, will update as I figure it out.
Update 2:
The main thing here is the lack of a currency, it persists even when given a valid Journal Entry record number
From the 'account' module:
#api.model
def _get_currency(self):
currency = False
context = self._context or {}
if context.get('default_journal_id', False):
currency = self.env['account.journal'].browse(context['default_journal_id']).currency_id
return currency
This is unlikely to be the issue since currency_id returns a res.currency object, it's only when I further look into it that I get False return values.
Update 3:
It appears that currencies not explicitly set during transaction creation are set to False, this is likely the source of my troubles. Fixed by testing for it and replacing by environment's default.
Methods for default values always have an empty recordset. You should fill the value in one of the following ways:
compute the value and store it (little hint: call the currency field rate with the journal entries date in context --> currency.with_context(date=<journal_entry_date>).rate --> because this field is computed and context date is taken into the computation)
override create/write and try to figure out the rate

How to get values in onchange with sudo()

I have added one onchange method, in that onchange method I have used sudo() while accessing many2one field.
But with sudo(), I am not able to get record's values with sudo.
So how can I get values of onchange record (<odoo.models.NewId object at 0x7fba62f7b3d8>) with sudo().
Here is sample code :
#api.onchange('product_id')
def onchange_product_id(self):
for record in self:
print(record.product_id)
print(record.sudo().product_id)
Actual result :
product.product(13,)
product.product()
Expected result :
product.product(13,)
product.product(13,)
That's because the recordset doesn't exist outside the current transaction. So your current user can see the contents but other users can't.
The code looks good to me, in fact, if you see path_to_v12/addons/hr_expense/models/hr_expense.py lines 563-567, you'll see a similar code:
#api.onchange('employee_id')
def _onchange_employee_id(self):
self.address_id = self.employee_id.sudo().address_home_id
self.department_id = self.employee_id.department_id
self.user_id = self.employee_id.expense_manager_id or
self.employee_id.parent_id.user_id

#api.constrains is not working properly

In the 'project.project' model I wrote a function to validate 'start Date' and 'end date' for this I used onchange function.The function is working and giving warning but record is creating. Actually if there is any error means record cannot be saved because I am using #api.constrains below is my code.
py.code:
#api.onchange('date','date_start')
#api.constrains('date','date_start')
def cheking_field_date(self):
self.t1 = self.date_start
self.t2 = self.date
if self.t2 == False:
pass
else:
if str(self.t1) > str(self.t2):
raise Warning('The Deadline Date is Invalid')
else:
pass
But When I was Editing the record if any change in date field means than everything is fine(i.e. validation problem in 'start date' and 'end date').At that time the record is not saving.Why this type problem is coming can any one help me please.
You need to take care of following points:
No need to use #api.onchange
Remove unnecessary variables.
Write only condition that you want to raise warning.
Try with following code.
#api.one
#api.constrains('date','date_start')
def cheking_field_date(self):
if self.date_start and self.date:
if self.date_start > self.date:
raise Warning('The Deadline Date is Invalid')

Getting view options in Microsoft Project using VBA

If I want to change the current date format to 20, for example, I can use the command
OptionsViewEx DateFormat:=20
but how can I get the current date format (or any other view option for that matter)?
DefaultDateFormat should be the function to use.
oldvalue = Application.DefaultDateFormat
Application.DefaultDateFormat = 20 ' or = pjDate_mm_dd_yyyy
This gets or sets the default date format. (technet)
This gives the complete list of format types.
If you use Date function get a date in current format, but if you need change use format(Date,"yyyy-mmmm-dd") for example.

How do I change the format ActiveRecord expects when parsing dates from a text field in a form?

The problem
I have a Ruby on Rails model with a Date attribute.
In the form for this model, I am using a single text field with a JQuery datepicker to represent this attribute (not a drop down for each of year, month, and day, as is the Rails custom).
The datepicker inserts dates with a mm/dd/yyyy format.
Rails is expecting dates with a dd/mm/yyyy format.
Examples
If a user selects March 12th, 2012, the datepicker puts 03/12/2012, which is interpreted by Rails as December 3rd, 2012.
If a user selects March 20th, 2012, the datepicker puts 03/20/2012, which is interpreted by Rails as the 3rd day of the 20th month of 2012. Since this date doesn't exist, Rails casts this to a nil value (I think).
Question
How do I change the date format Rails uses when parsing this date text field?
Notes:
1) I do not want to change the format of the date the datepicker inserts into the text field,
2) I am not asking about displaying my date attribute in a view.
I initially thought this could be solved through the Rails internationalization features, but it turns out I was wrong.
Ever since Ruby 1.9, the standard format for date parsing is dd/mm/yyyy, so as to better accomodate international users. More details can be found in this SO answer.
That standard is maintained in Rails, as Date.parse is now used to process data from form inputs. Using a before_validation callback won't work because the field is going to be received as nil by the callback method.
Right now there are two gems dealing with this specific issue, namely that date parsing in Rails does not follow the locale settings from I18n.locale. Both seem to work well.
delocalize, by clemens - Seems to have been applied successfully in a decent number or projects and has the highest number of stars at the moment.
i18n_alchemy by carlosantoniodasilva - This one has been released more recently. The author is a Rails core team member, and a very active one at that. Definitely deserves a look.
Since you don't want to change the picker's format, I would suggest you use a hidden field for the actual model property.
For example, add a hidden field for the model's date property, assuming you use a form builder as usual:
f.hidden_field :date
Then for the picker text input, don't bind it to the model's date property. Let's say the hidden field has ID 'modelname_date' and the picker text input has ID 'date_picker', use the following to make it work:
$(function(){
$("#date_picker").datepicker({altField: '#nodelname_date', altFormat: 'dd/mm/yyyy'});
});
In this way the date picker shows the date as 'mm/dd/yyyy' but Rails will see the date as 'dd/mm/yyyy'.
Update:
If you want to work this out on the Rails side, here's another solution I'd suggest:
Add a virtual property to your model: attr_accessor :bad_format_date
Add a before_validation callback in which you parse the input date and assign it to the real field:
before_validation do
self.date = Date.strptime(bad_format_date, "%m/%d/%Y")
end
Then for the form on the view use bad_format_date but initialize it with the date field value (if it's an edit form).
The timeliness gem makes ruby date/time parsing much more customizeable and integrates well with Rails.
Since you're working with Rails, be sure to check out the validates_timeliness project as well by the same guy. It includes all of timeliness plus sophisticated date/time validation methods for ActiveModel.
You could try do something like this.
$(function(){
$('#date_picker').datepicker( {
beforeShowDay: $.datepicker.noWeekends,
showOtherMonths: true,
selectOtherMonths: true,
dateFormat: 'dd-mm-yy',
defaultDate: date,
gotoCurrent: true
});
I just add the following monkey patch to config/time_formats.rb
class Date
class << self
alias :euro_parse :_parse
def _parse(str,comp=false)
str = str.to_s.strip
if str == ''
{}
elsif str =~ /^(\d{1,2})[-\/](\d{1,2})[-\/](\d{2,4})/
year,month,day = $3.to_i,$1,$2
date,*rest = str.split(' ')
year += (year < 35 ? 2000 : 1900) if year < 100
euro_parse("#{year}-#{month}-#{day} #{rest.join(' ')}",comp)
else
euro_parse(str,comp)
end
end
end
end