feat(giving): frontend models + API services
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,119 @@
|
||||
export type PaymentMethod = 'Cash' | 'Check' | 'Zelle' | 'PayPal' | 'Other';
|
||||
export type SessionStatus = 'Draft' | 'Submitted' | 'Reconciled';
|
||||
|
||||
export interface PagedResult<T> {
|
||||
items: T[];
|
||||
totalCount: number;
|
||||
page: number;
|
||||
pageSize: number;
|
||||
totalPages: number;
|
||||
}
|
||||
|
||||
// ── Giving categories ─────────────────────────────────────────────
|
||||
export interface GivingCategoryDto {
|
||||
id: number;
|
||||
name_en: string;
|
||||
name_zh: string | null;
|
||||
description_en: string | null;
|
||||
description_zh: string | null;
|
||||
isActive: boolean;
|
||||
sortOrder: number;
|
||||
}
|
||||
export interface CreateGivingCategoryRequest {
|
||||
name_en: string;
|
||||
name_zh: string | null;
|
||||
description_en: string | null;
|
||||
description_zh: string | null;
|
||||
sortOrder: number;
|
||||
}
|
||||
export interface UpdateGivingCategoryRequest extends CreateGivingCategoryRequest {
|
||||
isActive: boolean;
|
||||
}
|
||||
|
||||
// ── Single giving ─────────────────────────────────────────────────
|
||||
export interface GivingListItemDto {
|
||||
id: number;
|
||||
memberId: number | null;
|
||||
memberName: string | null;
|
||||
givingCategoryId: number;
|
||||
categoryName: string;
|
||||
amount: number;
|
||||
paymentMethod: PaymentMethod;
|
||||
givingDate: string; // yyyy-MM-dd
|
||||
isAnonymous: boolean;
|
||||
offeringSessionId: number | null;
|
||||
}
|
||||
export interface CreateGivingRequest {
|
||||
memberId: number | null;
|
||||
givingCategoryId: number;
|
||||
amount: number;
|
||||
paymentMethod: PaymentMethod;
|
||||
checkNumber: string | null;
|
||||
zelleReferenceCode: string | null;
|
||||
payPalTransactionId: string | null;
|
||||
givingDate: string; // yyyy-MM-dd
|
||||
isAnonymous: boolean;
|
||||
notes: string | null;
|
||||
}
|
||||
export type UpdateGivingRequest = CreateGivingRequest;
|
||||
|
||||
// ── Offering session (batch) ──────────────────────────────────────
|
||||
export interface OfferingGivingLineRequest {
|
||||
memberId: number | null;
|
||||
givingCategoryId: number;
|
||||
amount: number;
|
||||
paymentMethod: PaymentMethod;
|
||||
checkNumber: string | null;
|
||||
zelleReferenceCode: string | null;
|
||||
payPalTransactionId: string | null;
|
||||
isAnonymous: boolean;
|
||||
notes: string | null;
|
||||
}
|
||||
export interface CreateOfferingSessionRequest {
|
||||
sessionDate: string; // yyyy-MM-dd
|
||||
cashTotal: number;
|
||||
checkTotal: number;
|
||||
notes: string | null;
|
||||
givings: OfferingGivingLineRequest[];
|
||||
}
|
||||
export interface OfferingGivingLineDto {
|
||||
id: number;
|
||||
memberId: number | null;
|
||||
memberName: string | null;
|
||||
givingCategoryId: number;
|
||||
categoryName: string;
|
||||
amount: number;
|
||||
paymentMethod: PaymentMethod;
|
||||
checkNumber: string | null;
|
||||
zelleReferenceCode: string | null;
|
||||
payPalTransactionId: string | null;
|
||||
isAnonymous: boolean;
|
||||
notes: string | null;
|
||||
}
|
||||
export interface OfferingSessionDto {
|
||||
id: number;
|
||||
sessionDate: string;
|
||||
status: SessionStatus;
|
||||
cashTotal: number;
|
||||
checkTotal: number;
|
||||
systemTotal: number;
|
||||
difference: number;
|
||||
notes: string | null;
|
||||
givings: OfferingGivingLineDto[];
|
||||
}
|
||||
export interface OfferingSessionListItemDto {
|
||||
id: number;
|
||||
sessionDate: string;
|
||||
status: SessionStatus;
|
||||
cashTotal: number;
|
||||
checkTotal: number;
|
||||
systemTotal: number;
|
||||
difference: number;
|
||||
lineCount: number;
|
||||
}
|
||||
|
||||
/** A row held in the client-side batch buffer before submit. */
|
||||
export interface OfferingBufferLine extends OfferingGivingLineRequest {
|
||||
memberName: string | null; // for display only
|
||||
categoryName: string; // for display only
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { HttpClient, HttpParams } from '@angular/common/http';
|
||||
import { Observable } from 'rxjs';
|
||||
import { ApiConfigService } from '../../../core/services/api-config.service';
|
||||
import {
|
||||
GivingListItemDto, CreateGivingRequest, UpdateGivingRequest, PagedResult,
|
||||
} from '../models/giving.model';
|
||||
|
||||
export interface GivingQuery {
|
||||
page?: number; pageSize?: number; search?: string;
|
||||
categoryId?: number; from?: string; to?: string;
|
||||
}
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class GivingApiService {
|
||||
private readonly endpoint: string;
|
||||
constructor(private http: HttpClient, apiConfig: ApiConfigService) {
|
||||
this.endpoint = apiConfig.getApiUrl('givings');
|
||||
}
|
||||
|
||||
getPaged(q: GivingQuery = {}): Observable<PagedResult<GivingListItemDto>> {
|
||||
let p = new HttpParams().set('page', q.page ?? 1).set('pageSize', q.pageSize ?? 20);
|
||||
if (q.search) p = p.set('search', q.search);
|
||||
if (q.categoryId != null) p = p.set('categoryId', q.categoryId);
|
||||
if (q.from) p = p.set('from', q.from);
|
||||
if (q.to) p = p.set('to', q.to);
|
||||
return this.http.get<PagedResult<GivingListItemDto>>(this.endpoint, { params: p });
|
||||
}
|
||||
create(request: CreateGivingRequest): Observable<{ id: number }> {
|
||||
return this.http.post<{ id: number }>(this.endpoint, request);
|
||||
}
|
||||
update(id: number, request: UpdateGivingRequest): Observable<void> {
|
||||
return this.http.put<void>(`${this.endpoint}/${id}`, request);
|
||||
}
|
||||
delete(id: number): Observable<void> {
|
||||
return this.http.delete<void>(`${this.endpoint}/${id}`);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { HttpClient, HttpParams } from '@angular/common/http';
|
||||
import { Observable } from 'rxjs';
|
||||
import { ApiConfigService } from '../../../core/services/api-config.service';
|
||||
import {
|
||||
GivingCategoryDto, CreateGivingCategoryRequest, UpdateGivingCategoryRequest,
|
||||
} from '../models/giving.model';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class GivingCategoryApiService {
|
||||
private readonly endpoint: string;
|
||||
constructor(private http: HttpClient, apiConfig: ApiConfigService) {
|
||||
this.endpoint = apiConfig.getApiUrl('giving-categories');
|
||||
}
|
||||
|
||||
getAll(includeInactive = false): Observable<GivingCategoryDto[]> {
|
||||
const params = new HttpParams().set('includeInactive', includeInactive);
|
||||
return this.http.get<GivingCategoryDto[]>(this.endpoint, { params });
|
||||
}
|
||||
create(request: CreateGivingCategoryRequest): Observable<{ id: number }> {
|
||||
return this.http.post<{ id: number }>(this.endpoint, request);
|
||||
}
|
||||
update(id: number, request: UpdateGivingCategoryRequest): Observable<void> {
|
||||
return this.http.put<void>(`${this.endpoint}/${id}`, request);
|
||||
}
|
||||
deactivate(id: number): Observable<void> {
|
||||
return this.http.delete<void>(`${this.endpoint}/${id}`);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { HttpClient, HttpParams } from '@angular/common/http';
|
||||
import { Observable } from 'rxjs';
|
||||
import { ApiConfigService } from '../../../core/services/api-config.service';
|
||||
import {
|
||||
OfferingSessionDto, OfferingSessionListItemDto,
|
||||
CreateOfferingSessionRequest, PagedResult,
|
||||
} from '../models/giving.model';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class OfferingSessionApiService {
|
||||
private readonly endpoint: string;
|
||||
constructor(private http: HttpClient, apiConfig: ApiConfigService) {
|
||||
this.endpoint = apiConfig.getApiUrl('offering-sessions');
|
||||
}
|
||||
|
||||
getPaged(page = 1, pageSize = 20): Observable<PagedResult<OfferingSessionListItemDto>> {
|
||||
const params = new HttpParams().set('page', page).set('pageSize', pageSize);
|
||||
return this.http.get<PagedResult<OfferingSessionListItemDto>>(this.endpoint, { params });
|
||||
}
|
||||
getById(id: number): Observable<OfferingSessionDto> {
|
||||
return this.http.get<OfferingSessionDto>(`${this.endpoint}/${id}`);
|
||||
}
|
||||
checkDate(date: string): Observable<{ exists: boolean }> {
|
||||
const params = new HttpParams().set('date', date);
|
||||
return this.http.get<{ exists: boolean }>(`${this.endpoint}/check-date`, { params });
|
||||
}
|
||||
create(request: CreateOfferingSessionRequest): Observable<{ id: number }> {
|
||||
return this.http.post<{ id: number }>(this.endpoint, request);
|
||||
}
|
||||
reopen(id: number): Observable<void> {
|
||||
return this.http.post<void>(`${this.endpoint}/${id}/reopen`, {});
|
||||
}
|
||||
replace(id: number, request: CreateOfferingSessionRequest): Observable<void> {
|
||||
return this.http.put<void>(`${this.endpoint}/${id}`, request);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user