Skip to content

Commit

Permalink
23509 23731 - feature: api add ability to cancel document request cc …
Browse files Browse the repository at this point in the history
…payement.
  • Loading branch information
hfekete committed Nov 6, 2024
1 parent bc89cb7 commit 0156829
Show file tree
Hide file tree
Showing 6 changed files with 97 additions and 7 deletions.
32 changes: 32 additions & 0 deletions search-api/migrations/versions/20241105_164024_0ba810e98e41_.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
"""empty message
Revision ID: 0ba810e98e41
Revises: eaf25b9a20bf
Create Date: 2024-11-05 16:40:24.716461
"""
from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision = '0ba810e98e41'
down_revision = 'eaf25b9a20bf'
branch_labels = None
depends_on = None


def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('document_access_request', schema=None) as batch_op:
batch_op.create_index(batch_op.f('ix_document_access_request_payment_id'), ['payment_id'], unique=False)

# ### end Alembic commands ###


def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('document_access_request', schema=None) as batch_op:
batch_op.drop_index(batch_op.f('ix_document_access_request_payment_id'))

# ### end Alembic commands ###
8 changes: 6 additions & 2 deletions search-api/src/search_api/exceptions/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,13 @@ def __post_init__(self):
class DbRecordNotFoundException(BaseExceptionE):
"""Row not found in database."""

def __init__(self):
def __init__(self, message=None):
"""Return a valid Record Not Found Exception."""
self.message = 'DB record not found'
if message is None:
self.message = 'DB record not found'
else:
self.message = message

self.status_code = HTTPStatus.NOT_FOUND
super().__init__()

Expand Down
26 changes: 25 additions & 1 deletion search-api/src/search_api/models/document_access_request.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from datetime import datetime, timezone
from enum import auto
from http import HTTPStatus
from typing import List

from sqlalchemy import inspect
from sqlalchemy.ext.hybrid import hybrid_property
Expand Down Expand Up @@ -47,7 +48,7 @@ class Status(BaseEnum):
status = db.Column('status', db.Enum(Status), default=Status.CREATED)
account_id = db.Column('account_id', db.Integer)
_payment_status_code = db.Column('payment_status_code', db.String(50))
_payment_token = db.Column('payment_id', db.String(4096))
_payment_token = db.Column('payment_id', db.String(4096), index=True)
_payment_completion_date = db.Column('payment_completion_date', db.DateTime(timezone=True))
submission_date = db.Column(db.DateTime(timezone=True), default=datetime.utcnow)
expiry_date = db.Column(db.DateTime(timezone=True))
Expand Down Expand Up @@ -158,13 +159,36 @@ def find_by_id(cls, request_id: int) -> DocumentAccessRequest:
"""Return a request having the specified id."""
return cls.query.filter_by(id=request_id).one_or_none()

@classmethod
def find_by_payment_token(cls, payment_id: str) -> List[DocumentAccessRequest]:
"""Return a list of requests having the specified payment_id."""
return cls.query.filter_by(_payment_token=payment_id).all()

@staticmethod
def _raise_default_lock_exception():
raise BusinessException(
error='Request cannot be modified after the invoice is created.',
status_code=HTTPStatus.FORBIDDEN
)

def cancel(self):
"""
Cancels the current payment request if it is in the CREATED state.
Raises a BusinessException with an error and the HTTP status FORBIDDEN
if the payment request is not in the CREATED state.
Sets the status to ERROR and updates the payment status code to 'PAYMENT_CANCELLED'.
Saves the current state of the request.
"""
if self.status != self.Status.CREATED:
raise BusinessException(
error='Payment can be only cancelled if in state created.',
status_code=HTTPStatus.FORBIDDEN
)
self.status = DocumentAccessRequest.status = self.Status.ERROR
self._payment_status_code = 'PAYMENT_CANCELLED'
self.save()

def save(self):
"""Store the request into the db."""
db.session.add(self)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ def create_invoice(document_access_request: DocumentAccessRequest, user_jwt: Jwt
today_utc = datetime.now()

document_access_request.payment_token = pid
document_access_request.submission_date = today_utc
if is_pad:
document_access_request.status = DocumentAccessRequest.Status.PAID
document_access_request.payment_completion_date = today_utc
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,3 +131,28 @@ def post(business_identifier): # pylint: disable=too-many-return-statements
except Exception as default_exception: # noqa: B902
current_app.logger.error(default_exception.with_traceback(None))
return resource_utils.default_exception_response(default_exception)


@bp.delete('/<int:request_id>')
@cross_origin(origin='*')
@jwt.requires_auth
def cancel_request(business_identifier, request_id):
"""Cancel document access request by id if it is in state created."""
try:
account_id = request.headers.get('Account-Id', None)
if not account_id:
return resource_utils.account_required_response()

access_request = DocumentAccessRequest.find_by_id(request_id)

if not access_request or access_request.business_identifier != business_identifier:
return resource_utils.not_found_error_response('Document Access Request', request_id)
if str(access_request.account_id) != account_id:
return resource_utils.unauthorized_error_response(account_id)

access_request.cancel()

return {}, HTTPStatus.OK

except Exception as default_exception: # noqa: B902
return resource_utils.default_exception_response(default_exception)
12 changes: 8 additions & 4 deletions search-api/src/search_api/resources/v2/payments/payments.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,16 @@ def gcp_listener():
credit_card_payment = ce.data
if credit_card_payment.get('corpTypeCode', '') != 'BUS':
raise Exception('invalid or missing corpTypeCode.') # noqa: E713 # pylint: disable=broad-exception-raised
dar = DocumentAccessRequest.find_by_id(credit_card_payment['id'])
if not dar:
payment_id = credit_card_payment['id']

dars = DocumentAccessRequest.find_by_payment_token(str(payment_id))

if dars is None:
raise DbRecordNotFoundException()

dar.status = credit_card_payment['statusCode']
dar.save()
for dar in dars:
dar.status = credit_card_payment['statusCode']
dar.save()

return {}, HTTPStatus.OK
except Exception: # noqa pylint: disable=broad-except
Expand Down

0 comments on commit 0156829

Please sign in to comment.