diff --git a/APP/src/app/features/expense/models/expense-snapshot.model.ts b/APP/src/app/features/expense/models/expense-snapshot.model.ts new file mode 100644 index 0000000..1f9abaa --- /dev/null +++ b/APP/src/app/features/expense/models/expense-snapshot.model.ts @@ -0,0 +1,21 @@ +import { ExpenseLineInput, FunctionalClass } from './expense.model'; + +export interface ExpenseSnapshotLineDto { + categoryGroupId: number; categoryGroupName: string; + subCategoryId: number; subCategoryName: string; + functionalClass: FunctionalClass | null; amount: number; description: string | null; +} + +export interface ExpenseSnapshotDto { + id: number; name: string; ministryId: number; ministryName: string; + description: string; vendorName: string | null; checkNumber: string | null; notes: string | null; + totalAmount: number; lineCount: number; + createdByName: string | null; createdAt: string; + lines: ExpenseSnapshotLineDto[]; +} + +export interface CreateExpenseSnapshotRequest { + name: string; ministryId: number; lines: ExpenseLineInput[]; + description: string; vendorName: string | null; checkNumber: string | null; notes: string | null; +} +export type UpdateExpenseSnapshotRequest = CreateExpenseSnapshotRequest; diff --git a/APP/src/app/features/expense/services/expense-snapshot-api.service.spec.ts b/APP/src/app/features/expense/services/expense-snapshot-api.service.spec.ts new file mode 100644 index 0000000..eca110e --- /dev/null +++ b/APP/src/app/features/expense/services/expense-snapshot-api.service.spec.ts @@ -0,0 +1,52 @@ +import { TestBed } from '@angular/core/testing'; +import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; +import { ExpenseSnapshotApiService } from './expense-snapshot-api.service'; +import { ApiConfigService } from '../../../core/services/api-config.service'; +import { CreateExpenseSnapshotRequest } from '../models/expense-snapshot.model'; + +describe('ExpenseSnapshotApiService', () => { + let service: ExpenseSnapshotApiService; + let httpMock: HttpTestingController; + const base = 'http://test/api/expense-snapshots'; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [HttpClientTestingModule], + providers: [ + ExpenseSnapshotApiService, + { provide: ApiConfigService, useValue: { getApiUrl: () => base } }, + ], + }); + service = TestBed.inject(ExpenseSnapshotApiService); + httpMock = TestBed.inject(HttpTestingController); + }); + + afterEach(() => httpMock.verify()); + + it('getAll() GETs the collection endpoint', () => { + service.getAll().subscribe(); + const req = httpMock.expectOne(base); + expect(req.request.method).toBe('GET'); + req.flush([]); + }); + + it('create() POSTs the request body', () => { + const body: CreateExpenseSnapshotRequest = { + name: 'Rent', ministryId: 1, description: 'Office rent', + vendorName: 'Landlord X', checkNumber: null, notes: null, + lines: [{ categoryGroupId: 1, subCategoryId: 1, amount: 1200, functionalClass: null, description: null }], + }; + service.create(body).subscribe(); + const req = httpMock.expectOne(base); + expect(req.request.method).toBe('POST'); + expect(req.request.body.name).toBe('Rent'); + req.flush({ id: 7 }); + }); + + it('delete() DELETEs by id', () => { + service.delete(9).subscribe(); + const req = httpMock.expectOne(`${base}/9`); + expect(req.request.method).toBe('DELETE'); + req.flush(null); + }); +}); diff --git a/APP/src/app/features/expense/services/expense-snapshot-api.service.ts b/APP/src/app/features/expense/services/expense-snapshot-api.service.ts new file mode 100644 index 0000000..bcf3154 --- /dev/null +++ b/APP/src/app/features/expense/services/expense-snapshot-api.service.ts @@ -0,0 +1,30 @@ +import { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { Observable } from 'rxjs'; +import { ApiConfigService } from '../../../core/services/api-config.service'; +import { + ExpenseSnapshotDto, CreateExpenseSnapshotRequest, UpdateExpenseSnapshotRequest, +} from '../models/expense-snapshot.model'; + +@Injectable({ providedIn: 'root' }) +export class ExpenseSnapshotApiService { + private readonly endpoint: string; + constructor(private http: HttpClient, apiConfig: ApiConfigService) { + this.endpoint = apiConfig.getApiUrl('expense-snapshots'); + } + getAll(): Observable { + return this.http.get(this.endpoint); + } + getById(id: number): Observable { + return this.http.get(`${this.endpoint}/${id}`); + } + create(r: CreateExpenseSnapshotRequest): Observable<{ id: number }> { + return this.http.post<{ id: number }>(this.endpoint, r); + } + update(id: number, r: UpdateExpenseSnapshotRequest): Observable { + return this.http.put(`${this.endpoint}/${id}`, r); + } + delete(id: number): Observable { + return this.http.delete(`${this.endpoint}/${id}`); + } +}