Skip to content

Commit

Permalink
Merge branch 'form-value-fix' into form-value-fix-2
Browse files Browse the repository at this point in the history
  • Loading branch information
DhaaraniCIT committed Sep 24, 2024
2 parents a49650f + f663ea5 commit 13a33b5
Show file tree
Hide file tree
Showing 20 changed files with 227 additions and 58 deletions.
10 changes: 10 additions & 0 deletions .github/pr-checks-config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
pr_checks:
title:
- name: 'prefix_check'
regex: '^(?i)(fix|feat|test|chore|refactor|build):'
message_if_not_matching: 'PR title must start with "fix:", "feat:", "chore:", "refactor", or "test:" (case-insensitive)'

description:
- name: 'clickup_check'
regex: '(?i)app.clickup.com'
message_if_not_matching: 'PR description must contain a link to a ClickUp (case-insensitive)'
5 changes: 5 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
### Description
Please add PR description here, add screenshots if needed

## Clickup
Please add link here
File renamed without changes.
File renamed without changes.
20 changes: 20 additions & 0 deletions .github/workflows/pr-checks.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@

name: Strong PR Checks

on:
pull_request:
types: [opened, synchronize, edited]

permissions:
pull-requests: write
contents: read

jobs:
pr_checks:
runs-on: ubuntu-latest
steps:
- name: Run strong checks
uses: fylein/fyle-pr-action@v1
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
config-file: .github/pr-checks-config.yml
21 changes: 21 additions & 0 deletions .github/workflows/pr-size.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
name: Pull Request Labeling

on: [pull_request]

jobs:
size:
runs-on: ubuntu-latest
name: Label the PR size
steps:
- uses: "pascalgn/[email protected]"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
sizes: >
{
"0": "XS",
"20": "S",
"50": "M",
"250": "L",
"800": "XL"
}
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
[destinationFieldMap]="destinationFieldMap"
[isCategoryMappingGeneric]="false"
[destinationOptionsVersion]="'v1'"
[importCodeFields]="acceptedCodeField"
[errorsVersion]="'v1'">
</app-dashboard-error-section>
</div>
Original file line number Diff line number Diff line change
@@ -1,18 +1,13 @@
import { Component, OnInit } from '@angular/core';
import { Observable, catchError, forkJoin, from, interval, map, of, switchMap, takeWhile } from 'rxjs';
import { Observable, catchError, forkJoin, from, interval, of, switchMap, takeWhile } from 'rxjs';
import { brandingConfig, brandingFeatureConfig } from 'src/app/branding/branding-config';
import { AccountingErrorType, AppName, AppUrl, CCCImportState, ClickEvent, ExpenseState, ExportState, FyleField, FyleReferenceType, IntacctCategoryDestination, IntacctCorporateCreditCardExpensesObject, IntacctErrorType, IntacctReimbursableExpensesObject, RefinerSurveyType, ReimbursableImportState, TaskLogState, TaskLogType, TrackingApp } from 'src/app/core/models/enum/enum.model';
import { ExpenseGroupSetting } from 'src/app/core/models/db/expense-group-setting.model';
import { ExpenseGroup, ExpenseGroupList, ExportableExpenseGroup } from 'src/app/core/models/intacct/db/expense-group.model';
import { AccountingErrorType, AppName, AppUrl, CCCImportState, ExpenseState, ExportState, FyleReferenceType, IntacctCategoryDestination, IntacctCorporateCreditCardExpensesObject, IntacctErrorType, IntacctReimbursableExpensesObject, MappingSourceField, ReimbursableImportState, SageIntacctField, TaskLogState, TaskLogType } from 'src/app/core/models/enum/enum.model';
import { ExpenseGroupList } from 'src/app/core/models/intacct/db/expense-group.model';
import { Expense } from 'src/app/core/models/intacct/db/expense.model';
import { LastExport } from 'src/app/core/models/intacct/db/last-export.model';
import { IntacctTaskLog, IntacctTaskResponse } from 'src/app/core/models/intacct/db/task-log.model';
import { RefinerService } from 'src/app/core/services/integration/refiner.service';
import { TrackingService } from 'src/app/core/services/integration/tracking.service';
import { UserService } from 'src/app/core/services/misc/user.service';
import { ExportLogService } from 'src/app/core/services/si/export-log/export-log.service';
import { SiWorkspaceService } from 'src/app/core/services/si/si-core/si-workspace.service';
import { environment } from 'src/environments/environment';
import { AccountingExportSummary, AccountingExportSummaryModel } from 'src/app/core/models/db/accounting-export-summary.model';
import { AccountingGroupedErrorStat, AccountingGroupedErrors, Error } from 'src/app/core/models/db/error.model';
import { DashboardModel, DestinationFieldMap } from 'src/app/core/models/db/dashboard.model';
Expand Down Expand Up @@ -91,6 +86,8 @@ export class IntacctDashboardComponent implements OnInit {

destinationFieldMap : DestinationFieldMap;

acceptedCodeField: string[] = [SageIntacctField.ACCOUNT, SageIntacctField.DEPARTMENT, MappingSourceField.PROJECT, IntacctCategoryDestination.EXPENSE_TYPE];

readonly dummyExpenseGroupList: ExpenseGroupList[] = [{
index: 0,
exportedAt: new Date(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export class IntacctBaseMappingComponent implements OnInit {

cccExpenseObject: IntacctCorporateCreditCardExpensesObject | null;

acceptedCodeField: string[] = [SageIntacctField.ACCOUNT, SageIntacctField.DEPARTMENT, MappingSourceField.PROJECT];
acceptedCodeField: string[] = [SageIntacctField.ACCOUNT, SageIntacctField.DEPARTMENT, MappingSourceField.PROJECT, IntacctCategoryDestination.EXPENSE_TYPE];

brandingConfig = brandingConfig;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -435,7 +435,9 @@ export class IntacctC1ImportSettingsComponent implements OnInit {
costTypes: [importSettings.dependent_field_settings?.cost_type_field_name ? this.dependentFieldFormValue(importSettings.dependent_field_settings.cost_type_field_name, importSettings.dependent_field_settings.cost_type_placeholder, 'costTypes') : null],
isDependentImportEnabled: [importSettings.dependent_field_settings?.is_import_enabled || false],
sageIntacctTaxCodes: [importSettings.general_mappings.default_tax_code.id || null],
expenseFields: this.formBuilder.array(this.constructFormArray())
expenseFields: this.formBuilder.array(this.constructFormArray()),
importCodeField: [importSettings.configurations.import_code_fields],
importCodeFields: this.formBuilder.array([])
});

this.importSettingWatcher();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,10 @@ import { Component, Inject, OnInit } from '@angular/core';
import { AbstractControl, FormArray, FormBuilder, FormGroup, Validators } from '@angular/forms';
import { Router } from '@angular/router';
import { RxwebValidators } from '@rxweb/reactive-form-validators';
import { InputSwitchChangeEvent } from 'primeng/inputswitch';
import { forkJoin } from 'rxjs';
import { brandingConfig, brandingFeatureConfig, brandingKbArticles } from 'src/app/branding/branding-config';
import { ImportSettingsModel } from 'src/app/core/models/common/import-settings.model';
import { IntacctCategoryDestination, ConfigurationCta, IntacctOnboardingState, IntacctUpdateEvent, Page, ProgressPhase, ToastSeverity, MappingSourceField, AppName, TrackingApp, DefaultImportFields, SageIntacctField } from 'src/app/core/models/enum/enum.model';
import { IntacctCategoryDestination, ConfigurationCta, IntacctOnboardingState, IntacctUpdateEvent, Page, ProgressPhase, ToastSeverity, MappingSourceField, AppName, TrackingApp, SageIntacctField, IntacctReimbursableExpensesObject, IntacctCorporateCreditCardExpensesObject } from 'src/app/core/models/enum/enum.model';
import { IntacctDestinationAttribute } from 'src/app/core/models/intacct/db/destination-attribute.model';
import { ExpenseField } from 'src/app/core/models/intacct/db/expense-field.model';
import { LocationEntityMapping } from 'src/app/core/models/intacct/db/location-entity-mapping.model';
Expand Down Expand Up @@ -260,7 +259,7 @@ export class IntacctImportSettingsComponent implements OnInit {
const defaultFieldData: MappingSetting = {
source_field: '',
destination_field: '',
import_to_fyle: true,
import_to_fyle: false,
is_custom: false,
source_placeholder: null
};
Expand Down Expand Up @@ -299,6 +298,7 @@ export class IntacctImportSettingsComponent implements OnInit {
this.customFieldControl.disable();
this.customFieldForDependentField = false;
} else {
this.addImportCodeField({checked: true}, this.customFieldControl.get('destination_field')?.value);
this.customField = {
attribute_type: this.customFieldForm.get('attribute_type')?.value.split(' ').join('_').toUpperCase(),
display_name: this.customFieldForm.get('attribute_type')?.value,
Expand Down Expand Up @@ -506,6 +506,9 @@ export class IntacctImportSettingsComponent implements OnInit {

// Get the 'import_to_fyle' control at the specified index and disable it
(this.importSettingsForm.get('expenseFields') as FormArray).at(index)?.get('import_to_fyle')?.disable();
} else {
(this.importSettingsForm.get('expenseFields') as FormArray).at(index)?.get('import_to_fyle')?.setValue(true);
this.addImportCodeField({checked: true}, (this.importSettingsForm.get('expenseFields') as FormArray).at(index)?.get('destination_field')?.value);
}

if (selectedValue === 'custom_field') {
Expand Down Expand Up @@ -552,7 +555,12 @@ export class IntacctImportSettingsComponent implements OnInit {
this.fyleFields = this.fyleFields.filter(field => !field.is_dependent);
}

if (this.importSettings.configurations.import_code_fields.length > 0 && !this.importSettings.configurations.import_code_fields.includes(this.intacctCategoryDestination) && this.intacctImportCodeConfig[this.intacctCategoryDestination] && this.importSettings.configurations.import_categories) {
let sourceField = this.intacctCategoryDestination;
if (sourceField === IntacctCategoryDestination.GL_ACCOUNT) {
sourceField = IntacctCategoryDestination.ACCOUNT;
}

if (this.importSettings.configurations.import_code_fields && this.importSettings.configurations.import_code_fields.length > 0 && !this.importSettings.configurations.import_code_fields.includes(sourceField) && this.intacctImportCodeConfig[sourceField] && this.importSettings.configurations.import_categories) {
this.addImportCodeField({checked: true}, this.intacctCategoryDestination);
}

Expand Down Expand Up @@ -634,7 +642,7 @@ export class IntacctImportSettingsComponent implements OnInit {
}
}

if (configuration.employee_field_mapping==='EMPLOYEE') {
if (configuration.reimbursable_expenses_object === IntacctReimbursableExpensesObject.EXPENSE_REPORT || configuration.corporate_credit_card_expenses_object === IntacctCorporateCreditCardExpensesObject.EXPENSE_REPORT) {
this.intacctCategoryDestination = IntacctCategoryDestination.EXPENSE_TYPE;
} else {
this.intacctCategoryDestination = IntacctCategoryDestination.GL_ACCOUNT;
Expand Down
168 changes: 127 additions & 41 deletions src/app/integrations/intacct/intacct.component.spec.ts
Original file line number Diff line number Diff line change
@@ -1,49 +1,135 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { HttpClientModule } from '@angular/common/http';
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { RouterTestingModule } from '@angular/router/testing';
import { of, throwError } from 'rxjs';
import { Router, NavigationEnd, RouterModule } from '@angular/router';
import { of } from 'rxjs';
import { IntacctComponent } from './intacct.component';
import { errorResponse, workspaceResponse } from './intacct.fixture';
import { HelperService } from 'src/app/core/services/common/helper.service';
import { StorageService } from 'src/app/core/services/common/storage.service';
import { WindowService } from 'src/app/core/services/common/window.service';
import { AppcuesService } from 'src/app/core/services/integration/appcues.service';
import { UserService } from 'src/app/core/services/misc/user.service';
import { SiWorkspaceService } from 'src/app/core/services/si/si-core/si-workspace.service';
import { AppName, AppUrl, IntacctOnboardingState } from 'src/app/core/models/enum/enum.model';
import { mockUser, testOnboardingState, workspaceResponse } from './intacct.fixture';
import { IntacctWorkspace } from 'src/app/core/models/intacct/db/workspaces.model';

xdescribe('SiComponent', () => {
describe('IntacctComponent', () => {
let component: IntacctComponent;
let fixture: ComponentFixture<IntacctComponent>;
let workspace: SiWorkspaceService;
let userServiceSpy: jasmine.SpyObj<UserService>;
let workspaceServiceSpy: jasmine.SpyObj<SiWorkspaceService>;
let helperServiceSpy: jasmine.SpyObj<HelperService>;
let storageServiceSpy: jasmine.SpyObj<StorageService>;
let routerSpy: jasmine.SpyObj<Router>;
let windowServiceMock: Partial<WindowService>;
let appcuesServiceSpy: jasmine.SpyObj<AppcuesService>;

beforeEach(async () => {
const localStorageDump = {
email: '[email protected]',
org_id: 'abcdefgh'
};
localStorage.setItem('user', JSON.stringify(localStorageDump));
const service1 = {
getWorkspace: () => of(workspaceResponse),
postWorkspace: () => of(workspaceResponse)
};
await TestBed.configureTestingModule({
imports: [RouterTestingModule, HttpClientModule, HttpClientTestingModule],
declarations: [ IntacctComponent ],
providers: [
{ provide: SiWorkspaceService, useValue: service1 }
]
})
.compileComponents();

fixture = TestBed.createComponent(IntacctComponent);
component = fixture.componentInstance;
workspace = TestBed.inject(SiWorkspaceService);
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});

it('ngOnIng function check', async () => {
expect((component as any).getOrCreateWorkspace()).toBeUndefined();
spyOn(workspace, 'getWorkspace').and.returnValue(of([]));
expect((component as any).getOrCreateWorkspace()).toBeUndefined();
});
});
const userSpy = jasmine.createSpyObj('UserService', ['getUserProfile']);
const workspaceSpy = jasmine.createSpyObj('SiWorkspaceService', ['getWorkspace', 'postWorkspace', 'syncFyleDimensions', 'syncIntacctDimensions']);
const helperSpy = jasmine.createSpyObj('HelperService', ['setBaseApiURL']);
const storageSpy = jasmine.createSpyObj('StorageService', ['set']);
const routerSpyObj = jasmine.createSpyObj('Router', ['navigateByUrl', 'events']);
const appcuesSpy = jasmine.createSpyObj('AppcuesService', ['initialiseAppcues']);

windowServiceMock = {
get nativeWindow() {
return {
location: {
pathname: '/integrations/intacct'
}
} as Window;
}
};

await TestBed.configureTestingModule({
declarations: [ IntacctComponent ],
imports: [RouterModule],
providers: [
{ provide: HelperService, useValue: helperSpy },
{ provide: AppcuesService, useValue: appcuesSpy },
{ provide: Router, useValue: routerSpyObj },
{ provide: StorageService, useValue: storageSpy },
{ provide: UserService, useValue: userSpy },
{ provide: SiWorkspaceService, useValue: workspaceSpy },
{ provide: WindowService, useValue: windowServiceMock }
]
}).compileComponents();

userServiceSpy = TestBed.inject(UserService) as jasmine.SpyObj<UserService>;
workspaceServiceSpy = TestBed.inject(SiWorkspaceService) as jasmine.SpyObj<SiWorkspaceService>;
helperServiceSpy = TestBed.inject(HelperService) as jasmine.SpyObj<HelperService>;
storageServiceSpy = TestBed.inject(StorageService) as jasmine.SpyObj<StorageService>;
routerSpy = TestBed.inject(Router) as jasmine.SpyObj<Router>;
(routerSpy.events as any) = of(new NavigationEnd(0, '', ''));
appcuesServiceSpy = TestBed.inject(AppcuesService) as jasmine.SpyObj<AppcuesService>;

userServiceSpy.getUserProfile.and.returnValue(mockUser);
workspaceServiceSpy.getWorkspace.and.returnValue(of(workspaceResponse));
workspaceServiceSpy.syncFyleDimensions.and.returnValue(of());
workspaceServiceSpy.syncIntacctDimensions.and.returnValue(of());

fixture = TestBed.createComponent(IntacctComponent);
component = fixture.componentInstance;
});

it('should create', () => {
expect(component).toBeTruthy();
});

it('should setup workspace and navigate when workspace exists', () => {
fixture.detectChanges();

expect(helperServiceSpy.setBaseApiURL).toHaveBeenCalledWith(AppUrl.INTACCT);
expect(workspaceServiceSpy.getWorkspace).toHaveBeenCalledWith('mock org id');
expect(storageServiceSpy.set).toHaveBeenCalledWith('workspaceId', 1);
expect(storageServiceSpy.set).toHaveBeenCalledWith('onboarding-state', IntacctOnboardingState.CONNECTION);
expect(workspaceServiceSpy.syncFyleDimensions).toHaveBeenCalled();
expect(workspaceServiceSpy.syncIntacctDimensions).toHaveBeenCalled();
expect(routerSpy.navigateByUrl).toHaveBeenCalledWith('/integrations/intacct/onboarding/landing');
});

it('should create a new workspace if none exists', () => {
workspaceServiceSpy.getWorkspace.and.returnValue(of([]));
workspaceServiceSpy.postWorkspace.and.returnValue(of(workspaceResponse[0]));

fixture.detectChanges();

expect(workspaceServiceSpy.postWorkspace).toHaveBeenCalled();
expect(storageServiceSpy.set).toHaveBeenCalledWith('workspaceId', 1);
expect(storageServiceSpy.set).toHaveBeenCalledWith('onboarding-state', IntacctOnboardingState.CONNECTION);
expect(routerSpy.navigateByUrl).toHaveBeenCalledWith('/integrations/intacct/onboarding/landing');
});

it('should navigate to correct route based on onboarding state', () => {
Object.entries(testOnboardingState).forEach(([state, route ]) => {
routerSpy.navigateByUrl.calls.reset();
const testWorkspace: IntacctWorkspace = { ...workspaceResponse[0], onboarding_state: state as IntacctOnboardingState };
workspaceServiceSpy.getWorkspace.and.returnValue(of([testWorkspace]));

fixture.detectChanges();

expect(routerSpy.navigateByUrl).toHaveBeenCalledWith(route);

fixture = TestBed.createComponent(IntacctComponent);
component = fixture.componentInstance;
});
});

it('should not navigate if pathname is not /integrations/intacct', () => {
component.windowReference.location.pathname = '/some/other/path';
fixture.detectChanges();

expect(routerSpy.navigateByUrl).not.toHaveBeenCalled();
});

it('should initialise Appcues', () => {
(window as any).Appcues = {
page: jasmine.createSpy('Appcues.page')
};

fixture.detectChanges();

expect(appcuesServiceSpy.initialiseAppcues).toHaveBeenCalled();
expect((window as any).Appcues.page).toHaveBeenCalled();
});
});
2 changes: 1 addition & 1 deletion src/app/integrations/intacct/intacct.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ export class IntacctComponent implements OnInit {
private getOrCreateWorkspace(): void {
this.helperService.setBaseApiURL(AppUrl.INTACCT);
this.workspaceService.getWorkspace(this.user.org_id).subscribe((workspaces) => {
if (workspaces.length) {
if (workspaces.length && workspaces.length > 0) {
this.setupWorkspace(workspaces[0]);
} else {
this.workspaceService.postWorkspace().subscribe((workspaces: IntacctWorkspace) => {
Expand Down
16 changes: 16 additions & 0 deletions src/app/integrations/intacct/intacct.fixture.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { minimalUser } from "src/app/core/interceptor/jwt.fixture";
import { MinimalUser } from "src/app/core/models/db/user.model";
import { IntacctOnboardingState } from "src/app/core/models/enum/enum.model";
import { IntacctWorkspace } from "src/app/core/models/intacct/db/workspaces.model";

Expand Down Expand Up @@ -25,4 +27,18 @@ export const workspaceResponse: IntacctWorkspace[] = [{
is_expired: true,
company_name: 'Halo MasterChief'
}
};

export const mockUser: MinimalUser = {
...minimalUser,
org_id: 'mock org id'
};

export const testOnboardingState: {[k in IntacctOnboardingState]: string} = {
[IntacctOnboardingState.CONNECTION]: '/integrations/intacct/onboarding/landing',
[IntacctOnboardingState.LOCATION_ENTITY]: '/integrations/intacct/onboarding/connector',
[IntacctOnboardingState.EXPORT_SETTINGS]: '/integrations/intacct/onboarding/export_settings',
[IntacctOnboardingState.IMPORT_SETTINGS]: '/integrations/intacct/onboarding/import_settings',
[IntacctOnboardingState.ADVANCED_CONFIGURATION]: '/integrations/intacct/onboarding/advanced_settings',
[IntacctOnboardingState.COMPLETE]: '/integrations/intacct/main/dashboard'
};
Loading

0 comments on commit 13a33b5

Please sign in to comment.