From 33470d5fd4b076295d8f6dcff36ecdbe309dde51 Mon Sep 17 00:00:00 2001
From: Thanakarn Klangkasame <77600906+Simulationable@users.noreply.github.com>
Date: Thu, 2 Oct 2025 17:50:35 +0700
Subject: [PATCH] Add Slip Verify
---
AMREZ.EOP.API/Controllers/SCBController.cs | 41 +++++++++++++++++++
.../IVerifyFromImageUseCase.cs | 8 ++++
.../SlipVerification/QrDecode/IQrDecoder.cs | 6 +++
.../SCB/Clients/IScbSlipClient.cs | 6 +++
.../BankDetect/ParserBankDetect.cs | 25 +++++++++++
.../QrDecode/TransRefParser.cs | 6 +++
.../QrDecode/ZxingQrDecoder.cs | 6 +++
.../VerifyFromImageUseCase.cs | 6 +++
.../DTOs/Integrations/SCB/Common/SCBStatus.cs | 6 +++
.../Integrations/SCB/OAuth/OAuthRequest.cs | 6 +++
.../Integrations/SCB/OAuth/OAuthResponse.cs | 6 +++
.../SlipVerificationEnvelope.cs | 6 +++
.../VerifyFromImageRequest.cs | 6 +++
.../VerifyFromImageResponse.cs | 6 +++
.../Shared/Payments/SCBOptions.cs | 6 +++
.../Integrations/SCB/Clients/ScbSlipClient.cs | 6 +++
16 files changed, 152 insertions(+)
create mode 100644 AMREZ.EOP.API/Controllers/SCBController.cs
create mode 100644 AMREZ.EOP.Abstractions/Applications/UseCases/Payments/SlipVerification/IVerifyFromImageUseCase.cs
create mode 100644 AMREZ.EOP.Abstractions/Applications/UseCases/Payments/SlipVerification/QrDecode/IQrDecoder.cs
create mode 100644 AMREZ.EOP.Abstractions/Infrastructures/Integrations/SCB/Clients/IScbSlipClient.cs
create mode 100644 AMREZ.EOP.Application/UseCases/Payments/SlipVerification/BankDetect/ParserBankDetect.cs
create mode 100644 AMREZ.EOP.Application/UseCases/Payments/SlipVerification/QrDecode/TransRefParser.cs
create mode 100644 AMREZ.EOP.Application/UseCases/Payments/SlipVerification/QrDecode/ZxingQrDecoder.cs
create mode 100644 AMREZ.EOP.Application/UseCases/Payments/SlipVerification/VerifyFromImageUseCase.cs
create mode 100644 AMREZ.EOP.Contracts/DTOs/Integrations/SCB/Common/SCBStatus.cs
create mode 100644 AMREZ.EOP.Contracts/DTOs/Integrations/SCB/OAuth/OAuthRequest.cs
create mode 100644 AMREZ.EOP.Contracts/DTOs/Integrations/SCB/OAuth/OAuthResponse.cs
create mode 100644 AMREZ.EOP.Contracts/DTOs/Integrations/SCB/SlipVerification/SlipVerificationEnvelope.cs
create mode 100644 AMREZ.EOP.Contracts/DTOs/Payments/SlipVerification/VerifyFromImageRequest.cs
create mode 100644 AMREZ.EOP.Contracts/DTOs/Payments/SlipVerification/VerifyFromImageResponse.cs
create mode 100644 AMREZ.EOP.Domain/Shared/Payments/SCBOptions.cs
create mode 100644 AMREZ.EOP.Infrastructures/Integrations/SCB/Clients/ScbSlipClient.cs
diff --git a/AMREZ.EOP.API/Controllers/SCBController.cs b/AMREZ.EOP.API/Controllers/SCBController.cs
new file mode 100644
index 0000000..0aae1e6
--- /dev/null
+++ b/AMREZ.EOP.API/Controllers/SCBController.cs
@@ -0,0 +1,41 @@
+using AMREZ.EOP.Abstractions.Applications.UseCases.Payments.SlipVerification;
+using AMREZ.EOP.Contracts.DTOs.Payments.SlipVerification;
+using Microsoft.AspNetCore.Mvc;
+
+namespace AMREZ.EOP.API.Controllers;
+
+[ApiController]
+[Route("api/[controller]")]
+public class SCBController : ControllerBase
+{
+ private readonly IVerifyFromImageUseCase _verifyFromImage;
+
+ public SCBController(IVerifyFromImageUseCase verifyFromImage)
+ {
+ _verifyFromImage = verifyFromImage;
+ }
+
+ ///
+ /// อัปโหลด "รูปสลิป" เพื่อตรวจสอบกับธนาคาร (ไม่ใช้ OCR — scan QR + heuristic)
+ ///
+ [HttpPost("slips/verify")]
+ [Consumes("multipart/form-data")]
+ [RequestSizeLimit(5_000_000)]
+ public async Task VerifySlipFromImage(
+ [FromForm(Name = "Image")] IFormFile? Image,
+ [FromForm] string? OverrideSendingBank,
+ CancellationToken ct)
+ {
+ if (Image is null || Image.Length == 0)
+ return BadRequest(new { message = "Missing slip image" });
+
+ var res = await _verifyFromImage.ExecuteAsync(new VerifyFromImageRequest
+ {
+ Image = Image,
+ OverrideSendingBank = OverrideSendingBank
+ }, ct);
+
+ if (res is null) return NotFound(new { message = "Cannot extract transRef or verification failed" });
+ return Ok(res);
+ }
+}
\ No newline at end of file
diff --git a/AMREZ.EOP.Abstractions/Applications/UseCases/Payments/SlipVerification/IVerifyFromImageUseCase.cs b/AMREZ.EOP.Abstractions/Applications/UseCases/Payments/SlipVerification/IVerifyFromImageUseCase.cs
new file mode 100644
index 0000000..1bc21ff
--- /dev/null
+++ b/AMREZ.EOP.Abstractions/Applications/UseCases/Payments/SlipVerification/IVerifyFromImageUseCase.cs
@@ -0,0 +1,8 @@
+using AMREZ.EOP.Contracts.DTOs.Payments.SlipVerification;
+
+namespace AMREZ.EOP.Abstractions.Applications.UseCases.Payments;
+
+public interface IVerifyFromImageUseCase
+{
+ Task ExecuteAsync(VerifyFromImageRequest request, CancellationToken ct);
+}
diff --git a/AMREZ.EOP.Abstractions/Applications/UseCases/Payments/SlipVerification/QrDecode/IQrDecoder.cs b/AMREZ.EOP.Abstractions/Applications/UseCases/Payments/SlipVerification/QrDecode/IQrDecoder.cs
new file mode 100644
index 0000000..71342ef
--- /dev/null
+++ b/AMREZ.EOP.Abstractions/Applications/UseCases/Payments/SlipVerification/QrDecode/IQrDecoder.cs
@@ -0,0 +1,6 @@
+namespace AMREZ.EOP.Abstractions.Applications.UseCases.Payments.SlipVerification.QrDecode;
+
+public interface IQrDecoder
+{
+
+}
\ No newline at end of file
diff --git a/AMREZ.EOP.Abstractions/Infrastructures/Integrations/SCB/Clients/IScbSlipClient.cs b/AMREZ.EOP.Abstractions/Infrastructures/Integrations/SCB/Clients/IScbSlipClient.cs
new file mode 100644
index 0000000..45a1693
--- /dev/null
+++ b/AMREZ.EOP.Abstractions/Infrastructures/Integrations/SCB/Clients/IScbSlipClient.cs
@@ -0,0 +1,6 @@
+namespace AMREZ.EOP.Abstractions.Infrastructures.Integrations.SCB.Clients;
+
+public interface IScbSlipClient
+{
+
+}
\ No newline at end of file
diff --git a/AMREZ.EOP.Application/UseCases/Payments/SlipVerification/BankDetect/ParserBankDetect.cs b/AMREZ.EOP.Application/UseCases/Payments/SlipVerification/BankDetect/ParserBankDetect.cs
new file mode 100644
index 0000000..c26ba18
--- /dev/null
+++ b/AMREZ.EOP.Application/UseCases/Payments/SlipVerification/BankDetect/ParserBankDetect.cs
@@ -0,0 +1,25 @@
+using AMREZ.EOP.Abstractions.Applications.UseCases.Payments.SlipVerification.BankDetect;
+using AMREZ.EOP.Application.UseCases.Payments.SlipVerification.QrDecode;
+using SkiaSharp;
+
+namespace AMREZ.EOP.Application.UseCases.Payments.SlipVerification.BankDetect;
+
+public static class BankDetect
+{
+ // SCB=014, KBank=004
+ public static string? FromQrText(string? raw)
+ {
+ if (string.IsNullOrWhiteSpace(raw)) return null;
+
+ var id = TransRefParser.TryExtract(raw);
+ if (string.IsNullOrEmpty(id)) return null;
+
+ // เคสสลิป SCB มักขึ้นต้น "20..." (ปี+วันเวลา) → เดาว่า 014
+ if (id.StartsWith("20")) return "014";
+
+ // KBank มักเป็นตัวเลขยาวตามด้วยอักษร (เช่น 015275114427ATF02456) → เดา 004
+ if (id.Any(char.IsLetter)) return "004";
+
+ return null;
+ }
+}
diff --git a/AMREZ.EOP.Application/UseCases/Payments/SlipVerification/QrDecode/TransRefParser.cs b/AMREZ.EOP.Application/UseCases/Payments/SlipVerification/QrDecode/TransRefParser.cs
new file mode 100644
index 0000000..a1342f4
--- /dev/null
+++ b/AMREZ.EOP.Application/UseCases/Payments/SlipVerification/QrDecode/TransRefParser.cs
@@ -0,0 +1,6 @@
+namespace AMREZ.EOP.Application.UseCases.Payments.SlipVerification.QrDecode;
+
+public class TransRefParser
+{
+
+}
\ No newline at end of file
diff --git a/AMREZ.EOP.Application/UseCases/Payments/SlipVerification/QrDecode/ZxingQrDecoder.cs b/AMREZ.EOP.Application/UseCases/Payments/SlipVerification/QrDecode/ZxingQrDecoder.cs
new file mode 100644
index 0000000..ce0bd3c
--- /dev/null
+++ b/AMREZ.EOP.Application/UseCases/Payments/SlipVerification/QrDecode/ZxingQrDecoder.cs
@@ -0,0 +1,6 @@
+namespace AMREZ.EOP.Application.UseCases.Payments.SlipVerification.QrDecode;
+
+public class ZxingQrDecoder
+{
+
+}
\ No newline at end of file
diff --git a/AMREZ.EOP.Application/UseCases/Payments/SlipVerification/VerifyFromImageUseCase.cs b/AMREZ.EOP.Application/UseCases/Payments/SlipVerification/VerifyFromImageUseCase.cs
new file mode 100644
index 0000000..510508e
--- /dev/null
+++ b/AMREZ.EOP.Application/UseCases/Payments/SlipVerification/VerifyFromImageUseCase.cs
@@ -0,0 +1,6 @@
+namespace AMREZ.EOP.Application.UseCases.Payments.SlipVerification;
+
+public class VerifyFromImageUseCase
+{
+
+}
\ No newline at end of file
diff --git a/AMREZ.EOP.Contracts/DTOs/Integrations/SCB/Common/SCBStatus.cs b/AMREZ.EOP.Contracts/DTOs/Integrations/SCB/Common/SCBStatus.cs
new file mode 100644
index 0000000..4ecfd34
--- /dev/null
+++ b/AMREZ.EOP.Contracts/DTOs/Integrations/SCB/Common/SCBStatus.cs
@@ -0,0 +1,6 @@
+namespace AMREZ.EOP.Contracts.DTOs.Integrations.SCB.Common;
+
+public class SCBStatus
+{
+
+}
\ No newline at end of file
diff --git a/AMREZ.EOP.Contracts/DTOs/Integrations/SCB/OAuth/OAuthRequest.cs b/AMREZ.EOP.Contracts/DTOs/Integrations/SCB/OAuth/OAuthRequest.cs
new file mode 100644
index 0000000..bf6cc5a
--- /dev/null
+++ b/AMREZ.EOP.Contracts/DTOs/Integrations/SCB/OAuth/OAuthRequest.cs
@@ -0,0 +1,6 @@
+namespace AMREZ.EOP.Contracts.DTOs.Integrations.SCB.OAuth;
+
+public class OAuthRequest
+{
+
+}
\ No newline at end of file
diff --git a/AMREZ.EOP.Contracts/DTOs/Integrations/SCB/OAuth/OAuthResponse.cs b/AMREZ.EOP.Contracts/DTOs/Integrations/SCB/OAuth/OAuthResponse.cs
new file mode 100644
index 0000000..9e6b450
--- /dev/null
+++ b/AMREZ.EOP.Contracts/DTOs/Integrations/SCB/OAuth/OAuthResponse.cs
@@ -0,0 +1,6 @@
+namespace AMREZ.EOP.Contracts.DTOs.Integrations.SCB.OAuth;
+
+public class OAuthResponse
+{
+
+}
\ No newline at end of file
diff --git a/AMREZ.EOP.Contracts/DTOs/Integrations/SCB/SlipVerification/SlipVerificationEnvelope.cs b/AMREZ.EOP.Contracts/DTOs/Integrations/SCB/SlipVerification/SlipVerificationEnvelope.cs
new file mode 100644
index 0000000..7d11026
--- /dev/null
+++ b/AMREZ.EOP.Contracts/DTOs/Integrations/SCB/SlipVerification/SlipVerificationEnvelope.cs
@@ -0,0 +1,6 @@
+namespace AMREZ.EOP.Contracts.DTOs.Integrations.SCB.SlipVerification;
+
+public class SlipVerificationEnvelope
+{
+
+}
\ No newline at end of file
diff --git a/AMREZ.EOP.Contracts/DTOs/Payments/SlipVerification/VerifyFromImageRequest.cs b/AMREZ.EOP.Contracts/DTOs/Payments/SlipVerification/VerifyFromImageRequest.cs
new file mode 100644
index 0000000..c96d5f8
--- /dev/null
+++ b/AMREZ.EOP.Contracts/DTOs/Payments/SlipVerification/VerifyFromImageRequest.cs
@@ -0,0 +1,6 @@
+namespace AMREZ.EOP.Contracts.DTOs.Payments.SlipVerification;
+
+public class VerifyFromImageRequest
+{
+
+}
\ No newline at end of file
diff --git a/AMREZ.EOP.Contracts/DTOs/Payments/SlipVerification/VerifyFromImageResponse.cs b/AMREZ.EOP.Contracts/DTOs/Payments/SlipVerification/VerifyFromImageResponse.cs
new file mode 100644
index 0000000..139ebf9
--- /dev/null
+++ b/AMREZ.EOP.Contracts/DTOs/Payments/SlipVerification/VerifyFromImageResponse.cs
@@ -0,0 +1,6 @@
+namespace AMREZ.EOP.Contracts.DTOs.Payments.SlipVerification;
+
+public class VerifyFromImageResponse
+{
+
+}
\ No newline at end of file
diff --git a/AMREZ.EOP.Domain/Shared/Payments/SCBOptions.cs b/AMREZ.EOP.Domain/Shared/Payments/SCBOptions.cs
new file mode 100644
index 0000000..3c97a4e
--- /dev/null
+++ b/AMREZ.EOP.Domain/Shared/Payments/SCBOptions.cs
@@ -0,0 +1,6 @@
+namespace AMREZ.EOP.Domain.Shared.Payments;
+
+public class SCBOptions
+{
+
+}
\ No newline at end of file
diff --git a/AMREZ.EOP.Infrastructures/Integrations/SCB/Clients/ScbSlipClient.cs b/AMREZ.EOP.Infrastructures/Integrations/SCB/Clients/ScbSlipClient.cs
new file mode 100644
index 0000000..0af769a
--- /dev/null
+++ b/AMREZ.EOP.Infrastructures/Integrations/SCB/Clients/ScbSlipClient.cs
@@ -0,0 +1,6 @@
+namespace AMREZ.EOP.Infrastructures.Integrations.SCB.Clients;
+
+public class ScbSlipClient
+{
+
+}
\ No newline at end of file