backend phase 11
This commit is contained in:
+144
@@ -0,0 +1,144 @@
|
||||
#nullable enable
|
||||
using Baya.Application.Contracts.Persistence;
|
||||
using Baya.Application.Models.Common;
|
||||
using Baya.Application.Models.Refunds;
|
||||
using Baya.Domain.Entities.Booking;
|
||||
using Baya.Domain.Entities.Identity;
|
||||
using Baya.Domain.Entities.Payments;
|
||||
using Baya.Domain.Entities.Refunds;
|
||||
using Baya.Infrastructure.Persistence.Repositories.Common;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Baya.Infrastructure.Persistence.Repositories;
|
||||
|
||||
internal sealed class RefundRepository : BaseAsyncRepository<Refund>, IRefundRepository
|
||||
{
|
||||
public RefundRepository(ApplicationDbContext dbContext) : base(dbContext)
|
||||
{
|
||||
}
|
||||
|
||||
public Task<RefundMoneyContext?> GetRefundContextAsync(long bookingId, CancellationToken cancellationToken)
|
||||
=> (from t in DbContext.Set<PaymentTransaction>().AsNoTracking()
|
||||
where t.BookingId == bookingId && t.Status == PaymentTransactionStatus.Succeeded
|
||||
join b in DbContext.Set<Booking>() on t.BookingId equals b.Id
|
||||
join c in DbContext.Set<CustomerProfile>() on b.CustomerId equals c.Id
|
||||
join g in DbContext.Set<PaymentGateway>() on t.GatewayId equals g.Id
|
||||
select new RefundMoneyContext(
|
||||
b.Id,
|
||||
b.CustomerId,
|
||||
c.UserId,
|
||||
b.NurseId,
|
||||
b.GrossPriceIrr,
|
||||
b.BalinyaarCommissionIrr,
|
||||
b.NursePayoutAmount,
|
||||
b.CancellationPolicyCode,
|
||||
b.CancellationRefundPercentage,
|
||||
b.RefundableAmountIrr,
|
||||
t.Id,
|
||||
t.GatewayReferenceCode,
|
||||
t.Amount,
|
||||
g.Type))
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
|
||||
public async Task<long> GetRefundedSumForTransactionAsync(long paymentTransactionId, CancellationToken cancellationToken)
|
||||
=> await TableNoTracking
|
||||
.Where(r => r.PaymentTransactionId == paymentTransactionId
|
||||
&& r.Status != RefundStatus.Failed && r.Status != RefundStatus.Rejected)
|
||||
.SumAsync(r => (long?)r.Amount, cancellationToken) ?? 0;
|
||||
|
||||
public Task AddRefundAsync(Refund refund, CancellationToken cancellationToken)
|
||||
=> base.AddAsync(refund);
|
||||
|
||||
public Task AddClawbackAsync(NurseClawback clawback, CancellationToken cancellationToken)
|
||||
=> DbContext.Set<NurseClawback>().AddAsync(clawback, cancellationToken).AsTask();
|
||||
|
||||
public Task<NurseClawback?> GetTrackedClawbackByIdAsync(long id, CancellationToken cancellationToken)
|
||||
=> DbContext.Set<NurseClawback>().FirstOrDefaultAsync(c => c.Id == id, cancellationToken);
|
||||
|
||||
public async Task<PagedResult<RefundListItemDto>> ListAsync(long? bookingId, string? status, int page, int pageSize, CancellationToken cancellationToken)
|
||||
{
|
||||
var query = TableNoTracking;
|
||||
if (bookingId is { } bid)
|
||||
query = query.Where(r => r.BookingId == bid);
|
||||
if (!string.IsNullOrWhiteSpace(status))
|
||||
query = query.Where(r => r.Status == status);
|
||||
|
||||
var total = await query.CountAsync(cancellationToken);
|
||||
|
||||
var rows = await query
|
||||
.OrderByDescending(r => r.Id)
|
||||
.Skip((page - 1) * pageSize)
|
||||
.Take(pageSize)
|
||||
.Select(r => new
|
||||
{
|
||||
r.Id,
|
||||
r.BookingId,
|
||||
r.PaymentTransactionId,
|
||||
r.Amount,
|
||||
r.PlatformFeeRefundedIrr,
|
||||
r.NursePayoutRefundedIrr,
|
||||
r.RefundChannel,
|
||||
r.Status,
|
||||
r.RefundPercentage,
|
||||
r.ReasonCategory,
|
||||
r.CancellationPolicyCode,
|
||||
r.RefundPercentageApplied,
|
||||
r.ExpectedCustomerRefundEta,
|
||||
r.GatewayRefundReference,
|
||||
r.ExternalRevertReference,
|
||||
r.ProcessedAt,
|
||||
r.CreatedAt
|
||||
})
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
var items = rows
|
||||
.Select(r => new RefundListItemDto(
|
||||
r.Id, r.BookingId, r.PaymentTransactionId,
|
||||
r.Amount.ToString(), r.PlatformFeeRefundedIrr.ToString(), r.NursePayoutRefundedIrr.ToString(),
|
||||
r.RefundChannel, r.Status, r.RefundPercentage, r.ReasonCategory,
|
||||
r.CancellationPolicyCode, r.RefundPercentageApplied, r.ExpectedCustomerRefundEta,
|
||||
r.GatewayRefundReference, r.ExternalRevertReference, r.ProcessedAt, r.CreatedAt))
|
||||
.ToList();
|
||||
|
||||
return new PagedResult<RefundListItemDto>(items, total, page, pageSize);
|
||||
}
|
||||
|
||||
public async Task<RefundStatusProjection?> GetStatusAsync(long id, CancellationToken cancellationToken)
|
||||
{
|
||||
var row = await (from r in TableNoTracking
|
||||
where r.Id == id
|
||||
join b in DbContext.Set<Booking>() on r.BookingId equals b.Id
|
||||
join c in DbContext.Set<CustomerProfile>() on b.CustomerId equals c.Id
|
||||
select new
|
||||
{
|
||||
c.UserId,
|
||||
r.Id,
|
||||
r.BookingId,
|
||||
r.Status,
|
||||
r.RefundChannel,
|
||||
r.Amount,
|
||||
r.ExpectedCustomerRefundEta,
|
||||
r.GatewayRefundReference,
|
||||
r.ExternalRevertReference
|
||||
})
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
|
||||
if (row is null)
|
||||
return null;
|
||||
|
||||
var reference = Mask(row.GatewayRefundReference ?? row.ExternalRevertReference);
|
||||
var dto = new RefundStatusDto(row.Id, row.BookingId, row.Status, row.RefundChannel, row.Amount.ToString(),
|
||||
row.ExpectedCustomerRefundEta, reference);
|
||||
return new RefundStatusProjection(row.UserId, dto);
|
||||
}
|
||||
|
||||
// Show only the last 4 characters of an external reference to the customer — never the full PSP/BNPL id.
|
||||
private static string? Mask(string? reference)
|
||||
{
|
||||
if (string.IsNullOrEmpty(reference))
|
||||
return reference;
|
||||
return reference.Length <= 4
|
||||
? new string('•', reference.Length)
|
||||
: $"{new string('•', reference.Length - 4)}{reference[^4..]}";
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user