feat: drop timezone, assume UTC for all datetime values in DB

per changes in wuttjamaican
This commit is contained in:
Lance Edgar 2025-12-15 16:13:55 -06:00
parent 21c037dc25
commit d13f908da5
6 changed files with 545 additions and 18 deletions

View file

@ -33,7 +33,7 @@ license = {text = "GNU General Public License v3+"}
requires-python = ">= 3.8"
dependencies = [
"SQLAlchemy<2", # TODO: should allow 2.x
"WuttaWeb>=0.23.1",
"WuttaWeb>=0.24.0",
]
[project.optional-dependencies]

View file

@ -25,7 +25,6 @@ New Order Batch Handler
"""
# pylint: disable=too-many-lines
import datetime
import decimal
from collections import OrderedDict
@ -921,7 +920,7 @@ class NewOrderBatchHandler(BatchHandler): # pylint: disable=too-many-public-met
row.unit_price_quoted = None
row.case_price_quoted = None
if row.unit_price_sale is not None and (
not row.sale_ends or row.sale_ends > datetime.datetime.now()
not row.sale_ends or row.sale_ends > self.app.make_utc()
):
row.unit_price_quoted = row.unit_price_sale
else:

View file

@ -0,0 +1,531 @@
"""drop time zones
Revision ID: 9f2ff39f4743
Revises: fd8a2527bd30
Create Date: 2025-12-15 15:14:38.281566
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
import wuttjamaican.db.util
from sqlalchemy.dialects import postgresql
from wuttjamaican.util import make_utc
# revision identifiers, used by Alembic.
revision: str = "9f2ff39f4743"
down_revision: Union[str, None] = "fd8a2527bd30"
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
# sideshow_batch_neworder.created
op.add_column(
"sideshow_batch_neworder",
sa.Column("created_new", sa.DateTime(), nullable=True),
)
sideshow_batch_neworder = sa.sql.table(
"sideshow_batch_neworder",
sa.sql.column("uuid"),
sa.sql.column("created"),
sa.sql.column("created_new"),
)
cursor = op.get_bind().execute(sideshow_batch_neworder.select())
for row in cursor.fetchall():
op.get_bind().execute(
sideshow_batch_neworder.update()
.where(sideshow_batch_neworder.c.uuid == row.uuid)
.values({"created_new": make_utc(row.created)})
)
op.drop_column("sideshow_batch_neworder", "created")
op.alter_column(
"sideshow_batch_neworder",
"created_new",
new_column_name="created",
nullable=False,
existing_type=sa.DateTime(),
existing_nullable=True,
)
# sideshow_batch_neworder.executed
op.add_column(
"sideshow_batch_neworder",
sa.Column("executed_new", sa.DateTime(), nullable=True),
)
sideshow_batch_neworder = sa.sql.table(
"sideshow_batch_neworder",
sa.sql.column("uuid"),
sa.sql.column("executed"),
sa.sql.column("executed_new"),
)
cursor = op.get_bind().execute(sideshow_batch_neworder.select())
for row in cursor.fetchall():
if row.executed:
op.get_bind().execute(
sideshow_batch_neworder.update()
.where(sideshow_batch_neworder.c.uuid == row.uuid)
.values({"executed_new": make_utc(row.executed)})
)
op.drop_column("sideshow_batch_neworder", "executed")
op.alter_column(
"sideshow_batch_neworder",
"executed_new",
new_column_name="executed",
existing_type=sa.DateTime(),
existing_nullable=True,
)
# sideshow_batch_neworder_row.modified
op.add_column(
"sideshow_batch_neworder_row",
sa.Column("modified_new", sa.DateTime(), nullable=True),
)
sideshow_batch_neworder_row = sa.sql.table(
"sideshow_batch_neworder_row",
sa.sql.column("uuid"),
sa.sql.column("modified"),
sa.sql.column("modified_new"),
)
cursor = op.get_bind().execute(sideshow_batch_neworder_row.select())
for row in cursor.fetchall():
if row.modified:
op.get_bind().execute(
sideshow_batch_neworder_row.update()
.where(sideshow_batch_neworder_row.c.uuid == row.uuid)
.values({"modified_new": make_utc(row.modified)})
)
op.drop_column("sideshow_batch_neworder_row", "modified")
op.alter_column(
"sideshow_batch_neworder_row",
"modified_new",
new_column_name="modified",
existing_type=sa.DateTime(),
existing_nullable=True,
)
# sideshow_batch_neworder_row.sale_ends
op.add_column(
"sideshow_batch_neworder_row",
sa.Column("sale_ends_new", sa.DateTime(), nullable=True),
)
sideshow_batch_neworder_row = sa.sql.table(
"sideshow_batch_neworder_row",
sa.sql.column("uuid"),
sa.sql.column("sale_ends"),
sa.sql.column("sale_ends_new"),
)
cursor = op.get_bind().execute(sideshow_batch_neworder_row.select())
for row in cursor.fetchall():
if row.sale_ends:
op.get_bind().execute(
sideshow_batch_neworder_row.update()
.where(sideshow_batch_neworder_row.c.uuid == row.uuid)
.values({"sale_ends_new": make_utc(row.sale_ends)})
)
op.drop_column("sideshow_batch_neworder_row", "sale_ends")
op.alter_column(
"sideshow_batch_neworder_row",
"sale_ends_new",
new_column_name="sale_ends",
existing_type=sa.DateTime(),
existing_nullable=True,
)
# sideshow_customer_pending.created
op.add_column(
"sideshow_customer_pending",
sa.Column("created_new", sa.DateTime(), nullable=True),
)
sideshow_customer_pending = sa.sql.table(
"sideshow_customer_pending",
sa.sql.column("uuid"),
sa.sql.column("created"),
sa.sql.column("created_new"),
)
cursor = op.get_bind().execute(sideshow_customer_pending.select())
for row in cursor.fetchall():
op.get_bind().execute(
sideshow_customer_pending.update()
.where(sideshow_customer_pending.c.uuid == row.uuid)
.values({"created_new": make_utc(row.created)})
)
op.drop_column("sideshow_customer_pending", "created")
op.alter_column(
"sideshow_customer_pending",
"created_new",
new_column_name="created",
nullable=False,
existing_type=sa.DateTime(),
existing_nullable=True,
)
# sideshow_order.created
op.add_column(
"sideshow_order",
sa.Column("created_new", sa.DateTime(), nullable=True),
)
sideshow_order = sa.sql.table(
"sideshow_order",
sa.sql.column("uuid"),
sa.sql.column("created"),
sa.sql.column("created_new"),
)
cursor = op.get_bind().execute(sideshow_order.select())
for row in cursor.fetchall():
op.get_bind().execute(
sideshow_order.update()
.where(sideshow_order.c.uuid == row.uuid)
.values({"created_new": make_utc(row.created)})
)
op.drop_column("sideshow_order", "created")
op.alter_column(
"sideshow_order",
"created_new",
new_column_name="created",
nullable=False,
existing_type=sa.DateTime(),
existing_nullable=True,
)
# sideshow_order_item.sale_ends
op.add_column(
"sideshow_order_item",
sa.Column("sale_ends_new", sa.DateTime(), nullable=True),
)
sideshow_order_item = sa.sql.table(
"sideshow_order_item",
sa.sql.column("uuid"),
sa.sql.column("sale_ends"),
sa.sql.column("sale_ends_new"),
)
cursor = op.get_bind().execute(sideshow_order_item.select())
for row in cursor.fetchall():
if row.sale_ends:
op.get_bind().execute(
sideshow_order_item.update()
.where(sideshow_order_item.c.uuid == row.uuid)
.values({"sale_ends_new": make_utc(row.sale_ends)})
)
op.drop_column("sideshow_order_item", "sale_ends")
op.alter_column(
"sideshow_order_item",
"sale_ends_new",
new_column_name="sale_ends",
existing_type=sa.DateTime(),
existing_nullable=True,
)
# sideshow_order_item_event.occurred
op.add_column(
"sideshow_order_item_event",
sa.Column("occurred_new", sa.DateTime(), nullable=True),
)
sideshow_order_item_event = sa.sql.table(
"sideshow_order_item_event",
sa.sql.column("uuid"),
sa.sql.column("occurred"),
sa.sql.column("occurred_new"),
)
cursor = op.get_bind().execute(sideshow_order_item_event.select())
for row in cursor.fetchall():
op.get_bind().execute(
sideshow_order_item_event.update()
.where(sideshow_order_item_event.c.uuid == row.uuid)
.values({"occurred_new": make_utc(row.occurred)})
)
op.drop_column("sideshow_order_item_event", "occurred")
op.alter_column(
"sideshow_order_item_event",
"occurred_new",
new_column_name="occurred",
nullable=False,
existing_type=sa.DateTime(),
existing_nullable=True,
)
# sideshow_product_pending.created
op.add_column(
"sideshow_product_pending",
sa.Column("created_new", sa.DateTime(), nullable=True),
)
sideshow_product_pending = sa.sql.table(
"sideshow_product_pending",
sa.sql.column("uuid"),
sa.sql.column("created"),
sa.sql.column("created_new"),
)
cursor = op.get_bind().execute(sideshow_product_pending.select())
for row in cursor.fetchall():
op.get_bind().execute(
sideshow_product_pending.update()
.where(sideshow_product_pending.c.uuid == row.uuid)
.values({"created_new": make_utc(row.created)})
)
op.drop_column("sideshow_product_pending", "created")
op.alter_column(
"sideshow_product_pending",
"created_new",
new_column_name="created",
nullable=False,
existing_type=sa.DateTime(),
existing_nullable=True,
)
def downgrade() -> None:
# sideshow_product_pending.created
op.add_column(
"sideshow_product_pending",
sa.Column("created_old", sa.DateTime(timezone=True), nullable=True),
)
sideshow_product_pending = sa.sql.table(
"sideshow_product_pending",
sa.sql.column("uuid"),
sa.sql.column("created"),
sa.sql.column("created_old"),
)
cursor = op.get_bind().execute(sideshow_product_pending.select())
for row in cursor.fetchall():
op.get_bind().execute(
sideshow_product_pending.update()
.where(sideshow_product_pending.c.uuid == row.uuid)
.values({"created_old": row.created})
)
op.drop_column("sideshow_product_pending", "created")
op.alter_column(
"sideshow_product_pending",
"created_old",
new_column_name="created",
nullable=False,
existing_type=sa.DateTime(timezone=True),
existing_nullable=True,
)
# sideshow_order_item_event.occurred
op.add_column(
"sideshow_order_item_event",
sa.Column("occurred_old", sa.DateTime(timezone=True), nullable=True),
)
sideshow_order_item_event = sa.sql.table(
"sideshow_order_item_event",
sa.sql.column("uuid"),
sa.sql.column("occurred"),
sa.sql.column("occurred_old"),
)
cursor = op.get_bind().execute(sideshow_order_item_event.select())
for row in cursor.fetchall():
op.get_bind().execute(
sideshow_order_item_event.update()
.where(sideshow_order_item_event.c.uuid == row.uuid)
.values({"occurred_old": row.occurred})
)
op.drop_column("sideshow_order_item_event", "occurred")
op.alter_column(
"sideshow_order_item_event",
"occurred_old",
new_column_name="occurred",
nullable=False,
existing_type=sa.DateTime(timezone=True),
existing_nullable=True,
)
# sideshow_order_item.sale_ends
op.add_column(
"sideshow_order_item",
sa.Column("sale_ends_old", sa.DateTime(timezone=True), nullable=True),
)
sideshow_order_item = sa.sql.table(
"sideshow_order_item",
sa.sql.column("uuid"),
sa.sql.column("sale_ends"),
sa.sql.column("sale_ends_old"),
)
cursor = op.get_bind().execute(sideshow_order_item.select())
for row in cursor.fetchall():
if row.sale_ends:
op.get_bind().execute(
sideshow_order_item.update()
.where(sideshow_order_item.c.uuid == row.uuid)
.values({"sale_ends_old": row.sale_ends})
)
op.drop_column("sideshow_order_item", "sale_ends")
op.alter_column(
"sideshow_order_item",
"sale_ends_old",
new_column_name="sale_ends",
existing_type=sa.DateTime(timezone=True),
existing_nullable=True,
)
# sideshow_order.created
op.add_column(
"sideshow_order",
sa.Column("created_old", sa.DateTime(timezone=True), nullable=True),
)
sideshow_order = sa.sql.table(
"sideshow_order",
sa.sql.column("uuid"),
sa.sql.column("created"),
sa.sql.column("created_old"),
)
cursor = op.get_bind().execute(sideshow_order.select())
for row in cursor.fetchall():
op.get_bind().execute(
sideshow_order.update()
.where(sideshow_order.c.uuid == row.uuid)
.values({"created_old": row.created})
)
op.drop_column("sideshow_order", "created")
op.alter_column(
"sideshow_order",
"created_old",
new_column_name="created",
nullable=False,
existing_type=sa.DateTime(timezone=True),
existing_nullable=True,
)
# sideshow_customer_pending.created
op.add_column(
"sideshow_customer_pending",
sa.Column("created_old", sa.DateTime(timezone=True), nullable=True),
)
sideshow_customer_pending = sa.sql.table(
"sideshow_customer_pending",
sa.sql.column("uuid"),
sa.sql.column("created"),
sa.sql.column("created_old"),
)
cursor = op.get_bind().execute(sideshow_customer_pending.select())
for row in cursor.fetchall():
op.get_bind().execute(
sideshow_customer_pending.update()
.where(sideshow_customer_pending.c.uuid == row.uuid)
.values({"created_old": row.created})
)
op.drop_column("sideshow_customer_pending", "created")
op.alter_column(
"sideshow_customer_pending",
"created_old",
new_column_name="created",
nullable=False,
existing_type=sa.DateTime(timezone=True),
existing_nullable=True,
)
# sideshow_batch_neworder_row.sale_ends
op.add_column(
"sideshow_batch_neworder_row",
sa.Column("sale_ends_old", sa.DateTime(timezone=True), nullable=True),
)
sideshow_batch_neworder_row = sa.sql.table(
"sideshow_batch_neworder_row",
sa.sql.column("uuid"),
sa.sql.column("sale_ends"),
sa.sql.column("sale_ends_old"),
)
cursor = op.get_bind().execute(sideshow_batch_neworder_row.select())
for row in cursor.fetchall():
if row.sale_ends:
op.get_bind().execute(
sideshow_batch_neworder_row.update()
.where(sideshow_batch_neworder_row.c.uuid == row.uuid)
.values({"sale_ends_old": row.sale_ends})
)
op.drop_column("sideshow_batch_neworder_row", "sale_ends")
op.alter_column(
"sideshow_batch_neworder_row",
"sale_ends_old",
new_column_name="sale_ends",
existing_type=sa.DateTime(timezone=True),
existing_nullable=True,
)
# sideshow_batch_neworder_row.modified
op.add_column(
"sideshow_batch_neworder_row",
sa.Column("modified_old", sa.DateTime(timezone=True), nullable=True),
)
sideshow_batch_neworder_row = sa.sql.table(
"sideshow_batch_neworder_row",
sa.sql.column("uuid"),
sa.sql.column("modified"),
sa.sql.column("modified_old"),
)
cursor = op.get_bind().execute(sideshow_batch_neworder_row.select())
for row in cursor.fetchall():
if row.modified:
op.get_bind().execute(
sideshow_batch_neworder_row.update()
.where(sideshow_batch_neworder_row.c.uuid == row.uuid)
.values({"modified_old": row.modified})
)
op.drop_column("sideshow_batch_neworder_row", "modified")
op.alter_column(
"sideshow_batch_neworder_row",
"modified_old",
new_column_name="modified",
existing_type=sa.DateTime(timezone=True),
existing_nullable=True,
)
# sideshow_batch_neworder.executed
op.add_column(
"sideshow_batch_neworder",
sa.Column("executed_old", sa.DateTime(timezone=True), nullable=True),
)
sideshow_batch_neworder = sa.sql.table(
"sideshow_batch_neworder",
sa.sql.column("uuid"),
sa.sql.column("executed"),
sa.sql.column("executed_old"),
)
cursor = op.get_bind().execute(sideshow_batch_neworder.select())
for row in cursor.fetchall():
if row.executed:
op.get_bind().execute(
sideshow_batch_neworder.update()
.where(sideshow_batch_neworder.c.uuid == row.uuid)
.values({"executed_old": row.executed})
)
op.drop_column("sideshow_batch_neworder", "executed")
op.alter_column(
"sideshow_batch_neworder",
"executed_old",
new_column_name="executed",
existing_type=sa.DateTime(timezone=True),
existing_nullable=True,
)
# sideshow_batch_neworder.created
op.add_column(
"sideshow_batch_neworder",
sa.Column("created_old", sa.DateTime(timezone=True), nullable=True),
)
sideshow_batch_neworder = sa.sql.table(
"sideshow_batch_neworder",
sa.sql.column("uuid"),
sa.sql.column("created"),
sa.sql.column("created_old"),
)
cursor = op.get_bind().execute(sideshow_batch_neworder.select())
for row in cursor.fetchall():
op.get_bind().execute(
sideshow_batch_neworder.update()
.where(sideshow_batch_neworder.c.uuid == row.uuid)
.values({"created_old": row.created})
)
op.drop_column("sideshow_batch_neworder", "created")
op.alter_column(
"sideshow_batch_neworder",
"created_old",
new_column_name="created",
nullable=False,
existing_type=sa.DateTime(timezone=True),
existing_nullable=True,
)

View file

@ -24,12 +24,11 @@
Data models for Customers
"""
import datetime
import sqlalchemy as sa
from sqlalchemy import orm
from wuttjamaican.db import model
from wuttjamaican.util import make_utc
from sideshow.enum import PendingCustomerStatus
@ -175,9 +174,9 @@ class PendingCustomer( # pylint: disable=too-few-public-methods
)
created = sa.Column(
sa.DateTime(timezone=True),
sa.DateTime(),
nullable=False,
default=datetime.datetime.now,
default=make_utc,
doc="""
Timestamp when the customer record was created.
""",

View file

@ -24,13 +24,12 @@
Data models for Orders
"""
import datetime
import sqlalchemy as sa
from sqlalchemy import orm
from sqlalchemy.ext.orderinglist import ordering_list
from wuttjamaican.db import model
from wuttjamaican.util import make_utc
class OrderMixin: # pylint: disable=too-few-public-methods
@ -266,7 +265,7 @@ class OrderItemMixin: # pylint: disable=too-few-public-methods
)
sale_ends = sa.Column(
sa.DateTime(timezone=True),
sa.DateTime(),
nullable=True,
doc="""
End date/time for the sale in effect, if any.
@ -403,9 +402,9 @@ class Order( # pylint: disable=too-few-public-methods,duplicate-code
)
created = sa.Column(
sa.DateTime(timezone=True),
sa.DateTime(),
nullable=False,
default=datetime.datetime.now,
default=make_utc,
doc="""
Timestamp when the order was created.
@ -596,9 +595,9 @@ class OrderItemEvent(model.Base): # pylint: disable=too-few-public-methods
)
occurred = sa.Column(
sa.DateTime(timezone=True),
sa.DateTime(),
nullable=False,
default=datetime.datetime.now,
default=make_utc,
doc="""
Date and time when the event occurred.
""",

View file

@ -24,12 +24,11 @@
Data models for Products
"""
import datetime
import sqlalchemy as sa
from sqlalchemy import orm
from wuttjamaican.db import model
from wuttjamaican.util import make_utc
from sideshow.enum import PendingProductStatus
@ -265,9 +264,9 @@ class PendingProduct( # pylint: disable=too-few-public-methods
)
created = sa.Column(
sa.DateTime(timezone=True),
sa.DateTime(),
nullable=False,
default=datetime.datetime.now,
default=make_utc,
doc="""
Timestamp when the product record was created.
""",