Skip to content

Commit

Permalink
21537 - Shortname Refunds - PATCH / GET methods & Notification (#1758)
Browse files Browse the repository at this point in the history
  • Loading branch information
seeker25 authored Sep 27, 2024
1 parent 902fd6e commit ac82a1c
Show file tree
Hide file tree
Showing 47 changed files with 912 additions and 489 deletions.
45 changes: 45 additions & 0 deletions pay-api/migrations/versions/2024_09_20_75a39e02c746_.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
"""Fix audit columns for eft_refunds.
Revision ID: 75a39e02c746
Revises: 29f59e6f147b
Create Date: 2024-09-20 13:45:35.132557
"""
from alembic import op
import sqlalchemy as sa

# revision identifiers, used by Alembic.
# Note you may see foreign keys with distribution_codes_history
# For disbursement_distribution_code_id, service_fee_distribution_code_id
# Please ignore those lines and don't include in migration.

revision = '75a39e02c746'
down_revision = '29f59e6f147b'
branch_labels = None
depends_on = None


def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('eft_refunds', schema=None) as batch_op:
batch_op.add_column(sa.Column('created_name', sa.String(length=100), nullable=True))
batch_op.add_column(sa.Column('updated_name', sa.String(length=50), nullable=True))
batch_op.alter_column('updated_by',
existing_type=sa.VARCHAR(length=100),
type_=sa.String(length=50),
existing_nullable=True)
batch_op.drop_column('updated_by_name')
# ### end Alembic commands ###


def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('eft_refunds', schema=None) as batch_op:
batch_op.add_column(sa.Column('updated_by_name', sa.VARCHAR(length=100), autoincrement=False, nullable=True))
batch_op.alter_column('updated_by',
existing_type=sa.String(length=50),
type_=sa.VARCHAR(length=100),
existing_nullable=True)
batch_op.drop_column('updated_name')
batch_op.drop_column('created_name')
# ### end Alembic commands ###
28 changes: 28 additions & 0 deletions pay-api/migrations/versions/2024_09_24_87a09ba91c0d_.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
"""Drop refund email list, use keycloak instead.
Revision ID: 87a09ba91c0d
Revises: 75a39e02c746
Create Date: 2024-09-24 14:01:25.238895
"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import postgresql

# revision identifiers, used by Alembic.
# Note you may see foreign keys with distribution_codes_history
# For disbursement_distribution_code_id, service_fee_distribution_code_id
# Please ignore those lines and don't include in migration.

revision = '87a09ba91c0d'
down_revision = '75a39e02c746'
branch_labels = None
depends_on = None


def upgrade():
op.execute('DROP SEQUENCE IF EXISTS eft_refund_email_list_id_seq CASCADE')
op.execute('DROP TABLE IF EXISTS eft_refund_email_list')

def downgrade():
pass
1 change: 1 addition & 0 deletions pay-api/setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ notes=FIXME,XXX,TODO
ignored-modules=flask_sqlalchemy,sqlalchemy,SQLAlchemy,alembic,scoped_session
ignored-classes=scoped_session
min-similarity-lines=15
max-attributes=15
disable=C0301,W0511,R0903
good-names=
b,
Expand Down
1 change: 1 addition & 0 deletions pay-api/src/pay_api/dtos/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""Init."""
78 changes: 78 additions & 0 deletions pay-api/src/pay_api/dtos/eft_shortname.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
"""Rationale behind creating these DTOS below.
1. To ensure that the request and response payloads are validated before they are passed to the service layer.
2. To ensure that the request and response payloads are consistent across the application.
3. To ensure that the request and response payloads are consistent with the API documentation.
In the near future, will find a library that generates our API spec based off of these DTOs.
"""
from decimal import Decimal
from typing import List
from attrs import define

from pay_api.utils.serializable import Serializable


@define
class EFTShortNameGetRequest(Serializable):
"""EFT Short name search."""

short_name: str = None
short_name_id: int = None
short_name_type: str = None
amount_owing: Decimal = None
statement_id: int = None
state: str = None
page: int = 1
limit: int = 10
account_id: int = None
account_name: str = None
account_branch: str = None
account_id_list: str = None

@classmethod
def from_dict(cls, data: dict):
"""Convert from request args to EFTShortNameSearchDTO."""
dto = super().from_dict(data)
# In the future, we'll need a cleaner way to handle this.
dto.state = dto.state.split(',') if dto.state else None
dto.account_id_list = dto.account_id_list.split(',') if dto.account_id_list else None
return dto


@define
class EFTShortNameSummaryGetRequest(Serializable):
"""EFT Short name summary search."""

short_name: str = None
short_name_id: int = None
short_name_type: str = None
credits_remaining: Decimal = None
linked_accounts_count: int = None
payment_received_start_date: str = None
payment_received_end_date: str = None
page: int = 1
limit: int = 10


@define
class EFTShortNameRefundPatchRequest(Serializable):
"""EFT Short name refund DTO."""

comment: str
status: str
decline_reason: str = None


@define
class EFTShortNameRefundGetRequest:
"""EFT Short name refund DTO."""

statuses: List[str]

@classmethod
def from_dict(cls, data: dict):
"""Convert from request json to EFTShortNameRefundDTO."""
input_string = data.get('status', '')
statuses = input_string.split(',') if input_string else []
return EFTShortNameRefundGetRequest(statuses=statuses)
9 changes: 4 additions & 5 deletions pay-api/src/pay_api/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@
from .eft_credit_invoice_link import EFTCreditInvoiceLink
from .eft_file import EFTFile
from .eft_process_status_code import EFTProcessStatusCode
from .eft_short_names import EFTShortnames, EFTShortnameSchema, EFTShortnameSummarySchema
from .eft_short_names_historical import EFTShortnamesHistorical
from .eft_refund import EFTRefund
from .eft_short_name_links import EFTShortnameLinks, EFTShortnameLinkSchema
from .eft_short_names import EFTShortnames, EFTShortnameSchema, EFTShortnameSummarySchema
from .eft_short_names_historical import EFTShortnameHistorySchema, EFTShortnamesHistorical
from .eft_transaction import EFTTransaction, EFTTransactionSchema
from .ejv_file import EjvFile
from .ejv_header import EjvHeader
Expand All @@ -61,13 +61,12 @@
from .refunds_partial import RefundPartialLine, RefundsPartial
from .routing_slip import RoutingSlip, RoutingSlipSchema
from .routing_slip_status_code import RoutingSlipStatusCode, RoutingSlipStatusCodeSchema
from .statement import StatementDTO, Statement, StatementSchema
from .statement import Statement, StatementDTO, StatementSchema
from .statement_invoices import StatementInvoices, StatementInvoicesSchema # noqa: I005
from .statement_recipients import StatementRecipients, StatementRecipientsSchema
from .statement_settings import StatementSettings, StatementSettingsSchema
from .transaction_status_code import TransactionStatusCode, TransactionStatusCodeSchema
from .comment import Comment, CommentSchema
from .eft_refund_email_list import EFTRefundEmailList
from .comment import Comment, CommentSchema # This has to be at the bottom otherwise FeeSchedule errors


event.listen(Engine, 'before_cursor_execute', DBTracing.query_tracing)
5 changes: 5 additions & 0 deletions pay-api/src/pay_api/models/base_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ def delete(self):
db.session.delete(self)
db.session.commit()

def to_dict(self):
"""Quick and easy way to convert to a dict."""
# We need a better way to do this in the future.
return {c.name: str(getattr(self, c.name)) for c in self.__table__.columns if getattr(self, c.name) is not None}

@staticmethod
def rollback():
"""RollBack."""
Expand Down
2 changes: 1 addition & 1 deletion pay-api/src/pay_api/models/cfs_account.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
from .db import db


class CfsAccount(Versioned, BaseModel): # pylint:disable=too-many-instance-attributes
class CfsAccount(Versioned, BaseModel):
"""This class manages all of the base data about PayBC Account."""

__tablename__ = 'cfs_accounts'
Expand Down
2 changes: 1 addition & 1 deletion pay-api/src/pay_api/models/credit.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
from .db import db, ma


class Credit(BaseModel): # pylint:disable=too-many-instance-attributes
class Credit(BaseModel):
"""This class manages all of the base data about Credit."""

__tablename__ = 'credits'
Expand Down
2 changes: 1 addition & 1 deletion pay-api/src/pay_api/models/distribution_code.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ def bulk_save_links(cls, links: list):
BaseModel.commit()


class DistributionCode(Audit, Versioned, BaseModel): # pylint:disable=too-many-instance-attributes
class DistributionCode(Audit, Versioned, BaseModel):
"""This class manages all of the base data about distribution code.
Distribution code holds details on the codes for how the collected payment is going to be distributed.
Expand Down
7 changes: 4 additions & 3 deletions pay-api/src/pay_api/models/eft_credit.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
from .db import db


class EFTCredit(BaseModel): # pylint:disable=too-many-instance-attributes
class EFTCredit(BaseModel):
"""This class manages all of the base data for EFT credits."""

__tablename__ = 'eft_credits'
Expand Down Expand Up @@ -75,10 +75,11 @@ def get_eft_credit_balance(cls, short_name_id: int) -> Decimal:
return Decimal(result.credit_balance) if result else 0

@classmethod
def get_eft_credits(cls, short_name_id: int) -> List[Self]:
def get_eft_credits(cls, short_name_id: int, include_zero_remaining=False) -> List[Self]:
"""Get EFT Credits with a remaining amount."""
return (cls.query
.filter(EFTCredit.remaining_amount > 0)
.filter(include_zero_remaining or EFTCredit.remaining_amount > 0)
.filter(EFTCredit.short_name_id == short_name_id)
.with_for_update()
.order_by(EFTCredit.created_on.asc())
.all())
21 changes: 13 additions & 8 deletions pay-api/src/pay_api/models/eft_refund.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,15 @@
# See the License for the specific language governing permissions and
# limitations under the License.
"""Model to handle EFT REFUNDS, this is picked up by the AP job to mail out."""
from datetime import datetime, timezone
from typing import List

from sqlalchemy import ForeignKey

from .base_model import BaseModel
from .audit import Audit
from .db import db


class EFTRefund(BaseModel): # pylint: disable=too-many-instance-attributes
class EFTRefund(Audit):
"""This class manages the file data for EFT Refunds."""

__tablename__ = 'eft_refunds'
Expand All @@ -40,15 +40,16 @@ class EFTRefund(BaseModel): # pylint: disable=too-many-instance-attributes
'cas_supplier_number',
'comment',
'created_by',
'created_name'
'created_on',
'decline_reason',
'id',
'refund_amount',
'refund_email',
'short_name_id',
'status',
'updated_by_name',
'updated_by',
'updated_name',
'updated_on'
]
}
Expand All @@ -57,12 +58,16 @@ class EFTRefund(BaseModel): # pylint: disable=too-many-instance-attributes
comment = db.Column(db.String(), nullable=False)
decline_reason = db.Column(db.String(), nullable=True)
created_by = db.Column('created_by', db.String(100), nullable=True)
created_on = db.Column('created_on', db.DateTime, nullable=False, default=lambda: datetime.now(tz=timezone.utc))
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
refund_amount = db.Column(db.Numeric(), nullable=False)
refund_email = db.Column(db.String(100), nullable=False)
short_name_id = db.Column(db.Integer, ForeignKey('eft_short_names.id'), nullable=False)
status = db.Column(db.String(25), nullable=True)
updated_by = db.Column('updated_by', db.String(100), nullable=True)
updated_by_name = db.Column('updated_by_name', db.String(100), nullable=True)
updated_on = db.Column('updated_on', db.DateTime, nullable=True)

@classmethod
def find_refunds(cls, statuses: List[str]):
"""Return all refunds by status."""
query = cls.query
if statuses:
query = cls.query.filter(EFTRefund.status.in_(statuses))
return query.all()
55 changes: 0 additions & 55 deletions pay-api/src/pay_api/models/eft_refund_email_list.py

This file was deleted.

4 changes: 2 additions & 2 deletions pay-api/src/pay_api/models/eft_short_names_historical.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
from .db import db


class EFTShortnamesHistorical(BaseModel): # pylint:disable=too-many-instance-attributes
class EFTShortnamesHistorical(BaseModel):
"""This class manages all EFT Short name historical data."""

__tablename__ = 'eft_short_names_historical'
Expand Down Expand Up @@ -81,7 +81,7 @@ def find_by_related_group_link_id(cls, group_link_id: int) -> Self:
@classmethod
def find_by_eft_refund_id(cls, eft_refund_id: int) -> Self:
"""Find historical records by EFT refund id."""
return cls.query.filter_by(eft_refund_id=eft_refund_id).one_or_none()
return cls.query.filter_by(eft_refund_id=eft_refund_id).order_by(EFTShortnamesHistorical.id.desc()).all()


@define
Expand Down
2 changes: 1 addition & 1 deletion pay-api/src/pay_api/models/refund.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
from .db import db, ma


class Refund(BaseModel): # pylint:disable=too-many-instance-attributes
class Refund(BaseModel):
"""This class manages all of the base data about Refunds."""

__tablename__ = 'refunds'
Expand Down
Loading

0 comments on commit ac82a1c

Please sign in to comment.