0e98e68532
DB: - V006__CreateClients.sql: clients 테이블 (name, company_name, phone, email, service_type, tax_type, status, source, memo) Domain: - Client 엔티티 - IClientRepository (GetPagedAsync 이름/연락처/회사명 검색 + 상태 필터) Infrastructure: - ClientRepository: ILIKE 검색, 페이징, CRUD Application: - ClientService: ServiceTypes/TaxTypes/Sources 상수 정의 - CreateClientDto Admin UI: - ClientList.razor: 검색바 + 상태 필터 + 페이징 테이블 - ClientEdit.razor: 기본정보/세무정보/관리정보 섹션 폼 - MainLayout: 고객 관리 NavGroup 추가, 홈페이지 메뉴 그룹화 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
70 lines
2.7 KiB
C#
70 lines
2.7 KiB
C#
namespace TaxBaik.Application.Services;
|
|
|
|
using TaxBaik.Application.DTOs;
|
|
using TaxBaik.Domain.Entities;
|
|
using TaxBaik.Domain.Interfaces;
|
|
|
|
public class ClientService(IClientRepository repository)
|
|
{
|
|
public static readonly string[] ServiceTypes =
|
|
["기장", "부동산", "증여·상속", "종합소득세", "법인세", "부가가치세", "기타"];
|
|
|
|
public static readonly string[] TaxTypes =
|
|
["개인사업자", "법인사업자", "면세사업자", "근로소득자", "기타"];
|
|
|
|
public static readonly string[] Sources =
|
|
["홈페이지 문의", "소개", "직접 방문", "카카오 채널", "블로그", "기타"];
|
|
|
|
public async Task<(IEnumerable<Client> Items, int Total)> GetPagedAsync(
|
|
int page, int pageSize, string? status = null, string? search = null, CancellationToken ct = default) =>
|
|
await repository.GetPagedAsync(Math.Max(1, page), Math.Clamp(pageSize, 1, 100), status, search, ct);
|
|
|
|
public async Task<Client?> GetByIdAsync(int id, CancellationToken ct = default) =>
|
|
await repository.GetByIdAsync(id, ct);
|
|
|
|
public async Task<int> CreateAsync(CreateClientDto dto, CancellationToken ct = default)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(dto.Name))
|
|
throw new ValidationException("고객명을 입력하세요.");
|
|
|
|
var client = new Client
|
|
{
|
|
Name = dto.Name.Trim(),
|
|
CompanyName = dto.CompanyName?.Trim(),
|
|
Phone = dto.Phone?.Trim(),
|
|
Email = dto.Email?.Trim(),
|
|
ServiceType = dto.ServiceType,
|
|
TaxType = dto.TaxType,
|
|
Status = dto.Status,
|
|
Source = dto.Source,
|
|
Memo = dto.Memo?.Trim()
|
|
};
|
|
|
|
return await repository.CreateAsync(client, ct);
|
|
}
|
|
|
|
public async Task UpdateAsync(int id, CreateClientDto dto, CancellationToken ct = default)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(dto.Name))
|
|
throw new ValidationException("고객명을 입력하세요.");
|
|
|
|
var client = await repository.GetByIdAsync(id, ct)
|
|
?? throw new KeyNotFoundException($"고객 ID {id}를 찾을 수 없습니다.");
|
|
|
|
client.Name = dto.Name.Trim();
|
|
client.CompanyName = dto.CompanyName?.Trim();
|
|
client.Phone = dto.Phone?.Trim();
|
|
client.Email = dto.Email?.Trim();
|
|
client.ServiceType = dto.ServiceType;
|
|
client.TaxType = dto.TaxType;
|
|
client.Status = dto.Status;
|
|
client.Source = dto.Source;
|
|
client.Memo = dto.Memo?.Trim();
|
|
|
|
await repository.UpdateAsync(client, ct);
|
|
}
|
|
|
|
public async Task DeleteAsync(int id, CancellationToken ct = default) =>
|
|
await repository.DeleteAsync(id, ct);
|
|
}
|