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