backend phase 11

This commit is contained in:
hamid
2026-07-09 02:13:30 +03:30
parent 23605591eb
commit 465f75c29e
78 changed files with 9555 additions and 27 deletions
@@ -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..]}";
}
}