Skip to content

feat: system comments for p1, p2 areas#900

Merged
Hrishabh17 merged 11 commits intomasterfrom
system-generate-comments-3
Jan 29, 2026
Merged

feat: system comments for p1, p2 areas#900
Hrishabh17 merged 11 commits intomasterfrom
system-generate-comments-3

Conversation

@Hrishabh17
Copy link
Member

@Hrishabh17 Hrishabh17 commented Jan 27, 2026

Summary by CodeRabbit

  • New Features

    • System comments now cover retriggered stuck exports, export-summary-not-updated, payment-skip reasons, missing-dimension billable warnings, and REST API connection failures; added new comment intents/sources/reasons and an option to persist comments even when not exported.
  • Bug Fixes

    • Centralized, thread-safe collection and bulk persistence of system comments across export flows and error paths.
  • Tests

    • Large expansion of tests validating system comment generation across export scenarios and failures.
  • Chores

    • Added a DB migration and updated a repository submodule.

✏️ Tip: You can customize this high-level summary in your review settings.

@github-actions github-actions bot added the size/XL Extra Large PR label Jan 27, 2026
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 27, 2026

Walkthrough

Centralizes system-comment accumulation across Sage Intacct export flows, emits comments for missing billable dimensions and export/connection failures, adds enums/models/utilities for system comments, updates tests/fixtures, and adds a migration to run raw SQL.

Changes

Cohort / File(s) Summary
System Comment enums
apps/workspaces/enums.py
Added new enum members to SystemCommentSourceEnum, SystemCommentIntentEnum, and SystemCommentReasonEnum for new sources/intents/reasons (lineitem creation, retrigger, connection failures, payment-skip reasons).
System Comment model & helpers
apps/internal/tasks.py, apps/workspaces/system_comments.py, fyle_accounting_library/system_comments/...
Introduced SystemComment model and add_system_comment updates (new persist_without_export flag) and added create_filtered_system_comments to filter & bulk-persist comments; internal tasks now initialize/collect system_comments.
Export pipeline (accumulation & persistence)
apps/sage_intacct/tasks.py, apps/sage_intacct/...
Replaced per-block comment batching with a centralized system_comments accumulator propagated across export flows (bill, expense_report, journal_entry, charge_card_transaction, AP payment, reimbursements, retrigger) and persisted in finally/exception blocks via bulk-create.
Billable line-item validation
apps/sage_intacct/models.py
Added checks in multiple lineitem creation paths to emit system comments when billable is true but customer_id or item_id is missing; comments include original billable and missing-field info and use persist_without_export=False.
Skip-payment & helper signature
apps/sage_intacct/tasks.py
Updated validate_for_skipping_payment(..., system_comments: list = None) signature to accept accumulator and append payment-skip system comments when applicable.
Workspace views — connection error comments
apps/workspaces/views.py
On Sage Intacct REST API errors (InvalidTokenError, BadRequestError, InternalServerError), gather descriptive system comments and bulk-create them in finally blocks.
Tests & Fixtures
tests/conftest.py, tests/test_system_comments/test_system_comments.py, tests/test_workspaces/test_views.py
Added get_or_create_task_log fixture (duplicate present) and extensive tests validating system comment creation for missing dimensions, export-error states, stuck-export retriggering, payment-skip logic, and connection-failure comments; updated imports and assertions.
Migration & DB migrations submodule
apps/internal/migrations/0029_auto_generated_sql.py, fyle-integrations-db-migrations
New migration running raw SQL (delete_workspace.sql) via safe_run_sql; submodule pointer updated to a newer commit.

Sequence Diagram(s)

sequenceDiagram
    participant ExportFlow as Export Flow
    participant Validator as Billable Validator
    participant SystemSvc as SystemComment Service
    participant Intacct as Intacct API
    participant DB as Database

    ExportFlow->>SystemSvc: init system_comments = []
    loop per expense_group / lineitem
        ExportFlow->>Validator: validate billable dimensions
        alt missing customer_id or item_id
            Validator->>SystemSvc: append comment(source, intent, reason, info, persist_without_export)
        end
        ExportFlow->>Intacct: send export payload
        alt API error or auto-export previous ERROR
            Intacct-->>ExportFlow: error/state
            ExportFlow->>SystemSvc: append error/skip/retrigger comment
        end
    end
    alt system_comments not empty
        SystemSvc->>DB: bulk_create_comments(filtered system_comments with workspace/export_type)
        DB-->>SystemSvc: persisted
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Poem

🐰 I hopped through code and gathered notes so neat,
I flagged the missing bits beneath each seat,
I grouped the whispers, batched them with a thrum,
I nudged stuck exports back to where they come,
Then hopped away with tiny rabbit feet.

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Description check ⚠️ Warning No pull request description was provided by the author, missing all required template sections including Description and Clickup link. Add a comprehensive description following the template, including what changes were made, why they were made, links to related Clickup issues, and any testing notes.
Title check ❓ Inconclusive The title 'feat: system comments for p1, p2 areas' is vague and lacks specificity about what system comments are being added and to which areas. Clarify the title to describe the specific functionality, such as 'feat: add system comments for export retrigger and error handling workflows' to better indicate what was changed.
✅ Passed checks (1 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 98.48% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

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

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link

Coverage

Coverage Report
FileStmtsMissCoverMissing
apps
   exceptions.py471177%27, 33, 39–44, 50, 56–61, 67, 73, 79–80
apps/fyle
   actions.py124794%214, 263, 319–323
   constants.py10100% 
   helpers.py2351494%50–57, 66, 376, 470, 477–480, 483–484
   models.py3382194%315–317, 321–323, 327–329, 333–335, 339–341, 345–347, 408, 530–551, 574, 591
   queue.py500100% 
   serializers.py410100% 
   signals.py35683%22, 55–56, 69–71
   tasks.py5468784%132, 143–144, 147–148, 151–152, 174–175, 231–251, 263–268, 311–314, 339–343, 353–361, 400–410, 525–585, 906–910, 1048, 1059–1060, 1085–1086
   views.py1721591%84–91, 145, 245–246, 290–291, 316–320, 413–417
apps/internal
   actions.py39295%26–27
   helpers.py361364%18–35
   serializers.py300100% 
   tasks.py906528%31–35, 55–112, 121–172
   views.py83199%39
apps/internal/services
   e2e_setup.py590100% 
   fixture_factory.py59395%218–220
apps/mappings
   constants.py20100% 
   exceptions.py71692%69–71, 79–81
   helpers.py300100% 
   models.py500100% 
   schedules.py150100% 
   serializers.py100100% 
   signals.py1111487%90–92, 127, 179–184, 190–194, 200–203, 209–210
   tasks.py1732983%117–118, 141–142, 145, 209–226, 254, 257, 260, 266, 269, 275, 314–316, 327, 399
   utils.py340100% 
   views.py46491%34–35, 114–115
apps/sage_intacct
   actions.py29486%21–22, 49–50
   connector.py8052597%133, 309, 321, 327, 403, 1414, 1713, 1840–1841, 1892–1893, 1914–1915, 1944–1945, 1953–1964, 1996–1997, 2017–2018
   dependent_fields.py2904286%345, 381–384, 413–422, 424–425, 427–429, 431–432, 434–435, 437–438, 442–444, 488, 508, 548–550, 596–598, 646–652, 656–657
   enums.py250100% 
   helpers.py56689%38–41, 58, 95
   models.py9886793%78–79, 261–271, 399, 406, 450, 471–488, 560, 572, 622, 628, 663, 713–715, 729–742, 753, 789, 841–842, 940, 981, 1209, 1304–1307, 1351, 1353, 1444, 1548–1589, 1687, 1713, 1824, 2198–2200, 2262
   queue.py1711691%45, 53, 58, 105, 130–133, 173, 187, 205–208, 243, 267–270, 305, 330–333
   serializers.py350100% 
   tasks.py158719388%105, 119, 152, 188–189, 193–196, 198, 201, 251, 286–287, 407–408, 414, 417, 460–461, 502–507, 572, 578, 586, 750, 765–766, 786–789, 865–866, 870, 889, 904, 909, 914, 921, 927, 930–932, 935–938, 941–943, 963, 1016–1017, 1103–1104, 1108, 1132, 1186, 1199–1207, 1298–1299, 1380–1381, 1383, 1387–1390, 1409, 1455–1458, 1463, 1476–1484, 1575–1576, 1669–1670, 1673, 1699, 1719, 1730, 1741, 1753, 1764, 1767–1774, 1777–1785, 1788–1795, 1819, 1878–1881, 1964, 1976–1985, 2027, 2030–2035, 2038–2042, 2211–2215, 2314–2315, 2521–2531, 2534, 2543–2548, 2582–2584, 2618–2621, 2689–2693, 2702, 2791–2796, 2809, 2824, 2839
   utils.py8903396%718–722, 867, 1186, 1202–1208, 1217–1218, 1944–1948, 1976–1980, 2008–2012, 2056–2060, 2114–2118, 2139, 2148, 2157, 2166–2167
   views.py1453377%127–129, 134–135, 141–142, 185–188, 258–288, 299–314, 327–331
apps/sage_intacct/errors
   errors.py20100% 
   helpers.py47198%80
apps/sage_intacct/exports
   ap_payments.py130100% 
   bills.py280100% 
   charge_card_transactions.py220100% 
   expense_reports.py280100% 
   helpers.py56296%68, 141
   journal_entries.py76889%177–180, 316–319
   reimbursements.py130100% 
apps/tasks
   models.py690100% 
   serializers.py60100% 
   views.py370100% 
apps/users
   helpers.py120100% 
   models.py530100% 
   views.py170100% 
apps/workspaces
   actions.py46980%65, 84–85, 103, 122–133, 147
   enums.py840100% 
   helpers.py80100% 
   models.py1760100% 
   permissions.py34974%33, 59–67
   serializers.py43198%54
   signals.py310100% 
   system_comments.py60100% 
   tasks.py175995%53–59, 187–194, 235, 267–268, 379
   utils.py90100% 
   views.py320997%107–109, 136–139, 665–666
apps/workspaces/apis/advanced_settings
   serializers.py80396%260, 263, 266
   triggers.py100100% 
   views.py110100% 
apps/workspaces/apis/errors
   serializers.py200100% 
   views.py150100% 
apps/workspaces/apis/export_settings
   helpers.py730100% 
   serializers.py103397%267, 270, 273
   triggers.py39295%32–33
   views.py110100% 
apps/workspaces/apis/import_settings
   serializers.py1411887%232–238, 243–249, 257–265, 283, 286, 314, 317–318, 326
   triggers.py47198%31
   views.py330100% 
fyle_integrations_imports
   dataclasses.py310100% 
   models.py230100% 
   queues.py34585%24, 99, 136, 148–149
   signals.py100100% 
   tasks.py1278136%69–111, 120–126, 139–208, 212–227, 252–255, 257, 259, 264
fyle_integrations_imports/modules
   base.py1881095%75, 91–92, 95, 126, 230–231, 237–238, 351
   categories.py1773381%80, 96, 99–100, 103–104, 272–273, 283, 296, 298, 342, 351–355, 364–410
   cost_centers.py961288%132–133, 152–153, 162, 178, 180, 226, 235–239
   expense_custom_fields.py121794%83–88, 247, 263, 265, 294
   merchants.py1062576%80–83, 111–129, 155–162, 179–180, 190, 203, 205, 235, 238–242
   projects.py1234067%88, 103–168, 188–189, 199, 223, 270, 284–288
   tax_groups.py180100% 
   webhook_attributes.py130695%98, 100–102, 213–214
workers
   actions.py210100% 
   helpers.py420100% 
   worker.py56591%44–45, 77–78, 125
TOTAL10845101691% 

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

@github-actions
Copy link

Failure. Coverage is below 90%.

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

apps/internal/tasks.py (36.4%): Missing lines 92-96,111-112
apps/sage_intacct/models.py (100%)
apps/sage_intacct/tasks.py (81.6%): Missing lines 750,1199-1203,1387-1390,1455-1458,1476-1480,1767-1771,1777-1781,1788-1792,1879-1881
apps/workspaces/enums.py (100%)

Total: 253 lines
Missing: 44 lines
Coverage: 82%

@github-actions
Copy link

Coverage

Coverage Report
FileStmtsMissCoverMissing
apps
   exceptions.py471177%27, 33, 39–44, 50, 56–61, 67, 73, 79–80
apps/fyle
   actions.py124794%214, 263, 319–323
   constants.py10100% 
   helpers.py2351494%50–57, 66, 376, 470, 477–480, 483–484
   models.py3382194%315–317, 321–323, 327–329, 333–335, 339–341, 345–347, 408, 530–551, 574, 591
   queue.py500100% 
   serializers.py410100% 
   signals.py35683%22, 55–56, 69–71
   tasks.py5468784%132, 143–144, 147–148, 151–152, 174–175, 231–251, 263–268, 311–314, 339–343, 353–361, 400–410, 525–585, 906–910, 1048, 1059–1060, 1085–1086
   views.py1721591%84–91, 145, 245–246, 290–291, 316–320, 413–417
apps/internal
   actions.py39295%26–27
   helpers.py361364%18–35
   serializers.py300100% 
   tasks.py903264%31–35, 61–66, 109, 121–172
   views.py83199%39
apps/internal/services
   e2e_setup.py590100% 
   fixture_factory.py59395%218–220
apps/mappings
   constants.py20100% 
   exceptions.py71692%69–71, 79–81
   helpers.py300100% 
   models.py500100% 
   schedules.py150100% 
   serializers.py100100% 
   signals.py1111487%90–92, 127, 179–184, 190–194, 200–203, 209–210
   tasks.py1732983%117–118, 141–142, 145, 209–226, 254, 257, 260, 266, 269, 275, 314–316, 327, 399
   utils.py340100% 
   views.py46491%34–35, 114–115
apps/sage_intacct
   actions.py29486%21–22, 49–50
   connector.py8052597%133, 309, 321, 327, 403, 1414, 1713, 1840–1841, 1892–1893, 1914–1915, 1944–1945, 1953–1964, 1996–1997, 2017–2018
   dependent_fields.py2904286%345, 381–384, 413–422, 424–425, 427–429, 431–432, 434–435, 437–438, 442–444, 488, 508, 548–550, 596–598, 646–652, 656–657
   enums.py250100% 
   helpers.py56689%38–41, 58, 95
   models.py9886793%78–79, 261–271, 399, 406, 450, 471–488, 560, 572, 622, 628, 663, 713–715, 729–742, 753, 789, 841–842, 940, 981, 1209, 1304–1307, 1351, 1353, 1444, 1548–1589, 1687, 1713, 1824, 2198–2200, 2262
   queue.py1711691%45, 53, 58, 105, 130–133, 173, 187, 205–208, 243, 267–270, 305, 330–333
   serializers.py350100% 
   tasks.py158715990%105, 119, 152, 188–189, 193–196, 198, 201, 251, 286–287, 407–408, 414, 417, 460–461, 502–507, 572, 578, 586, 765–766, 786–789, 865–866, 889, 904, 909, 914, 921, 927, 930–932, 935–938, 941–943, 963, 1016–1017, 1103–1104, 1108, 1132, 1186, 1298–1299, 1380–1381, 1383, 1575–1576, 1669–1670, 1673, 1699, 1719, 1730, 1741, 1753, 1764, 1767–1774, 1777–1785, 1788–1795, 1819, 1964, 1976–1985, 2027, 2030–2035, 2038–2042, 2211–2215, 2314–2315, 2521–2531, 2534, 2543–2548, 2582–2584, 2618–2621, 2689–2693, 2702, 2791–2796, 2809, 2824, 2839
   utils.py8903396%718–722, 867, 1186, 1202–1208, 1217–1218, 1944–1948, 1976–1980, 2008–2012, 2056–2060, 2114–2118, 2139, 2148, 2157, 2166–2167
   views.py1453377%127–129, 134–135, 141–142, 185–188, 258–288, 299–314, 327–331
apps/sage_intacct/errors
   errors.py20100% 
   helpers.py47198%80
apps/sage_intacct/exports
   ap_payments.py130100% 
   bills.py280100% 
   charge_card_transactions.py220100% 
   expense_reports.py280100% 
   helpers.py56296%68, 141
   journal_entries.py76889%177–180, 316–319
   reimbursements.py130100% 
apps/tasks
   models.py690100% 
   serializers.py60100% 
   views.py370100% 
apps/users
   helpers.py120100% 
   models.py530100% 
   views.py170100% 
apps/workspaces
   actions.py46980%65, 84–85, 103, 122–133, 147
   enums.py840100% 
   helpers.py80100% 
   models.py1760100% 
   permissions.py34974%33, 59–67
   serializers.py43198%54
   signals.py310100% 
   system_comments.py60100% 
   tasks.py175995%53–59, 187–194, 235, 267–268, 379
   utils.py90100% 
   views.py320997%107–109, 136–139, 665–666
apps/workspaces/apis/advanced_settings
   serializers.py80396%260, 263, 266
   triggers.py100100% 
   views.py110100% 
apps/workspaces/apis/errors
   serializers.py200100% 
   views.py150100% 
apps/workspaces/apis/export_settings
   helpers.py730100% 
   serializers.py103397%267, 270, 273
   triggers.py39295%32–33
   views.py110100% 
apps/workspaces/apis/import_settings
   serializers.py1411887%232–238, 243–249, 257–265, 283, 286, 314, 317–318, 326
   triggers.py47198%31
   views.py330100% 
fyle_integrations_imports
   dataclasses.py310100% 
   models.py230100% 
   queues.py34585%24, 99, 136, 148–149
   signals.py100100% 
   tasks.py1278136%69–111, 120–126, 139–208, 212–227, 252–255, 257, 259, 264
fyle_integrations_imports/modules
   base.py1881095%75, 91–92, 95, 126, 230–231, 237–238, 351
   categories.py1773381%80, 96, 99–100, 103–104, 272–273, 283, 296, 298, 342, 351–355, 364–410
   cost_centers.py961288%132–133, 152–153, 162, 178, 180, 226, 235–239
   expense_custom_fields.py121794%83–88, 247, 263, 265, 294
   merchants.py1062576%80–83, 111–129, 155–162, 179–180, 190, 203, 205, 235, 238–242
   projects.py1234067%88, 103–168, 188–189, 199, 223, 270, 284–288
   tax_groups.py180100% 
   webhook_attributes.py130695%98, 100–102, 213–214
workers
   actions.py210100% 
   helpers.py420100% 
   worker.py56591%44–45, 77–78, 125
TOTAL1084594991% 

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

@github-actions
Copy link


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

apps/internal/tasks.py (100%)
apps/sage_intacct/models.py (100%)
apps/sage_intacct/tasks.py (92.5%): Missing lines 1767-1771,1777-1781,1788-1792
apps/workspaces/enums.py (100%)

Total: 253 lines
Missing: 15 lines
Coverage: 94%

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
apps/sage_intacct/models.py (1)

1129-1167: Keep the billable flag consistent with the dimensions you persist

The new warning uses dimensions_values (post-allocation), but the saved billable flag still uses the pre-allocation customer_id/item_id variables. If allocation clears those dimensions, you can persist billable=True while customer_id/item_id are NULL, yet log “billable disabled.” Compute billable once from the same dimensions_values and reuse it here (and in the other lineitem creators).

Proposed fix
-            if lineitem.billable and not (dimensions_values['customer_id'] and dimensions_values['item_id']):
+            is_billable = bool(lineitem.billable and dimensions_values['customer_id'] and dimensions_values['item_id'])
+            if lineitem.billable and not is_billable:
                 missing_fields = []
                 if not dimensions_values['customer_id']:
                     missing_fields.append('customer_id')
                 if not dimensions_values['item_id']:
                     missing_fields.append('item_id')
                 add_system_comment(
                     system_comments=system_comments,
                     source=SystemCommentSourceEnum.CREATE_BILL_LINEITEMS,
                     intent=SystemCommentIntentEnum.BILLABLE_DISABLED,
                     entity_type=SystemCommentEntityTypeEnum.EXPENSE,
                     workspace_id=expense_group.workspace_id,
                     entity_id=lineitem.id,
                     reason=SystemCommentReasonEnum.BILLABLE_SET_TO_FALSE_MISSING_DIMENSIONS,
                     info={'missing_fields': missing_fields, 'original_billable': lineitem.billable}
                 )
 
             bill_lineitem_object, _ = BillLineitem.objects.update_or_create(
                 bill=bill,
                 expense_id=lineitem.id,
                 defaults={
@@
-                    'billable': lineitem.billable if customer_id and item_id else False,
+                    'billable': is_billable,
apps/sage_intacct/tasks.py (1)

891-963: Missing system_comments bulk creation in journal entry exception handlers.

Unlike create_expense_report, create_bill, and create_charge_card_transaction, the create_journal_entry function does not persist system_comments in its exception handlers. This means any collected comments (e.g., from lines 750-760 for ERROR state or 789-798 for fallback vendor) will be lost if the export fails.

🐛 Proposed fix - add bulk create to each exception handler

For example, in the BulkError handler:

     except BulkError as exception:
+        if system_comments:
+            for comment in system_comments:
+                comment['workspace_id'] = expense_group.workspace_id
+                comment['export_type'] = ExportTypeEnum.JOURNAL_ENTRY
+            SystemComment.bulk_create_comments(system_comments)
         logger.info(exception.response)
         detail = exception.response

Apply the same pattern to all other exception handlers (WrongParamsError, NoPrivilegeError, InvalidTokenError, ValueErrorWithResponse, IntacctRESTBadRequestError, IntacctRESTInvalidTokenError, IntacctRESTInternalServerError, and Exception).

🤖 Fix all issues with AI agents
In `@tests/conftest.py`:
- Around line 350-372: The fixture get_or_create_task_log creates TaskLog
instances but doesn't apply a provided updated_at because TaskLog.updated_at
uses auto_now=True which ignores create() values; modify the
_get_or_create_task_log function so that if updated_at is provided and a TaskLog
was just created (or exists), set task_log.updated_at = updated_at and call
task_log.save(update_fields=["updated_at"]) (referencing TaskLog and
_get_or_create_task_log) to persist the historical timestamp used by tests.

In `@tests/test_system_comments/test_system_comments.py`:
- Around line 993-998: The mock for Schedule.objects.filter needs to support
chaining to .first()—instead of returning None from .filter(), have the patched
return value provide a .first() method (e.g. return a MagicMock whose first()
returns None or the desired object); update the mocker.patch call that targets
Schedule.objects.filter so it returns a MagicMock with first configured
(referencing Schedule.objects.filter and its .first() call) so the test no
longer raises AttributeError.
🧹 Nitpick comments (2)
apps/sage_intacct/tasks.py (2)

1095-1099: Consider extracting repeated system comment persistence logic into a helper.

The same 5-line block for persisting system comments is repeated in the success path and every exception handler across create_expense_report, create_bill, and create_charge_card_transaction (30+ times total). This could be simplified with a helper function.

♻️ Suggested helper function
def persist_system_comments(system_comments: list, workspace_id: int, export_type: ExportTypeEnum) -> None:
    """Persist collected system comments with workspace and export type context."""
    if system_comments:
        for comment in system_comments:
            comment['workspace_id'] = workspace_id
            comment['export_type'] = export_type
        SystemComment.bulk_create_comments(system_comments)

Then each handler becomes a single call:

persist_system_comments(system_comments, expense_group.workspace_id, ExportTypeEnum.EXPENSE_REPORT)

1852-1852: Type hint should use explicit | None instead of implicit Optional.

Per PEP 484 and the static analysis hint (RUF013), the parameter type should explicitly indicate it can be None.

-def validate_for_skipping_payment(export_module: Bill | ExpenseReport, workspace_id: int, type: str, system_comments: list = None) -> bool:
+def validate_for_skipping_payment(export_module: Bill | ExpenseReport, workspace_id: int, type: str, system_comments: list | None = None) -> bool:

Comment on lines +350 to +372
@pytest.fixture
def get_or_create_task_log(db) -> Callable:
"""
Fixture to get or create a TaskLog for an expense group
Returns a function that can be called with expense_group and optional parameters
"""
def _get_or_create_task_log(
expense_group: ExpenseGroup,
task_type: str = 'FETCHING_EXPENSES',
status: str = 'COMPLETE',
updated_at: Optional[datetime] = None
) -> TaskLog:
task_log = TaskLog.objects.filter(expense_group_id=expense_group.id).first()
if not task_log:
task_log = TaskLog.objects.create(
expense_group_id=expense_group.id,
workspace_id=expense_group.workspace_id,
type=task_type,
status=status,
updated_at=updated_at
)
return task_log
return _get_or_create_task_log
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 | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

find . -type f -name "*.py" | xargs grep -l "class TaskLog" | head -5

Repository: fylein/fyle-intacct-api

Length of output: 117


🏁 Script executed:

cat ./apps/tasks/models.py

Repository: fylein/fyle-intacct-api

Length of output: 6929


🏁 Script executed:

grep -n "get_or_create_task_log" tests/conftest.py -A 5 -B 2

Repository: fylein/fyle-intacct-api

Length of output: 642


🏁 Script executed:

grep -r "get_or_create_task_log" tests/ --include="*.py" -n

Repository: fylein/fyle-intacct-api

Length of output: 7416


🏁 Script executed:

sed -n '976,1000p' tests/test_system_comments/test_system_comments.py

Repository: fylein/fyle-intacct-api

Length of output: 1206


🏁 Script executed:

sed -n '1756,1775p' tests/test_system_comments/test_system_comments.py

Repository: fylein/fyle-intacct-api

Length of output: 734


Handle updated_at after TaskLog creation since auto_now=True prevents passing it to create()

TaskLog.updated_at uses auto_now=True, so values passed to create() are silently ignored. Tests relying on historical timestamps (e.g., stuck exports detection) will use current time instead. Update the timestamp after creation when provided.

     def _get_or_create_task_log(
         expense_group: ExpenseGroup,
         task_type: str = 'FETCHING_EXPENSES',
         status: str = 'COMPLETE',
         updated_at: Optional[datetime] = None
     ) -> TaskLog:
         task_log = TaskLog.objects.filter(expense_group_id=expense_group.id).first()
         if not task_log:
             task_log = TaskLog.objects.create(
                 expense_group_id=expense_group.id,
                 workspace_id=expense_group.workspace_id,
                 type=task_type,
                 status=status,
                 updated_at=updated_at
             )
+        if updated_at is not None:
+            TaskLog.objects.filter(id=task_log.id).update(updated_at=updated_at)
+            task_log.refresh_from_db()
         return task_log
🧰 Tools
🪛 Ruff (0.14.14)

351-351: Unused function argument: db

(ARG001)

🤖 Prompt for AI Agents
In `@tests/conftest.py` around lines 350 - 372, The fixture get_or_create_task_log
creates TaskLog instances but doesn't apply a provided updated_at because
TaskLog.updated_at uses auto_now=True which ignores create() values; modify the
_get_or_create_task_log function so that if updated_at is provided and a TaskLog
was just created (or exists), set task_log.updated_at = updated_at and call
task_log.save(update_fields=["updated_at"]) (referencing TaskLog and
_get_or_create_task_log) to persist the historical timestamp used by tests.

Comment on lines +993 to +998
captured_comments = []
mocker.patch('apps.internal.tasks.export_to_intacct')
mocker.patch('apps.internal.tasks.update_failed_expenses')
mocker.patch('apps.internal.tasks.post_accounting_export_summary')
mocker.patch('apps.internal.tasks.Schedule.objects.filter', return_value=mocker.MagicMock(filter=mocker.MagicMock(return_value=None)))
mocker.patch.object(SystemComment, 'bulk_create_comments', side_effect=lambda comments: captured_comments.extend(comments))
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 | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, let's look at the test file and the surrounding context
cat -n tests/test_system_comments/test_system_comments.py | sed -n '990,1010p'

Repository: fylein/fyle-intacct-api

Length of output: 1401


🏁 Script executed:

# Let's get more context around the test function
cat -n tests/test_system_comments/test_system_comments.py | sed -n '970,1020p'

Repository: fylein/fyle-intacct-api

Length of output: 2910


🏁 Script executed:

# Let's find the test function name to understand what's being tested
cat -n tests/test_system_comments/test_system_comments.py | sed -n '950,1000p'

Repository: fylein/fyle-intacct-api

Length of output: 2951


🏁 Script executed:

# Find the retrigger_stuck_exports function
rg -n "def retrigger_stuck_exports" --type py

Repository: fylein/fyle-intacct-api

Length of output: 131


🏁 Script executed:

# Look for usage of Schedule.objects.filter in the codebase
rg -n "Schedule\.objects\.filter" --type py -A 3

Repository: fylein/fyle-intacct-api

Length of output: 18382


🏁 Script executed:

# Get the retrigger_stuck_exports function implementation
cat -n apps/internal/tasks.py | sed -n '38,200p'

Repository: fylein/fyle-intacct-api

Length of output: 8262


🏁 Script executed:

# Verify the test actually fails with current mock by checking if there are any other test runs
# Also check if this is the only place this mock pattern appears
rg -n "Schedule.objects.filter.*return_value.*MagicMock.*filter.*MagicMock.*return_value.*None" tests/

Repository: fylein/fyle-intacct-api

Length of output: 260


🏁 Script executed:

# Check line 1777 which also has a Schedule.objects.filter mock
cat -n tests/test_system_comments/test_system_comments.py | sed -n '1770,1800p'

Repository: fylein/fyle-intacct-api

Length of output: 1897


Fix mock to support .filter(...).first() chaining

The current mock returns None from .filter(), which causes .first() to raise AttributeError. Set up the mock to properly chain these calls.

Proposed fix
-    mocker.patch('apps.internal.tasks.Schedule.objects.filter', return_value=mocker.MagicMock(filter=mocker.MagicMock(return_value=None)))
+    mock_schedule_qs = mocker.MagicMock()
+    mock_schedule_filter = mocker.MagicMock()
+    mock_schedule_filter.first.return_value = None
+    mock_schedule_qs.filter.return_value = mock_schedule_filter
+    mocker.patch('apps.internal.tasks.Schedule.objects.filter', return_value=mock_schedule_qs)
🤖 Prompt for AI Agents
In `@tests/test_system_comments/test_system_comments.py` around lines 993 - 998,
The mock for Schedule.objects.filter needs to support chaining to
.first()—instead of returning None from .filter(), have the patched return value
provide a .first() method (e.g. return a MagicMock whose first() returns None or
the desired object); update the mocker.patch call that targets
Schedule.objects.filter so it returns a MagicMock with first configured
(referencing Schedule.objects.filter and its .first() call) so the test no
longer raises AttributeError.

@github-actions
Copy link

Coverage

Coverage Report
FileStmtsMissCoverMissing
apps
   exceptions.py471177%27, 33, 39–44, 50, 56–61, 67, 73, 79–80
apps/fyle
   actions.py124794%214, 263, 319–323
   constants.py10100% 
   helpers.py2351494%50–57, 66, 376, 470, 477–480, 483–484
   models.py3382194%315–317, 321–323, 327–329, 333–335, 339–341, 345–347, 408, 530–551, 574, 591
   queue.py500100% 
   serializers.py410100% 
   signals.py35683%22, 55–56, 69–71
   tasks.py5468784%132, 143–144, 147–148, 151–152, 174–175, 231–251, 263–268, 311–314, 339–343, 353–361, 400–410, 525–585, 906–910, 1048, 1059–1060, 1085–1086
   views.py1721591%84–91, 145, 245–246, 290–291, 316–320, 413–417
apps/internal
   actions.py39295%26–27
   helpers.py361364%18–35
   serializers.py300100% 
   tasks.py903264%31–35, 61–66, 109, 121–172
   views.py83199%39
apps/internal/services
   e2e_setup.py590100% 
   fixture_factory.py59395%218–220
apps/mappings
   constants.py20100% 
   exceptions.py71692%69–71, 79–81
   helpers.py300100% 
   models.py500100% 
   schedules.py150100% 
   serializers.py100100% 
   signals.py1111487%90–92, 127, 179–184, 190–194, 200–203, 209–210
   tasks.py1732983%117–118, 141–142, 145, 209–226, 254, 257, 260, 266, 269, 275, 314–316, 327, 399
   utils.py340100% 
   views.py46491%34–35, 114–115
apps/sage_intacct
   actions.py29486%21–22, 49–50
   connector.py8052597%133, 309, 321, 327, 403, 1414, 1713, 1840–1841, 1892–1893, 1914–1915, 1944–1945, 1953–1964, 1996–1997, 2017–2018
   dependent_fields.py2904286%345, 381–384, 413–422, 424–425, 427–429, 431–432, 434–435, 437–438, 442–444, 488, 508, 548–550, 596–598, 646–652, 656–657
   enums.py250100% 
   helpers.py56689%38–41, 58, 95
   models.py9886793%78–79, 261–271, 399, 406, 450, 471–488, 560, 572, 622, 628, 663, 713–715, 729–742, 753, 789, 841–842, 940, 981, 1209, 1304–1307, 1351, 1353, 1444, 1548–1589, 1687, 1713, 1824, 2198–2200, 2262
   queue.py1711691%45, 53, 58, 105, 130–133, 173, 187, 205–208, 243, 267–270, 305, 330–333
   serializers.py350100% 
   tasks.py144714490%105, 119, 152, 188–189, 193–196, 198, 201, 251, 286–287, 407–408, 414, 417, 460–461, 502–507, 572, 578, 586, 765–766, 786–789, 865–866, 889, 904, 909, 914, 921, 927, 930–932, 935–938, 941–943, 963, 1016–1017, 1097–1098, 1102, 1121, 1155, 1254–1255, 1330–1331, 1333, 1487–1488, 1575–1576, 1579, 1600, 1615, 1621, 1627, 1634, 1640, 1643–1645, 1648–1651, 1654–1656, 1682, 1827, 1839–1848, 1890, 1893–1898, 1901–1905, 2074–2078, 2177–2178, 2384–2394, 2397, 2406–2411, 2445–2447, 2481–2484, 2552–2556, 2565, 2654–2659, 2672, 2687, 2702
   utils.py8903396%718–722, 867, 1186, 1202–1208, 1217–1218, 1944–1948, 1976–1980, 2008–2012, 2056–2060, 2114–2118, 2139, 2148, 2157, 2166–2167
   views.py1453377%127–129, 134–135, 141–142, 185–188, 258–288, 299–314, 327–331
apps/sage_intacct/errors
   errors.py20100% 
   helpers.py47198%80
apps/sage_intacct/exports
   ap_payments.py130100% 
   bills.py280100% 
   charge_card_transactions.py220100% 
   expense_reports.py280100% 
   helpers.py56296%68, 141
   journal_entries.py76889%177–180, 316–319
   reimbursements.py130100% 
apps/tasks
   models.py690100% 
   serializers.py60100% 
   views.py370100% 
apps/users
   helpers.py120100% 
   models.py530100% 
   views.py170100% 
apps/workspaces
   actions.py46980%65, 84–85, 103, 122–133, 147
   enums.py840100% 
   helpers.py80100% 
   models.py1760100% 
   permissions.py34974%33, 59–67
   serializers.py43198%54
   signals.py310100% 
   system_comments.py60100% 
   tasks.py175995%53–59, 187–194, 235, 267–268, 379
   utils.py90100% 
   views.py320997%107–109, 136–139, 665–666
apps/workspaces/apis/advanced_settings
   serializers.py80396%260, 263, 266
   triggers.py100100% 
   views.py110100% 
apps/workspaces/apis/errors
   serializers.py200100% 
   views.py150100% 
apps/workspaces/apis/export_settings
   helpers.py730100% 
   serializers.py103397%267, 270, 273
   triggers.py39295%32–33
   views.py110100% 
apps/workspaces/apis/import_settings
   serializers.py1411887%232–238, 243–249, 257–265, 283, 286, 314, 317–318, 326
   triggers.py47198%31
   views.py330100% 
fyle_integrations_imports
   dataclasses.py310100% 
   models.py230100% 
   queues.py34585%24, 99, 136, 148–149
   signals.py100100% 
   tasks.py1278136%69–111, 120–126, 139–208, 212–227, 252–255, 257, 259, 264
fyle_integrations_imports/modules
   base.py1881095%75, 91–92, 95, 126, 230–231, 237–238, 351
   categories.py1773381%80, 96, 99–100, 103–104, 272–273, 283, 296, 298, 342, 351–355, 364–410
   cost_centers.py961288%132–133, 152–153, 162, 178, 180, 226, 235–239
   expense_custom_fields.py121794%83–88, 247, 263, 265, 294
   merchants.py1062576%80–83, 111–129, 155–162, 179–180, 190, 203, 205, 235, 238–242
   projects.py1234067%88, 103–168, 188–189, 199, 223, 270, 284–288
   tax_groups.py180100% 
   webhook_attributes.py130695%98, 100–102, 213–214
workers
   actions.py210100% 
   helpers.py420100% 
   worker.py56591%44–45, 77–78, 125
TOTAL1070593491% 

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

@github-actions
Copy link


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

apps/internal/tasks.py (100%)
apps/sage_intacct/models.py (100%)
apps/sage_intacct/tasks.py (100%)
apps/workspaces/enums.py (100%)

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

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

🤖 Fix all issues with AI agents
In `@apps/sage_intacct/tasks.py`:
- Around line 746-761: system_comments are being accumulated via
add_system_comment but the bulk-create is only executed on the success path of
the Intacct journal-entry export, so any exception after accumulation causes
comments to be lost; locate where system_comments is collected (look for
variables named system_comments and calls to add_system_comment in the
journal-entry export flow for expense_group) and move the
persistence/bulk-create call for those system_comments into a finally block (or
ensure it's executed in finally) so comments are always saved regardless of
success or exception; apply the same change to the other similar blocks
referenced (around the ranges that add_system_comment at the other spots).

@github-actions
Copy link

Coverage

Coverage Report
FileStmtsMissCoverMissing
apps
   exceptions.py471177%27, 33, 39–44, 50, 56–61, 67, 73, 79–80
apps/fyle
   actions.py124794%214, 263, 319–323
   constants.py10100% 
   helpers.py2351494%50–57, 66, 376, 470, 477–480, 483–484
   models.py3382194%315–317, 321–323, 327–329, 333–335, 339–341, 345–347, 408, 530–551, 574, 591
   queue.py500100% 
   serializers.py410100% 
   signals.py35683%22, 55–56, 69–71
   tasks.py5468784%132, 143–144, 147–148, 151–152, 174–175, 231–251, 263–268, 311–314, 339–343, 353–361, 400–410, 525–585, 906–910, 1048, 1059–1060, 1085–1086
   views.py1721591%84–91, 145, 245–246, 290–291, 316–320, 413–417
apps/internal
   actions.py39295%26–27
   helpers.py361364%18–35
   serializers.py300100% 
   tasks.py903264%31–35, 61–66, 109, 121–172
   views.py83199%39
apps/internal/services
   e2e_setup.py590100% 
   fixture_factory.py59395%218–220
apps/mappings
   constants.py20100% 
   exceptions.py71692%69–71, 79–81
   helpers.py300100% 
   models.py500100% 
   schedules.py150100% 
   serializers.py100100% 
   signals.py1111487%90–92, 127, 179–184, 190–194, 200–203, 209–210
   tasks.py1732983%117–118, 141–142, 145, 209–226, 254, 257, 260, 266, 269, 275, 314–316, 327, 399
   utils.py340100% 
   views.py46491%34–35, 114–115
apps/sage_intacct
   actions.py29486%21–22, 49–50
   connector.py8052597%133, 309, 321, 327, 403, 1414, 1713, 1840–1841, 1892–1893, 1914–1915, 1944–1945, 1953–1964, 1996–1997, 2017–2018
   dependent_fields.py2904286%345, 381–384, 413–422, 424–425, 427–429, 431–432, 434–435, 437–438, 442–444, 488, 508, 548–550, 596–598, 646–652, 656–657
   enums.py250100% 
   helpers.py56689%38–41, 58, 95
   models.py9886793%78–79, 261–271, 399, 406, 450, 471–488, 560, 572, 622, 628, 663, 713–715, 729–742, 753, 789, 841–842, 940, 981, 1209, 1304–1307, 1351, 1353, 1444, 1548–1589, 1687, 1713, 1824, 2198–2200, 2262
   queue.py1711691%45, 53, 58, 105, 130–133, 173, 187, 205–208, 243, 267–270, 305, 330–333
   serializers.py350100% 
   tasks.py144714490%105, 119, 152, 188–189, 193–196, 198, 201, 251, 286–287, 407–408, 414, 417, 460–461, 502–507, 572, 578, 586, 765–766, 786–789, 865–866, 889, 904, 909, 914, 921, 927, 930–932, 935–938, 941–943, 963, 1016–1017, 1097–1098, 1102, 1121, 1155, 1254–1255, 1330–1331, 1333, 1487–1488, 1575–1576, 1579, 1600, 1615, 1621, 1627, 1634, 1640, 1643–1645, 1648–1651, 1654–1656, 1682, 1827, 1839–1848, 1890, 1893–1898, 1901–1905, 2074–2078, 2177–2178, 2384–2394, 2397, 2406–2411, 2445–2447, 2481–2484, 2552–2556, 2565, 2654–2659, 2672, 2687, 2702
   utils.py8903396%718–722, 867, 1186, 1202–1208, 1217–1218, 1944–1948, 1976–1980, 2008–2012, 2056–2060, 2114–2118, 2139, 2148, 2157, 2166–2167
   views.py1453377%127–129, 134–135, 141–142, 185–188, 258–288, 299–314, 327–331
apps/sage_intacct/errors
   errors.py20100% 
   helpers.py47198%80
apps/sage_intacct/exports
   ap_payments.py130100% 
   bills.py280100% 
   charge_card_transactions.py220100% 
   expense_reports.py280100% 
   helpers.py56296%68, 141
   journal_entries.py76889%177–180, 316–319
   reimbursements.py130100% 
apps/tasks
   models.py690100% 
   serializers.py60100% 
   views.py370100% 
apps/users
   helpers.py120100% 
   models.py530100% 
   views.py170100% 
apps/workspaces
   actions.py46980%65, 84–85, 103, 122–133, 147
   enums.py840100% 
   helpers.py80100% 
   models.py1760100% 
   permissions.py34974%33, 59–67
   serializers.py43198%54
   signals.py310100% 
   system_comments.py60100% 
   tasks.py175995%53–59, 187–194, 235, 267–268, 379
   utils.py90100% 
   views.py320997%107–109, 136–139, 665–666
apps/workspaces/apis/advanced_settings
   serializers.py80396%260, 263, 266
   triggers.py100100% 
   views.py110100% 
apps/workspaces/apis/errors
   serializers.py200100% 
   views.py150100% 
apps/workspaces/apis/export_settings
   helpers.py730100% 
   serializers.py103397%267, 270, 273
   triggers.py39295%32–33
   views.py110100% 
apps/workspaces/apis/import_settings
   serializers.py1411887%232–238, 243–249, 257–265, 283, 286, 314, 317–318, 326
   triggers.py47198%31
   views.py330100% 
fyle_integrations_imports
   dataclasses.py310100% 
   models.py230100% 
   queues.py34585%24, 99, 136, 148–149
   signals.py100100% 
   tasks.py1278136%69–111, 120–126, 139–208, 212–227, 252–255, 257, 259, 264
fyle_integrations_imports/modules
   base.py1881095%75, 91–92, 95, 126, 230–231, 237–238, 351
   categories.py1773381%80, 96, 99–100, 103–104, 272–273, 283, 296, 298, 342, 351–355, 364–410
   cost_centers.py961288%132–133, 152–153, 162, 178, 180, 226, 235–239
   expense_custom_fields.py121794%83–88, 247, 263, 265, 294
   merchants.py1062576%80–83, 111–129, 155–162, 179–180, 190, 203, 205, 235, 238–242
   projects.py1234067%88, 103–168, 188–189, 199, 223, 270, 284–288
   tax_groups.py180100% 
   webhook_attributes.py130695%98, 100–102, 213–214
workers
   actions.py210100% 
   helpers.py420100% 
   worker.py56591%44–45, 77–78, 125
TOTAL1070593491% 

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

@github-actions
Copy link


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

apps/internal/tasks.py (100%)
apps/sage_intacct/models.py (100%)
apps/sage_intacct/tasks.py (100%)
apps/workspaces/enums.py (100%)

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

@Hrishabh17 Hrishabh17 changed the title feat: system comments for p1 areas feat: system comments for p1, p2 areas Jan 29, 2026
@github-actions
Copy link

Coverage

Coverage Report
FileStmtsMissCoverMissing
apps
   exceptions.py471177%27, 33, 39–44, 50, 56–61, 67, 73, 79–80
apps/fyle
   actions.py124794%214, 263, 319–323
   constants.py10100% 
   helpers.py2351494%50–57, 66, 376, 470, 477–480, 483–484
   models.py3382194%315–317, 321–323, 327–329, 333–335, 339–341, 345–347, 408, 530–551, 574, 591
   queue.py500100% 
   serializers.py410100% 
   signals.py35683%22, 55–56, 69–71
   tasks.py5468784%132, 143–144, 147–148, 151–152, 174–175, 231–251, 263–268, 311–314, 339–343, 353–361, 400–410, 525–585, 906–910, 1048, 1059–1060, 1085–1086
   views.py1721591%84–91, 145, 245–246, 290–291, 316–320, 413–417
apps/internal
   actions.py39295%26–27
   helpers.py361364%18–35
   serializers.py300100% 
   tasks.py903264%31–35, 61–66, 109, 121–172
   views.py83199%39
apps/internal/services
   e2e_setup.py590100% 
   fixture_factory.py59395%218–220
apps/mappings
   constants.py20100% 
   exceptions.py71692%69–71, 79–81
   helpers.py300100% 
   models.py500100% 
   schedules.py150100% 
   serializers.py100100% 
   signals.py1111487%90–92, 127, 179–184, 190–194, 200–203, 209–210
   tasks.py1732983%117–118, 141–142, 145, 209–226, 254, 257, 260, 266, 269, 275, 314–316, 327, 399
   utils.py340100% 
   views.py46491%34–35, 114–115
apps/sage_intacct
   actions.py29486%21–22, 49–50
   connector.py8052597%133, 309, 321, 327, 403, 1414, 1713, 1840–1841, 1892–1893, 1914–1915, 1944–1945, 1953–1964, 1996–1997, 2017–2018
   dependent_fields.py2904286%345, 381–384, 413–422, 424–425, 427–429, 431–432, 434–435, 437–438, 442–444, 488, 508, 548–550, 596–598, 646–652, 656–657
   enums.py250100% 
   helpers.py56689%38–41, 58, 95
   models.py9886793%78–79, 261–271, 399, 406, 450, 471–488, 560, 572, 622, 628, 663, 713–715, 729–742, 753, 789, 841–842, 940, 981, 1209, 1304–1307, 1351, 1353, 1444, 1548–1589, 1687, 1713, 1824, 2198–2200, 2262
   queue.py1711691%45, 53, 58, 105, 130–133, 173, 187, 205–208, 243, 267–270, 305, 330–333
   serializers.py350100% 
   tasks.py144714490%105, 119, 152, 188–189, 193–196, 198, 201, 251, 286–287, 407–408, 414, 417, 460–461, 502–507, 572, 578, 586, 765–766, 786–789, 865–866, 889, 904, 909, 914, 921, 927, 930–932, 935–938, 941–943, 963, 1016–1017, 1097–1098, 1102, 1121, 1155, 1254–1255, 1330–1331, 1333, 1487–1488, 1575–1576, 1579, 1600, 1615, 1621, 1627, 1634, 1640, 1643–1645, 1648–1651, 1654–1656, 1682, 1827, 1839–1848, 1890, 1893–1898, 1901–1905, 2074–2078, 2177–2178, 2384–2394, 2397, 2406–2411, 2445–2447, 2481–2484, 2552–2556, 2565, 2654–2659, 2672, 2687, 2702
   utils.py8903396%718–722, 867, 1186, 1202–1208, 1217–1218, 1944–1948, 1976–1980, 2008–2012, 2056–2060, 2114–2118, 2139, 2148, 2157, 2166–2167
   views.py1453377%127–129, 134–135, 141–142, 185–188, 258–288, 299–314, 327–331
apps/sage_intacct/errors
   errors.py20100% 
   helpers.py47198%80
apps/sage_intacct/exports
   ap_payments.py130100% 
   bills.py280100% 
   charge_card_transactions.py220100% 
   expense_reports.py280100% 
   helpers.py56296%68, 141
   journal_entries.py76889%177–180, 316–319
   reimbursements.py130100% 
apps/tasks
   models.py690100% 
   serializers.py60100% 
   views.py370100% 
apps/users
   helpers.py120100% 
   models.py530100% 
   views.py170100% 
apps/workspaces
   actions.py46980%65, 84–85, 103, 122–133, 147
   enums.py860100% 
   helpers.py80100% 
   models.py1760100% 
   permissions.py34974%33, 59–67
   serializers.py43198%54
   signals.py310100% 
   system_comments.py60100% 
   tasks.py175995%53–59, 187–194, 235, 267–268, 379
   utils.py90100% 
   views.py329997%110–112, 139–142, 702–703
apps/workspaces/apis/advanced_settings
   serializers.py80396%260, 263, 266
   triggers.py100100% 
   views.py110100% 
apps/workspaces/apis/errors
   serializers.py200100% 
   views.py150100% 
apps/workspaces/apis/export_settings
   helpers.py730100% 
   serializers.py103397%267, 270, 273
   triggers.py39295%32–33
   views.py110100% 
apps/workspaces/apis/import_settings
   serializers.py1411887%232–238, 243–249, 257–265, 283, 286, 314, 317–318, 326
   triggers.py47198%31
   views.py330100% 
fyle_integrations_imports
   dataclasses.py310100% 
   models.py230100% 
   queues.py34585%24, 99, 136, 148–149
   signals.py100100% 
   tasks.py1278136%69–111, 120–126, 139–208, 212–227, 252–255, 257, 259, 264
fyle_integrations_imports/modules
   base.py1881095%75, 91–92, 95, 126, 230–231, 237–238, 351
   categories.py1773381%80, 96, 99–100, 103–104, 272–273, 283, 296, 298, 342, 351–355, 364–410
   cost_centers.py961288%132–133, 152–153, 162, 178, 180, 226, 235–239
   expense_custom_fields.py121794%83–88, 247, 263, 265, 294
   merchants.py1062576%80–83, 111–129, 155–162, 179–180, 190, 203, 205, 235, 238–242
   projects.py1234067%88, 103–168, 188–189, 199, 223, 270, 284–288
   tax_groups.py180100% 
   webhook_attributes.py130695%98, 100–102, 213–214
workers
   actions.py210100% 
   helpers.py420100% 
   worker.py56591%44–45, 77–78, 125
TOTAL1071693491% 

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

@github-actions
Copy link


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

apps/internal/tasks.py (100%)
apps/sage_intacct/models.py (100%)
apps/sage_intacct/tasks.py (100%)
apps/workspaces/enums.py (100%)
apps/workspaces/views.py (100%)

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

@github-actions
Copy link

Coverage

Coverage Report
FileStmtsMissCoverMissing
apps
   exceptions.py471177%27, 33, 39–44, 50, 56–61, 67, 73, 79–80
apps/fyle
   actions.py124794%214, 263, 319–323
   constants.py10100% 
   helpers.py2351494%50–57, 66, 376, 470, 477–480, 483–484
   models.py3382194%315–317, 321–323, 327–329, 333–335, 339–341, 345–347, 408, 530–551, 574, 591
   queue.py500100% 
   serializers.py410100% 
   signals.py35683%22, 55–56, 69–71
   tasks.py5468784%132, 143–144, 147–148, 151–152, 174–175, 231–251, 263–268, 311–314, 339–343, 353–361, 400–410, 525–585, 906–910, 1048, 1059–1060, 1085–1086
   views.py1721591%84–91, 145, 245–246, 290–291, 316–320, 413–417
apps/internal
   actions.py39295%26–27
   helpers.py361364%18–35
   serializers.py300100% 
   tasks.py913562%31–35, 61–66, 96–97, 110, 113, 122–173
   views.py83199%39
apps/internal/services
   e2e_setup.py590100% 
   fixture_factory.py59395%218–220
apps/mappings
   constants.py20100% 
   exceptions.py71692%69–71, 79–81
   helpers.py300100% 
   models.py500100% 
   schedules.py150100% 
   serializers.py100100% 
   signals.py1111487%90–92, 127, 179–184, 190–194, 200–203, 209–210
   tasks.py1732983%117–118, 141–142, 145, 209–226, 254, 257, 260, 266, 269, 275, 314–316, 327, 399
   utils.py340100% 
   views.py46491%34–35, 114–115
apps/sage_intacct
   actions.py29486%21–22, 49–50
   connector.py8052597%133, 309, 321, 327, 403, 1414, 1713, 1840–1841, 1892–1893, 1914–1915, 1944–1945, 1953–1964, 1996–1997, 2017–2018
   dependent_fields.py2904286%345, 381–384, 413–422, 424–425, 427–429, 431–432, 434–435, 437–438, 442–444, 488, 508, 548–550, 596–598, 646–652, 656–657
   enums.py250100% 
   helpers.py56689%38–41, 58, 95
   models.py9886793%78–79, 261–271, 399, 406, 450, 471–488, 560, 572, 622, 628, 663, 713–715, 729–742, 753, 789, 841–842, 940, 981, 1209, 1304–1307, 1351, 1353, 1444, 1548–1589, 1687, 1713, 1824, 2198–2200, 2262
   queue.py1711691%45, 53, 58, 105, 130–133, 173, 187, 205–208, 243, 267–270, 305, 330–333
   serializers.py350100% 
   tasks.py144914490%105, 119, 152, 188–189, 193–196, 198, 201, 251, 286–287, 407–408, 414, 417, 460–461, 502–507, 572, 578, 586, 765–766, 786–789, 865–866, 889, 904, 909, 914, 921, 927, 930–932, 935–938, 941–943, 963, 1016–1017, 1097–1098, 1102, 1123, 1157, 1256–1257, 1332–1333, 1335, 1489–1490, 1577–1578, 1581, 1602, 1617, 1623, 1629, 1636, 1642, 1645–1647, 1650–1653, 1656–1658, 1684, 1829, 1841–1850, 1892, 1895–1900, 1903–1907, 2076–2080, 2179–2180, 2386–2396, 2399, 2408–2413, 2447–2449, 2483–2486, 2554–2558, 2567, 2656–2661, 2674, 2689, 2704
   utils.py8903396%718–722, 867, 1186, 1202–1208, 1217–1218, 1944–1948, 1976–1980, 2008–2012, 2056–2060, 2114–2118, 2139, 2148, 2157, 2166–2167
   views.py1453377%127–129, 134–135, 141–142, 185–188, 258–288, 299–314, 327–331
apps/sage_intacct/errors
   errors.py20100% 
   helpers.py47198%80
apps/sage_intacct/exports
   ap_payments.py130100% 
   bills.py280100% 
   charge_card_transactions.py220100% 
   expense_reports.py280100% 
   helpers.py56296%68, 141
   journal_entries.py76889%177–180, 316–319
   reimbursements.py130100% 
apps/tasks
   models.py690100% 
   serializers.py60100% 
   views.py370100% 
apps/users
   helpers.py120100% 
   models.py530100% 
   views.py170100% 
apps/workspaces
   actions.py46980%65, 84–85, 103, 122–133, 147
   enums.py860100% 
   helpers.py80100% 
   models.py1760100% 
   permissions.py34974%33, 59–67
   serializers.py43198%54
   signals.py310100% 
   system_comments.py60100% 
   tasks.py175995%53–59, 187–194, 235, 267–268, 379
   utils.py90100% 
   views.py329997%110–112, 139–142, 702–703
apps/workspaces/apis/advanced_settings
   serializers.py80396%260, 263, 266
   triggers.py100100% 
   views.py110100% 
apps/workspaces/apis/errors
   serializers.py200100% 
   views.py150100% 
apps/workspaces/apis/export_settings
   helpers.py730100% 
   serializers.py103397%267, 270, 273
   triggers.py39295%32–33
   views.py110100% 
apps/workspaces/apis/import_settings
   serializers.py1411887%232–238, 243–249, 257–265, 283, 286, 314, 317–318, 326
   triggers.py47198%31
   views.py330100% 
fyle_integrations_imports
   dataclasses.py310100% 
   models.py230100% 
   queues.py34585%24, 99, 136, 148–149
   signals.py100100% 
   tasks.py1278136%69–111, 120–126, 139–208, 212–227, 252–255, 257, 259, 264
fyle_integrations_imports/modules
   base.py1881095%75, 91–92, 95, 126, 230–231, 237–238, 351
   categories.py1773381%80, 96, 99–100, 103–104, 272–273, 283, 296, 298, 342, 351–355, 364–410
   cost_centers.py961288%132–133, 152–153, 162, 178, 180, 226, 235–239
   expense_custom_fields.py121794%83–88, 247, 263, 265, 294
   merchants.py1062576%80–83, 111–129, 155–162, 179–180, 190, 203, 205, 235, 238–242
   projects.py1234067%88, 103–168, 188–189, 199, 223, 270, 284–288
   tax_groups.py180100% 
   webhook_attributes.py130695%98, 100–102, 213–214
workers
   actions.py210100% 
   helpers.py420100% 
   worker.py56591%44–45, 77–78, 125
TOTAL1071993791% 

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

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

🤖 Fix all issues with AI agents
In `@apps/sage_intacct/tasks.py`:
- Around line 1717-1724: Update the type hint for the system_comments parameter
in validate_for_skipping_payment to explicitly allow None by changing its
annotation from "list = None" to "list | None = None"; ensure the default
remains None and keep all internal logic that checks for None unchanged so
callers and behavior are unaffected.

Comment on lines +1717 to 1724
def validate_for_skipping_payment(export_module: Bill | ExpenseReport, workspace_id: int, type: str, system_comments: list = None) -> bool:
"""
Validate for skipping payment
:param export_module: Export Module
:param workspace_id: Workspace Id
:param type: Type
:param system_comments: optional list to collect system comment data
:return: True if payment is to be skipped, False otherwise
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 | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

cat -n apps/sage_intacct/tasks.py | sed -n '1710,1735p'

Repository: fylein/fyle-intacct-api

Length of output: 1338


Make system_comments explicitly optional in the type hint.

The parameter system_comments: list = None uses an implicit Optional pattern. Ruff RUF013 flags this; use list | None instead to explicitly indicate the parameter accepts None.

-def validate_for_skipping_payment(export_module: Bill | ExpenseReport, workspace_id: int, type: str, system_comments: list = None) -> bool:
+def validate_for_skipping_payment(export_module: Bill | ExpenseReport, workspace_id: int, type: str, system_comments: list | None = None) -> bool:
📝 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
def validate_for_skipping_payment(export_module: Bill | ExpenseReport, workspace_id: int, type: str, system_comments: list = None) -> bool:
"""
Validate for skipping payment
:param export_module: Export Module
:param workspace_id: Workspace Id
:param type: Type
:param system_comments: optional list to collect system comment data
:return: True if payment is to be skipped, False otherwise
def validate_for_skipping_payment(export_module: Bill | ExpenseReport, workspace_id: int, type: str, system_comments: list | None = None) -> bool:
"""
Validate for skipping payment
:param export_module: Export Module
:param workspace_id: Workspace Id
:param type: Type
:param system_comments: optional list to collect system comment data
:return: True if payment is to be skipped, False otherwise
🧰 Tools
🪛 Ruff (0.14.14)

1717-1717: PEP 484 prohibits implicit Optional

Convert to T | None

(RUF013)

🤖 Prompt for AI Agents
In `@apps/sage_intacct/tasks.py` around lines 1717 - 1724, Update the type hint
for the system_comments parameter in validate_for_skipping_payment to explicitly
allow None by changing its annotation from "list = None" to "list | None =
None"; ensure the default remains None and keep all internal logic that checks
for None unchanged so callers and behavior are unaffected.

@github-actions
Copy link

Coverage

Coverage Report
FileStmtsMissCoverMissing
apps
   exceptions.py471177%27, 33, 39–44, 50, 56–61, 67, 73, 79–80
apps/fyle
   actions.py124794%214, 263, 319–323
   constants.py10100% 
   helpers.py2351494%50–57, 66, 376, 470, 477–480, 483–484
   models.py3382194%315–317, 321–323, 327–329, 333–335, 339–341, 345–347, 408, 530–551, 574, 591
   queue.py500100% 
   serializers.py410100% 
   signals.py35683%22, 55–56, 69–71
   tasks.py5468784%132, 143–144, 147–148, 151–152, 174–175, 231–251, 263–268, 311–314, 339–343, 353–361, 400–410, 525–585, 906–910, 1048, 1059–1060, 1085–1086
   views.py1721591%84–91, 145, 245–246, 290–291, 316–320, 413–417
apps/internal
   actions.py39295%26–27
   helpers.py361364%18–35
   serializers.py300100% 
   tasks.py923265%31–35, 61–66, 111, 123–174
   views.py83199%39
apps/internal/services
   e2e_setup.py590100% 
   fixture_factory.py59395%218–220
apps/mappings
   constants.py20100% 
   exceptions.py71692%69–71, 79–81
   helpers.py300100% 
   models.py500100% 
   schedules.py150100% 
   serializers.py100100% 
   signals.py1111487%90–92, 127, 179–184, 190–194, 200–203, 209–210
   tasks.py1732983%117–118, 141–142, 145, 209–226, 254, 257, 260, 266, 269, 275, 314–316, 327, 399
   utils.py340100% 
   views.py46491%34–35, 114–115
apps/sage_intacct
   actions.py29486%21–22, 49–50
   connector.py8052597%133, 309, 321, 327, 403, 1414, 1713, 1840–1841, 1892–1893, 1914–1915, 1944–1945, 1953–1964, 1996–1997, 2017–2018
   dependent_fields.py2904286%345, 381–384, 413–422, 424–425, 427–429, 431–432, 434–435, 437–438, 442–444, 488, 508, 548–550, 596–598, 646–652, 656–657
   enums.py250100% 
   helpers.py56689%38–41, 58, 95
   models.py9886793%78–79, 261–271, 399, 406, 450, 471–488, 560, 572, 622, 628, 663, 713–715, 729–742, 753, 789, 841–842, 940, 981, 1209, 1304–1307, 1351, 1353, 1444, 1548–1589, 1687, 1713, 1824, 2198–2200, 2262
   queue.py1711691%45, 53, 58, 105, 130–133, 173, 187, 205–208, 243, 267–270, 305, 330–333
   serializers.py350100% 
   tasks.py144914490%105, 119, 152, 188–189, 193–196, 198, 201, 251, 286–287, 407–408, 414, 417, 460–461, 502–507, 572, 578, 586, 765–766, 786–789, 859–860, 883, 898, 903, 908, 915, 921, 924–926, 929–932, 935–937, 964, 1017–1018, 1098–1099, 1103, 1124, 1158, 1257–1258, 1333–1334, 1336, 1490–1491, 1578–1579, 1582, 1603, 1618, 1624, 1630, 1637, 1643, 1646–1648, 1651–1654, 1657–1659, 1685, 1830, 1842–1851, 1893, 1896–1901, 1904–1908, 2077–2081, 2180–2181, 2387–2397, 2400, 2409–2414, 2448–2450, 2484–2487, 2555–2559, 2568, 2657–2662, 2675, 2690, 2705
   utils.py8903396%718–722, 867, 1186, 1202–1208, 1217–1218, 1944–1948, 1976–1980, 2008–2012, 2056–2060, 2114–2118, 2139, 2148, 2157, 2166–2167
   views.py1453377%127–129, 134–135, 141–142, 185–188, 258–288, 299–314, 327–331
apps/sage_intacct/errors
   errors.py20100% 
   helpers.py47198%80
apps/sage_intacct/exports
   ap_payments.py130100% 
   bills.py280100% 
   charge_card_transactions.py220100% 
   expense_reports.py280100% 
   helpers.py56296%68, 141
   journal_entries.py76889%177–180, 316–319
   reimbursements.py130100% 
apps/tasks
   models.py690100% 
   serializers.py60100% 
   views.py370100% 
apps/users
   helpers.py120100% 
   models.py530100% 
   views.py170100% 
apps/workspaces
   actions.py46980%65, 84–85, 103, 122–133, 147
   enums.py860100% 
   helpers.py80100% 
   models.py1760100% 
   permissions.py34974%33, 59–67
   serializers.py43198%54
   signals.py310100% 
   system_comments.py60100% 
   tasks.py175995%53–59, 187–194, 235, 267–268, 379
   utils.py90100% 
   views.py329997%110–112, 139–142, 702–703
apps/workspaces/apis/advanced_settings
   serializers.py80396%260, 263, 266
   triggers.py100100% 
   views.py110100% 
apps/workspaces/apis/errors
   serializers.py200100% 
   views.py150100% 
apps/workspaces/apis/export_settings
   helpers.py730100% 
   serializers.py103397%267, 270, 273
   triggers.py39295%32–33
   views.py110100% 
apps/workspaces/apis/import_settings
   serializers.py1411887%232–238, 243–249, 257–265, 283, 286, 314, 317–318, 326
   triggers.py47198%31
   views.py330100% 
fyle_integrations_imports
   dataclasses.py310100% 
   models.py230100% 
   queues.py34585%24, 99, 136, 148–149
   signals.py100100% 
   tasks.py1278136%69–111, 120–126, 139–208, 212–227, 252–255, 257, 259, 264
fyle_integrations_imports/modules
   base.py1881095%75, 91–92, 95, 126, 230–231, 237–238, 351
   categories.py1773381%80, 96, 99–100, 103–104, 272–273, 283, 296, 298, 342, 351–355, 364–410
   cost_centers.py961288%132–133, 152–153, 162, 178, 180, 226, 235–239
   expense_custom_fields.py121794%83–88, 247, 263, 265, 294
   merchants.py1062576%80–83, 111–129, 155–162, 179–180, 190, 203, 205, 235, 238–242
   projects.py1234067%88, 103–168, 188–189, 199, 223, 270, 284–288
   tax_groups.py180100% 
   webhook_attributes.py130695%98, 100–102, 213–214
workers
   actions.py210100% 
   helpers.py420100% 
   worker.py56591%44–45, 77–78, 125
TOTAL1072093491% 

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

@github-actions
Copy link


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

apps/internal/tasks.py (100%)
apps/sage_intacct/models.py (100%)
apps/sage_intacct/tasks.py (100%)
apps/workspaces/enums.py (100%)
apps/workspaces/views.py (100%)

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

@github-actions
Copy link

Coverage

Coverage Report
FileStmtsMissCoverMissing
apps
   exceptions.py471177%27, 33, 39–44, 50, 56–61, 67, 73, 79–80
apps/fyle
   actions.py124794%214, 263, 319–323
   constants.py10100% 
   helpers.py2351494%50–57, 66, 376, 470, 477–480, 483–484
   models.py3382194%315–317, 321–323, 327–329, 333–335, 339–341, 345–347, 408, 530–551, 574, 591
   queue.py500100% 
   serializers.py410100% 
   signals.py35683%22, 55–56, 69–71
   tasks.py5468784%132, 143–144, 147–148, 151–152, 174–175, 231–251, 263–268, 311–314, 339–343, 353–361, 400–410, 525–585, 906–910, 1048, 1059–1060, 1085–1086
   views.py1721591%84–91, 145, 245–246, 290–291, 316–320, 413–417
apps/internal
   actions.py39295%26–27
   helpers.py361364%18–35
   serializers.py300100% 
   tasks.py923265%31–35, 61–66, 111, 123–174
   views.py83199%39
apps/internal/services
   e2e_setup.py590100% 
   fixture_factory.py59395%218–220
apps/mappings
   constants.py20100% 
   exceptions.py71692%69–71, 79–81
   helpers.py300100% 
   models.py500100% 
   schedules.py150100% 
   serializers.py100100% 
   signals.py1111487%90–92, 127, 179–184, 190–194, 200–203, 209–210
   tasks.py1732983%117–118, 141–142, 145, 209–226, 254, 257, 260, 266, 269, 275, 314–316, 327, 399
   utils.py340100% 
   views.py46491%34–35, 114–115
apps/sage_intacct
   actions.py29486%21–22, 49–50
   connector.py8052597%133, 309, 321, 327, 403, 1414, 1713, 1840–1841, 1892–1893, 1914–1915, 1944–1945, 1953–1964, 1996–1997, 2017–2018
   dependent_fields.py2904286%345, 381–384, 413–422, 424–425, 427–429, 431–432, 434–435, 437–438, 442–444, 488, 508, 548–550, 596–598, 646–652, 656–657
   enums.py250100% 
   helpers.py56689%38–41, 58, 95
   models.py9886793%78–79, 264–275, 405, 412, 456, 477–494, 567, 579, 629, 635, 670, 720–722, 736–749, 760, 796, 848–849, 949, 990, 1219, 1314–1317, 1361, 1363, 1455, 1559–1602, 1700, 1727, 1838, 2213–2215, 2277
   queue.py1711691%45, 53, 58, 105, 130–133, 173, 187, 205–208, 243, 267–270, 305, 330–333
   serializers.py350100% 
   tasks.py143314490%105, 119, 152, 188–189, 193–196, 198, 201, 251, 286–287, 407–408, 414, 417, 460–461, 502–507, 572, 578, 586, 765–766, 786–789, 860–861, 884, 899, 904, 909, 916, 922, 925–927, 930–933, 936–938, 966, 1019–1020, 1100–1101, 1105, 1126, 1160, 1260–1261, 1336–1337, 1339, 1494–1495, 1583–1584, 1587, 1608, 1623, 1629, 1635, 1642, 1648, 1651–1653, 1656–1659, 1662–1664, 1691, 1836, 1848–1857, 1899, 1902–1907, 1910–1914, 2083–2087, 2186–2187, 2393–2403, 2406, 2415–2420, 2454–2456, 2490–2493, 2561–2565, 2574, 2663–2668, 2681, 2696, 2711
   utils.py8903396%718–722, 867, 1186, 1202–1208, 1217–1218, 1944–1948, 1976–1980, 2008–2012, 2056–2060, 2114–2118, 2139, 2148, 2157, 2166–2167
   views.py1453377%127–129, 134–135, 141–142, 185–188, 258–288, 299–314, 327–331
apps/sage_intacct/errors
   errors.py20100% 
   helpers.py47198%80
apps/sage_intacct/exports
   ap_payments.py130100% 
   bills.py280100% 
   charge_card_transactions.py220100% 
   expense_reports.py280100% 
   helpers.py56296%68, 141
   journal_entries.py76889%177–180, 316–319
   reimbursements.py130100% 
apps/tasks
   models.py690100% 
   serializers.py60100% 
   views.py370100% 
apps/users
   helpers.py120100% 
   models.py530100% 
   views.py170100% 
apps/workspaces
   actions.py46980%65, 84–85, 103, 122–133, 147
   enums.py860100% 
   helpers.py80100% 
   models.py1760100% 
   permissions.py34974%33, 59–67
   serializers.py43198%54
   signals.py310100% 
   system_comments.py190100% 
   tasks.py175995%53–59, 187–194, 235, 267–268, 379
   utils.py90100% 
   views.py329997%110–112, 139–142, 702–703
apps/workspaces/apis/advanced_settings
   serializers.py80396%260, 263, 266
   triggers.py100100% 
   views.py110100% 
apps/workspaces/apis/errors
   serializers.py200100% 
   views.py150100% 
apps/workspaces/apis/export_settings
   helpers.py730100% 
   serializers.py103397%267, 270, 273
   triggers.py39295%32–33
   views.py110100% 
apps/workspaces/apis/import_settings
   serializers.py1411887%232–238, 243–249, 257–265, 283, 286, 314, 317–318, 326
   triggers.py47198%31
   views.py330100% 
fyle_integrations_imports
   dataclasses.py310100% 
   models.py230100% 
   queues.py34585%24, 99, 136, 148–149
   signals.py100100% 
   tasks.py1278136%69–111, 120–126, 139–208, 212–227, 252–255, 257, 259, 264
fyle_integrations_imports/modules
   base.py1881095%75, 91–92, 95, 126, 230–231, 237–238, 351
   categories.py1773381%80, 96, 99–100, 103–104, 272–273, 283, 296, 298, 342, 351–355, 364–410
   cost_centers.py961288%132–133, 152–153, 162, 178, 180, 226, 235–239
   expense_custom_fields.py121794%83–88, 247, 263, 265, 294
   merchants.py1062576%80–83, 111–129, 155–162, 179–180, 190, 203, 205, 235, 238–242
   projects.py1234067%88, 103–168, 188–189, 199, 223, 270, 284–288
   tax_groups.py180100% 
   webhook_attributes.py130695%98, 100–102, 213–214
workers
   actions.py210100% 
   helpers.py420100% 
   worker.py56591%44–45, 77–78, 125
TOTAL1071793491% 

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

@github-actions
Copy link


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

apps/internal/tasks.py (100%)
apps/sage_intacct/models.py (100%)
apps/sage_intacct/tasks.py (100%)
apps/workspaces/enums.py (100%)
apps/workspaces/system_comments.py (100%)
apps/workspaces/views.py (100%)

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

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

🤖 Fix all issues with AI agents
In `@apps/workspaces/system_comments.py`:
- Around line 17-18: Update the type hint for the parameter named "info" to be
explicitly optional (use Optional[dict]) to satisfy Ruff RUF013; locate the
function or method signature that declares "info: dict = None" (the same
signature that also declares "persist_without_export: bool = True") and change
the annotation to "info: Optional[dict]" while adding the required typing import
(Optional) if it's not already imported.

Comment on lines +17 to +18
info: dict = None,
persist_without_export: bool = True
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 | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

cat -n apps/workspaces/system_comments.py | head -25

Repository: fylein/fyle-intacct-api

Length of output: 949


Make info explicitly optional in the type hint.

Line 17 uses an implicit Optional; update it to satisfy Ruff RUF013.

🔧 Proposed fix
-    info: dict = None,
+    info: dict | None = None,
📝 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
info: dict = None,
persist_without_export: bool = True
info: dict | None = None,
persist_without_export: bool = True
🧰 Tools
🪛 Ruff (0.14.14)

17-17: PEP 484 prohibits implicit Optional

Convert to T | None

(RUF013)

🤖 Prompt for AI Agents
In `@apps/workspaces/system_comments.py` around lines 17 - 18, Update the type
hint for the parameter named "info" to be explicitly optional (use
Optional[dict]) to satisfy Ruff RUF013; locate the function or method signature
that declares "info: dict = None" (the same signature that also declares
"persist_without_export: bool = True") and change the annotation to "info:
Optional[dict]" while adding the required typing import (Optional) if it's not
already imported.

@Hrishabh17 Hrishabh17 merged commit 6ab1320 into master Jan 29, 2026
6 checks passed
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