feat(ledger): 거래 단계별 처리시각 기록·조회 및 pacs.002 결과통보 조회

- transfer에 pdng_at(Dior)·acsp_at(Hermes) 컬럼 추가(V5), Dior/Hermes가 각 단계 처리시각 기록
- Chanel /inquiry 응답에 접수·순번·기록·정산·완결 5단계 시각(rcvdAt/actcAt/pdngAt/acspAt/acccAt) 노출
- 경합 안전 upsert(Dior COALESCE, Hermes acsp_at 갱신·pdng_at 보존)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
rtgs
2026-07-16 13:40:46 +09:00
parent 58ca23b5d9
commit ffbeb35d18
7 changed files with 42 additions and 15 deletions

View File

@@ -2,6 +2,7 @@ package kr.or.bok.rtgs.chanel
import kr.or.bok.rtgs.chanel.jpa.AccountRepository
import kr.or.bok.rtgs.chanel.jpa.NotificationRepository
import kr.or.bok.rtgs.chanel.jpa.RawMessageRepository
import kr.or.bok.rtgs.chanel.jpa.TransferRepository
import kr.or.bok.rtgs.common.iso20022.Iso20022Codec
import org.springframework.http.MediaType
@@ -21,6 +22,7 @@ class ChanelController(
private val transfers: TransferRepository,
private val accounts: AccountRepository,
private val notifications: NotificationRepository,
private val rawMessages: RawMessageRepository,
) {
/** 자금이체 신청/접수: pacs.008 XML → pacs.002 XML. */
@PostMapping(
@@ -31,11 +33,13 @@ class ChanelController(
fun payCustomer(@RequestBody rawXml: String): String =
Iso20022Codec.writePacs002(service.accept(rawXml))
/** 거래 상태 조회. */
/** 거래 상태 조회. 서비스별 단계 처리시각(타임라인) 포함. */
@GetMapping("/inquiry/{bmi}")
fun inquiry(@PathVariable bmi: String): Map<String, Any?> {
val t = transfers.findById(bmi).orElse(null)
?: return mapOf("bmi" to bmi, "status" to "IN_FLIGHT", "note" to "not yet persisted")
val finalized = t.status.name == "ACCC" || t.status.name == "RJCT"
val rcvdAt = rawMessages.findById(bmi).orElse(null)?.receivedAt
return mapOf(
"bmi" to t.bmi,
"globalSeq" to t.globalSeq,
@@ -46,6 +50,12 @@ class ChanelController(
"originCenter" to t.originCenter,
"updatedAt" to t.updatedAt,
"reason" to t.reason,
// 서비스별 처리시각(epoch ms). 접수=Chanel, 순번=Sequencer, 기록=Dior, 정산=Hermes, 완결=Prada.
"rcvdAt" to rcvdAt,
"actcAt" to t.createdAt,
"pdngAt" to t.pdngAt,
"acspAt" to t.acspAt,
"acccAt" to if (finalized) t.updatedAt else null,
)
}