using System.Globalization; using AMREZ.EOP.Abstractions.Applications.UseCases.Payments.SlipVerification; using AMREZ.EOP.Abstractions.Applications.UseCases.Payments.SlipVerification.QrDecode; using AMREZ.EOP.Abstractions.Infrastructures.Integrations.SCB.Clients; using AMREZ.EOP.Application.UseCases.Payments.SlipVerification.BankDetect; using AMREZ.EOP.Application.UseCases.Payments.SlipVerification.QrDecode; using AMREZ.EOP.Contracts.DTOs.Payments.SlipVerification; using AMREZ.EOP.Domain.Shared.Payments; namespace AMREZ.EOP.Application.UseCases.Payments.SlipVerification; public sealed class VerifyFromImageUseCase : IVerifyFromImageUseCase { private readonly IQrDecoder _qr; private readonly IScbSlipClient _scb; private readonly SCBOptions _opts; public VerifyFromImageUseCase(IQrDecoder qr, IScbSlipClient scb, SCBOptions opts) { _qr = qr; _scb = scb; _opts = opts; } public async Task ExecuteAsync(VerifyFromImageRequest request, CancellationToken ct) { await using var ms = new MemoryStream(); await request.Image.CopyToAsync(ms, ct); var qrText = _qr.TryDecodeText(ms.ToArray()); var transId = TransRefParser.TryExtract(qrText); var bank = ParserBankDetect.FromQrText(qrText) ?? _opts.DefaultSendingBank; if (string.IsNullOrWhiteSpace(transId)) return null; // ไม่มี id ก็หยุด // ← SCB API ต้องการ “id” (transRef/txnId) + sendingBank เท่านั้น var env = await _scb.VerifyAsync(transId, bank, ct); if (env?.Status?.Code != 1000 || env.Data is null) return null; // 3) map → controller response var d = env.Data; var amount = decimal.TryParse(d.PaidLocalAmount ?? d.Amount ?? "0", NumberStyles.Any, CultureInfo.InvariantCulture, out var v) ? v : 0m; var when = CombineBangkok(d.TransDate, d.TransTime); var msisdn = d.Sender?.Proxy?.Type == "MSISDN" ? d.Sender.Proxy.Value : null; var biller = d.Receiver?.Proxy?.Type == "BILLERID" ? d.Receiver.Proxy.Value : null; return new VerifyFromImageResponse { TransRef = d.TransRef ?? transId, SendingBank = bank, AmountTHB = amount, CurrencyNumeric = d.PaidLocalCurrency ?? "764", SenderMsisdn = msisdn, BillerId = biller, TransactedAt = when }; } private static DateTimeOffset CombineBangkok(string? date, string? time) { if (string.IsNullOrWhiteSpace(date) || string.IsNullOrWhiteSpace(time)) return DateTimeOffset.UtcNow; // fallback var dt = DateTime.ParseExact($"{date} {time}", "yyyyMMdd HH:mm:ss", CultureInfo.InvariantCulture); var local = DateTime.SpecifyKind(dt, DateTimeKind.Unspecified); TimeZoneInfo? tz = null; try { tz = TimeZoneInfo.FindSystemTimeZoneById("Asia/Bangkok"); } catch { } if (tz is null) try { tz = TimeZoneInfo.FindSystemTimeZoneById("SE Asia Standard Time"); } catch { } return tz is null ? new DateTimeOffset(local, TimeSpan.FromHours(7)) : new DateTimeOffset(local, tz.GetUtcOffset(local)); } }