4

I have two fields in my module,(start_date and end_date). I want to validate the date range as end_date must be greater than start_date and display error message like "End Date Should be greater than Start Date" This is mu cord.

from openerp.osv import osv, fields


class op_batch(osv.Model):

    _name = 'op.batch'
    _columns = {
        'name': fields.char(size=25, string='Name', required=True),
        'code': fields.char(size=15, string='Code', required=True),
        'start_date': fields.date(size=15, string='Start Date', required=True),
        'end_date': fields.date(size=15, string='End Date', required=True, onchange="validate_date_range"),
        'state': fields.selection(
        [('planned', 'Planned'), ('running', 'Running'), ('cancel', 'Cancel'), ('finished', 'finished')],
        string='State'),
        'course_id': fields.many2one('op.course', string='Course', ondelete='restrict', required=True),
}

    def validate_date_range(self, cr, uid, vals, context=None):
        en_date = date.start_date.value
        st_date = date.end_date.value
        if en_date < st_date:
            raise Warning(_("End Date Should be greater than Start Date"))
    return True

    _sql_constraints = [('code', 'UNIQUE (code)', 'The CODE of the Batch must be unique!')]

    _defaults = {
    'state': 'planned',
    }

how should I do that? Please Help me to do this...

Chamal
  • 235
  • 1
  • 7
  • 13

3 Answers3

4

To enforce data integrity, odoo support two types of constraints: SQL and Python.

SQL constraints are added to the table definition in the database and implemented by PostgreSQL. They are defined using the class attribute _sql_constraints. It is a list of tuples with the constraint identifier name, the SQL for the constraint, and the error message to use.

Python Constraint

In v7 api,

_constraint is a collection of list of tuples.

Tuple contains three parameters,

  1. Method Name (where your actual logic coded)
  2. The Validation Message (Message that you want to show to user)
  3. List of Fields (fields to which you want to apply the constraint)

_constraint will raise the validation message if the condition returns False on create/update record.

Just add constraints for that,

def _check_date(self, cr, uid, vals, context=None):
    for obj in self.browse(cr, uid, ids):
        start_date = obj.start_date
        end_date = obj.end_date

        if start_date and end_date:
            DATETIME_FORMAT = "%Y-%m-%d"  ## Set your date format here
            from_dt = datetime.datetime.strptime(start_date, DATETIME_FORMAT)
            to_dt = datetime.datetime.strptime(end_date, DATETIME_FORMAT)

            if to_dt < from_dt:
                return False
    return True

_constraints = [
        (_check_date, 'Your Message!', ['start_date','end_date']),
    ]

In v8 api,

@api.constrains

This decorator will ensure that decorated function will be called on create, write, unlink operation. If a constraint is met the function should raise a openerp.exceptions.Warning with appropriate message.

@api.multi
@api.constrains('start_date','end_date')
def _check_date(self):
    for obj in self:
        start_date = obj.start_date
        end_date = obj.end_date

        if start_date and end_date:
            DATETIME_FORMAT = "%Y-%m-%d"  ## Set your date format here
            from_dt = datetime.datetime.strptime(start_date, DATETIME_FORMAT)
            to_dt = datetime.datetime.strptime(end_date, DATETIME_FORMAT)

            if to_dt < from_dt:
                #raise your exception

If you want to change the existing constraints, it can be done by using inheritance see here

  • Thank you Emipro Technologies.. It was very helpful.. Also this matter I have to change ids in browse method and import datetime. THANK YOU – Chamal Apr 02 '15 at 03:23
  • Thanks for the complements. – Emipro Technologies Pvt. Ltd. Apr 02 '15 at 04:08
  • Why do you use the format stuff ? You can just compare the strings... or not? I though that the date were always converted to "%Y-%m-%d" before triggering the constraint check. – yucer Oct 23 '15 at 10:30
  • There is a strong reason behind this, if you don't convert this to object then it's considered as a string comparison, and for string (even format is same) it will not give the perfect result, let say '2015-10-03' and '2015-2-04' it will not give you the right result. – Emipro Technologies Pvt. Ltd. Oct 23 '15 at 11:28
  • if single digit format is there for month then for February it's 2 and for October it's 10 and in string February is higher then October :) – Emipro Technologies Pvt. Ltd. Oct 23 '15 at 11:30
0

Another solution is to validate it when it changes in the client side, so you have an immediate response:

from openerp import exceptions, _

    @api.onchange('start_date','end_date')
    def check_change(self):
        if start_date > end_date:   # already in "%Y-%m-%d" format
            raise exceptions.ValidationError(_('Your Message!'))
yucer
  • 4,431
  • 3
  • 34
  • 42
  • I should add that here is easy because you have both dates from the client to compare. But i don't know very well how to proceed when comparing with the current date, because this code runs in the server. I don't remember if the dates are converted to the server timezone before triggering the onchage api. – yucer Oct 23 '15 at 10:17
0

Other than onchange we can use constraints... It helps to validate something when create and edit and also in change.. Here is my code and it works fine

@api.multi
@api.constrains('start_date', 'start_date')
def _check_date(self):
    start_date = self.start_date
    end_date = self.end_date

    if (start_date and end_date) and (start_date > end_date):
        raise ValidationError(_('The start date must be less than to the end date. ')
Ridma Gimhani
  • 133
  • 3
  • 12
  • Thanks for answering questions, but this answer doesn't add any extra value since the same is already stated in the accepted answer. On SO we don't like repetition. Please consider removing this answer. – ViG Mar 29 '18 at 11:08