Skip to content

chore: remove is_sync_after_timestamp_enabled#890

Open
ruuushhh wants to merge 3 commits intomasterfrom
chore-remove-is_sync_after_timestamp_enabled
Open

chore: remove is_sync_after_timestamp_enabled#890
ruuushhh wants to merge 3 commits intomasterfrom
chore-remove-is_sync_after_timestamp_enabled

Conversation

@ruuushhh
Copy link
Contributor

@ruuushhh ruuushhh commented Aug 13, 2025

Description

chore: remove is_sync_after_timestamp_enabled

Clickup

https://app.clickup.com/

Summary by CodeRabbit

  • Bug Fixes

    • Improved QuickBooks Online syncing for items, accounts, departments, tax codes, vendors, employees, classes, and customers: inactive records are now consistently included, reducing missed updates.
  • Refactor

    • Standardized per-entity incremental syncing and unified sync flows for more consistent and reliable sync behavior.
  • Chores

    • Removed a deprecated workspace setting related to sync-after timestamps.

@coderabbitai
Copy link

coderabbitai bot commented Aug 13, 2025

Walkthrough

Standardizes QuickBooks Online entity syncing to a single per-entity sync_after timestamp, removes WorkspaceGeneralSettings gating and batching/transactional deactivation, always advances sync timestamps after each entity, removes the is_sync_after_timestamp_enabled field, updates fixtures/serializers, and expands tests to multi-entity sync flows.

Changes

Cohort / File(s) Summary
QBO Sync Utilities
apps/quickbooks_online/utils.py
Consolidated per-entity sync flow using get_entity_sync_timestamp; unified inactive retrieval via get_inactive(sync_after); removed gating on WorkspaceGeneralSettings and transactional batching; unconditionally call QBOSyncTimestamp.update_sync_timestamp; changed get_entity_sync_timestamp return annotation to str.
Workspace Settings Removal
apps/workspaces/migrations/0056_remove_workspacegeneralsettings_is_sync_after_timestamp_enabled.py, apps/workspaces/models.py
Removed WorkspaceGeneralSettings.is_sync_after_timestamp_enabled field and added migration to drop the column.
Serializer Update
apps/workspaces/serializers.py
Removed is_sync_after_timestamp_enabled from WorkSpaceGeneralSettingsSerializer.Meta.exclude (field no longer excluded).
Test DB Fixtures
tests/sql_fixtures/reset_db_fixtures/reset_db.sql
Updated dump to remove is_sync_after_timestamp_enabled, adjusted COPY data/columns, added migration entry, introduced last_export_details seed block, and bumped migration sequence.
Tax Groups Tests
tests/test_fyle_integrations_imports/test_modules/test_tax_groups.py
Added mocks for qbosdk.apis.TaxCodes.get_inactive and apps.quickbooks_online.utils.get_entity_sync_timestamp; relaxed some count assertions to allow minimum thresholds.
QBO Utils Tests Expansion
tests/test_quickbooks_online/test_utils.py, tests/test_quickbooks_online/fixtures.py, tests/test_quickbooks_online/test_tasks.py
Reworked tests to cover Items, Accounts, Employees, Vendors, Departments, Classes, Customers, Tax Codes with unified three-case sync-after scenarios; added vendor create test; updated vendor fixtures (create_vendor_response and vendor_response) and adjusted a mocked return in test_tasks.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor Scheduler as Sync Trigger
  participant Utils as QBO Utils
  participant Store as SyncTimestamp Store
  participant QBO as QBOSDK API
  participant Dest as DestinationAttribute
  participant TS as QBOSyncTimestamp

  Scheduler->>Utils: sync(entity_type, workspace_id)
  Utils->>Store: get_entity_sync_timestamp(workspace_id, entity_type)
  Store-->>Utils: sync_after (str or None)

  Utils->>QBO: get_all_generator(sync_after)
  QBO-->>Utils: current records (iter)

  Utils->>QBO: get_inactive(sync_after)
  QBO-->>Utils: inactive records (iter)

  Utils->>Dest: bulk_create_or_update_destination_attributes(current + inactive)

  Utils->>TS: update_sync_timestamp(workspace_id, entity_type)
  TS-->>Utils: ack
  Utils-->>Scheduler: done
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

I thump my paw at ticking time,
One clock for each QuickBooks line.
No gates, no forks, a single trail—
Sync-after winds fill every sail.
We hop, we stamp, timestamps advance,
Inactive shadows join the dance.
Carrots logged. Commit, enhance. 🥕🚀


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c3471b9 and 26d4270.

📒 Files selected for processing (4)
  • tests/test_fyle_integrations_imports/test_modules/test_tax_groups.py (3 hunks)
  • tests/test_quickbooks_online/fixtures.py (2 hunks)
  • tests/test_quickbooks_online/test_tasks.py (1 hunks)
  • tests/test_quickbooks_online/test_utils.py (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/test_fyle_integrations_imports/test_modules/test_tax_groups.py
🧰 Additional context used
🧬 Code Graph Analysis (1)
tests/test_quickbooks_online/test_utils.py (2)
apps/workspaces/models.py (2)
  • QBOCredential (144-165)
  • get_active_qbo_credentials (164-165)
apps/quickbooks_online/utils.py (10)
  • QBOConnector (108-1696)
  • sync_items (253-298)
  • sync_accounts (300-429)
  • sync_employees (617-644)
  • sync_vendors (532-580)
  • sync_departments (431-476)
  • sync_classes (646-708)
  • sync_customers (710-754)
  • sync_tax_codes (478-530)
  • get_or_create_vendor (184-209)
🔇 Additional comments (11)
tests/test_quickbooks_online/fixtures.py (1)

954-999: LGTM! The vendor fixture restructuring clearly distinguishes between creation and existing vendor payloads.

The change to introduce create_vendor_response and vendor_response as separate fixtures improves test clarity by explicitly differentiating between vendor creation scenarios and existing vendor scenarios.

tests/test_quickbooks_online/test_tasks.py (1)

87-87: LGTM! The mock updated correctly to use the create_vendor_response fixture.

The change aligns with the fixture restructuring in fixtures.py, correctly simulating the created-vendor scenario when searching for a vendor by display name.

tests/test_quickbooks_online/test_utils.py (9)

30-76: LGTM! The sync_items test properly covers all sync_after scenarios.

The test comprehensively verifies:

  • Initial sync (None sync_after)
  • Incremental sync with timestamp
  • Inactive items sync

The assertions correctly validate the expected counts and API calls with appropriate sync_after values.


77-118: LGTM! The sync_accounts test is well-structured for multi-phase sync validation.

The test properly covers all sync_after scenarios with appropriate assertions for both active and inactive account synchronization.


120-166: LGTM! The sync_employees test correctly handles incremental employee counts.

The test properly tracks initial employee counts and validates the incremental additions, ensuring accurate assertions for all sync scenarios.


168-213: LGTM! The sync_vendors test properly validates vendor synchronization.

The test correctly implements the three-case sync_after model with appropriate count tracking and assertions.


215-262: LGTM! The sync_departments test comprehensively validates department synchronization.

The test properly covers all sync scenarios including inactive departments with appropriate assertions.


264-309: LGTM! The sync_classes test properly validates class synchronization.

The test correctly implements all sync scenarios with appropriate assertions for both active and inactive classes.


311-356: LGTM! The sync_customers test correctly uses the customer fixture.

The test properly uses customer_response_after_sync fixture instead of the incorrect class_response, fixing the issue identified in the past review comments.


358-407: LGTM! The sync_tax_codes test comprehensively validates tax code synchronization.

The test properly covers all sync scenarios including inactive tax codes with appropriate tax rate mocking and assertions.


409-420: LGTM! The test_post_vendor function correctly validates vendor creation.

The test properly mocks the vendor search and post operations, correctly asserting that the returned vendor matches the expected response.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch chore-remove-is_sync_after_timestamp_enabled

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ 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.
    • 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.
  • 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 the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

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

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • 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/XL Extra Large PR label Aug 13, 2025
@github-actions
Copy link

Coverage

Coverage Report
FileStmtsMissCoverMissing
apps
   exceptions.py481177%23, 29–30, 36–37, 40–41, 44–45, 48, 51
apps/fyle
   actions.py163696%332, 380–384
   constants.py10100% 
   helpers.py185796%59, 157–159, 163, 166, 280, 314
   models.py3291396%256–258, 262–264, 467–488, 521, 535, 601
   queue.py280100% 
   serializers.py380100% 
   signals.py31390%30–32
   tasks.py2353884%53–54, 102–112, 124–129, 165, 178, 181, 214–215, 305, 315–324, 332–338, 342, 439–440
   views.py830100% 
apps/internal
   actions.py180100% 
   views.py360100% 
apps/mappings
   actions.py120100% 
   constants.py20100% 
   exceptions.py901583%23, 29–31, 34, 37–38, 41–42, 49–53, 56
   helpers.py11464%11–15
   models.py260100% 
   queues.py55395%37, 76, 88
   schedules.py160100% 
   signals.py79495%131–137
   tasks.py157597%32, 88–89, 216–218
   views.py100100% 
apps/quickbooks_online
   actions.py68691%44–45, 79–82
   exceptions.py1141389%85–90, 133, 154–161
   helpers.py20385%25, 33, 37
   models.py5441398%20, 22, 26, 126, 159, 179, 514, 528, 532, 669, 855–856, 865
   queue.py169199%59
   serializers.py620100% 
   tasks.py58610882%135, 157–158, 196–197, 202–206, 241, 245–246, 289, 390–394, 434–435, 454–455, 460–464, 509–510, 529–530, 535–539, 583–584, 603–604, 609–613, 622, 655–656, 665, 677, 680, 687–711, 751–755, 796–804, 839–865, 875–883, 894–895
   utils.py7524195%57, 81–96, 149, 203, 249, 259–260, 367, 538–539, 565–570, 812, 906, 911, 963–968, 1169, 1245, 1332, 1337, 1403, 1411, 1486–1490, 1543, 1638
   views.py770100% 
apps/quickbooks_online/errors
   helpers.py29197%67
apps/tasks
   models.py650100% 
   serializers.py60100% 
   views.py110100% 
apps/users
   actions.py6350%6–8
   helpers.py120100% 
   models.py140100% 
   views.py90100% 
apps/workspaces
   actions.py2082588%117–119, 126, 267–276, 299, 318–329, 345, 364–375, 388
   helpers.py190100% 
   models.py1210100% 
   permissions.py59788%31–36, 67
   queue.py80100% 
   serializers.py260100% 
   signals.py320100% 
   tasks.py1431590%64–68, 89, 139, 183, 208, 215–218, 245, 249
   utils.py420100% 
   views.py137894%75–78, 109–110, 175–177
apps/workspaces/apis/advanced_configurations
   serializers.py64395%113, 116, 119
   triggers.py160100% 
   views.py110100% 
apps/workspaces/apis/clone_settings
   helpers.py90100% 
   serializers.py53198%89
   views.py220100% 
apps/workspaces/apis/errors
   serializers.py200100% 
   views.py190100% 
apps/workspaces/apis/export_settings
   serializers.py106397%132, 187, 190
   triggers.py280100% 
   views.py110100% 
apps/workspaces/apis/import_settings
   serializers.py98595%95–96, 152, 155, 159
   triggers.py95199%81
   views.py190100% 
apps/workspaces/apis/map_employees
   serializers.py31197%49
   triggers.py60100% 
   views.py110100% 
fyle_integrations_imports
   dataclasses.py310100% 
   models.py230100% 
   queues.py26485%21, 51, 86, 118
   tasks.py891385%70–71, 75, 90, 96–98, 111, 136, 163–164, 210–211
fyle_integrations_imports/modules
   base.py163796%72–73, 159, 175–176, 183, 326
   categories.py147895%78, 99–100, 267–268, 286, 288, 332
   cost_centers.py87990%119–120, 131–132, 150–151, 171, 173, 219
   expense_custom_fields.py1172777%83–88, 243–288
   merchants.py961189%102–108, 177–178, 194, 196
   projects.py79989%85–86, 107–108, 136, 138, 185, 192–193
   tax_groups.py180100% 
workers/export
   actions.py11191%19
   worker.py46589%29–30, 55–56, 83
TOTAL654446193% 

Tests Skipped Failures Errors Time
313 0 💤 0 ❌ 0 🔥 1m 2s ⏱️

@github-actions
Copy link


Diff Coverage
Diff: origin/master..HEAD, staged and unstaged changes

apps/quickbooks_online/utils.py (100%)
apps/workspaces/serializers.py (100%)

Total: 52 lines
Missing: 0 lines
Coverage: 100%

Copy link

@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 comments (1)
apps/quickbooks_online/utils.py (1)

62-71: Return type annotation mismatch detected.

The function is annotated to return str but can actually return None when getattr(qbo_sync_timestamp, f'{entity_type}_synced_at') is None.

-def get_entity_sync_timestamp(workspace_id: int, entity_type: str) -> str:
+def get_entity_sync_timestamp(workspace_id: int, entity_type: str) -> Optional[str]:

Also add the import:

-from typing import Dict, List, Optional
+from typing import Dict, List, Optional
♻️ Duplicate comments (1)
tests/test_fyle_integrations_imports/test_modules/test_tax_groups.py (1)

172-179: Code duplication in subsequent test case.

The same mock patches are repeated again. This reinforces the need for a shared fixture.

🧹 Nitpick comments (3)
tests/sql_fixtures/reset_db_fixtures/reset_db.sql (1)

5-5: Avoid committing environment-specific dump headers to reduce diff churn

The pgdg build metadata in the header tends to change across machines/containers and creates noisy diffs with no functional impact. Consider normalizing or stripping pg_dump header lines in fixtures generation.

tests/test_fyle_integrations_imports/test_modules/test_tax_groups.py (1)

123-130: Duplicate mock patches should be optimized.

The same patches are repeated across multiple test cases. Consider extracting these common mocks into a test fixture to reduce code duplication and improve maintainability.

+@pytest.fixture
+def mock_tax_code_sync(mocker):
+    """Common mocks for tax code sync operations."""
+    mocker.patch('qbosdk.apis.TaxCodes.get_inactive', return_value=[])
+    mocker.patch('apps.quickbooks_online.utils.get_entity_sync_timestamp', return_value=None)
+
 def test_auto_create_destination_attributes(mocker, db):
     # ... existing code ...
-    mocker.patch(
-        'qbosdk.apis.TaxCodes.get_inactive',
-        return_value=[]
-    )
-    mocker.patch(
-        'apps.quickbooks_online.utils.get_entity_sync_timestamp',
-        return_value=None
-    )
tests/test_quickbooks_online/test_utils.py (1)

76-117: Consider extracting common test patterns.

The sync tests for accounts, employees, and vendors follow an identical pattern. Consider creating a parameterized test or helper function to reduce duplication.

@pytest.mark.parametrize("entity_config", [
    {
        'entity_type': 'account',
        'api_module': 'Accounts',
        'attribute_type': 'ACCOUNT',
        'workspace_id': 1,
        'min_count': 60,
    },
    {
        'entity_type': 'employee',
        'api_module': 'Employees',
        'attribute_type': 'EMPLOYEE',
        'workspace_id': 3,
        'min_count': 2,
    },
    # ... other entities
])
def test_sync_entity_with_sync_after(mocker, db, entity_config):
    """Test sync functionality with sync_after for various entities."""
    # Common test logic here

Also applies to: 119-161, 163-204

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d1df399 and c3471b9.

📒 Files selected for processing (7)
  • apps/quickbooks_online/utils.py (21 hunks)
  • apps/workspaces/migrations/0056_remove_workspacegeneralsettings_is_sync_after_timestamp_enabled.py (1 hunks)
  • apps/workspaces/models.py (0 hunks)
  • apps/workspaces/serializers.py (1 hunks)
  • tests/sql_fixtures/reset_db_fixtures/reset_db.sql (6 hunks)
  • tests/test_fyle_integrations_imports/test_modules/test_tax_groups.py (4 hunks)
  • tests/test_quickbooks_online/test_utils.py (1 hunks)
💤 Files with no reviewable changes (1)
  • apps/workspaces/models.py
🧰 Additional context used
🧬 Code Graph Analysis (2)
tests/test_quickbooks_online/test_utils.py (3)
apps/workspaces/models.py (2)
  • QBOCredential (144-165)
  • get_active_qbo_credentials (164-165)
apps/quickbooks_online/utils.py (10)
  • QBOConnector (108-1696)
  • sync_items (253-298)
  • sync_accounts (300-429)
  • sync_employees (617-644)
  • sync_vendors (532-580)
  • sync_departments (431-476)
  • sync_classes (646-708)
  • sync_customers (710-754)
  • sync_tax_codes (478-530)
  • get_or_create_vendor (184-209)
apps/quickbooks_online/models.py (1)
  • QBOSyncTimestamp (1052-1086)
apps/quickbooks_online/utils.py (2)
apps/quickbooks_online/models.py (2)
  • QBOSyncTimestamp (1052-1086)
  • update_sync_timestamp (1077-1086)
apps/workspaces/helpers.py (1)
  • get_app_name (26-31)
🪛 Pylint (3.3.7)
apps/workspaces/migrations/0056_remove_workspacegeneralsettings_is_sync_after_timestamp_enabled.py

[error] 1-1: Unrecognized option found: no-space-check

(E0015)


[refactor] 1-1: Useless option value for '--disable', 'print-statement' was removed from pylint, see pylint-dev/pylint#4942.

(R0022)


[refactor] 1-1: Useless option value for '--disable', 'parameter-unpacking' was removed from pylint, see pylint-dev/pylint#4942.

(R0022)


[refactor] 1-1: Useless option value for '--disable', 'unpacking-in-except' was removed from pylint, see pylint-dev/pylint#4942.

(R0022)


[refactor] 1-1: Useless option value for '--disable', 'old-raise-syntax' was removed from pylint, see pylint-dev/pylint#4942.

(R0022)


[refactor] 1-1: Useless option value for '--disable', 'backtick' was removed from pylint, see pylint-dev/pylint#4942.

(R0022)


[refactor] 1-1: Useless option value for '--disable', 'import-star-module-level' was removed from pylint, see pylint-dev/pylint#4942.

(R0022)


[refactor] 1-1: Useless option value for '--disable', 'apply-builtin' was removed from pylint, see pylint-dev/pylint#4942.

(R0022)


[refactor] 1-1: Useless option value for '--disable', 'basestring-builtin' was removed from pylint, see pylint-dev/pylint#4942.

(R0022)


[refactor] 1-1: Useless option value for '--disable', 'buffer-builtin' was removed from pylint, see pylint-dev/pylint#4942.

(R0022)


[refactor] 1-1: Useless option value for '--disable', 'cmp-builtin' was removed from pylint, see pylint-dev/pylint#4942.

(R0022)


[refactor] 1-1: Useless option value for '--disable', 'coerce-builtin' was removed from pylint, see pylint-dev/pylint#4942.

(R0022)


[refactor] 1-1: Useless option value for '--disable', 'execfile-builtin' was removed from pylint, see pylint-dev/pylint#4942.

(R0022)


[refactor] 1-1: Useless option value for '--disable', 'file-builtin' was removed from pylint, see pylint-dev/pylint#4942.

(R0022)


[refactor] 1-1: Useless option value for '--disable', 'long-builtin' was removed from pylint, see pylint-dev/pylint#4942.

(R0022)


[refactor] 1-1: Useless option value for '--disable', 'raw_input-builtin' was removed from pylint, see pylint-dev/pylint#4942.

(R0022)


[refactor] 1-1: Useless option value for '--disable', 'reduce-builtin' was removed from pylint, see pylint-dev/pylint#4942.

(R0022)


[refactor] 1-1: Useless option value for '--disable', 'standarderror-builtin' was removed from pylint, see pylint-dev/pylint#4942.

(R0022)


[refactor] 1-1: Useless option value for '--disable', 'unicode-builtin' was removed from pylint, see pylint-dev/pylint#4942.

(R0022)


[refactor] 1-1: Useless option value for '--disable', 'xrange-builtin' was removed from pylint, see pylint-dev/pylint#4942.

(R0022)


[refactor] 1-1: Useless option value for '--disable', 'coerce-method' was removed from pylint, see pylint-dev/pylint#4942.

(R0022)


[refactor] 1-1: Useless option value for '--disable', 'delslice-method' was removed from pylint, see pylint-dev/pylint#4942.

(R0022)


[refactor] 1-1: Useless option value for '--disable', 'getslice-method' was removed from pylint, see pylint-dev/pylint#4942.

(R0022)


[refactor] 1-1: Useless option value for '--disable', 'setslice-method' was removed from pylint, see pylint-dev/pylint#4942.

(R0022)


[refactor] 1-1: Useless option value for '--disable', 'no-absolute-import' was removed from pylint, see pylint-dev/pylint#4942.

(R0022)


[refactor] 1-1: Useless option value for '--disable', 'old-division' was removed from pylint, see pylint-dev/pylint#4942.

(R0022)


[refactor] 1-1: Useless option value for '--disable', 'dict-iter-method' was removed from pylint, see pylint-dev/pylint#4942.

(R0022)


[refactor] 1-1: Useless option value for '--disable', 'dict-view-method' was removed from pylint, see pylint-dev/pylint#4942.

(R0022)


[refactor] 1-1: Useless option value for '--disable', 'next-method-called' was removed from pylint, see pylint-dev/pylint#4942.

(R0022)


[refactor] 1-1: Useless option value for '--disable', 'metaclass-assignment' was removed from pylint, see pylint-dev/pylint#4942.

(R0022)


[refactor] 1-1: Useless option value for '--disable', 'indexing-exception' was removed from pylint, see pylint-dev/pylint#4942.

(R0022)


[refactor] 1-1: Useless option value for '--disable', 'raising-string' was removed from pylint, see pylint-dev/pylint#4942.

(R0022)


[refactor] 1-1: Useless option value for '--disable', 'reload-builtin' was removed from pylint, see pylint-dev/pylint#4942.

(R0022)


[refactor] 1-1: Useless option value for '--disable', 'oct-method' was removed from pylint, see pylint-dev/pylint#4942.

(R0022)


[refactor] 1-1: Useless option value for '--disable', 'hex-method' was removed from pylint, see pylint-dev/pylint#4942.

(R0022)


[refactor] 1-1: Useless option value for '--disable', 'nonzero-method' was removed from pylint, see pylint-dev/pylint#4942.

(R0022)


[refactor] 1-1: Useless option value for '--disable', 'cmp-method' was removed from pylint, see pylint-dev/pylint#4942.

(R0022)


[refactor] 1-1: Useless option value for '--disable', 'input-builtin' was removed from pylint, see pylint-dev/pylint#4942.

(R0022)


[refactor] 1-1: Useless option value for '--disable', 'round-builtin' was removed from pylint, see pylint-dev/pylint#4942.

(R0022)


[refactor] 1-1: Useless option value for '--disable', 'intern-builtin' was removed from pylint, see pylint-dev/pylint#4942.

(R0022)


[refactor] 1-1: Useless option value for '--disable', 'unichr-builtin' was removed from pylint, see pylint-dev/pylint#4942.

(R0022)


[refactor] 1-1: Useless option value for '--disable', 'map-builtin-not-iterating' was removed from pylint, see pylint-dev/pylint#4942.

(R0022)


[refactor] 1-1: Useless option value for '--disable', 'zip-builtin-not-iterating' was removed from pylint, see pylint-dev/pylint#4942.

(R0022)


[refactor] 1-1: Useless option value for '--disable', 'range-builtin-not-iterating' was removed from pylint, see pylint-dev/pylint#4942.

(R0022)


[refactor] 1-1: Useless option value for '--disable', 'filter-builtin-not-iterating' was removed from pylint, see pylint-dev/pylint#4942.

(R0022)


[refactor] 1-1: Useless option value for '--disable', 'using-cmp-argument' was removed from pylint, see pylint-dev/pylint#4942.

(R0022)


[refactor] 1-1: Useless option value for '--disable', 'div-method' was removed from pylint, see pylint-dev/pylint#4942.

(R0022)


[refactor] 1-1: Useless option value for '--disable', 'idiv-method' was removed from pylint, see pylint-dev/pylint#4942.

(R0022)


[refactor] 1-1: Useless option value for '--disable', 'rdiv-method' was removed from pylint, see pylint-dev/pylint#4942.

(R0022)


[refactor] 1-1: Useless option value for '--disable', 'exception-message-attribute' was removed from pylint, see pylint-dev/pylint#4942.

(R0022)


[refactor] 1-1: Useless option value for '--disable', 'invalid-str-codec' was removed from pylint, see pylint-dev/pylint#4942.

(R0022)


[refactor] 1-1: Useless option value for '--disable', 'sys-max-int' was removed from pylint, see pylint-dev/pylint#4942.

(R0022)


[refactor] 1-1: Useless option value for '--disable', 'bad-python3-import' was removed from pylint, see pylint-dev/pylint#4942.

(R0022)


[refactor] 1-1: Useless option value for '--disable', 'deprecated-string-function' was removed from pylint, see pylint-dev/pylint#4942.

(R0022)


[refactor] 1-1: Useless option value for '--disable', 'deprecated-str-translate-call' was removed from pylint, see pylint-dev/pylint#4942.

(R0022)


[refactor] 1-1: Useless option value for '--disable', 'deprecated-itertools-function' was removed from pylint, see pylint-dev/pylint#4942.

(R0022)


[refactor] 1-1: Useless option value for '--disable', 'deprecated-types-field' was removed from pylint, see pylint-dev/pylint#4942.

(R0022)


[refactor] 1-1: Useless option value for '--disable', 'next-method-defined' was removed from pylint, see pylint-dev/pylint#4942.

(R0022)


[refactor] 1-1: Useless option value for '--disable', 'dict-items-not-iterating' was removed from pylint, see pylint-dev/pylint#4942.

(R0022)


[refactor] 1-1: Useless option value for '--disable', 'dict-keys-not-iterating' was removed from pylint, see pylint-dev/pylint#4942.

(R0022)


[refactor] 1-1: Useless option value for '--disable', 'dict-values-not-iterating' was removed from pylint, see pylint-dev/pylint#4942.

(R0022)


[refactor] 1-1: Useless option value for '--disable', 'deprecated-operator-function' was removed from pylint, see pylint-dev/pylint#4942.

(R0022)


[refactor] 1-1: Useless option value for '--disable', 'deprecated-urllib-function' was removed from pylint, see pylint-dev/pylint#4942.

(R0022)


[refactor] 1-1: Useless option value for '--disable', 'xreadlines-attribute' was removed from pylint, see pylint-dev/pylint#4942.

(R0022)


[refactor] 1-1: Useless option value for '--disable', 'deprecated-sys-function' was removed from pylint, see pylint-dev/pylint#4942.

(R0022)


[refactor] 1-1: Useless option value for '--disable', 'exception-escape' was removed from pylint, see pylint-dev/pylint#4942.

(R0022)


[refactor] 1-1: Useless option value for '--disable', 'comprehension-escape' was removed from pylint, see pylint-dev/pylint#4942.

(R0022)


[refactor] 1-1: Useless option value for '--disable', 'no-self-use' was moved to an optional extension, see https://pylint.readthedocs.io/en/latest/whatsnew/2/2.14/summary.html#removed-checkers.

(R0022)

🔇 Additional comments (16)
apps/workspaces/serializers.py (1)

41-43: No lingering references to is_sync_after_timestamp_enabled found — safe to approve

Verified via a recursive search (rg -n -S) that the field isn’t referenced anywhere outside of migrations or SQL fixtures. Removing it from the serializer’s exclude list now correctly aligns with the model migration.

apps/workspaces/migrations/0056_remove_workspacegeneralsettings_is_sync_after_timestamp_enabled.py (1)

12-17: Migration is minimal and correct for column removal

The RemoveField operation and dependency on 0055 look correct for dropping the column. No additional state ops needed given a simple boolean removal.

tests/sql_fixtures/reset_db_fixtures/reset_db.sql (5)

1019-1020: WorkspaceGeneralSettings schema update looks correct

Column is_sync_after_timestamp_enabled is removed and the table now ends with skip_accounting_export_summary_post boolean NOT NULL. No dangling comma or type mismatch in this snippet.


5738-5739: Migration entry added for column removal — LGTM

0056_remove_workspacegeneralsettings_is_sync_after_timestamp_enabled is recorded with id 238, consistent with the PR intent. Ensure the migration file exists and runs before tests that load this fixture.


35707-35708: Seq setval for django_migrations updated — ensure it matches max id

Set to 238, which aligns with the added migration entry. If you run the verification script above, it confirms the setval equals the max id to prevent fixture load issues.


35173-35185: last_export_details sequence setval confirmed

Verified that tests/sql_fixtures/reset_db_fixtures/reset_db.sql contains
SELECT pg_catalog.setval('public.last_export_details_id_seq', 5, true); at line 35840, so test inserts won’t collide. No further changes required.


35600-35606: Fixtures validated: COPY blocks align and omitted column confirmed

Both public.workspace_general_settings and public.last_export_details COPY definitions now:

  • Match their column counts against every data row (30 and 11 fields respectively).
  • Correctly omit the is_sync_after_timestamp_enabled column.

Occurrences of the string is_sync_after_timestamp_enabled only appear in the django_migrations fixture as migration names (e.g. 0054_workspacegeneralsettings_is_sync_after_timestamp_enabled), which is expected. No further changes are required.

tests/test_fyle_integrations_imports/test_modules/test_tax_groups.py (2)

23-30: LGTM! The new mocks correctly support the per-entity sync timestamp mechanism.

The addition of mocks for get_inactive and get_entity_sync_timestamp aligns with the PR's objective to standardize entity syncing using per-entity timestamps. The mock returns are appropriate for initial sync scenarios.


152-152: Test assertion change requires clarification.

The change from exact equality (== 4) to minimum bound (>= 3) reduces test precision. This could mask potential issues if the actual count unexpectedly decreases.

Could you explain why the exact count assertion was relaxed? If this is due to test environment variability, consider using a more deterministic test setup instead.

apps/quickbooks_online/utils.py (5)

262-262: Consistent pattern implementation for entity syncing.

The implementation correctly follows a consistent pattern across all sync methods: get timestamp, fetch active records, fetch inactive records, then update timestamp. This aligns well with the PR's objective to standardize syncing behavior.

Also applies to: 281-281, 296-296


455-473: Good addition of inactive department handling.

The new code properly handles inactive departments by stripping the "(deleted)" suffix and setting active=False. This ensures consistency with other entity types' inactive handling.


510-527: Proper implementation of inactive tax code syncing.

The inactive tax codes are correctly processed with tax rate calculation and proper value formatting. The implementation maintains consistency with the active tax code processing logic.


632-641: Consistent inactive entity handling across all resource types.

The inactive employee processing follows the established pattern, properly handling display name cleanup and bulk attribute updates.


682-706: Complete implementation of inactive classes syncing.

The inactive classes are properly handled with appropriate display name cleanup and bulk creation/update operations. The pattern is consistent with other entity types.

tests/test_quickbooks_online/test_utils.py (2)

30-74: Comprehensive test coverage for items sync with three distinct cases.

The test properly validates all three sync scenarios (initial, with timestamp, and inactive) and correctly asserts the expected mock calls and database state. The implementation aligns with the new per-entity sync timestamp approach.


385-396: New vendor creation test validates the sync changes.

The test properly validates vendor creation flow and the returned vendor ID, which is important for the overall sync functionality.

@ruuushhh ruuushhh self-assigned this Aug 13, 2025
@ruuushhh ruuushhh requested a review from Hrishabh17 August 13, 2025 12:01
@github-actions
Copy link

Coverage

Coverage Report
FileStmtsMissCoverMissing
apps
   exceptions.py481177%23, 29–30, 36–37, 40–41, 44–45, 48, 51
apps/fyle
   actions.py163696%332, 380–384
   constants.py10100% 
   helpers.py185796%59, 157–159, 163, 166, 280, 314
   models.py3291396%256–258, 262–264, 467–488, 521, 535, 601
   queue.py280100% 
   serializers.py380100% 
   signals.py31390%30–32
   tasks.py2353884%53–54, 102–112, 124–129, 165, 178, 181, 214–215, 305, 315–324, 332–338, 342, 439–440
   views.py830100% 
apps/internal
   actions.py180100% 
   views.py360100% 
apps/mappings
   actions.py120100% 
   constants.py20100% 
   exceptions.py901583%23, 29–31, 34, 37–38, 41–42, 49–53, 56
   helpers.py11464%11–15
   models.py260100% 
   queues.py55395%37, 76, 88
   schedules.py160100% 
   signals.py79495%131–137
   tasks.py157597%32, 88–89, 216–218
   views.py100100% 
apps/quickbooks_online
   actions.py68691%44–45, 79–82
   exceptions.py1141389%85–90, 133, 154–161
   helpers.py20385%25, 33, 37
   models.py5441398%20, 22, 26, 126, 159, 179, 514, 528, 532, 669, 855–856, 865
   queue.py169199%59
   serializers.py620100% 
   tasks.py58610882%135, 157–158, 196–197, 202–206, 241, 245–246, 289, 390–394, 434–435, 454–455, 460–464, 509–510, 529–530, 535–539, 583–584, 603–604, 609–613, 622, 655–656, 665, 677, 680, 687–711, 751–755, 796–804, 839–865, 875–883, 894–895
   utils.py7524195%57, 81–96, 149, 203, 249, 259–260, 367, 538–539, 565–570, 812, 906, 911, 963–968, 1169, 1245, 1332, 1337, 1403, 1411, 1486–1490, 1543, 1638
   views.py770100% 
apps/quickbooks_online/errors
   helpers.py29197%67
apps/tasks
   models.py650100% 
   serializers.py60100% 
   views.py110100% 
apps/users
   actions.py6350%6–8
   helpers.py120100% 
   models.py140100% 
   views.py90100% 
apps/workspaces
   actions.py2082588%117–119, 126, 267–276, 299, 318–329, 345, 364–375, 388
   helpers.py190100% 
   models.py1210100% 
   permissions.py59788%31–36, 67
   queue.py80100% 
   serializers.py260100% 
   signals.py320100% 
   tasks.py1431590%64–68, 89, 139, 183, 208, 215–218, 245, 249
   utils.py420100% 
   views.py137894%75–78, 109–110, 175–177
apps/workspaces/apis/advanced_configurations
   serializers.py64395%113, 116, 119
   triggers.py160100% 
   views.py110100% 
apps/workspaces/apis/clone_settings
   helpers.py90100% 
   serializers.py53198%89
   views.py220100% 
apps/workspaces/apis/errors
   serializers.py200100% 
   views.py190100% 
apps/workspaces/apis/export_settings
   serializers.py106397%132, 187, 190
   triggers.py280100% 
   views.py110100% 
apps/workspaces/apis/import_settings
   serializers.py98595%95–96, 152, 155, 159
   triggers.py95199%81
   views.py190100% 
apps/workspaces/apis/map_employees
   serializers.py31197%49
   triggers.py60100% 
   views.py110100% 
fyle_integrations_imports
   dataclasses.py310100% 
   models.py230100% 
   queues.py26485%21, 51, 86, 118
   tasks.py891385%70–71, 75, 90, 96–98, 111, 136, 163–164, 210–211
fyle_integrations_imports/modules
   base.py163796%72–73, 159, 175–176, 183, 326
   categories.py147895%78, 99–100, 267–268, 286, 288, 332
   cost_centers.py87990%119–120, 131–132, 150–151, 171, 173, 219
   expense_custom_fields.py1172777%83–88, 243–288
   merchants.py961189%102–108, 177–178, 194, 196
   projects.py79989%85–86, 107–108, 136, 138, 185, 192–193
   tax_groups.py180100% 
workers/export
   actions.py11191%19
   worker.py46589%29–30, 55–56, 83
TOTAL654446193% 

Tests Skipped Failures Errors Time
313 0 💤 0 ❌ 0 🔥 44.871s ⏱️

@github-actions
Copy link


Diff Coverage
Diff: origin/master..HEAD, staged and unstaged changes

apps/quickbooks_online/utils.py (100%)
apps/workspaces/serializers.py (100%)

Total: 52 lines
Missing: 0 lines
Coverage: 100%

@github-actions
Copy link

Coverage

Coverage Report
FileStmtsMissCoverMissing
apps
   exceptions.py481177%23, 29–30, 36–37, 40–41, 44–45, 48, 51
apps/fyle
   actions.py163696%332, 380–384
   constants.py10100% 
   helpers.py185796%59, 157–159, 163, 166, 280, 314
   models.py3291396%256–258, 262–264, 467–488, 521, 535, 601
   queue.py280100% 
   serializers.py380100% 
   signals.py31390%30–32
   tasks.py2353884%53–54, 102–112, 124–129, 165, 178, 181, 214–215, 305, 315–324, 332–338, 342, 439–440
   views.py830100% 
apps/internal
   actions.py180100% 
   views.py360100% 
apps/mappings
   actions.py120100% 
   constants.py20100% 
   exceptions.py901583%23, 29–31, 34, 37–38, 41–42, 49–53, 56
   helpers.py11464%11–15
   models.py260100% 
   queues.py55395%37, 76, 88
   schedules.py160100% 
   signals.py79495%131–137
   tasks.py157597%32, 88–89, 216–218
   views.py100100% 
apps/quickbooks_online
   actions.py68691%44–45, 79–82
   exceptions.py1141389%85–90, 133, 154–161
   helpers.py20385%25, 33, 37
   models.py5441398%20, 22, 26, 126, 159, 179, 514, 528, 532, 669, 855–856, 865
   queue.py169199%59
   serializers.py620100% 
   tasks.py58610882%135, 157–158, 196–197, 202–206, 241, 245–246, 289, 390–394, 434–435, 454–455, 460–464, 509–510, 529–530, 535–539, 583–584, 603–604, 609–613, 622, 655–656, 665, 677, 680, 687–711, 751–755, 796–804, 839–865, 875–883, 894–895
   utils.py7524195%57, 81–96, 149, 203, 249, 259–260, 367, 538–539, 565–570, 812, 906, 911, 963–968, 1169, 1245, 1332, 1337, 1403, 1411, 1486–1490, 1543, 1638
   views.py770100% 
apps/quickbooks_online/errors
   helpers.py29197%67
apps/tasks
   models.py650100% 
   serializers.py60100% 
   views.py110100% 
apps/users
   actions.py6350%6–8
   helpers.py120100% 
   models.py140100% 
   views.py90100% 
apps/workspaces
   actions.py2082588%117–119, 126, 267–276, 299, 318–329, 345, 364–375, 388
   helpers.py190100% 
   models.py1210100% 
   permissions.py59788%31–36, 67
   queue.py80100% 
   serializers.py260100% 
   signals.py320100% 
   tasks.py1431590%64–68, 89, 139, 183, 208, 215–218, 245, 249
   utils.py420100% 
   views.py137894%75–78, 109–110, 175–177
apps/workspaces/apis/advanced_configurations
   serializers.py64395%113, 116, 119
   triggers.py160100% 
   views.py110100% 
apps/workspaces/apis/clone_settings
   helpers.py90100% 
   serializers.py53198%89
   views.py220100% 
apps/workspaces/apis/errors
   serializers.py200100% 
   views.py190100% 
apps/workspaces/apis/export_settings
   serializers.py106397%132, 187, 190
   triggers.py280100% 
   views.py110100% 
apps/workspaces/apis/import_settings
   serializers.py98595%95–96, 152, 155, 159
   triggers.py95199%81
   views.py190100% 
apps/workspaces/apis/map_employees
   serializers.py31197%49
   triggers.py60100% 
   views.py110100% 
fyle_integrations_imports
   dataclasses.py310100% 
   models.py230100% 
   queues.py26485%21, 51, 86, 118
   tasks.py891385%70–71, 75, 90, 96–98, 111, 136, 163–164, 210–211
fyle_integrations_imports/modules
   base.py163796%72–73, 159, 175–176, 183, 326
   categories.py147895%78, 99–100, 267–268, 286, 288, 332
   cost_centers.py87990%119–120, 131–132, 150–151, 171, 173, 219
   expense_custom_fields.py1172777%83–88, 243–288
   merchants.py961189%102–108, 177–178, 194, 196
   projects.py79989%85–86, 107–108, 136, 138, 185, 192–193
   tax_groups.py180100% 
workers/export
   actions.py11191%19
   worker.py46589%29–30, 55–56, 83
TOTAL654446193% 

Tests Skipped Failures Errors Time
313 0 💤 0 ❌ 0 🔥 1m 1s ⏱️

@github-actions
Copy link


Diff Coverage
Diff: origin/master..HEAD, staged and unstaged changes

apps/quickbooks_online/utils.py (100%)
apps/workspaces/serializers.py (100%)

Total: 52 lines
Missing: 0 lines
Coverage: 100%

@ruuushhh ruuushhh requested a review from ashwin1111 August 13, 2025 12:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/XL Extra Large PR

Development

Successfully merging this pull request may close these issues.

3 participants