Skip to content
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: Added limits to attributes #564

Merged
merged 5 commits into from
Oct 8, 2024
Merged

Conversation

Ashutosh619-sudo
Copy link
Contributor

@Ashutosh619-sudo Ashutosh619-sudo commented Oct 1, 2024

Description

Please add PR description here, add screenshots if needed

Clickup

Please add link here
https://app.clickup.com/1864988/v/l/6-901603904304-1

Summary by CodeRabbit

  • New Features

    • Introduced a new method to enforce synchronization limits for various entity types.
    • Updated synchronization processes to include checks for permitted sync operations based on defined limits.
  • Bug Fixes

    • Enhanced the synchronization process to prevent exceeding attribute limits, improving overall reliability.
  • Documentation

    • Added comments for better clarity and understanding of the synchronization logic.
  • Tests

    • Expanded test coverage for synchronization logic, including enhancements for expense attributes, employee mappings, and error resolution.
    • Added tests to validate the skipping of synchronization when limits are exceeded.

Copy link
Contributor

coderabbitai bot commented Oct 1, 2024

Walkthrough

The changes introduce a new method, is_sync_allowed, in the SageIntacctConnector class, which regulates synchronization limits for various entity types based on attribute counts. The synchronization methods for accounts, departments, expense types, and others have been updated to incorporate this check, enhancing the control flow and ensuring compliance with defined synchronization limits. Additionally, the SYNC_UPPER_LIMIT dictionary has been modified, and minor formatting adjustments and comments have been added for clarity.

Changes

Files Change Summary
apps/sage_intacct/utils.py Added is_sync_allowed method to enforce synchronization limits; updated multiple sync methods to utilize this check; modified SYNC_UPPER_LIMIT dictionary; included minor formatting and comments.
tests/test_mappings/test_imports/test_modules/test_categories.py Enhanced mocking of external API calls and adjusted assertions for category synchronization; refined import logic and test case structure.
tests/test_mappings/test_imports/test_modules/test_expense_custom_fields.py Improved tests for syncing expense attributes and destination attributes; expanded mock patches for API calls.
tests/test_mappings/test_imports/test_modules/test_tax_groups.py Modified tests to verify synchronization of tax group attributes; added mock for TaxDetails.count.
tests/test_mappings/test_tasks.py Added new tests and modified existing ones for expense attributes, employee mappings, and scheduling tasks; enhanced error resolution tests.
tests/test_sageintacct/test_utils.py Updated tests for SageIntacctConnector to include new mocks for various entity counts; refined tests for financial document construction.

Possibly related PRs

  • Sync allocation #526: The changes in this PR enhance the SageIntacctConnector class in apps/sage_intacct/utils.py, which is directly related to the synchronization methods modified in the main PR, particularly in how synchronization is handled for various entities.
  • feat: Add generators in all the sage dimension sync #551: This PR also modifies synchronization methods in apps/sage_intacct/utils.py, adding generators to improve efficiency, which aligns with the changes made in the main PR regarding synchronization logic.
  • feat: Fix generator code and remove loggers #563: This PR addresses modifications in the SageIntacctConnector class, including updates to synchronization methods, which are relevant to the changes made in the main PR regarding the synchronization process.

Suggested labels

deploy, size/XL

Suggested reviewers

  • ruuushhh
  • DhaaraniCIT

Poem

In the garden where data flows,
A rabbit hops where the sync limit grows.
With checks in place, we dance and play,
Ensuring smooth syncs every day! 🐇✨
Attributes count, but worries are few,
Thanks to the changes, we know what to do!


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?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

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)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@github-actions github-actions bot added the size/M Medium PR label Oct 1, 2024
Copy link

github-actions bot commented Oct 1, 2024

Tests Skipped Failures Errors Time
281 0 💤 19 ❌ 0 🔥 39.495s ⏱️

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Outside diff range and nitpick comments (2)
apps/sage_intacct/utils.py (2)

117-117: Avoid hardcoding dates; consider making the date configurable

Hardcoding the date datetime(2024, 10, 1) may lead to maintenance issues in the future. Consider defining the date as a constant or retrieving it from a configuration to improve flexibility.

Apply this diff to define the date as a constant:

+    SYNC_START_DATE = datetime(2024, 10, 1)
     workspace_created_at = Workspace.objects.get(id=self.workspace_id).created_at
-    if workspace_created_at > datetime(2024, 10, 1) and attribute_count > SYNC_UPPER_LIMIT[attribute_type]:
+    if workspace_created_at > SYNC_START_DATE and attribute_count > SYNC_UPPER_LIMIT[attribute_type]:

Alternatively, define SYNC_START_DATE at the class or module level for broader accessibility.

🧰 Tools
🪛 Ruff

117-120: Return the negated condition directly

Inline condition

(SIM103)


150-151: Correct grammatical errors in log messages

The log messages contain minor grammatical errors. Adjust them for clarity and correctness.

Apply this diff to correct the messages:

-        logger.info('Skipping sync of accounts for workspace %s as it has %s counts which is over the limit', self.workspace_id, attribute_count)
+        logger.info('Skipping sync of accounts for workspace %s as it has %s items which are over the limit', self.workspace_id, attribute_count)

-        logger.info('Skipping sync of department for workspace %s as it has %s counts which is over the limit', self.workspace_id, attribute_count)
+        logger.info('Skipping sync of departments for workspace %s as it has %s items which are over the limit', self.workspace_id, attribute_count)

-        logger.info('Skipping sync of expense_type for workspace %s as it has %s counts which is over the limit', self.workspace_id, attribute_count)
+        logger.info('Skipping sync of expense types for workspace %s as it has %s items which are over the limit', self.workspace_id, attribute_count)

-        logger.info('Skipping sync of cost_types for workspace %s as it has %s counts which is over the limit', self.workspace_id, attribute_count)
+        logger.info('Skipping sync of cost types for workspace %s as it has %s items which are over the limit', self.workspace_id, attribute_count)

-        logger.info('Skipping sync of projects for workspace %s as it has %s counts which is over the limit', self.workspace_id, attribute_count)
+        logger.info('Skipping sync of projects for workspace %s as it has %s items which are over the limit', self.workspace_id, attribute_count)

-        logger.info('Skipping sync of items for workspace %s as it has %s counts which is over the limit', self.workspace_id, attribute_count)
+        logger.info('Skipping sync of items for workspace %s as it has %s items which are over the limit', self.workspace_id, attribute_count)

-        logger.info('Skipping sync of locations for workspace %s as it has %s counts which is over the limit', self.workspace_id, attribute_count)
+        logger.info('Skipping sync of locations for workspace %s as it has %s items which are over the limit', self.workspace_id, attribute_count)

-        logger.info('Skipping sync of classes for workspace %s as it has %s counts which is over the limit', self.workspace_id, attribute_count)
+        logger.info('Skipping sync of classes for workspace %s as it has %s items which are over the limit', self.workspace_id, attribute_count)

-        logger.info('Skipping sync of customers for workspace %s as it has %s counts which is over the limit', self.workspace_id, attribute_count)
+        logger.info('Skipping sync of customers for workspace %s as it has %s items which are over the limit', self.workspace_id, attribute_count)

-        logger.info('Skipping sync of tax_details for workspace %s as it has %s counts which is over the limit', self.workspace_id, attribute_count)
+        logger.info('Skipping sync of tax details for workspace %s as it has %s items which are over the limit', self.workspace_id, attribute_count)

Also applies to: 198-199, 235-236, 325-326, 356-357, 400-401, 433-434, 650-651, 678-679, 707-708

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 19d59d8 and 5d1190d.

📒 Files selected for processing (1)
  • apps/sage_intacct/utils.py (8 hunks)
🧰 Additional context used
🪛 Ruff
apps/sage_intacct/utils.py

117-120: Return the negated condition directly

Inline condition

(SIM103)

🔇 Additional comments (1)
apps/sage_intacct/utils.py (1)

117-120: [Verify] Ensure the SYNC_UPPER_LIMIT dictionary includes all necessary attribute types

Verify that all attribute types used in the is_sync_allowed method are present in the SYNC_UPPER_LIMIT dictionary to prevent KeyError exceptions.

Run the following script to list all attribute types checked and ensure they are keys in SYNC_UPPER_LIMIT:

🧰 Tools
🪛 Ruff

117-120: Return the negated condition directly

Inline condition

(SIM103)

Comment on lines +149 to +151
if not self.is_sync_allowed(attribute_type = 'accounts', attribute_count=attribute_count):
logger.info('Skipping sync of accounts for workspace %s as it has %s counts which is over the limit', self.workspace_id, attribute_count)
return
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Refactor repetitive sync checks to a helper method

The pattern of obtaining attribute_count, checking is_sync_allowed, logging, and returning is repeated across multiple sync_* methods. Consider refactoring this logic into a helper function to reduce code duplication and enhance maintainability.

Here's an example of how you might refactor the repeated code:

def check_and_sync(self, attribute_name: str, attribute_type: str, sync_function):
    attribute_count = getattr(self.connection, attribute_name).count()
    if not self.is_sync_allowed(attribute_type=attribute_type, attribute_count=attribute_count):
        logger.info('Skipping sync of %s for workspace %s as it has %s items which are over the limit', attribute_type, self.workspace_id, attribute_count)
        return
    sync_function()

Then, update your sync_* methods accordingly:

-    def sync_accounts(self):
+    def sync_accounts(self):
         """
         Get accounts
         """
-        attribute_count = self.connection.accounts.count()
-        if not self.is_sync_allowed(attribute_type='accounts', attribute_count=attribute_count):
-            logger.info('Skipping sync of accounts for workspace %s as it has %s counts which is over the limit', self.workspace_id, attribute_count)
-            return
+        self.check_and_sync('accounts', 'accounts', self._sync_accounts_logic)

+    def _sync_accounts_logic(self):
+        # Existing logic for syncing accounts goes here

Repeat this pattern for the other sync_* methods by moving their existing logic into corresponding private methods (e.g., _sync_departments_logic) and calling them through check_and_sync.

Also applies to: 196-200, 233-237, 323-327, 354-358, 399-402, 431-434, 648-652, 676-680, 705-709

Comment on lines 117 to 120
if workspace_created_at > datetime(2024, 10, 1) and attribute_count > SYNC_UPPER_LIMIT[attribute_type]:
return False

return True
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Simplify the return statement by returning the condition directly

The is_sync_allowed method can be simplified by returning the negated condition directly, improving readability and conciseness.

Apply this diff to simplify the return statement:

     workspace_created_at = Workspace.objects.get(id=self.workspace_id).created_at
-    if workspace_created_at > datetime(2024, 10, 1) and attribute_count > SYNC_UPPER_LIMIT[attribute_type]:
-        return False
-
-    return True
+    return not (workspace_created_at > datetime(2024, 10, 1) and attribute_count > SYNC_UPPER_LIMIT[attribute_type])
📝 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.

Suggested change
if workspace_created_at > datetime(2024, 10, 1) and attribute_count > SYNC_UPPER_LIMIT[attribute_type]:
return False
return True
workspace_created_at = Workspace.objects.get(id=self.workspace_id).created_at
return not (workspace_created_at > datetime(2024, 10, 1) and attribute_count > SYNC_UPPER_LIMIT[attribute_type])
🧰 Tools
🪛 Ruff

117-120: Return the negated condition directly

Inline condition

(SIM103)

@github-actions github-actions bot added size/L Large PR and removed size/M Medium PR labels Oct 1, 2024
Copy link

github-actions bot commented Oct 1, 2024

Tests Skipped Failures Errors Time
281 0 💤 0 ❌ 0 🔥 39.952s ⏱️

Copy link
Contributor

@coderabbitai coderabbitai bot left a 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 (5)
tests/test_mappings/test_imports/test_modules/test_tax_groups.py (2)

Line range hint 10-10: Fix the typo in the function name

The function name test_sync_destination_atrributes is misspelled. It should be test_sync_destination_attributes.

Apply this diff to correct the function name:

-def test_sync_destination_atrributes(mocker, db):
+def test_sync_destination_attributes(mocker, db):

Line range hint 40-40: Fix the typo in the function name

The function name test_sync_expense_atrributes is misspelled. It should be test_sync_expense_attributes.

Apply this diff to correct the function name:

-def test_sync_expense_atrributes(mocker, db):
+def test_sync_expense_attributes(mocker, db):
tests/test_mappings/test_tasks.py (2)

140-147: Consider adding assertions to validate synchronization with non-zero counts

You've appropriately mocked the Locations.count and Departments.count methods to return 1, simulating scenarios where these entities are present. To enhance test robustness, consider adding assertions that verify the synchronization logic handles these counts as expected.


173-177: Ensure test coverage for scenarios with zero cost types

Mocking CostTypes.count to return 0 effectively simulates the absence of cost types. Adding assertions to confirm that the synchronization logic correctly handles this scenario will strengthen the test and ensure that edge cases are properly validated.

tests/test_sageintacct/test_utils.py (1)

Line range hint 510-542: Unusual attribute key 'GLDIMWHAT_IS_NILESH_PANT' in test assertion

In the test_sync_allocations function, the assertion checks for 'GLDIMWHAT_IS_NILESH_PANT' as a key in allocation_attribute.detail.keys(). This attribute name appears unconventional and might be a placeholder or temporary identifier. Please verify if this is intentional and consider renaming it to reflect its purpose more clearly.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 5d1190d and 1a25f46.

📒 Files selected for processing (6)
  • apps/sage_intacct/utils.py (9 hunks)
  • tests/test_mappings/test_imports/test_modules/test_categories.py (7 hunks)
  • tests/test_mappings/test_imports/test_modules/test_expense_custom_fields.py (1 hunks)
  • tests/test_mappings/test_imports/test_modules/test_tax_groups.py (2 hunks)
  • tests/test_mappings/test_tasks.py (2 hunks)
  • tests/test_sageintacct/test_utils.py (5 hunks)
🧰 Additional context used
🪛 Ruff
apps/sage_intacct/utils.py

118-121: Return the negated condition directly

Inline condition

(SIM103)

🔇 Additional comments (13)
apps/sage_intacct/utils.py (6)

149-153: LGTM: Sync allowance check added

The addition of the sync allowance check at the beginning of the sync_accounts method is a good improvement. It prevents unnecessary processing when the sync is not allowed and provides informative logging.


197-201: LGTM: Consistent sync allowance check added

The addition of the sync allowance check in the sync_departments method is consistent with the changes in the sync_accounts method. This ensures that department synchronization adheres to the defined limits and prevents unnecessary processing when sync is not allowed.


234-238: LGTM: Sync allowance check added for expense types

The addition of the sync allowance check in the sync_expense_types method is consistent with the changes in other sync methods. This ensures that expense type synchronization adheres to the defined limits and prevents unnecessary processing when sync is not allowed.


355-391: LGTM: Sync allowance check and formatting improvements

The changes in the sync_projects method include:

  1. Addition of a sync allowance check, consistent with other sync methods.
  2. Improved code formatting with better whitespace usage.

These changes enhance sync control and improve code readability.


399-423: LGTM: Sync allowance check and formatting improvements for items

The changes in the sync_items method include:

  1. Addition of a sync allowance check, consistent with other sync methods.
  2. Improved code formatting with better whitespace usage.

These changes enhance sync control and improve code readability.


649-669: LGTM: Sync allowance check and formatting improvements for classes

The changes in the sync_classes method include:

  1. Addition of a sync allowance check, consistent with other sync methods.
  2. Improved code formatting with better whitespace usage.

These changes enhance sync control and improve code readability.

tests/test_mappings/test_imports/test_modules/test_tax_groups.py (2)

15-18: LGTM!

The mocking of sageintacctsdk.apis.TaxDetails.count is set up correctly to return 100, which aligns with the test requirements.


87-90: LGTM!

The additional mock setup for sageintacctsdk.apis.TaxDetails.count is appropriate and ensures consistent test behavior by returning 100.

tests/test_mappings/test_imports/test_modules/test_categories.py (2)

42-46: Refactor repeated mocks into fixtures or helper functions

Similarly, the mock for 'sageintacctsdk.apis.ExpenseTypes.count' with a return value of 5 is repeated. Refactoring this into a shared fixture can improve code reusability.


238-241: Verify handling of zero accounts in tests

The mocked return value of 'sageintacctsdk.apis.Accounts.count' is set to 0. Please ensure that the test correctly handles cases where there are no accounts and that all assertions reflect the expected behavior in this scenario.

tests/test_sageintacct/test_utils.py (3)

79-82: Properly mocked 'Departments.count' in the test

The addition of the mock for 'sageintacctsdk.apis.Departments.count' ensures that the test simulates department counts accurately, leading to more reliable test outcomes.


102-106: Properly mocked 'ExpenseTypes.count' in the test

Including the mock for 'sageintacctsdk.apis.ExpenseTypes.count' allows the test to correctly simulate the number of expense types, enhancing the test's reliability.


221-224: Properly mocked 'Locations.count' in the test

Adding the mock for 'sageintacctsdk.apis.Locations.count' ensures the test accurately reflects location counts, contributing to more dependable test results.

Comment on lines 110 to 121
def is_sync_allowed(self, attribute_type: str, attribute_count: int):
"""
Checks if the sync is allowed

Returns:
bool: True
"""
workspace_created_at = Workspace.objects.get(id=self.workspace_id).created_at
if workspace_created_at > timezone.make_aware(datetime(2024, 10, 1), timezone.get_current_timezone()) and attribute_count > SYNC_UPPER_LIMIT[attribute_type]:
return False

return True
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Simplify the return statement and add error handling

The is_sync_allowed method can be improved in two ways:

  1. Simplify the return statement by directly returning the boolean expression.
  2. Add error handling for cases where the attribute_type is not in the SYNC_UPPER_LIMIT dictionary.

Here's a suggested implementation:

 def is_sync_allowed(self, attribute_type: str, attribute_count: int):
     """
     Checks if the sync is allowed

     Returns:
-        bool: True
+        bool: True if sync is allowed, False otherwise
     """
     workspace_created_at = Workspace.objects.get(id=self.workspace_id).created_at
-    if workspace_created_at > timezone.make_aware(datetime(2024, 10, 1), timezone.get_current_timezone()) and attribute_count > SYNC_UPPER_LIMIT[attribute_type]:
-        return False
-
-    return True
+    if attribute_type not in SYNC_UPPER_LIMIT:
+        logger.warning(f"Unknown attribute type: {attribute_type}")
+        return False
+    
+    return not (
+        workspace_created_at > timezone.make_aware(datetime(2024, 10, 1), timezone.get_current_timezone())
+        and attribute_count > SYNC_UPPER_LIMIT[attribute_type]
+    )

This change simplifies the logic, improves readability, and adds error handling for unknown attribute types.

Committable suggestion was skipped due to low confidence.

🧰 Tools
🪛 Ruff

118-121: Return the negated condition directly

Inline condition

(SIM103)

Comment on lines +62 to +65
mocker.patch(
'sageintacctsdk.apis.Locations.count',
return_value=21
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Inconsistent use of mock.patch and mocker.patch

In this test function, both mock.patch (from the unittest.mock module) and mocker.patch (from the pytest-mock plugin) are used. Mixing these two can lead to confusion and potential issues in test behavior. It's recommended to use one mocking approach consistently throughout your tests to enhance readability and maintainability. Since mock.patch is used in your context managers elsewhere in the test, consider replacing mocker.patch with mock.patch.

Apply this diff to standardize the mocking framework:

-    mocker.patch(
+    with mock.patch(
         'sageintacctsdk.apis.Locations.count',
         return_value=21
-    )
+    ):
+        # Place the code that requires the patched method here

Alternatively, if you prefer using mocker.patch, replace all instances of mock.patch with mocker.patch.

Committable suggestion was skipped due to low confidence.

Comment on lines +19 to +22
mocker.patch(
'sageintacctsdk.apis.Accounts.count',
return_value=2
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Refactor repeated mocks into fixtures or helper functions

The mock patching of 'sageintacctsdk.apis.Accounts.count' with a return value of 2 is duplicated across multiple tests. Consider refactoring this mock into a fixture or helper function to reduce code duplication and enhance maintainability.

Comment on lines +453 to +456
mocker.patch(
'sageintacctsdk.apis.TaxDetails.count',
return_value=5
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Inconsistency between mocked 'TaxDetails.count' and test assertions

The mock for 'sageintacctsdk.apis.TaxDetails.count' returns 5, but both tax_code_count and new_tax_code_count are asserted to be 0. This inconsistency may lead to confusion or inaccurate test results. Please verify and adjust the return value or assertions accordingly to ensure the test reflects the intended scenario.

Comment on lines +476 to +479
mocker.patch(
'sageintacctsdk.apis.Accounts.count',
return_value=5
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Inconsistency between mocked 'Accounts.count' and test assertions

The mock for 'sageintacctsdk.apis.Accounts.count' returns 5, yet both account_count and new_account_count are asserted to be 170. This mismatch could cause the test to produce misleading results. Please ensure the mocked return value aligns with the expected counts to maintain test accuracy.

Comment on lines +79 to +82
mocker.patch(
'sageintacctsdk.apis.Departments.count',
return_value=2
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider refactoring repeated mock patches into a reusable fixture

The mock patches for '*.count' methods are repeated across multiple tests. Refactoring these into a common fixture or helper function can reduce code duplication and improve test maintainability.

Also applies to: 102-106, 221-224, 453-456, 476-479

Copy link

github-actions bot commented Oct 1, 2024

Tests Skipped Failures Errors Time
281 0 💤 0 ❌ 0 🔥 42.900s ⏱️

@ashwin1111 ashwin1111 requested a review from ruuushhh October 1, 2024 11:43
Returns:
bool: True
"""
workspace_created_at = Workspace.objects.get(id=self.workspace_id).created_at
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


if attribute_count > SYNC_UPPER_LIMIT[attribute_type]:
    workspace_created_at = Workspace.objects.get(id=self.workspace_id).created_at
    if workspace_created_at > timezone.make_aware(datetime(2024, 10, 1), timezone.get_current_timezone()):
        return False
    else:
        return True

return True

output doesn't change but this queries db only when count is > limit

'detail': detail
})

DestinationAttribute.bulk_create_or_update_destination_attributes(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

upsert should happen per page


DestinationAttribute.bulk_create_or_update_destination_attributes(
item_attributes, 'ITEM', self.workspace_id, True)
DestinationAttribute.bulk_create_or_update_destination_attributes(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

upsert should happen per page


DestinationAttribute.bulk_create_or_update_destination_attributes(
class_attributes, 'CLASS', self.workspace_id, True)
DestinationAttribute.bulk_create_or_update_destination_attributes(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as above


DestinationAttribute.bulk_create_or_update_destination_attributes(
customer_attributes, 'CUSTOMER', self.workspace_id, True)
DestinationAttribute.bulk_create_or_update_destination_attributes(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same

@@ -459,6 +473,10 @@ def test_sync_tax_details(mocker, db):
def tests_sync_accounts(mocker, db):
workspace_id = 1

mocker.patch(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pls to add tests for skip case by mocking and returning high values

Copy link

github-actions bot commented Oct 3, 2024

Tests Skipped Failures Errors Time
282 0 💤 0 ❌ 0 🔥 40.195s ⏱️

Copy link

github-actions bot commented Oct 3, 2024

Tests Skipped Failures Errors Time
282 0 💤 0 ❌ 0 🔥 39.742s ⏱️

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Outside diff range and nitpick comments (3)
tests/test_sageintacct/test_utils.py (2)

936-969: LGTM: New skip sync test added

Great addition of the test_skip_sync_attributes function. This test covers the important case of skipping synchronization when the number of attributes is too high. It effectively addresses the previously requested skip case tests.

A small suggestion for improvement:
Instead of using datetime.today(), consider using a fixed date or freezegun library to make the test deterministic. This will prevent potential issues if the test is run close to midnight or if the date affects the behavior in any way.


Line range hint 1-969: Overall improvements with some remaining issues

The changes in this file generally improve the test coverage and structure:

  1. New mocks have been added for various API calls, enhancing the test isolation.
  2. A new test function test_skip_sync_attributes has been implemented, addressing the previously requested skip case scenarios.
  3. Code readability has been improved with better spacing between functions.

However, there are still some areas that need attention:

  1. Some inconsistencies between mocked values and assertions remain, as noted in previous comments.
  2. Consider refactoring repeated mock patches into reusable fixtures, as suggested earlier.
  3. The new test function could be made more deterministic by using a fixed date instead of datetime.today().

Please address these remaining issues to further improve the quality and reliability of the test suite.

apps/sage_intacct/utils.py (1)

358-385: LGTM! Good improvements to the sync_projects method.

The changes to the sync_projects method are well-implemented:

  1. The addition of the is_sync_allowed check is consistent with other sync methods, preventing excessive syncing.
  2. The updated method structure improves readability and potentially efficiency.
  3. The use of construct_get_all_generator_params and is_import_enabled methods suggests good code reuse.

One minor suggestion for improvement:

Consider renaming the params variable to something more descriptive, such as generator_params or sync_params, to better reflect its purpose:

generator_params = self.construct_get_all_generator_params(fields=fields, latest_updated_at=latest_updated_at)
project_generator = self.connection.projects.get_all_generator(**generator_params)

This small change could further enhance code readability.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 1a25f46 and bc844d9.

📒 Files selected for processing (2)
  • apps/sage_intacct/utils.py (13 hunks)
  • tests/test_sageintacct/test_utils.py (7 hunks)
🧰 Additional context used
🪛 Ruff
apps/sage_intacct/utils.py

119-122: Return the negated condition directly

Inline condition

(SIM103)

🔇 Additional comments (13)
tests/test_sageintacct/test_utils.py (5)

3-3: LGTM: Necessary import added

The addition of the datetime import is correct and will be used in the new test case added later in the file.


80-83: Consider using a more flexible mocking approach

The new mock for 'sageintacctsdk.apis.Departments.count' is correctly implemented. However, consider using a variable or parameterized value instead of a fixed return value of 2. This would allow for testing different scenarios more easily.

As previously suggested, consider refactoring repeated mock patches into a reusable fixture to improve test maintainability.


454-457: New mock added, but inconsistency remains

The new mock for 'sageintacctsdk.apis.TaxDetails.count' is correctly implemented. However, the previously noted inconsistency between the mocked count (5) and the test assertions (0) still exists. Please review and adjust either the mock return value or the assertions to ensure the test accurately reflects the intended scenario.


477-480: New mock added, but issues remain

The new mock for 'sageintacctsdk.apis.Accounts.count' is correctly implemented. However:

  1. The previously noted inconsistency between the mocked count (5) and the test assertions (170) still exists. Please review and adjust either the mock return value or the assertions to ensure the test accurately reflects the intended scenario.

  2. The requested tests for the skip case have not been implemented yet. Consider adding these tests to improve coverage.


934-935: LGTM: Improved readability

The addition of blank lines improves the readability of the code by clearly separating test functions.

apps/sage_intacct/utils.py (8)

152-156: LGTM! Good addition of sync limit check.

The addition of the is_sync_allowed check is a good improvement to prevent excessive syncing. The log message is informative and includes relevant details. The early return prevents unnecessary processing if sync is not allowed.


200-204: LGTM! Consistent implementation of sync limit check.

The addition of the is_sync_allowed check in the sync_departments method is consistent with the improvements in the sync_accounts method. This ensures a uniform approach to preventing excessive syncing across different entity types.


237-241: LGTM! Consistent implementation of sync limit check for expense types.

The addition of the is_sync_allowed check in the sync_expense_types method maintains consistency with other sync methods. This uniform approach to preventing excessive syncing across different entity types is commendable.


435-438: LGTM! Consistent implementation of sync limit check for locations.

The addition of the is_sync_allowed check in the sync_locations method maintains consistency with other sync methods. This uniform approach to preventing excessive syncing across different entity types is commendable.


652-669: LGTM! Good improvements to the sync_classes method.

The changes to the sync_classes method are well-implemented:

  1. The addition of the is_sync_allowed check is consistent with other sync methods, preventing excessive syncing.
  2. The updated method structure improves readability.
  3. The use of a generator for fetching classes suggests efficient data handling.

These changes maintain consistency with other sync methods and improve the overall functionality of the method.


680-698: LGTM! Consistent improvements to the sync_customers method.

The changes to the sync_customers method are well-implemented and consistent with the improvements made to other sync methods:

  1. The addition of the is_sync_allowed check prevents excessive syncing.
  2. The updated method structure improves readability.
  3. The use of a generator for fetching customers suggests efficient data handling.

These changes maintain consistency across sync methods and improve the overall functionality of the method.


709-713: LGTM! Consistent implementation of sync limit check for tax details.

The addition of the is_sync_allowed check in the sync_tax_details method maintains consistency with other sync methods. This uniform approach to preventing excessive syncing across different entity types is commendable.


402-423: LGTM! Good improvements to the sync_items method with a query.

The changes to the sync_items method are well-implemented and consistent with other sync methods. The addition of the is_sync_allowed check prevents excessive syncing, which is good.

I noticed an interesting condition in the code:

if item['ITEMTYPE'] == 'Non-Inventory':
    # ... add item to item_attributes

Could you provide more context about why only 'Non-Inventory' items are being processed? This selective processing might have implications for the overall synchronization process. If this is intentional, consider adding a comment explaining the rationale. If not, we might need to review if other item types should be included.

To verify this, we can check if there are other item types in use:

This will help us understand if there are other item types that might need to be considered in this synchronization process.

Comment on lines +110 to +124
def is_sync_allowed(self, attribute_type: str, attribute_count: int):
"""
Checks if the sync is allowed

Returns:
bool: True
"""
if attribute_count > SYNC_UPPER_LIMIT[attribute_type]:
workspace_created_at = Workspace.objects.get(id=self.workspace_id).created_at
if workspace_created_at > timezone.make_aware(datetime(2024, 10, 1), timezone.get_current_timezone()):
return False
else:
return True

return True
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Improve the is_sync_allowed method for better readability and robustness.

The is_sync_allowed method can be improved in several ways:

  1. Simplify the return statement for better readability.
  2. Add error handling for unknown attribute types.
  3. Consider making the date (October 1, 2024) configurable.
  4. Add a docstring for better documentation.

Here's a suggested implementation:

def is_sync_allowed(self, attribute_type: str, attribute_count: int) -> bool:
    """
    Checks if the sync is allowed based on attribute type and count.

    Args:
        attribute_type (str): The type of attribute being synced.
        attribute_count (int): The count of attributes.

    Returns:
        bool: True if sync is allowed, False otherwise.

    Raises:
        ValueError: If the attribute_type is unknown.
    """
    if attribute_type not in SYNC_UPPER_LIMIT:
        raise ValueError(f"Unknown attribute type: {attribute_type}")

    workspace_created_at = Workspace.objects.get(id=self.workspace_id).created_at
    sync_limit_date = timezone.make_aware(datetime(2024, 10, 1), timezone.get_current_timezone())

    return not (
        workspace_created_at > sync_limit_date
        and attribute_count > SYNC_UPPER_LIMIT[attribute_type]
    )

This implementation improves readability, adds error handling, and includes a docstring for better documentation. Consider making the sync_limit_date configurable if needed.

🧰 Tools
🪛 Ruff

119-122: Return the negated condition directly

Inline condition

(SIM103)

workspace_id = 1

mocker.patch(
'sageintacctsdk.apis.Classes.count',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same comment as netsuite

Copy link

github-actions bot commented Oct 3, 2024

Tests Skipped Failures Errors Time
282 0 💤 0 ❌ 0 🔥 41.292s ⏱️

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between bc844d9 and 606c30f.

📒 Files selected for processing (1)
  • tests/test_sageintacct/test_utils.py (7 hunks)

Comment on lines +938 to +980
mocker.patch(
'sageintacctsdk.apis.Projects.count',
return_value=25001
)
mocker.patch(
'sageintacctsdk.apis.Classes.count',
return_value=1001
)
mocker.patch(
'sageintacctsdk.apis.Accounts.count',
return_value=2001
)
mocker.patch(
'sageintacctsdk.apis.Locations.count',
return_value=1001
)
mocker.patch(
'sageintacctsdk.apis.Departments.count',
return_value=1001
)
mocker.patch(
'sageintacctsdk.apis.Customers.count',
return_value=10001
)
mocker.patch(
'sageintacctsdk.apis.Vendors.count',
return_value=20001
)

mocker.patch(
'sageintacctsdk.apis.TaxDetails.count',
return_value=201
)

mocker.patch(
'sageintacctsdk.apis.CostTypes.count',
return_value=500001
)

mocker.patch(
'sageintacctsdk.apis.ExpenseTypes.count',
return_value=1001
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider refactoring repeated mock patches into a reusable fixture

In the test_skip_sync_attributes function, the mock patches for 'sageintacctsdk.apis.*.count' are repeated multiple times. Refactoring these mock patches into a common fixture or helper function can reduce code duplication and improve test maintainability.

@Ashutosh619-sudo Ashutosh619-sudo merged commit 95d7cf6 into master Oct 8, 2024
3 checks passed
Ashutosh619-sudo added a commit that referenced this pull request Oct 9, 2024
* feat: Added limits to attributes

* test fixed

* resolved comments and added test

* removed loggers

* added test
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
size/L Large PR
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants