-
Notifications
You must be signed in to change notification settings - Fork 39
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
17829 - Implement summary route for statements. #1256
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -37,10 +37,10 @@ | |
@_jwt.requires_auth | ||
def get_account_statements(account_id): | ||
"""Get all statements records for an account.""" | ||
current_app.logger.info('<Aget_account_statements') | ||
current_app.logger.info('<get_account_statements') | ||
|
||
# Check if user is authorized to perform this action | ||
check_auth(business_identifier=None, account_id=account_id, contains_role=EDIT_ROLE, is_premium=True) | ||
check_auth(business_identifier=None, account_id=account_id, contains_role=EDIT_ROLE) | ||
|
||
page: int = int(request.args.get('page', '1')) | ||
limit: int = int(request.args.get('limit', '10')) | ||
|
@@ -60,12 +60,26 @@ def get_account_statement(account_id: str, statement_id: str): | |
response_content_type = request.headers.get('Accept', ContentType.PDF.value) | ||
|
||
# Check if user is authorized to perform this action | ||
auth = check_auth(business_identifier=None, account_id=account_id, contains_role=EDIT_ROLE, is_premium=True) | ||
auth = check_auth(business_identifier=None, account_id=account_id, contains_role=EDIT_ROLE) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Some cleanup, eventually we want to get rid of premium accounts |
||
|
||
report, report_name = StatementService.get_statement_report(statement_id=statement_id, | ||
content_type=response_content_type, auth=auth) | ||
response = Response(report, 200) | ||
response.headers.set('Content-Disposition', 'attachment', filename=report_name) | ||
response.headers.set('Content-Type', response_content_type) | ||
response.headers.set('Access-Control-Expose-Headers', 'Content-Disposition') | ||
current_app.logger.info('>get_account_statement') | ||
return response | ||
|
||
|
||
@bp.route('/summary', methods=['GET', 'OPTIONS']) | ||
@cross_origin(origins='*', methods=['GET']) | ||
@_tracing.trace() | ||
@_jwt.requires_auth | ||
def get_account_statement_summary(account_id: str): | ||
"""Create the statement report.""" | ||
current_app.logger.info('<get_account_statement_summary') | ||
check_auth(business_identifier=None, account_id=account_id, contains_role=EDIT_ROLE) | ||
response, status = StatementService.get_summary(account_id), HTTPStatus.OK | ||
current_app.logger.info('>get_account_statement_summary') | ||
return jsonify(response), status |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,12 +15,17 @@ | |
from datetime import date, datetime | ||
|
||
from flask import current_app | ||
from sqlalchemy import func | ||
|
||
from pay_api.models import db | ||
from pay_api.models import Invoice as InvoiceModel | ||
from pay_api.models import PaymentAccount as PaymentAccountModel | ||
from pay_api.models import Statement as StatementModel | ||
from pay_api.models import StatementInvoices as StatementInvoicesModel | ||
from pay_api.models import StatementSchema as StatementModelSchema | ||
from pay_api.utils.enums import ContentType, StatementFrequency | ||
from pay_api.utils.enums import ContentType, InvoiceStatus, StatementFrequency | ||
from pay_api.utils.constants import DT_SHORT_FORMAT | ||
|
||
from pay_api.utils.util import get_local_formatted_date | ||
from .payment import Payment as PaymentService | ||
|
||
|
||
|
@@ -163,3 +168,26 @@ def get_statement_report(statement_id: str, content_type: str, template_name='st | |
current_app.logger.debug('>get_statement_report') | ||
|
||
return report_response, report_name | ||
|
||
@staticmethod | ||
def get_summary(auth_account_id: str): | ||
"""Get summary for statements by account id.""" | ||
# This is written outside of the model, because we have multiple model references that need to be included. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Perhaps worth reading |
||
# If we include these references inside of a model, it runs the risk of having circular dependencies. | ||
# It's easier to build out features if our models don't rely on other models. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ideally resources rely on services, should rely on models, models should never rely on models - Otherwise you're in for a world of pain with circular references. |
||
result = db.session.query(func.sum(InvoiceModel.total - InvoiceModel.paid).label('total_due'), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should cover partial payments ideally (not implemented currently, maybe for online banking) |
||
func.min(InvoiceModel.overdue_date).label('oldest_overdue_date')) \ | ||
.join(PaymentAccountModel) \ | ||
.join(StatementInvoicesModel) \ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Uses Statement invoices, so this only shows invoices that have statements. Otherwise I would have moved this into the invoice service. |
||
.filter(PaymentAccountModel.auth_account_id == auth_account_id) \ | ||
.filter(InvoiceModel.invoice_status_code == InvoiceStatus.OVERDUE.value) \ | ||
.filter(StatementInvoicesModel.invoice_id == InvoiceModel.id) \ | ||
.group_by(InvoiceModel.payment_account_id) \ | ||
.one_or_none() | ||
|
||
total_due = float(result.total_due) if result else 0 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Couldn't find a nicer way to do this unfortunately. I tried .first(), .all() etc. Could be replaced by scalars() in SQLAlchemy 2 possibly |
||
oldest_overdue_date = get_local_formatted_date(result.oldest_overdue_date) if result else None | ||
return { | ||
'total_due': total_due, | ||
'oldest_overdue_date': oldest_overdue_date | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some cleanup, eventually we want to get rid of premium accounts