Managing events and all-day events with calendar view

Hi,

I’m trying a small custo to manage shipments events and displaying them in calendar view.

We have 2 types of shipment events:

  • We don’t know what time it should be delivered/shipped, so we don’t care about time to have an “all day event” (ics calendar event with only a dtstart without time)
  • The carrier warns us about the delivery/shipping time so we need the time to have the event at the correct time in the calendar (there’s a function field that define an “end” with a 1 hour interval from specified time) (ics calendar event with dtstart and dtend)

My problem is how to display both types of event in the calendar view:

  • When it’s an “all-day event”, I just need a start date without time
  • otherwise, I need a start date and a end_date with time

Calendar view needs two fields to define dtstart and dtend attributes.

So I’m working with:

    ....
    planned_date = fields.DateTime("Planned Date",
        required=True,
        states={
            'readonly': Eval('state').in_(['cancelled', 'done']),
            },
        help="When the shipement is expected to be shipped or received.")
    end_planned_date = fields.DateTime("End Planned Date", readonly=True)
    all_day_event = fields.Boolean("All Day Event")
    ....

and doing a specific write depending on events:

  • end_planned_date is just 1 hour later than planned_date
  • end_planned_date = planned_date without time if all day event
    @classmethod
    def write(cls, *args):
        super().write(*args)
        actions = iter(args)
        to_write = []
        for events, values in zip(actions, actions):
            for event in events:
                write = {}
                end_date = None
                if not event.all_day_event and event.planned_date:
                    end_date = event.planned_date + dt.timedelta(hours=1)
                if event.all_day_event and event.planned_date:
                    start_date = event.planned_date.date()
                if start_date != event.planned_date:
                    write['planned_date'] = start_date
                if (end_date != event.end_planned_date):
                    write['end_planned_date'] = end_date
                if write:
                    to_write.extend(([event], write))
        if to_write:
            cls.write(*to_write)

but when saving an ‘all day event’, I have this error:


Traceback (most recent call last):
  File "/home/mrichez/Workspace/tryton/issues/tryton_72_dev/trytond/trytond/wsgi.py", line 110, in dispatch_request
    return endpoint(request, **request.view_args)
  File "/home/mrichez/Workspace/tryton/issues/tryton_72_dev/trytond/trytond/protocols/dispatcher.py", line 44, in rpc
    return methods.get(request.rpc_method, _dispatch)(
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
        request, database_name, *request.rpc_params)
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/mrichez/Workspace/tryton/issues/tryton_72_dev/trytond/trytond/wsgi.py", line 76, in wrapper
    return func(request, *args, **kwargs)
  File "/home/mrichez/Workspace/tryton/issues/tryton_72_dev/trytond/trytond/protocols/wrappers.py", line 208, in wrapper
    result = func(request, pool, *args, **kwargs)
  File "/home/mrichez/Workspace/tryton/issues/tryton_72_dev/trytond/trytond/protocols/dispatcher.py", line 216, in _dispatch
    result = rpc.result(meth(*c_args, **c_kwargs))
                        ~~~~^^^^^^^^^^^^^^^^^^^^^
  File "/home/mrichez/Workspace/tryton/issues/tryton_72_dev/trytond/trytond/model/modelview.py", line 764, in wrapper
    return func(cls, records, *args, **kwargs)
  File "/home/mrichez/Workspace/tryton/issues/tryton_72_dev/trytond/trytond/model/workflow.py", line 44, in wrapper
    cls.write(to_update, {
    ~~~~~~~~~^^^^^^^^^^^^^
            cls._transition_state: state,
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
            })
            ^^
  File "/home/mrichez/Workspace/tryton/issues/tryton_72_dev/trytond/trytond/modules/preciball/stock/stock.py", line 560, in write
    cls.write(*to_write)
    ~~~~~~~~~^^^^^^^^^^^
  File "/home/mrichez/Workspace/tryton/issues/tryton_72_dev/trytond/trytond/modules/preciball/stock/stock.py", line 540, in write
    super().write(*args)
    ~~~~~~~~~~~~~^^^^^^^
  File "/home/mrichez/Workspace/tryton/issues/tryton_72_dev/trytond/trytond/model/modelsql.py", line 268, in wrapper
    return func(cls, *args, **kwargs)
  File "/home/mrichez/Workspace/tryton/issues/tryton_72_dev/trytond/trytond/model/modelsql.py", line 1360, in write
    update_values.append(field.sql_format(value))
                         ~~~~~~~~~~~~~~~~^^^^^^^
  File "/home/mrichez/Workspace/tryton/issues/tryton_72_dev/trytond/trytond/model/fields/date.py", line 119, in sql_format
    value = super().sql_format(value)
  File "/home/mrichez/Workspace/tryton/issues/tryton_72_dev/trytond/trytond/model/fields/date.py", line 88, in sql_format
    return super().sql_format(value)
           ~~~~~~~~~~~~~~~~~~^^^^^^^
  File "/home/mrichez/Workspace/tryton/issues/tryton_72_dev/trytond/trytond/model/fields/field.py", line 414, in sql_format
    value = self._py_type(value)
TypeError: 'datetime.date' object cannot be interpreted as an integer

Fault: 'datetime.date' object cannot be interpreted as an integer

Any idea ? It is not possible to save only a date in a datetime field ?
Thanks.

No, you must cast it to datetime, you cannot mix the two concepts.

s. Date vs. DateTime

If you want to get a datetime field displayed in calendar view, it needs an dtend set. So depending on your preference I would either set it from 0:00 - 23:59 or to a short time frame like 0:00 - 0:15 (to be displayed on top of the calendar).

But all calendars allow mixing all-day events and events:

For instance, a birthday date and also a meeting at 10am…

An all-day event should be only a date as dtstart and other kind of event are datetime with dtstart and dtend…

Bug or feature in Tryton Calendar ?

We hit that problem too. It is probably a feature but we need it too.

1 Like

The calendar view of Tryton is not a calendar but a view as a calendar.
It put the record on a calendar.

I do not think we should expect a full featured calendar in Tryton.
For me if someone want such behavior it will be better to implement a readonly HTTP CardDAV.

But maybe it is doable by allowing 4 attributes instead of two:

  • start_date
  • end_date
  • start_datetime
  • end_datetime

If both a date and a datetime attributes are provided, then the mixed events calendar could be used.

This is ambigus. What happen if boths are filled or a date and a datetime? Also what does the client need to update on DnD or fill when creating a new record?

I think it could be possible to mix both kind of event:

  • All day event has only a start datetime
  • Other events have start datetime and end datetime

Domain here should just allow None as dtend (tryton/tryton/gui/window/view_form/view/calendar_gtk/calendar_.py · branch/default · Tryton / Tryton · GitLab)

        domain = ['OR',
            ['AND', (dtstart, '!=', None), (dtend, '!=', None),
                ['OR',
                    ['AND', (dtstart, '>=', start), (dtstart, '<', end)],
                    ['AND', (dtend, '>=', start), (dtend, '<', end)],
                    ['AND', (dtstart, '<', start), (dtend, '>', end)],
                ],
            ],
            ['AND', 
                (dtstart, '!=', None), 
                (dtend, '=', None),
                (dtstart, '>=', start), 
                (dtstart, '<', end),
            ]
            ]

Theoretically an all day event can span on multiple days.

Indeed… :slight_smile:

Fair enough. A “whole_day” boolean field could be added to distinguish between the two.