You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

122 lines
4.2 KiB

  1. # Copyright 2015, 2017 Jairo Llopis <jairo.llopis@tecnativa.com>
  2. # Copyright 2016 Tecnativa, S.L. - Vicent Cubells
  3. # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
  4. from datetime import datetime, timedelta
  5. from odoo import _, api, fields, models
  6. from odoo.tools import (DEFAULT_SERVER_DATE_FORMAT,
  7. DEFAULT_SERVER_TIME_FORMAT)
  8. from odoo.exceptions import UserError
  9. # Available modes for :param:`.ResLang.datetime_formatter.template`
  10. MODE_DATETIME = "MODE_DATETIME"
  11. MODE_DATE = "MODE_DATE"
  12. MODE_TIME = "MODE_TIME"
  13. class ResLang(models.Model):
  14. _inherit = "res.lang"
  15. @api.model
  16. @api.returns('self')
  17. def best_match(self, lang=None, failure_safe=True):
  18. """Get best match of current default lang.
  19. :param str lang:
  20. If a language in the form of "en_US" is supplied, it will have the
  21. highest priority.
  22. :param bool failure_safe:
  23. If ``False`` and the best matched language is not found installed,
  24. an exception will be raised. Otherwise, the first installed
  25. language found in the DB will be returned.
  26. """
  27. # Find some installed language, as fallback
  28. first_installed = self.search([("active", "=", True)], limit=1)
  29. if not lang:
  30. lang = (
  31. # Object's language, if called like
  32. # ``record.lang.datetime_formatter(datetime_obj)``
  33. (self.ids and self[0].code) or
  34. # Context language
  35. self.env.context.get("lang") or
  36. # User's language
  37. self.env.user.lang or
  38. # First installed language found
  39. first_installed.code)
  40. # Get DB lang record
  41. record = self.search([("code", "=", lang)])
  42. try:
  43. record.ensure_one()
  44. except ValueError:
  45. if not failure_safe:
  46. raise UserError(
  47. _("Best matched language (%s) not found.") % lang
  48. )
  49. else:
  50. record = first_installed
  51. return record
  52. @api.model
  53. def datetime_formatter(self, value, lang=None, template=MODE_DATETIME,
  54. separator=" ", failure_safe=True):
  55. """Convert a datetime field to lang's default format.
  56. :type value: `str`, `float` or `datetime.datetime`
  57. :param value:
  58. Datetime that will be formatted to the user's preferred format.
  59. :param str lang:
  60. See :param:`lang` from :meth:`~.best_match`.
  61. :param bool failure_safe:
  62. See :param:`failure_safe` from :meth:`~.best_match`.
  63. :param str template:
  64. Will be used to format :param:`value`. If it is one of the special
  65. constants :const:`MODE_DATETIME`, :const:`MODE_DATE` or
  66. :const:`MODE_TIME`, it will use the :param:`lang`'s default
  67. template for that mode.
  68. :param str separator:
  69. Only used when :param:`template` is :const:`MODE_DATETIME`, as the
  70. separator between the date and time parts.
  71. """
  72. # Get the correct lang
  73. lang = self.best_match(lang)
  74. # Get the template
  75. if template in {MODE_DATETIME, MODE_DATE, MODE_TIME}:
  76. defaults = []
  77. if "DATE" in template:
  78. defaults.append(lang.date_format or
  79. DEFAULT_SERVER_DATE_FORMAT)
  80. if "TIME" in template:
  81. defaults.append(lang.time_format or
  82. DEFAULT_SERVER_TIME_FORMAT)
  83. template = separator.join(defaults)
  84. # Convert str to datetime objects
  85. if isinstance(value, str):
  86. try:
  87. value = fields.Datetime.from_string(value)
  88. except ValueError:
  89. # Probably failed due to value being only time
  90. value = datetime.strptime(value, DEFAULT_SERVER_TIME_FORMAT)
  91. # Time-only fields are floats for Odoo
  92. elif isinstance(value, float):
  93. # Patch values >= 24 hours
  94. if value >= 24:
  95. template = template.replace("%H", "%d" % value)
  96. # Convert to time
  97. value = (datetime.min + timedelta(hours=value)).time()
  98. return value.strftime(template)