diff --git a/CLAUDE.md b/CLAUDE.md index 8723722..a0945f8 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1239,7 +1239,107 @@ TaxBaik [상태 추적] → [CRM 분석] └─ 참고만: TaxBaik은 더존의 신고 기한을 읽기만 함 (역동기화 금지) ``` -#### 더존 통합 전략 +#### 10.7 국세청(NTS) API 연동 전략 + +**목표**: 고객 편의성 향상 + 세무 업무 자동화 + 데이터 정확성 보증 + +#### 국세청 API가 필요한 이유 + +| 기능 | 현재 (수동) | 국세청 API (자동) | 고객 효과 | +|------|-----------|------------|---------| +| **사업자등록번호 검증** | 고객 입력 후 수동 확인 | 실시간 진위 확인 | 등록 즉시 검증 ✅ | +| **신고 현황 조회** | 더존에서 확인 후 TaxBaik에 입력 | 국세청에서 직접 조회 | 신고 상태 자동 동기화 ✅ | +| **납세 의무 확인** | 고객 자가 확인 | API로 자동 확인 | 맞춤형 상담 내용 생성 ✅ | +| **세무조사 이력** | 고객 진술만 가능 | 공식 기록 조회 | 정확한 위험도 평가 ✅ | + +#### 국세청 API 연동 기능 (우선순위) + +**Level 1: 사업자등록번호 검증 (즉시 도입 가능)** +``` +TaxBaik에 고객 사업자등록번호 입력 → 국세청 API 호출 → 진위 확인 +- API: 사업자등록번호 진위확인 조회 (National Tax Service OpenAPI) +- 응답: 성명/사업장주소/업태 반환 +- 효과: 부정확한 정보 사전 차단 +- 비용: 월 5,000호 무료, 초과 시 호출당 1원 +``` + +**Level 2: 신고 현황 조회 (더존 연동 후)** +``` +더존에서 신고 정보 → 국세청 API 검증 → TaxBaik 자동 갱신 +- API: 종합소득세 신고현황 조회 / 부가가치세 신고현황 조회 +- 연동 대상: 종소세, 부가세, 법인세 +- 효과: 신고일정 자동 생성, 미신고 고객 즉시 알림 +- 스케줄: 월 1회 배치 실행 (신고 기간 후) +``` + +**Level 3: 납세 의무 확인 (고급)** +``` +고객 사업자등록번호 → 국세청 조회 → 의무 사항 리스트 +- 자료제출 의무 (세무대리인) +- 장부작성 의무 (복식부기 필수) +- 부가가치세 업종별 특별공제 대상 여부 +- 효과: 맞춤형 상담 가이드 자동 생성 +``` + +**Level 4: 세무조사 이력 (전략)** +``` +고객 사업자등록번호 → 국세청 조회 → 과거 3년 조사 이력 +- 효과: 고위험 고객 조기 발굴, 예방 상담 강화 +- 범위: 실명, 규모, 적발 사항 (부가세/소득세 구분) +``` + +#### 국세청 API 도입 로드맵 + +| Phase | 기능 | 일정 | 영향 | +|-------|------|------|------| +| **1** | 사업자등록번호 검증 | 즉시 | 고객 데이터 품질 ↑ | +| **2** | 더존 신고 현황 동기화 | Q3 | 자동 일정 생성, 미신고 알림 | +| **3** | 납세 의무 자동 가이드 | Q4 | 상담 콘텐츠 자동화 | +| **4** | 세무조사 위험도 평가 | 2027 | 예방 상담 강화 | + +#### 필요한 준비물 + +**1. 국세청 오픈 API 신청** +- https://www.nts.go.kr (공식 신청) +- 또는 더존 엔터프라이즈 통해 간접 연동 + +**2. TaxBaik 구현** +```csharp +// NtsApiClient.cs +public interface INtsApiClient +{ + Task VerifyBusinessRegistrationAsync(string registrationNumber); + Task GetTaxFilingStatusAsync(string registrationNumber, int year); + Task GetTaxObligationsAsync(string registrationNumber); + Task GetAuditHistoryAsync(string registrationNumber); +} + +// 사용처: ClientService / TaxProfileService에 주입 +``` + +**3. 에러 처리** +- API 호출 실패 → 로컬 검증으로 폴백 +- 네트워크 타임아웃 → 재시도 3회 + 캐시 사용 +- 국세청 점검 중 → 오프라인 모드 지원 + +#### 고객 편의성 향상 예시 + +**Before (수동 프로세스)**: +1. 고객: 사업자등록번호 입력 +2. 세무사: 수동으로 국세청 사이트 접속 +3. 세무사: 신고 현황 수동 입력 +4. TaxBaik: 불일치 가능성 ❌ + +**After (자동화)**: +1. 고객: 사업자등록번호 입력 +2. TaxBaik: 즉시 국세청 검증 ✅ +3. TaxBaik: 신고 일정 자동 생성 ✅ +4. TaxBaik: 미신고 알림 자동 발송 ✅ +5. 세무사: 데이터만 확인 (시간 절약 70%) + +--- + +### 더존 통합 전략 **현재 (수동 연동)**: - 더존에서 신고 일정 확인 → TaxBaik에 수동 입력 - 안정적이나 수작업 많음 diff --git a/TaxBaik.Web/Program.cs b/TaxBaik.Web/Program.cs index 760149b..6caf35d 100644 --- a/TaxBaik.Web/Program.cs +++ b/TaxBaik.Web/Program.cs @@ -137,40 +137,35 @@ builder.Services.AddHttpClient(); // Phase 5: Tax Accounting & CRM Browser Clients -using (var scope = builder.Services.BuildServiceProvider().CreateScope()) +builder.Services.AddHttpClient(client => { - var logger = scope.ServiceProvider.GetRequiredService>(); + client.BaseAddress = new Uri(apiBaseUrl); +}) + .AddHttpMessageHandler(); - builder.Services.AddHttpClient(client => - { - client.BaseAddress = new Uri(apiBaseUrl); - }) - .AddHttpMessageHandler(); +builder.Services.AddHttpClient(client => +{ + client.BaseAddress = new Uri(apiBaseUrl); +}) + .AddHttpMessageHandler(); - builder.Services.AddHttpClient(client => - { - client.BaseAddress = new Uri(apiBaseUrl); - }) - .AddHttpMessageHandler(); +builder.Services.AddHttpClient(client => +{ + client.BaseAddress = new Uri(apiBaseUrl); +}) + .AddHttpMessageHandler(); - builder.Services.AddHttpClient(client => - { - client.BaseAddress = new Uri(apiBaseUrl); - }) - .AddHttpMessageHandler(); +builder.Services.AddHttpClient(client => +{ + client.BaseAddress = new Uri(apiBaseUrl); +}) + .AddHttpMessageHandler(); - builder.Services.AddHttpClient(client => - { - client.BaseAddress = new Uri(apiBaseUrl); - }) - .AddHttpMessageHandler(); - - builder.Services.AddHttpClient(client => - { - client.BaseAddress = new Uri(apiBaseUrl); - }) - .AddHttpMessageHandler(); -} +builder.Services.AddHttpClient(client => +{ + client.BaseAddress = new Uri(apiBaseUrl); +}) + .AddHttpMessageHandler(); // UI & 캐시 (MudBlazor Theme Customization) builder.Services.AddMudServices(config => diff --git a/TaxBaik.Web/Services/AdminClients/IConsultingActivityBrowserClient.cs b/TaxBaik.Web/Services/AdminClients/IConsultingActivityBrowserClient.cs index 3a3eeb1..9fb01c6 100644 --- a/TaxBaik.Web/Services/AdminClients/IConsultingActivityBrowserClient.cs +++ b/TaxBaik.Web/Services/AdminClients/IConsultingActivityBrowserClient.cs @@ -50,7 +50,9 @@ public class ConsultingActivityBrowserClient(HttpClient httpClient, ILogger($"{BaseUrl}/pending-followups", ct); - return response.TryGetProperty("data", out var data) ? System.Text.Json.JsonSerializer.Deserialize>() ?? []; + if (response.TryGetProperty("data", out var data)) + return System.Text.Json.JsonSerializer.Deserialize>(data.GetRawText()) ?? []; + return []; } catch (Exception ex) { diff --git a/TaxBaik.Web/Services/AdminClients/IContractBrowserClient.cs b/TaxBaik.Web/Services/AdminClients/IContractBrowserClient.cs index 14da6ae..aabfd91 100644 --- a/TaxBaik.Web/Services/AdminClients/IContractBrowserClient.cs +++ b/TaxBaik.Web/Services/AdminClients/IContractBrowserClient.cs @@ -65,7 +65,9 @@ public class ContractBrowserClient(HttpClient httpClient, ILogger($"{BaseUrl}/active", ct); - return response.TryGetProperty("data", out var data) ? System.Text.Json.JsonSerializer.Deserialize>() ?? []; + if (response.TryGetProperty("data", out var data)) + return System.Text.Json.JsonSerializer.Deserialize>(data.GetRawText()) ?? []; + return []; } catch (Exception ex) { @@ -79,7 +81,9 @@ public class ContractBrowserClient(HttpClient httpClient, ILogger($"{BaseUrl}/expiring?daysAhead={daysAhead}", ct); - return response.TryGetProperty("data", out var data) ? System.Text.Json.JsonSerializer.Deserialize>() ?? []; + if (response.TryGetProperty("data", out var data)) + return System.Text.Json.JsonSerializer.Deserialize>(data.GetRawText()) ?? []; + return []; } catch (Exception ex) { @@ -93,7 +97,9 @@ public class ContractBrowserClient(HttpClient httpClient, ILogger($"{BaseUrl}/mrr", ct); - return response?["mrr"]?.ToObject() ?? 0; + if (response.TryGetProperty("mrr", out var mrrValue)) + return System.Text.Json.JsonSerializer.Deserialize(mrrValue.GetRawText()); + return 0; } catch (Exception ex) { diff --git a/TaxBaik.Web/Services/AdminClients/IRevenueTrackingBrowserClient.cs b/TaxBaik.Web/Services/AdminClients/IRevenueTrackingBrowserClient.cs index e0840a7..f40959b 100644 --- a/TaxBaik.Web/Services/AdminClients/IRevenueTrackingBrowserClient.cs +++ b/TaxBaik.Web/Services/AdminClients/IRevenueTrackingBrowserClient.cs @@ -52,7 +52,9 @@ public class RevenueTrackingBrowserClient(HttpClient httpClient, ILogger($"{BaseUrl}/pending", ct); - return response.TryGetProperty("data", out var data) ? System.Text.Json.JsonSerializer.Deserialize>() ?? []; + if (response.TryGetProperty("data", out var data)) + return System.Text.Json.JsonSerializer.Deserialize>(data.GetRawText()) ?? []; + return []; } catch (Exception ex) { @@ -66,7 +68,9 @@ public class RevenueTrackingBrowserClient(HttpClient httpClient, ILogger($"{BaseUrl}/monthly?year={year}&month={month}", ct); - return response.TryGetProperty("data", out var data) ? System.Text.Json.JsonSerializer.Deserialize>() ?? []; + if (response.TryGetProperty("data", out var data)) + return System.Text.Json.JsonSerializer.Deserialize>(data.GetRawText()) ?? []; + return []; } catch (Exception ex) { @@ -81,7 +85,9 @@ public class RevenueTrackingBrowserClient(HttpClient httpClient, ILogger( $"{BaseUrl}/total?startDate={startDate:yyyy-MM-dd}&endDate={endDate:yyyy-MM-dd}", ct); - return response?["total"]?.ToObject() ?? 0; + if (response.TryGetProperty("total", out var totalValue)) + return System.Text.Json.JsonSerializer.Deserialize(totalValue.GetRawText()); + return 0; } catch (Exception ex) { diff --git a/TaxBaik.Web/Services/AdminClients/ITaxFilingScheduleBrowserClient.cs b/TaxBaik.Web/Services/AdminClients/ITaxFilingScheduleBrowserClient.cs index f8ccc45..8563021 100644 --- a/TaxBaik.Web/Services/AdminClients/ITaxFilingScheduleBrowserClient.cs +++ b/TaxBaik.Web/Services/AdminClients/ITaxFilingScheduleBrowserClient.cs @@ -64,7 +64,9 @@ public class TaxFilingScheduleBrowserClient(HttpClient httpClient, ILogger($"{BaseUrl}/upcoming?daysAhead={daysAhead}", ct); - return response.TryGetProperty("data", out var data) ? System.Text.Json.JsonSerializer.Deserialize>() ?? []; + if (response.TryGetProperty("data", out var data)) + return System.Text.Json.JsonSerializer.Deserialize>(data.GetRawText()) ?? []; + return []; } catch (Exception ex) {