Compare commits
3 Commits
bb20ad2c4e
...
82944e11d0
| Author | SHA1 | Date | |
|---|---|---|---|
| 82944e11d0 | |||
| ce98efdd68 | |||
| d232399f43 |
@@ -1,3 +1,4 @@
|
||||
using System.Linq.Expressions;
|
||||
using System.Linq.Dynamic.Core;
|
||||
using CMSMicroservice.Domain.Common;
|
||||
|
||||
@@ -16,6 +17,21 @@ public static class SortByExtensions
|
||||
return source.OrderBy(NormalizeSortBy(sortBy));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// موجودیدارها اول، سپس سورت درخواستی کاربر (یا Created desc اگر SortBy خالی باشد).
|
||||
/// </summary>
|
||||
public static IQueryable<TSource> ApplyOrderWithInStockPriority<TSource>(
|
||||
this IQueryable<TSource> source,
|
||||
string? sortBy,
|
||||
Expression<Func<TSource, bool>> isInStock) where TSource : BaseAuditableEntity
|
||||
{
|
||||
var ordered = source.OrderByDescending(isInStock);
|
||||
if (string.IsNullOrWhiteSpace(sortBy))
|
||||
return ordered.ThenByDescending(p => p.Created);
|
||||
|
||||
return ordered.ThenBy(NormalizeSortBy(sortBy));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dynamic LINQ treats "-Created" as unary minus on DateTime (invalid).
|
||||
/// Project convention: leading '-' means descending sort.
|
||||
|
||||
+2
-4
@@ -57,10 +57,8 @@ public class GetDiscountProductsQueryHandler : IRequestHandler<GetDiscountProduc
|
||||
query = query.Where(p => p.Price <= request.MaxPrice.Value);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(request.SortBy))
|
||||
query = query.ApplyOrder(request.SortBy);
|
||||
else
|
||||
query = query.OrderByDescending(p => p.Created);
|
||||
// موجودیدارها اول، سپس سورت درخواستی
|
||||
query = query.ApplyOrderWithInStockPriority(request.SortBy, p => p.RemainingCount > 0);
|
||||
|
||||
var totalCount = await query.CountAsync(cancellationToken);
|
||||
|
||||
|
||||
+2
-5
@@ -67,11 +67,8 @@ public class GetCustomerProductsByFilterQueryHandler : IRequestHandler<GetCustom
|
||||
if (request.IsActive.HasValue)
|
||||
query = query.Where(x => x.IsDeleted != request.IsActive.Value);
|
||||
|
||||
// Apply sorting
|
||||
if (!string.IsNullOrEmpty(request.SortBy))
|
||||
query = query.ApplyOrder(request.SortBy);
|
||||
else
|
||||
query = query.OrderByDescending(x => x.Created);
|
||||
// موجودیدارها اول، سپس سورت درخواستی
|
||||
query = query.ApplyOrderWithInStockPriority(request.SortBy, x => x.RemainingCount > 0);
|
||||
|
||||
// Pagination
|
||||
var totalCount = await query.CountAsync(cancellationToken);
|
||||
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
using MediatR;
|
||||
|
||||
namespace CMSMicroservice.Application.WalletCQ.Commands.AdminManualCreditCharge;
|
||||
|
||||
public class AdminManualCreditChargeCommand : IRequest<AdminManualCreditChargeResult>
|
||||
{
|
||||
public long UserId { get; set; }
|
||||
public long Amount { get; set; }
|
||||
public string? Note { get; set; }
|
||||
public string? PerformedByAdminId { get; set; }
|
||||
}
|
||||
|
||||
public class AdminManualCreditChargeResult
|
||||
{
|
||||
public bool Success { get; set; }
|
||||
public string Message { get; set; } = string.Empty;
|
||||
public long TransactionId { get; set; }
|
||||
public long NewBalance { get; set; }
|
||||
}
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
using CMSMicroservice.Application.Common;
|
||||
using CMSMicroservice.Application.Common.Exceptions;
|
||||
using CMSMicroservice.Application.Common.Interfaces;
|
||||
using CMSMicroservice.Domain.Entities;
|
||||
using CMSMicroservice.Domain.Enums;
|
||||
using MediatR;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace CMSMicroservice.Application.WalletCQ.Commands.AdminManualCreditCharge;
|
||||
|
||||
public class AdminManualCreditChargeCommandHandler
|
||||
: IRequestHandler<AdminManualCreditChargeCommand, AdminManualCreditChargeResult>
|
||||
{
|
||||
private readonly IApplicationDbContext _context;
|
||||
private readonly ILogger<AdminManualCreditChargeCommandHandler> _logger;
|
||||
private readonly IUserPaymentLock _paymentLock;
|
||||
|
||||
public AdminManualCreditChargeCommandHandler(
|
||||
IApplicationDbContext context,
|
||||
ILogger<AdminManualCreditChargeCommandHandler> logger,
|
||||
IUserPaymentLock paymentLock)
|
||||
{
|
||||
_context = context;
|
||||
_logger = logger;
|
||||
_paymentLock = paymentLock;
|
||||
}
|
||||
|
||||
public Task<AdminManualCreditChargeResult> Handle(
|
||||
AdminManualCreditChargeCommand request,
|
||||
CancellationToken cancellationToken) =>
|
||||
_paymentLock.ExecuteAsync(
|
||||
PaymentLockScopes.Initiate(request.UserId),
|
||||
PaymentLockStrategy.FailFast,
|
||||
ct => HandleCore(request, ct),
|
||||
cancellationToken);
|
||||
|
||||
private async Task<AdminManualCreditChargeResult> HandleCore(
|
||||
AdminManualCreditChargeCommand request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var user = await _context.Users
|
||||
.FirstOrDefaultAsync(u => u.Id == request.UserId, cancellationToken)
|
||||
?? throw new NotFoundException(nameof(User), request.UserId);
|
||||
|
||||
var wallet = await _context.UserWallets
|
||||
.FirstOrDefaultAsync(w => w.UserId == user.Id, cancellationToken)
|
||||
?? throw new NotFoundException($"کیف پول کاربر با شناسه {request.UserId} یافت نشد");
|
||||
|
||||
var oldBalance = wallet.Balance;
|
||||
wallet.Balance += request.Amount;
|
||||
|
||||
var refId = $"MANUAL-{Guid.NewGuid():N}";
|
||||
var notePart = string.IsNullOrWhiteSpace(request.Note)
|
||||
? string.Empty
|
||||
: $" — {request.Note.Trim()}";
|
||||
var adminPart = string.IsNullOrWhiteSpace(request.PerformedByAdminId)
|
||||
? string.Empty
|
||||
: $" (ادمین: {request.PerformedByAdminId})";
|
||||
|
||||
var transaction = new Transaction
|
||||
{
|
||||
Amount = request.Amount,
|
||||
Description = $"شارژ دستی کیف پول اصلی - کاربر {user.Id}{notePart}{adminPart}",
|
||||
PaymentStatus = PaymentStatus.Success,
|
||||
PaymentDate = DateTime.Now,
|
||||
RefId = refId,
|
||||
Type = TransactionType.ManualCreditWalletCharge
|
||||
};
|
||||
|
||||
_context.Transactions.Add(transaction);
|
||||
await _context.SaveChangesAsync(cancellationToken);
|
||||
|
||||
_context.UserWalletHistories.Add(new UserWalletHistory
|
||||
{
|
||||
WalletId = wallet.Id,
|
||||
CurrentBalance = wallet.Balance,
|
||||
ChangeValue = request.Amount,
|
||||
CurrentNetworkBalance = wallet.NetworkBalance,
|
||||
ChangeNerworkValue = 0,
|
||||
CurrentDiscountBalance = wallet.DiscountBalance,
|
||||
ChangeDiscountValue = 0,
|
||||
IsIncrease = true,
|
||||
RefrenceId = transaction.Id
|
||||
});
|
||||
await _context.SaveChangesAsync(cancellationToken);
|
||||
|
||||
_logger.LogInformation(
|
||||
"Manual credit charge: UserId={UserId}, Amount={Amount}, OldBalance={Old}, NewBalance={New}, TxId={TxId}, Admin={Admin}",
|
||||
user.Id,
|
||||
request.Amount,
|
||||
oldBalance,
|
||||
wallet.Balance,
|
||||
transaction.Id,
|
||||
request.PerformedByAdminId);
|
||||
|
||||
return new AdminManualCreditChargeResult
|
||||
{
|
||||
Success = true,
|
||||
Message = "شارژ دستی کیف پول اصلی با موفقیت انجام شد",
|
||||
TransactionId = transaction.Id,
|
||||
NewBalance = wallet.Balance
|
||||
};
|
||||
}
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
using CMSMicroservice.Domain.Common;
|
||||
using FluentValidation;
|
||||
|
||||
namespace CMSMicroservice.Application.WalletCQ.Commands.AdminManualCreditCharge;
|
||||
|
||||
public class AdminManualCreditChargeCommandValidator : AbstractValidator<AdminManualCreditChargeCommand>
|
||||
{
|
||||
public AdminManualCreditChargeCommandValidator()
|
||||
{
|
||||
RuleFor(x => x.UserId)
|
||||
.GreaterThan(0)
|
||||
.WithMessage("شناسه کاربر باید بزرگتر از صفر باشد");
|
||||
|
||||
RuleFor(x => x.Amount)
|
||||
.GreaterThanOrEqualTo(SystemConstants.DiscountWalletMinCharge)
|
||||
.WithMessage("حداقل مبلغ شارژ ۱۰,۰۰۰ تومان است")
|
||||
.LessThanOrEqualTo(SystemConstants.WalletMaxSafeAmount)
|
||||
.WithMessage("مبلغ وارد شده بیش از حد مجاز است");
|
||||
}
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
using CMSMicroservice.Application.Common.Models;
|
||||
using MediatR;
|
||||
|
||||
namespace CMSMicroservice.Application.WalletCQ.Queries.GetManualCreditCharges;
|
||||
|
||||
public class GetManualCreditChargesQuery : IRequest<GetManualCreditChargesResponseDto>
|
||||
{
|
||||
public PaginationState? PaginationState { get; set; }
|
||||
public string? SortBy { get; set; }
|
||||
public GetManualCreditChargesFilter? Filter { get; set; }
|
||||
}
|
||||
|
||||
public class GetManualCreditChargesFilter
|
||||
{
|
||||
public long? UserId { get; set; }
|
||||
public long? TransactionId { get; set; }
|
||||
public string? RefId { get; set; }
|
||||
public DateTime? CreatedFrom { get; set; }
|
||||
public DateTime? CreatedTo { get; set; }
|
||||
}
|
||||
|
||||
public class GetManualCreditChargesResponseDto
|
||||
{
|
||||
public MetaData MetaData { get; set; } = new();
|
||||
public List<ManualCreditChargeModelDto> Models { get; set; } = new();
|
||||
}
|
||||
|
||||
public class ManualCreditChargeModelDto
|
||||
{
|
||||
public long TransactionId { get; set; }
|
||||
public long UserId { get; set; }
|
||||
public string UserName { get; set; } = string.Empty;
|
||||
public long Amount { get; set; }
|
||||
public string Description { get; set; } = string.Empty;
|
||||
public string? RefId { get; set; }
|
||||
public long NewBalance { get; set; }
|
||||
public DateTime Created { get; set; }
|
||||
public DateTime? PaymentDate { get; set; }
|
||||
}
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
using CMSMicroservice.Application.Common.Extensions;
|
||||
using CMSMicroservice.Application.Common.Interfaces;
|
||||
using CMSMicroservice.Domain.Enums;
|
||||
using MediatR;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace CMSMicroservice.Application.WalletCQ.Queries.GetManualCreditCharges;
|
||||
|
||||
public class GetManualCreditChargesQueryHandler
|
||||
: IRequestHandler<GetManualCreditChargesQuery, GetManualCreditChargesResponseDto>
|
||||
{
|
||||
private readonly IApplicationDbContext _context;
|
||||
|
||||
public GetManualCreditChargesQueryHandler(IApplicationDbContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public async Task<GetManualCreditChargesResponseDto> Handle(
|
||||
GetManualCreditChargesQuery request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var filter = request.Filter;
|
||||
|
||||
var query =
|
||||
from t in _context.Transactions.AsNoTracking()
|
||||
where t.Type == TransactionType.ManualCreditWalletCharge
|
||||
join h in _context.UserWalletHistories.AsNoTracking() on t.Id equals h.RefrenceId
|
||||
join w in _context.UserWallets.AsNoTracking() on h.WalletId equals w.Id
|
||||
join u in _context.Users.AsNoTracking() on w.UserId equals u.Id
|
||||
select new ManualCreditChargeModelDto
|
||||
{
|
||||
TransactionId = t.Id,
|
||||
UserId = w.UserId,
|
||||
UserName = ((u.FirstName ?? "") + " " + (u.LastName ?? "")).Trim(),
|
||||
Amount = t.Amount,
|
||||
Description = t.Description ?? string.Empty,
|
||||
RefId = t.RefId,
|
||||
NewBalance = h.CurrentBalance,
|
||||
Created = t.Created,
|
||||
PaymentDate = t.PaymentDate
|
||||
};
|
||||
|
||||
if (filter?.UserId is long userId)
|
||||
query = query.Where(x => x.UserId == userId);
|
||||
|
||||
if (filter?.TransactionId is long txId)
|
||||
query = query.Where(x => x.TransactionId == txId);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(filter?.RefId))
|
||||
query = query.Where(x => x.RefId != null && x.RefId.Contains(filter.RefId));
|
||||
|
||||
if (filter?.CreatedFrom is DateTime from)
|
||||
query = query.Where(x => x.Created >= from);
|
||||
|
||||
if (filter?.CreatedTo is DateTime to)
|
||||
query = query.Where(x => x.Created <= to);
|
||||
|
||||
query = query.OrderByDescending(x => x.Created);
|
||||
|
||||
return new GetManualCreditChargesResponseDto
|
||||
{
|
||||
MetaData = await query.GetMetaData(request.PaginationState, cancellationToken),
|
||||
Models = await query
|
||||
.PaginatedListAsync(paginationState: request.PaginationState)
|
||||
.ToListAsync(cancellationToken)
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -41,4 +41,9 @@ public enum TransactionType
|
||||
/// شارژ کیف پول اصلی از درگاه
|
||||
/// </summary>
|
||||
CreditWalletCharge = 16,
|
||||
|
||||
/// <summary>
|
||||
/// شارژ دستی کیف پول اصلی توسط ادمین
|
||||
/// </summary>
|
||||
ManualCreditWalletCharge = 17,
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<Version>0.0.204</Version>
|
||||
<Version>0.0.205</Version>
|
||||
<DebugType>None</DebugType>
|
||||
<DebugSymbols>False</DebugSymbols>
|
||||
<GeneratePackageOnBuild>False</GeneratePackageOnBuild>
|
||||
|
||||
@@ -116,6 +116,7 @@ enum TransactionType
|
||||
MagicWalletDeposit = 14;
|
||||
MagicWalletBonus = 15;
|
||||
CreditWalletCharge = 16;
|
||||
ManualCreditWalletCharge = 17;
|
||||
}
|
||||
enum ContractType
|
||||
{
|
||||
|
||||
@@ -125,6 +125,20 @@ service UserWalletContract
|
||||
body: "*"
|
||||
};
|
||||
};
|
||||
|
||||
// ============= Admin Manual Credit Charge =============
|
||||
|
||||
rpc AdminManualCreditCharge(AdminManualCreditChargeRequest) returns (AdminManualCreditChargeResponse){
|
||||
option (google.api.http) = {
|
||||
post: "/Admin/ManualCreditCharge"
|
||||
body: "*"
|
||||
};
|
||||
};
|
||||
rpc GetManualCreditCharges(GetManualCreditChargesRequest) returns (GetManualCreditChargesResponse){
|
||||
option (google.api.http) = {
|
||||
get: "/Admin/GetManualCreditCharges"
|
||||
};
|
||||
};
|
||||
}
|
||||
message CreateNewUserWalletRequest
|
||||
{
|
||||
@@ -324,4 +338,56 @@ message VerifyWalletChargeResponse
|
||||
{
|
||||
bool success = 1;
|
||||
string message = 2;
|
||||
}
|
||||
|
||||
// ============= Admin Manual Credit Charge Messages =============
|
||||
|
||||
message AdminManualCreditChargeRequest
|
||||
{
|
||||
int64 user_id = 1;
|
||||
int64 amount = 2; // تومان
|
||||
google.protobuf.StringValue note = 3;
|
||||
}
|
||||
|
||||
message AdminManualCreditChargeResponse
|
||||
{
|
||||
bool success = 1;
|
||||
string message = 2;
|
||||
int64 transaction_id = 3;
|
||||
int64 new_balance = 4;
|
||||
}
|
||||
|
||||
message GetManualCreditChargesRequest
|
||||
{
|
||||
messages.PaginationState pagination_state = 1;
|
||||
google.protobuf.StringValue sort_by = 2;
|
||||
GetManualCreditChargesFilter filter = 3;
|
||||
}
|
||||
|
||||
message GetManualCreditChargesFilter
|
||||
{
|
||||
google.protobuf.Int64Value user_id = 1;
|
||||
google.protobuf.Int64Value transaction_id = 2;
|
||||
google.protobuf.StringValue ref_id = 3;
|
||||
google.protobuf.Timestamp created_from = 4;
|
||||
google.protobuf.Timestamp created_to = 5;
|
||||
}
|
||||
|
||||
message GetManualCreditChargesResponse
|
||||
{
|
||||
messages.MetaData meta_data = 1;
|
||||
repeated ManualCreditChargeModel models = 2;
|
||||
}
|
||||
|
||||
message ManualCreditChargeModel
|
||||
{
|
||||
int64 transaction_id = 1;
|
||||
int64 user_id = 2;
|
||||
string user_name = 3;
|
||||
int64 amount = 4;
|
||||
string description = 5;
|
||||
string ref_id = 6;
|
||||
int64 new_balance = 7;
|
||||
google.protobuf.Timestamp created = 8;
|
||||
google.protobuf.Timestamp payment_date = 9;
|
||||
}
|
||||
@@ -9,6 +9,9 @@ using CMSMicroservice.Application.WalletCQ.Commands.ChargeCreditWallet;
|
||||
using CMSMicroservice.Application.WalletCQ.Commands.VerifyMagicWalletCharge;
|
||||
using CMSMicroservice.Application.WalletCQ.Commands.VerifyDiscountWalletCharge;
|
||||
using CMSMicroservice.Application.WalletCQ.Commands.VerifyCreditWalletCharge;
|
||||
using CMSMicroservice.Application.WalletCQ.Commands.AdminManualCreditCharge;
|
||||
using CMSMicroservice.Application.WalletCQ.Queries.GetManualCreditCharges;
|
||||
using AppManualChargeFilter = CMSMicroservice.Application.WalletCQ.Queries.GetManualCreditCharges.GetManualCreditChargesFilter;
|
||||
using CMSMicroservice.Application.UserWalletCQ.Queries.GetUserWallet;
|
||||
using CMSMicroservice.Application.UserWalletCQ.Queries.GetAllUserWalletByFilter;
|
||||
using CMSMicroservice.Application.UserWalletCQ.Queries.GetCustomerWalletHistory;
|
||||
@@ -518,4 +521,116 @@ public class UserWalletService : UserWalletContract.UserWalletContractBase
|
||||
MinWithdrawalAmount = settings.MinWithdrawalAmount
|
||||
};
|
||||
}
|
||||
|
||||
// ============= Admin Manual Credit Charge =============
|
||||
|
||||
public override async Task<AdminManualCreditChargeResponse> AdminManualCreditCharge(
|
||||
AdminManualCreditChargeRequest request, ServerCallContext context)
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = await _sender.Send(new AdminManualCreditChargeCommand
|
||||
{
|
||||
UserId = request.UserId,
|
||||
Amount = request.Amount,
|
||||
Note = request.Note,
|
||||
PerformedByAdminId = _currentUserService.GetPerformedBy()
|
||||
}, context.CancellationToken);
|
||||
|
||||
return new AdminManualCreditChargeResponse
|
||||
{
|
||||
Success = result.Success,
|
||||
Message = result.Message ?? string.Empty,
|
||||
TransactionId = result.TransactionId,
|
||||
NewBalance = result.NewBalance
|
||||
};
|
||||
}
|
||||
catch (PaymentInProgressException ex)
|
||||
{
|
||||
return new AdminManualCreditChargeResponse
|
||||
{
|
||||
Success = false,
|
||||
Message = ex.Message
|
||||
};
|
||||
}
|
||||
catch (NotFoundException ex)
|
||||
{
|
||||
return new AdminManualCreditChargeResponse
|
||||
{
|
||||
Success = false,
|
||||
Message = ex.Message
|
||||
};
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "AdminManualCreditCharge failed for UserId={UserId}", request.UserId);
|
||||
return new AdminManualCreditChargeResponse
|
||||
{
|
||||
Success = false,
|
||||
Message = ex.Message
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public override async Task<GetManualCreditChargesResponse> GetManualCreditCharges(
|
||||
GetManualCreditChargesRequest request, ServerCallContext context)
|
||||
{
|
||||
var result = await _sender.Send(new GetManualCreditChargesQuery
|
||||
{
|
||||
SortBy = request.SortBy,
|
||||
PaginationState = request.PaginationState != null
|
||||
? new Application.Common.Models.PaginationState
|
||||
{
|
||||
PageNumber = request.PaginationState.PageNumber,
|
||||
PageSize = request.PaginationState.PageSize
|
||||
}
|
||||
: new Application.Common.Models.PaginationState { PageNumber = 1, PageSize = 20 },
|
||||
Filter = new AppManualChargeFilter
|
||||
{
|
||||
UserId = request.Filter?.UserId,
|
||||
TransactionId = request.Filter?.TransactionId,
|
||||
RefId = request.Filter?.RefId,
|
||||
CreatedFrom = request.Filter?.CreatedFrom?.ToDateTime(),
|
||||
CreatedTo = request.Filter?.CreatedTo?.ToDateTime()
|
||||
}
|
||||
}, context.CancellationToken);
|
||||
|
||||
var response = new GetManualCreditChargesResponse
|
||||
{
|
||||
MetaData = new CMSMicroservice.Protobuf.Protos.MetaData
|
||||
{
|
||||
CurrentPage = result.MetaData.CurrentPage,
|
||||
TotalPage = result.MetaData.TotalPage,
|
||||
PageSize = result.MetaData.PageSize,
|
||||
TotalCount = result.MetaData.TotalCount,
|
||||
HasPrevious = result.MetaData.HasPrevious,
|
||||
HasNext = result.MetaData.HasNext
|
||||
}
|
||||
};
|
||||
|
||||
foreach (var m in result.Models)
|
||||
{
|
||||
var model = new ManualCreditChargeModel
|
||||
{
|
||||
TransactionId = m.TransactionId,
|
||||
UserId = m.UserId,
|
||||
UserName = m.UserName ?? string.Empty,
|
||||
Amount = m.Amount,
|
||||
Description = m.Description ?? string.Empty,
|
||||
RefId = m.RefId ?? string.Empty,
|
||||
NewBalance = m.NewBalance,
|
||||
Created = Timestamp.FromDateTime(DateTime.SpecifyKind(m.Created, DateTimeKind.Utc))
|
||||
};
|
||||
|
||||
if (m.PaymentDate.HasValue)
|
||||
{
|
||||
model.PaymentDate = Timestamp.FromDateTime(
|
||||
DateTime.SpecifyKind(m.PaymentDate.Value, DateTimeKind.Utc));
|
||||
}
|
||||
|
||||
response.Models.Add(model);
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user