diff --git a/app/model/schema/token.py b/app/model/schema/token.py index ac2ef2a7..0f4a47c8 100644 --- a/app/model/schema/token.py +++ b/app/model/schema/token.py @@ -363,6 +363,7 @@ class ListAllHoldersSortItem(StrEnum): balance = "balance" pending_transfer = "pending_transfer" locked = "locked" + balance_and_pending_transfer = "balance_and_pending_transfer" key_manager = "key_manager" holder_name = "holder_name" @@ -395,6 +396,16 @@ class ListAllHoldersQuery: description="search condition of locked amount(0:equal, 1:greater than or equal, 2:less than or equal)", ), ] = ValueOperator.EQUAL + balance_and_pending_transfer: Annotated[ + Optional[int], + Query(description="number of balance plus pending transfer amount"), + ] = None + balance_and_pending_transfer_operator: Annotated[ + Optional[ValueOperator], + Query( + description="search condition of balance plus pending transfer(0:equal, 1:greater than or equal, 2:less than or equal)", + ), + ] = ValueOperator.EQUAL account_address: Annotated[ Optional[str], Query(description="account address(partial match)") ] = None diff --git a/app/routers/bond.py b/app/routers/bond.py index faf763c7..cdcac913 100644 --- a/app/routers/bond.py +++ b/app/routers/bond.py @@ -825,11 +825,6 @@ async def list_all_additional_issue_upload( get_query: ListAllAdditionalIssueUploadQuery = Depends(), issuer_address: Optional[str] = Header(None), ): - processed = get_query.processed - sort_order = get_query.sort_order - offset = get_query.offset - limit = get_query.limit - # Get a list of uploads stmt = select(BatchIssueRedeemUpload).where( and_( @@ -844,22 +839,22 @@ async def list_all_additional_issue_upload( total = await db.scalar(select(func.count()).select_from(stmt.subquery())) - if processed is not None: - stmt = stmt.where(BatchIssueRedeemUpload.processed == processed) + if get_query.processed is not None: + stmt = stmt.where(BatchIssueRedeemUpload.processed == get_query.processed) count = await db.scalar(select(func.count()).select_from(stmt.subquery())) # Sort - if sort_order == 0: # ASC + if get_query.sort_order == 0: # ASC stmt = stmt.order_by(BatchIssueRedeemUpload.created) else: # DESC stmt = stmt.order_by(desc(BatchIssueRedeemUpload.created)) # Pagination - if limit is not None: - stmt = stmt.limit(limit) - if offset is not None: - stmt = stmt.offset(offset) + if get_query.limit is not None: + stmt = stmt.limit(get_query.limit) + if get_query.offset is not None: + stmt = stmt.offset(get_query.offset) _upload_list: Sequence[BatchIssueRedeemUpload] = (await db.scalars(stmt)).all() @@ -880,8 +875,8 @@ async def list_all_additional_issue_upload( resp = { "result_set": { "count": count, - "offset": offset, - "limit": limit, + "offset": get_query.offset, + "limit": get_query.limit, "total": total, }, "uploads": uploads, @@ -1071,11 +1066,6 @@ async def list_redeem_history( get_query: ListRedeemHistoryQuery = Depends(), ): """List redemption history""" - sort_item = get_query.sort_item - sort_order = get_query.sort_order - offset = get_query.offset - limit = get_query.limit - # Get token _token: Token | None = ( await db.scalars( @@ -1106,20 +1096,20 @@ async def list_redeem_history( count = total # Sort - sort_attr = getattr(IDXIssueRedeem, sort_item.value, None) - if sort_order == 0: # ASC + sort_attr = getattr(IDXIssueRedeem, get_query.sort_item.value, None) + if get_query.sort_order == 0: # ASC stmt = stmt.order_by(sort_attr) else: # DESC stmt = stmt.order_by(desc(sort_attr)) - if sort_item != IDXIssueRedeemSortItem.BLOCK_TIMESTAMP: + if get_query.sort_item != IDXIssueRedeemSortItem.BLOCK_TIMESTAMP: # NOTE: Set secondary sort for consistent results stmt = stmt.order_by(desc(IDXIssueRedeem.block_timestamp)) # Pagination - if limit is not None: - stmt = stmt.limit(limit) - if offset is not None: - stmt = stmt.offset(offset) + if get_query.limit is not None: + stmt = stmt.limit(get_query.limit) + if get_query.offset is not None: + stmt = stmt.offset(get_query.offset) _events: Sequence[IDXIssueRedeem] = (await db.scalars(stmt)).all() @@ -1141,8 +1131,8 @@ async def list_redeem_history( { "result_set": { "count": count, - "offset": offset, - "limit": limit, + "offset": get_query.offset, + "limit": get_query.limit, "total": total, }, "history": history, @@ -1241,11 +1231,6 @@ async def list_all_redeem_upload( get_query: ListAllRedeemUploadQuery = Depends(), issuer_address: Optional[str] = Header(None), ): - processed = get_query.processed - sort_order = get_query.sort_order - offset = get_query.offset - limit = get_query.limit - # Get a list of uploads stmt = select(BatchIssueRedeemUpload).where( and_( @@ -1261,22 +1246,22 @@ async def list_all_redeem_upload( total = await db.scalar(select(func.count()).select_from(stmt.subquery())) - if processed is not None: - stmt = stmt.where(BatchIssueRedeemUpload.processed == processed) + if get_query.processed is not None: + stmt = stmt.where(BatchIssueRedeemUpload.processed == get_query.processed) count = await db.scalar(select(func.count()).select_from(stmt.subquery())) # Sort - if sort_order == 0: # ASC + if get_query.sort_order == 0: # ASC stmt = stmt.order_by(BatchIssueRedeemUpload.created) else: # DESC stmt = stmt.order_by(desc(BatchIssueRedeemUpload.created)) # Pagination - if limit is not None: - stmt = stmt.limit(limit) - if offset is not None: - stmt = stmt.offset(offset) + if get_query.limit is not None: + stmt = stmt.limit(get_query.limit) + if get_query.offset is not None: + stmt = stmt.offset(get_query.offset) _upload_list: Sequence[BatchIssueRedeemUpload] = (await db.scalars(stmt)).all() @@ -1297,8 +1282,8 @@ async def list_all_redeem_upload( resp = { "result_set": { "count": count, - "offset": offset, - "limit": limit, + "offset": get_query.offset, + "limit": get_query.limit, "total": total, }, "uploads": uploads, @@ -1782,21 +1767,6 @@ async def list_all_holders( issuer_address: str = Header(...), ): """List all bond token holders""" - include_former_holder = get_query.include_former_holder - balance = get_query.balance - balance_operator = get_query.balance_operator - pending_transfer = get_query.pending_transfer - pending_transfer_operator = get_query.pending_transfer_operator - locked = get_query.locked - locked_operator = get_query.locked_operator - account_address = get_query.account_address - holder_name = get_query.holder_name - key_manager = get_query.key_manager - sort_item = get_query.sort_item - sort_order = get_query.sort_order - offset = get_query.offset - limit = get_query.limit - # Validate Headers validate_headers(issuer_address=(issuer_address, address_is_valid_address)) @@ -1863,7 +1833,7 @@ async def list_all_holders( total = await db.scalar(select(func.count()).select_from(stmt.subquery())) - if not include_former_holder: + if not get_query.include_former_holder: stmt = stmt.where( or_( IDXPosition.balance != 0, @@ -1874,75 +1844,109 @@ async def list_all_holders( ) ) - if balance is not None and balance_operator is not None: - match balance_operator: + if get_query.balance is not None and get_query.balance_operator is not None: + match get_query.balance_operator: + case ValueOperator.EQUAL: + stmt = stmt.where(IDXPosition.balance == get_query.balance) + case ValueOperator.GTE: + stmt = stmt.where(IDXPosition.balance >= get_query.balance) + case ValueOperator.LTE: + stmt = stmt.where(IDXPosition.balance <= get_query.balance) + + if ( + get_query.pending_transfer is not None + and get_query.pending_transfer_operator is not None + ): + match get_query.pending_transfer_operator: case ValueOperator.EQUAL: - stmt = stmt.where(IDXPosition.balance == balance) + stmt = stmt.where( + IDXPosition.pending_transfer == get_query.pending_transfer + ) case ValueOperator.GTE: - stmt = stmt.where(IDXPosition.balance >= balance) + stmt = stmt.where( + IDXPosition.pending_transfer >= get_query.pending_transfer + ) case ValueOperator.LTE: - stmt = stmt.where(IDXPosition.balance <= balance) + stmt = stmt.where( + IDXPosition.pending_transfer <= get_query.pending_transfer + ) - if pending_transfer is not None and pending_transfer_operator is not None: - match pending_transfer_operator: + if get_query.locked is not None and get_query.locked_operator is not None: + match get_query.locked_operator: case ValueOperator.EQUAL: - stmt = stmt.where(IDXPosition.pending_transfer == pending_transfer) + stmt = stmt.having(locked_value == get_query.locked) case ValueOperator.GTE: - stmt = stmt.where(IDXPosition.pending_transfer >= pending_transfer) + stmt = stmt.having(locked_value >= get_query.locked) case ValueOperator.LTE: - stmt = stmt.where(IDXPosition.pending_transfer <= pending_transfer) + stmt = stmt.having(locked_value <= get_query.locked) - if locked is not None and locked_operator is not None: - match locked_operator: + if ( + get_query.balance_and_pending_transfer is not None + and get_query.balance_and_pending_transfer_operator is not None + ): + match get_query.balance_and_pending_transfer_operator: case ValueOperator.EQUAL: - stmt = stmt.having(locked_value == locked) + stmt = stmt.where( + IDXPosition.balance + IDXPosition.pending_transfer + == get_query.balance_and_pending_transfer + ) case ValueOperator.GTE: - stmt = stmt.having(locked_value >= locked) + stmt = stmt.where( + IDXPosition.balance + IDXPosition.pending_transfer + >= get_query.balance_and_pending_transfer + ) case ValueOperator.LTE: - stmt = stmt.having(locked_value <= locked) + stmt = stmt.where( + IDXPosition.balance + IDXPosition.pending_transfer + <= get_query.balance_and_pending_transfer + ) - if account_address is not None: - stmt = stmt.where(IDXPosition.account_address.like("%" + account_address + "%")) + if get_query.account_address is not None: + stmt = stmt.where( + IDXPosition.account_address.like("%" + get_query.account_address + "%") + ) - if holder_name is not None: + if get_query.holder_name is not None: stmt = stmt.where( IDXPersonalInfo._personal_info["name"] .as_string() - .like("%" + holder_name + "%") + .like("%" + get_query.holder_name + "%") ) - if key_manager is not None: + if get_query.key_manager is not None: stmt = stmt.where( IDXPersonalInfo._personal_info["key_manager"] .as_string() - .like("%" + key_manager + "%") + .like("%" + get_query.key_manager + "%") ) count = await db.scalar(select(func.count()).select_from(stmt.subquery())) # Sort - if sort_item == ListAllHoldersSortItem.holder_name: + if get_query.sort_item == ListAllHoldersSortItem.holder_name: sort_attr = IDXPersonalInfo._personal_info["name"].as_string() - elif sort_item == ListAllHoldersSortItem.key_manager: + elif get_query.sort_item == ListAllHoldersSortItem.key_manager: sort_attr = IDXPersonalInfo._personal_info["key_manager"].as_string() - elif sort_item == ListAllHoldersSortItem.locked: + elif get_query.sort_item == ListAllHoldersSortItem.locked: sort_attr = locked_value + elif get_query.sort_item == ListAllHoldersSortItem.balance_and_pending_transfer: + sort_attr = IDXPosition.balance + IDXPosition.pending_transfer else: - sort_attr = getattr(IDXPosition, sort_item) + sort_attr = getattr(IDXPosition, get_query.sort_item) - if sort_order == 0: # ASC + if get_query.sort_order == 0: # ASC stmt = stmt.order_by(asc(sort_attr)) else: # DESC stmt = stmt.order_by(desc(sort_attr)) - if sort_item != ListAllHoldersSortItem.created: + if get_query.sort_item != ListAllHoldersSortItem.created: # NOTE: Set secondary sort for consistent results stmt = stmt.order_by(asc(IDXPosition.created)) # Pagination - if limit is not None: - stmt = stmt.limit(limit) - if offset is not None: - stmt = stmt.offset(offset) + if get_query.limit is not None: + stmt = stmt.limit(get_query.limit) + if get_query.offset is not None: + stmt = stmt.offset(get_query.offset) _holders: Sequence[ tuple[IDXPosition, int, IDXPersonalInfo | None, datetime | None] @@ -1995,8 +1999,8 @@ async def list_all_holders( "result_set": { "count": count, "total": total, - "limit": limit, - "offset": offset, + "limit": get_query.limit, + "offset": get_query.offset, }, "holders": holders, } @@ -2320,11 +2324,6 @@ async def list_all_personal_info_batch_registration_uploads( get_query: ListAllPersonalInfoBatchRegistrationUploadQuery = Depends(), ): """List all personal information batch registration uploads""" - status = get_query.status - sort_order = get_query.sort_order - offset = get_query.offset - limit = get_query.limit - # Verify that the token is issued by the issuer_address _token: Token | None = ( await db.scalars( @@ -2352,22 +2351,22 @@ async def list_all_personal_info_batch_registration_uploads( total = await db.scalar(select(func.count()).select_from(stmt.subquery())) - if status is not None: - stmt = stmt.where(BatchRegisterPersonalInfoUpload.status == status) + if get_query.status is not None: + stmt = stmt.where(BatchRegisterPersonalInfoUpload.status == get_query.status) count = await db.scalar(select(func.count()).select_from(stmt.subquery())) # Sort - if sort_order == 0: # ASC + if get_query.sort_order == 0: # ASC stmt = stmt.order_by(BatchRegisterPersonalInfoUpload.created) else: # DESC stmt = stmt.order_by(desc(BatchRegisterPersonalInfoUpload.created)) # Pagination - if limit is not None: - stmt = stmt.limit(limit) - if offset is not None: - stmt = stmt.offset(offset) + if get_query.limit is not None: + stmt = stmt.limit(get_query.limit) + if get_query.offset is not None: + stmt = stmt.offset(get_query.offset) _upload_list: Sequence[BatchRegisterPersonalInfoUpload] = ( await db.scalars(stmt) @@ -2388,8 +2387,8 @@ async def list_all_personal_info_batch_registration_uploads( { "result_set": { "count": count, - "offset": offset, - "limit": limit, + "offset": get_query.offset, + "limit": get_query.limit, "total": total, }, "uploads": uploads, @@ -3118,14 +3117,6 @@ async def list_token_transfer_approval_history( get_query: ListTransferApprovalHistoryQuery = Depends(), ): """List token transfer approval history""" - from_address = get_query.from_address - to_address = get_query.to_address - status = get_query.status - sort_item = get_query.sort_item - sort_order = get_query.sort_order - offset = get_query.offset - limit = get_query.limit - # Get token _token: Token | None = ( await db.scalars( @@ -3242,33 +3233,33 @@ async def list_token_transfer_approval_history( total = await db.scalar(select(func.count()).select_from(stmt.subquery())) # Search Filter - if from_address is not None: - stmt = stmt.where(subquery.from_address == from_address) - if to_address is not None: - stmt = stmt.where(subquery.to_address == to_address) - if status is not None: - stmt = stmt.where(literal_column("status").in_(status)) + if get_query.from_address is not None: + stmt = stmt.where(subquery.from_address == get_query.from_address) + if get_query.to_address is not None: + stmt = stmt.where(subquery.to_address == get_query.to_address) + if get_query.status is not None: + stmt = stmt.where(literal_column("status").in_(get_query.status)) count = await db.scalar(select(func.count()).select_from(stmt.subquery())) # Sort - if sort_item != IDXTransferApprovalsSortItem.STATUS: - sort_attr = getattr(subquery, sort_item, None) + if get_query.sort_item != IDXTransferApprovalsSortItem.STATUS: + sort_attr = getattr(subquery, get_query.sort_item, None) else: sort_attr = literal_column("status") - if sort_order == 0: # ASC + if get_query.sort_order == 0: # ASC stmt = stmt.order_by(sort_attr) else: # DESC stmt = stmt.order_by(desc(sort_attr)) - if sort_item != IDXTransferApprovalsSortItem.ID: + if get_query.sort_item != IDXTransferApprovalsSortItem.ID: # NOTE: Set secondary sort for consistent results stmt = stmt.order_by(desc(subquery.id)) # Pagination - if limit is not None: - stmt = stmt.limit(limit) - if offset is not None: - stmt = stmt.offset(offset) + if get_query.limit is not None: + stmt = stmt.limit(get_query.limit) + if get_query.offset is not None: + stmt = stmt.offset(get_query.offset) _transfer_approvals: Sequence[ tuple[ @@ -3396,8 +3387,8 @@ async def list_token_transfer_approval_history( { "result_set": { "count": count, - "offset": offset, - "limit": limit, + "offset": get_query.offset, + "limit": get_query.limit, "total": total, }, "transfer_approval_history": transfer_approval_history, diff --git a/app/routers/share.py b/app/routers/share.py index 9fedb78e..46fb6f3d 100644 --- a/app/routers/share.py +++ b/app/routers/share.py @@ -797,11 +797,6 @@ async def list_all_additional_issue_upload( get_query: ListAllAdditionalIssueUploadQuery = Depends(), issuer_address: Optional[str] = Header(None), ): - processed = get_query.processed - sort_order = get_query.sort_order - offset = get_query.offset - limit = get_query.limit - # Get a list of uploads stmt = select(BatchIssueRedeemUpload).where( and_( @@ -816,22 +811,22 @@ async def list_all_additional_issue_upload( total = await db.scalar(select(func.count()).select_from(stmt.subquery())) - if processed is not None: - stmt = stmt.where(BatchIssueRedeemUpload.processed == processed) + if get_query.processed is not None: + stmt = stmt.where(BatchIssueRedeemUpload.processed == get_query.processed) count = await db.scalar(select(func.count()).select_from(stmt.subquery())) # Sort - if sort_order == 0: # ASC + if get_query.sort_order == 0: # ASC stmt = stmt.order_by(BatchIssueRedeemUpload.created) else: # DESC stmt = stmt.order_by(desc(BatchIssueRedeemUpload.created)) # Pagination - if limit is not None: - stmt = stmt.limit(limit) - if offset is not None: - stmt = stmt.offset(offset) + if get_query.limit is not None: + stmt = stmt.limit(get_query.limit) + if get_query.offset is not None: + stmt = stmt.offset(get_query.offset) _upload_list: Sequence[BatchIssueRedeemUpload] = (await db.scalars(stmt)).all() @@ -852,8 +847,8 @@ async def list_all_additional_issue_upload( resp = { "result_set": { "count": count, - "offset": offset, - "limit": limit, + "offset": get_query.offset, + "limit": get_query.limit, "total": total, }, "uploads": uploads, @@ -1043,11 +1038,6 @@ async def list_redeem_history( get_query: ListRedeemHistoryQuery = Depends(), ): """List redemption history""" - sort_item = get_query.sort_item - sort_order = get_query.sort_order - offset = get_query.offset - limit = get_query.limit - # Get token _token: Token | None = ( await db.scalars( @@ -1078,20 +1068,20 @@ async def list_redeem_history( count = total # Sort - sort_attr = getattr(IDXIssueRedeem, sort_item.value, None) - if sort_order == 0: # ASC + sort_attr = getattr(IDXIssueRedeem, get_query.sort_item.value, None) + if get_query.sort_order == 0: # ASC stmt = stmt.order_by(sort_attr) else: # DESC stmt = stmt.order_by(desc(sort_attr)) - if sort_item != IDXIssueRedeemSortItem.BLOCK_TIMESTAMP: + if get_query.sort_item != IDXIssueRedeemSortItem.BLOCK_TIMESTAMP: # NOTE: Set secondary sort for consistent results stmt = stmt.order_by(desc(IDXIssueRedeem.block_timestamp)) # Pagination - if limit is not None: - stmt = stmt.limit(limit) - if offset is not None: - stmt = stmt.offset(offset) + if get_query.limit is not None: + stmt = stmt.limit(get_query.limit) + if get_query.offset is not None: + stmt = stmt.offset(get_query.offset) _events: Sequence[IDXIssueRedeem] = (await db.scalars(stmt)).all() @@ -1113,8 +1103,8 @@ async def list_redeem_history( { "result_set": { "count": count, - "offset": offset, - "limit": limit, + "offset": get_query.offset, + "limit": get_query.limit, "total": total, }, "history": history, @@ -1213,10 +1203,6 @@ async def list_all_redeem_upload( get_query: ListAllRedeemUploadQuery = Depends(), issuer_address: Optional[str] = Header(None), ): - processed = get_query.processed - sort_order = get_query.sort_order - offset = get_query.offset - limit = get_query.limit # Get a list of uploads stmt = select(BatchIssueRedeemUpload).where( @@ -1233,22 +1219,22 @@ async def list_all_redeem_upload( total = await db.scalar(select(func.count()).select_from(stmt.subquery())) - if processed is not None: - stmt = stmt.where(BatchIssueRedeemUpload.processed == processed) + if get_query.processed is not None: + stmt = stmt.where(BatchIssueRedeemUpload.processed == get_query.processed) count = await db.scalar(select(func.count()).select_from(stmt.subquery())) # Sort - if sort_order == 0: # ASC + if get_query.sort_order == 0: # ASC stmt = stmt.order_by(BatchIssueRedeemUpload.created) else: # DESC stmt = stmt.order_by(desc(BatchIssueRedeemUpload.created)) # Pagination - if limit is not None: - stmt = stmt.limit(limit) - if offset is not None: - stmt = stmt.offset(offset) + if get_query.limit is not None: + stmt = stmt.limit(get_query.limit) + if get_query.offset is not None: + stmt = stmt.offset(get_query.offset) _upload_list: Sequence[BatchIssueRedeemUpload] = (await db.scalars(stmt)).all() @@ -1269,8 +1255,8 @@ async def list_all_redeem_upload( resp = { "result_set": { "count": count, - "offset": offset, - "limit": limit, + "offset": get_query.offset, + "limit": get_query.limit, "total": total, }, "uploads": uploads, @@ -1744,21 +1730,6 @@ async def list_all_holders( issuer_address: str = Header(...), ): """List all share token holders""" - include_former_holder = get_query.include_former_holder - balance = get_query.balance - balance_operator = get_query.balance_operator - pending_transfer = get_query.pending_transfer - pending_transfer_operator = get_query.pending_transfer_operator - locked = get_query.locked - locked_operator = get_query.locked_operator - account_address = get_query.account_address - holder_name = get_query.holder_name - key_manager = get_query.key_manager - sort_item = get_query.sort_item - sort_order = get_query.sort_order - offset = get_query.offset - limit = get_query.limit - # Validate Headers validate_headers(issuer_address=(issuer_address, address_is_valid_address)) @@ -1825,7 +1796,7 @@ async def list_all_holders( total = await db.scalar(select(func.count()).select_from(stmt.subquery())) - if not include_former_holder: + if not get_query.include_former_holder: stmt = stmt.where( or_( IDXPosition.balance != 0, @@ -1836,75 +1807,109 @@ async def list_all_holders( ) ) - if balance is not None and balance_operator is not None: - match balance_operator: + if get_query.balance is not None and get_query.balance_operator is not None: + match get_query.balance_operator: case ValueOperator.EQUAL: - stmt = stmt.where(IDXPosition.balance == balance) + stmt = stmt.where(IDXPosition.balance == get_query.balance) case ValueOperator.GTE: - stmt = stmt.where(IDXPosition.balance >= balance) + stmt = stmt.where(IDXPosition.balance >= get_query.balance) case ValueOperator.LTE: - stmt = stmt.where(IDXPosition.balance <= balance) + stmt = stmt.where(IDXPosition.balance <= get_query.balance) - if pending_transfer is not None and pending_transfer_operator is not None: - match pending_transfer_operator: + if ( + get_query.pending_transfer is not None + and get_query.pending_transfer_operator is not None + ): + match get_query.pending_transfer_operator: case ValueOperator.EQUAL: - stmt = stmt.where(IDXPosition.pending_transfer == pending_transfer) + stmt = stmt.where( + IDXPosition.pending_transfer == get_query.pending_transfer + ) case ValueOperator.GTE: - stmt = stmt.where(IDXPosition.pending_transfer >= pending_transfer) + stmt = stmt.where( + IDXPosition.pending_transfer >= get_query.pending_transfer + ) case ValueOperator.LTE: - stmt = stmt.where(IDXPosition.pending_transfer <= pending_transfer) + stmt = stmt.where( + IDXPosition.pending_transfer <= get_query.pending_transfer + ) - if locked is not None and locked_operator is not None: - match locked_operator: + if get_query.locked is not None and get_query.locked_operator is not None: + match get_query.locked_operator: case ValueOperator.EQUAL: - stmt = stmt.having(locked_value == locked) + stmt = stmt.having(locked_value == get_query.locked) case ValueOperator.GTE: - stmt = stmt.having(locked_value >= locked) + stmt = stmt.having(locked_value >= get_query.locked) case ValueOperator.LTE: - stmt = stmt.having(locked_value <= locked) + stmt = stmt.having(locked_value <= get_query.locked) - if account_address is not None: - stmt = stmt.where(IDXPosition.account_address.like("%" + account_address + "%")) + if ( + get_query.balance_and_pending_transfer is not None + and get_query.balance_and_pending_transfer_operator is not None + ): + match get_query.balance_and_pending_transfer_operator: + case ValueOperator.EQUAL: + stmt = stmt.where( + IDXPosition.balance + IDXPosition.pending_transfer + == get_query.balance_and_pending_transfer + ) + case ValueOperator.GTE: + stmt = stmt.where( + IDXPosition.balance + IDXPosition.pending_transfer + >= get_query.balance_and_pending_transfer + ) + case ValueOperator.LTE: + stmt = stmt.where( + IDXPosition.balance + IDXPosition.pending_transfer + <= get_query.balance_and_pending_transfer + ) + + if get_query.account_address is not None: + stmt = stmt.where( + IDXPosition.account_address.like("%" + get_query.account_address + "%") + ) - if holder_name is not None: + if get_query.holder_name is not None: stmt = stmt.where( IDXPersonalInfo._personal_info["name"] .as_string() - .like("%" + holder_name + "%") + .like("%" + get_query.holder_name + "%") ) - if key_manager is not None: + if get_query.key_manager is not None: stmt = stmt.where( IDXPersonalInfo._personal_info["key_manager"] .as_string() - .like("%" + key_manager + "%") + .like("%" + get_query.key_manager + "%") ) count = await db.scalar(select(func.count()).select_from(stmt.subquery())) # Sort - if sort_item == ListAllHoldersSortItem.holder_name: + if get_query.sort_item == ListAllHoldersSortItem.holder_name: sort_attr = IDXPersonalInfo._personal_info["name"].as_string() - elif sort_item == ListAllHoldersSortItem.key_manager: + elif get_query.sort_item == ListAllHoldersSortItem.key_manager: sort_attr = IDXPersonalInfo._personal_info["key_manager"].as_string() - elif sort_item == ListAllHoldersSortItem.locked: + elif get_query.sort_item == ListAllHoldersSortItem.locked: sort_attr = locked_value + elif get_query.sort_item == ListAllHoldersSortItem.balance_and_pending_transfer: + sort_attr = IDXPosition.balance + IDXPosition.pending_transfer else: - sort_attr = getattr(IDXPosition, sort_item) + sort_attr = getattr(IDXPosition, get_query.sort_item) - if sort_order == 0: # ASC + if get_query.sort_order == 0: # ASC stmt = stmt.order_by(asc(sort_attr)) else: # DESC stmt = stmt.order_by(desc(sort_attr)) - if sort_item != ListAllHoldersSortItem.created: + if get_query.sort_item != ListAllHoldersSortItem.created: # NOTE: Set secondary sort for consistent results stmt = stmt.order_by(asc(IDXPosition.created)) # Pagination - if limit is not None: - stmt = stmt.limit(limit) - if offset is not None: - stmt = stmt.offset(offset) + if get_query.limit is not None: + stmt = stmt.limit(get_query.limit) + if get_query.offset is not None: + stmt = stmt.offset(get_query.offset) _holders: Sequence[ tuple[IDXPosition, int, IDXPersonalInfo | None, datetime | None] @@ -1957,8 +1962,8 @@ async def list_all_holders( "result_set": { "count": count, "total": total, - "limit": limit, - "offset": offset, + "limit": get_query.limit, + "offset": get_query.offset, }, "holders": holders, } @@ -2282,11 +2287,6 @@ async def list_all_personal_info_batch_registration_uploads( get_query: ListAllPersonalInfoBatchRegistrationUploadQuery = Depends(), ): """List all personal information batch registration uploads""" - status = get_query.status - sort_order = get_query.sort_order - offset = get_query.offset - limit = get_query.limit - # Verify that the token is issued by the issuer_address _token: Token | None = ( await db.scalars( @@ -2314,22 +2314,22 @@ async def list_all_personal_info_batch_registration_uploads( total = await db.scalar(select(func.count()).select_from(stmt.subquery())) - if status is not None: - stmt = stmt.where(BatchRegisterPersonalInfoUpload.status == status) + if get_query.status is not None: + stmt = stmt.where(BatchRegisterPersonalInfoUpload.status == get_query.status) count = await db.scalar(select(func.count()).select_from(stmt.subquery())) # Sort - if sort_order == 0: # ASC + if get_query.sort_order == 0: # ASC stmt = stmt.order_by(BatchRegisterPersonalInfoUpload.created) else: # DESC stmt = stmt.order_by(desc(BatchRegisterPersonalInfoUpload.created)) # Pagination - if limit is not None: - stmt = stmt.limit(limit) - if offset is not None: - stmt = stmt.offset(offset) + if get_query.limit is not None: + stmt = stmt.limit(get_query.limit) + if get_query.offset is not None: + stmt = stmt.offset(get_query.offset) _upload_list: Sequence[BatchRegisterPersonalInfoUpload] = ( await db.scalars(stmt) @@ -2350,8 +2350,8 @@ async def list_all_personal_info_batch_registration_uploads( { "result_set": { "count": count, - "offset": offset, - "limit": limit, + "offset": get_query.offset, + "limit": get_query.limit, "total": total, }, "uploads": uploads, @@ -3082,14 +3082,6 @@ async def list_token_transfer_approval_history( get_query: ListTransferApprovalHistoryQuery = Depends(), ): """List token transfer approval history""" - from_address = get_query.from_address - to_address = get_query.to_address - status = get_query.status - sort_item = get_query.sort_item - sort_order = get_query.sort_order - offset = get_query.offset - limit = get_query.limit - # Get token _token: Token | None = ( await db.scalars( @@ -3206,33 +3198,33 @@ async def list_token_transfer_approval_history( total = await db.scalar(select(func.count()).select_from(stmt.subquery())) # Search Filter - if from_address is not None: - stmt = stmt.where(subquery.from_address == from_address) - if to_address is not None: - stmt = stmt.where(subquery.to_address == to_address) - if status is not None: - stmt = stmt.where(literal_column("status").in_(status)) + if get_query.from_address is not None: + stmt = stmt.where(subquery.from_address == get_query.from_address) + if get_query.to_address is not None: + stmt = stmt.where(subquery.to_address == get_query.to_address) + if get_query.status is not None: + stmt = stmt.where(literal_column("status").in_(get_query.status)) count = await db.scalar(select(func.count()).select_from(stmt.subquery())) # Sort - if sort_item != IDXTransferApprovalsSortItem.STATUS: - sort_attr = getattr(subquery, sort_item, None) + if get_query.sort_item != IDXTransferApprovalsSortItem.STATUS: + sort_attr = getattr(subquery, get_query.sort_item, None) else: sort_attr = literal_column("status") - if sort_order == 0: # ASC + if get_query.sort_order == 0: # ASC stmt = stmt.order_by(sort_attr) else: # DESC stmt = stmt.order_by(desc(sort_attr)) - if sort_item != IDXTransferApprovalsSortItem.ID: + if get_query.sort_item != IDXTransferApprovalsSortItem.ID: # NOTE: Set secondary sort for consistent results stmt = stmt.order_by(desc(subquery.id)) # Pagination - if limit is not None: - stmt = stmt.limit(limit) - if offset is not None: - stmt = stmt.offset(offset) + if get_query.limit is not None: + stmt = stmt.limit(get_query.limit) + if get_query.offset is not None: + stmt = stmt.offset(get_query.offset) _transfer_approvals: Sequence[ tuple[ @@ -3360,8 +3352,8 @@ async def list_token_transfer_approval_history( { "result_set": { "count": count, - "offset": offset, - "limit": limit, + "offset": get_query.offset, + "limit": get_query.limit, "total": total, }, "transfer_approval_history": transfer_approval_history, diff --git a/docs/ibet_prime.yaml b/docs/ibet_prime.yaml index 3f886591..e22f4aab 100644 --- a/docs/ibet_prime.yaml +++ b/docs/ibet_prime.yaml @@ -348,8 +348,8 @@ paths: application/json: schema: anyOf: - - $ref: '#/components/schemas/AuthTokenAlreadyExistsErrorResponse' - $ref: '#/components/schemas/InvalidParameterErrorResponse' + - $ref: '#/components/schemas/AuthTokenAlreadyExistsErrorResponse' title: Response 400 Create Auth Token Accounts Issuer Address Auth Token Post delete: @@ -607,10 +607,10 @@ paths: application/json: schema: anyOf: + - $ref: '#/components/schemas/InvalidParameterErrorResponse' - $ref: '#/components/schemas/ContractRevertErrorResponse' - $ref: '#/components/schemas/OperationNotSupportedVersionErrorResponse' - $ref: '#/components/schemas/SendTransactionErrorResponse' - - $ref: '#/components/schemas/InvalidParameterErrorResponse' title: Response 400 Update Token Bond Tokens Token Address Post /bond/tokens/{token_address}/history: get: @@ -882,9 +882,9 @@ paths: application/json: schema: anyOf: + - $ref: '#/components/schemas/InvalidParameterErrorResponse' - $ref: '#/components/schemas/ContractRevertErrorResponse' - $ref: '#/components/schemas/SendTransactionErrorResponse' - - $ref: '#/components/schemas/InvalidParameterErrorResponse' title: Response 400 Additional Issue Bond Tokens Token Address Additional Issue Post /bond/tokens/{token_address}/additional_issue/batch: @@ -1242,9 +1242,9 @@ paths: application/json: schema: anyOf: + - $ref: '#/components/schemas/InvalidParameterErrorResponse' - $ref: '#/components/schemas/ContractRevertErrorResponse' - $ref: '#/components/schemas/SendTransactionErrorResponse' - - $ref: '#/components/schemas/InvalidParameterErrorResponse' title: Response 400 Redeem Token Bond Tokens Token Address Redeem Post /bond/tokens/{token_address}/redeem/batch: @@ -1556,8 +1556,8 @@ paths: application/json: schema: anyOf: - - $ref: '#/components/schemas/OperationNotSupportedVersionErrorResponse' - $ref: '#/components/schemas/InvalidParameterErrorResponse' + - $ref: '#/components/schemas/OperationNotSupportedVersionErrorResponse' title: Response 400 Schedule New Update Event Bond Tokens Token Address Scheduled Events Post /bond/tokens/{token_address}/scheduled_events/{scheduled_event_id}: @@ -1763,6 +1763,29 @@ paths: title: Locked Operator description: search condition of locked amount(0:equal, 1:greater than or equal, 2:less than or equal) + - name: balance_and_pending_transfer + in: query + required: false + schema: + anyOf: + - type: integer + - type: 'null' + description: number of balance plus pending transfer amount + title: Balance And Pending Transfer + description: number of balance plus pending transfer amount + - name: balance_and_pending_transfer_operator + in: query + required: false + schema: + anyOf: + - $ref: '#/components/schemas/ValueOperator' + - type: 'null' + description: search condition of balance plus pending transfer(0:equal, + 1:greater than or equal, 2:less than or equal) + default: 0 + title: Balance And Pending Transfer Operator + description: search condition of balance plus pending transfer(0:equal, + 1:greater than or equal, 2:less than or equal) - name: account_address in: query required: false @@ -2039,9 +2062,9 @@ paths: application/json: schema: anyOf: + - $ref: '#/components/schemas/InvalidParameterErrorResponse' - $ref: '#/components/schemas/ContractRevertErrorResponse' - $ref: '#/components/schemas/SendTransactionErrorResponse' - - $ref: '#/components/schemas/InvalidParameterErrorResponse' title: Response 400 Register Holder Personal Info Bond Tokens Token Address Personal Info Post /bond/tokens/{token_address}/personal_info/batch: @@ -2451,9 +2474,9 @@ paths: application/json: schema: anyOf: + - $ref: '#/components/schemas/InvalidParameterErrorResponse' - $ref: '#/components/schemas/ContractRevertErrorResponse' - $ref: '#/components/schemas/SendTransactionErrorResponse' - - $ref: '#/components/schemas/InvalidParameterErrorResponse' title: Response 400 Transfer Ownership Bond Transfers Post /bond/transfers/{token_address}: get: @@ -2875,10 +2898,10 @@ paths: application/json: schema: anyOf: + - $ref: '#/components/schemas/OperationNotAllowedStateErrorResponse' + - $ref: '#/components/schemas/InvalidParameterErrorResponse' - $ref: '#/components/schemas/ContractRevertErrorResponse' - $ref: '#/components/schemas/SendTransactionErrorResponse' - - $ref: '#/components/schemas/InvalidParameterErrorResponse' - - $ref: '#/components/schemas/OperationNotAllowedStateErrorResponse' title: Response 400 Update Transfer Approval Bond Transfer Approvals Token Address Id Post get: @@ -3125,9 +3148,9 @@ paths: application/json: schema: anyOf: + - $ref: '#/components/schemas/InvalidParameterErrorResponse' - $ref: '#/components/schemas/ContractRevertErrorResponse' - $ref: '#/components/schemas/SendTransactionErrorResponse' - - $ref: '#/components/schemas/InvalidParameterErrorResponse' title: Response 400 Create Account E2E Messaging Accounts Post /e2e_messaging/accounts/{account_address}: get: @@ -3706,8 +3729,8 @@ paths: application/json: schema: anyOf: - - $ref: '#/components/schemas/Integer64bitLimitExceededErrorResponse' - $ref: '#/components/schemas/InvalidParameterErrorResponse' + - $ref: '#/components/schemas/Integer64bitLimitExceededErrorResponse' title: Response 400 Retrieve Ledger History Ledger Token Address History Ledger Id Get /ledger/{token_address}/template: @@ -4533,9 +4556,9 @@ paths: application/json: schema: anyOf: + - $ref: '#/components/schemas/InvalidParameterErrorResponse' - $ref: '#/components/schemas/ContractRevertErrorResponse' - $ref: '#/components/schemas/SendTransactionErrorResponse' - - $ref: '#/components/schemas/InvalidParameterErrorResponse' title: Response 400 Force Unlock Positions Account Address Force Unlock Post /positions/{account_address}/{token_address}: @@ -4796,10 +4819,10 @@ paths: application/json: schema: anyOf: + - $ref: '#/components/schemas/InvalidParameterErrorResponse' - $ref: '#/components/schemas/ContractRevertErrorResponse' - $ref: '#/components/schemas/OperationNotSupportedVersionErrorResponse' - $ref: '#/components/schemas/SendTransactionErrorResponse' - - $ref: '#/components/schemas/InvalidParameterErrorResponse' title: Response 400 Update Token Share Tokens Token Address Post /share/tokens/{token_address}/history: get: @@ -5071,9 +5094,9 @@ paths: application/json: schema: anyOf: + - $ref: '#/components/schemas/InvalidParameterErrorResponse' - $ref: '#/components/schemas/ContractRevertErrorResponse' - $ref: '#/components/schemas/SendTransactionErrorResponse' - - $ref: '#/components/schemas/InvalidParameterErrorResponse' title: Response 400 Additional Issue Share Tokens Token Address Additional Issue Post /share/tokens/{token_address}/additional_issue/batch: @@ -5431,9 +5454,9 @@ paths: application/json: schema: anyOf: + - $ref: '#/components/schemas/InvalidParameterErrorResponse' - $ref: '#/components/schemas/ContractRevertErrorResponse' - $ref: '#/components/schemas/SendTransactionErrorResponse' - - $ref: '#/components/schemas/InvalidParameterErrorResponse' title: Response 400 Redeem Token Share Tokens Token Address Redeem Post /share/tokens/{token_address}/redeem/batch: @@ -5745,8 +5768,8 @@ paths: application/json: schema: anyOf: - - $ref: '#/components/schemas/OperationNotSupportedVersionErrorResponse' - $ref: '#/components/schemas/InvalidParameterErrorResponse' + - $ref: '#/components/schemas/OperationNotSupportedVersionErrorResponse' title: Response 400 Schedule New Update Event Share Tokens Token Address Scheduled Events Post /share/tokens/{token_address}/scheduled_events/{scheduled_event_id}: @@ -5952,6 +5975,29 @@ paths: title: Locked Operator description: search condition of locked amount(0:equal, 1:greater than or equal, 2:less than or equal) + - name: balance_and_pending_transfer + in: query + required: false + schema: + anyOf: + - type: integer + - type: 'null' + description: number of balance plus pending transfer amount + title: Balance And Pending Transfer + description: number of balance plus pending transfer amount + - name: balance_and_pending_transfer_operator + in: query + required: false + schema: + anyOf: + - $ref: '#/components/schemas/ValueOperator' + - type: 'null' + description: search condition of balance plus pending transfer(0:equal, + 1:greater than or equal, 2:less than or equal) + default: 0 + title: Balance And Pending Transfer Operator + description: search condition of balance plus pending transfer(0:equal, + 1:greater than or equal, 2:less than or equal) - name: account_address in: query required: false @@ -6228,9 +6274,9 @@ paths: application/json: schema: anyOf: + - $ref: '#/components/schemas/InvalidParameterErrorResponse' - $ref: '#/components/schemas/ContractRevertErrorResponse' - $ref: '#/components/schemas/SendTransactionErrorResponse' - - $ref: '#/components/schemas/InvalidParameterErrorResponse' title: Response 400 Register Holder Personal Info Share Tokens Token Address Personal Info Post /share/tokens/{token_address}/personal_info/batch: @@ -6640,9 +6686,9 @@ paths: application/json: schema: anyOf: + - $ref: '#/components/schemas/InvalidParameterErrorResponse' - $ref: '#/components/schemas/ContractRevertErrorResponse' - $ref: '#/components/schemas/SendTransactionErrorResponse' - - $ref: '#/components/schemas/InvalidParameterErrorResponse' title: Response 400 Transfer Ownership Share Transfers Post /share/transfers/{token_address}: get: @@ -7065,10 +7111,10 @@ paths: application/json: schema: anyOf: + - $ref: '#/components/schemas/OperationNotAllowedStateErrorResponse' + - $ref: '#/components/schemas/InvalidParameterErrorResponse' - $ref: '#/components/schemas/ContractRevertErrorResponse' - $ref: '#/components/schemas/SendTransactionErrorResponse' - - $ref: '#/components/schemas/InvalidParameterErrorResponse' - - $ref: '#/components/schemas/OperationNotAllowedStateErrorResponse' title: Response 400 Update Transfer Approval Share Transfer Approvals Token Address Id Post get: @@ -8049,8 +8095,8 @@ paths: application/json: schema: anyOf: - - $ref: '#/components/schemas/SendTransactionErrorResponse' - $ref: '#/components/schemas/InvalidParameterErrorResponse' + - $ref: '#/components/schemas/SendTransactionErrorResponse' title: Response 400 Recordnewfreezelog /freeze_log/logs/{log_index}: post: @@ -8095,8 +8141,8 @@ paths: application/json: schema: anyOf: - - $ref: '#/components/schemas/SendTransactionErrorResponse' - $ref: '#/components/schemas/InvalidParameterErrorResponse' + - $ref: '#/components/schemas/SendTransactionErrorResponse' title: Response 400 Updatefreezelog get: tags: @@ -8460,8 +8506,8 @@ paths: application/json: schema: anyOf: - - $ref: '#/components/schemas/SendTransactionErrorResponse' - $ref: '#/components/schemas/InvalidParameterErrorResponse' + - $ref: '#/components/schemas/SendTransactionErrorResponse' title: Response 400 Createdvpdelivery /settlement/dvp/{exchange_address}/delivery/{delivery_id}: get: @@ -8587,14 +8633,17 @@ paths: application/json: schema: anyOf: - - $ref: '#/components/schemas/SendTransactionErrorResponse' - $ref: '#/components/schemas/InvalidParameterErrorResponse' + - $ref: '#/components/schemas/SendTransactionErrorResponse' title: Response 400 Updatedvpdelivery components: schemas: AbortDVPDeliveryRequest: properties: operation_type: + type: string + enum: + - Abort const: Abort title: Operation Type account_address: @@ -8726,6 +8775,9 @@ components: 2:CHANGING 3:SET AuthTokenAlreadyExistsErrorCode: + type: integer + enum: + - 3 const: 3 title: AuthTokenAlreadyExistsErrorCode AuthTokenAlreadyExistsErrorMetainfo: @@ -8758,6 +8810,9 @@ components: - detail title: AuthTokenAlreadyExistsErrorResponse AuthorizationErrorCode: + type: integer + enum: + - 1 const: 1 title: AuthorizationErrorCode AuthorizationErrorMetainfo: @@ -8839,6 +8894,9 @@ components: type: string title: Created notice_type: + type: string + enum: + - BatchIssueProcessed const: BatchIssueProcessed title: Notice Type metainfo: @@ -8945,6 +9003,9 @@ components: type: string title: Created notice_type: + type: string + enum: + - BatchRegisterPersonalInfoError const: BatchRegisterPersonalInfoError title: Notice Type metainfo: @@ -9243,6 +9304,9 @@ components: type: string title: Created notice_type: + type: string + enum: + - BulkTransferError const: BulkTransferError title: Notice Type metainfo: @@ -9367,6 +9431,9 @@ components: CancelDVPDeliveryRequest: properties: operation_type: + type: string + enum: + - Cancel const: Cancel title: Operation Type type: object @@ -9668,6 +9735,9 @@ components: type: string title: Created notice_type: + type: string + enum: + - CreateLedgerInfo const: CreateLedgerInfo title: Notice Type metainfo: @@ -10245,6 +10315,9 @@ components: FinishDVPDeliveryRequest: properties: operation_type: + type: string + enum: + - Finish const: Finish title: Operation Type account_address: @@ -10524,21 +10597,30 @@ components: anyOf: - type: string pattern: ^(19[0-9]{2}|20[0-9]{2})(0[1-9]|1[0-2])(0[1-9]|[12][0-9]|3[01])$ - - const: '' + - type: string + enum: + - '' + const: '' - type: 'null' title: Dividend Record Date dividend_payment_date: anyOf: - type: string pattern: ^(19[0-9]{2}|20[0-9]{2})(0[1-9]|1[0-2])(0[1-9]|[12][0-9]|3[01])$ - - const: '' + - type: string + enum: + - '' + const: '' - type: 'null' title: Dividend Payment Date cancellation_date: anyOf: - type: string pattern: ^(19[0-9]{2}|20[0-9]{2})(0[1-9]|1[0-2])(0[1-9]|[12][0-9]|3[01])$ - - const: '' + - type: string + enum: + - '' + const: '' - type: 'null' title: Cancellation Date transferable: @@ -10769,21 +10851,30 @@ components: anyOf: - type: string pattern: ^(19[0-9]{2}|20[0-9]{2})(0[1-9]|1[0-2])(0[1-9]|[12][0-9]|3[01])$ - - const: '' + - type: string + enum: + - '' + const: '' - type: 'null' title: Cancellation Date dividend_record_date: anyOf: - type: string pattern: ^(19[0-9]{2}|20[0-9]{2})(0[1-9]|1[0-2])(0[1-9]|[12][0-9]|3[01])$ - - const: '' + - type: string + enum: + - '' + const: '' - type: 'null' title: Dividend Record Date dividend_payment_date: anyOf: - type: string pattern: ^(19[0-9]{2}|20[0-9]{2})(0[1-9]|1[0-2])(0[1-9]|[12][0-9]|3[01])$ - - const: '' + - type: string + enum: + - '' + const: '' - type: 'null' title: Dividend Payment Date dividends: @@ -11287,7 +11378,10 @@ components: - type: string maxLength: 3 minLength: 3 - - const: '' + - type: string + enum: + - '' + const: '' - type: 'null' title: Interest Payment Currency redemption_value: @@ -11302,7 +11396,10 @@ components: - type: string maxLength: 3 minLength: 3 - - const: '' + - type: string + enum: + - '' + const: '' - type: 'null' title: Redemption Value Currency base_fx_rate: @@ -11373,6 +11470,9 @@ components: title: IbetStraightBondUpdate description: ibet Straight Bond schema (Update) Integer64bitLimitExceededErrorCode: + type: integer + enum: + - 5 const: 5 title: Integer64bitLimitExceededErrorCode Integer64bitLimitExceededErrorMetainfo: @@ -11405,6 +11505,9 @@ components: - detail title: Integer64bitLimitExceededErrorResponse InvalidParameterErrorCode: + type: integer + enum: + - 1 const: 1 title: InvalidParameterErrorCode InvalidParameterErrorMetainfo: @@ -11476,6 +11579,9 @@ components: type: string title: Created notice_type: + type: string + enum: + - IssueError const: IssueError title: Notice Type metainfo: @@ -11742,6 +11848,7 @@ components: - balance - pending_transfer - locked + - balance_and_pending_transfer - key_manager - holder_name title: ListAllHoldersSortItem @@ -12126,6 +12233,9 @@ components: type: string title: Created notice_type: + type: string + enum: + - LockInfo const: LockInfo title: Notice Type metainfo: @@ -12190,6 +12300,9 @@ components: title: NotificationsListResponse description: Notifications List schema (Response) OperationNotAllowedStateErrorCode: + type: integer + enum: + - 101 const: 101 title: OperationNotAllowedStateErrorCode OperationNotAllowedStateErrorMetainfo: @@ -12224,6 +12337,9 @@ components: description: Error returned when server-side data is not ready to process the request OperationNotSupportedVersionErrorCode: + type: integer + enum: + - 6 const: 6 title: OperationNotSupportedVersionErrorCode OperationNotSupportedVersionErrorMetainfo: @@ -12510,6 +12626,9 @@ components: title: RegisterPersonalInfoRequest description: Register Personal Information schema (REQUEST) ResponseLimitExceededErrorCode: + type: integer + enum: + - 4 const: 4 title: ResponseLimitExceededErrorCode ResponseLimitExceededErrorMetainfo: @@ -12906,6 +13025,9 @@ components: type: string title: Created notice_type: + type: string + enum: + - ScheduleEventError const: ScheduleEventError title: Notice Type metainfo: @@ -12969,9 +13091,14 @@ components: description: scheduled event (Response) ScheduledEventType: type: string + enum: + - Update const: Update title: ScheduledEventType SendTransactionErrorCode: + type: integer + enum: + - 2 const: 2 title: SendTransactionErrorCode SendTransactionErrorMetainfo: @@ -13004,6 +13131,9 @@ components: - detail title: SendTransactionErrorResponse ServiceUnavailableErrorCode: + type: integer + enum: + - 1 const: 1 title: ServiceUnavailableErrorCode ServiceUnavailableErrorMetainfo: @@ -13176,6 +13306,9 @@ components: type: string title: Created notice_type: + type: string + enum: + - TransferApprovalInfo const: TransferApprovalInfo title: Notice Type metainfo: @@ -13677,6 +13810,9 @@ components: type: string title: Created notice_type: + type: string + enum: + - UnlockInfo const: UnlockInfo title: Notice Type metainfo: diff --git a/tests/test_app_routers_bond_tokens_{token_address}_holders_GET.py b/tests/test_app_routers_bond_tokens_{token_address}_holders_GET.py index e07bef98..db4a3fcb 100644 --- a/tests/test_app_routers_bond_tokens_{token_address}_holders_GET.py +++ b/tests/test_app_routers_bond_tokens_{token_address}_holders_GET.py @@ -2555,9 +2555,613 @@ def test_normal_4_4_3(self, client, db): ], } - # + # + # Search filter: balance + pending_transfer & "=" + def test_normal_4_5_1(self, client, db): + user = config_eth_account("user1") + _issuer_address = user["address"] + _token_address = "0x82b1c9374aB625380bd498a3d9dF4033B8A0E3Bb" + _account_address_1 = "0xb75c7545b9230FEe99b7af370D38eBd3DAD929f7" + _account_address_2 = "0x3F198534Bbe3B2a197d3B317d41392F348EAC707" + _account_address_3 = "0x8277D905F37F8a9717F5718d0daC21495dFE74bf" + + account = Account() + account.issuer_address = _issuer_address + db.add(account) + + token = Token() + token.type = TokenType.IBET_STRAIGHT_BOND.value + token.tx_hash = "" + token.issuer_address = _issuer_address + token.token_address = _token_address + token.abi = "" + token.version = TokenVersion.V_24_06 + db.add(token) + + # prepare data: account_address_1 + idx_position_1 = IDXPosition() + idx_position_1.token_address = _token_address + idx_position_1.account_address = _account_address_1 + idx_position_1.balance = 10 + idx_position_1.exchange_balance = 11 + idx_position_1.exchange_commitment = 12 + idx_position_1.pending_transfer = 5 + idx_position_1.modified = datetime(2023, 10, 24, 0, 0, 0) + db.add(idx_position_1) + + idx_locked_position = IDXLockedPosition() + idx_locked_position.token_address = _token_address + idx_locked_position.lock_address = ( + "0x1234567890123456789012345678900000000001" # lock address 1 + ) + idx_locked_position.account_address = _account_address_1 + idx_locked_position.value = 5 + idx_locked_position.modified = datetime(2023, 10, 24, 1, 0, 0) + db.add(idx_locked_position) + + idx_locked_position = IDXLockedPosition() + idx_locked_position.token_address = _token_address + idx_locked_position.lock_address = ( + "0x1234567890123456789012345678900000000002" # lock address 2 + ) + idx_locked_position.account_address = _account_address_1 + idx_locked_position.value = 5 + idx_locked_position.modified = datetime(2023, 10, 24, 1, 10, 0) + db.add(idx_locked_position) + + idx_personal_info_1 = IDXPersonalInfo() + idx_personal_info_1.account_address = _account_address_1 + idx_personal_info_1.issuer_address = _issuer_address + idx_personal_info_1.personal_info = { + "key_manager": "key_manager_test1", + "name": "name_test1", + "postal_code": "postal_code_test1", + "address": "address_test1", + "email": "email_test1", + "birth": "birth_test1", + "is_corporate": False, + "tax_category": 10, + } + db.add(idx_personal_info_1) + + # prepare data: account_address_2 + idx_position_2 = IDXPosition() + idx_position_2.token_address = _token_address + idx_position_2.account_address = _account_address_2 + idx_position_2.balance = 20 + idx_position_2.exchange_balance = 21 + idx_position_2.exchange_commitment = 22 + idx_position_2.pending_transfer = 10 + idx_position_2.modified = datetime(2023, 10, 24, 2, 0, 0) + db.add(idx_position_2) + + idx_locked_position = IDXLockedPosition() + idx_locked_position.token_address = _token_address + idx_locked_position.lock_address = ( + "0x1234567890123456789012345678900000000001" # lock address 1 + ) + idx_locked_position.account_address = _account_address_2 + idx_locked_position.value = 10 + idx_locked_position.modified = datetime(2023, 10, 24, 2, 10, 0) + db.add(idx_locked_position) + + idx_locked_position = IDXLockedPosition() + idx_locked_position.token_address = _token_address + idx_locked_position.lock_address = ( + "0x1234567890123456789012345678900000000002" # lock address 2 + ) + idx_locked_position.account_address = _account_address_2 + idx_locked_position.value = 10 + idx_locked_position.modified = datetime(2023, 10, 24, 2, 20, 0) + db.add(idx_locked_position) + + # prepare data: account_address_3 + idx_position_3 = IDXPosition() + idx_position_3.token_address = _token_address + idx_position_3.account_address = _account_address_3 + idx_position_3.balance = 99 + idx_position_3.exchange_balance = 99 + idx_position_3.exchange_commitment = 99 + idx_position_3.pending_transfer = 99 + idx_position_3.modified = datetime(2023, 10, 24, 3, 0, 0) + db.add(idx_position_3) + + idx_locked_position = IDXLockedPosition() + idx_locked_position.token_address = _token_address + idx_locked_position.lock_address = ( + "0x1234567890123456789012345678900000000001" # lock address 1 + ) + idx_locked_position.account_address = _account_address_3 + idx_locked_position.value = 15 + idx_locked_position.modified = datetime(2023, 10, 24, 4, 0, 0) + db.add(idx_locked_position) + + idx_locked_position = IDXLockedPosition() + idx_locked_position.token_address = _token_address + idx_locked_position.lock_address = ( + "0x1234567890123456789012345678900000000002" # lock address 2 + ) + idx_locked_position.account_address = _account_address_3 + idx_locked_position.value = 15 + idx_locked_position.modified = datetime(2023, 10, 24, 5, 0, 0) + db.add(idx_locked_position) + + # Other locked position + _locked_position = IDXLockedPosition() + _locked_position.token_address = "other_token_address" + _locked_position.lock_address = ( + "0x1234567890123456789012345678900000000002" # lock address 2 + ) + _locked_position.account_address = _account_address_1 + _locked_position.value = 5 + _locked_position.modified = datetime(2023, 10, 25, 0, 2, 0) + db.add(_locked_position) + + idx_personal_info_3 = IDXPersonalInfo() + idx_personal_info_3.account_address = _account_address_3 + idx_personal_info_3.issuer_address = _issuer_address + idx_personal_info_3.personal_info = { + "key_manager": "key_manager_test1", + "name": "name_test3", + "postal_code": "postal_code_test3", + "address": "address_test3", + "email": "email_test3", + "birth": "birth_test3", + # PersonalInfo is partially registered. + } + db.add(idx_personal_info_3) + + db.commit() + + # request target API + resp = client.get( + self.base_url.format(_token_address), + headers={"issuer-address": _issuer_address}, + params={ + "balance_and_pending_transfer": 30, + "balance_and_pending_transfer_operator": 0, + }, + ) + + # assertion + assert resp.status_code == 200 + assert resp.json() == { + "result_set": {"count": 1, "total": 3, "offset": None, "limit": None}, + "holders": [ + { + "account_address": _account_address_2, + "personal_information": { + "key_manager": None, + "name": None, + "postal_code": None, + "address": None, + "email": None, + "birth": None, + "is_corporate": None, + "tax_category": None, + }, + "balance": 20, + "exchange_balance": 21, + "exchange_commitment": 22, + "pending_transfer": 10, + "locked": 20, + "modified": "2023-10-24T02:20:00", + }, + ], + } + + # + # Search filter: balance + pending_transfer & ">=" + def test_normal_4_5_2(self, client, db): + user = config_eth_account("user1") + _issuer_address = user["address"] + _token_address = "0x82b1c9374aB625380bd498a3d9dF4033B8A0E3Bb" + _account_address_1 = "0xb75c7545b9230FEe99b7af370D38eBd3DAD929f7" + _account_address_2 = "0x3F198534Bbe3B2a197d3B317d41392F348EAC707" + _account_address_3 = "0x8277D905F37F8a9717F5718d0daC21495dFE74bf" + + account = Account() + account.issuer_address = _issuer_address + db.add(account) + + token = Token() + token.type = TokenType.IBET_STRAIGHT_BOND.value + token.tx_hash = "" + token.issuer_address = _issuer_address + token.token_address = _token_address + token.abi = "" + token.version = TokenVersion.V_24_06 + db.add(token) + + # prepare data: account_address_1 + idx_position_1 = IDXPosition() + idx_position_1.token_address = _token_address + idx_position_1.account_address = _account_address_1 + idx_position_1.balance = 10 + idx_position_1.exchange_balance = 11 + idx_position_1.exchange_commitment = 12 + idx_position_1.pending_transfer = 5 + idx_position_1.modified = datetime(2023, 10, 24, 0, 0, 0) + db.add(idx_position_1) + + idx_locked_position = IDXLockedPosition() + idx_locked_position.token_address = _token_address + idx_locked_position.lock_address = ( + "0x1234567890123456789012345678900000000001" # lock address 1 + ) + idx_locked_position.account_address = _account_address_1 + idx_locked_position.value = 5 + idx_locked_position.modified = datetime(2023, 10, 24, 1, 0, 0) + db.add(idx_locked_position) + + idx_locked_position = IDXLockedPosition() + idx_locked_position.token_address = _token_address + idx_locked_position.lock_address = ( + "0x1234567890123456789012345678900000000002" # lock address 2 + ) + idx_locked_position.account_address = _account_address_1 + idx_locked_position.value = 5 + idx_locked_position.modified = datetime(2023, 10, 24, 1, 10, 0) + db.add(idx_locked_position) + + idx_personal_info_1 = IDXPersonalInfo() + idx_personal_info_1.account_address = _account_address_1 + idx_personal_info_1.issuer_address = _issuer_address + idx_personal_info_1.personal_info = { + "key_manager": "key_manager_test1", + "name": "name_test1", + "postal_code": "postal_code_test1", + "address": "address_test1", + "email": "email_test1", + "birth": "birth_test1", + "is_corporate": False, + "tax_category": 10, + } + db.add(idx_personal_info_1) + + # prepare data: account_address_2 + idx_position_2 = IDXPosition() + idx_position_2.token_address = _token_address + idx_position_2.account_address = _account_address_2 + idx_position_2.balance = 20 + idx_position_2.exchange_balance = 21 + idx_position_2.exchange_commitment = 22 + idx_position_2.pending_transfer = 10 + idx_position_2.modified = datetime(2023, 10, 24, 2, 0, 0) + db.add(idx_position_2) + + idx_locked_position = IDXLockedPosition() + idx_locked_position.token_address = _token_address + idx_locked_position.lock_address = ( + "0x1234567890123456789012345678900000000001" # lock address 1 + ) + idx_locked_position.account_address = _account_address_2 + idx_locked_position.value = 10 + idx_locked_position.modified = datetime(2023, 10, 24, 2, 10, 0) + db.add(idx_locked_position) + + idx_locked_position = IDXLockedPosition() + idx_locked_position.token_address = _token_address + idx_locked_position.lock_address = ( + "0x1234567890123456789012345678900000000002" # lock address 2 + ) + idx_locked_position.account_address = _account_address_2 + idx_locked_position.value = 10 + idx_locked_position.modified = datetime(2023, 10, 24, 2, 20, 0) + db.add(idx_locked_position) + + # prepare data: account_address_3 + idx_position_3 = IDXPosition() + idx_position_3.token_address = _token_address + idx_position_3.account_address = _account_address_3 + idx_position_3.balance = 99 + idx_position_3.exchange_balance = 99 + idx_position_3.exchange_commitment = 99 + idx_position_3.pending_transfer = 99 + idx_position_3.modified = datetime(2023, 10, 24, 3, 0, 0) + db.add(idx_position_3) + + idx_locked_position = IDXLockedPosition() + idx_locked_position.token_address = _token_address + idx_locked_position.lock_address = ( + "0x1234567890123456789012345678900000000001" # lock address 1 + ) + idx_locked_position.account_address = _account_address_3 + idx_locked_position.value = 15 + idx_locked_position.modified = datetime(2023, 10, 24, 4, 0, 0) + db.add(idx_locked_position) + + idx_locked_position = IDXLockedPosition() + idx_locked_position.token_address = _token_address + idx_locked_position.lock_address = ( + "0x1234567890123456789012345678900000000002" # lock address 2 + ) + idx_locked_position.account_address = _account_address_3 + idx_locked_position.value = 15 + idx_locked_position.modified = datetime(2023, 10, 24, 5, 0, 0) + db.add(idx_locked_position) + + # Other locked position + _locked_position = IDXLockedPosition() + _locked_position.token_address = "other_token_address" + _locked_position.lock_address = ( + "0x1234567890123456789012345678900000000002" # lock address 2 + ) + _locked_position.account_address = _account_address_1 + _locked_position.value = 5 + _locked_position.modified = datetime(2023, 10, 25, 0, 2, 0) + db.add(_locked_position) + + idx_personal_info_3 = IDXPersonalInfo() + idx_personal_info_3.account_address = _account_address_3 + idx_personal_info_3.issuer_address = _issuer_address + idx_personal_info_3.personal_info = { + "key_manager": "key_manager_test1", + "name": "name_test3", + "postal_code": "postal_code_test3", + "address": "address_test3", + "email": "email_test3", + "birth": "birth_test3", + # PersonalInfo is partially registered. + } + db.add(idx_personal_info_3) + + db.commit() + + # request target API + resp = client.get( + self.base_url.format(_token_address), + headers={"issuer-address": _issuer_address}, + params={ + "balance_and_pending_transfer": 30, + "balance_and_pending_transfer_operator": 1, + }, + ) + + # assertion + assert resp.status_code == 200 + assert resp.json() == { + "result_set": {"count": 2, "total": 3, "offset": None, "limit": None}, + "holders": [ + { + "account_address": _account_address_2, + "personal_information": { + "key_manager": None, + "name": None, + "postal_code": None, + "address": None, + "email": None, + "birth": None, + "is_corporate": None, + "tax_category": None, + }, + "balance": 20, + "exchange_balance": 21, + "exchange_commitment": 22, + "pending_transfer": 10, + "locked": 20, + "modified": "2023-10-24T02:20:00", + }, + { + "account_address": _account_address_3, + "personal_information": { + "key_manager": "key_manager_test1", + "name": "name_test3", + "postal_code": "postal_code_test3", + "address": "address_test3", + "email": "email_test3", + "birth": "birth_test3", + "is_corporate": None, + "tax_category": None, + }, + "balance": 99, + "exchange_balance": 99, + "exchange_commitment": 99, + "pending_transfer": 99, + "locked": 30, + "modified": "2023-10-24T05:00:00", + }, + ], + } + + # + # Search filter: balance + pending_transfer & "<=" + def test_normal_4_5_3(self, client, db): + user = config_eth_account("user1") + _issuer_address = user["address"] + _token_address = "0x82b1c9374aB625380bd498a3d9dF4033B8A0E3Bb" + _account_address_1 = "0xb75c7545b9230FEe99b7af370D38eBd3DAD929f7" + _account_address_2 = "0x3F198534Bbe3B2a197d3B317d41392F348EAC707" + _account_address_3 = "0x8277D905F37F8a9717F5718d0daC21495dFE74bf" + + account = Account() + account.issuer_address = _issuer_address + db.add(account) + + token = Token() + token.type = TokenType.IBET_STRAIGHT_BOND.value + token.tx_hash = "" + token.issuer_address = _issuer_address + token.token_address = _token_address + token.abi = "" + token.version = TokenVersion.V_24_06 + db.add(token) + + # prepare data: account_address_1 + idx_position_1 = IDXPosition() + idx_position_1.token_address = _token_address + idx_position_1.account_address = _account_address_1 + idx_position_1.balance = 10 + idx_position_1.exchange_balance = 11 + idx_position_1.exchange_commitment = 12 + idx_position_1.pending_transfer = 5 + idx_position_1.modified = datetime(2023, 10, 24, 0, 0, 0) + db.add(idx_position_1) + + idx_locked_position = IDXLockedPosition() + idx_locked_position.token_address = _token_address + idx_locked_position.lock_address = ( + "0x1234567890123456789012345678900000000001" # lock address 1 + ) + idx_locked_position.account_address = _account_address_1 + idx_locked_position.value = 5 + idx_locked_position.modified = datetime(2023, 10, 24, 1, 0, 0) + db.add(idx_locked_position) + + idx_locked_position = IDXLockedPosition() + idx_locked_position.token_address = _token_address + idx_locked_position.lock_address = ( + "0x1234567890123456789012345678900000000002" # lock address 2 + ) + idx_locked_position.account_address = _account_address_1 + idx_locked_position.value = 5 + idx_locked_position.modified = datetime(2023, 10, 24, 1, 10, 0) + db.add(idx_locked_position) + + idx_personal_info_1 = IDXPersonalInfo() + idx_personal_info_1.account_address = _account_address_1 + idx_personal_info_1.issuer_address = _issuer_address + idx_personal_info_1.personal_info = { + "key_manager": "key_manager_test1", + "name": "name_test1", + "postal_code": "postal_code_test1", + "address": "address_test1", + "email": "email_test1", + "birth": "birth_test1", + "is_corporate": False, + "tax_category": 10, + } + db.add(idx_personal_info_1) + + # prepare data: account_address_2 + idx_position_2 = IDXPosition() + idx_position_2.token_address = _token_address + idx_position_2.account_address = _account_address_2 + idx_position_2.balance = 20 + idx_position_2.exchange_balance = 21 + idx_position_2.exchange_commitment = 22 + idx_position_2.pending_transfer = 10 + idx_position_2.modified = datetime(2023, 10, 24, 2, 0, 0) + db.add(idx_position_2) + + idx_locked_position = IDXLockedPosition() + idx_locked_position.token_address = _token_address + idx_locked_position.lock_address = ( + "0x1234567890123456789012345678900000000001" # lock address 1 + ) + idx_locked_position.account_address = _account_address_2 + idx_locked_position.value = 10 + idx_locked_position.modified = datetime(2023, 10, 24, 2, 10, 0) + db.add(idx_locked_position) + + idx_locked_position = IDXLockedPosition() + idx_locked_position.token_address = _token_address + idx_locked_position.lock_address = ( + "0x1234567890123456789012345678900000000002" # lock address 2 + ) + idx_locked_position.account_address = _account_address_2 + idx_locked_position.value = 10 + idx_locked_position.modified = datetime(2023, 10, 24, 2, 20, 0) + db.add(idx_locked_position) + + # prepare data: account_address_3 + idx_position_3 = IDXPosition() + idx_position_3.token_address = _token_address + idx_position_3.account_address = _account_address_3 + idx_position_3.balance = 99 + idx_position_3.exchange_balance = 99 + idx_position_3.exchange_commitment = 99 + idx_position_3.pending_transfer = 99 + idx_position_3.modified = datetime(2023, 10, 24, 3, 0, 0) + db.add(idx_position_3) + + idx_locked_position = IDXLockedPosition() + idx_locked_position.token_address = _token_address + idx_locked_position.lock_address = ( + "0x1234567890123456789012345678900000000001" # lock address 1 + ) + idx_locked_position.account_address = _account_address_3 + idx_locked_position.value = 15 + idx_locked_position.modified = datetime(2023, 10, 24, 4, 0, 0) + db.add(idx_locked_position) + + idx_locked_position = IDXLockedPosition() + idx_locked_position.token_address = _token_address + idx_locked_position.lock_address = ( + "0x1234567890123456789012345678900000000002" # lock address 2 + ) + idx_locked_position.account_address = _account_address_3 + idx_locked_position.value = 15 + idx_locked_position.modified = datetime(2023, 10, 24, 5, 0, 0) + db.add(idx_locked_position) + + # Other locked position + _locked_position = IDXLockedPosition() + _locked_position.token_address = "other_token_address" + _locked_position.lock_address = ( + "0x1234567890123456789012345678900000000002" # lock address 2 + ) + _locked_position.account_address = _account_address_1 + _locked_position.value = 5 + _locked_position.modified = datetime(2023, 10, 25, 0, 2, 0) + db.add(_locked_position) + + idx_personal_info_3 = IDXPersonalInfo() + idx_personal_info_3.account_address = _account_address_3 + idx_personal_info_3.issuer_address = _issuer_address + idx_personal_info_3.personal_info = { + "key_manager": "key_manager_test1", + "name": "name_test3", + "postal_code": "postal_code_test3", + "address": "address_test3", + "email": "email_test3", + "birth": "birth_test3", + # PersonalInfo is partially registered. + } + db.add(idx_personal_info_3) + + db.commit() + + # request target API + resp = client.get( + self.base_url.format(_token_address), + headers={"issuer-address": _issuer_address}, + params={ + "balance_and_pending_transfer": 20, + "balance_and_pending_transfer_operator": 2, + }, + ) + + # assertion + assert resp.status_code == 200 + assert resp.json() == { + "result_set": {"count": 1, "total": 3, "offset": None, "limit": None}, + "holders": [ + { + "account_address": _account_address_1, + "personal_information": { + "key_manager": "key_manager_test1", + "name": "name_test1", + "postal_code": "postal_code_test1", + "address": "address_test1", + "email": "email_test1", + "birth": "birth_test1", + "is_corporate": False, + "tax_category": 10, + }, + "balance": 10, + "exchange_balance": 11, + "exchange_commitment": 12, + "pending_transfer": 5, + "locked": 10, + "modified": "2023-10-24T01:10:00", + }, + ], + } + + # # Search filter: holder_name - def test_normal_4_5(self, client, db): + def test_normal_4_6(self, client, db): user = config_eth_account("user1") _issuer_address = user["address"] _token_address = "0x82b1c9374aB625380bd498a3d9dF4033B8A0E3Bb" @@ -2747,9 +3351,9 @@ def test_normal_4_5(self, client, db): ], } - # + # # Search filter: key_manager - def test_normal_4_6(self, client, db): + def test_normal_4_7(self, client, db): user = config_eth_account("user1") _issuer_address = user["address"] _token_address = "0x82b1c9374aB625380bd498a3d9dF4033B8A0E3Bb" @@ -2958,9 +3562,9 @@ def test_normal_4_6(self, client, db): ], } - # + # # Search filter: account_address - def test_normal_4_7(self, client, db): + def test_normal_4_8(self, client, db): user = config_eth_account("user1") _issuer_address = user["address"] _token_address = "0x82b1c9374aB625380bd498a3d9dF4033B8A0E3Bb" @@ -4316,7 +4920,7 @@ def test_normal_5_5(self, client, db): } # - # Sort Item: holder_name + # Sort Item: balance + pending_transfer def test_normal_5_6(self, client, db): user = config_eth_account("user1") _issuer_address = user["address"] @@ -4324,6 +4928,239 @@ def test_normal_5_6(self, client, db): _account_address_1 = "0xb75c7545b9230FEe99b7af370D38eBd3DAD929f7" _account_address_2 = "0x3F198534Bbe3B2a197d3B317d41392F348EAC707" _account_address_3 = "0x8277D905F37F8a9717F5718d0daC21495dFE74bf" + + account = Account() + account.issuer_address = _issuer_address + db.add(account) + + token = Token() + token.type = TokenType.IBET_STRAIGHT_BOND.value + token.tx_hash = "" + token.issuer_address = _issuer_address + token.token_address = _token_address + token.abi = "" + token.version = TokenVersion.V_24_06 + db.add(token) + + # prepare data: account_address_1 + idx_position_1 = IDXPosition() + idx_position_1.token_address = _token_address + idx_position_1.account_address = _account_address_1 + idx_position_1.balance = 10 + idx_position_1.exchange_balance = 11 + idx_position_1.exchange_commitment = 12 + idx_position_1.pending_transfer = 5 + idx_position_1.created = datetime(2023, 10, 24, 0, 0, 0) + idx_position_1.modified = datetime(2023, 10, 24, 0, 0, 0) + db.add(idx_position_1) + + idx_locked_position = IDXLockedPosition() + idx_locked_position.token_address = _token_address + idx_locked_position.lock_address = ( + "0x1234567890123456789012345678900000000001" # lock address 1 + ) + idx_locked_position.account_address = _account_address_1 + idx_locked_position.value = 5 + idx_locked_position.modified = datetime(2023, 10, 24, 1, 0, 0) + db.add(idx_locked_position) + + idx_locked_position = IDXLockedPosition() + idx_locked_position.token_address = _token_address + idx_locked_position.lock_address = ( + "0x1234567890123456789012345678900000000002" # lock address 2 + ) + idx_locked_position.account_address = _account_address_1 + idx_locked_position.value = 5 + idx_locked_position.modified = datetime(2023, 10, 24, 1, 10, 0) + db.add(idx_locked_position) + + idx_personal_info_1 = IDXPersonalInfo() + idx_personal_info_1.account_address = _account_address_1 + idx_personal_info_1.issuer_address = _issuer_address + idx_personal_info_1.personal_info = { + "key_manager": "key_manager_test1", + "name": "name_test1", + "postal_code": "postal_code_test1", + "address": "address_test1", + "email": "email_test1", + "birth": "birth_test1", + "is_corporate": False, + "tax_category": 10, + } + db.add(idx_personal_info_1) + + # prepare data: account_address_2 + idx_position_2 = IDXPosition() + idx_position_2.token_address = _token_address + idx_position_2.account_address = _account_address_2 + idx_position_2.balance = 20 + idx_position_2.exchange_balance = 21 + idx_position_2.exchange_commitment = 22 + idx_position_2.pending_transfer = 10 + idx_position_2.created = datetime(2023, 10, 24, 2, 0, 0) + idx_position_2.modified = datetime(2023, 10, 24, 2, 0, 0) + db.add(idx_position_2) + + idx_locked_position = IDXLockedPosition() + idx_locked_position.token_address = _token_address + idx_locked_position.lock_address = ( + "0x1234567890123456789012345678900000000001" # lock address 1 + ) + idx_locked_position.account_address = _account_address_2 + idx_locked_position.value = 10 + idx_locked_position.modified = datetime(2023, 10, 24, 2, 10, 0) + db.add(idx_locked_position) + + idx_locked_position = IDXLockedPosition() + idx_locked_position.token_address = _token_address + idx_locked_position.lock_address = ( + "0x1234567890123456789012345678900000000002" # lock address 2 + ) + idx_locked_position.account_address = _account_address_2 + idx_locked_position.value = 10 + idx_locked_position.modified = datetime(2023, 10, 24, 2, 20, 0) + db.add(idx_locked_position) + + # prepare data: account_address_3 + idx_position_3 = IDXPosition() + idx_position_3.token_address = _token_address + idx_position_3.account_address = _account_address_3 + idx_position_3.balance = 99 + idx_position_3.exchange_balance = 99 + idx_position_3.exchange_commitment = 99 + idx_position_3.pending_transfer = 99 + idx_position_3.created = datetime(2023, 10, 24, 3, 0, 0) + idx_position_3.modified = datetime(2023, 10, 24, 3, 0, 0) + db.add(idx_position_3) + + idx_locked_position = IDXLockedPosition() + idx_locked_position.token_address = _token_address + idx_locked_position.lock_address = ( + "0x1234567890123456789012345678900000000001" # lock address 1 + ) + idx_locked_position.account_address = _account_address_3 + idx_locked_position.value = 15 + idx_locked_position.modified = datetime(2023, 10, 24, 4, 0, 0) + db.add(idx_locked_position) + + idx_locked_position = IDXLockedPosition() + idx_locked_position.token_address = _token_address + idx_locked_position.lock_address = ( + "0x1234567890123456789012345678900000000002" # lock address 2 + ) + idx_locked_position.account_address = _account_address_3 + idx_locked_position.value = 15 + idx_locked_position.modified = datetime(2023, 10, 24, 5, 0, 0) + db.add(idx_locked_position) + + # Other locked position + _locked_position = IDXLockedPosition() + _locked_position.token_address = "other_token_address" + _locked_position.lock_address = ( + "0x1234567890123456789012345678900000000002" # lock address 2 + ) + _locked_position.account_address = _account_address_1 + _locked_position.value = 5 + _locked_position.modified = datetime(2023, 10, 25, 0, 2, 0) + db.add(_locked_position) + + idx_personal_info_3 = IDXPersonalInfo() + idx_personal_info_3.account_address = _account_address_3 + idx_personal_info_3.issuer_address = _issuer_address + idx_personal_info_3.personal_info = { + "key_manager": "key_manager_test1", + "name": "name_test3", + "postal_code": "postal_code_test3", + "address": "address_test3", + "email": "email_test3", + "birth": "birth_test3", + # PersonalInfo is partially registered. + } + db.add(idx_personal_info_3) + + db.commit() + + # request target API + resp = client.get( + self.base_url.format(_token_address), + headers={"issuer-address": _issuer_address}, + params={"sort_order": 1, "sort_item": "balance_and_pending_transfer"}, + ) + + # assertion + assert resp.status_code == 200 + assert resp.json() == { + "result_set": {"count": 3, "total": 3, "offset": None, "limit": None}, + "holders": [ + { + "account_address": _account_address_3, + "personal_information": { + "key_manager": "key_manager_test1", + "name": "name_test3", + "postal_code": "postal_code_test3", + "address": "address_test3", + "email": "email_test3", + "birth": "birth_test3", + "is_corporate": None, + "tax_category": None, + }, + "balance": 99, + "exchange_balance": 99, + "exchange_commitment": 99, + "pending_transfer": 99, + "locked": 30, + "modified": "2023-10-24T05:00:00", + }, + { + "account_address": _account_address_2, + "personal_information": { + "key_manager": None, + "name": None, + "postal_code": None, + "address": None, + "email": None, + "birth": None, + "is_corporate": None, + "tax_category": None, + }, + "balance": 20, + "exchange_balance": 21, + "exchange_commitment": 22, + "pending_transfer": 10, + "locked": 20, + "modified": "2023-10-24T02:20:00", + }, + { + "account_address": _account_address_1, + "personal_information": { + "key_manager": "key_manager_test1", + "name": "name_test1", + "postal_code": "postal_code_test1", + "address": "address_test1", + "email": "email_test1", + "birth": "birth_test1", + "is_corporate": False, + "tax_category": 10, + }, + "balance": 10, + "exchange_balance": 11, + "exchange_commitment": 12, + "pending_transfer": 5, + "locked": 10, + "modified": "2023-10-24T01:10:00", + }, + ], + } + + # + # Sort Item: holder_name + def test_normal_5_7(self, client, db): + user = config_eth_account("user1") + _issuer_address = user["address"] + _token_address = "0x82b1c9374aB625380bd498a3d9dF4033B8A0E3Bb" + _account_address_1 = "0xb75c7545b9230FEe99b7af370D38eBd3DAD929f7" + _account_address_2 = "0x3F198534Bbe3B2a197d3B317d41392F348EAC707" + _account_address_3 = "0x8277D905F37F8a9717F5718d0daC21495dFE74bf" _account_address_4 = "0x917eFFaC072dcda308e2337636f562D0A96F42eA" account = Account() @@ -4580,9 +5417,9 @@ def test_normal_5_6(self, client, db): ], } - # + # # Sort Item: key_manager - def test_normal_5_7(self, client, db): + def test_normal_5_8(self, client, db): user = config_eth_account("user1") _issuer_address = user["address"] _token_address = "0x82b1c9374aB625380bd498a3d9dF4033B8A0E3Bb" diff --git a/tests/test_app_routers_share_tokens_{token_address}_holders_GET.py b/tests/test_app_routers_share_tokens_{token_address}_holders_GET.py index a6dd00f9..78ff561a 100644 --- a/tests/test_app_routers_share_tokens_{token_address}_holders_GET.py +++ b/tests/test_app_routers_share_tokens_{token_address}_holders_GET.py @@ -2569,9 +2569,632 @@ def test_normal_4_4_3(self, client, db): ], } - # + # + # Search filter: balance + pending_transfer & "=" + def test_normal_4_5_1(self, client, db): + user = config_eth_account("user1") + _issuer_address = user["address"] + _token_address = "0x82b1c9374aB625380bd498a3d9dF4033B8A0E3Bb" + _account_address_1 = "0xb75c7545b9230FEe99b7af370D38eBd3DAD929f7" + _account_address_2 = "0x3F198534Bbe3B2a197d3B317d41392F348EAC707" + _account_address_3 = "0x8277D905F37F8a9717F5718d0daC21495dFE74bf" + + account = Account() + account.issuer_address = _issuer_address + db.add(account) + + token = Token() + token.type = TokenType.IBET_SHARE.value + token.tx_hash = "" + token.issuer_address = _issuer_address + token.token_address = _token_address + token.abi = "" + token.version = TokenVersion.V_24_06 + db.add(token) + + # prepare data: account_address_1 + idx_position_1 = IDXPosition() + idx_position_1.token_address = _token_address + idx_position_1.account_address = _account_address_1 + idx_position_1.balance = 10 + idx_position_1.exchange_balance = 11 + idx_position_1.exchange_commitment = 12 + idx_position_1.pending_transfer = 5 + idx_position_1.modified = datetime(2023, 10, 24, 0, 0, 0) + db.add(idx_position_1) + + idx_locked_position = IDXLockedPosition() + idx_locked_position.token_address = _token_address + idx_locked_position.lock_address = ( + "0x1234567890123456789012345678900000000001" # lock address 1 + ) + idx_locked_position.account_address = _account_address_1 + idx_locked_position.value = 5 + idx_locked_position.modified = datetime(2023, 10, 24, 1, 0, 0) + db.add(idx_locked_position) + + idx_locked_position = IDXLockedPosition() + idx_locked_position.token_address = _token_address + idx_locked_position.lock_address = ( + "0x1234567890123456789012345678900000000002" # lock address 2 + ) + idx_locked_position.account_address = _account_address_1 + idx_locked_position.value = 5 + idx_locked_position.modified = datetime(2023, 10, 24, 1, 10, 0) + db.add(idx_locked_position) + + idx_personal_info_1 = IDXPersonalInfo() + idx_personal_info_1.account_address = _account_address_1 + idx_personal_info_1.issuer_address = _issuer_address + idx_personal_info_1.personal_info = { + "key_manager": "key_manager_test1", + "name": "name_test1", + "postal_code": "postal_code_test1", + "address": "address_test1", + "email": "email_test1", + "birth": "birth_test1", + "is_corporate": False, + "tax_category": 10, + } + db.add(idx_personal_info_1) + + # prepare data: account_address_2 + idx_position_2 = IDXPosition() + idx_position_2.token_address = _token_address + idx_position_2.account_address = _account_address_2 + idx_position_2.balance = 20 + idx_position_2.exchange_balance = 21 + idx_position_2.exchange_commitment = 22 + idx_position_2.pending_transfer = 10 + idx_position_2.modified = datetime(2023, 10, 24, 2, 0, 0) + db.add(idx_position_2) + + idx_locked_position = IDXLockedPosition() + idx_locked_position.token_address = _token_address + idx_locked_position.lock_address = ( + "0x1234567890123456789012345678900000000001" # lock address 1 + ) + idx_locked_position.account_address = _account_address_2 + idx_locked_position.value = 10 + idx_locked_position.modified = datetime(2023, 10, 24, 2, 10, 0) + db.add(idx_locked_position) + + idx_locked_position = IDXLockedPosition() + idx_locked_position.token_address = _token_address + idx_locked_position.lock_address = ( + "0x1234567890123456789012345678900000000002" # lock address 2 + ) + idx_locked_position.account_address = _account_address_2 + idx_locked_position.value = 10 + idx_locked_position.modified = datetime(2023, 10, 24, 2, 20, 0) + db.add(idx_locked_position) + + # prepare data: account_address_3 + idx_position_3 = IDXPosition() + idx_position_3.token_address = _token_address + idx_position_3.account_address = _account_address_3 + idx_position_3.balance = 99 + idx_position_3.exchange_balance = 99 + idx_position_3.exchange_commitment = 99 + idx_position_3.pending_transfer = 99 + idx_position_3.modified = datetime(2023, 10, 24, 3, 0, 0) + db.add(idx_position_3) + + idx_locked_position = IDXLockedPosition() + idx_locked_position.token_address = _token_address + idx_locked_position.lock_address = ( + "0x1234567890123456789012345678900000000001" # lock address 1 + ) + idx_locked_position.account_address = _account_address_3 + idx_locked_position.value = 15 + idx_locked_position.modified = datetime(2023, 10, 24, 4, 0, 0) + db.add(idx_locked_position) + + idx_locked_position = IDXLockedPosition() + idx_locked_position.token_address = _token_address + idx_locked_position.lock_address = ( + "0x1234567890123456789012345678900000000002" # lock address 2 + ) + idx_locked_position.account_address = _account_address_3 + idx_locked_position.value = 15 + idx_locked_position.modified = datetime(2023, 10, 24, 5, 0, 0) + db.add(idx_locked_position) + + # Other locked position + _locked_position = IDXLockedPosition() + _locked_position.token_address = "other_token_address" + _locked_position.lock_address = ( + "0x1234567890123456789012345678900000000002" # lock address 2 + ) + _locked_position.account_address = _account_address_1 + _locked_position.value = 5 + _locked_position.modified = datetime(2023, 10, 25, 0, 2, 0) + db.add(_locked_position) + + idx_personal_info_3 = IDXPersonalInfo() + idx_personal_info_3.account_address = _account_address_3 + idx_personal_info_3.issuer_address = _issuer_address + idx_personal_info_3.personal_info = { + "key_manager": "key_manager_test1", + "name": "name_test3", + "postal_code": "postal_code_test3", + "address": "address_test3", + "email": "email_test3", + "birth": "birth_test3", + # PersonalInfo is partially registered. + } + db.add(idx_personal_info_3) + + db.commit() + + # request target API + resp = client.get( + self.base_url.format(_token_address), + headers={"issuer-address": _issuer_address}, + params={ + "balance_and_pending_transfer": 30, + "balance_and_pending_transfer_operator": 0, + }, + ) + + # assertion + assert resp.status_code == 200 + assert resp.json() == { + "result_set": {"count": 1, "total": 3, "offset": None, "limit": None}, + "holders": [ + { + "account_address": _account_address_2, + "personal_information": { + "key_manager": None, + "name": None, + "postal_code": None, + "address": None, + "email": None, + "birth": None, + "is_corporate": None, + "tax_category": None, + }, + "balance": 20, + "exchange_balance": 21, + "exchange_commitment": 22, + "pending_transfer": 10, + "locked": 20, + "modified": "2023-10-24T02:20:00", + }, + ], + } + + # + # Search filter: balance + pending_transfer & ">=" + def test_normal_4_5_2(self, client, db): + user = config_eth_account("user1") + _issuer_address = user["address"] + _token_address = "0x82b1c9374aB625380bd498a3d9dF4033B8A0E3Bb" + _account_address_1 = "0xb75c7545b9230FEe99b7af370D38eBd3DAD929f7" + _account_address_2 = "0x3F198534Bbe3B2a197d3B317d41392F348EAC707" + _account_address_3 = "0x8277D905F37F8a9717F5718d0daC21495dFE74bf" + + account = Account() + account.issuer_address = _issuer_address + db.add(account) + + token = Token() + token.type = TokenType.IBET_SHARE.value + token.tx_hash = "" + token.issuer_address = _issuer_address + token.token_address = _token_address + token.abi = "" + token.version = TokenVersion.V_24_06 + db.add(token) + + # prepare data: account_address_1 + idx_position_1 = IDXPosition() + idx_position_1.token_address = _token_address + idx_position_1.account_address = _account_address_1 + idx_position_1.balance = 10 + idx_position_1.exchange_balance = 11 + idx_position_1.exchange_commitment = 12 + idx_position_1.pending_transfer = 5 + idx_position_1.modified = datetime(2023, 10, 24, 0, 0, 0) + db.add(idx_position_1) + + idx_locked_position = IDXLockedPosition() + idx_locked_position.token_address = _token_address + idx_locked_position.lock_address = ( + "0x1234567890123456789012345678900000000001" # lock address 1 + ) + idx_locked_position.account_address = _account_address_1 + idx_locked_position.value = 5 + idx_locked_position.modified = datetime(2023, 10, 24, 1, 0, 0) + db.add(idx_locked_position) + + idx_locked_position = IDXLockedPosition() + idx_locked_position.token_address = _token_address + idx_locked_position.lock_address = ( + "0x1234567890123456789012345678900000000002" # lock address 2 + ) + idx_locked_position.account_address = _account_address_1 + idx_locked_position.value = 5 + idx_locked_position.modified = datetime(2023, 10, 24, 1, 10, 0) + db.add(idx_locked_position) + + idx_personal_info_1 = IDXPersonalInfo() + idx_personal_info_1.account_address = _account_address_1 + idx_personal_info_1.issuer_address = _issuer_address + idx_personal_info_1.personal_info = { + "key_manager": "key_manager_test1", + "name": "name_test1", + "postal_code": "postal_code_test1", + "address": "address_test1", + "email": "email_test1", + "birth": "birth_test1", + "is_corporate": False, + "tax_category": 10, + } + db.add(idx_personal_info_1) + + # prepare data: account_address_2 + idx_position_2 = IDXPosition() + idx_position_2.token_address = _token_address + idx_position_2.account_address = _account_address_2 + idx_position_2.balance = 20 + idx_position_2.exchange_balance = 21 + idx_position_2.exchange_commitment = 22 + idx_position_2.pending_transfer = 10 + idx_position_2.modified = datetime(2023, 10, 24, 2, 0, 0) + db.add(idx_position_2) + + idx_locked_position = IDXLockedPosition() + idx_locked_position.token_address = _token_address + idx_locked_position.lock_address = ( + "0x1234567890123456789012345678900000000001" # lock address 1 + ) + idx_locked_position.account_address = _account_address_2 + idx_locked_position.value = 10 + idx_locked_position.modified = datetime(2023, 10, 24, 2, 10, 0) + db.add(idx_locked_position) + + idx_locked_position = IDXLockedPosition() + idx_locked_position.token_address = _token_address + idx_locked_position.lock_address = ( + "0x1234567890123456789012345678900000000002" # lock address 2 + ) + idx_locked_position.account_address = _account_address_2 + idx_locked_position.value = 10 + idx_locked_position.modified = datetime(2023, 10, 24, 2, 20, 0) + db.add(idx_locked_position) + + # prepare data: account_address_3 + idx_position_3 = IDXPosition() + idx_position_3.token_address = _token_address + idx_position_3.account_address = _account_address_3 + idx_position_3.balance = 99 + idx_position_3.exchange_balance = 99 + idx_position_3.exchange_commitment = 99 + idx_position_3.pending_transfer = 99 + idx_position_3.modified = datetime(2023, 10, 24, 3, 0, 0) + db.add(idx_position_3) + + idx_locked_position = IDXLockedPosition() + idx_locked_position.token_address = _token_address + idx_locked_position.lock_address = ( + "0x1234567890123456789012345678900000000001" # lock address 1 + ) + idx_locked_position.account_address = _account_address_3 + idx_locked_position.value = 15 + idx_locked_position.modified = datetime(2023, 10, 24, 4, 0, 0) + db.add(idx_locked_position) + + idx_locked_position = IDXLockedPosition() + idx_locked_position.token_address = _token_address + idx_locked_position.lock_address = ( + "0x1234567890123456789012345678900000000002" # lock address 2 + ) + idx_locked_position.account_address = _account_address_3 + idx_locked_position.value = 15 + idx_locked_position.modified = datetime(2023, 10, 24, 5, 0, 0) + db.add(idx_locked_position) + + # Other locked position + _locked_position = IDXLockedPosition() + _locked_position.token_address = "other_token_address" + _locked_position.lock_address = ( + "0x1234567890123456789012345678900000000002" # lock address 2 + ) + _locked_position.account_address = _account_address_1 + _locked_position.value = 5 + _locked_position.modified = datetime(2023, 10, 25, 0, 2, 0) + db.add(_locked_position) + + idx_personal_info_3 = IDXPersonalInfo() + idx_personal_info_3.account_address = _account_address_3 + idx_personal_info_3.issuer_address = _issuer_address + idx_personal_info_3.personal_info = { + "key_manager": "key_manager_test1", + "name": "name_test3", + "postal_code": "postal_code_test3", + "address": "address_test3", + "email": "email_test3", + "birth": "birth_test3", + # PersonalInfo is partially registered. + } + db.add(idx_personal_info_3) + + db.commit() + + # request target API + resp = client.get( + self.base_url.format(_token_address), + headers={"issuer-address": _issuer_address}, + params={ + "balance_and_pending_transfer": 30, + "balance_and_pending_transfer_operator": 1, + }, + ) + + # assertion + assert resp.status_code == 200 + assert resp.json() == { + "result_set": {"count": 2, "total": 3, "offset": None, "limit": None}, + "holders": [ + { + "account_address": _account_address_2, + "personal_information": { + "key_manager": None, + "name": None, + "postal_code": None, + "address": None, + "email": None, + "birth": None, + "is_corporate": None, + "tax_category": None, + }, + "balance": 20, + "exchange_balance": 21, + "exchange_commitment": 22, + "pending_transfer": 10, + "locked": 20, + "modified": "2023-10-24T02:20:00", + }, + { + "account_address": _account_address_3, + "personal_information": { + "key_manager": "key_manager_test1", + "name": "name_test3", + "postal_code": "postal_code_test3", + "address": "address_test3", + "email": "email_test3", + "birth": "birth_test3", + "is_corporate": None, + "tax_category": None, + }, + "balance": 99, + "exchange_balance": 99, + "exchange_commitment": 99, + "pending_transfer": 99, + "locked": 30, + "modified": "2023-10-24T05:00:00", + }, + ], + } + + # + # Search filter: balance + pending_transfer & "<=" + def test_normal_4_5_3(self, client, db): + user = config_eth_account("user1") + _issuer_address = user["address"] + _token_address = "0x82b1c9374aB625380bd498a3d9dF4033B8A0E3Bb" + _account_address_1 = "0xb75c7545b9230FEe99b7af370D38eBd3DAD929f7" + _account_address_2 = "0x3F198534Bbe3B2a197d3B317d41392F348EAC707" + _account_address_3 = "0x8277D905F37F8a9717F5718d0daC21495dFE74bf" + + account = Account() + account.issuer_address = _issuer_address + db.add(account) + + token = Token() + token.type = TokenType.IBET_SHARE.value + token.tx_hash = "" + token.issuer_address = _issuer_address + token.token_address = _token_address + token.abi = "" + token.version = TokenVersion.V_24_06 + db.add(token) + + # prepare data: account_address_1 + idx_position_1 = IDXPosition() + idx_position_1.token_address = _token_address + idx_position_1.account_address = _account_address_1 + idx_position_1.balance = 10 + idx_position_1.exchange_balance = 11 + idx_position_1.exchange_commitment = 12 + idx_position_1.pending_transfer = 5 + idx_position_1.modified = datetime(2023, 10, 24, 0, 0, 0) + db.add(idx_position_1) + + idx_locked_position = IDXLockedPosition() + idx_locked_position.token_address = _token_address + idx_locked_position.lock_address = ( + "0x1234567890123456789012345678900000000001" # lock address 1 + ) + idx_locked_position.account_address = _account_address_1 + idx_locked_position.value = 5 + idx_locked_position.modified = datetime(2023, 10, 24, 1, 0, 0) + db.add(idx_locked_position) + + idx_locked_position = IDXLockedPosition() + idx_locked_position.token_address = _token_address + idx_locked_position.lock_address = ( + "0x1234567890123456789012345678900000000002" # lock address 2 + ) + idx_locked_position.account_address = _account_address_1 + idx_locked_position.value = 5 + idx_locked_position.modified = datetime(2023, 10, 24, 1, 10, 0) + db.add(idx_locked_position) + + idx_personal_info_1 = IDXPersonalInfo() + idx_personal_info_1.account_address = _account_address_1 + idx_personal_info_1.issuer_address = _issuer_address + idx_personal_info_1.personal_info = { + "key_manager": "key_manager_test1", + "name": "name_test1", + "postal_code": "postal_code_test1", + "address": "address_test1", + "email": "email_test1", + "birth": "birth_test1", + "is_corporate": False, + "tax_category": 10, + } + db.add(idx_personal_info_1) + + # prepare data: account_address_2 + idx_position_2 = IDXPosition() + idx_position_2.token_address = _token_address + idx_position_2.account_address = _account_address_2 + idx_position_2.balance = 20 + idx_position_2.exchange_balance = 21 + idx_position_2.exchange_commitment = 22 + idx_position_2.pending_transfer = 10 + idx_position_2.modified = datetime(2023, 10, 24, 2, 0, 0) + db.add(idx_position_2) + + idx_locked_position = IDXLockedPosition() + idx_locked_position.token_address = _token_address + idx_locked_position.lock_address = ( + "0x1234567890123456789012345678900000000001" # lock address 1 + ) + idx_locked_position.account_address = _account_address_2 + idx_locked_position.value = 10 + idx_locked_position.modified = datetime(2023, 10, 24, 2, 10, 0) + db.add(idx_locked_position) + + idx_locked_position = IDXLockedPosition() + idx_locked_position.token_address = _token_address + idx_locked_position.lock_address = ( + "0x1234567890123456789012345678900000000002" # lock address 2 + ) + idx_locked_position.account_address = _account_address_2 + idx_locked_position.value = 10 + idx_locked_position.modified = datetime(2023, 10, 24, 2, 20, 0) + db.add(idx_locked_position) + + # prepare data: account_address_3 + idx_position_3 = IDXPosition() + idx_position_3.token_address = _token_address + idx_position_3.account_address = _account_address_3 + idx_position_3.balance = 99 + idx_position_3.exchange_balance = 99 + idx_position_3.exchange_commitment = 99 + idx_position_3.pending_transfer = 99 + idx_position_3.modified = datetime(2023, 10, 24, 3, 0, 0) + db.add(idx_position_3) + + idx_locked_position = IDXLockedPosition() + idx_locked_position.token_address = _token_address + idx_locked_position.lock_address = ( + "0x1234567890123456789012345678900000000001" # lock address 1 + ) + idx_locked_position.account_address = _account_address_3 + idx_locked_position.value = 15 + idx_locked_position.modified = datetime(2023, 10, 24, 4, 0, 0) + db.add(idx_locked_position) + + idx_locked_position = IDXLockedPosition() + idx_locked_position.token_address = _token_address + idx_locked_position.lock_address = ( + "0x1234567890123456789012345678900000000002" # lock address 2 + ) + idx_locked_position.account_address = _account_address_3 + idx_locked_position.value = 15 + idx_locked_position.modified = datetime(2023, 10, 24, 5, 0, 0) + db.add(idx_locked_position) + + # Other locked position + _locked_position = IDXLockedPosition() + _locked_position.token_address = "other_token_address" + _locked_position.lock_address = ( + "0x1234567890123456789012345678900000000002" # lock address 2 + ) + _locked_position.account_address = _account_address_1 + _locked_position.value = 5 + _locked_position.modified = datetime(2023, 10, 25, 0, 2, 0) + db.add(_locked_position) + + idx_personal_info_3 = IDXPersonalInfo() + idx_personal_info_3.account_address = _account_address_3 + idx_personal_info_3.issuer_address = _issuer_address + idx_personal_info_3.personal_info = { + "key_manager": "key_manager_test1", + "name": "name_test3", + "postal_code": "postal_code_test3", + "address": "address_test3", + "email": "email_test3", + "birth": "birth_test3", + # PersonalInfo is partially registered. + } + db.add(idx_personal_info_3) + + db.commit() + + # request target API + resp = client.get( + self.base_url.format(_token_address), + headers={"issuer-address": _issuer_address}, + params={ + "balance_and_pending_transfer": 30, + "balance_and_pending_transfer_operator": 2, + }, + ) + + # assertion + assert resp.status_code == 200 + assert resp.json() == { + "result_set": {"count": 2, "total": 3, "offset": None, "limit": None}, + "holders": [ + { + "account_address": _account_address_1, + "personal_information": { + "key_manager": "key_manager_test1", + "name": "name_test1", + "postal_code": "postal_code_test1", + "address": "address_test1", + "email": "email_test1", + "birth": "birth_test1", + "is_corporate": False, + "tax_category": 10, + }, + "balance": 10, + "exchange_balance": 11, + "exchange_commitment": 12, + "pending_transfer": 5, + "locked": 10, + "modified": "2023-10-24T01:10:00", + }, + { + "account_address": _account_address_2, + "personal_information": { + "key_manager": None, + "name": None, + "postal_code": None, + "address": None, + "email": None, + "birth": None, + "is_corporate": None, + "tax_category": None, + }, + "balance": 20, + "exchange_balance": 21, + "exchange_commitment": 22, + "pending_transfer": 10, + "locked": 20, + "modified": "2023-10-24T02:20:00", + }, + ], + } + + # # Search filter: holder_name - def test_normal_4_5(self, client, db): + def test_normal_4_6(self, client, db): user = config_eth_account("user1") _issuer_address = user["address"] _token_address = "0x82b1c9374aB625380bd498a3d9dF4033B8A0E3Bb" @@ -2761,9 +3384,9 @@ def test_normal_4_5(self, client, db): ], } - # + # # Search filter: key_manager - def test_normal_4_6(self, client, db): + def test_normal_4_7(self, client, db): user = config_eth_account("user1") _issuer_address = user["address"] _token_address = "0x82b1c9374aB625380bd498a3d9dF4033B8A0E3Bb" @@ -2972,9 +3595,9 @@ def test_normal_4_6(self, client, db): ], } - # + # # Search filter: account_address - def test_normal_4_7(self, client, db): + def test_normal_4_8(self, client, db): user = config_eth_account("user1") _issuer_address = user["address"] _token_address = "0x82b1c9374aB625380bd498a3d9dF4033B8A0E3Bb" @@ -4330,7 +4953,7 @@ def test_normal_5_5(self, client, db): } # - # Sort Item: holder_name + # Sort Item: balance + pending_transfer def test_normal_5_6(self, client, db): user = config_eth_account("user1") _issuer_address = user["address"] @@ -4338,6 +4961,239 @@ def test_normal_5_6(self, client, db): _account_address_1 = "0xb75c7545b9230FEe99b7af370D38eBd3DAD929f7" _account_address_2 = "0x3F198534Bbe3B2a197d3B317d41392F348EAC707" _account_address_3 = "0x8277D905F37F8a9717F5718d0daC21495dFE74bf" + + account = Account() + account.issuer_address = _issuer_address + db.add(account) + + token = Token() + token.type = TokenType.IBET_SHARE.value + token.tx_hash = "" + token.issuer_address = _issuer_address + token.token_address = _token_address + token.abi = "" + token.version = TokenVersion.V_24_06 + db.add(token) + + # prepare data: account_address_1 + idx_position_1 = IDXPosition() + idx_position_1.token_address = _token_address + idx_position_1.account_address = _account_address_1 + idx_position_1.balance = 10 + idx_position_1.exchange_balance = 11 + idx_position_1.exchange_commitment = 12 + idx_position_1.pending_transfer = 5 + idx_position_1.created = datetime(2023, 10, 24, 0, 0, 0) + idx_position_1.modified = datetime(2023, 10, 24, 0, 0, 0) + db.add(idx_position_1) + + idx_locked_position = IDXLockedPosition() + idx_locked_position.token_address = _token_address + idx_locked_position.lock_address = ( + "0x1234567890123456789012345678900000000001" # lock address 1 + ) + idx_locked_position.account_address = _account_address_1 + idx_locked_position.value = 5 + idx_locked_position.modified = datetime(2023, 10, 24, 1, 0, 0) + db.add(idx_locked_position) + + idx_locked_position = IDXLockedPosition() + idx_locked_position.token_address = _token_address + idx_locked_position.lock_address = ( + "0x1234567890123456789012345678900000000002" # lock address 2 + ) + idx_locked_position.account_address = _account_address_1 + idx_locked_position.value = 5 + idx_locked_position.modified = datetime(2023, 10, 24, 1, 10, 0) + db.add(idx_locked_position) + + idx_personal_info_1 = IDXPersonalInfo() + idx_personal_info_1.account_address = _account_address_1 + idx_personal_info_1.issuer_address = _issuer_address + idx_personal_info_1.personal_info = { + "key_manager": "key_manager_test1", + "name": "name_test1", + "postal_code": "postal_code_test1", + "address": "address_test1", + "email": "email_test1", + "birth": "birth_test1", + "is_corporate": False, + "tax_category": 10, + } + db.add(idx_personal_info_1) + + # prepare data: account_address_2 + idx_position_2 = IDXPosition() + idx_position_2.token_address = _token_address + idx_position_2.account_address = _account_address_2 + idx_position_2.balance = 20 + idx_position_2.exchange_balance = 21 + idx_position_2.exchange_commitment = 22 + idx_position_2.pending_transfer = 10 + idx_position_2.created = datetime(2023, 10, 24, 2, 0, 0) + idx_position_2.modified = datetime(2023, 10, 24, 2, 0, 0) + db.add(idx_position_2) + + idx_locked_position = IDXLockedPosition() + idx_locked_position.token_address = _token_address + idx_locked_position.lock_address = ( + "0x1234567890123456789012345678900000000001" # lock address 1 + ) + idx_locked_position.account_address = _account_address_2 + idx_locked_position.value = 10 + idx_locked_position.modified = datetime(2023, 10, 24, 2, 10, 0) + db.add(idx_locked_position) + + idx_locked_position = IDXLockedPosition() + idx_locked_position.token_address = _token_address + idx_locked_position.lock_address = ( + "0x1234567890123456789012345678900000000002" # lock address 2 + ) + idx_locked_position.account_address = _account_address_2 + idx_locked_position.value = 10 + idx_locked_position.modified = datetime(2023, 10, 24, 2, 20, 0) + db.add(idx_locked_position) + + # prepare data: account_address_3 + idx_position_3 = IDXPosition() + idx_position_3.token_address = _token_address + idx_position_3.account_address = _account_address_3 + idx_position_3.balance = 99 + idx_position_3.exchange_balance = 99 + idx_position_3.exchange_commitment = 99 + idx_position_3.pending_transfer = 99 + idx_position_3.created = datetime(2023, 10, 24, 3, 0, 0) + idx_position_3.modified = datetime(2023, 10, 24, 3, 0, 0) + db.add(idx_position_3) + + idx_locked_position = IDXLockedPosition() + idx_locked_position.token_address = _token_address + idx_locked_position.lock_address = ( + "0x1234567890123456789012345678900000000001" # lock address 1 + ) + idx_locked_position.account_address = _account_address_3 + idx_locked_position.value = 15 + idx_locked_position.modified = datetime(2023, 10, 24, 4, 0, 0) + db.add(idx_locked_position) + + idx_locked_position = IDXLockedPosition() + idx_locked_position.token_address = _token_address + idx_locked_position.lock_address = ( + "0x1234567890123456789012345678900000000002" # lock address 2 + ) + idx_locked_position.account_address = _account_address_3 + idx_locked_position.value = 15 + idx_locked_position.modified = datetime(2023, 10, 24, 5, 0, 0) + db.add(idx_locked_position) + + # Other locked position + _locked_position = IDXLockedPosition() + _locked_position.token_address = "other_token_address" + _locked_position.lock_address = ( + "0x1234567890123456789012345678900000000002" # lock address 2 + ) + _locked_position.account_address = _account_address_1 + _locked_position.value = 5 + _locked_position.modified = datetime(2023, 10, 25, 0, 2, 0) + db.add(_locked_position) + + idx_personal_info_3 = IDXPersonalInfo() + idx_personal_info_3.account_address = _account_address_3 + idx_personal_info_3.issuer_address = _issuer_address + idx_personal_info_3.personal_info = { + "key_manager": "key_manager_test1", + "name": "name_test3", + "postal_code": "postal_code_test3", + "address": "address_test3", + "email": "email_test3", + "birth": "birth_test3", + # PersonalInfo is partially registered. + } + db.add(idx_personal_info_3) + + db.commit() + + # request target API + resp = client.get( + self.base_url.format(_token_address), + headers={"issuer-address": _issuer_address}, + params={"sort_order": 1, "sort_item": "balance_and_pending_transfer"}, + ) + + # assertion + assert resp.status_code == 200 + assert resp.json() == { + "result_set": {"count": 3, "total": 3, "offset": None, "limit": None}, + "holders": [ + { + "account_address": _account_address_3, + "personal_information": { + "key_manager": "key_manager_test1", + "name": "name_test3", + "postal_code": "postal_code_test3", + "address": "address_test3", + "email": "email_test3", + "birth": "birth_test3", + "is_corporate": None, + "tax_category": None, + }, + "balance": 99, + "exchange_balance": 99, + "exchange_commitment": 99, + "pending_transfer": 99, + "locked": 30, + "modified": "2023-10-24T05:00:00", + }, + { + "account_address": _account_address_2, + "personal_information": { + "key_manager": None, + "name": None, + "postal_code": None, + "address": None, + "email": None, + "birth": None, + "is_corporate": None, + "tax_category": None, + }, + "balance": 20, + "exchange_balance": 21, + "exchange_commitment": 22, + "pending_transfer": 10, + "locked": 20, + "modified": "2023-10-24T02:20:00", + }, + { + "account_address": _account_address_1, + "personal_information": { + "key_manager": "key_manager_test1", + "name": "name_test1", + "postal_code": "postal_code_test1", + "address": "address_test1", + "email": "email_test1", + "birth": "birth_test1", + "is_corporate": False, + "tax_category": 10, + }, + "balance": 10, + "exchange_balance": 11, + "exchange_commitment": 12, + "pending_transfer": 5, + "locked": 10, + "modified": "2023-10-24T01:10:00", + }, + ], + } + + # + # Sort Item: holder_name + def test_normal_5_7(self, client, db): + user = config_eth_account("user1") + _issuer_address = user["address"] + _token_address = "0x82b1c9374aB625380bd498a3d9dF4033B8A0E3Bb" + _account_address_1 = "0xb75c7545b9230FEe99b7af370D38eBd3DAD929f7" + _account_address_2 = "0x3F198534Bbe3B2a197d3B317d41392F348EAC707" + _account_address_3 = "0x8277D905F37F8a9717F5718d0daC21495dFE74bf" _account_address_4 = "0x917eFFaC072dcda308e2337636f562D0A96F42eA" account = Account() @@ -4594,9 +5450,9 @@ def test_normal_5_6(self, client, db): ], } - # + # # Sort Item: key_manager - def test_normal_5_7(self, client, db): + def test_normal_5_8(self, client, db): user = config_eth_account("user1") _issuer_address = user["address"] _token_address = "0x82b1c9374aB625380bd498a3d9dF4033B8A0E3Bb"