Make transaction.meter_end required and force tz utc for all datetimes

This commit is contained in:
Oliver Traber 2025-05-25 21:04:35 +00:00
parent 4272f2878e
commit 8e42205301
Signed by: Bluemedia
GPG key ID: C0674B105057136C
8 changed files with 32 additions and 10 deletions

View file

@ -12,7 +12,7 @@ class Transaction(Base):
started_at = Column(DateTime, index=True)
ended_at = Column(DateTime, nullable=True, index=True)
meter_start = Column(Numeric(10,2))
meter_end = Column(Numeric(10,2), nullable=True)
meter_end = Column(Numeric(10,2))
end_reason = Column(Enum(TransactionEventTriggerReason), nullable=True)
price = Column(Numeric(10,2))

View file

@ -3,6 +3,7 @@ from datetime import datetime
from pydantic import BaseModel
from app.schemas.user import Role
from app.util.encoders import force_utc_datetime
@dataclass
@ -19,3 +20,6 @@ class TokenResponse(BaseModel):
access_token: str
refresh_token: str
not_after: datetime
class Config:
json_encoders = {datetime: force_utc_datetime}

View file

@ -8,7 +8,7 @@ from app.schemas.connector import Connector
from ocpp.v201.enums import ResetEnumType, ResetStatusEnumType
from app.util.encoders import decimal_encoder
from app.util.encoders import decimal_encoder, force_utc_datetime
class ChargePointBase(BaseModel):
identity: str
@ -34,7 +34,7 @@ class ChargePoint(ChargePointBase):
class Config:
from_attributes = True
json_encoders = {Decimal: decimal_encoder}
json_encoders = {Decimal: decimal_encoder, datetime: force_utc_datetime}
class ChargePointThumb(BaseModel):
id: UUID

View file

@ -5,7 +5,7 @@ from typing import Optional
from uuid import UUID
from pydantic import BaseModel
from app.util.encoders import decimal_encoder
from app.util.encoders import decimal_encoder, force_utc_datetime
class PhaseType(enum.Enum):
L1 = "L1"
@ -57,4 +57,4 @@ class MeterValue(BaseModel):
class Config:
from_attributes = True
json_encoders = {Decimal: decimal_encoder}
json_encoders = {Decimal: decimal_encoder, datetime: force_utc_datetime}

View file

@ -2,6 +2,8 @@ from datetime import datetime
from uuid import UUID
from pydantic import BaseModel
from app.util.encoders import force_utc_datetime
class Session(BaseModel):
id: UUID
@ -9,4 +11,5 @@ class Session(BaseModel):
last_used: datetime
class Config:
from_attributes = True
from_attributes = True
json_encoders = {datetime: force_utc_datetime}

View file

@ -6,7 +6,7 @@ from pydantic import BaseModel
from app.schemas.chargepoint import ChargePointThumb
from app.schemas.user import UserThumb
from app.util.encoders import decimal_encoder
from app.util.encoders import decimal_encoder, force_utc_datetime
class TransactionStatus(enum.Enum):
ONGOING = "ongoing"
@ -45,7 +45,7 @@ class Transaction(BaseModel):
started_at: datetime
ended_at: Optional[datetime] = None
meter_start: Decimal
meter_end: Optional[Decimal] = None
meter_end: Decimal
end_reason: Optional[TransactionEventTriggerReason] = None
price: Decimal
user: UserThumb
@ -53,7 +53,7 @@ class Transaction(BaseModel):
class Config:
from_attributes = True
json_encoders = {Decimal: decimal_encoder}
json_encoders = {Decimal: decimal_encoder, datetime: force_utc_datetime}
class RemoteTransactionStartStopResponse(BaseModel):
status: RemoteTransactionStartStopStatus

View file

@ -21,19 +21,23 @@ async def create_transaction(
with SessionLocal() as db:
chargepoint = db.query(ChargePoint).filter(ChargePoint.identity == chargepoint_identity).first()
meter_start=0
meter_end=0
if "meter_value" in transaction_data.keys():
for meter_value_entry in transaction_data['meter_value']:
for sampled_value in meter_value_entry['sampled_value']:
if "measurand" in sampled_value.keys():
if sampled_value['measurand'] == str(Measurand.ENERGY_ACTIVE_IMPORT_REGISTER):
meter_start = sampled_value['value']
meter_end = sampled_value['value']
else:
meter_start = sampled_value['value']
meter_end = sampled_value['value']
transaction = Transaction(
id=transaction_info["transaction_id"],
status=TransactionStatus.ONGOING,
started_at=timestamp,
meter_start=meter_start,
meter_end=meter_end,
price=chargepoint.price,
chargepoint_id=chargepoint.id,
user_id=user_id
@ -55,6 +59,12 @@ async def update_transaction(
transaction_id=transaction.id,
meter_value_data=meter_value_entry
)
# Update current meter_end value
for sampled_value in meter_value_entry['sampled_value']:
if "measurand" in sampled_value.keys():
if sampled_value['measurand'] == str(Measurand.ENERGY_ACTIVE_IMPORT_REGISTER):
transaction.meter_end = sampled_value['value']
db.commit()
async def end_transaction(
transaction_id: str,

View file

@ -1,3 +1,4 @@
from datetime import datetime, timezone
from decimal import Decimal
from typing import Union
@ -19,4 +20,8 @@ def decimal_encoder(dec_value: Decimal) -> Union[int, float]:
if isinstance(exponent, int) and exponent >= 0:
return int(dec_value)
else:
return float(dec_value)
return float(dec_value)
def force_utc_datetime(datetime_value: datetime) -> datetime:
"""Force a datetime to be in the UTC timzone"""
return datetime_value.replace(tzinfo=timezone.utc)