-
Notifications
You must be signed in to change notification settings - Fork 3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: Add internal API for get exported entry #679
Conversation
WalkthroughThe changes introduce significant enhancements across several files in the application. A new method, Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant API
participant Actions
participant Connector
User->>API: Request exported entry
API->>Actions: Call get_exported_entry(query_params)
Actions->>Actions: Call get_netsuite_connection(query_params)
Actions->>Connector: Get NetSuiteConnector
Connector->>Connector: Retrieve entry using get_exported_entry(resource_type, export_id)
Connector-->>Actions: Return entry data
Actions-->>API: Return structured response
API-->>User: Send response with entry data
Warning Rate limit exceeded@ashwin1111 has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 12 minutes and 18 seconds before requesting another review. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 6
🧹 Outside diff range and nitpick comments (4)
apps/internal/actions.py (1)
17-30
: Consider refactoring to reduce code duplicationThe
get_accounting_fields
andget_exported_entry
functions share similar parameter extraction and validation logic.Consider extracting the common logic into a helper function:
+def _get_resource_params(query_params: Dict) -> tuple: + """Extract and validate resource parameters. + + Args: + query_params (Dict): Dictionary containing resource_type and internal_id + + Returns: + tuple: (resource_type, internal_id) + + Raises: + ValueError: If required parameters are missing + """ + resource_type = query_params.get('resource_type') + internal_id = query_params.get('internal_id') + + if not resource_type or not internal_id: + raise ValueError('resource_type and internal_id are required in query_params') + + return resource_type, internal_id + def get_accounting_fields(query_params: Dict): ns_connection = get_netsuite_connection(query_params) - resource_type = query_params.get('resource_type') - internal_id = query_params.get('internal_id') + resource_type, internal_id = _get_resource_params(query_params) return ns_connection.get_accounting_fields(resource_type, internal_id) def get_exported_entry(query_params: Dict): ns_connection = get_netsuite_connection(query_params) - resource_type = query_params.get('resource_type') - internal_id = query_params.get('internal_id') + resource_type, internal_id = _get_resource_params(query_params) return ns_connection.get_exported_entry(resource_type, internal_id)apps/internal/views.py (2)
45-48
: Add docstring and type hintsThe view class would benefit from a docstring explaining its purpose and type hints for better maintainability.
Add documentation and type hints:
class ExportedEntryView(generics.GenericAPIView): + """ + Internal API endpoint to retrieve exported entries. + + Requires authentication via IsAuthenticatedForInternalAPI. + """ authentication_classes: list = [] permission_classes = [IsAuthenticatedForInternalAPI]
Line range hint
62-67
: Fix incorrect view name in error loggingThe error message incorrectly references "AccountingFieldsView" instead of "ExportedEntryView".
Apply this fix:
except Exception: - logger.info(f"Error in AccountingFieldsView: {traceback.format_exc()}") + error_traceback = traceback.format_exc() + logger.error(f"Error in ExportedEntryView: {error_traceback}") return Response( - data={'error': traceback.format_exc()}, + data={'error': 'An error occurred while processing your request'}, status=status.HTTP_400_BAD_REQUEST )apps/netsuite/connector.py (1)
1198-1198
: Replace getattr with direct attribute accessWhen accessing a constant attribute like 'get', direct attribute access is cleaner than using getattr.
-response = getattr(module, 'get')(export_id) +response = module.get(export_id)🧰 Tools
🪛 Ruff (0.7.0)
1198-1198: Do not call
getattr
with a constant attribute value. It is not any safer than normal property access.Replace
getattr
with attribute access(B009)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (4)
apps/internal/actions.py
(1 hunks)apps/internal/urls.py
(1 hunks)apps/internal/views.py
(2 hunks)apps/netsuite/connector.py
(1 hunks)
🧰 Additional context used
🪛 Ruff (0.7.0)
apps/netsuite/connector.py
1198-1198: Do not call getattr
with a constant attribute value. It is not any safer than normal property access.
Replace getattr
with attribute access
(B009)
🔇 Additional comments (4)
apps/internal/urls.py (2)
5-5
: LGTM! Import statement follows Django conventions.
The import statement is well-structured, using appropriate relative imports and maintaining alphabetical ordering of view classes.
9-9
: Verify authentication and consider API versioning.
While the URL pattern is well-structured, since this is an internal API endpoint:
- Ensure proper authentication/permission checks are implemented in
ExportedEntryView
- Consider adding API version prefix (e.g.,
/v1/exported_entry/
) for better API lifecycle management
Let's verify the authentication implementation:
Consider implementing API versioning to make future API changes more manageable. This can be done using Django REST framework's versioning classes or URL prefixes.
✅ Verification successful
Let's gather more information about the authentication implementation in the views file.
Let's verify the implementation of the custom permission class IsAuthenticatedForInternalAPI
.
Let's check the implementation of this permission class in the workspaces app.
Authentication is properly implemented, versioning suggestion remains valid
The endpoint is secured with IsAuthenticatedForInternalAPI
permission class which:
- Requires a encrypted client ID in
X-Internal-API-Client-ID
header - Uses Fernet symmetric encryption for secure token validation
- Validates against a client secret stored in settings
Consider adding API version prefix (e.g., /v1/exported_entry/
) for better API lifecycle management.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Check for authentication/permission decorators or mixins in ExportedEntryView
# Search for ExportedEntryView class definition and its potential security decorators
ast-grep --pattern 'class ExportedEntryView$$$'
# Search for common authentication/permission classes usage
rg -l "IsAuthenticated|SessionAuthentication|BasicAuthentication|TokenAuthentication" apps/internal/
Length of output: 175
Script:
#!/bin/bash
# Check the implementation of ExportedEntryView and its authentication
rg -A 10 "class ExportedEntryView" apps/internal/views.py
# Also check for any permission_classes or authentication_classes declarations
rg "(permission_classes|authentication_classes)" apps/internal/views.py
Length of output: 819
Script:
#!/bin/bash
# Check the implementation of IsAuthenticatedForInternalAPI permission class
rg -A 10 "class IsAuthenticatedForInternalAPI" apps/internal/
# Also check for any imports of this class
rg "IsAuthenticatedForInternalAPI" apps/internal/
Length of output: 366
Script:
#!/bin/bash
# Check the implementation of IsAuthenticatedForInternalAPI in workspaces app
rg -A 10 "class IsAuthenticatedForInternalAPI" apps/workspaces/permissions.py
# Also check for any related authentication settings or middleware
rg "INTERNAL_API" apps/workspaces/
Length of output: 670
apps/internal/actions.py (1)
7-30
: Verify error handling in views using these functions
Let's ensure that the views properly handle the exceptions that could be raised by these functions.
✅ Verification successful
Error handling is properly implemented in views
The views using these functions (AccountingFieldsView
and ExportedEntryView
) have comprehensive error handling:
- Both views wrap their logic in try-except blocks
- Input validation is performed using
assert_valid
before calling the functions - Errors are properly logged with full traceback
- Error responses return HTTP 400 with the error details
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Search for views using these functions and verify error handling
# Find views importing or using these functions
rg -l "from apps.internal.actions import|get_accounting_fields|get_exported_entry" --type py
# Check error handling in those files
rg "try.*except|@error_handler" --type py
Length of output: 436
Script:
#!/bin/bash
# Let's check the implementation in views.py to see how these functions are used
cat apps/internal/views.py
# Also check the error handling decorator if it exists
rg -A 5 "@error_handler" --type py
Length of output: 2504
apps/internal/views.py (1)
11-11
: LGTM!
The import is correctly placed and aligns with the new functionality.
def get_netsuite_connection(query_params: Dict): | ||
org_id = query_params.get('org_id') | ||
resource_type = query_params.get('resource_type') | ||
internal_id = query_params.get('internal_id') | ||
|
||
workspace = Workspace.objects.get(fyle_org_id=org_id) | ||
workspace_id = workspace.id | ||
ns_credentials = NetSuiteCredentials.objects.get(workspace_id=workspace.id) | ||
|
||
ns_connection = NetSuiteConnector(netsuite_credentials=ns_credentials, workspace_id=workspace_id) | ||
return NetSuiteConnector(netsuite_credentials=ns_credentials, workspace_id=workspace_id) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add error handling and input validation
The function needs proper error handling for various failure scenarios:
- Missing or invalid org_id in query_params
- Non-existent Workspace
- Missing NetSuite credentials
Consider applying this improvement:
def get_netsuite_connection(query_params: Dict):
- org_id = query_params.get('org_id')
+ """Get NetSuite connection for the given organization.
+
+ Args:
+ query_params (Dict): Dictionary containing org_id
+
+ Returns:
+ NetSuiteConnector: Initialized connector instance
+
+ Raises:
+ ValueError: If org_id is missing
+ Workspace.DoesNotExist: If workspace not found
+ NetSuiteCredentials.DoesNotExist: If credentials not found
+ """
+ org_id = query_params.get('org_id')
+ if not org_id:
+ raise ValueError('org_id is required in query_params')
workspace = Workspace.objects.get(fyle_org_id=org_id)
workspace_id = workspace.id
ns_credentials = NetSuiteCredentials.objects.get(workspace_id=workspace.id)
return NetSuiteConnector(netsuite_credentials=ns_credentials, workspace_id=workspace_id)
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
def get_netsuite_connection(query_params: Dict): | |
org_id = query_params.get('org_id') | |
resource_type = query_params.get('resource_type') | |
internal_id = query_params.get('internal_id') | |
workspace = Workspace.objects.get(fyle_org_id=org_id) | |
workspace_id = workspace.id | |
ns_credentials = NetSuiteCredentials.objects.get(workspace_id=workspace.id) | |
ns_connection = NetSuiteConnector(netsuite_credentials=ns_credentials, workspace_id=workspace_id) | |
return NetSuiteConnector(netsuite_credentials=ns_credentials, workspace_id=workspace_id) | |
def get_netsuite_connection(query_params: Dict): | |
"""Get NetSuite connection for the given organization. | |
Args: | |
query_params (Dict): Dictionary containing org_id | |
Returns: | |
NetSuiteConnector: Initialized connector instance | |
Raises: | |
ValueError: If org_id is missing | |
Workspace.DoesNotExist: If workspace not found | |
NetSuiteCredentials.DoesNotExist: If credentials not found | |
""" | |
org_id = query_params.get('org_id') | |
if not org_id: | |
raise ValueError('org_id is required in query_params') | |
workspace = Workspace.objects.get(fyle_org_id=org_id) | |
workspace_id = workspace.id | |
ns_credentials = NetSuiteCredentials.objects.get(workspace_id=workspace.id) | |
return NetSuiteConnector(netsuite_credentials=ns_credentials, workspace_id=workspace_id) |
def get_exported_entry(query_params: Dict): | ||
ns_connection = get_netsuite_connection(query_params) | ||
resource_type = query_params.get('resource_type') | ||
internal_id = query_params.get('internal_id') | ||
|
||
return ns_connection.get_exported_entry(resource_type, internal_id) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add parameter validation and documentation
Similar to get_accounting_fields, this function needs parameter validation and proper documentation.
Apply this improvement:
def get_exported_entry(query_params: Dict):
+ """Get exported entry details for the specified resource.
+
+ Args:
+ query_params (Dict): Dictionary containing org_id, resource_type, and internal_id
+
+ Returns:
+ Dict: Exported entry details
+
+ Raises:
+ ValueError: If required parameters are missing
+ """
+ resource_type = query_params.get('resource_type')
+ internal_id = query_params.get('internal_id')
+
+ if not resource_type or not internal_id:
+ raise ValueError('resource_type and internal_id are required in query_params')
+
ns_connection = get_netsuite_connection(query_params)
- resource_type = query_params.get('resource_type')
- internal_id = query_params.get('internal_id')
return ns_connection.get_exported_entry(resource_type, internal_id)
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
def get_exported_entry(query_params: Dict): | |
ns_connection = get_netsuite_connection(query_params) | |
resource_type = query_params.get('resource_type') | |
internal_id = query_params.get('internal_id') | |
return ns_connection.get_exported_entry(resource_type, internal_id) | |
def get_exported_entry(query_params: Dict): | |
"""Get exported entry details for the specified resource. | |
Args: | |
query_params (Dict): Dictionary containing org_id, resource_type, and internal_id | |
Returns: | |
Dict: Exported entry details | |
Raises: | |
ValueError: If required parameters are missing | |
""" | |
resource_type = query_params.get('resource_type') | |
internal_id = query_params.get('internal_id') | |
if not resource_type or not internal_id: | |
raise ValueError('resource_type and internal_id are required in query_params') | |
ns_connection = get_netsuite_connection(query_params) | |
return ns_connection.get_exported_entry(resource_type, internal_id) |
def get_accounting_fields(query_params: Dict): | ||
ns_connection = get_netsuite_connection(query_params) | ||
resource_type = query_params.get('resource_type') | ||
internal_id = query_params.get('internal_id') | ||
|
||
return ns_connection.get_accounting_fields(resource_type, internal_id) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add parameter validation and error handling
The function should validate the required parameters before proceeding.
Apply this improvement:
def get_accounting_fields(query_params: Dict):
+ """Get accounting fields for the specified resource.
+
+ Args:
+ query_params (Dict): Dictionary containing org_id, resource_type, and internal_id
+
+ Returns:
+ Dict: Accounting fields for the resource
+
+ Raises:
+ ValueError: If required parameters are missing
+ """
+ resource_type = query_params.get('resource_type')
+ internal_id = query_params.get('internal_id')
+
+ if not resource_type or not internal_id:
+ raise ValueError('resource_type and internal_id are required in query_params')
+
ns_connection = get_netsuite_connection(query_params)
- resource_type = query_params.get('resource_type')
- internal_id = query_params.get('internal_id')
return ns_connection.get_accounting_fields(resource_type, internal_id)
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
def get_accounting_fields(query_params: Dict): | |
ns_connection = get_netsuite_connection(query_params) | |
resource_type = query_params.get('resource_type') | |
internal_id = query_params.get('internal_id') | |
return ns_connection.get_accounting_fields(resource_type, internal_id) | |
def get_accounting_fields(query_params: Dict): | |
"""Get accounting fields for the specified resource. | |
Args: | |
query_params (Dict): Dictionary containing org_id, resource_type, and internal_id | |
Returns: | |
Dict: Accounting fields for the resource | |
Raises: | |
ValueError: If required parameters are missing | |
""" | |
resource_type = query_params.get('resource_type') | |
internal_id = query_params.get('internal_id') | |
if not resource_type or not internal_id: | |
raise ValueError('resource_type and internal_id are required in query_params') | |
ns_connection = get_netsuite_connection(query_params) | |
return ns_connection.get_accounting_fields(resource_type, internal_id) |
except Exception: | ||
logger.info(f"Error in AccountingFieldsView: {traceback.format_exc()}") | ||
return Response( | ||
data={'error': traceback.format_exc()}, | ||
status=status.HTTP_400_BAD_REQUEST | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Security & Logging Issues in Error Handling
- Sending full tracebacks in API responses exposes internal implementation details and could pose a security risk.
- Using
logger.info
for errors is incorrect - should uselogger.error
for exceptions.
Apply this fix:
except Exception:
- logger.info(f"Error in AccountingFieldsView: {traceback.format_exc()}")
+ error_traceback = traceback.format_exc()
+ logger.error(f"Error in AccountingFieldsView: {error_traceback}")
return Response(
- data={'error': traceback.format_exc()},
+ data={'error': 'An error occurred while processing your request'},
status=status.HTTP_400_BAD_REQUEST
)
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
except Exception: | |
logger.info(f"Error in AccountingFieldsView: {traceback.format_exc()}") | |
return Response( | |
data={'error': traceback.format_exc()}, | |
status=status.HTTP_400_BAD_REQUEST | |
) | |
except Exception: | |
error_traceback = traceback.format_exc() | |
logger.error(f"Error in AccountingFieldsView: {error_traceback}") | |
return Response( | |
data={'error': 'An error occurred while processing your request'}, | |
status=status.HTTP_400_BAD_REQUEST | |
) |
def get(self, request, *args, **kwargs): | ||
try: | ||
params = request.query_params | ||
assert_valid(params.get('org_id') is not None, 'Org ID is required') | ||
assert_valid(params.get('resource_type') is not None, 'Resource Type is required') | ||
assert_valid(params.get('internal_id') is not None, 'Internal ID is required') | ||
|
||
response = get_exported_entry(request.query_params) | ||
|
||
return Response( | ||
data={'data': response}, | ||
status=status.HTTP_200_OK | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Codebase verification
Error handling needs improvement in the export entry flow
The verification reveals several gaps in error handling:
- The
get_exported_entry
function inapps/internal/actions.py
doesn't have any try-catch blocks despite making critical database queries (Workspace.objects.get
,NetSuiteCredentials.objects.get
) - The
NetSuiteConnector.get_exported_entry
method inapps/netsuite/connector.py
uses dynamic attribute access (getattr
) without exception handling - Multiple potential exceptions are imported but not handled:
NetSuiteRequestError
,NetSuiteRateLimitError
,NetSuiteLoginError
Key areas that need error handling:
- Database queries in
get_netsuite_connection
- NetSuite API calls in
NetSuiteConnector.get_exported_entry
- Dynamic attribute access using
getattr
🔗 Analysis chain
Verify error handling for get_exported_entry
The view correctly validates required parameters, but we should verify error handling in the get_exported_entry
function.
Let's check the implementation of get_exported_entry
:
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Check error handling in get_exported_entry function
# Look for the function definition and its error handling
ast-grep --pattern 'def get_exported_entry($_):
$$$
'
# Also check for any existing tests
fd -e py test_.*internal.*
Length of output: 535
Script:
#!/bin/bash
# Let's check the implementation of get_netsuite_connection and its error handling
ast-grep --pattern 'def get_netsuite_connection($_):
$$$
'
# Also check if there are any try-catch blocks around get_exported_entry calls
rg -A 5 "get_exported_entry"
# Look for any custom exceptions defined
rg "class.*Error" apps/internal/
Length of output: 2261
Script:
#!/bin/bash
# Let's check for exception handling in the NetSuiteConnector class
rg -B 5 -A 10 "class NetSuiteConnector" apps/netsuite/
# Check for any exception handling in Workspace and NetSuiteCredentials models
rg -A 5 "class (Workspace|NetSuiteCredentials)" apps/
# Look for any exception imports
rg "^from.*import.*Error" apps/
Length of output: 7205
def get_exported_entry(self, resource_type: str, export_id: str): | ||
module = getattr(self.connection, resource_type) | ||
response = getattr(module, 'get')(export_id) | ||
return json.loads(json.dumps(response, default=str)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Add documentation and error handling
The method needs documentation and error handling improvements:
- Add docstring to describe parameters and return value
- Add error handling for potential NetSuiteRequestError exceptions, similar to other methods in this class
def get_exported_entry(self, resource_type: str, export_id: str):
+ """
+ Retrieve an exported entry from NetSuite.
+
+ Args:
+ resource_type (str): The type of resource to fetch (e.g., 'vendor_bills', 'expense_reports', etc.)
+ export_id (str): The NetSuite internal ID of the exported entry
+
+ Returns:
+ dict: JSON response containing the exported entry details
+
+ Raises:
+ NetSuiteRequestError: If the request to NetSuite fails
+ """
+ try:
module = getattr(self.connection, resource_type)
- response = getattr(module, 'get')(export_id)
+ response = module.get(export_id)
return json.loads(json.dumps(response, default=str))
+ except NetSuiteRequestError as e:
+ logger.info('Error while getting exported entry - %s', e)
+ raise
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
def get_exported_entry(self, resource_type: str, export_id: str): | |
module = getattr(self.connection, resource_type) | |
response = getattr(module, 'get')(export_id) | |
return json.loads(json.dumps(response, default=str)) | |
def get_exported_entry(self, resource_type: str, export_id: str): | |
""" | |
Retrieve an exported entry from NetSuite. | |
Args: | |
resource_type (str): The type of resource to fetch (e.g., 'vendor_bills', 'expense_reports', etc.) | |
export_id (str): The NetSuite internal ID of the exported entry | |
Returns: | |
dict: JSON response containing the exported entry details | |
Raises: | |
NetSuiteRequestError: If the request to NetSuite fails | |
""" | |
try: | |
module = getattr(self.connection, resource_type) | |
response = module.get(export_id) | |
return json.loads(json.dumps(response, default=str)) | |
except NetSuiteRequestError as e: | |
logger.info('Error while getting exported entry - %s', e) | |
raise |
🧰 Tools
🪛 Ruff (0.7.0)
1198-1198: Do not call getattr
with a constant attribute value. It is not any safer than normal property access.
Replace getattr
with attribute access
(B009)
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
🧹 Outside diff range and nitpick comments (2)
tests/test_internal/test_views.py (2)
46-53
: Enhance test coverage with additional error scenariosConsider adding test cases for:
- Invalid
org_id
- Invalid
resource_type
values- Invalid
internal_id
format- Assert error messages in the response body
Example addition:
response = api_client.get(url, {'org_id': 'or79Cob97KSh', 'resource_type': 'vendor_bills'}) assert response.status_code == 400 + + # Test invalid org_id + response = api_client.get(url, {'org_id': 'invalid', 'resource_type': 'vendor_bills', 'internal_id': '1'}) + assert response.status_code == 400 + assert response.json()['message'] == 'Invalid organization id' + + # Test invalid resource_type + response = api_client.get(url, {'org_id': 'or79Cob97KSh', 'resource_type': 'invalid', 'internal_id': '1'}) + assert response.status_code == 400 + assert response.json()['message'] == 'Invalid resource type'
Line range hint
13-13
: Fix typo in test function nameThe function name contains a typo:
test_netsutie_fields_view
should betest_netsuite_fields_view
-def test_netsutie_fields_view(db, api_client, mocker): +def test_netsuite_fields_view(db, api_client, mocker):
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (2)
tests/test_internal/test_actions.py
(2 hunks)tests/test_internal/test_views.py
(1 hunks)
🔇 Additional comments (2)
tests/test_internal/test_actions.py (1)
1-1
: LGTM! Import statement is correctly updated
The import statement properly includes the new get_exported_entry
function alongside the existing get_accounting_fields
.
tests/test_internal/test_views.py (1)
41-44
: Verify URL configuration for 'exported-entry'
The test assumes the existence of a URL pattern named 'exported-entry'. Let's ensure this URL pattern is properly configured.
✅ Verification successful
URL pattern 'exported-entry' is properly configured
The URL pattern 'exported-entry' is correctly defined in apps/internal/urls.py
and maps to ExportedEntryView
, matching the test's requirements.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Verify the URL pattern exists in the urls.py files
# Expected: Find URL pattern definition for 'exported-entry'
rg -l "exported-entry" --type py
Length of output: 88
Script:
#!/bin/bash
# Check the URL pattern definition in apps/internal/urls.py
rg "exported-entry" apps/internal/urls.py -B 2 -A 2
Length of output: 240
def test_get_exported_entry(db, mocker): | ||
query_params = { | ||
'org_id': 'or79Cob97KSh', | ||
'resource_type': 'vendor_bills', | ||
'internal_id': '1' | ||
} | ||
mocker.patch( | ||
'netsuitesdk.api.vendor_bills.VendorBills.get', | ||
return_value={'summa': 'hehe'} | ||
) | ||
|
||
entry = get_exported_entry(query_params) | ||
assert entry is not None |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Test implementation needs strengthening
While the basic test structure is in place, several improvements would make the test more robust and meaningful:
- The mock return value
{'summa': 'hehe'}
should be replaced with realistic test data - The assertion should verify the actual structure and content of the returned data
- Error cases should be covered
- The test should verify that the mocked function is called with correct parameters
Here's a suggested improvement:
def test_get_exported_entry(db, mocker):
query_params = {
'org_id': 'or79Cob97KSh',
'resource_type': 'vendor_bills',
'internal_id': '1'
}
+ expected_data = {
+ 'id': '1',
+ 'type': 'vendor_bills',
+ 'amount': 100.00,
+ 'status': 'PAID',
+ # Add other relevant fields
+ }
+ mock_get = mocker.patch(
'netsuitesdk.api.vendor_bills.VendorBills.get',
- return_value={'summa': 'hehe'}
+ return_value=expected_data
)
entry = get_exported_entry(query_params)
- assert entry is not None
+ assert entry == expected_data
+ mock_get.assert_called_once_with('1')
+
+ # Test error case
+ mock_get.side_effect = Exception('NetSuite API error')
+ with pytest.raises(Exception):
+ get_exported_entry(query_params)
Additionally, consider adding test cases for:
- Different resource types
- Invalid internal_id
- Missing required parameters
- API timeout scenarios
Committable suggestion skipped: line range outside the PR's diff.
💡 Codebase verification
Additional test scenarios needed for get_exported_entry
The current test only covers the 'vendor_bills' resource type, but the implementation shows it's used for multiple resource types. Missing test scenarios:
- Test with 'custom_segments', 'custom_lists', and 'custom_record_types' resource types
- Test error cases when required parameters (resource_type, internal_id) are missing
- Test with invalid NetSuite connection parameters
🔗 Analysis chain
Verify test coverage for all scenarios
Let's ensure the test coverage aligns with the implementation in apps.internal.actions.get_exported_entry
.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Find all possible resource types and parameters used in the implementation
ast-grep --pattern 'def get_exported_entry($$$)' -f 'apps/internal/actions.py' -A 20
# Check for error handling patterns that should be tested
rg -t python "raise\s+\w+Error" apps/internal/actions.py
Length of output: 352
Script:
#!/bin/bash
# Find the implementation of get_exported_entry
ast-grep --pattern 'def get_exported_entry($$$)'
# Find error handling patterns
rg "raise.*Error"
# Find resource types handling
rg "resource_type.*=|resource_type.*in"
Length of output: 5554
Script:
#!/bin/bash
# Find the complete implementation of get_exported_entry in connector
ast-grep --pattern 'def get_exported_entry($$$)'
# Find all test files related to exported entries
fd test.*actions.py
# Look for resource type validations
rg -B2 -A2 "resource_type.*=" apps/internal/actions.py
Length of output: 619
mocker.patch( | ||
'netsuitesdk.api.vendor_bills.VendorBills.get', | ||
return_value={'summa': 'hehe'} | ||
) | ||
|
||
response = api_client.get(url, {'org_id': 'or79Cob97KSh', 'resource_type': 'vendor_bills', 'internal_id': '1'}) | ||
assert response.status_code == 200 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Improve test data and response validation
The current implementation has several areas for improvement:
- The mock return value
{'summa': 'hehe'}
doesn't reflect a realistic NetSuite response structure - The test only verifies the status code without validating the response data
- Test data should be moved to the fixtures file for consistency with other tests
Suggested improvements:
+ # Import test data from fixtures
+ from tests.test_netsuite.fixtures import data
+
mocker.patch(
'netsuitesdk.api.vendor_bills.VendorBills.get',
- return_value={'summa': 'hehe'}
+ return_value=data['get_vendor_bill'] # Add realistic test data to fixtures
)
response = api_client.get(url, {'org_id': 'or79Cob97KSh', 'resource_type': 'vendor_bills', 'internal_id': '1'})
assert response.status_code == 200
+ response_data = response.json()
+
+ # Verify response structure
+ expected_fields = ['id', 'status', 'amount', ...] # Add expected fields
+ for field in expected_fields:
+ assert field in response_data
Committable suggestion skipped: line range outside the PR's diff.
* tests: get accounting field internal API * feat: Add internal API for get exported entry (#679) * feat: Add internal API for get exported entry * add tests
Description
Please add PR description here, add screenshots if needed
Clickup
https://app.clickup.com/
Summary by CodeRabbit