Wprowadzenie
Daty i znaczniki czasu to podstawowy element niemal każdej procedury firmowej — od zamówień po obecności pracowników. W Odoo do przechowywania takiej informacji używamy specjalnego pola, które składa datę i godzinę w jedną wartość, dzięki czemu możemy precyzyjnie rejestrować momenty, w których zachodzą zdarzenia biznesowe.
W odróżnieniu od prostego pola Date, które przechowuje wyłącznie dzień kalendarzowy, pole Datetime zapamiętuje także godzinę i minuty (a nawet sekundy). To istotne, gdy pracujemy z użytkownikami w różnych strefach czasowych albo gdy wyniki raportów zależą od konkretnej godziny zdarzenia.
Ten przewodnik wyjaśnia najważniejsze zagadnienia dotyczące pola Datetime w Odoo: co jest w nim zapisywane, jak zachowuje się w modelu danych, jak je dodać przez Odoo Studio, kod Python lub API, oraz podaje praktyczne scenariusze użycia w firmowych procesach.
Czym jest pole Datetime w Odoo
Na poziomie ORM Odoo pole fields.Datetime przechowuje łączną wartość daty i czasu z dokładnością do sekundy. W bazie danych odpowiada mu kolumna typu TIMESTAMP w PostgreSQL. Odoo zapisuje te wartości wewnętrznie w UTC i dopiero przy wyświetlaniu konwertuje je do strefy czasowej ustawionej dla danego użytkownika.
Z perspektywy użytkownika pole Datetime w formularzu wygląda jak jeden kontroler zawierający kalendarz oraz pole do wpisania godziny. W widokach listy i w raportach wartość prezentowana jest zgodnie z preferencjami językowymi i ustawioną strefą czasową aktywnego użytkownika.
Przykład definicji pola Datetime w modelu Python pokazuje typowe parametry i zastosowanie w rozszerzonym modelu biznesowym.
from odoo import fields, models
class SaleOrder(models.Model):
_inherit = 'sale.order'
x_confirmed_on = fields.Datetime(
string='Confirmed On',
default=fields.Datetime.now,
readonly=True,
copy=False,
)
Parametr string określa etykietę wyświetlaną w interfejsie. default ustawia wartość domyślną (tutaj aktualny znacznik czasu). readonly blokuje ręczne zmiany — często tak oznaczane są znaczniki audytowe, które powinny odzwierciedlać faktyczny stan systemu.
W Odoo Studio typ ten nazywa się Date & Time. Pole utworzone przez Studio dostaje automatycznie prefix x_studio_. Gdy pole dodasz programistycznie lub przez API, sam decydujesz o jego technicznej nazwie.
Jak pole działa
Gdy zdefiniujesz pole Datetime w modelu, Odoo podczas instalacji lub aktualizacji modułu automatycznie doda odpowiednią kolumnę w bazie danych — nie musisz pisać ręcznych migracji SQL.
Wielu użytkowników i deweloperów zdziwi fakt, jak Odoo zarządza strefami czasowymi. Baza przechowuje zawsze czas w UTC. Jeśli użytkownik z Paryża zapisze spotkanie na 15:00, w bazie pojawi się wartość 13:00 UTC. Inny użytkownik w Nowym Jorku zobaczy tę samą zapis jako 09:00 w swoim interfejsie — konwersję robi ORM na podstawie ustawień profilu użytkownika.
Kluczowe właściwości pola
Poniżej najważniejsze atrybuty pola Datetime w Odoo, które warto znać przy projektowaniu modelu danych:
- default: zwykle ustawiany jako
fields.Datetime.now, aby podczas tworzenia rekordu automatycznie wstawić aktualny znacznik czasu UTC. - required: oznacza pole jako obowiązkowe w formularzach i na poziomie modelu.
- readonly: blokuje edycję w interfejsie — typowe dla automatycznie generowanych znaczników czasu.
- compute: pozwala powiązać pole z metodą Pythona, która oblicza wartość na podstawie innych pól lub logiki biznesowej.
- store: razem z
computeoznacza, że obliczona wartość będzie zapisana w bazie, co umożliwia wyszukiwanie i raportowanie po tej kolumnie. - copy: kontroluje, czy wartość ma być kopiowana przy duplikacji rekordu. Domyślnie
True; ustawienieFalsejest zalecane dla znaczników czasu, które nie powinny przenosić się na kopie. - index: tworzy indeks w bazie — przydatne dla pól często wykorzystywanych w filtrach, np. planowanych dat w dużych tabelach.
Jak wygląda w widokach
W formularzach pole Datetime renderuje się jako połączony wybór daty i pola godziny — użytkownik może jednocześnie korzystać z kalendarza i wpisać czas. W listach wartości są formatowane zgodnie z językiem użytkownika. W filtrach wyszukiwania dostępne są operatory typu przed, po, między, co ułatwia tworzenie zapytań po przedziałach czasowych.
Dodatkowo można zastosować widget date_range, aby w formularzu pokazać bezpośrednio wybór przedziału — przydatne przy planowaniu okien czasowych lub zadań terminowych.
Datetime a Date: jak wybrać właściwy typ
Powszechna wątpliwość to, kiedy użyć fields.Datetime, a kiedy fields.Date. Prosta zasada: jeśli czas dnia nie ma znaczenia, wybierz Date; jeśli potrzebujesz precyzji co do godziny i minuty — wybierz Datetime.
Użyj pola Date dla: terminów płatności faktur, dat urodzin, dat ważności produktów, terminów odnowienia umów.
Użyj pola Datetime dla: momentu potwierdzenia zamówienia, godzin rozpoczęcia spotkań, rejestracji obecności pracowników, zaplanowanych operacji magazynowych.
Niepotrzebne użycie Datetime wprowadza zbędną złożoność związaną ze strefami czasowymi. Gdy masz wątpliwości, zapytaj: czy godzina dnia naprawdę ma wpływ na proces biznesowy lub raportowanie?
Przykłady zastosowań biznesowych
Pole Datetime występuje w praktycznie każdym module Odoo. Poniżej pięć typowych zastosowań z życia firmy.
CRM: śledzenie aktywności leadów
W CRM pola Datetime służą do rejestracji najważniejszych momentów: kiedy lead zmienił etap na „w toku”, kiedy ustawiono termin kontaktu czy kiedy wysłano ofertę. Menedżerowie wykorzystują te dane, by mierzyć czas reakcji, wychwytywać zaniedbane szanse i raportować efektywność zespołu. Dodatkowe, niestandardowe pola Datetime pozwalają np. logować dokładny czas wykonania rozmowy czy wysłania propozycji handlowej.
Sprzedaż: znacznik potwierdzenia zamówienia
Pole date_order na sale.order to Datetime, który zapisuje moment potwierdzenia sprzedaży. Dzięki temu raporty mogą analizować sprzedaż w podziale godzinowym, mierzyć czas przetwarzania zamówień i kontrolować zmiany po potwierdzeniu. Filtrowanie zamówień po tej dacie to jedna z najczęściej wykonywanych operacji analitycznych w dziale handlowym.
Magazyn: planowane daty przesunięć
Na modelu stock.picking pole scheduled_date pomaga zespołom magazynowym planować odbiory i wysyłki. Automatyczne reguły mogą uruchamiać akcje, gdy termin minął — np. wysyłać powiadomienie o opóźnieniu dostawy. Dzięki temu firma może komunikować się z klientem zanim on zgłosi reklamację.
Produkcja: czasy startu i zakończenia
Zlecenia produkcyjne rejestrują dokładne czasy rozpoczęcia i zakończenia pracy. Te wartości są bazą do planowania zdolności produkcyjnych, analiz wydajności oraz porównania planu z rzeczywistością. W zakładach pracujących na zmiany precyzyjne rekordy czasowe pomagają zidentyfikować wąskie gardła i ocenić efektywność operatorów o różnych porach doby.
HR: rejestracja czasu pracy i urlopy
Moduł obecności korzysta z Datetime, by zapisać godzinę przyjścia i wyjścia pracownika. Wnioski urlopowe również często muszą zawierać dokładny czas rozpoczęcia i zakończenia nieobecności. Wynagrodzenia i nadgodziny opierają się na precyzyjnych zapisach — brak lub przesunięcie znacznika czasu bezpośrednio wpływa na obliczenia płacowe, dlatego dokładność jest tu wymagana przez biznes, nie tylko przez dział IT.
Tworzenie i dostosowywanie pola Datetime
Są trzy główne sposoby dodania pola Datetime do modelu Odoo — wybór zależy od tego, czy wolisz rozwiązanie bezkodowe, czy zarządzane przez dewelopera.
Dodawanie przez Odoo Studio (bez kodu)
Odoo Studio to narzędzie do szybkich modyfikacji interfejsu, pozwalające dodać pole bez programowania. Kroki są proste i dostępne dla użytkowników biznesowych:
- Otwórz Odoo Studio z menu głównego.
- Przejdź do formularza, w którym chcesz dodać pole.
- Przeciągnij pole Date & Time z paska narzędzi na formularz.
- W panelu właściwości ustaw etykietę, wymagane/niewymagane i opcjonalnie wartość domyślną.
- Zapisz i zamknij Studio.
Studio automatycznie utworzy pole z prefiksem x_studio_ i doda je do widoku — nie musisz ręcznie wykonywać migracji bazy. To wygodne rozwiązanie, gdy trzeba szybko rozszerzyć formularz bez angażowania dewelopera.
Dodawanie przez Pythona w module (dla deweloperów)
Dla modyfikacji, które mają być wersjonowane i wdrażane w różnych środowiskach, pola definiujemy w plikach Pythona modułu. To podejście jest zalecane przy produkcyjnych rozszerzeniach:
from odoo import fields, models
class ResPartner(models.Model):
_inherit = 'res.partner'
x_last_contact_date = fields.Datetime(
string='Last Contact Date',
default=fields.Datetime.now,
copy=False,
)
Po zdefiniowaniu pola należy dodać odpowiedni zapis w XML widoku, aby pole było widoczne w interfejsie. Odoo podczas instalacji lub aktualizacji modułu sam stworzy kolumnę TIMESTAMP w bazie — ręczne SQL nie jest konieczne.
Tworzenie przez API XML-RPC
Jeżeli zarządzasz konfiguracją zdalnie lub automatyzujesz wdrożenia, możesz tworzyć pola przez API XML-RPC — to przydatne w skryptach konfiguracyjnych lub pipeline'ach wdrożeniowych:
field_id = models.execute_kw(
ODOO_DB, uid, ODOO_API_KEY,
'ir.model.fields', 'create',
[{
'name': 'x_last_contact_date',
'field_description': 'Last Contact Date',
'model_id': model_id,
'ttype': 'datetime',
'state': 'manual',
}]
)
Parametr ttype: datetime instruuje Odoo, by utworzyć pole Datetime. state: manual oznacza, że pole zostało dodane poza modułem — właściwe przy tworzeniu pól z poziomu Studio lub API. Takie podejście jest często stosowane w zautomatyzowanych konfiguracjach dla klientów.
Dobre praktyki
1. Używaj fields.Datetime.now jako referencji funkcji, nie jej wywołania
Przy ustawianiu wartości domyślnej używaj default=fields.Datetime.now bez nawiasów. Jeżeli dodasz nawiasy, funkcja zostanie wywołana raz przy ładowaniu klasy, a każdy nowy rekord utworzony w tym procesie dostanie tę samą, «zamrożoną» wartość — zamiast aktualnego czasu tworzenia rekordu.
2. Ustaw copy=False dla znaczników wydarzeń
Dla pól, które rejestrują faktyczne zdarzenia (np. data potwierdzenia), ustaw copy=False. Przy kopiowaniu rekordu nie chcesz przenosić oryginalnej daty potwierdzenia na kopię — to zniekształca historię i raporty.
3. Zawsze przesyłaj czasy w UTC przy zapisie przez API
Podczas zapisu przez XML-RPC przesyłaj wartości Datetime w UTC w formacie YYYY-MM-DD HH:MM:SS. API nie dokonuje automatycznej konwersji stref czasowych przy zapisie, więc podanie lokalnego czasu zostawi w bazie błędną wartość i będzie to trudne do zdiagnozowania później.
4. Stosuj readonly dla automatycznych znaczników czasu
Znaczniki systemowe powinny zwykle być tylko do odczytu w interfejsie, by użytkownicy nie mogli ich dowolnie modyfikować. Jeśli istnieje konieczność edycji, lepiej kontrolować to przez uprawnienia dostępu do pól, a nie pozostawiać pole otwarte do edycji wszystkim.
5. Wybierz Date, gdy czas nie jest istotny
Jeśli potrzebujesz tylko daty kalendarzowej (termin płatności, data ważności), użyj fields.Date. Datetime wprowadza niepotrzebne komplikacje związane ze strefami czasowymi i utrudnia utrzymanie prostoty modelu danych.
Częste pułapki
Zamieszanie ze strefami czasowymi przy odczycie surowych wartości
Najczęstszy problem: odczytując bezpośrednio z bazy lub przez API widzisz wartości w UTC, a nie w lokalnym czasie użytkownika. Raporty i integracje budowane na surowych danych często dają przesunięcia godzinowe. Zawsze konwertuj czas po stronie klienta przed prezentacją użytkownikowi i traktuj tę konwersję jako krok obowiązkowy w integracjach.
Zapis lokalnych czasów przez API
Jeśli wyślesz do API Datetime już w lokalnej strefie, Odoo zapisze ją jako UTC — bez korekty. Spotkanie ustawione na 15:00 czasu lokalnego zapisane jako 2026-01-01 15:00:00 może później być wyświetlone jako inna godzina w zależności od sezonowego czasu. To błąd, który ujawnia się dopiero przy rzeczywistym użytkowaniu w różnych strefach czasowych.
Użycie default=fields.Datetime.now() z nawiasami
Dodanie nawiasów do domyślnej funkcji to subtelna, ale poważna pomyłka. fields.Datetime.now() zostanie ocenione raz przy ładowaniu klasy, przez co wszystkie rekordy utworzone w tym procesie będą miały identyczny czas stworzenia. Taki błąd jest trudny do wykrycia, bo dane wyglądają na poprawne, ale analizy czasowe stają się bezwartościowe.
Zapominanie o copy=False przy znacznikach wydarzeń
Bez copy=False duplikaty rekordów odziedziczą wszystkie Datetime z oryginału. Data potwierdzenia czy czas rozpoczęcia produkcji zacierają się w nowych rekordach, co fałszuje historię i raporty. To drobne ustawienie, które jednak ma duży wpływ na jakość danych.
Używanie Datetime tam, gdzie wystarczy Date
Wybór Datetime do prostych dat (np. termin płatności) dodaje niepotrzebną złożoność: użytkownik widzi pole godziny, system wykonuje konwersje stref czasowych, a interfejs staje się mniej czytelny bez realnej korzyści. Zachowaj prostotę tam, gdzie to możliwe.
Podsumowanie
Pole Datetime to jedno z najbardziej użytecznych narzędzi w Odoo, gdy potrzebujesz precyzji. Od rejestracji otwarcia leada, przez czasy produkcji, po ewidencję obecności — znajduje zastosowanie w niemal każdym module.
Najważniejsza rzecz do zapamiętania to model przechowywania w UTC. Baza trzyma dane w UTC, a interfejs robi konwersję do strefy użytkownika. Większość błędów związanych ze strefami czasowymi w integracjach wynika z nieporozumień związanych z tym mechanizmem.
Poza tym stosowanie poprawnej składni dla domyślnych wartości, ustawienie copy=False tam, gdzie to konieczne, oraz wybieranie prostszego typu Date zamiast Datetime, gdy czas nie jest potrzebny, pomogą utrzymać model danych czytelnym i raporty wiarygodnymi.
W Dasolo wspieramy firmy we wdrażaniu, dostosowywaniu i optymalizacji Odoo w całej organizacji. Pomagamy zaprojektować solidny model danych, dodać odpowiednie pola do procesów lub stworzyć cały moduł od zera — działamy praktycznie na każdym etapie projektu. Skontaktuj się z nami Porozmawiajmy o Twoim projekcie Odoo.