feat: P6 후속 — PWA 출금폼/명세상세/토큰refresh + 펌뱅킹 SETTLED 동기화 + user phone UI
외부 SDK 차단 항목 외 P6 잔여 운영성 작업을 일괄 완료. DB 변경 없음(v85 유지).
PWA:
- 출금 신청 작성 폼 (WithdrawCreate.tsx + POST /api/mobile/me/withdraw-requests + GET /settle-masters)
· 클라이언트가 보낸 agentId/userId 무시, 토큰에서 강제 결정
- 명세서 상세 + 엑셀 다운로드 (StatementDetail.tsx + GET /api/mobile/me/statements/{id}[/download])
· 본인 agentId 검증 후 기존 CommissionStatementService.download() 재사용
- 토큰 자동 refresh (request.ts interceptor + authStore.refreshToken)
· 401 시 단일 refresh 호출로 합치고 broadcast, login/refresh 자체 401 은 무한루프 차단
펌뱅킹 SETTLED 동기화:
- WithdrawBankSettleService + POST /api/internal/bank-settle (BankSettleController)
- Mapper: selectAcceptedTransfers / markSettled / markSettleFailed
- 어댑터 queryStatus 폴링 결과로 SETTLED→COMPLETED, FAILED→APPROVED(재시도풀) 전이
- app.bank-settle.cron 옵션 (기본 비활성)
사용자 phone 등록 UI:
- PUT /api/system/users/{id}/phone — NotBlank 검증 없는 단일 패치 endpoint
- UserList 에 phone 컬럼 + "전화번호" 액션 → Antd Modal 인라인 편집
- 결재 SMS 발신 전제 충족
검증 (9/9 PASS, 라이브):
- ga-common/ga-core/ga-external-adapter/ga-api compileJava BUILD SUCCESSFUL
- ga-frontend / ga-mobile-pwa tsc --noEmit PASS
- POST /api/internal/bank-settle → data=3 (3건 COMPLETED 전이 확인)
- PUT /api/system/users/1/phone → 200, 이후 GET 으로 phone 노출 확인
- 보안 강제: admin(agentId=null)으로 /api/mobile/me/{statements,settle-masters,withdraw-requests} → E403
- POST /api/auth/refresh → 200, 새 accessToken 발급
- 3개 서비스 라이브: ga-api :8082 / ga-frontend :3000 / ga-mobile-pwa :3001
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -26,6 +26,7 @@ public interface UserMapper {
|
||||
int incrementFailCount(@Param("userId") Long userId);
|
||||
int resetFailCount(@Param("userId") Long userId);
|
||||
int updateStatus(@Param("userId") Long userId, @Param("status") String status);
|
||||
int updatePhone(@Param("userId") Long userId, @Param("phone") String phone);
|
||||
|
||||
List<String> selectRoleCodes(@Param("userId") Long userId);
|
||||
|
||||
|
||||
@@ -33,4 +33,17 @@ public interface WithdrawRequestMapper {
|
||||
* account_no 는 복호화되어 반환.
|
||||
*/
|
||||
List<WithdrawRequestVO> selectFailedTransfers(@Param("limit") int limit);
|
||||
|
||||
/**
|
||||
* SETTLED 동기화 대상 — transfer_status='ACCEPTED' 이고 status='SENT'.
|
||||
* queryStatus 폴링 결과로 입금 확정/실패를 판정한다.
|
||||
*/
|
||||
List<WithdrawRequestVO> selectAcceptedTransfers(@Param("limit") int limit);
|
||||
|
||||
/** queryStatus 가 SETTLED 응답: status='COMPLETED', transfer_status='SETTLED', completed_at=NOW(). */
|
||||
int markSettled(@Param("requestId") Long requestId);
|
||||
|
||||
/** queryStatus 가 FAILED 응답: status='APPROVED'(재시도 풀로), transfer_status='FAILED', fail_reason. */
|
||||
int markSettleFailed(@Param("requestId") Long requestId,
|
||||
@Param("failReason") String failReason);
|
||||
}
|
||||
|
||||
@@ -110,6 +110,10 @@
|
||||
UPDATE users SET status = #{status} WHERE user_id = #{userId}
|
||||
</update>
|
||||
|
||||
<update id="updatePhone">
|
||||
UPDATE users SET phone = #{phone,jdbcType=VARCHAR} WHERE user_id = #{userId}
|
||||
</update>
|
||||
|
||||
<select id="selectRoleCodes" resultType="string">
|
||||
SELECT r.role_code FROM role r
|
||||
JOIN user_role ur ON ur.role_id = r.role_id
|
||||
|
||||
@@ -176,4 +176,43 @@
|
||||
WHERE request_id = #{requestId}
|
||||
</update>
|
||||
|
||||
<!-- SETTLED 동기화 대상 — 펌뱅킹 어댑터로 보냈고(SENT) 외부 응답이 접수만(ACCEPTED) 된 건 -->
|
||||
<select id="selectAcceptedTransfers" resultMap="VOMap">
|
||||
SELECT wr.request_id, wr.settle_master_id, wr.agent_id, wr.amount,
|
||||
wr.requested_by, wr.requested_at, wr.approval_request_id,
|
||||
wr.bank_code, wr.account_no, wr.status,
|
||||
wr.sent_at, wr.completed_at, wr.fail_reason,
|
||||
wr.transfer_tx_id, wr.transfer_status, wr.transfer_at,
|
||||
wr.created_at, wr.updated_at
|
||||
FROM withdraw_request wr
|
||||
WHERE wr.transfer_status = 'ACCEPTED'
|
||||
AND wr.status = 'SENT'
|
||||
AND wr.transfer_tx_id IS NOT NULL
|
||||
ORDER BY wr.transfer_at NULLS FIRST, wr.request_id
|
||||
LIMIT #{limit}
|
||||
</select>
|
||||
|
||||
<!-- 입금 확정 — SETTLED -->
|
||||
<update id="markSettled">
|
||||
UPDATE withdraw_request
|
||||
SET transfer_status = 'SETTLED',
|
||||
status = 'COMPLETED',
|
||||
completed_at = NOW(),
|
||||
fail_reason = NULL,
|
||||
updated_at = NOW()
|
||||
WHERE request_id = #{requestId}
|
||||
AND status = 'SENT'
|
||||
</update>
|
||||
|
||||
<!-- 입금 실패 동기화 — 재시도 풀(APPROVED + FAILED) 로 회귀 -->
|
||||
<update id="markSettleFailed">
|
||||
UPDATE withdraw_request
|
||||
SET transfer_status = 'FAILED',
|
||||
status = 'APPROVED',
|
||||
fail_reason = #{failReason,jdbcType=VARCHAR},
|
||||
updated_at = NOW()
|
||||
WHERE request_id = #{requestId}
|
||||
AND status = 'SENT'
|
||||
</update>
|
||||
|
||||
</mapper>
|
||||
|
||||
Reference in New Issue
Block a user