import base64
import datetime as DT
+import logging
+import pytz
import re
-import string
-import sys
-import warnings
import xmlrpclib
from psycopg2 import Binary
import openerp
-import openerp.netsvc as netsvc
import openerp.tools as tools
from openerp.tools.translate import _
from openerp.tools import float_round, float_repr
-import json
+import simplejson
+
+_logger = logging.getLogger(__name__)
def _symbol_set(symb):
if symb == None or symb == False:
def __init__(self, string='unknown', required=False, **args):
super(boolean, self).__init__(string=string, required=required, **args)
if required:
- warnings.warn("Making a boolean field `required` has no effect, as NULL values are "
- "automatically turned into False", PendingDeprecationWarning, stacklevel=2)
+ _logger.debug(
+ "required=True is deprecated: making a boolean field"
+ " `required` has no effect, as NULL values are "
+ "automatically turned into False.")
class integer(_column):
_type = 'integer'
def __init__(self, string='unknown', required=False, **args):
super(integer, self).__init__(string=string, required=required, **args)
if required:
- warnings.warn("Making an integer field `required` has no effect, as NULL values are "
- "automatically turned into 0", PendingDeprecationWarning, stacklevel=2)
+ _logger.debug(
+ "required=True is deprecated: making an integer field"
+ " `required` has no effect, as NULL values are "
+ "automatically turned into 0.")
class integer_big(_column):
"""Experimental 64 bit integer column type, currently unused.
def __init__(self, string='unknown', required=False, **args):
super(integer_big, self).__init__(string=string, required=required, **args)
if required:
- warnings.warn("Making an integer_big field `required` has no effect, as NULL values are "
- "automatically turned into 0", PendingDeprecationWarning, stacklevel=2)
+ _logger.debug(
+ "required=True is deprecated: making an integer_big field"
+ " `required` has no effect, as NULL values are "
+ "automatically turned into 0.")
class reference(_column):
_type = 'reference'
# synopsis: digits_compute(cr) -> (precision, scale)
self.digits_compute = digits_compute
if required:
- warnings.warn("Making a float field `required` has no effect, as NULL values are "
- "automatically turned into 0.0", PendingDeprecationWarning, stacklevel=2)
+ _logger.debug(
+ "required=True is deprecated: making a float field"
+ " `required` has no effect, as NULL values are "
+ "automatically turned into 0.0.")
def digits_change(self, cr):
if self.digits_compute:
class date(_column):
_type = 'date'
+
@staticmethod
def today(*args):
""" Returns the current date in a format fit for being a
return DT.date.today().strftime(
tools.DEFAULT_SERVER_DATE_FORMAT)
+ @staticmethod
+ def context_today(model, cr, uid, context=None, timestamp=None):
+ """Returns the current date as seen in the client's timezone
+ in a format fit for date fields.
+ This method may be passed as value to initialize _defaults.
+
+ :param Model model: model (osv) for which the date value is being
+ computed - technical field, currently ignored,
+ automatically passed when used in _defaults.
+ :param datetime timestamp: optional datetime value to use instead of
+ the current date and time (must be a
+ datetime, regular dates can't be converted
+ between timezones.)"""
+ today = timestamp or DT.datetime.now()
+ context_today = None
+ if context and context.get('tz'):
+ try:
+ utc = pytz.timezone('UTC')
+ context_tz = pytz.timezone(context['tz'])
+ utc_today = utc.localize(today, is_dst=False)
+ context_today = utc_today.astimezone(context_tz)
+ except Exception:
+ _logger.debug("failed to compute context/client-specific today date, "
+ "using the UTC value for `today`",
+ exc_info=True)
+ return (context_today or today).strftime(tools.DEFAULT_SERVER_DATE_FORMAT)
+
class datetime(_column):
_type = 'datetime'
@staticmethod
_deprecated = True
def __init__(self, obj, string='unknown', **args):
- warnings.warn("The one2one field doesn't work anymore", DeprecationWarning)
+ _logger.warning("The one2one field is deprecated and doesn't work anymore.")
_column.__init__(self, string=string, **args)
self._obj = obj
elif act[0] == 5:
reverse_rel = obj._all_columns.get(self._fields_id)
assert reverse_rel, 'Trying to unlink the content of a o2m but the pointed model does not have a m2o'
- # if the model has on delete cascade, just delete the rows
+ # if the o2m has a static domain we must respect it when unlinking
+ extra_domain = self._domain if isinstance(getattr(self, '_domain', None), list) else []
+ ids_to_unlink = obj.search(cr, user, [(self._fields_id,'=',id)] + extra_domain, context=context)
+ # If the model has cascade deletion, we delete the rows because it is the intended behavior,
+ # otherwise we only nullify the reverse foreign key column.
if reverse_rel.column.ondelete == "cascade":
- obj.unlink(cr, user, obj.search(cr, user, [(self._fields_id,'=',id)], context=context), context=context)
+ obj.unlink(cr, user, ids_to_unlink, context=context)
else:
- cr.execute('update '+_table+' set '+self._fields_id+'=null where '+self._fields_id+'=%s', (id,))
+ obj.write(cr, user, ids_to_unlink, {self._fields_id: False}, context=context)
elif act[0] == 6:
# Must use write() to recompute parent_store structure if needed
obj.write(cr, user, act[2], {self._fields_id:id}, context=context or {})
for id in ids:
res[id] = []
if offset:
- warnings.warn("Specifying offset at a many2many.get() may produce unpredictable results.",
- DeprecationWarning, stacklevel=2)
+ _logger.warning(
+ "Specifying offset at a many2many.get() is deprecated and may"
+ " produce unpredictable results.")
obj = model.pool.get(self._obj)
rel, id1, id2 = self._sql_names(model)
"""
def _symbol_set_struct(val):
- return json.dumps(val)
+ return simplejson.dumps(val)
def _symbol_get_struct(self, val):
- return json.loads(val or '{}')
+ return simplejson.loads(val or '{}')
_prefetch = False
_type = 'serialized'