Skip to content

Comments

feat: expose real-time exports and import with code for c1#1760

Open
ashwin1111 wants to merge 4 commits intomasterfrom
real-time-c1
Open

feat: expose real-time exports and import with code for c1#1760
ashwin1111 wants to merge 4 commits intomasterfrom
real-time-c1

Conversation

@ashwin1111
Copy link
Contributor

@ashwin1111 ashwin1111 commented Feb 23, 2026

Description

Please add PR description here, add screenshots if needed

Clickup

https://app.clickup.com/

Summary by CodeRabbit

  • Refactor

    • Removed branding feature flags that previously gated repurposed export summaries and import-code visibility; export summary behavior now depends on integration type and import-code UI appears based on available config or app name.
  • New Features

    • Added a configurable import-code workflow for Sage Intacct with UI controls and supporting translations.
  • Bug Fixes

    • Onboarding now consistently enables export scheduling and related defaults regardless of removed flags.

@github-actions github-actions bot added the size/S Small PR label Feb 23, 2026
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 23, 2026

Walkthrough

Removed two branding feature flags (dashboard.useRepurposedExportSummary, importSettings.allowImportCode) and updated configs, services, templates, and multiple advanced-settings/dashboard flows to rely on app-name checks or simpler onboarding/workspace conditions instead of those flags.

Changes

Cohort / File(s) Summary
Branding configs & model
src/app/branding/c1/branding-config.ts, src/app/branding/fyle/branding-config.ts, src/app/core/models/branding/feature-configuration.model.ts
Deleted importSettings.allowImportCode and dashboard.useRepurposedExportSummary from branding configs and the FeatureConfiguration model.
Accounting export service
src/app/core/services/common/accounting-export.service.ts
Removed useRepurposedExportSummary parameter from getAccountingExportSummary signature and eliminated conditional gating based on that flag.
Dashboard call sites
src/app/integrations/.../*-dashboard.component.ts
src/app/integrations/intacct/.../intacct-dashboard.component.ts, .../netsuite-dashboard.component.ts, .../qbd-direct-dashboard.component.ts, .../qbo-dashboard.component.ts, .../sage300-dashboard.component.ts, .../xero-dashboard.component.ts
Updated calls to use the new getAccountingExportSummary(version, appName) signature (removed feature-flag argument).
Export summary UI & logic
src/app/shared/components/dashboard/dashboard-export-summary-section/dashboard-export-summary-section.component.html, .../dashboard-export-summary-section.component.ts
Removed feature-flag gating; repurposed vs standard export summary selection now depends solely on appName membership in the allowed set (affects headers, metrics, timestamp selection).
Core advanced settings
src/app/core/services/common/advanced-settings.service.ts
Dropped dashboard feature-flag checks from getHoursOptions and getExportFrequency; real-time option and frequency logic no longer depend on the removed flag.
ERP advanced-settings services
src/app/core/services/.../netsuite-advanced-settings.service.ts, .../qbd-direct-advanced-settings.service.ts, .../qbo-advanced-settings.service.ts, .../sage300-advanced-settings.service.ts, .../xero-advanced-settings.service.ts
Simplified form-control defaults for schedule/exportSchedule to `workspace_schedules.enabled
Import-settings templates (allowImportCode removals)
src/app/integrations/intacct/.../intacct-import-settings.component.html, src/app/integrations/qbd-direct/.../qbd-direct-import-settings.component.html, src/app/integrations/qbo/.../qbo-clone-settings.component.html, src/app/integrations/qbo/.../qbo-import-settings.component.html
Removed brandingFeatureConfig.featureFlags.importSettings.allowImportCode checks; import-code UI blocks now render based on existing data/config presence only.
Shared import/config templates
src/app/shared/components/configuration/configuration-import-field/configuration-import-field.component.html, src/app/shared/components/helper/mapping/generic-mapping-table/.../generic-mapping-table.component.html
Dropped allowImportCode gating; import-code UI/display logic now depends on appName (SAGE300) or presence of value.code / multi-line option, not the feature flag.
Intacct C1 import-code feature
src/app/integrations/intacct/intacct-shared/intacct-c1-import-settings/intacct-c1-import-settings.component.ts, .../intacct-c1-import-settings.component.html, src/assets/i18n/en.json
Added a new import-code configuration workflow: new enum additions, ImportSettingsService usage, component fields/getters/methods (add/get form groups, initialize importCodeFields, handleImportCodeEnabled), template panel + formArray rendering, and i18n keys for the UI.
Misc
README.md
Whitespace/trailing newline formatting adjustment only.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 I hopped through flags both old and new,

Snipped two strings to clear the view,
Apps now follow names, not a switchy code,
Import paths sprout a brighter road,
A tiny cheer from this rabbit's pew! 🎉

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description is a placeholder template with no meaningful content about the changes, objectives, or testing approach. Only a generic ClickUp link is provided without context. Replace the placeholder with a detailed description including: what feature flags were removed and why, how real-time exports and import-with-code are now exposed, what C1-specific changes were made, and any testing performed.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'expose real-time exports and import with code for c1' clearly describes the main changes: enabling real-time exports and import-with-code functionality specifically for C1, which aligns with the substantial code additions and feature flag removals throughout the changeset.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch real-time-c1

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.

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

🧹 Nitpick comments (3)
src/app/core/services/common/advanced-settings.service.ts (1)

25-33: Unnecessary double-spread around the Real-time entry.

...[{ label: 'Real-time', value: 0 }] spreads a single-element array that was just constructed inline — it's equivalent to a plain object literal in this position.

♻️ Proposed cleanup
  static getHoursOptions(): SelectFormOption[] {
    return [
-     ...[{ label: 'Real-time', value: 0 }],
+     { label: 'Real-time', value: 0 },
      ...[...Array(24).keys()].map(hour => ({
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/app/core/services/common/advanced-settings.service.ts` around lines 25 -
33, The getHoursOptions function currently uses an unnecessary double-spread for
the "Real-time" entry (...[{ label: 'Real-time', value: 0 }]); remove the outer
spread and return the options as a single array where the Real-time object is
included directly before the spread of the hours array (e.g., include { label:
'Real-time', value: 0 } followed by ...[...Array(24).keys()].map(...) ) so the
output shape is unchanged but the redundant spread is eliminated.
src/app/core/services/common/accounting-export.service.ts (1)

272-287: Extract the allowlist to a named constant to reduce duplication.

The inline array [AppName.XERO, AppName.QBO, AppName.NETSUITE, AppName.INTACCT, AppName.QBD_DIRECT, AppName.SAGE300] is duplicated across the codebase in at least three locations:

  • src/app/core/services/common/accounting-export.service.ts:274
  • src/app/core/services/common/export-log.service.ts:87
  • src/app/shared/components/dashboard/dashboard-export-summary-section/dashboard-export-summary-section.component.ts:110, 115

A shared constant would make it easier to update when adding new apps and improve code maintainability. All current callers of getAccountingExportSummary() use the correct signature—no old-style three-argument calls remain.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/app/core/services/common/accounting-export.service.ts` around lines 272 -
287, Extract the inline app allowlist into a named exported constant (e.g.,
ALLOWED_EXPORT_START_DATE_APPS: AppName[]) and use that constant instead of the
inline array in getAccountingExportSummary (method in AccountingExportService);
then import and replace the same inline array usages in ExportLogService
(reference to its method using that array) and
DashboardExportSummarySectionComponent (both occurrences) so all three locations
reference the single exported constant and remove the duplicated literal arrays.
src/app/shared/components/dashboard/dashboard-export-summary-section/dashboard-export-summary-section.component.ts (1)

108-118: Extract the allowed-apps list into a single source of truth.

The list is duplicated across component logic and the template, which risks drift. Consider a readonly Set<AppName> + isRepurposedExportSummaryApp getter and reuse it in both TS and HTML.

♻️ Suggested refactor
+  private readonly repurposedExportApps = new Set<AppName>([
+    AppName.XERO,
+    AppName.QBO,
+    AppName.NETSUITE,
+    AppName.INTACCT,
+    AppName.QBD_DIRECT,
+    AppName.SAGE300
+  ]);
+
+  get isRepurposedExportSummaryApp(): boolean {
+    return this.repurposedExportApps.has(this.appName);
+  }
...
-        if ([AppName.XERO, AppName.QBO, AppName.NETSUITE, AppName.INTACCT, AppName.QBD_DIRECT, AppName.SAGE300].includes(this.appName)) {
+        if (this.isRepurposedExportSummaryApp) {
           lastExportedAt = this.accountingExportSummary.repurposed_last_exported_at;
         } else {
           lastExportedAt = this.accountingExportSummary.last_exported_at;
         }
-      } else if (status === AccountingExportStatus.FAILED && [AppName.XERO, AppName.QBO, AppName.NETSUITE, AppName.INTACCT, AppName.QBD_DIRECT, AppName.SAGE300].includes(this.appName)) {
+      } else if (status === AccountingExportStatus.FAILED && this.isRepurposedExportSummaryApp) {
         lastUpdatedAt = this.accountingExportSummary.repurposed_last_exported_at;
       }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/app/shared/components/dashboard/dashboard-export-summary-section/dashboard-export-summary-section.component.ts`
around lines 108 - 118, The duplicated allowed-apps array should be centralized:
add a readonly Set<AppName> (e.g., repurposedExportApps) and an
isRepurposedExportSummaryApp getter on the
DashboardExportSummarySectionComponent that returns
repurposedExportApps.has(this.appName); update the TS logic (replace the inline
array checks in the block that sets lastExportedAt/lastUpdatedAt) to call
isRepurposedExportSummaryApp, and update the component template to use the same
getter instead of repeating the literal list so both template and class share a
single source of truth.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@src/app/shared/components/dashboard/dashboard-export-summary-section/dashboard-export-summary-section.component.html`:
- Line 5: The header currently uses literal user-facing strings; replace them
with Transloco translations by using the transloco pipe for the two branches
instead of raw text. In the h4 that references appName and AppName (in
dashboard-export-summary-section.component.html), change the conditional text to
use translation keys (e.g. "dashboard.exportOverview" and
"dashboard.yourLastExport") and pipe them through Transloco (e.g. {{
'dashboard.exportOverview' | transloco }} or via property binding like
[innerText]="('dashboard.exportOverview' | transloco)"), preserving the existing
conditional that checks [AppName.XERO, AppName.QBO, ...]. Ensure both branches
use the transloco pipe and update translation files with the new keys.

---

Nitpick comments:
In `@src/app/core/services/common/accounting-export.service.ts`:
- Around line 272-287: Extract the inline app allowlist into a named exported
constant (e.g., ALLOWED_EXPORT_START_DATE_APPS: AppName[]) and use that constant
instead of the inline array in getAccountingExportSummary (method in
AccountingExportService); then import and replace the same inline array usages
in ExportLogService (reference to its method using that array) and
DashboardExportSummarySectionComponent (both occurrences) so all three locations
reference the single exported constant and remove the duplicated literal arrays.

In `@src/app/core/services/common/advanced-settings.service.ts`:
- Around line 25-33: The getHoursOptions function currently uses an unnecessary
double-spread for the "Real-time" entry (...[{ label: 'Real-time', value: 0 }]);
remove the outer spread and return the options as a single array where the
Real-time object is included directly before the spread of the hours array
(e.g., include { label: 'Real-time', value: 0 } followed by
...[...Array(24).keys()].map(...) ) so the output shape is unchanged but the
redundant spread is eliminated.

In
`@src/app/shared/components/dashboard/dashboard-export-summary-section/dashboard-export-summary-section.component.ts`:
- Around line 108-118: The duplicated allowed-apps array should be centralized:
add a readonly Set<AppName> (e.g., repurposedExportApps) and an
isRepurposedExportSummaryApp getter on the
DashboardExportSummarySectionComponent that returns
repurposedExportApps.has(this.appName); update the TS logic (replace the inline
array checks in the block that sets lastExportedAt/lastUpdatedAt) to call
isRepurposedExportSummaryApp, and update the component template to use the same
getter instead of repeating the literal list so both template and class share a
single source of truth.
ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1417032 and 84ef140.

📒 Files selected for processing (19)
  • src/app/branding/c1/branding-config.ts
  • src/app/branding/fyle/branding-config.ts
  • src/app/core/models/branding/feature-configuration.model.ts
  • src/app/core/services/common/accounting-export.service.ts
  • src/app/core/services/common/advanced-settings.service.ts
  • src/app/core/services/netsuite/netsuite-configuration/netsuite-advanced-settings.service.ts
  • src/app/core/services/qbd-direct/qbd-direct-configuration/qbd-direct-advanced-settings.service.ts
  • src/app/core/services/qbo/qbo-configuration/qbo-advanced-settings.service.ts
  • src/app/core/services/sage300/sage300-configuration/sage300-advanced-settings.service.ts
  • src/app/core/services/xero/xero-configuration/xero-advanced-settings.service.ts
  • src/app/integrations/intacct/intacct-main/intacct-dashboard/intacct-dashboard.component.ts
  • src/app/integrations/intacct/intacct-shared/intacct-advanced-settings/intacct-advanced-settings.component.ts
  • src/app/integrations/netsuite/netsuite-main/netsuite-dashboard/netsuite-dashboard.component.ts
  • src/app/integrations/qbd-direct/qbd-direct-main/qbd-direct-dashboard/qbd-direct-dashboard.component.ts
  • src/app/integrations/qbo/qbo-main/qbo-dashboard/qbo-dashboard.component.ts
  • src/app/integrations/sage300/sage300-main/sage300-dashboard/sage300-dashboard.component.ts
  • src/app/integrations/xero/xero-main/xero-dashboard/xero-dashboard.component.ts
  • src/app/shared/components/dashboard/dashboard-export-summary-section/dashboard-export-summary-section.component.html
  • src/app/shared/components/dashboard/dashboard-export-summary-section/dashboard-export-summary-section.component.ts
💤 Files with no reviewable changes (3)
  • src/app/branding/c1/branding-config.ts
  • src/app/core/models/branding/feature-configuration.model.ts
  • src/app/branding/fyle/branding-config.ts

@github-actions github-actions bot added size/M Medium PR and removed size/S Small PR labels Feb 23, 2026
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

♻️ Duplicate comments (1)
src/app/shared/components/dashboard/dashboard-export-summary-section/dashboard-export-summary-section.component.html (1)

5-11: Transloco header keys addressed — LGTM.

dashboardExportSummarySection.todaysExportOverview and dashboardExportSummarySection.yourLastExport correctly follow the i18n naming convention (top-level key = camelCase component folder name, semantic sub-keys). This resolves the previous review comment.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/app/shared/components/dashboard/dashboard-export-summary-section/dashboard-export-summary-section.component.html`
around lines 5 - 11, The transloco keys used in the dashboard header are correct
and require no changes: leave the conditional header binding in
DashboardExportSummarySectionComponent (the h4 that checks [AppName.XERO,
AppName.QBO, AppName.NETSUITE, AppName.INTACCT, AppName.QBD_DIRECT,
AppName.SAGE300].includes(appName) and uses
'dashboardExportSummarySection.todaysExportOverview' or
'dashboardExportSummarySection.yourLastExport') as-is; no code updates are
needed other than keeping the existing transloco keys and their usage intact.
🧹 Nitpick comments (3)
src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-import-settings/qbd-direct-import-settings.component.html (1)

69-69: [isDisabled] is a dead expression — always false inside this @if block.

The parent @if on line 56 already asserts QbdDirectImportCodeFieldCodeConfig[DefaultImportFields.ACCOUNT] to be truthy, so !QbdDirectImportCodeFieldCodeConfig[DefaultImportFields.ACCOUNT] can never be true here. Consider simplifying to [isDisabled]="false" or removing the binding entirely if false is the default.

♻️ Proposed simplification
-  [isDisabled]="!QbdDirectImportCodeFieldCodeConfig[DefaultImportFields.ACCOUNT]"

(Remove the binding; isDisabled defaults to false in app-configuration-select-field.)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-import-settings/qbd-direct-import-settings.component.html`
at line 69, The template binding
[isDisabled]="!QbdDirectImportCodeFieldCodeConfig[DefaultImportFields.ACCOUNT]"
is redundant because an enclosing `@if` already guarantees
QbdDirectImportCodeFieldCodeConfig[DefaultImportFields.ACCOUNT] is truthy;
remove the dead expression by deleting the [isDisabled] attribute (or replace it
with [isDisabled]="false" if explicitness is desired) on the
app-configuration-select-field to leave isDisabled at its default false state
and reference QbdDirectImportCodeFieldCodeConfig, DefaultImportFields.ACCOUNT
and the isDisabled input to locate the element to change.
src/app/shared/components/configuration/configuration-import-field/configuration-import-field.component.html (1)

276-327: Redundant inner @if — remove the extra nesting level.

The outer block at line 254 already guarantees uiExposedAppName === AppName.SAGE300, so the inner @if (uiExposedAppName === AppName.SAGE300) at line 276 is always true and can never gate anything. Before this PR the inner condition included the allowImportCode flag, which provided an independent gate; now only the app-name check remains, making it a no-op that only adds indentation.

♻️ Proposed fix
-      `@if` (uiExposedAppName === AppName.SAGE300) {
-        <div>
-          `@for` (defaultField of defaultImportFields; ...
-          ...
-          <div formArrayName="expenseFields">
-            ...
-          </div>
-        </div>
-      }
+      <div>
+        `@for` (defaultField of defaultImportFields; ...
+        ...
+        <div formArrayName="expenseFields">
+          ...
+        </div>
+      </div>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/app/shared/components/configuration/configuration-import-field/configuration-import-field.component.html`
around lines 276 - 327, Remove the redundant inner "@if (uiExposedAppName ===
AppName.SAGE300)" block around the defaultImportFields/expenseFields rendering
in configuration-import-field.component.html: locate the inner conditional that
currently wraps the defaultImportFields loop and the <div
formArrayName="expenseFields"> section and delete that `@if` and its extra wrapper
div so the content directly lives under the existing outer app-name check;
ensure you keep all existing bindings (defaultImportFields,
defaultField.import_code, importCodeFieldConfig, getImportCodeSelectorOptions,
expenseFieldsGetter, showImportCodeSection, getFormGroup, getImportSubLabel,
etc.) and preserve the original logic and indentation for those elements.
src/app/shared/components/dashboard/dashboard-export-summary-section/dashboard-export-summary-section.component.html (1)

7-7: Inline array literal duplicated 4× — extract to a component property.

[AppName.XERO, AppName.QBO, AppName.NETSUITE, AppName.INTACCT, AppName.QBD_DIRECT, AppName.SAGE300] is copy-pasted at lines 7, 22, 38, and 55. Adding or removing an app from this set will require four synchronised edits, making it a maintenance hazard.

Declare a single readonly property in the component class and reference it in the template:

♻️ Proposed fix

In the component .ts file:

+  readonly repurposedExportSummaryApps = [
+    AppName.XERO, AppName.QBO, AppName.NETSUITE,
+    AppName.INTACCT, AppName.QBD_DIRECT, AppName.SAGE300,
+  ] as const;

In the template (apply to all 4 occurrences):

-[AppName.XERO, AppName.QBO, AppName.NETSUITE, AppName.INTACCT, AppName.QBD_DIRECT, AppName.SAGE300].includes(appName)
+repurposedExportSummaryApps.includes(appName)

Also applies to: 22-22, 38-38, 55-55

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/app/shared/components/dashboard/dashboard-export-summary-section/dashboard-export-summary-section.component.html`
at line 7, The template repeats the same inline array of AppName values in
multiple places; add a single readonly array property on the
DashboardExportSummarySectionComponent (e.g. supportedApps or
SUPPORTED_EXPORT_APPS) containing [AppName.XERO, AppName.QBO, AppName.NETSUITE,
AppName.INTACCT, AppName.QBD_DIRECT, AppName.SAGE300] and replace all four
template expressions with supportedApps.includes(appName) so future changes are
made in one place; update the component class (constructor or as a top-level
readonly field) and change each template occurrence to reference that property.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@src/app/integrations/intacct/intacct-shared/intacct-import-settings/intacct-import-settings.component.html`:
- Line 287: In the template condition referencing importSettingsForm, remove the
unnecessary "this." and make the length access null-safe; change the check using
importSettingsForm.get('importCodeFields') to use optional chaining for both
value and length (e.g.,
importSettingsForm.get('importCodeFields')?.value?.length > 0) so the form
control and its value are guarded, targeting the importSettingsForm and the
'importCodeFields' control in the template.

---

Duplicate comments:
In
`@src/app/shared/components/dashboard/dashboard-export-summary-section/dashboard-export-summary-section.component.html`:
- Around line 5-11: The transloco keys used in the dashboard header are correct
and require no changes: leave the conditional header binding in
DashboardExportSummarySectionComponent (the h4 that checks [AppName.XERO,
AppName.QBO, AppName.NETSUITE, AppName.INTACCT, AppName.QBD_DIRECT,
AppName.SAGE300].includes(appName) and uses
'dashboardExportSummarySection.todaysExportOverview' or
'dashboardExportSummarySection.yourLastExport') as-is; no code updates are
needed other than keeping the existing transloco keys and their usage intact.

---

Nitpick comments:
In
`@src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-import-settings/qbd-direct-import-settings.component.html`:
- Line 69: The template binding
[isDisabled]="!QbdDirectImportCodeFieldCodeConfig[DefaultImportFields.ACCOUNT]"
is redundant because an enclosing `@if` already guarantees
QbdDirectImportCodeFieldCodeConfig[DefaultImportFields.ACCOUNT] is truthy;
remove the dead expression by deleting the [isDisabled] attribute (or replace it
with [isDisabled]="false" if explicitness is desired) on the
app-configuration-select-field to leave isDisabled at its default false state
and reference QbdDirectImportCodeFieldCodeConfig, DefaultImportFields.ACCOUNT
and the isDisabled input to locate the element to change.

In
`@src/app/shared/components/configuration/configuration-import-field/configuration-import-field.component.html`:
- Around line 276-327: Remove the redundant inner "@if (uiExposedAppName ===
AppName.SAGE300)" block around the defaultImportFields/expenseFields rendering
in configuration-import-field.component.html: locate the inner conditional that
currently wraps the defaultImportFields loop and the <div
formArrayName="expenseFields"> section and delete that `@if` and its extra wrapper
div so the content directly lives under the existing outer app-name check;
ensure you keep all existing bindings (defaultImportFields,
defaultField.import_code, importCodeFieldConfig, getImportCodeSelectorOptions,
expenseFieldsGetter, showImportCodeSection, getFormGroup, getImportSubLabel,
etc.) and preserve the original logic and indentation for those elements.

In
`@src/app/shared/components/dashboard/dashboard-export-summary-section/dashboard-export-summary-section.component.html`:
- Line 7: The template repeats the same inline array of AppName values in
multiple places; add a single readonly array property on the
DashboardExportSummarySectionComponent (e.g. supportedApps or
SUPPORTED_EXPORT_APPS) containing [AppName.XERO, AppName.QBO, AppName.NETSUITE,
AppName.INTACCT, AppName.QBD_DIRECT, AppName.SAGE300] and replace all four
template expressions with supportedApps.includes(appName) so future changes are
made in one place; update the component class (constructor or as a top-level
readonly field) and change each template occurrence to reference that property.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 84ef140 and da28510.

📒 Files selected for processing (11)
  • src/app/branding/c1/branding-config.ts
  • src/app/branding/fyle/branding-config.ts
  • src/app/core/models/branding/feature-configuration.model.ts
  • src/app/core/services/common/advanced-settings.service.ts
  • src/app/integrations/intacct/intacct-shared/intacct-import-settings/intacct-import-settings.component.html
  • src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-import-settings/qbd-direct-import-settings.component.html
  • src/app/integrations/qbo/qbo-onboarding/qbo-clone-settings/qbo-clone-settings.component.html
  • src/app/integrations/qbo/qbo-shared/qbo-import-settings/qbo-import-settings.component.html
  • src/app/shared/components/configuration/configuration-import-field/configuration-import-field.component.html
  • src/app/shared/components/dashboard/dashboard-export-summary-section/dashboard-export-summary-section.component.html
  • src/app/shared/components/helper/mapping/generic-mapping-table/generic-mapping-table.component.html
💤 Files with no reviewable changes (3)
  • src/app/core/models/branding/feature-configuration.model.ts
  • src/app/branding/c1/branding-config.ts
  • src/app/branding/fyle/branding-config.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/app/core/services/common/advanced-settings.service.ts

}
</div>
@if (brandingFeatureConfig.featureFlags.importSettings.allowImportCode && this.importSettingsForm.get('importCodeFields')?.value.length > 0 ) {
@if (this.importSettingsForm.get('importCodeFields')?.value.length > 0 ) {
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

Remove this. and add null-safe chaining on .length.

Two issues in the condition:

  1. this. in template — Angular templates never need the this. prefix; every other importSettingsForm reference in this file (lines 17, 49, 118, 200, 221, 272, etc.) omits it. This is inconsistent.
  2. Unsafe .length access?. only guards .value against a null control reference; if the control is absent, .value short-circuits to undefined and the subsequent .length access throws a TypeError. Add a second ?. before .length.
🛡️ Proposed fix
-          `@if` (this.importSettingsForm.get('importCodeFields')?.value.length > 0 ) {
+          `@if` (importSettingsForm.get('importCodeFields')?.value?.length > 0) {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@if (this.importSettingsForm.get('importCodeFields')?.value.length > 0 ) {
`@if` (importSettingsForm.get('importCodeFields')?.value?.length > 0) {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/app/integrations/intacct/intacct-shared/intacct-import-settings/intacct-import-settings.component.html`
at line 287, In the template condition referencing importSettingsForm, remove
the unnecessary "this." and make the length access null-safe; change the check
using importSettingsForm.get('importCodeFields') to use optional chaining for
both value and length (e.g.,
importSettingsForm.get('importCodeFields')?.value?.length > 0) so the form
control and its value are guarded, targeting the importSettingsForm and the
'importCodeFields' control in the template.

@ashwin1111 ashwin1111 changed the title feat: expose real-time exports for c1 feat: expose real-time exports and import with code for c1 Feb 23, 2026
@ashwin1111 ashwin1111 added the c1_staging_deploy Deploys to c1 staging label Feb 23, 2026
@ashwin1111 ashwin1111 added c1_staging_deploy Deploys to c1 staging and removed c1_staging_deploy Deploys to c1 staging labels Feb 23, 2026
@github-actions github-actions bot added size/L Large PR and removed size/M Medium PR labels Feb 24, 2026
@github-actions
Copy link

🔁 Code Duplication Report - Angular

Format Files analyzed Total lines Total tokens Clones found Duplicated lines Duplicated tokens
typescript 786 58544 536245 351 5798 (9.90%) +0.04% ❗ 54514 (10.17%) +0.07% ❗
scss 68 3795 20521 7 148 (3.90%) 769 (3.75%)
markup 352 17851 167244 158 2105 (11.79%) -0.04% 🚀 17750 (10.61%) -0.02% 🚀
python 4 727 5680 3 32 (4.40%) 368 (6.48%)
yaml 3 155 905 0 0 (0.00%) 0 (0.00%)
javascript 6 397 3497 0 0 (0.00%) 0 (0.00%)
markdown 2 96 366 0 0 (0.00%) 0 (0.00%)
bash 2 69 804 0 0 (0.00%) 0 (0.00%)
Total: 1223 81634 735262 519 8083 (9.90%) +0.02% ❗ 73401 (9.98%) +0.04% ❗

⚠️ This PR introduces 0.04% more duplicated code.

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

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@src/app/integrations/intacct/intacct-shared/intacct-c1-import-settings/intacct-c1-import-settings.component.ts`:
- Around line 179-201: The import payload is being built from two unsynchronized
sources (the legacy importCodeField control and the new importCodeFields
FormArray), so remove the legacy control usage and make the payload builder
derive import-code entries exclusively from the importCodeFields FormArray;
update addImportCodeField (and any initialization) to only add/remove entries
from this.importSettingsForm.get('importCodeFields') and remove/stop
initializing the legacy importCodeField control, and modify the payload
construction in the import-settings.model (the function that currently
concatenates importCodeField and importCodeFields) to read and map values solely
from the importCodeFields FormArray so user changes are reflected correctly.

In `@src/assets/i18n/en.json`:
- Around line 893-908: The i18n child keys under intacctC1ImportSettings are out
of alphabetical order; reorder the keys (for example the entries like
"category", "configureImportMethodTitle", "configureImportMethodDescription",
"exampleCodesAndNamesConstruction", "exampleCodesAndNamesFinance",
"exampleCodesAndNamesMeals", "exampleNamesOnlyConstruction",
"exampleNamesOnlyFinance", "exampleNamesOnlyMeals", "howToImportLabel",
"howToImportSubLabel", "importCodesAndNames", "importNamesOnly",
"oneTimeSetupNote", "selectImportMethodError", "selectImportMethodPlaceholder")
into strict alphabetical order within the intacctC1ImportSettings object in
src/assets/i18n/en.json so the child keys are sorted to reduce future merge
conflicts.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c30eb73 and 6216f55.

📒 Files selected for processing (3)
  • src/app/integrations/intacct/intacct-shared/intacct-c1-import-settings/intacct-c1-import-settings.component.html
  • src/app/integrations/intacct/intacct-shared/intacct-c1-import-settings/intacct-c1-import-settings.component.ts
  • src/assets/i18n/en.json

Comment on lines +179 to +201
addImportCodeField(event: any, sourceField: string): void {
const importCodeFieldsArray = this.importSettingsForm.get('importCodeFields') as FormArray;

if (sourceField === IntacctCategoryDestination.GL_ACCOUNT || sourceField === 'GENERAL_LEDGER_ACCOUNT') {
sourceField = IntacctCategoryDestination.ACCOUNT;
}

const index = importCodeFieldsArray.controls.findIndex(control => control?.get('source_field')?.value === sourceField);

if (event.checked) {
if (this.acceptedImportCodeField.includes(sourceField) && this.intacctImportCodeConfig[sourceField] && index === -1) {
const value = this.formBuilder.group({
source_field: [sourceField],
import_code: [this.importSettingsService.getImportCodeField(this.importSettings!.configurations.import_code_fields, sourceField, this.intacctImportCodeConfig), Validators.required]
});
importCodeFieldsArray.push(value);
}
} else {
if (index !== -1) {
importCodeFieldsArray.removeAt(index);
}
}
}
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:

#!/bin/bash
# Inspect payload construction and where import_code_fields is sourced
rg -n --type=ts "constructPayload" src/app/core/models/intacct/intacct-configuration
rg -n --type=ts "importCodeFields|importCodeField|import_code_fields" src/app

Repository: fylein/fyle-integrations-app

Length of output: 29537


🏁 Script executed:

sed -n '130,155p' src/app/core/models/intacct/intacct-configuration/import-settings.model.ts

Repository: fylein/fyle-integrations-app

Length of output: 1775


Resolve conflicting sources in import-code payload construction.

The payload builder reads and merges two unsynchronized controls: the legacy importCodeField (initialized once, never updated) and the new importCodeFields FormArray (mutated by addImportCodeField). Line 140 in import-settings.model.ts concatenates both, causing initial values to persist in the payload even after user modifications. Refactor to use importCodeFields FormArray alone, remove the legacy control, and adjust the payload logic accordingly.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/app/integrations/intacct/intacct-shared/intacct-c1-import-settings/intacct-c1-import-settings.component.ts`
around lines 179 - 201, The import payload is being built from two
unsynchronized sources (the legacy importCodeField control and the new
importCodeFields FormArray), so remove the legacy control usage and make the
payload builder derive import-code entries exclusively from the importCodeFields
FormArray; update addImportCodeField (and any initialization) to only add/remove
entries from this.importSettingsForm.get('importCodeFields') and remove/stop
initializing the legacy importCodeField control, and modify the payload
construction in the import-settings.model (the function that currently
concatenates importCodeField and importCodeFields) to read and map values solely
from the importCodeFields FormArray so user changes are reflected correctly.

Comment on lines +893 to +908
"category": "Category",
"configureImportMethodTitle": "Configure import method",
"configureImportMethodDescription": "You have the option to import either just the names of your values or both names and code, based on how your employees identify these values.",
"oneTimeSetupNote": "This is a one-time setup and cannot be modified once the values are imported to {{brandName}}.",
"selectImportMethodPlaceholder": "Select how to import {{field}}",
"howToImportLabel": "How to import the {{field}} from {{appName}}?",
"howToImportSubLabel": "You have the option to import either just the names of your {{field}} or both the names and codes.",
"selectImportMethodError": "Please select how the {{field}} should be imported",
"importCodesAndNames": "Import codes + names",
"importNamesOnly": "Import names only",
"exampleCodesAndNamesMeals": "Example: 4567: Meals & Entertainment",
"exampleNamesOnlyMeals": "Example: Meals & Entertainment",
"exampleCodesAndNamesFinance": "Example: 24: Finance",
"exampleNamesOnlyFinance": "Example: Finance",
"exampleCodesAndNamesConstruction": "Example: 12-00-201: PCL Construction",
"exampleNamesOnlyConstruction": "Example: PCL Construction"
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:

#!/bin/bash
# 1. Check the new keys and their alphabetical order in en.json
# 2. Verify presence in other locale files

python - <<'PY'
import json
from pathlib import Path

# Load en.json
en_path = Path("src/assets/i18n/en.json")
en_data = json.load(en_path.open())
intacct_keys = en_data.get("intacctC1ImportSettings", {})

# Check alphabetical ordering
keys_list = list(intacct_keys.keys())
sorted_keys = sorted(keys_list)
is_sorted = keys_list == sorted_keys

print("=== en.json intacctC1ImportSettings ===")
print(f"Keys in order: {keys_list}")
print(f"Alphabetically sorted: {is_sorted}")
if not is_sorted:
    print(f"Should be: {sorted_keys}")

# Check other locale files
print("\n=== Checking other locales ===")
en_keys = set(intacct_keys.keys())
locales = {}

for path in sorted(Path("src/assets/i18n").glob("*.json")):
    if path.name == "en.json":
        continue
    try:
        data = json.load(path.open())
        other_keys = set(data.get("intacctC1ImportSettings", {}).keys())
        missing = sorted(en_keys - other_keys)
        locales[path.name] = {
            "has_section": "intacctC1ImportSettings" in data,
            "missing_keys": missing if missing else []
        }
    except Exception as e:
        locales[path.name] = {"error": str(e)}

for locale, info in locales.items():
    if "error" in info:
        print(f"{locale}: ERROR - {info['error']}")
    else:
        status = "✓ complete" if not info["missing_keys"] and info["has_section"] else "✗ incomplete"
        print(f"{locale}: {status}", end="")
        if info["missing_keys"]:
            print(f" - missing: {info['missing_keys']}")
        else:
            print()
PY

Repository: fylein/fyle-integrations-app

Length of output: 1558


🏁 Script executed:

#!/bin/bash
# Check what locale files exist and their intacctC1ImportSettings sections

cd src/assets/i18n
echo "=== Available locale files ==="
ls -la *.json

echo -e "\n=== Checking intacctC1ImportSettings presence ==="
for file in *.json; do
    if grep -q '"intacctC1ImportSettings"' "$file"; then
        echo "$file: ✓ has section"
    else
        echo "$file: ✗ missing section"
    fi
done

echo -e "\n=== Key count comparison ==="
python - <<'PY'
import json
from pathlib import Path

for path in sorted(Path(".").glob("*.json")):
    data = json.load(path.open())
    count = len(data.get("intacctC1ImportSettings", {}))
    print(f"{path.name}: {count} keys")
PY

Repository: fylein/fyle-integrations-app

Length of output: 282


Alphabetize intacctC1ImportSettings keys in en.json.

The new keys added to intacctC1ImportSettings are not alphabetically sorted. Reorder them alphabetically to comply with the coding guideline: "Keep i18n child keys alphabetically sorted to reduce merge conflicts."

Note: Other locale files (es.json, etc.) do not currently exist in the repository, so propagation to additional locales is not applicable at this time. When additional locale files are introduced, ensure they include the same keys.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/assets/i18n/en.json` around lines 893 - 908, The i18n child keys under
intacctC1ImportSettings are out of alphabetical order; reorder the keys (for
example the entries like "category", "configureImportMethodTitle",
"configureImportMethodDescription", "exampleCodesAndNamesConstruction",
"exampleCodesAndNamesFinance", "exampleCodesAndNamesMeals",
"exampleNamesOnlyConstruction", "exampleNamesOnlyFinance",
"exampleNamesOnlyMeals", "howToImportLabel", "howToImportSubLabel",
"importCodesAndNames", "importNamesOnly", "oneTimeSetupNote",
"selectImportMethodError", "selectImportMethodPlaceholder") into strict
alphabetical order within the intacctC1ImportSettings object in
src/assets/i18n/en.json so the child keys are sorted to reduce future merge
conflicts.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

c1_staging_deploy Deploys to c1 staging size/L Large PR

Development

Successfully merging this pull request may close these issues.

2 participants