odex30_standard/months_custom/__init__.py

176 lines
7.6 KiB
Python

# -*- coding: utf-8 -*-
import babel.dates
import pytz
import logging
import odoo
from odoo import models, api
from odoo.osv import expression
from odoo.tools.misc import DEFAULT_SERVER_DATETIME_FORMAT, DEFAULT_SERVER_DATE_FORMAT
from odoo.tools.misc import posix_to_ldml, file_open
from odoo import http
from odoo.http import request
import werkzeug
from datetime import datetime
_logger = logging.getLogger(__name__)
def format_date(env, value, lang_code=False, date_format=False):
if not value:
return ''
if isinstance(value, str):
try:
# Convert string to datetime object for Odoo 18
if len(value) > 10: # datetime
value = datetime.fromisoformat(value.replace('Z', '+00:00'))
value = odoo.fields.Datetime.context_timestamp(env['res.lang'], value)
else: # date
value = datetime.fromisoformat(value)
except ValueError:
return ''
lang = env['res.lang']._lang_get(lang_code or env.context.get('lang') or 'en_US')
locale = babel.Locale.parse(lang.code)
locale = str(locale)
if locale.lower().startswith('ar'):
locale = "ar"
if not date_format:
date_format = posix_to_ldml(lang.date_format, locale=locale)
return babel.dates.format_date(value, format=date_format, locale=locale)
# Only override if not already overridden
if not hasattr(odoo.tools.misc, '_original_format_date'):
odoo.tools.misc._original_format_date = odoo.tools.misc.format_date
odoo.tools.misc.format_date = format_date
class WebClientInherit(http.Controller):
@http.route('/web/webclient/locale/<string:lang>', type='http', auth="none")
def load_locale(self, lang):
magic_file_finding = [lang.replace("_", '-').lower(), lang.split('_')[0]]
for code in magic_file_finding:
if code.lower().startswith('ar'):
code = 'ar-sa'
try:
# Updated for Odoo 18 file structure
file_path = f'web/static/lib/moment/locale/{code}.js'
file_content = file_open(file_path, 'rb').read()
return request.make_response(
file_content,
headers=[
('Content-Type', 'application/javascript; charset=utf-8'),
('Cache-Control', 'max-age=36000'),
]
)
except (IOError, FileNotFoundError):
_logger.debug("No moment locale for code %s", code)
return request.make_response("", headers=[
('Content-Type', 'application/javascript'),
('Cache-Control', 'max-age=36000'),
])
class BaseModelExtend(models.BaseModel):
_name = 'basemodel.extend_custom_months'
_description = 'Base Model Extension for Custom Months'
def _register_hook(self):
# Store original method
original_method = models.BaseModel._read_group_format_result
@api.model
def _read_group_format_result_custom(self, rows_dict, lazy_groupby):
"""
Enhanced version of _read_group_format_result with Arabic locale support.
Overrides Odoo 18's method to use 'ar' locale instead of 'ar_SY' for Arabic.
"""
from odoo.models import READ_GROUP_TIME_GRANULARITY, READ_GROUP_DISPLAY_FORMAT
from odoo.tools.misc import get_lang
import datetime
for group in lazy_groupby:
field_name = group.split(':')[0].split('.')[0]
field = self._fields.get(field_name)
if not field:
continue
if field.type in ('date', 'datetime'):
granularity = group.split(':')[1] if ':' in group else 'month'
if granularity in READ_GROUP_TIME_GRANULARITY:
# Get locale and modify for Arabic
lang = get_lang(self.env)
locale = lang.code
if locale.lower().startswith('ar'):
locale = "ar"
fmt = DEFAULT_SERVER_DATETIME_FORMAT if field.type == 'datetime' else DEFAULT_SERVER_DATE_FORMAT
interval = READ_GROUP_TIME_GRANULARITY[granularity]
elif field.type == "properties":
self._read_group_format_result_properties(rows_dict, group)
continue
for row in rows_dict:
value = row.get(group)
if isinstance(value, models.BaseModel):
row[group] = (value.id, value.sudo().display_name) if value else False
value = value.id
if not value and field.type == 'many2many':
additional_domain = [(field_name, 'not any', [])]
else:
additional_domain = [(field_name, '=', value)]
if field.type in ('date', 'datetime'):
if value and isinstance(value, (datetime.date, datetime.datetime)):
range_start = value
range_end = value + interval
if field.type == 'datetime':
tzinfo = None
if self._context.get('tz') in pytz.all_timezones_set:
tzinfo = pytz.timezone(self._context['tz'])
range_start = tzinfo.localize(range_start).astimezone(pytz.utc)
range_end = tzinfo.localize(range_end).astimezone(pytz.utc)
label = babel.dates.format_datetime(
range_start, format=READ_GROUP_DISPLAY_FORMAT[granularity],
tzinfo=tzinfo, locale=locale
)
else:
label = babel.dates.format_date(
value, format=READ_GROUP_DISPLAY_FORMAT[granularity],
locale=locale
)
# Special case for weeks
if granularity == 'week':
from odoo.tools import date_utils
year, week = date_utils.weeknumber(
babel.Locale.parse(locale),
value,
)
label = f"W{week} {year:04}"
range_start = range_start.strftime(fmt)
range_end = range_end.strftime(fmt)
row[group] = label
row.setdefault('__range', {})[group] = {'from': range_start, 'to': range_end}
additional_domain = [
'&',
(field_name, '>=', range_start),
(field_name, '<', range_end),
]
elif not value:
row.setdefault('__range', {})[group] = False
row['__domain'] = expression.AND([row.get('__domain', []), additional_domain])
# Only override if not already overridden
if not hasattr(models.BaseModel, '_months_custom_override'):
models.BaseModel._months_custom_override = True
models.BaseModel._read_group_format_result = _read_group_format_result_custom
return super(BaseModelExtend, self)._register_hook()