feat: Implement manual payment system with gRPC service and related commands/queries

This commit is contained in:
masoodafar-web
2025-12-05 17:26:58 +03:30
parent ee1fa9d064
commit 217ef147dd
8 changed files with 257 additions and 5 deletions

View File

@@ -15,6 +15,7 @@ public class GetAllUserOrderByFilterQueryHandler : IRequestHandler<GetAllUserOrd
.Include(i => i.User)
.Include(i => i.FactorDetails)
.ThenInclude(t => t.Product)
.Include(i => i.OrderVAT)
.ApplyOrder(sortBy: request.SortBy)
.AsNoTracking()
.AsQueryable();
@@ -61,7 +62,9 @@ public class GetAllUserOrderByFilterQueryHandler : IRequestHandler<GetAllUserOrd
TrackingCode = x.TrackingCode,
DeliveryDescription = x.DeliveryDescription,
UserFullName = (x.User.FirstName ?? string.Empty) + " " + (x.User.LastName ?? string.Empty),
UserNationalCode = x.User.NationalCode
UserNationalCode = x.User.NationalCode,
VatAmount = x.OrderVAT != null ? x.OrderVAT.VATAmount : 0,
VatPercentage = x.OrderVAT != null ? (double)(x.OrderVAT.VATRate * 100) : 0
})
.ToListAsync(cancellationToken);

View File

@@ -42,6 +42,10 @@ public class GetAllUserOrderByFilterResponseDto
public string? UserFullName { get; set; }
// کدملی کاربر
public string? UserNationalCode { get; set; }
// مبلغ مالیات بر ارزش افزوده (ریال)
public long VatAmount { get; set; }
// درصد مالیات بر ارزش افزوده (مثلاً 9 برای 9٪)
public double VatPercentage { get; set; }
}
public class GetAllUserOrderByFilterResponseModelFactorDetail
{

View File

@@ -16,6 +16,7 @@ public class GetUserOrderQueryHandler : IRequestHandler<GetUserOrderQuery, GetUs
.Include(i => i.User)
.Include(i => i.FactorDetails)
.ThenInclude(t => t.Product)
.Include(i => i.OrderVAT)
.AsNoTracking()
.Where(x => x.Id == request.Id)
.Select(x => new GetUserOrderResponseDto
@@ -43,7 +44,15 @@ public class GetUserOrderQueryHandler : IRequestHandler<GetUserOrderQuery, GetUs
TrackingCode = x.TrackingCode,
DeliveryDescription = x.DeliveryDescription,
UserFullName = (x.User.FirstName ?? string.Empty) + " " + (x.User.LastName ?? string.Empty),
UserNationalCode = x.User.NationalCode
UserNationalCode = x.User.NationalCode,
VatInfo = x.OrderVAT != null ? new OrderVATInfoDto
{
VatRate = x.OrderVAT.VATRate,
BaseAmount = x.OrderVAT.BaseAmount,
VatAmount = x.OrderVAT.VATAmount,
TotalAmount = x.OrderVAT.TotalAmount,
IsPaid = x.OrderVAT.IsPaid
} : null
})
.FirstOrDefaultAsync(cancellationToken);

View File

@@ -27,7 +27,7 @@ public class GetUserOrderResponseDto
public List<GetUserOrderResponseFactorDetail>? FactorDetails { get; set; }
// وضعیت ارسال سفارش
public DeliveryStatus DeliveryStatus { get; set; }
// کد رهگیری مرسوله
// کدرهگیری مرسوله
public string? TrackingCode { get; set; }
// توضیحات ارسال
public string? DeliveryDescription { get; set; }
@@ -35,8 +35,38 @@ public class GetUserOrderResponseDto
public string? UserFullName { get; set; }
// کدملی کاربر
public string? UserNationalCode { get; set; }
// اطلاعات مالیات بر ارزش افزوده
public OrderVATInfoDto? VatInfo { get; set; }
}
}public class GetUserOrderResponseFactorDetail
/// <summary>
/// اطلاعات مالیات بر ارزش افزوده
/// </summary>
public class OrderVATInfoDto
{
/// <summary>
/// نرخ مالیات (مثلاً 0.09 = 9%)
/// </summary>
public decimal VatRate { get; set; }
/// <summary>
/// مبلغ پایه (قبل از مالیات)
/// </summary>
public long BaseAmount { get; set; }
/// <summary>
/// مبلغ مالیات
/// </summary>
public long VatAmount { get; set; }
/// <summary>
/// مبلغ کل (پایه + مالیات)
/// </summary>
public long TotalAmount { get; set; }
/// <summary>
/// آیا پرداخت شده
/// </summary>
public bool IsPaid { get; set; }
}
public class GetUserOrderResponseFactorDetail
{
//شناسه
public long ProductId { get; set; }

View File

@@ -48,6 +48,8 @@
<Protobuf Include="Protos\clubmembership.proto" ProtoRoot="Protos\" GrpcServices="Both" />
<Protobuf Include="Protos\networkmembership.proto" ProtoRoot="Protos\" GrpcServices="Both" />
<Protobuf Include="Protos\commission.proto" ProtoRoot="Protos\" GrpcServices="Both" />
<!-- Manual Payment System -->
<Protobuf Include="Protos\manualpayment.proto" ProtoRoot="Protos\" GrpcServices="Both" />
<!-- Club Discount Shop System - Phase 9 -->
<Protobuf Include="Protos\discountproduct.proto" ProtoRoot="Protos\" GrpcServices="Both" />
<Protobuf Include="Protos\discountcategory.proto" ProtoRoot="Protos\" GrpcServices="Both" />

View File

@@ -0,0 +1,130 @@
syntax = "proto3";
package manualpayment;
import "public_messages.proto";
import "google/protobuf/empty.proto";
import "google/protobuf/wrappers.proto";
import "google/protobuf/timestamp.proto";
import "google/api/annotations.proto";
option csharp_namespace = "CMSMicroservice.Protobuf.Protos.ManualPayment";
service ManualPaymentContract
{
rpc CreateManualPayment(CreateManualPaymentRequest) returns (CreateManualPaymentResponse){
option (google.api.http) = {
post: "/CreateManualPayment"
body: "*"
};
};
rpc ApproveManualPayment(ApproveManualPaymentRequest) returns (google.protobuf.Empty){
option (google.api.http) = {
post: "/ApproveManualPayment"
body: "*"
};
};
rpc RejectManualPayment(RejectManualPaymentRequest) returns (google.protobuf.Empty){
option (google.api.http) = {
post: "/RejectManualPayment"
body: "*"
};
};
rpc GetAllManualPayments(GetAllManualPaymentsRequest) returns (GetAllManualPaymentsResponse){
option (google.api.http) = {
get: "/GetAllManualPayments"
};
};
}
// Enums mirroring CMSMicroservice.Domain.Enums.ManualPaymentType
enum ManualPaymentType
{
ManualPaymentType_Unknown = 0;
ManualPaymentType_CashDeposit = 1;
ManualPaymentType_DiscountWalletCharge = 2;
ManualPaymentType_NetworkWalletCharge = 3;
ManualPaymentType_Settlement = 4;
ManualPaymentType_ErrorCorrection = 5;
ManualPaymentType_Refund = 6;
ManualPaymentType_Other = 99;
}
// Enums mirroring CMSMicroservice.Domain.Enums.ManualPaymentStatus
enum ManualPaymentStatus
{
ManualPaymentStatus_Pending = 0;
ManualPaymentStatus_Approved = 1;
ManualPaymentStatus_Rejected = 2;
ManualPaymentStatus_Cancelled = 3;
}
message CreateManualPaymentRequest
{
int64 user_id = 1;
int64 amount = 2;
ManualPaymentType type = 3;
string description = 4;
google.protobuf.StringValue reference_number = 5;
}
message CreateManualPaymentResponse
{
int64 id = 1;
}
message ApproveManualPaymentRequest
{
int64 manual_payment_id = 1;
google.protobuf.StringValue approval_note = 2;
}
message RejectManualPaymentRequest
{
int64 manual_payment_id = 1;
string rejection_reason = 2;
}
message GetAllManualPaymentsRequest
{
int32 page_number = 1;
int32 page_size = 2;
google.protobuf.Int64Value user_id = 3;
google.protobuf.Int32Value status = 4;
google.protobuf.Int32Value type = 5;
google.protobuf.Int64Value requested_by = 6;
google.protobuf.BoolValue order_by_descending = 7;
}
message GetAllManualPaymentsResponse
{
messages.MetaData meta_data = 1;
repeated ManualPaymentModel models = 2;
}
message ManualPaymentModel
{
int64 id = 1;
int64 user_id = 2;
string user_full_name = 3;
string user_mobile = 4;
int64 amount = 5;
ManualPaymentType type = 6;
string type_display = 7;
string description = 8;
google.protobuf.StringValue reference_number = 9;
ManualPaymentStatus status = 10;
string status_display = 11;
int64 requested_by = 12;
string requested_by_name = 13;
google.protobuf.Int64Value approved_by = 14;
google.protobuf.StringValue approved_by_name = 15;
google.protobuf.Timestamp approved_at = 16;
google.protobuf.StringValue rejection_reason = 17;
google.protobuf.Int64Value transaction_id = 18;
google.protobuf.Timestamp created = 19;
}

View File

@@ -163,7 +163,20 @@ message GetUserOrderResponse
// نام کامل و کدملی کاربر
google.protobuf.StringValue user_full_name = 15;
google.protobuf.StringValue user_national_code = 16;
// اطلاعات مالیات بر ارزش افزوده
OrderVATInfo vat_info = 17;
}
// اطلاعات مالیات بر ارزش افزوده
message OrderVATInfo
{
double vat_rate = 1; // نرخ مالیات (مثلاً 0.09)
int64 base_amount = 2; // مبلغ پایه (قبل از مالیات)
int64 vat_amount = 3; // مبلغ مالیات
int64 total_amount = 4; // مبلغ کل (پایه + مالیات)
bool is_paid = 5; // آیا پرداخت شده
}
message GetUserOrderResponseFactorDetail
{
int64 product_id = 1;
@@ -236,6 +249,9 @@ message GetAllUserOrderByFilterResponseModel
// نام کامل و کدملی کاربر
google.protobuf.StringValue user_full_name = 15;
google.protobuf.StringValue user_national_code = 16;
// مبلغ و درصد مالیات بر ارزش افزوده
int64 vat_amount = 17;
double vat_percentage = 18;
}
message GetAllUserOrderByFilterResponseModelFactorDetail
{
@@ -352,4 +368,3 @@ message ProductPVDto
int64 unit_pv = 4;
int64 total_pv = 5;
}

View File

@@ -0,0 +1,59 @@
using CMSMicroservice.Protobuf.Protos.ManualPayment;
using CMSMicroservice.WebApi.Common.Services;
using CMSMicroservice.Application.ManualPaymentCQ.Commands.CreateManualPayment;
using CMSMicroservice.Application.ManualPaymentCQ.Commands.ApproveManualPayment;
using CMSMicroservice.Application.ManualPaymentCQ.Commands.RejectManualPayment;
using CMSMicroservice.Application.ManualPaymentCQ.Queries.GetAllManualPayments;
using Grpc.Core;
using Mapster;
using MediatR;
namespace CMSMicroservice.WebApi.Services;
public class ManualPaymentService : ManualPaymentContract.ManualPaymentContractBase
{
private readonly IDispatchRequestToCQRS _dispatchRequestToCQRS;
private readonly ISender _sender;
public ManualPaymentService(
IDispatchRequestToCQRS dispatchRequestToCQRS,
ISender sender)
{
_dispatchRequestToCQRS = dispatchRequestToCQRS;
_sender = sender;
}
public override async Task<CreateManualPaymentResponse> CreateManualPayment(
CreateManualPaymentRequest request,
ServerCallContext context)
{
var command = request.Adapt<CreateManualPaymentCommand>();
var id = await _sender.Send(command, context.CancellationToken);
return new CreateManualPaymentResponse
{
Id = id
};
}
public override async Task<Google.Protobuf.WellKnownTypes.Empty> ApproveManualPayment(
ApproveManualPaymentRequest request,
ServerCallContext context)
{
return await _dispatchRequestToCQRS.Handle<ApproveManualPaymentRequest, ApproveManualPaymentCommand>(request, context);
}
public override async Task<Google.Protobuf.WellKnownTypes.Empty> RejectManualPayment(
RejectManualPaymentRequest request,
ServerCallContext context)
{
return await _dispatchRequestToCQRS.Handle<RejectManualPaymentRequest, RejectManualPaymentCommand>(request, context);
}
public override async Task<GetAllManualPaymentsResponse> GetAllManualPayments(
GetAllManualPaymentsRequest request,
ServerCallContext context)
{
return await _dispatchRequestToCQRS.Handle<GetAllManualPaymentsRequest, GetAllManualPaymentsQuery, GetAllManualPaymentsResponse>(request, context);
}
}