From a81313447b0472ddd4b98697e17919248863e509 Mon Sep 17 00:00:00 2001 From: VivianDee <115420678+VivianDee@users.noreply.github.com> Date: Fri, 16 May 2025 13:40:33 +0100 Subject: [PATCH] [add]: timestamp fix --- app/models/account.py | 5 +- app/models/charge.py | 6 +- app/models/customer.py | 6 +- app/models/loan.py | 5 +- app/models/loan_charge.py | 6 +- app/models/loan_repayment_schedule.py | 6 +- app/models/offer.py | 6 +- app/models/rac_checks.py | 6 +- app/models/repayment.py | 5 +- app/models/transaction.py | 6 +- app/models/transaction_offers.py | 10 +- migrations/versions/2eee4157505f_.py | 250 ++++++++++++++++++++++++++ 12 files changed, 286 insertions(+), 31 deletions(-) create mode 100644 migrations/versions/2eee4157505f_.py diff --git a/app/models/account.py b/app/models/account.py index d136d58..1ee197d 100644 --- a/app/models/account.py +++ b/app/models/account.py @@ -2,6 +2,7 @@ from datetime import datetime, timezone from sqlalchemy.orm import relationship from app.extensions import db from sqlalchemy.exc import IntegrityError +from sqlalchemy.sql import func class Account(db.Model): __tablename__ = 'accounts' @@ -11,8 +12,8 @@ class Account(db.Model): account_type = db.Column(db.String(50)) status = db.Column(db.String(20), default='active') lien_amount = db.Column(db.Float, default=0.0) - created_at = db.Column(db.DateTime, default=datetime.now(timezone.utc)) - updated_at = db.Column(db.DateTime, default=datetime.now(timezone.utc), onupdate=datetime.now(timezone.utc)) + created_at = db.Column(db.DateTime(timezone=True), server_default=func.now()) + updated_at = db.Column(db.DateTime(timezone=True), onupdate=func.now()) customer = relationship( "Customer", diff --git a/app/models/charge.py b/app/models/charge.py index cd79824..17986b1 100644 --- a/app/models/charge.py +++ b/app/models/charge.py @@ -1,6 +1,7 @@ from datetime import datetime, timezone, timedelta from app.extensions import db from sqlalchemy.orm import relationship +from sqlalchemy.sql import func class Charge(db.Model): @@ -12,9 +13,8 @@ class Charge(db.Model): percent = db.Column(db.Float, default=0.0) description = db.Column(db.Text, nullable=True) due = db.Column(db.Integer, nullable=False) - created_at = db.Column(db.DateTime, default=datetime.now(timezone.utc)) - updated_at = db.Column(db.DateTime, default=datetime.now(timezone.utc), onupdate=datetime.now(timezone.utc)) - + created_at = db.Column(db.DateTime(timezone=True), server_default=func.now()) + updated_at = db.Column(db.DateTime(timezone=True), onupdate=func.now()) offer = relationship( "Offer", primaryjoin="Charge.offer_id == Offer.id", diff --git a/app/models/customer.py b/app/models/customer.py index 4b6382a..036712c 100644 --- a/app/models/customer.py +++ b/app/models/customer.py @@ -3,6 +3,7 @@ from sqlalchemy.orm import relationship from app.extensions import db from app.models.account import Account from sqlalchemy.exc import IntegrityError +from sqlalchemy.sql import func class Customer(db.Model): __tablename__ = 'customers' @@ -10,9 +11,8 @@ class Customer(db.Model): id = db.Column(db.String(50), primary_key=True) msisdn = db.Column(db.String(20), unique=True, nullable=False) country_code = db.Column(db.String(3), nullable=False) - created_at = db.Column(db.DateTime, default=datetime.now(timezone.utc)) - updated_at = db.Column(db.DateTime, default=datetime.now(timezone.utc), onupdate=datetime.now(timezone.utc)) - + created_at = db.Column(db.DateTime(timezone=True), server_default=func.now()) + updated_at = db.Column(db.DateTime(timezone=True), onupdate=func.now()) accounts = relationship( "Account", primaryjoin="Customer.id == Account.customer_id", diff --git a/app/models/loan.py b/app/models/loan.py index 2af5711..6a0b9ab 100644 --- a/app/models/loan.py +++ b/app/models/loan.py @@ -8,6 +8,7 @@ from dateutil.relativedelta import relativedelta from datetime import timedelta import logging from sqlalchemy import and_, or_, not_ +from sqlalchemy.sql import func logger = logging.getLogger(__name__) @@ -37,8 +38,8 @@ class Loan(db.Model): status = db.Column(db.String(20), default='pending') tenor = db.Column(db.Integer, nullable=True) due_date = db.Column(db.DateTime, nullable=True) - created_at = db.Column(db.DateTime, default=datetime.now(timezone.utc)) - updated_at = db.Column(db.DateTime, default=datetime.now(timezone.utc), onupdate=datetime.now(timezone.utc)) + created_at = db.Column(db.DateTime(timezone=True), server_default=func.now()) + updated_at = db.Column(db.DateTime(timezone=True), onupdate=func.now()) eligible_amount = db.Column(db.Float, nullable=True, default=0.0) disburse_date = db.Column(db.DateTime, nullable=True) disburse_verify = db.Column(db.DateTime, nullable=True) diff --git a/app/models/loan_charge.py b/app/models/loan_charge.py index 773d32b..36c451d 100644 --- a/app/models/loan_charge.py +++ b/app/models/loan_charge.py @@ -2,6 +2,7 @@ from datetime import datetime, timezone, timedelta from app.extensions import db from sqlalchemy.orm import relationship from app.utils.logger import logger +from sqlalchemy.sql import func class LoanCharge(db.Model): @@ -16,9 +17,8 @@ class LoanCharge(db.Model): description = db.Column(db.Text, nullable=True) due = db.Column(db.Integer, nullable=False) due_date = db.Column(db.DateTime, nullable=True) - created_at = db.Column(db.DateTime, default=datetime.now(timezone.utc)) - updated_at = db.Column(db.DateTime, default=datetime.now(timezone.utc), onupdate=datetime.now(timezone.utc)) - + created_at = db.Column(db.DateTime(timezone=True), server_default=func.now()) + updated_at = db.Column(db.DateTime(timezone=True), onupdate=func.now()) loan = relationship( "Loan", primaryjoin="LoanCharge.loan_id == Loan.id", diff --git a/app/models/loan_repayment_schedule.py b/app/models/loan_repayment_schedule.py index b9719aa..62aa952 100644 --- a/app/models/loan_repayment_schedule.py +++ b/app/models/loan_repayment_schedule.py @@ -2,6 +2,7 @@ from datetime import datetime, timezone from app.extensions import db from sqlalchemy.orm import relationship from dateutil.relativedelta import relativedelta +from sqlalchemy.sql import func class LoanRepaymentSchedule(db.Model): __tablename__ = 'loan_repayment_schedules' @@ -17,9 +18,8 @@ class LoanRepaymentSchedule(db.Model): paid = db.Column(db.Boolean, default=False) paid_at = db.Column(db.DateTime, nullable=True) - created_at = db.Column(db.DateTime, default=datetime.now(timezone.utc)) - updated_at = db.Column(db.DateTime, default=datetime.now(timezone.utc), onupdate=datetime.now(timezone.utc)) - + created_at = db.Column(db.DateTime(timezone=True), server_default=func.now()) + updated_at = db.Column(db.DateTime(timezone=True), onupdate=func.now()) loan = relationship( "Loan", primaryjoin="LoanRepaymentSchedule.loan_id == Loan.id", diff --git a/app/models/offer.py b/app/models/offer.py index c37d4aa..b5c0b70 100644 --- a/app/models/offer.py +++ b/app/models/offer.py @@ -2,6 +2,7 @@ from datetime import datetime, timezone from app.extensions import db from app.models.charge import Charge from sqlalchemy.orm import relationship +from sqlalchemy.sql import func class Offer(db.Model): __tablename__ = 'offers' @@ -17,9 +18,8 @@ class Offer(db.Model): insurance_rate = db.Column(db.Float, default=1.0) vat_rate = db.Column(db.Float, default=7.5) list_order = db.Column(db.Integer, nullable=True) - created_at = db.Column(db.DateTime, default=datetime.now(timezone.utc)) - updated_at = db.Column(db.DateTime, default=datetime.now(timezone.utc), onupdate=datetime.now(timezone.utc)) - + created_at = db.Column(db.DateTime(timezone=True), server_default=func.now()) + updated_at = db.Column(db.DateTime(timezone=True), onupdate=func.now()) charges = relationship( "Charge", primaryjoin="Offer.id == Charge.offer_id", diff --git a/app/models/rac_checks.py b/app/models/rac_checks.py index 88ec31c..dd6a6f1 100644 --- a/app/models/rac_checks.py +++ b/app/models/rac_checks.py @@ -4,6 +4,7 @@ from sqlalchemy.orm import relationship from sqlalchemy.exc import IntegrityError from uuid import uuid4 from sqlalchemy.types import JSON +from sqlalchemy.sql import func class RACCheck(db.Model): __tablename__ = 'rac_checks' @@ -13,9 +14,8 @@ class RACCheck(db.Model): customer_id = db.Column(db.String, nullable=False) account_id = db.Column(db.String, nullable=False) rac_response = db.Column(db.JSON, nullable=False) - created_at = db.Column(db.DateTime, default=datetime.now(timezone.utc)) - updated_at = db.Column(db.DateTime, default=datetime.now(timezone.utc), onupdate=datetime.now(timezone.utc)) - + created_at = db.Column(db.DateTime(timezone=True), server_default=func.now()) + updated_at = db.Column(db.DateTime(timezone=True), onupdate=func.now()) @classmethod def add_rac_check(cls, customer_id, account_id, transaction_id, data = None): diff --git a/app/models/repayment.py b/app/models/repayment.py index 3cc8451..f1faea4 100644 --- a/app/models/repayment.py +++ b/app/models/repayment.py @@ -4,6 +4,7 @@ from app.extensions import db from app.models.customer import Customer from app.models.loan import Loan from sqlalchemy.exc import IntegrityError +from sqlalchemy.sql import func class Repayment(db.Model): @@ -17,8 +18,8 @@ class Repayment(db.Model): loan_id = db.Column(db.String(50), nullable=False) customer_id = db.Column(db.String(50), nullable=False) product_id = db.Column(db.String(20), nullable=True) - created_at = db.Column(db.DateTime, default=datetime.now(timezone.utc)) - updated_at = db.Column(db.DateTime, default=datetime.now(timezone.utc), onupdate=datetime.now(timezone.utc)) + created_at = db.Column(db.DateTime(timezone=True), server_default=func.now()) + updated_at = db.Column(db.DateTime(timezone=True), onupdate=func.now()) transaction_id = db.Column(db.String(50), nullable=True) @classmethod diff --git a/app/models/transaction.py b/app/models/transaction.py index 27fa8ae..a772905 100644 --- a/app/models/transaction.py +++ b/app/models/transaction.py @@ -3,6 +3,7 @@ from app.extensions import db from app.models import account from sqlalchemy.exc import IntegrityError from sqlalchemy import and_, or_, not_ +from sqlalchemy.sql import func class Transaction(db.Model): __tablename__ = 'transactions' @@ -16,9 +17,8 @@ class Transaction(db.Model): customer_id = db.Column(db.String(50), nullable=True) type = db.Column(db.String(50), nullable=False) channel = db.Column(db.String(50), nullable=False) - created_at = db.Column(db.DateTime, default=datetime.now(timezone.utc)) - updated_at = db.Column(db.DateTime, default=datetime.now(timezone.utc), onupdate=datetime.now(timezone.utc)) - + created_at = db.Column(db.DateTime(timezone=True), server_default=func.now()) + updated_at = db.Column(db.DateTime(timezone=True), onupdate=func.now()) def __repr__(self): return f'' diff --git a/app/models/transaction_offers.py b/app/models/transaction_offers.py index feba03e..3c03c30 100644 --- a/app/models/transaction_offers.py +++ b/app/models/transaction_offers.py @@ -1,9 +1,12 @@ from datetime import datetime, timezone from app.extensions import db from sqlalchemy.orm import relationship +from sqlalchemy.sql import func import logging logger = logging.getLogger(__name__) + + class TransactionOffer(db.Model): __tablename__ = 'transaction_offers' @@ -18,9 +21,8 @@ class TransactionOffer(db.Model): eligible_amount = db.Column(db.Float, nullable=True) tenor = db.Column(db.Integer, nullable=True) # tenor in months, typically - created_at = db.Column(db.DateTime, default=datetime.now(timezone.utc)) - updated_at = db.Column(db.DateTime, default=datetime.now(timezone.utc), onupdate=datetime.now(timezone.utc)) - + created_at = db.Column(db.DateTime(timezone=True), server_default=func.now()) + updated_at = db.Column(db.DateTime(timezone=True), onupdate=func.now()) customer = relationship( "Customer", primaryjoin="Customer.id == TransactionOffer.customer_id", @@ -34,7 +36,7 @@ class TransactionOffer(db.Model): transaction_offer = cls.query.filter_by( id = transaction_offer, customer_id = customer_id, - # product_id = product_id + product_id = product_id # transaction_id = transaction_id, ).first() diff --git a/migrations/versions/2eee4157505f_.py b/migrations/versions/2eee4157505f_.py new file mode 100644 index 0000000..427b545 --- /dev/null +++ b/migrations/versions/2eee4157505f_.py @@ -0,0 +1,250 @@ +"""empty message + +Revision ID: 2eee4157505f +Revises: 565bc3d0ba6e +Create Date: 2025-05-16 13:24:41.914400 + +""" +from alembic import op +import sqlalchemy as sa +from sqlalchemy.dialects import postgresql + +# revision identifiers, used by Alembic. +revision = '2eee4157505f' +down_revision = '565bc3d0ba6e' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + with op.batch_alter_table('accounts', schema=None) as batch_op: + batch_op.alter_column('created_at', + existing_type=postgresql.TIMESTAMP(), + type_=sa.DateTime(timezone=True), + existing_nullable=True) + batch_op.alter_column('updated_at', + existing_type=postgresql.TIMESTAMP(), + type_=sa.DateTime(timezone=True), + existing_nullable=True) + + with op.batch_alter_table('charges', schema=None) as batch_op: + batch_op.alter_column('created_at', + existing_type=postgresql.TIMESTAMP(), + type_=sa.DateTime(timezone=True), + existing_nullable=True) + batch_op.alter_column('updated_at', + existing_type=postgresql.TIMESTAMP(), + type_=sa.DateTime(timezone=True), + existing_nullable=True) + + with op.batch_alter_table('customers', schema=None) as batch_op: + batch_op.alter_column('created_at', + existing_type=postgresql.TIMESTAMP(), + type_=sa.DateTime(timezone=True), + existing_nullable=True) + batch_op.alter_column('updated_at', + existing_type=postgresql.TIMESTAMP(), + type_=sa.DateTime(timezone=True), + existing_nullable=True) + + with op.batch_alter_table('loan_charges', schema=None) as batch_op: + batch_op.alter_column('created_at', + existing_type=postgresql.TIMESTAMP(), + type_=sa.DateTime(timezone=True), + existing_nullable=True) + batch_op.alter_column('updated_at', + existing_type=postgresql.TIMESTAMP(), + type_=sa.DateTime(timezone=True), + existing_nullable=True) + + with op.batch_alter_table('loan_repayment_schedules', schema=None) as batch_op: + batch_op.alter_column('created_at', + existing_type=postgresql.TIMESTAMP(), + type_=sa.DateTime(timezone=True), + existing_nullable=True) + batch_op.alter_column('updated_at', + existing_type=postgresql.TIMESTAMP(), + type_=sa.DateTime(timezone=True), + existing_nullable=True) + + with op.batch_alter_table('loans', schema=None) as batch_op: + batch_op.alter_column('created_at', + existing_type=postgresql.TIMESTAMP(), + type_=sa.DateTime(timezone=True), + existing_nullable=True) + batch_op.alter_column('updated_at', + existing_type=postgresql.TIMESTAMP(), + type_=sa.DateTime(timezone=True), + existing_nullable=True) + + with op.batch_alter_table('offers', schema=None) as batch_op: + batch_op.alter_column('created_at', + existing_type=postgresql.TIMESTAMP(), + type_=sa.DateTime(timezone=True), + existing_nullable=True) + batch_op.alter_column('updated_at', + existing_type=postgresql.TIMESTAMP(), + type_=sa.DateTime(timezone=True), + existing_nullable=True) + + with op.batch_alter_table('rac_checks', schema=None) as batch_op: + batch_op.alter_column('created_at', + existing_type=postgresql.TIMESTAMP(), + type_=sa.DateTime(timezone=True), + existing_nullable=True) + batch_op.alter_column('updated_at', + existing_type=postgresql.TIMESTAMP(), + type_=sa.DateTime(timezone=True), + existing_nullable=True) + + with op.batch_alter_table('repayments', schema=None) as batch_op: + batch_op.alter_column('created_at', + existing_type=postgresql.TIMESTAMP(), + type_=sa.DateTime(timezone=True), + existing_nullable=True) + batch_op.alter_column('updated_at', + existing_type=postgresql.TIMESTAMP(), + type_=sa.DateTime(timezone=True), + existing_nullable=True) + + with op.batch_alter_table('transaction_offers', schema=None) as batch_op: + batch_op.alter_column('created_at', + existing_type=postgresql.TIMESTAMP(), + type_=sa.DateTime(timezone=True), + existing_nullable=True) + batch_op.alter_column('updated_at', + existing_type=postgresql.TIMESTAMP(), + type_=sa.DateTime(timezone=True), + existing_nullable=True) + + with op.batch_alter_table('transactions', schema=None) as batch_op: + batch_op.alter_column('created_at', + existing_type=postgresql.TIMESTAMP(), + type_=sa.DateTime(timezone=True), + existing_nullable=True, + existing_server_default=sa.text('now()')) + batch_op.alter_column('updated_at', + existing_type=postgresql.TIMESTAMP(), + type_=sa.DateTime(timezone=True), + existing_nullable=True, + existing_server_default=sa.text('now()')) + + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + with op.batch_alter_table('transactions', schema=None) as batch_op: + batch_op.alter_column('updated_at', + existing_type=sa.DateTime(timezone=True), + type_=postgresql.TIMESTAMP(), + existing_nullable=True, + existing_server_default=sa.text('now()')) + batch_op.alter_column('created_at', + existing_type=sa.DateTime(timezone=True), + type_=postgresql.TIMESTAMP(), + existing_nullable=True, + existing_server_default=sa.text('now()')) + + with op.batch_alter_table('transaction_offers', schema=None) as batch_op: + batch_op.alter_column('updated_at', + existing_type=sa.DateTime(timezone=True), + type_=postgresql.TIMESTAMP(), + existing_nullable=True) + batch_op.alter_column('created_at', + existing_type=sa.DateTime(timezone=True), + type_=postgresql.TIMESTAMP(), + existing_nullable=True) + + with op.batch_alter_table('repayments', schema=None) as batch_op: + batch_op.alter_column('updated_at', + existing_type=sa.DateTime(timezone=True), + type_=postgresql.TIMESTAMP(), + existing_nullable=True) + batch_op.alter_column('created_at', + existing_type=sa.DateTime(timezone=True), + type_=postgresql.TIMESTAMP(), + existing_nullable=True) + + with op.batch_alter_table('rac_checks', schema=None) as batch_op: + batch_op.alter_column('updated_at', + existing_type=sa.DateTime(timezone=True), + type_=postgresql.TIMESTAMP(), + existing_nullable=True) + batch_op.alter_column('created_at', + existing_type=sa.DateTime(timezone=True), + type_=postgresql.TIMESTAMP(), + existing_nullable=True) + + with op.batch_alter_table('offers', schema=None) as batch_op: + batch_op.alter_column('updated_at', + existing_type=sa.DateTime(timezone=True), + type_=postgresql.TIMESTAMP(), + existing_nullable=True) + batch_op.alter_column('created_at', + existing_type=sa.DateTime(timezone=True), + type_=postgresql.TIMESTAMP(), + existing_nullable=True) + + with op.batch_alter_table('loans', schema=None) as batch_op: + batch_op.alter_column('updated_at', + existing_type=sa.DateTime(timezone=True), + type_=postgresql.TIMESTAMP(), + existing_nullable=True) + batch_op.alter_column('created_at', + existing_type=sa.DateTime(timezone=True), + type_=postgresql.TIMESTAMP(), + existing_nullable=True) + + with op.batch_alter_table('loan_repayment_schedules', schema=None) as batch_op: + batch_op.alter_column('updated_at', + existing_type=sa.DateTime(timezone=True), + type_=postgresql.TIMESTAMP(), + existing_nullable=True) + batch_op.alter_column('created_at', + existing_type=sa.DateTime(timezone=True), + type_=postgresql.TIMESTAMP(), + existing_nullable=True) + + with op.batch_alter_table('loan_charges', schema=None) as batch_op: + batch_op.alter_column('updated_at', + existing_type=sa.DateTime(timezone=True), + type_=postgresql.TIMESTAMP(), + existing_nullable=True) + batch_op.alter_column('created_at', + existing_type=sa.DateTime(timezone=True), + type_=postgresql.TIMESTAMP(), + existing_nullable=True) + + with op.batch_alter_table('customers', schema=None) as batch_op: + batch_op.alter_column('updated_at', + existing_type=sa.DateTime(timezone=True), + type_=postgresql.TIMESTAMP(), + existing_nullable=True) + batch_op.alter_column('created_at', + existing_type=sa.DateTime(timezone=True), + type_=postgresql.TIMESTAMP(), + existing_nullable=True) + + with op.batch_alter_table('charges', schema=None) as batch_op: + batch_op.alter_column('updated_at', + existing_type=sa.DateTime(timezone=True), + type_=postgresql.TIMESTAMP(), + existing_nullable=True) + batch_op.alter_column('created_at', + existing_type=sa.DateTime(timezone=True), + type_=postgresql.TIMESTAMP(), + existing_nullable=True) + + with op.batch_alter_table('accounts', schema=None) as batch_op: + batch_op.alter_column('updated_at', + existing_type=sa.DateTime(timezone=True), + type_=postgresql.TIMESTAMP(), + existing_nullable=True) + batch_op.alter_column('created_at', + existing_type=sa.DateTime(timezone=True), + type_=postgresql.TIMESTAMP(), + existing_nullable=True) + + # ### end Alembic commands ### -- 2.34.1