Skip to content

Commit

Permalink
feat: migrate public currency and exchange rate api to platform (#3220)
Browse files Browse the repository at this point in the history
  • Loading branch information
ravikumar-hash authored Oct 10, 2024
1 parent fb10289 commit 46ee637
Show file tree
Hide file tree
Showing 8 changed files with 158 additions and 32 deletions.
5 changes: 3 additions & 2 deletions src/app/core/mock-data/currency.data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ export const apiAllCurrencies: CurrencyName = deepFreeze({
MMK: 'Myanma Kyat',
MNT: 'Mongolian Tugrik',
MOP: 'Macanese Pataca',
MRO: 'Mauritanian Ouguiya',
MRU: 'Mauritanian Ouguiya',
MUR: 'Mauritian Rupee',
MVR: 'Maldivian Rufiyaa',
MWK: 'Malawian Kwacha',
Expand Down Expand Up @@ -130,7 +130,7 @@ export const apiAllCurrencies: CurrencyName = deepFreeze({
SAR: 'Saudi Riyal',
SBD: 'Solomon Islands Dollar',
SCR: 'Seychellois Rupee',
SDG: 'Sudanese Pound',
SDG: 'South Sudanese Pound',
SEK: 'Swedish Krona',
SGD: 'Singapore Dollar',
SHP: 'Saint Helena Pound',
Expand Down Expand Up @@ -173,6 +173,7 @@ export const apiAllCurrencies: CurrencyName = deepFreeze({
ZMK: 'Zambian Kwacha (pre-2013)',
ZMW: 'Zambian Kwacha',
ZWL: 'Zimbabwean Dollar',
CNH: 'Chinese Yuan Offshore',
});

export const apiAllCurrencies2: CurrencyName = deepFreeze({
Expand Down
3 changes: 3 additions & 0 deletions src/app/core/models/exchange-rate-response.model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export interface ExchangeRateResponse {
exchange_rate: number;
}
34 changes: 17 additions & 17 deletions src/app/core/services/currency.service.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { TestBed } from '@angular/core/testing';
import { CurrencyService } from './currency.service';
import { ApiService } from './api.service';
import { AuthService } from './auth.service';
import { PlatformCommonApiService } from './platform-common-api.service';
import { OrgService } from './org.service';
import { apiEouRes } from '../mock-data/extended-org-user.data';
import { apiAllCurrencies } from '../mock-data/currency.data';
Expand All @@ -11,13 +11,13 @@ import * as dayjs from 'dayjs';

describe('CurrencyService', () => {
let currencyService: CurrencyService;
let apiService: jasmine.SpyObj<ApiService>;
let platformCommonApiService: jasmine.SpyObj<PlatformCommonApiService>;
let authService: jasmine.SpyObj<AuthService>;
let orgService: jasmine.SpyObj<OrgService>;
const dt = new Date();

beforeEach(() => {
const apiServiceSpy = jasmine.createSpyObj('ApiService', ['get']);
const platformCommonApiServiceSpy = jasmine.createSpyObj('PlatformCommonApiService', ['get']);
const authServiceSpy = jasmine.createSpyObj('AuthService', ['getEou']);
const orgServiceSpy = jasmine.createSpyObj('OrgService', ['getCurrentOrg']);
TestBed.configureTestingModule({
Expand All @@ -28,8 +28,8 @@ describe('CurrencyService', () => {
useValue: authServiceSpy,
},
{
provide: ApiService,
useValue: apiServiceSpy,
provide: PlatformCommonApiService,
useValue: platformCommonApiServiceSpy,
},
{
provide: OrgService,
Expand All @@ -39,7 +39,7 @@ describe('CurrencyService', () => {
});
currencyService = TestBed.inject(CurrencyService);
authService = TestBed.inject(AuthService) as jasmine.SpyObj<AuthService>;
apiService = TestBed.inject(ApiService) as jasmine.SpyObj<ApiService>;
platformCommonApiService = TestBed.inject(PlatformCommonApiService) as jasmine.SpyObj<PlatformCommonApiService>;
orgService = TestBed.inject(OrgService) as jasmine.SpyObj<OrgService>;
});

Expand All @@ -49,13 +49,13 @@ describe('CurrencyService', () => {

it('getAll(): should return all currencies', (done) => {
authService.getEou.and.resolveTo(apiEouRes);
apiService.get.and.returnValue(of(apiAllCurrencies));
platformCommonApiService.get.and.returnValue(of({ data: apiAllCurrencies }));

currencyService.getAll().subscribe((res) => {
expect(res).toEqual(apiAllCurrencies);
expect(apiService.get).toHaveBeenCalledOnceWith('/currency/all', {
expect(platformCommonApiService.get).toHaveBeenCalledOnceWith('/currency/list', {
params: {
org_id: apiEouRes && apiEouRes.ou && apiEouRes.ou.org_id,
org_id: apiEouRes?.ou?.org_id,
},
});
expect(authService.getEou).toHaveBeenCalledTimes(1);
Expand All @@ -79,21 +79,21 @@ describe('CurrencyService', () => {

describe('getExchangeRate():', () => {
it('should get the exchange rate', (done) => {
apiService.get.and.returnValue(
platformCommonApiService.get.and.returnValue(
of({
exchange_rate: 82.708499,
data: { exchange_rate: 82.708499 },
})
);

const txnID = 'tx6Oe6FaYDZl';

currencyService.getExchangeRate('USD', 'INR', new Date(), txnID).subscribe((res) => {
expect(res).toEqual(82.708499);
expect(apiService.get).toHaveBeenCalledOnceWith('/currency/exchange', {
expect(platformCommonApiService.get).toHaveBeenCalledOnceWith('/currency/exchange_rate', {
params: {
from: 'USD',
to: 'INR',
dt: dayjs(dt).format('YYYY-MM-D'),
date: dayjs(dt).format('YYYY-MM-D'),
tx6Oe6FaYDZl: 'tx6Oe6FaYDZl',
},
});
Expand All @@ -102,19 +102,19 @@ describe('CurrencyService', () => {
});

it('should get the exchange rate when date and transaction ID not specified', (done) => {
apiService.get.and.returnValue(
platformCommonApiService.get.and.returnValue(
of({
exchange_rate: 82.708499,
data: { exchange_rate: 82.708499 },
})
);

currencyService.getExchangeRate('USD', 'INR').subscribe((res) => {
expect(res).toEqual(82.708499);
expect(apiService.get).toHaveBeenCalledOnceWith('/currency/exchange', {
expect(platformCommonApiService.get).toHaveBeenCalledOnceWith('/currency/exchange_rate', {
params: {
from: 'USD',
to: 'INR',
dt: dayjs(dt).format('YYYY-MM-D'),
date: dayjs(dt).format('YYYY-MM-D'),
},
});
done();
Expand Down
32 changes: 19 additions & 13 deletions src/app/core/services/currency.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,36 +6,40 @@ import { catchError, map, switchMap } from 'rxjs/operators';
import { Cacheable } from 'ts-cacheable';
import { CurrencyName } from '../models/currency.model';
import { ExtendedOrgUser } from '../models/extended-org-user.model';
import { PublicPolicyExpense } from '../models/public-policy-expense.model';
import { ApiService } from './api.service';
import { ExchangeRateResponse } from '../models/exchange-rate-response.model';
import { AuthService } from './auth.service';
import { OrgService } from './org.service';

import { PlatformCommonApiService } from './platform-common-api.service';
import { PlatformApiResponse } from '../models/platform/platform-api-response.model';
@Injectable({
providedIn: 'root',
})
export class CurrencyService {
constructor(private orgService: OrgService, private authService: AuthService, private apiService: ApiService) {}
constructor(
private orgService: OrgService,
private authService: AuthService,
private platformCommonApiService: PlatformCommonApiService
) {}

@Cacheable()
getExchangeRate(fromCurrency: string, toCurrency: string, dt = new Date(), txnId?: string): Observable<number> {
const txnDt = dayjs(dt).format('YYYY-MM-D');
const queryParams = {
from: fromCurrency,
to: toCurrency,
dt: txnDt,
date: txnDt,
};

if (txnId) {
queryParams[txnId] = txnId;
}

return this.apiService
.get<Partial<PublicPolicyExpense>>('/currency/exchange', {
return this.platformCommonApiService
.get<PlatformApiResponse<ExchangeRateResponse>>('/currency/exchange_rate', {
params: queryParams,
})
.pipe(
map((res) => parseFloat(res.exchange_rate.toFixed(7))),
map((res) => parseFloat(res.data.exchange_rate.toFixed(7))),
catchError(() => of(1))
);
}
Expand All @@ -44,11 +48,13 @@ export class CurrencyService {
getAll(): Observable<CurrencyName> {
return from(this.authService.getEou()).pipe(
switchMap((currentEou: ExtendedOrgUser) =>
this.apiService.get<CurrencyName>('/currency/all', {
params: {
org_id: currentEou && currentEou.ou && currentEou.ou.org_id,
},
})
this.platformCommonApiService
.get<PlatformApiResponse<CurrencyName>>('/currency/list', {
params: {
org_id: currentEou?.ou?.org_id,
},
})
.pipe(map((response) => response.data))
)
);
}
Expand Down
81 changes: 81 additions & 0 deletions src/app/core/services/platform-common-api.service.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { TestBed } from '@angular/core/testing';
import { PlatformCommonApiService } from './platform-common-api.service';
import { HttpTestingController, HttpClientTestingModule } from '@angular/common/http/testing';
import { HttpClient } from '@angular/common/http';
import { of } from 'rxjs';

const requestObj = {
someKey: 'someValue',
};

const apiResponse = {
message: 'SUCCESS',
};

describe('PlatformCommonApiService', () => {
let platformCommonApiService: PlatformCommonApiService;
let httpTestingController: HttpTestingController;
let httpClient: jasmine.SpyObj<HttpClient>;
const rootUrl = 'https://staging.fyle.tech';

beforeEach(() => {
const httpClientSpy = jasmine.createSpyObj('HttpClient', ['get', 'post']);

TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
providers: [
PlatformCommonApiService,
{
provide: HttpClient,
useValue: httpClientSpy,
},
],
});
platformCommonApiService = TestBed.inject(PlatformCommonApiService);
httpTestingController = TestBed.inject(HttpTestingController);
httpClient = TestBed.inject(HttpClient) as jasmine.SpyObj<HttpClient>;
platformCommonApiService.setRoot(rootUrl);
});

it('should be created', () => {
expect(platformCommonApiService).toBeTruthy();
});

it('setRoot(): should set root url', () => {
expect(platformCommonApiService.ROOT_ENDPOINT).toBe(rootUrl);
});

describe('get():', () => {
it('should make GET request without params', (done) => {
httpClient.get.and.returnValue(of(apiResponse));

platformCommonApiService.get('/currency/list').subscribe((res) => {
expect(res).toEqual(apiResponse);
expect(httpClient.get).toHaveBeenCalledOnceWith(
'https://staging.fyle.tech/platform/v1/common/currency/list',
{}
);
done();
});
});

it('should make GET request with params', (done) => {
httpClient.get.and.returnValue(of(apiResponse));

platformCommonApiService.get('/currency/exchange_rate', { params: requestObj }).subscribe((res) => {
expect(res).toEqual(apiResponse);
expect(httpClient.get).toHaveBeenCalledOnceWith(
'https://staging.fyle.tech/platform/v1/common/currency/exchange_rate',
{
params: requestObj,
}
);
done();
});
});
});

afterEach(() => {
httpTestingController.verify();
});
});
23 changes: 23 additions & 0 deletions src/app/core/services/platform-common-api.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { environment } from 'src/environments/environment';

@Injectable({
providedIn: 'root',
})
export class PlatformCommonApiService {
ROOT_ENDPOINT: string;

constructor(private httpClient: HttpClient) {
this.ROOT_ENDPOINT = environment.ROOT_URL;
}

setRoot(rootUrl: string): void {
this.ROOT_ENDPOINT = rootUrl;
}

get<T>(url: string, config = {}): Observable<T> {
return this.httpClient.get<T>(this.ROOT_ENDPOINT + '/platform/v1/common' + url, config);
}
}
9 changes: 9 additions & 0 deletions src/app/core/services/router-auth.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { TransactionsOutboxService } from './transactions-outbox.service';
import { VendorService } from './vendor.service';
import { ApproverPlatformApiService } from './approver-platform-api.service';
import { SpenderPlatformV1ApiService } from './spender-platform-v1-api.service';
import { PlatformCommonApiService } from './platform-common-api.service';
import { of } from 'rxjs';
import { apiAuthRes, authResData1 } from '../mock-data/auth-reponse.data';
import { ExpenseAggregationService } from './expense-aggregation.service';
Expand All @@ -29,6 +30,7 @@ describe('RouterAuthService', () => {
let vendorService: jasmine.SpyObj<VendorService>;
let approverPlatformApiService: jasmine.SpyObj<ApproverPlatformApiService>;
let spenderPlatformV1ApiService: jasmine.SpyObj<SpenderPlatformV1ApiService>;
let platformCommonApiService: jasmine.SpyObj<PlatformCommonApiService>;
let expenseAggregationService: jasmine.SpyObj<ExpenseAggregationService>;
let spenderService: jasmine.SpyObj<SpenderService>;
let approverService: jasmine.SpyObj<ApproverService>;
Expand Down Expand Up @@ -57,6 +59,7 @@ describe('RouterAuthService', () => {
const transactionOutboxServiceSpy = jasmine.createSpyObj('TransactionsOutboxService', ['setRoot']);
const vendorServiceSpy = jasmine.createSpyObj('VendorService', ['setRoot']);
const spenderPlatformV1ApiServiceSpy = jasmine.createSpyObj('SpenderPlatformV1ApiService', ['setRoot']);
const platformCommonApiServiceSpy = jasmine.createSpyObj('PlatformCommonApiService', ['setRoot']);
const approverPlatformApiServiceSpy = jasmine.createSpyObj('ApproverPlatformApiService', ['setRoot']);
const expenseAggregationServiceSpy = jasmine.createSpyObj('ExpenseAggregationService', ['setRoot']);
const spenderServiceSpy = jasmine.createSpyObj('SpenderService', ['setRoot']);
Expand Down Expand Up @@ -102,6 +105,10 @@ describe('RouterAuthService', () => {
provide: SpenderPlatformV1ApiService,
useValue: spenderPlatformV1ApiServiceSpy,
},
{
provide: PlatformCommonApiService,
useValue: platformCommonApiServiceSpy,
},
{
provide: ApproverPlatformApiService,
useValue: approverPlatformApiServiceSpy,
Expand Down Expand Up @@ -136,6 +143,7 @@ describe('RouterAuthService', () => {
spenderPlatformV1ApiService = TestBed.inject(
SpenderPlatformV1ApiService
) as jasmine.SpyObj<SpenderPlatformV1ApiService>;
platformCommonApiService = TestBed.inject(PlatformCommonApiService) as jasmine.SpyObj<PlatformCommonApiService>;
approverPlatformApiService = TestBed.inject(
ApproverPlatformApiService
) as jasmine.SpyObj<ApproverPlatformApiService>;
Expand Down Expand Up @@ -172,6 +180,7 @@ describe('RouterAuthService', () => {
expect(vendorService.setRoot).toHaveBeenCalledOnceWith(domain);
expect(approverPlatformApiService.setRoot).toHaveBeenCalledOnceWith(domain);
expect(spenderPlatformV1ApiService.setRoot).toHaveBeenCalledWith(domain);
expect(platformCommonApiService.setRoot).toHaveBeenCalledWith(domain);
expect(spenderPlatformV1ApiService.setRoot).toHaveBeenCalledTimes(2);
expect(tokenService.setClusterDomain).toHaveBeenCalledOnceWith(domain);
expect(expenseAggregationService.setRoot).toHaveBeenCalledOnceWith(domain);
Expand Down
3 changes: 3 additions & 0 deletions src/app/core/services/router-auth.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { LocationService } from './location.service';
import { TransactionsOutboxService } from './transactions-outbox.service';
import { VendorService } from './vendor.service';
import { SpenderPlatformV1ApiService } from './spender-platform-v1-api.service';
import { PlatformCommonApiService } from './platform-common-api.service';
import { ApproverPlatformApiService } from './approver-platform-api.service';
import { ExpenseAggregationService } from './expense-aggregation.service';
import { SpenderService } from './platform/v1/spender/spender.service';
Expand All @@ -34,6 +35,7 @@ export class RouterAuthService {
private vendorService: VendorService,
private approverPlatformApiService: ApproverPlatformApiService,
private spenderPlatformV1ApiService: SpenderPlatformV1ApiService,
private platformCommonApiService: PlatformCommonApiService,
private expenseAggregationService: ExpenseAggregationService,
private spenderService: SpenderService,
private approverService: ApproverService,
Expand Down Expand Up @@ -65,6 +67,7 @@ export class RouterAuthService {
this.spenderPlatformV1ApiService.setRoot(domain);
this.approverPlatformApiService.setRoot(domain);
this.spenderPlatformV1ApiService.setRoot(domain);
this.platformCommonApiService.setRoot(domain);
this.expenseAggregationService.setRoot(domain);
this.spenderService.setRoot(domain);
this.approverService.setRoot(domain);
Expand Down

0 comments on commit 46ee637

Please sign in to comment.