feat(expense-snapshot): frontend model + api service with tests
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -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;
|
||||
@@ -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);
|
||||
});
|
||||
});
|
||||
@@ -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<ExpenseSnapshotDto[]> {
|
||||
return this.http.get<ExpenseSnapshotDto[]>(this.endpoint);
|
||||
}
|
||||
getById(id: number): Observable<ExpenseSnapshotDto> {
|
||||
return this.http.get<ExpenseSnapshotDto>(`${this.endpoint}/${id}`);
|
||||
}
|
||||
create(r: CreateExpenseSnapshotRequest): Observable<{ id: number }> {
|
||||
return this.http.post<{ id: number }>(this.endpoint, r);
|
||||
}
|
||||
update(id: number, r: UpdateExpenseSnapshotRequest): Observable<void> {
|
||||
return this.http.put<void>(`${this.endpoint}/${id}`, r);
|
||||
}
|
||||
delete(id: number): Observable<void> {
|
||||
return this.http.delete<void>(`${this.endpoint}/${id}`);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user