[IMP] base, hr_timesheet: add option digital in qweb field duration

The option `digital` has been added. It allows to display "01:00" instead of "1
hour". This behaviour was implemented in a report (timesheet) but the logic
was done in the XML, which is not adequate.

This commit also allows to have a negative value for this widget.
This commit is contained in:
Christophe Matthieu
2018-08-13 17:09:28 +02:00
parent 9dbf815dd8
commit 5779807a31
3 changed files with 40 additions and 26 deletions
@@ -43,7 +43,7 @@
<t t-if="l.task_id"><span t-field="l.task_id.name"/></t>
</td>
<td class="text-right">
<span t-field="l.unit_amount" t-options="{'widget': 'float_time'}"/>
<span t-field="l.unit_amount" t-options="{'widget': 'duration', 'digital': True, 'unit': 'hour', 'round': 'minute'}"/>
</td>
</tr>
<tr>
@@ -51,9 +51,7 @@
<td />
<td t-if="show_task"/>
<td class="text-right"><strong>Total</strong></td>
<t t-set="total_value" t-value="sum(docs.mapped('unit_amount'))" />
<t t-set="sign" t-value="'-' if total_value &lt; 0 else ''"/>
<td class="text-right"><strong t-esc="sign + '%s:%02.0f' % tuple(int(round(x)) for x in divmod(abs(total_value)*60,60))"/></td>
<td class="text-right"><strong t-esc="sum(docs.mapped('unit_amount'))" t-options="{'widget': 'duration', 'digital': True, 'unit': 'hour', 'round': 'minute'}"/></td>
</tr>
</tbody>
</table>
+30 -15
View File
@@ -471,9 +471,13 @@ class DurationConverter(models.AbstractModel):
Can be used on any numerical field.
Has a mandatory option ``unit`` which can be one of ``second``, ``minute``,
Has an option ``unit`` which can be one of ``second``, ``minute``,
``hour``, ``day``, ``week`` or ``year``, used to interpret the numerical
field value before converting it.
field value before converting it. By default use ``second``.
Has an option ``round``. By default use ``second``.
Has an option ``digital`` to display 01:00 instead of 1 hour
Sub-second values will be ignored.
"""
@@ -485,8 +489,9 @@ class DurationConverter(models.AbstractModel):
options = super(DurationConverter, self).get_available_options()
unit = [[u[0], _(u[0])] for u in TIMEDELTA_UNITS]
options.update(
unit=dict(type="selection", params=unit, string=_('Date unit'), description=_('Date unit used for comparison and formatting'), default_value='hour'),
round=dict(type="selection", params=unit, string=_('Rounding unit'), description=_('Date unit used for the rounding. If the value is given, this must be smaller than the unit'), default_value='Same unit than "unit" option'),
digital=dict(type="boolean", string=_('Digital formating')),
unit=dict(type="selection", params=unit, string=_('Date unit'), description=_('Date unit used for comparison and formatting'), default_value='second', required=True),
round=dict(type="selection", params=unit, string=_('Rounding unit'), description=_("Date unit used for the rounding. The value must be smaller than 'hour' if you use the digital formating."), default_value='second'),
)
return options
@@ -494,22 +499,32 @@ class DurationConverter(models.AbstractModel):
def value_to_html(self, value, options):
units = dict(TIMEDELTA_UNITS)
if value < 0:
raise ValueError(_("Durations can't be negative"))
if not options or options.get('unit', 'hour') not in units:
raise ValueError(_("A unit must be provided to duration widgets"))
locale = babel.Locale.parse(self.user_lang().code)
factor = units[options.get('unit', 'hour')]
factor = units[options.get('unit', 'second')]
round_to = units[options.get('round', 'second')]
if options.get('digital') and round_to > 3600:
round_to = 3600
r = round((value * factor) / round_to) * round_to
sections = []
r = value * factor
if options.get('round') in units:
round_to = units[options['round']]
r = round(r / round_to) * round_to
if options.get('digital'):
for unit, secs_per_unit in TIMEDELTA_UNITS:
if secs_per_unit > 3600:
continue
v, r = divmod(r, secs_per_unit)
if not v and (secs_per_unit > factor or secs_per_unit < round_to):
continue
if len(sections):
sections.append(u':')
sections.append(u"%02.0f" % int(round(v)))
return u''.join(sections)
if value < 0:
r = -r
sections.append(u'-')
for unit, secs_per_unit in TIMEDELTA_UNITS:
v, r = divmod(r, secs_per_unit)
if not v:
@@ -297,17 +297,18 @@ class TestDurationExport(TestBasicExport):
# needs to have lang installed otherwise falls back on en_US
self.env['res.lang'].load_lang('fr_FR')
def test_default_unit(self):
converter = self.get_converter('float', 'duration')
self.assertEqual(converter(4), u'4 seconds')
def test_negative(self):
converter = self.get_converter('float', 'duration')
self.assertEqual(converter(-4), u'- 4 seconds')
with self.assertRaises(ValueError):
converter(-4)
def test_missing_unit(self):
def test_negative_with_round(self):
converter = self.get_converter('float', 'duration')
with self.assertRaises(ValueError):
converter(4)
result = converter(-4.678, {'unit': 'year', 'round': 'hour'}, {'lang': 'fr_FR'})
self.assertEqual(result, u'- 4 ans 8 mois 1 semaine 11 heures')
def test_basic(self):
converter = self.get_converter('float', 'duration')