Skip to content

Commit

Permalink
17534 - NSF Implementation (#1377)
Browse files Browse the repository at this point in the history
* Squashed commit of the following:

commit 91785fa
Author: Rodrigo Barraza <hello@rod.dev>
Date:   Tue Jan 16 07:59:01 2024 -0800

    revision update

commit 19b8a90
Merge: 915cc0d 676d202
Author: Rodrigo Barraza <hello@rod.dev>
Date:   Fri Jan 12 08:15:08 2024 -0800

    Merge branch 'main' into feature/17534

commit 915cc0d
Author: Rodrigo Barraza <hello@rod.dev>
Date:   Fri Jan 12 06:38:47 2024 -0800

    Updating NSF query

commit 89d80bc
Merge: 2b50ab4 7ca3f7d
Author: Rodrigo Barraza <hello@rod.dev>
Date:   Tue Jan 2 09:55:10 2024 -0800

    Merge branch 'main' into feature/17534

commit 2b50ab4
Author: Rodrigo Barraza <hello@rod.dev>
Date:   Fri Dec 15 07:26:47 2023 -0800

    Unit test fix

commit ae9c1de
Author: Rodrigo Barraza <hello@rod.dev>
Date:   Fri Dec 15 07:17:50 2023 -0800

    Expanding API test

commit b034d16
Author: Rodrigo Barraza <hello@rod.dev>
Date:   Fri Dec 15 07:02:58 2023 -0800

    Flake8 fix

commit 521b252
Author: Rodrigo Barraza <hello@rod.dev>
Date:   Fri Dec 15 06:56:30 2023 -0800

    Unit test fix

commit 9005132
Author: Rodrigo Barraza <hello@rod.dev>
Date:   Fri Dec 15 06:46:42 2023 -0800

    Expanding tests

commit 5d75820
Author: Rodrigo Barraza <hello@rod.dev>
Date:   Fri Dec 15 06:33:01 2023 -0800

    Checking auth, getting latest CFS account

commit 4aab599
Author: Rodrigo Barraza <hello@rod.dev>
Date:   Thu Dec 14 12:30:13 2023 -0800

    Cleanup, new CFS method

commit 23c4099
Author: Rodrigo Barraza <hello@rod.dev>
Date:   Wed Dec 13 18:21:20 2023 -0800

    Expanding unit test

commit fad3b66
Author: Rodrigo Barraza <hello@rod.dev>
Date:   Wed Dec 13 14:00:40 2023 -0800

    Lint fix

commit 848ec10
Merge: f2cebe8 dbb11ad
Author: Rodrigo Barraza <hello@rod.dev>
Date:   Wed Dec 13 13:55:09 2023 -0800

    Merge branch 'main' into feature/17534

commit f2cebe8
Author: Rodrigo Barraza <hello@rod.dev>
Date:   Wed Dec 13 13:55:01 2023 -0800

    Unit test fixes

commit a6fbaa4
Author: Rodrigo Barraza <hello@rod.dev>
Date:   Tue Dec 12 13:40:35 2023 -0800

    NSF query refactoring

    NSF query refactoring and accommodating template structure

commit e2946ad
Author: Rodrigo Barraza <hello@rod.dev>
Date:   Tue Dec 12 09:08:41 2023 -0800

    Moving logic to query, updating template

commit 13a4eb7
Author: Rodrigo Barraza <hello@rod.dev>
Date:   Mon Dec 11 13:17:15 2023 -0800

    Feedback updates

commit 08d62ac
Author: Rodrigo Barraza <hello@rod.dev>
Date:   Mon Dec 11 13:13:13 2023 -0800

    New NSF query and cleanup for NSF PDF template

commit dff9b98
Author: Rodrigo Barraza <hello@rod.dev>
Date:   Sun Dec 10 22:18:56 2023 -0800

    Test fixes

commit 5063764
Author: Rodrigo Barraza <hello@rod.dev>
Date:   Sun Dec 10 21:10:11 2023 -0800

    Version bump

commit baa28b4
Author: Rodrigo Barraza <hello@rod.dev>
Date:   Sun Dec 10 21:03:08 2023 -0800

    flake8 fix

commit 5d24d0d
Author: Rodrigo Barraza <hello@rod.dev>
Date:   Sun Dec 10 20:55:22 2023 -0800

    Model and service changes

commit e08b591
Author: Rodrigo Barraza <hello@rod.dev>
Date:   Sun Dec 10 19:50:21 2023 -0800

    asdict

commit be2d5e2
Author: Rodrigo Barraza <hello@rod.dev>
Date:   Sun Dec 10 19:06:27 2023 -0800

    Cleanup

commit 6cc9bdc
Author: Rodrigo Barraza <hello@rod.dev>
Date:   Sun Dec 10 18:33:27 2023 -0800

    Lint fixes

commit 31aa3da
Merge: 456eb65 dafa812
Author: Rodrigo Barraza <hello@rod.dev>
Date:   Sun Dec 10 18:20:21 2023 -0800

    Merge branch 'main' into feature/17534

commit 456eb65
Author: Rodrigo Barraza <hello@rod.dev>
Date:   Sun Dec 10 18:20:07 2023 -0800

    PDF fixes

commit f6c676f
Author: Rodrigo Barraza <hello@rod.dev>
Date:   Fri Dec 8 13:29:14 2023 -0800

    Query fix

commit 91e3ed5
Author: Rodrigo Barraza <hello@rod.dev>
Date:   Thu Dec 7 08:50:50 2023 -0800

    Ignoring lint on NonSufficientFundsSearchModel

commit a9fa502
Author: Rodrigo Barraza <hello@rod.dev>
Date:   Thu Dec 7 08:46:10 2023 -0800

    Lint cleanup

commit b7c6a93
Author: Rodrigo Barraza <hello@rod.dev>
Date:   Thu Dec 7 08:36:33 2023 -0800

    New NSF template, adding search model, migration script, cleanup

commit e7cc660
Author: Rodrigo Barraza <hello@rod.dev>
Date:   Sun Dec 3 19:42:32 2023 -0800

    import fix

commit 04742b8
Author: Rodrigo Barraza <hello@rod.dev>
Date:   Sun Dec 3 19:33:34 2023 -0800

    isort fix

commit 7f663da
Author: Rodrigo Barraza <hello@rod.dev>
Date:   Sun Dec 3 19:26:14 2023 -0800

    Fixes

commit df55123
Author: Rodrigo Barraza <hello@rod.dev>
Date:   Sun Dec 3 19:07:58 2023 -0800

    More flake8 test fixes

commit 40a4b47
Author: Rodrigo Barraza <hello@rod.dev>
Date:   Sun Dec 3 18:51:54 2023 -0800

    Flake8 fixes

commit 01aa77e
Author: Rodrigo Barraza <hello@rod.dev>
Date:   Sun Dec 3 18:40:15 2023 -0800

    Lint and test fixes

commit bb0ccdd
Author: Rodrigo Barraza <hello@rod.dev>
Date:   Sun Dec 3 18:26:56 2023 -0800

    Linting and test fix

commit 6c7e6c0
Merge: 93390b7 2235d3d
Author: Rodrigo Barraza <hello@rod.dev>
Date:   Sun Dec 3 18:08:59 2023 -0800

    Merge branch 'main' into feature/17534

commit 93390b7
Author: Rodrigo Barraza <hello@rod.dev>
Date:   Sun Dec 3 18:08:51 2023 -0800

    Non sufficient funds implementation

* Squashed commit of the following:

commit b78db55
Author: Rodrigo Barraza <hello@rod.dev>
Date:   Tue Jan 16 08:58:32 2024 -0800

    Linting fixes

commit 29e2180
Merge: 0e691bb 676d202
Author: Rodrigo Barraza <hello@rod.dev>
Date:   Tue Jan 16 08:37:23 2024 -0800

    Merge branch 'main' into feature/17507

commit 0e691bb
Author: Rodrigo Barraza <hello@rod.dev>
Date:   Mon Dec 11 09:40:53 2023 -0800

    reminder

commit 6ad3242
Author: Rodrigo Barraza <hello@rod.dev>
Date:   Mon Dec 11 00:20:31 2023 -0800

    Payload reformatting

commit ea27395
Merge: a130ae2 dafa812
Author: Rodrigo Barraza <hello@rod.dev>
Date:   Sun Dec 10 23:31:06 2023 -0800

    Merge branch 'main' into feature/17507

commit a130ae2
Author: Rodrigo Barraza <hello@rod.dev>
Date:   Thu Nov 23 18:05:14 2023 -0800

    Cleanup

commit 24f771f
Author: Rodrigo Barraza <hello@rod.dev>
Date:   Wed Nov 15 08:55:20 2023 -0800

    Argument fix

commit b7af147
Author: Rodrigo Barraza <hello@rod.dev>
Date:   Tue Nov 14 20:09:51 2023 -0800

    Moving payload over

commit 8a0f788
Author: Rodrigo Barraza <hello@rod.dev>
Date:   Thu Nov 9 08:54:10 2023 -0800

    Error fix

commit b9106f2
Author: Rodrigo Barraza <hello@rod.dev>
Date:   Thu Nov 9 08:41:31 2023 -0800

    PDF payload information

commit 034cd7c
Author: Rodrigo Barraza <hello@rod.dev>
Date:   Thu Nov 9 07:53:04 2023 -0800

    Passing payload data for PDF

commit 6110773
Author: Rodrigo Barraza <hello@rod.dev>
Date:   Mon Nov 6 05:37:41 2023 -0800

    Email update

* Cleanup

* Fix unlocking account

* Dict fix

* Dict fix
  • Loading branch information
rodrigo-barraza authored Jan 22, 2024
1 parent a598989 commit 49bfe45
Show file tree
Hide file tree
Showing 17 changed files with 1,131 additions and 16 deletions.
30 changes: 30 additions & 0 deletions pay-api/migrations/versions/2023_12_05_b65365f7852b_.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
"""Add Non-Sufficient Funds table to store Non-Sufficient Funds invoices
Revision ID: b65365f7852b
Revises: eec11500a81e
Create Date: 2023-12-05 12:28:27.025012
"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import postgresql

# revision identifiers, used by Alembic.
revision = 'b65365f7852b'
down_revision = 'eec11500a81e'
branch_labels = None
depends_on = None


def upgrade():
op.create_table('non_sufficient_funds',
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
sa.Column('description', sa.String(length=50), nullable=True),
sa.Column('invoice_id', sa.Integer(), nullable=False),
sa.ForeignKeyConstraint(['invoice_id'], ['invoices.id'], ),
sa.PrimaryKeyConstraint('id')
)


def downgrade():
op.drop_table('non_sufficient_funds')
1 change: 1 addition & 0 deletions pay-api/src/pay_api/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
from .invoice_reference_status_code import InvoiceReferenceStatusCode, InvoiceReferenceStatusCodeSchema
from .invoice_status_code import InvoiceStatusCode, InvoiceStatusCodeSchema
from .line_item_status_code import LineItemStatusCode, LineItemStatusCodeSchema
from .non_sufficient_funds import NonSufficientFundsModel, NonSufficientFundsSchema
from .notification_status_code import NotificationStatusCode, NotificationStatusCodeSchema
from .payment import Payment, PaymentSchema
from .payment_account import PaymentAccount, PaymentAccountSchema # noqa: I001
Expand Down
6 changes: 6 additions & 0 deletions pay-api/src/pay_api/models/cfs_account.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,12 @@ def find_effective_by_account_id(cls, account_id: str):
return CfsAccount.query.filter(CfsAccount.account_id == account_id,
CfsAccount.status != CfsAccountStatus.INACTIVE.value).one_or_none()

@classmethod
def find_latest_account_by_account_id(cls, account_id: str):
"""Return a frozen account by account_id, and return the record with the highest id."""
return CfsAccount.query.filter(
CfsAccount.account_id == account_id).order_by(CfsAccount.id.desc()).one_or_none()

@classmethod
def find_by_account_id(cls, account_id: str) -> List[CfsAccount]:
"""Return a Account by id."""
Expand Down
65 changes: 65 additions & 0 deletions pay-api/src/pay_api/models/non_sufficient_funds.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# Copyright © 2019 Province of British Columbia
#
# 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.
"""Model to handle all operations related to Non-Sufficient Funds."""
from __future__ import annotations

from attrs import define
from sqlalchemy import ForeignKey

from .base_model import BaseModel
from .db import db


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

__tablename__ = 'non_sufficient_funds'
# this mapper is used so that new and old versions of the service can be run simultaneously,
# making rolling upgrades easier
# This is used by SQLAlchemy to explicitly define which fields we're interested
# so it doesn't freak out and say it can't map the structure if other fields are present.
# This could occur from a failed deploy or during an upgrade.
# The other option is to tell SQLAlchemy to ignore differences, but that is ambiguous
# and can interfere with Alembic upgrades.
#
# NOTE: please keep mapper names in alpha-order, easier to track that way
# Exception, id is always first, _fields first
__mapper_args__ = {
'include_properties': [
'id',
'description',
'invoice_id',
]
}

id = db.Column(db.Integer, primary_key=True, autoincrement=True)
description = db.Column(db.String(50), nullable=True)
invoice_id = db.Column(db.Integer, ForeignKey('invoices.id'), nullable=False)


@define
class NonSufficientFundsSchema: # pylint: disable=too-few-public-methods
"""Used to search for NSF records."""

id: int
invoice_id: int
description: str

@classmethod
def from_row(cls, row: NonSufficientFundsModel):
"""From row is used so we don't tightly couple to our database class.
https://www.attrs.org/en/stable/init.html
"""
return cls(id=row.id, invoice_id=row.invoice_id, description=row.description)
6 changes: 4 additions & 2 deletions pay-api/src/pay_api/models/payment_line_item.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,10 @@ class Meta: # pylint: disable=too-few-public-methods
class PaymentLineItemSearchModel: # pylint: disable=too-few-public-methods
"""Payment Line Item Search Model."""

total: Decimal
gst: Decimal
pst: Decimal
service_fees: Decimal
description: str
filing_type_code: str

Expand All @@ -121,5 +123,5 @@ def from_row(cls, row: PaymentLineItem):
https://www.attrs.org/en/stable/init.html
"""
return cls(gst=row.gst, pst=row.pst, description=row.description,
filing_type_code=row.fee_schedule.filing_type_code)
return cls(total=row.total, gst=row.gst, pst=row.pst, service_fees=row.service_fees,
description=row.description, filing_type_code=row.fee_schedule.filing_type_code)
2 changes: 2 additions & 0 deletions pay-api/src/pay_api/resources/v1/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
from .invoice_receipt import bp as invoice_receipt_bp
from .invoices import bp as invoices_bp
from .meta import bp as meta_bp
from .non_sufficient_funds import bp as non_sufficient_funds_bp
from ..ops import bp as ops_bp
from .payment import bp as payment_bp
from .refund import bp as refund_bp
Expand Down Expand Up @@ -66,6 +67,7 @@ def init_app(self, app):
self.app.register_blueprint(invoices_bp)
self.app.register_blueprint(invoice_receipt_bp)
self.app.register_blueprint(meta_bp)
self.app.register_blueprint(non_sufficient_funds_bp)
self.app.register_blueprint(ops_bp)
self.app.register_blueprint(payment_bp)
self.app.register_blueprint(refund_bp)
Expand Down
67 changes: 67 additions & 0 deletions pay-api/src/pay_api/resources/v1/non_sufficient_funds.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# Copyright © 2019 Province of British Columbia
#
# 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.
"""Resource for Account Non-Sufficient Funds endpoints."""
from http import HTTPStatus

from flask import Blueprint, Response, current_app, jsonify
from flask_cors import cross_origin

from pay_api.exceptions import BusinessException
from pay_api.services import NonSufficientFundsService
from pay_api.services.auth import check_auth
from pay_api.utils.auth import jwt as _jwt
from pay_api.utils.constants import EDIT_ROLE, MAKE_PAYMENT, VIEW_ROLE
from pay_api.utils.endpoints_enums import EndpointEnum
from pay_api.utils.trace import tracing as _tracing


bp = Blueprint('NON_SUFFICIENT_FUNDS', __name__,
url_prefix=f'{EndpointEnum.API_V1.value}/accounts/<string:account_id>/nsf')


@bp.route('', methods=['GET', 'OPTIONS'])
@cross_origin(origins='*', methods=['GET'])
@_tracing.trace()
@_jwt.requires_auth
def get_non_sufficient_funds(account_id: str):
"""Get non sufficient funds."""
current_app.logger.info('<get_non_sufficient_funds')
# Check if user is authorized to perform this action
check_auth(business_identifier=None, account_id=account_id, one_of_roles=[MAKE_PAYMENT, EDIT_ROLE, VIEW_ROLE])
response, status = NonSufficientFundsService.find_all_non_sufficient_funds_invoices(
account_id=account_id), HTTPStatus.OK
current_app.logger.debug('>get_non_sufficient_funds')
return jsonify(response), status


@bp.route('/statement', methods=['POST', 'OPTIONS'])
@cross_origin(origins='*', methods=['POST'])
@_tracing.trace()
@_jwt.requires_auth
def get_non_sufficient_funds_statement_pdf(account_id: str):
"""Get non sufficient funds statement pdf."""
current_app.logger.info('<get_non_sufficient_funds_statement_pdf')
# Check if user is authorized to perform this action
check_auth(business_identifier=None, account_id=account_id, one_of_roles=[MAKE_PAYMENT, EDIT_ROLE, VIEW_ROLE])
try:
pdf, pdf_filename = NonSufficientFundsService.create_non_sufficient_funds_statement_pdf(account_id=account_id)
response = Response(pdf, 201)
response.headers.set('Content-Disposition', 'attachment', filename=f'{pdf_filename}.pdf')
response.headers.set('Content-Type', 'application/pdf')
response.headers.set('Access-Control-Expose-Headers', 'Content-Disposition')
current_app.logger.debug('>get_non_sufficient_funds_statement')
return response
except BusinessException as exception:
current_app.logger.debug('>get_non_sufficient_funds_statement_pdf')
return exception.response()
1 change: 1 addition & 0 deletions pay-api/src/pay_api/services/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
from .hashing import HashingService
from .internal_pay_service import InternalPayService
from .invoice import Invoice as InvoiceService
from .non_sufficient_funds import NonSufficientFundsService
from .payment import Payment
from .payment_service import PaymentService
from .payment_transaction import PaymentTransaction as TransactionService
Expand Down
158 changes: 158 additions & 0 deletions pay-api/src/pay_api/services/non_sufficient_funds.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
# Copyright © 2019 Province of British Columbia
#
# 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.
"""Service to manage Non-Sufficient Funds."""
from __future__ import annotations

from datetime import datetime

from flask import current_app

from sqlalchemy import case, func

from pay_api.models import CfsAccount as CfsAccountModel
from pay_api.models import Invoice as InvoiceModel
from pay_api.models import InvoiceReference as InvoiceReferenceModel
from pay_api.models import InvoiceSearchModel, NonSufficientFundsModel, NonSufficientFundsSchema
from pay_api.models import PaymentAccount as PaymentAccountModel
from pay_api.models import PaymentLineItem as PaymentLineItemModel
from pay_api.models import db
from pay_api.utils.converter import Converter
from pay_api.utils.enums import AuthHeaderType, ContentType, InvoiceReferenceStatus, ReverseOperation
from pay_api.utils.user_context import user_context

from .oauth_service import OAuthService


class NonSufficientFundsService:
"""Service to manage Non-Sufficient Funds related operations."""

def __init__(self):
"""Initialize the service."""
self.dao = NonSufficientFundsModel()

def asdict(self):
"""Return the EFT Short name as a python dict."""
return Converter().unstructure(NonSufficientFundsSchema.from_row(self.dao))

@staticmethod
def populate(value: NonSufficientFundsModel):
"""Populate Non-Sufficient Funds Service."""
non_sufficient_funds_service = NonSufficientFundsService()
non_sufficient_funds_service.dao = value
return non_sufficient_funds_service

@staticmethod
def save_non_sufficient_funds(invoice_id: int, description: str) -> NonSufficientFundsService:
"""Create Non-Sufficient Funds record."""
current_app.logger.debug('<save_non_sufficient_funds')
non_sufficient_funds_service = NonSufficientFundsService()

non_sufficient_funds_service.dao.invoice_id = invoice_id
non_sufficient_funds_service.dao.description = description
non_sufficient_funds_dao = non_sufficient_funds_service.dao.save()

non_sufficient_funds_service = NonSufficientFundsService.populate(non_sufficient_funds_dao)
current_app.logger.debug('>save_non_sufficient_funds')
return NonSufficientFundsService.asdict(non_sufficient_funds_service)

@staticmethod
def query_all_non_sufficient_funds_invoices(account_id: str):
"""Return all Non-Sufficient Funds invoices and their aggregate amounts."""
query = (db.session.query(
InvoiceModel, InvoiceReferenceModel)
.join(InvoiceReferenceModel, InvoiceReferenceModel.invoice_id == InvoiceModel.id)
.outerjoin(NonSufficientFundsModel, NonSufficientFundsModel.invoice_id == InvoiceModel.id)
.join(PaymentAccountModel, PaymentAccountModel.id == InvoiceModel.payment_account_id)
.filter(PaymentAccountModel.auth_account_id == account_id)
.group_by(InvoiceModel.id, InvoiceReferenceModel.id)
)

totals_query = (db.session.query(
func.sum(InvoiceModel.total - InvoiceModel.paid).label('total_amount_remaining'),
func.max(case(
[(PaymentLineItemModel.description == ReverseOperation.NSF.value, PaymentLineItemModel.total)],
else_=0))
.label('nsf_amount'),
func.sum(InvoiceModel.total - case(
[(PaymentLineItemModel.description == ReverseOperation.NSF.value, PaymentLineItemModel.total)],
else_=0)).label('total_amount'))
.join(PaymentAccountModel, PaymentAccountModel.id == InvoiceModel.payment_account_id)
.join(PaymentLineItemModel, PaymentLineItemModel.invoice_id == InvoiceModel.id)
.filter(PaymentAccountModel.auth_account_id == account_id)
)

aggregate_totals = totals_query.one()
results = query.all()
total = len(results)

return results, total, aggregate_totals

@staticmethod
def find_all_non_sufficient_funds_invoices(account_id: str):
"""Return all Non-Sufficient Funds invoices."""
results, total, aggregate_totals = NonSufficientFundsService.query_all_non_sufficient_funds_invoices(
account_id=account_id)
invoice_search_model = [InvoiceSearchModel.from_row(invoice_dao) for invoice_dao, _ in results]
converter = Converter()
invoice_list = converter.unstructure(invoice_search_model)
new_invoices = [converter.remove_nones(invoice_dict) for invoice_dict in invoice_list]

data = {
'total': total,
'invoices': new_invoices,
'total_amount': float(aggregate_totals.total_amount),
'total_amount_remaining': float(aggregate_totals.total_amount_remaining),
'nsf_amount': float(aggregate_totals.nsf_amount)
}

return data

@staticmethod
@user_context
def create_non_sufficient_funds_statement_pdf(account_id: str, **kwargs):
"""Create Non-Sufficient Funds statement pdf."""
current_app.logger.debug('<generate_non_sufficient_funds_statement_pdf')
invoice = NonSufficientFundsService.find_all_non_sufficient_funds_invoices(account_id=account_id)
cfs_account: CfsAccountModel = CfsAccountModel.find_latest_account_by_account_id(account_id)
invoice_reference: InvoiceReferenceModel = InvoiceReferenceModel.find_by_invoice_id_and_status(
invoice['invoices'][0]['id'], InvoiceReferenceStatus.ACTIVE.value)
account_url = current_app.config.get('AUTH_API_ENDPOINT') + f'orgs/{account_id}'
account = OAuthService.get(
endpoint=account_url, token=kwargs['user'].bearer_token,
auth_header_type=AuthHeaderType.BEARER, content_type=ContentType.JSON).json()
template_vars = {
'suspendedOn': datetime.strptime(account['suspendedOn'], '%Y-%m-%dT%H:%M:%S%z').strftime('%B %-d, %Y'),
'accountNumber': cfs_account.cfs_account,
'businessName': account['businessName'],
'totalAmountRemaining': invoice['total_amount_remaining'],
'totalAmount': invoice['total_amount'],
'nsfAmount': invoice['nsf_amount'],
'invoices': invoice['invoices'],
'invoiceNumber': invoice_reference.invoice_number,
}

invoice_pdf_dict = {
'templateName': 'non_sufficient_funds',
'reportName': 'non_sufficient_funds',
'templateVars': template_vars,
'populatePageNumber': True
}
current_app.logger.debug('Invoice PDF Dict %s', invoice_pdf_dict)

pdf_response = OAuthService.post(current_app.config.get('REPORT_API_BASE_URL'),
kwargs['user'].bearer_token, AuthHeaderType.BEARER,
ContentType.JSON, invoice_pdf_dict)
current_app.logger.debug('<OAuthService responded to generate_non_sufficient_funds_statement_pdf')

return pdf_response, invoice_pdf_dict.get('reportName')
Loading

0 comments on commit 49bfe45

Please sign in to comment.