feat: Add discount balance and change value to wallet change log
- Added CurrentDiscountBalance and ChangeDiscountValue properties to GetCustomerWalletChangeLogResponseDto. - Updated userwallet.proto to include current_discount_balance and change_discount_value fields. - Enhanced CommissionProfile mapping to support GetMyCommissionPayouts requests and responses. - Implemented GetMyCommissionPayouts query and handler to retrieve user commission payouts. - Added validation for GetMyCommissionPayouts query. - Updated UserOrderService to handle user orders, including VAT calculations and wallet transactions. - Enhanced UserWalletService to include new properties in wallet change log responses.
This commit is contained in:
+25
@@ -0,0 +1,25 @@
|
||||
using CMSMicroservice.Application.Common.Models;
|
||||
using CMSMicroservice.Domain.Enums;
|
||||
|
||||
namespace CMSMicroservice.Application.CommissionCQ.Queries.GetMyCommissionPayouts;
|
||||
|
||||
/// <summary>
|
||||
/// Query برای دریافت پرداختهای کمیسیون کاربر جاری (از JWT)
|
||||
/// </summary>
|
||||
public record GetMyCommissionPayoutsQuery : IRequest<GetMyCommissionPayoutsResponseDto>
|
||||
{
|
||||
/// <summary>
|
||||
/// فیلتر وضعیت
|
||||
/// </summary>
|
||||
public CommissionPayoutStatus? Status { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// شماره هفته (اختیاری)
|
||||
/// </summary>
|
||||
public long? WeekDefinitionId { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Pagination
|
||||
/// </summary>
|
||||
public PaginationState? PaginationState { get; init; }
|
||||
}
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
using CMSMicroservice.Application.Common.Interfaces;
|
||||
using CMSMicroservice.Application.Common.Extensions;
|
||||
using CMSMicroservice.Domain.Enums;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace CMSMicroservice.Application.CommissionCQ.Queries.GetMyCommissionPayouts;
|
||||
|
||||
public class GetMyCommissionPayoutsQueryHandler : IRequestHandler<GetMyCommissionPayoutsQuery, GetMyCommissionPayoutsResponseDto>
|
||||
{
|
||||
private readonly IApplicationDbContext _context;
|
||||
private readonly ICurrentUserService _currentUser;
|
||||
|
||||
public GetMyCommissionPayoutsQueryHandler(
|
||||
IApplicationDbContext context,
|
||||
ICurrentUserService currentUser)
|
||||
{
|
||||
_context = context;
|
||||
_currentUser = currentUser;
|
||||
}
|
||||
|
||||
public async Task<GetMyCommissionPayoutsResponseDto> Handle(GetMyCommissionPayoutsQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
// دریافت UserId از JWT (فقط برای Customer API)
|
||||
if (!long.TryParse(_currentUser.UserId, out var userId))
|
||||
{
|
||||
throw new UnauthorizedAccessException("User not authenticated");
|
||||
}
|
||||
|
||||
var query = _context.UserCommissionPayouts
|
||||
.Include(x => x.WeekDefinition)
|
||||
.Where(x => x.UserId == userId)
|
||||
.AsNoTracking()
|
||||
.AsQueryable();
|
||||
|
||||
// فیلترها
|
||||
if (request.Status.HasValue)
|
||||
{
|
||||
query = query.Where(x => x.Status == request.Status.Value);
|
||||
}
|
||||
|
||||
if (request.WeekDefinitionId.HasValue)
|
||||
{
|
||||
query = query.Where(x => x.WeekDefinitionId == request.WeekDefinitionId.Value);
|
||||
}
|
||||
|
||||
// مرتبسازی: جدیدترین اول
|
||||
query = query.OrderByDescending(x => x.Created);
|
||||
|
||||
var meta = await query.GetMetaData(request.PaginationState, cancellationToken);
|
||||
|
||||
var models = await query
|
||||
.PaginatedListAsync(paginationState: request.PaginationState)
|
||||
.Select(x => new GetMyCommissionPayoutsResponseModel
|
||||
{
|
||||
Id = x.Id,
|
||||
WeekDefinitionId = x.WeekDefinitionId,
|
||||
WeekDisplayName = x.WeekDefinition != null ? x.WeekDefinition.DisplayName : "",
|
||||
BalancesEarned = x.BalancesEarned,
|
||||
TotalAmount = x.TotalAmount,
|
||||
AmountFormatted = x.TotalAmount.ToString("N0") + " تومان",
|
||||
Status = x.Status,
|
||||
CalculatedDate = x.PaidAt ?? (DateTime?)x.Created,
|
||||
DatePersian = ""
|
||||
})
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
return new GetMyCommissionPayoutsResponseDto
|
||||
{
|
||||
MetaData = meta,
|
||||
Models = models
|
||||
};
|
||||
}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
using FluentValidation;
|
||||
|
||||
namespace CMSMicroservice.Application.CommissionCQ.Queries.GetMyCommissionPayouts;
|
||||
|
||||
public class GetMyCommissionPayoutsQueryValidator : AbstractValidator<GetMyCommissionPayoutsQuery>
|
||||
{
|
||||
public GetMyCommissionPayoutsQueryValidator()
|
||||
{
|
||||
RuleFor(x => x.PaginationState)
|
||||
.NotNull()
|
||||
.WithMessage("Pagination state is required");
|
||||
|
||||
When(x => x.PaginationState != null, () =>
|
||||
{
|
||||
RuleFor(x => x.PaginationState!.PageNumber)
|
||||
.GreaterThan(0)
|
||||
.WithMessage("Page number must be greater than 0");
|
||||
|
||||
RuleFor(x => x.PaginationState!.PageSize)
|
||||
.GreaterThan(0)
|
||||
.LessThanOrEqualTo(100)
|
||||
.WithMessage("Page size must be between 1 and 100");
|
||||
});
|
||||
}
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
using CMSMicroservice.Application.Common.Models;
|
||||
using CMSMicroservice.Domain.Enums;
|
||||
|
||||
namespace CMSMicroservice.Application.CommissionCQ.Queries.GetMyCommissionPayouts;
|
||||
|
||||
public class GetMyCommissionPayoutsResponseDto
|
||||
{
|
||||
public MetaData? MetaData { get; set; }
|
||||
public List<GetMyCommissionPayoutsResponseModel> Models { get; set; } = new();
|
||||
}
|
||||
|
||||
public class GetMyCommissionPayoutsResponseModel
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public long WeekDefinitionId { get; set; }
|
||||
public string WeekDisplayName { get; set; } = string.Empty;
|
||||
public int BalancesEarned { get; set; }
|
||||
public long TotalAmount { get; set; }
|
||||
public string AmountFormatted { get; set; } = string.Empty;
|
||||
public CommissionPayoutStatus Status { get; set; }
|
||||
public DateTime? CalculatedDate { get; set; }
|
||||
public string DatePersian { get; set; } = string.Empty;
|
||||
}
|
||||
+10
@@ -22,6 +22,16 @@ public class GetCustomerWalletChangeLogResponseDto
|
||||
/// </summary>
|
||||
public long ChangeNerworkValue { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// موجودی جاری تخفیف
|
||||
/// </summary>
|
||||
public long CurrentDiscountBalance { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// مقدار تغییر تخفیف
|
||||
/// </summary>
|
||||
public long ChangeDiscountValue { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// افزایشی است؟
|
||||
/// </summary>
|
||||
|
||||
@@ -160,9 +160,11 @@ message CustomerWalletChangeLogModel
|
||||
int64 change_value = 2;
|
||||
int64 current_network_balance = 3;
|
||||
int64 change_nerwork_value = 4;
|
||||
bool is_increase = 5;
|
||||
google.protobuf.Int64Value refrence_id = 6;
|
||||
google.protobuf.Timestamp created_at = 7;
|
||||
int64 current_discount_balance = 5;
|
||||
int64 change_discount_value = 6;
|
||||
bool is_increase = 7;
|
||||
google.protobuf.Int64Value refrence_id = 8;
|
||||
google.protobuf.Timestamp created_at = 9;
|
||||
}
|
||||
|
||||
message CustomerWithdrawBalanceRequest
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
using CMSMicroservice.Application.CommissionCQ.Queries.GetUserWeeklyBalances;
|
||||
using CMSMicroservice.Application.CommissionCQ.Queries.GetAvailableWeeks;
|
||||
using CMSMicroservice.Application.CommissionCQ.Queries.GetUserCommissionPayouts;
|
||||
using CMSMicroservice.Application.CommissionCQ.Queries.GetMyCommissionPayouts;
|
||||
using CMSMicroservice.Application.CommissionCQ.Queries.GetWeekDefinitions;
|
||||
using CMSMicroservice.Application.Common.Models;
|
||||
using CMSMicroservice.Domain.Enums;
|
||||
using CMSMicroservice.Protobuf.Protos.Commission;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
using Mapster;
|
||||
@@ -124,5 +126,38 @@ public class CommissionProfile : IRegister
|
||||
: null)
|
||||
.Map(dest => dest.IsExpired, src => src.IsExpired)
|
||||
.Map(dest => dest.Created, src => Timestamp.FromDateTimeOffset(src.Created));
|
||||
|
||||
// GetMyCommissionPayouts Request Mapping
|
||||
config.NewConfig<GetMyCommissionPayoutsRequest, GetMyCommissionPayoutsQuery>()
|
||||
.Map(dest => dest.Status, src => src.Status != null && src.Status.Value >= 0
|
||||
? (CommissionPayoutStatus?)src.Status.Value
|
||||
: null)
|
||||
.Map(dest => dest.WeekDefinitionId, src => src.WeekDefinitionId != null ? src.WeekDefinitionId.Value : (long?)null)
|
||||
.Map(dest => dest.PaginationState, src => new PaginationState
|
||||
{
|
||||
PageNumber = src.PageNumber > 0 ? src.PageNumber : 1,
|
||||
PageSize = src.PageSize > 0 ? src.PageSize : 10
|
||||
});
|
||||
|
||||
// GetMyCommissionPayouts Response Mapping
|
||||
config.NewConfig<GetMyCommissionPayoutsResponseDto, GetMyCommissionPayoutsResponse>()
|
||||
.Map(dest => dest.MetaData, src => src.MetaData != null
|
||||
? new CustomerMetaData { TotalCount = src.MetaData.TotalCount }
|
||||
: new CustomerMetaData())
|
||||
.Map(dest => dest.Payouts, src => src.Models);
|
||||
|
||||
// CustomerCommissionPayoutModel Mapping
|
||||
config.NewConfig<GetMyCommissionPayoutsResponseModel, CustomerCommissionPayoutModel>()
|
||||
.Map(dest => dest.Id, src => src.Id)
|
||||
.Map(dest => dest.WeekDefinitionId, src => src.WeekDefinitionId)
|
||||
.Map(dest => dest.WeekDisplayName, src => src.WeekDisplayName)
|
||||
.Map(dest => dest.BalancesEarned, src => src.BalancesEarned)
|
||||
.Map(dest => dest.TotalAmount, src => src.TotalAmount)
|
||||
.Map(dest => dest.AmountFormatted, src => src.AmountFormatted)
|
||||
.Map(dest => dest.Status, src => (int)src.Status)
|
||||
.Map(dest => dest.CalculatedDate, src => src.CalculatedDate.HasValue
|
||||
? Timestamp.FromDateTime(src.CalculatedDate.Value.ToUniversalTime())
|
||||
: null)
|
||||
.Map(dest => dest.DatePersian, src => src.DatePersian);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,14 +5,19 @@ using CMSMicroservice.Application.CategoryCQ.Commands.UpdateCategory;
|
||||
using CMSMicroservice.Application.CategoryCQ.Commands.DeleteCategory;
|
||||
using CMSMicroservice.Application.CategoryCQ.Queries.GetCategory;
|
||||
using CMSMicroservice.Application.CategoryCQ.Queries.GetAllCategoryByFilter;
|
||||
using MediatR;
|
||||
using AppModels = CMSMicroservice.Application.Common.Models;
|
||||
|
||||
namespace CMSMicroservice.WebApi.Services;
|
||||
public class CategoryService : CategoryContract.CategoryContractBase
|
||||
{
|
||||
private readonly IDispatchRequestToCQRS _dispatchRequestToCQRS;
|
||||
private readonly ISender _sender;
|
||||
|
||||
public CategoryService(IDispatchRequestToCQRS dispatchRequestToCQRS)
|
||||
public CategoryService(IDispatchRequestToCQRS dispatchRequestToCQRS, ISender sender)
|
||||
{
|
||||
_dispatchRequestToCQRS = dispatchRequestToCQRS;
|
||||
_sender = sender;
|
||||
}
|
||||
public override async Task<CreateNewCategoryResponse> CreateNewCategory(CreateNewCategoryRequest request, ServerCallContext context)
|
||||
{
|
||||
@@ -45,20 +50,52 @@ public class CategoryService : CategoryContract.CategoryContractBase
|
||||
|
||||
public override async Task<GetAllCategoriesForCustomerResponse> GetAllCategoriesForCustomer(GetAllCategoriesForCustomerRequest request, ServerCallContext context)
|
||||
{
|
||||
// TODO: Implement using existing CMS Category Application layer
|
||||
// For now, return empty response
|
||||
return new GetAllCategoriesForCustomerResponse
|
||||
// Use GetAllCategoryByFilter to get all active categories
|
||||
var query = new GetAllCategoryByFilterQuery
|
||||
{
|
||||
Filter = new CMSMicroservice.Application.CategoryCQ.Queries.GetAllCategoryByFilter.GetAllCategoryByFilterFilter
|
||||
{
|
||||
IsActive = true // Only active categories for customers
|
||||
},
|
||||
PaginationState = new AppModels.PaginationState
|
||||
{
|
||||
PageNumber = request.PageNumber > 0 ? request.PageNumber : 1,
|
||||
PageSize = request.PageSize > 0 ? request.PageSize : 100 // Default to large page size to get all
|
||||
},
|
||||
SortBy = "SortOrder" // Sort by display order
|
||||
};
|
||||
|
||||
var result = await _sender.Send(query, context.CancellationToken);
|
||||
|
||||
var response = new GetAllCategoriesForCustomerResponse
|
||||
{
|
||||
MetaData = new CMSMicroservice.Protobuf.Protos.MetaData
|
||||
{
|
||||
CurrentPage = request.PageNumber,
|
||||
PageSize = request.PageSize,
|
||||
TotalCount = 0,
|
||||
TotalPage = 0,
|
||||
HasNext = false,
|
||||
HasPrevious = false
|
||||
CurrentPage = result.MetaData.CurrentPage,
|
||||
PageSize = result.MetaData.PageSize,
|
||||
TotalCount = result.MetaData.TotalCount,
|
||||
TotalPage = result.MetaData.TotalPage,
|
||||
HasNext = result.MetaData.HasNext,
|
||||
HasPrevious = result.MetaData.HasPrevious
|
||||
}
|
||||
};
|
||||
|
||||
foreach (var cat in result.Models)
|
||||
{
|
||||
response.Models.Add(new GetAllCategoryFilterResponseModel
|
||||
{
|
||||
Id = cat.Id,
|
||||
Name = cat.Name,
|
||||
Title = cat.Title,
|
||||
Description = cat.Description ?? string.Empty,
|
||||
ImagePath = cat.ImagePath ?? string.Empty,
|
||||
ParentId = cat.ParentId ?? 0,
|
||||
IsActive = cat.IsActive,
|
||||
SortOrder = cat.SortOrder
|
||||
});
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
public override async Task<GetCategoryByIdForCustomerResponse> GetCategoryByIdForCustomer(GetCategoryByIdForCustomerRequest request, ServerCallContext context)
|
||||
|
||||
@@ -19,6 +19,7 @@ using CMSMicroservice.Application.CommissionCQ.Queries.GetWorkerExecutionLogs;
|
||||
using CMSMicroservice.Application.CommissionCQ.Queries.GetWithdrawalReports;
|
||||
using CMSMicroservice.Application.CommissionCQ.Queries.GetAvailableWeeks;
|
||||
using CMSMicroservice.Application.CommissionCQ.Queries.GetWeekDefinitions;
|
||||
using CMSMicroservice.Application.CommissionCQ.Queries.GetMyCommissionPayouts;
|
||||
|
||||
namespace CMSMicroservice.WebApi.Services;
|
||||
|
||||
@@ -68,6 +69,11 @@ public class CommissionService : CommissionContract.CommissionContractBase
|
||||
return await _dispatchRequestToCQRS.Handle<GetUserCommissionPayoutsRequest, GetUserCommissionPayoutsQuery, GetUserCommissionPayoutsResponse>(request, context);
|
||||
}
|
||||
|
||||
public override async Task<GetMyCommissionPayoutsResponse> GetMyCommissionPayouts(GetMyCommissionPayoutsRequest request, ServerCallContext context)
|
||||
{
|
||||
return await _dispatchRequestToCQRS.Handle<GetMyCommissionPayoutsRequest, GetMyCommissionPayoutsQuery, GetMyCommissionPayoutsResponse>(request, context);
|
||||
}
|
||||
|
||||
public override async Task<GetCommissionPayoutHistoryResponse> GetCommissionPayoutHistory(GetCommissionPayoutHistoryRequest request, ServerCallContext context)
|
||||
{
|
||||
return await _dispatchRequestToCQRS.Handle<GetCommissionPayoutHistoryRequest, GetCommissionPayoutHistoryQuery, GetCommissionPayoutHistoryResponse>(request, context);
|
||||
|
||||
@@ -6,6 +6,7 @@ using CMSMicroservice.Application.ProductsCQ.Queries.GetCustomerProductsByFilter
|
||||
using Mapster;
|
||||
using AppModels = CMSMicroservice.Application.Common.Models;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace CMSMicroservice.WebApi.Services;
|
||||
|
||||
@@ -39,7 +40,64 @@ public class ProductsService : ProductsContract.ProductsContractBase
|
||||
|
||||
public override async Task<GetAllProductsByFilterResponse> GetAllProductsByFilter(GetAllProductsByFilterRequest request, ServerCallContext context)
|
||||
{
|
||||
throw new RpcException(new Status(StatusCode.Unimplemented, "Method not implemented yet"));
|
||||
// Map to GetCustomerProductsByFilter query (public products API)
|
||||
var query = new GetCustomerProductsByFilterQuery
|
||||
{
|
||||
Id = request.Filter?.Id,
|
||||
Title = request.Filter?.Title ?? string.Empty,
|
||||
Description = request.Filter?.Description ?? string.Empty,
|
||||
ShortInfomation = request.Filter?.ShortInfomation ?? string.Empty,
|
||||
FullInformation = request.Filter?.FullInformation ?? string.Empty,
|
||||
Price = request.Filter?.Price,
|
||||
Discount = request.Filter?.Discount,
|
||||
Rate = request.Filter?.Rate,
|
||||
SaleCount = request.Filter?.SaleCount,
|
||||
ViewCount = request.Filter?.ViewCount,
|
||||
RemainingCount = request.Filter?.RemainingCount,
|
||||
CategoryIds = request.Filter?.CategoryId.HasValue == true
|
||||
? new List<long> { request.Filter.CategoryId.Value }
|
||||
: new List<long>(),
|
||||
SortBy = request.SortBy ?? string.Empty,
|
||||
PaginationState = request.PaginationState != null
|
||||
? new AppModels.PaginationState
|
||||
{
|
||||
PageNumber = request.PaginationState.PageNumber,
|
||||
PageSize = request.PaginationState.PageSize
|
||||
}
|
||||
: new AppModels.PaginationState { PageNumber = 1, PageSize = 20 }
|
||||
};
|
||||
|
||||
var result = await _sender.Send(query, context.CancellationToken);
|
||||
|
||||
return new GetAllProductsByFilterResponse
|
||||
{
|
||||
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
|
||||
},
|
||||
Models = { result.Models.Select(m => new GetAllProductsByFilterResponseModel
|
||||
{
|
||||
Id = m.Id,
|
||||
Title = m.Title,
|
||||
Description = m.Description,
|
||||
ShortInfomation = m.ShortInfomation,
|
||||
FullInformation = m.FullInformation,
|
||||
Price = m.Price,
|
||||
Discount = m.Discount,
|
||||
Rate = m.Rate,
|
||||
ImagePath = m.ImagePath,
|
||||
ThumbnailPath = m.ThumbnailPath,
|
||||
SaleCount = m.SaleCount,
|
||||
ViewCount = m.ViewCount,
|
||||
RemainingCount = m.RemainingCount,
|
||||
CategoryIds = { m.Categories?.Select(c => c.CategoryId) ?? Enumerable.Empty<long>() }
|
||||
}) }
|
||||
};
|
||||
}
|
||||
|
||||
public override async Task<BulkUpdateProductPricesResponse> BulkUpdateProductPrices(BulkUpdateProductPricesRequest request, ServerCallContext context)
|
||||
|
||||
@@ -2,23 +2,33 @@ using CMSMicroservice.Protobuf.Protos.UserOrder;
|
||||
using CMSMicroservice.Application.UserOrderCQ.Queries.GetCustomerOrders;
|
||||
using CMSMicroservice.Application.UserOrderCQ.Queries.GetCustomerOrder;
|
||||
using CMSMicroservice.Application.UserOrderCQ.Queries.GetCustomerOrderHistory;
|
||||
using CMSMicroservice.Application.Common.Interfaces;
|
||||
using CMSMicroservice.Domain.Entities;
|
||||
using CMSMicroservice.Domain.Entities.Order;
|
||||
using CMSMicroservice.Domain.Enums;
|
||||
using AppModels = CMSMicroservice.Application.Common.Models;
|
||||
using Grpc.Core;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using CMSMicroservice.Protobuf.Protos;
|
||||
using MediatR;
|
||||
using Mapster;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace CMSMicroservice.WebApi.Services;
|
||||
|
||||
public class UserOrderService : UserOrderContract.UserOrderContractBase
|
||||
{
|
||||
private readonly ISender _sender;
|
||||
private readonly IApplicationDbContext _context;
|
||||
private readonly ICurrentUserService _currentUserService;
|
||||
|
||||
public UserOrderService(ISender sender)
|
||||
public UserOrderService(ISender sender, IApplicationDbContext context, ICurrentUserService currentUserService)
|
||||
{
|
||||
_sender = sender;
|
||||
_context = context;
|
||||
_currentUserService = currentUserService;
|
||||
}
|
||||
public override async Task<CreateNewUserOrderResponse> CreateNewUserOrder(CreateNewUserOrderRequest request, ServerCallContext context)
|
||||
{
|
||||
@@ -37,17 +47,299 @@ public class UserOrderService : UserOrderContract.UserOrderContractBase
|
||||
|
||||
public override async Task<GetUserOrderResponse> GetUserOrder(GetUserOrderRequest request, ServerCallContext context)
|
||||
{
|
||||
throw new RpcException(new Status(StatusCode.Unimplemented, "Method not implemented yet"));
|
||||
var query = new GetCustomerOrderQuery
|
||||
{
|
||||
OrderId = request.Id,
|
||||
UserId = 0 // از JWT دریافت میشود
|
||||
};
|
||||
|
||||
var result = await _sender.Send(query, context.CancellationToken);
|
||||
|
||||
var response = new GetUserOrderResponse
|
||||
{
|
||||
Id = result.Id,
|
||||
Amount = result.Amount,
|
||||
PackageId = result.PackageId ?? 0,
|
||||
TransactionId = result.TransactionId,
|
||||
UserId = result.UserId,
|
||||
UserAddressId = result.UserAddressId,
|
||||
UserAddressText = result.UserAddressText,
|
||||
TrackingCode = result.TrackingCode,
|
||||
DeliveryDescription = result.DeliveryDescription,
|
||||
UserFullName = result.UserFullName,
|
||||
UserNationalCode = result.UserNationalCode
|
||||
};
|
||||
|
||||
// VAT Info
|
||||
if (result.VatAmount > 0)
|
||||
{
|
||||
response.VatInfo = new OrderVATInfo
|
||||
{
|
||||
VatRate = result.VatPercentage / 100,
|
||||
BaseAmount = result.Amount - result.VatAmount,
|
||||
VatAmount = result.VatAmount,
|
||||
TotalAmount = result.Amount,
|
||||
IsPaid = result.PaymentStatus == Domain.Enums.PaymentStatus.Success
|
||||
};
|
||||
}
|
||||
|
||||
response.PaymentStatus = (CMSMicroservice.Protobuf.Protos.PaymentStatus)result.PaymentStatus;
|
||||
if (result.PaymentDate.HasValue)
|
||||
response.PaymentDate = Timestamp.FromDateTime(DateTime.SpecifyKind(result.PaymentDate.Value, DateTimeKind.Utc));
|
||||
|
||||
if (result.PaymentMethod.HasValue)
|
||||
response.PaymentMethod = (CMSMicroservice.Protobuf.Protos.PaymentMethod)result.PaymentMethod.Value;
|
||||
|
||||
response.DeliveryStatus = (CMSMicroservice.Protobuf.Protos.DeliveryStatus)result.DeliveryStatus;
|
||||
|
||||
foreach (var fd in result.FactorDetails)
|
||||
{
|
||||
response.FactorDetails.Add(new GetUserOrderResponseFactorDetail
|
||||
{
|
||||
ProductId = fd.ProductId,
|
||||
ProductTitle = fd.ProductTitle,
|
||||
ProductThumbnailPath = fd.ProductThumbnailPath,
|
||||
UnitPrice = fd.UnitPrice,
|
||||
Count = fd.Count,
|
||||
UnitDiscountPrice = fd.UnitDiscountPrice
|
||||
});
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
public override async Task<GetAllUserOrderByFilterResponse> GetAllUserOrderByFilter(GetAllUserOrderByFilterRequest request, ServerCallContext context)
|
||||
{
|
||||
throw new RpcException(new Status(StatusCode.Unimplemented, "Method not implemented yet"));
|
||||
// Admin API - can view all orders or filter by specific user
|
||||
var query = new GetCustomerOrdersQuery
|
||||
{
|
||||
UserId = request.Filter?.UserId ?? 0, // 0 means all users (admin view)
|
||||
PaginationState = request.PaginationState?.Adapt<AppModels.PaginationState>(),
|
||||
PaymentStatusFilter = request.Filter?.PaymentStatus != null
|
||||
? (int?)request.Filter.PaymentStatus
|
||||
: null,
|
||||
DeliveryStatusFilter = request.Filter?.DeliveryStatus != null
|
||||
? (int?)request.Filter.DeliveryStatus
|
||||
: null,
|
||||
FromDate = request.Filter?.PaymentDate?.ToDateTime(),
|
||||
ToDate = null
|
||||
};
|
||||
|
||||
var result = await _sender.Send(query, context.CancellationToken);
|
||||
|
||||
var response = new GetAllUserOrderByFilterResponse
|
||||
{
|
||||
MetaData = result.MetaData.Adapt<MetaData>()
|
||||
};
|
||||
|
||||
foreach (var model in result.Models)
|
||||
{
|
||||
var orderModel = new GetAllUserOrderByFilterResponseModel
|
||||
{
|
||||
Id = model.Id,
|
||||
Amount = model.Amount,
|
||||
PackageId = model.PackageId ?? 0,
|
||||
TransactionId = model.TransactionId,
|
||||
UserId = model.UserId,
|
||||
UserAddressId = model.UserAddressId,
|
||||
UserAddressText = model.UserAddressText,
|
||||
TrackingCode = model.TrackingCode,
|
||||
DeliveryDescription = model.DeliveryDescription,
|
||||
UserFullName = model.UserFullName,
|
||||
UserNationalCode = model.UserNationalCode,
|
||||
VatAmount = model.VatAmount,
|
||||
VatPercentage = model.VatPercentage
|
||||
};
|
||||
|
||||
orderModel.PaymentStatus = (CMSMicroservice.Protobuf.Protos.PaymentStatus)model.PaymentStatus;
|
||||
if (model.PaymentDate.HasValue)
|
||||
orderModel.PaymentDate = Timestamp.FromDateTime(DateTime.SpecifyKind(model.PaymentDate.Value, DateTimeKind.Utc));
|
||||
|
||||
if (model.PaymentMethod.HasValue)
|
||||
orderModel.PaymentMethod = (CMSMicroservice.Protobuf.Protos.PaymentMethod)model.PaymentMethod.Value;
|
||||
|
||||
orderModel.DeliveryStatus = (CMSMicroservice.Protobuf.Protos.DeliveryStatus)model.DeliveryStatus;
|
||||
|
||||
foreach (var fd in model.FactorDetails)
|
||||
{
|
||||
orderModel.FactorDetails.Add(new GetAllUserOrderByFilterResponseModelFactorDetail
|
||||
{
|
||||
ProductId = fd.ProductId,
|
||||
ProductTitle = fd.ProductTitle,
|
||||
ProductThumbnailPath = fd.ProductThumbnailPath,
|
||||
UnitPrice = fd.UnitPrice,
|
||||
Count = fd.Count,
|
||||
UnitDiscountPrice = fd.UnitDiscountPrice
|
||||
});
|
||||
}
|
||||
|
||||
response.Models.Add(orderModel);
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
public override async Task<SubmitShopBuyOrderResponse> SubmitShopBuyOrder(SubmitShopBuyOrderRequest request, ServerCallContext context)
|
||||
{
|
||||
throw new RpcException(new Status(StatusCode.Unimplemented, "Method not implemented yet"));
|
||||
// Get UserId from JWT or request
|
||||
var userId = !string.IsNullOrEmpty(_currentUserService.UserId)
|
||||
? long.Parse(_currentUserService.UserId)
|
||||
: request.UserId;
|
||||
|
||||
if (userId == 0)
|
||||
{
|
||||
throw new RpcException(new Status(StatusCode.Unauthenticated, "User not authenticated"));
|
||||
}
|
||||
|
||||
// Get user's cart items with product details
|
||||
var cartItems = await _context.UserCarts
|
||||
.Include(c => c.Product)
|
||||
.Where(c => c.UserId == userId && !c.IsDeleted)
|
||||
.ToListAsync(context.CancellationToken);
|
||||
|
||||
if (!cartItems.Any())
|
||||
{
|
||||
throw new RpcException(new Status(StatusCode.FailedPrecondition, "سبد خرید خالی است"));
|
||||
}
|
||||
|
||||
// Get user's default address
|
||||
var defaultAddress = await _context.UserAddresses
|
||||
.Where(a => a.UserId == userId && a.IsDefault && !a.IsDeleted)
|
||||
.FirstOrDefaultAsync(context.CancellationToken);
|
||||
|
||||
if (defaultAddress == null)
|
||||
{
|
||||
throw new RpcException(new Status(StatusCode.FailedPrecondition, "آدرس پیشفرض یافت نشد"));
|
||||
}
|
||||
|
||||
// Calculate amounts
|
||||
const decimal vatRate = 0.09m;
|
||||
long baseAmount = cartItems.Sum(c => c.Product.Price * c.Count);
|
||||
long vatAmount = (long)(baseAmount * vatRate);
|
||||
long totalAmount = baseAmount + vatAmount;
|
||||
|
||||
// Validate total amount
|
||||
if (request.TotalAmount > 0 && Math.Abs(totalAmount - request.TotalAmount) > 100)
|
||||
{
|
||||
throw new RpcException(new Status(StatusCode.InvalidArgument,
|
||||
$"مبلغ نامعتبر است. محاسبه شده: {totalAmount}, دریافتی: {request.TotalAmount}"));
|
||||
}
|
||||
|
||||
// Get user's wallet
|
||||
var wallet = await _context.UserWallets
|
||||
.Where(w => w.UserId == userId)
|
||||
.FirstOrDefaultAsync(context.CancellationToken);
|
||||
|
||||
if (wallet == null)
|
||||
{
|
||||
throw new RpcException(new Status(StatusCode.FailedPrecondition, "کیف پول یافت نشد"));
|
||||
}
|
||||
|
||||
// Check wallet balance
|
||||
if (wallet.Balance < totalAmount)
|
||||
{
|
||||
throw new RpcException(new Status(StatusCode.FailedPrecondition,
|
||||
$"موجودی کیف پول کافی نیست. موجودی: {wallet.Balance:N0} تومان، مورد نیاز: {totalAmount:N0} تومان"));
|
||||
}
|
||||
|
||||
// Create transaction
|
||||
var transaction = new Transaction
|
||||
{
|
||||
Amount = totalAmount,
|
||||
Description = $"خرید محصولات - سفارش شماره در حال ایجاد",
|
||||
PaymentStatus = CMSMicroservice.Domain.Enums.PaymentStatus.Success,
|
||||
PaymentDate = DateTime.UtcNow,
|
||||
Type = CMSMicroservice.Domain.Enums.TransactionType.Buy,
|
||||
RefId = $"SHOP_{DateTime.UtcNow.Ticks}"
|
||||
};
|
||||
|
||||
_context.Transactions.Add(transaction);
|
||||
await _context.SaveChangesAsync(context.CancellationToken);
|
||||
|
||||
// Deduct from wallet
|
||||
var oldBalance = wallet.Balance;
|
||||
wallet.Balance -= totalAmount;
|
||||
|
||||
// Create wallet change log
|
||||
var walletLog = new UserWalletChangeLog
|
||||
{
|
||||
WalletId = wallet.Id,
|
||||
CurrentBalance = wallet.Balance,
|
||||
ChangeValue = -totalAmount,
|
||||
CurrentNetworkBalance = wallet.NetworkBalance,
|
||||
ChangeNerworkValue = 0,
|
||||
CurrentDiscountBalance = wallet.DiscountBalance,
|
||||
ChangeDiscountValue = 0,
|
||||
IsIncrease = false,
|
||||
RefrenceId = transaction.Id
|
||||
};
|
||||
|
||||
_context.UserWalletChangeLogs.Add(walletLog);
|
||||
|
||||
// Create order
|
||||
var order = new UserOrder
|
||||
{
|
||||
UserId = userId,
|
||||
UserAddressId = defaultAddress.Id,
|
||||
Amount = totalAmount,
|
||||
TransactionId = transaction.Id,
|
||||
PaymentStatus = CMSMicroservice.Domain.Enums.PaymentStatus.Success,
|
||||
PaymentDate = DateTime.UtcNow,
|
||||
PaymentMethod = CMSMicroservice.Domain.Enums.PaymentMethod.Wallet,
|
||||
DeliveryStatus = CMSMicroservice.Domain.Enums.DeliveryStatus.Pending,
|
||||
HasVAT = true
|
||||
};
|
||||
|
||||
_context.UserOrders.Add(order);
|
||||
await _context.SaveChangesAsync(context.CancellationToken);
|
||||
|
||||
// Update transaction description with order ID
|
||||
transaction.Description = $"خرید محصولات - سفارش #{order.Id}";
|
||||
await _context.SaveChangesAsync(context.CancellationToken);
|
||||
|
||||
// Create order VAT record
|
||||
var orderVat = new OrderVAT
|
||||
{
|
||||
OrderId = order.Id,
|
||||
VATRate = vatRate,
|
||||
BaseAmount = baseAmount,
|
||||
VATAmount = vatAmount,
|
||||
TotalAmount = totalAmount
|
||||
};
|
||||
|
||||
_context.OrderVATs.Add(orderVat);
|
||||
|
||||
// Create factor details for each cart item
|
||||
foreach (var cartItem in cartItems)
|
||||
{
|
||||
var factorDetail = new FactorDetails
|
||||
{
|
||||
OrderId = order.Id,
|
||||
ProductId = cartItem.ProductId,
|
||||
Count = cartItem.Count,
|
||||
UnitPrice = cartItem.Product.Price,
|
||||
UnitDiscount = 0,
|
||||
UnitDiscountPrice = cartItem.Product.Price,
|
||||
IsChangePrice = false
|
||||
};
|
||||
|
||||
_context.FactorDetails.Add(factorDetail);
|
||||
}
|
||||
|
||||
await _context.SaveChangesAsync(context.CancellationToken);
|
||||
|
||||
// Clear user's cart
|
||||
foreach (var cartItem in cartItems)
|
||||
{
|
||||
cartItem.IsDeleted = true;
|
||||
}
|
||||
|
||||
await _context.SaveChangesAsync(context.CancellationToken);
|
||||
|
||||
return new SubmitShopBuyOrderResponse
|
||||
{
|
||||
Id = order.Id
|
||||
};
|
||||
}
|
||||
|
||||
public override async Task<CancelOrderResponse> CancelOrder(CancelOrderRequest request, ServerCallContext context)
|
||||
@@ -131,14 +423,14 @@ public class UserOrderService : UserOrderContract.UserOrderContractBase
|
||||
VatPercentage = model.VatPercentage
|
||||
};
|
||||
|
||||
orderModel.PaymentStatus = (PaymentStatus)model.PaymentStatus;
|
||||
orderModel.PaymentStatus = (CMSMicroservice.Protobuf.Protos.PaymentStatus)model.PaymentStatus;
|
||||
if (model.PaymentDate.HasValue)
|
||||
orderModel.PaymentDate = Timestamp.FromDateTime(DateTime.SpecifyKind(model.PaymentDate.Value, DateTimeKind.Utc));
|
||||
|
||||
if (model.PaymentMethod.HasValue)
|
||||
orderModel.PaymentMethod = (PaymentMethod)model.PaymentMethod.Value;
|
||||
orderModel.PaymentMethod = (CMSMicroservice.Protobuf.Protos.PaymentMethod)model.PaymentMethod.Value;
|
||||
|
||||
orderModel.DeliveryStatus = (DeliveryStatus)model.DeliveryStatus;
|
||||
orderModel.DeliveryStatus = (CMSMicroservice.Protobuf.Protos.DeliveryStatus)model.DeliveryStatus;
|
||||
|
||||
foreach (var fd in model.FactorDetails)
|
||||
{
|
||||
@@ -197,14 +489,14 @@ public class UserOrderService : UserOrderContract.UserOrderContractBase
|
||||
};
|
||||
}
|
||||
|
||||
response.PaymentStatus = (PaymentStatus)result.PaymentStatus;
|
||||
response.PaymentStatus = (CMSMicroservice.Protobuf.Protos.PaymentStatus)result.PaymentStatus;
|
||||
if (result.PaymentDate.HasValue)
|
||||
response.PaymentDate = Timestamp.FromDateTime(DateTime.SpecifyKind(result.PaymentDate.Value, DateTimeKind.Utc));
|
||||
|
||||
if (result.PaymentMethod.HasValue)
|
||||
response.PaymentMethod = (PaymentMethod)result.PaymentMethod.Value;
|
||||
response.PaymentMethod = (CMSMicroservice.Protobuf.Protos.PaymentMethod)result.PaymentMethod.Value;
|
||||
|
||||
response.DeliveryStatus = (DeliveryStatus)result.DeliveryStatus;
|
||||
response.DeliveryStatus = (CMSMicroservice.Protobuf.Protos.DeliveryStatus)result.DeliveryStatus;
|
||||
|
||||
foreach (var fd in result.FactorDetails)
|
||||
{
|
||||
@@ -384,4 +676,15 @@ public class UserOrderService : UserOrderContract.UserOrderContractBase
|
||||
TotalAmount = totalAmount
|
||||
};
|
||||
}
|
||||
|
||||
public override Task<GetVATRateResponse> GetVATRate(Google.Protobuf.WellKnownTypes.Empty request, ServerCallContext context)
|
||||
{
|
||||
// VAT Rate for Iran: 9% (نرخ مالیات بر ارزش افزوده ایران)
|
||||
return Task.FromResult(new GetVATRateResponse
|
||||
{
|
||||
VatRate = 0.09,
|
||||
VatPercentage = 9,
|
||||
IsEnabled = true
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,6 +87,8 @@ public class UserWalletService : UserWalletContract.UserWalletContractBase
|
||||
ChangeValue = log.ChangeValue,
|
||||
CurrentNetworkBalance = log.CurrentNetworkBalance,
|
||||
ChangeNerworkValue = log.ChangeNerworkValue,
|
||||
CurrentDiscountBalance = log.CurrentDiscountBalance,
|
||||
ChangeDiscountValue = log.ChangeDiscountValue,
|
||||
IsIncrease = log.IsIncrease,
|
||||
RefrenceId = log.RefrenceId,
|
||||
CreatedAt = Google.Protobuf.WellKnownTypes.Timestamp.FromDateTime(DateTime.SpecifyKind(log.Created, DateTimeKind.Utc))
|
||||
|
||||
Reference in New Issue
Block a user