Revised the calculation of "today" to use the client's timezone instead of the server's timezone.
This commit is contained in:
parent
6ee3ee76ea
commit
80ae4bd91c
@ -1,7 +1,7 @@
|
||||
# The Mia! Accounting Project.
|
||||
# Author: imacat@mail.imacat.idv.tw (imacat), 2023/2/18
|
||||
|
||||
# Copyright (c) 2023 imacat.
|
||||
# Copyright (c) 2023-2024 imacat.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
@ -33,6 +33,7 @@ from accounting.utils.flash_errors import flash_form_errors
|
||||
from accounting.utils.journal_entry_types import JournalEntryType
|
||||
from accounting.utils.next_uri import inherit_next, or_next
|
||||
from accounting.utils.permission import has_permission, can_view, can_edit
|
||||
from accounting.utils.timezone import get_tz_today
|
||||
from accounting.utils.user import get_current_user_pk
|
||||
from .forms import sort_journal_entries_in, JournalEntryReorderForm
|
||||
from .template_filters import with_type, to_transfer, format_amount_input, \
|
||||
@ -67,7 +68,7 @@ def show_add_journal_entry_form(journal_entry_type: JournalEntryType) -> str:
|
||||
form.validate()
|
||||
else:
|
||||
form = journal_entry_op.form()
|
||||
form.date.data = dt.date.today()
|
||||
form.date.data = get_tz_today()
|
||||
return journal_entry_op.render_create_template(form)
|
||||
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
# The Mia! Accounting Project.
|
||||
# Author: imacat@mail.imacat.idv.tw (imacat), 2023/3/4
|
||||
|
||||
# Copyright (c) 2023 imacat.
|
||||
# Copyright (c) 2023-2024 imacat.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
@ -24,6 +24,7 @@ import datetime as dt
|
||||
from collections.abc import Callable
|
||||
|
||||
from accounting.models import JournalEntry
|
||||
from accounting.utils.timezone import get_tz_today
|
||||
from .period import Period
|
||||
from .shortcuts import ThisMonth, LastMonth, SinceLastMonth, ThisYear, \
|
||||
LastYear, Today, Yesterday, AllTime, TemplatePeriod, YearPeriod
|
||||
@ -80,7 +81,7 @@ class PeriodChooser:
|
||||
"""The available years."""
|
||||
|
||||
if self.has_data:
|
||||
today: dt.date = dt.date.today()
|
||||
today: dt.date = get_tz_today()
|
||||
self.has_last_month = start < dt.date(today.year, today.month, 1)
|
||||
self.has_last_year = start.year < today.year
|
||||
self.has_yesterday = start < today
|
||||
|
@ -1,7 +1,7 @@
|
||||
# The Mia! Accounting Project.
|
||||
# Author: imacat@mail.imacat.idv.tw (imacat), 2023/3/4
|
||||
|
||||
# Copyright (c) 2023 imacat.
|
||||
# Copyright (c) 2023-2024 imacat.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
@ -20,6 +20,7 @@
|
||||
import datetime as dt
|
||||
|
||||
from accounting.locale import gettext
|
||||
from accounting.utils.timezone import get_tz_today
|
||||
from .month_end import month_end
|
||||
from .period import Period
|
||||
|
||||
@ -27,7 +28,7 @@ from .period import Period
|
||||
class ThisMonth(Period):
|
||||
"""The period of this month."""
|
||||
def __init__(self):
|
||||
today: dt.date = dt.date.today()
|
||||
today: dt.date = get_tz_today()
|
||||
this_month_start: dt.date = dt.date(today.year, today.month, 1)
|
||||
super().__init__(this_month_start, month_end(today))
|
||||
self.is_default = True
|
||||
@ -43,7 +44,7 @@ class ThisMonth(Period):
|
||||
class LastMonth(Period):
|
||||
"""The period of this month."""
|
||||
def __init__(self):
|
||||
today: dt.date = dt.date.today()
|
||||
today: dt.date = get_tz_today()
|
||||
year: int = today.year
|
||||
month: int = today.month - 1
|
||||
if month < 1:
|
||||
@ -63,7 +64,7 @@ class LastMonth(Period):
|
||||
class SinceLastMonth(Period):
|
||||
"""The period of this month."""
|
||||
def __init__(self):
|
||||
today: dt.date = dt.date.today()
|
||||
today: dt.date = get_tz_today()
|
||||
year: int = today.year
|
||||
month: int = today.month - 1
|
||||
if month < 1:
|
||||
@ -82,7 +83,7 @@ class SinceLastMonth(Period):
|
||||
class ThisYear(Period):
|
||||
"""The period of this year."""
|
||||
def __init__(self):
|
||||
year: int = dt.date.today().year
|
||||
year: int = get_tz_today().year
|
||||
start: dt.date = dt.date(year, 1, 1)
|
||||
end: dt.date = dt.date(year, 12, 31)
|
||||
super().__init__(start, end)
|
||||
@ -97,7 +98,7 @@ class ThisYear(Period):
|
||||
class LastYear(Period):
|
||||
"""The period of last year."""
|
||||
def __init__(self):
|
||||
year: int = dt.date.today().year
|
||||
year: int = get_tz_today().year
|
||||
start: dt.date = dt.date(year - 1, 1, 1)
|
||||
end: dt.date = dt.date(year - 1, 12, 31)
|
||||
super().__init__(start, end)
|
||||
@ -112,7 +113,7 @@ class LastYear(Period):
|
||||
class Today(Period):
|
||||
"""The period of today."""
|
||||
def __init__(self):
|
||||
today: dt.date = dt.date.today()
|
||||
today: dt.date = get_tz_today()
|
||||
super().__init__(today, today)
|
||||
self.is_today = True
|
||||
|
||||
@ -125,7 +126,7 @@ class Today(Period):
|
||||
class Yesterday(Period):
|
||||
"""The period of yesterday."""
|
||||
def __init__(self):
|
||||
yesterday: dt.date = dt.date.today() - dt.timedelta(days=1)
|
||||
yesterday: dt.date = get_tz_today() - dt.timedelta(days=1)
|
||||
super().__init__(yesterday, yesterday)
|
||||
self.is_yesterday = True
|
||||
|
||||
|
37
src/accounting/static/js/timezone.js
Normal file
37
src/accounting/static/js/timezone.js
Normal file
@ -0,0 +1,37 @@
|
||||
/* The Mia! Accounting Project
|
||||
* timezone.js: The JavaScript for the timezone
|
||||
*/
|
||||
|
||||
/* Copyright (c) 2024 imacat.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/* Author: imacat@mail.imacat.idv.tw (imacat)
|
||||
* First written: 2024/6/4
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
// Initializes the page JavaScript.
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
setTimeZone();
|
||||
});
|
||||
|
||||
/**
|
||||
* Sets the time zone.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
function setTimeZone() {
|
||||
document.cookie = `accounting-tz=${Intl.DateTimeFormat().resolvedOptions().timeZone}; SameSite=Strict`;
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
# The Mia! Accounting Project.
|
||||
# Author: imacat@mail.imacat.idv.tw (imacat), 2023/2/25
|
||||
|
||||
# Copyright (c) 2023 imacat.
|
||||
# Copyright (c) 2023-2024 imacat.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
@ -24,6 +24,7 @@ from typing import Any
|
||||
from flask_babel import get_locale
|
||||
|
||||
from accounting.locale import gettext
|
||||
from accounting.utils.timezone import get_tz_today
|
||||
|
||||
|
||||
def format_amount(value: Decimal | None) -> str | None:
|
||||
@ -47,7 +48,7 @@ def format_date(value: dt.date) -> str:
|
||||
:param value: The date.
|
||||
:return: The human-friendly date text.
|
||||
"""
|
||||
today: dt.date = dt.date.today()
|
||||
today: dt.date = get_tz_today()
|
||||
if value == today:
|
||||
return gettext("Today")
|
||||
if value == today - dt.timedelta(days=1):
|
||||
|
@ -2,7 +2,7 @@
|
||||
The Mia! Accounting Project
|
||||
base.html: The application-wide base template.
|
||||
|
||||
Copyright (c) 2023 imacat.
|
||||
Copyright (c) 2023-2024 imacat.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@ -27,5 +27,6 @@ First written: 2023/1/27
|
||||
|
||||
{% block scripts %}
|
||||
<script src="{{ url_for("accounting.babel_catalog") }}"></script>
|
||||
<script src="{{ url_for("accounting.static", filename="js/timezone.js") }}"></script>
|
||||
{% block accounting_scripts %}{% endblock %}
|
||||
{% endblock %}
|
||||
|
37
src/accounting/utils/timezone.py
Normal file
37
src/accounting/utils/timezone.py
Normal file
@ -0,0 +1,37 @@
|
||||
# The Mia! Accounting Project.
|
||||
# Author: imacat@mail.imacat.idv.tw (imacat), 2024/6/4
|
||||
|
||||
# Copyright (c) 2024 imacat.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
"""The timezone utility.
|
||||
|
||||
This module should not import any other module from the application.
|
||||
|
||||
"""
|
||||
|
||||
import datetime as dt
|
||||
|
||||
import pytz
|
||||
from flask import request
|
||||
|
||||
|
||||
def get_tz_today() -> dt.date:
|
||||
"""Returns today in the client timezone.
|
||||
|
||||
:return: today in the client timezone.
|
||||
"""
|
||||
tz_name: str | None = request.cookies.get("accounting-tz")
|
||||
if tz_name is None:
|
||||
return dt.date.today()
|
||||
return dt.datetime.now(tz=pytz.timezone(tz_name)).date()
|
@ -1,7 +1,7 @@
|
||||
# The Mia! Accounting Demonstration Website.
|
||||
# Author: imacat@mail.imacat.idv.tw (imacat), 2023/4/13
|
||||
|
||||
# Copyright (c) 2023 imacat.
|
||||
# Copyright (c) 2023-2024 imacat.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
@ -28,6 +28,7 @@ from typing import Any
|
||||
import sqlalchemy as sa
|
||||
from flask import Flask
|
||||
|
||||
from accounting.utils.timezone import get_tz_today
|
||||
from . import db
|
||||
from .auth import User
|
||||
|
||||
@ -44,6 +45,17 @@ class Accounts:
|
||||
MEAL: str = "6272-001"
|
||||
|
||||
|
||||
def get_today() -> dt.date:
|
||||
"""Returns today, based on the context.
|
||||
|
||||
:return: Today.
|
||||
"""
|
||||
try:
|
||||
return get_tz_today()
|
||||
except RuntimeError:
|
||||
return dt.date.today()
|
||||
|
||||
|
||||
class JournalEntryLineItemData:
|
||||
"""The journal entry line item data."""
|
||||
|
||||
@ -183,7 +195,7 @@ class JournalEntryData:
|
||||
:param is_update: True for an update operation, or False otherwise
|
||||
:return: The journal entry as a form.
|
||||
"""
|
||||
date: dt.date = dt.date.today() - dt.timedelta(days=self.days)
|
||||
date: dt.date = get_today() - dt.timedelta(days=self.days)
|
||||
form: dict[str, str] = {"csrf_token": csrf_token,
|
||||
"next": encoded_next_uri,
|
||||
"date": date.isoformat()}
|
||||
@ -260,8 +272,7 @@ class BaseTestData(ABC):
|
||||
existing_j_id: set[int] = {x["id"] for x in self.__journal_entries}
|
||||
existing_l_id: set[int] = {x["id"] for x in self.__line_items}
|
||||
journal_entry_data.id = self.__new_id(existing_j_id)
|
||||
date: dt.date \
|
||||
= dt.date.today() - dt.timedelta(days=journal_entry_data.days)
|
||||
date: dt.date = get_today() - dt.timedelta(days=journal_entry_data.days)
|
||||
self.__journal_entries.append(
|
||||
{"id": journal_entry_data.id,
|
||||
"date": date,
|
||||
|
@ -1,7 +1,7 @@
|
||||
# The Mia! Accounting Demonstration Website.
|
||||
# Author: imacat@mail.imacat.idv.tw (imacat), 2023/4/12
|
||||
|
||||
# Copyright (c) 2023 imacat.
|
||||
# Copyright (c) 2023-2024 imacat.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
@ -23,6 +23,7 @@ from flask import Flask, Blueprint, url_for, flash, redirect, session, \
|
||||
render_template, current_app
|
||||
from flask_babel import lazy_gettext
|
||||
|
||||
from accounting.utils.timezone import get_tz_today
|
||||
from . import db
|
||||
from .auth import admin_required
|
||||
from .lib import Accounts, JournalEntryLineItemData, JournalEntryData, \
|
||||
@ -117,7 +118,7 @@ class SampleData(BaseTestData):
|
||||
|
||||
:return: None.
|
||||
"""
|
||||
today: dt.date = dt.date.today()
|
||||
today: dt.date = get_tz_today()
|
||||
days: int
|
||||
year: int
|
||||
month: int
|
||||
@ -160,7 +161,7 @@ class SampleData(BaseTestData):
|
||||
|
||||
:return: None.
|
||||
"""
|
||||
today: dt.date = dt.date.today()
|
||||
today: dt.date = get_tz_today()
|
||||
|
||||
year: int = today.year - 5
|
||||
month: int = today.month
|
||||
|
Loading…
Reference in New Issue
Block a user