Complete FrontOffice BFF to CMS Migration
- Migrated all 9 services from FrontOffice.BFF to CMS architecture - Enhanced user.proto with 7 additional Customer API endpoints: * UpdateCustomerProfile, GetCustomerProfile * ChangeCustomerPassword with validation * GetCustomerReferrals with commission stats * UploadCustomerAvatar with file validation * GetCustomerSettings, UpdateCustomerSettings - All services now support Customer endpoints with /Customer/ prefix - Mock implementations with realistic Persian data - Fixed namespace conflicts and compilation issues - Comprehensive testing completed for all endpoints - Services migrated: Categories, City, UserCarts, Products, UserWallet, Transaction, UserOrder, Package, User (enhanced)
This commit is contained in:
@@ -5,6 +5,8 @@
|
||||
<Nullable>enable</Nullable>
|
||||
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
||||
<DockerfileContext>..\..\..</DockerfileContext>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<NoWarn>$(NoWarn);1591</NoWarn>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@@ -12,7 +14,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Google.Protobuf" Version="3.23.3" />
|
||||
<PackageReference Include="Google.Protobuf" Version="3.27.0" />
|
||||
<PackageReference Include="Grpc.AspNetCore" Version="2.54.0" />
|
||||
<PackageReference Include="Grpc.AspNetCore.Web" Version="2.54.0" />
|
||||
<PackageReference Include="Grpc.Net.Client" Version="2.54.0" />
|
||||
@@ -29,6 +31,7 @@
|
||||
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore" Version="9.0.0" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.18.1" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Grpc.Swagger" Version="0.3.8" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Grpc.JsonTranscoding" Version="9.0.11" />
|
||||
<PackageReference Include="Serilog.AspNetCore" Version="9.0.0" />
|
||||
<PackageReference Include="Serilog.Sinks.MSSqlServer" Version="9.0.2" />
|
||||
<PackageReference Include="Serilog.Sinks.Seq" Version="9.0.0" />
|
||||
|
||||
@@ -24,9 +24,9 @@ public class CityProfile : IRegister
|
||||
// Response: Application → Proto
|
||||
config.NewConfig<AppCity.GetAllCitiesByFilterResponseDto, ProtoCity.GetAllCitiesByFilterResponse>()
|
||||
.Map(dest => dest.MetaData, src => src.MetaData)
|
||||
.Map(dest => dest.Models, src => src.Models);
|
||||
.Map(dest => dest.Cities, src => src.Models);
|
||||
|
||||
config.NewConfig<AppCity.GetAllCitiesByFilterResponseModel, ProtoCity.GetAllCitiesByFilterResponseModel>()
|
||||
config.NewConfig<AppCity.GetAllCitiesByFilterResponseModel, ProtoCity.CityDto>()
|
||||
.Map(dest => dest.Id, src => src.Id)
|
||||
.Map(dest => dest.ExternalId, src => src.ExternalId)
|
||||
.Map(dest => dest.Name, src => src.Name)
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
using CMSMicroservice.Protobuf.Protos.Health;
|
||||
using CMSMicroservice.Application.HealthCQ.Queries.GetSystemHealth;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
|
||||
namespace CMSMicroservice.WebApi.Common.Mappings;
|
||||
|
||||
public class HealthProfile : IRegister
|
||||
{
|
||||
public void Register(TypeAdapterConfig config)
|
||||
{
|
||||
// DTO to Proto mappings
|
||||
config.NewConfig<GetSystemHealthResponseDto, GetSystemHealthResponse>()
|
||||
.Map(dest => dest.OverallHealthy, src => src.OverallHealthy)
|
||||
.Map(dest => dest.Services, src => src.Services)
|
||||
.Map(dest => dest.CheckedAt, src => Timestamp.FromDateTime(src.CheckedAt))
|
||||
.Map(dest => dest.Version, src => src.Version)
|
||||
.Map(dest => dest.Environment, src => src.Environment);
|
||||
|
||||
config.NewConfig<ServiceHealthDto, ServiceHealthModel>()
|
||||
.Map(dest => dest.ServiceName, src => src.ServiceName)
|
||||
.Map(dest => dest.Status, src => src.Status)
|
||||
.Map(dest => dest.Description, src => src.Description)
|
||||
.Map(dest => dest.ResponseTimeMs, src => src.ResponseTimeMs)
|
||||
.Map(dest => dest.LastCheck, src => Timestamp.FromDateTime(src.LastCheck))
|
||||
.Map(dest => dest.Details, src => src.Details);
|
||||
|
||||
config.NewConfig<HealthDetailDto, HealthDetail>()
|
||||
.Map(dest => dest.Key, src => src.Key)
|
||||
.Map(dest => dest.Value, src => src.Value)
|
||||
.Map(dest => dest.Status, src => src.Status);
|
||||
|
||||
// Enum mappings
|
||||
config.NewConfig<HealthStatusDto, HealthStatus>()
|
||||
.Map(dest => dest, src => (HealthStatus)(int)src);
|
||||
}
|
||||
}
|
||||
@@ -1,93 +0,0 @@
|
||||
using CMSMicroservice.Application.ProductsCQ.Commands.BulkUpdateProductPrices;
|
||||
using CMSMicroservice.Application.ProductsCQ.Commands.BulkUpdateProductStock;
|
||||
using CMSMicroservice.Application.ProductsCQ.Commands.ToggleProductStatus;
|
||||
using CMSMicroservice.Application.ProductsCQ.Queries.GetLowStockProducts;
|
||||
using CMSMicroservice.Protobuf.Protos.Products;
|
||||
using ProtoProductPriceUpdate = CMSMicroservice.Protobuf.Protos.Products.ProductPriceUpdate;
|
||||
using AppProductPriceUpdate = CMSMicroservice.Application.ProductsCQ.Commands.BulkUpdateProductPrices.ProductPriceUpdate;
|
||||
using ProtoProductStockUpdate = CMSMicroservice.Protobuf.Protos.Products.ProductStockUpdate;
|
||||
using AppProductStockUpdate = CMSMicroservice.Application.ProductsCQ.Commands.BulkUpdateProductStock.ProductStockUpdate;
|
||||
using ProtoStockUpdateType = CMSMicroservice.Protobuf.Protos.Products.StockUpdateType;
|
||||
using AppStockUpdateType = CMSMicroservice.Application.ProductsCQ.Commands.BulkUpdateProductStock.StockUpdateType;
|
||||
using System.Linq;
|
||||
|
||||
namespace CMSMicroservice.WebApi.Common.Mappings;
|
||||
|
||||
public class ProductsProfile : IRegister
|
||||
{
|
||||
void IRegister.Register(TypeAdapterConfig config)
|
||||
{
|
||||
// BulkUpdateProductPrices mappings
|
||||
config.NewConfig<BulkUpdateProductPricesRequest, BulkUpdateProductPricesCommand>()
|
||||
.Map(dest => dest.Products, src => src.Products);
|
||||
|
||||
config.NewConfig<ProtoProductPriceUpdate, AppProductPriceUpdate>()
|
||||
.Map(dest => dest.ProductId, src => src.ProductId)
|
||||
.Map(dest => dest.NewPrice, src => src.NewPrice)
|
||||
.Map(dest => dest.NewDiscount, src => src.NewDiscount != null ? (int?)src.NewDiscount.Value : null)
|
||||
.Map(dest => dest.NewClubDiscountPercent, src => src.NewClubDiscountPercent != null ? (int?)src.NewClubDiscountPercent.Value : null);
|
||||
|
||||
config.NewConfig<BulkUpdateProductPricesResponseDto, BulkUpdateProductPricesResponse>()
|
||||
.Map(dest => dest.Total, src => src.UpdatedCount + src.FailedCount)
|
||||
.Map(dest => dest.Succeeded, src => src.UpdatedCount)
|
||||
.Map(dest => dest.Failed, src => src.FailedCount)
|
||||
.Map(dest => dest.Errors, src => src.Errors.Select((msg, idx) => new BulkOperationError
|
||||
{
|
||||
ProductId = 0, // We don't have the ID in the error message
|
||||
ErrorMessage = msg
|
||||
}).ToList());
|
||||
|
||||
// BulkUpdateProductStock mappings
|
||||
config.NewConfig<BulkUpdateProductStockRequest, BulkUpdateProductStockCommand>()
|
||||
.Map(dest => dest.Products, src => src.Products)
|
||||
.Map(dest => dest.UpdateType, src => (AppStockUpdateType)src.UpdateType);
|
||||
|
||||
config.NewConfig<ProtoProductStockUpdate, AppProductStockUpdate>()
|
||||
.Map(dest => dest.ProductId, src => src.ProductId)
|
||||
.Map(dest => dest.Quantity, src => src.Quantity);
|
||||
|
||||
config.NewConfig<BulkUpdateProductStockResponseDto, BulkUpdateProductStockResponse>()
|
||||
.Map(dest => dest.Total, src => src.UpdatedCount + src.FailedCount)
|
||||
.Map(dest => dest.Succeeded, src => src.UpdatedCount)
|
||||
.Map(dest => dest.Failed, src => src.FailedCount)
|
||||
.Map(dest => dest.Errors, src => src.Errors.Select(msg => new BulkOperationError
|
||||
{
|
||||
ProductId = 0,
|
||||
ErrorMessage = msg
|
||||
}).ToList());
|
||||
|
||||
// GetLowStockProducts mappings
|
||||
config.NewConfig<GetLowStockProductsRequest, GetLowStockProductsQuery>()
|
||||
.Map(dest => dest.Threshold, src => src.Threshold)
|
||||
.Map(dest => dest.PageIndex, src => src.PageIndex)
|
||||
.Map(dest => dest.PageSize, src => src.PageSize)
|
||||
.Map(dest => dest.IsClubExclusive, src => src.IsClubExclusive != null ? (bool?)src.IsClubExclusive.Value : null);
|
||||
|
||||
config.NewConfig<GetLowStockProductsResponseDto, GetLowStockProductsResponse>()
|
||||
.Map(dest => dest.MetaData, src => src.MetaData)
|
||||
.Map(dest => dest.Products, src => src.Products);
|
||||
|
||||
config.NewConfig<LowStockProductDto, LowStockProduct>()
|
||||
.Map(dest => dest.Id, src => src.Id)
|
||||
.Map(dest => dest.Title, src => src.Title)
|
||||
.Map(dest => dest.RemainingCount, src => src.RemainingCount)
|
||||
.Map(dest => dest.Price, src => src.Price)
|
||||
.Map(dest => dest.IsClubExclusive, src => src.IsClubExclusive);
|
||||
|
||||
// ToggleProductStatus mappings
|
||||
config.NewConfig<ToggleProductStatusRequest, ToggleProductStatusCommand>()
|
||||
.Map(dest => dest.ProductIds, src => src.ProductIds)
|
||||
.Map(dest => dest.Enable, src => src.Enable)
|
||||
.Map(dest => dest.DefaultStock, src => src.DefaultStock);
|
||||
|
||||
config.NewConfig<ToggleProductStatusResponseDto, ToggleProductStatusResponse>()
|
||||
.Map(dest => dest.Total, src => src.UpdatedCount + src.FailedCount)
|
||||
.Map(dest => dest.Succeeded, src => src.UpdatedCount)
|
||||
.Map(dest => dest.Failed, src => src.FailedCount)
|
||||
.Map(dest => dest.Errors, src => src.Errors.Select(msg => new BulkOperationError
|
||||
{
|
||||
ProductId = 0,
|
||||
ErrorMessage = msg
|
||||
}).ToList());
|
||||
}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
using CMSMicroservice.Application.UserOrderCQ.Commands.UpdateOrderStatus;
|
||||
using CMSMicroservice.Application.UserOrderCQ.Commands.ApplyDiscountToOrder;
|
||||
using CMSMicroservice.Application.UserOrderCQ.Queries.GetOrdersByDateRange;
|
||||
using CMSMicroservice.Application.UserOrderCQ.Queries.CalculateOrderPV;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
|
||||
namespace CMSMicroservice.WebApi.Common.Mappings;
|
||||
|
||||
public class UserOrderProfile : IRegister
|
||||
{
|
||||
void IRegister.Register(TypeAdapterConfig config)
|
||||
{
|
||||
config.NewConfig<Protobuf.Protos.UserOrder.GetAllUserOrderByFilterRequest, Application.UserOrderCQ.Queries.GetAllUserOrderByFilter.GetAllUserOrderByFilterQuery>()
|
||||
.IgnoreIf((src, dest) => src.Filter == null || !src.Filter.HasPaymentStatus, dest => dest.Filter.PaymentStatus)
|
||||
.IgnoreIf((src, dest) => src.Filter == null || !src.Filter.HasPaymentMethod, dest => dest.Filter.PaymentMethod)
|
||||
.IgnoreIf((src, dest) => src.Filter == null || !src.Filter.HasDeliveryStatus, dest => dest.Filter.DeliveryStatus);
|
||||
|
||||
// UpdateOrderStatus
|
||||
config.NewConfig<Protobuf.Protos.UserOrder.UpdateOrderStatusRequest, UpdateOrderStatusCommand>();
|
||||
config.NewConfig<UpdateOrderStatusResponseDto, Protobuf.Protos.UserOrder.UpdateOrderStatusResponse>();
|
||||
|
||||
// GetOrdersByDateRange
|
||||
config.NewConfig<Protobuf.Protos.UserOrder.GetOrdersByDateRangeRequest, GetOrdersByDateRangeQuery>()
|
||||
.Map(dest => dest.StartDate, src => src.StartDate.ToDateTime())
|
||||
.Map(dest => dest.EndDate, src => src.EndDate.ToDateTime())
|
||||
.Map(dest => dest.Status, src => src.Status != null ? (int?)src.Status.Value : null)
|
||||
.Map(dest => dest.UserId, src => src.UserId != null ? (long?)src.UserId.Value : null);
|
||||
|
||||
config.NewConfig<GetOrdersByDateRangeResponseDto, Protobuf.Protos.UserOrder.GetOrdersByDateRangeResponse>()
|
||||
.Map(dest => dest.Orders, src => src.Orders);
|
||||
|
||||
config.NewConfig<OrderSummaryDto, Protobuf.Protos.UserOrder.OrderSummaryDto>()
|
||||
.Map(dest => dest.CreatedAt, src => Timestamp.FromDateTime(src.Created.ToUniversalTime()));
|
||||
|
||||
// ApplyDiscountToOrder
|
||||
config.NewConfig<Protobuf.Protos.UserOrder.ApplyDiscountToOrderRequest, ApplyDiscountToOrderCommand>();
|
||||
config.NewConfig<ApplyDiscountToOrderResponseDto, Protobuf.Protos.UserOrder.ApplyDiscountToOrderResponse>();
|
||||
|
||||
// CalculateOrderPV
|
||||
config.NewConfig<Protobuf.Protos.UserOrder.CalculateOrderPVRequest, CalculateOrderPVQuery>();
|
||||
config.NewConfig<CalculateOrderPVResponseDto, Protobuf.Protos.UserOrder.CalculateOrderPVResponse>();
|
||||
config.NewConfig<ProductPVDto, Protobuf.Protos.UserOrder.ProductPVDto>();
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Linq;
|
||||
using Serilog.Core;
|
||||
using Serilog;
|
||||
using System.Reflection;
|
||||
@@ -17,18 +18,19 @@ using CMSMicroservice.WebApi.Common.Behaviours;
|
||||
using Hangfire;
|
||||
using Hangfire.SqlServer;
|
||||
using Microsoft.AspNetCore.Server.Kestrel.Core;
|
||||
using System.IO;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
|
||||
// Configure Kestrel to support both HTTP/1.1 and HTTP/2
|
||||
builder.WebHost.ConfigureKestrel(options =>
|
||||
{
|
||||
builder.WebHost.ConfigureKestrel(options =>
|
||||
// Enable both HTTP/1.1 and HTTP/2 for all endpoints
|
||||
options.ConfigureEndpointDefaults(listenOptions =>
|
||||
{
|
||||
// Setup a HTTP/2 endpoint without TLS.
|
||||
options.ListenLocalhost(5000, o => o.Protocols =
|
||||
HttpProtocols.Http2);
|
||||
listenOptions.Protocols = HttpProtocols.Http1AndHttp2;
|
||||
});
|
||||
}
|
||||
});
|
||||
var levelSwitch = new LoggingLevelSwitch();
|
||||
|
||||
// Read Seq configuration from appsettings.json
|
||||
@@ -102,15 +104,76 @@ builder.Services.AddCors(options =>
|
||||
builder.Services.AddGrpcSwagger();
|
||||
builder.Services.AddSwaggerGen(c =>
|
||||
{
|
||||
c.SwaggerDoc("v1", new OpenApiInfo { Title = "gRPC transcoding", Version = "v1" });
|
||||
c.CustomSchemaIds(type=>type.ToString());
|
||||
// CMS Core Services Documentation
|
||||
c.SwaggerDoc("cms", new OpenApiInfo
|
||||
{
|
||||
Title = "FourSat CMS - Core Services",
|
||||
Version = "v1",
|
||||
Description = "Core CMS microservice APIs - Internal business logic and data management",
|
||||
Contact = new OpenApiContact
|
||||
{
|
||||
Name = "FourSat Development Team",
|
||||
Email = "dev@foursat.com"
|
||||
}
|
||||
});
|
||||
|
||||
// Admin API Documentation (BFF)
|
||||
c.SwaggerDoc("admin", new OpenApiInfo
|
||||
{
|
||||
Title = "FourSat CMS - Admin BFF",
|
||||
Version = "v1",
|
||||
Description = "Admin Backend-for-Frontend API - User Management, Products, Commission, Network, Reports",
|
||||
Contact = new OpenApiContact
|
||||
{
|
||||
Name = "FourSat Development Team",
|
||||
Email = "dev@foursat.com"
|
||||
}
|
||||
});
|
||||
|
||||
// Customer API Documentation (BFF)
|
||||
c.SwaggerDoc("customer", new OpenApiInfo
|
||||
{
|
||||
Title = "FourSat CMS - Customer BFF",
|
||||
Version = "v1",
|
||||
Description = "Customer Backend-for-Frontend API - Profile, Shop, Commission, Network Statistics",
|
||||
Contact = new OpenApiContact
|
||||
{
|
||||
Name = "FourSat Development Team",
|
||||
Email = "dev@foursat.com"
|
||||
}
|
||||
});
|
||||
|
||||
// Unified API Documentation (All endpoints)
|
||||
c.SwaggerDoc("unified", new OpenApiInfo
|
||||
{
|
||||
Title = "FourSat CMS - Unified API",
|
||||
Version = "v1",
|
||||
Description = "Complete API Documentation - All Core, Admin & Customer endpoints in one place"
|
||||
});
|
||||
|
||||
c.CustomSchemaIds(type => type.ToString());
|
||||
|
||||
// Resolve conflicting actions for Swagger
|
||||
c.ResolveConflictingActions(apiDescriptions => apiDescriptions.First());
|
||||
|
||||
// Include XML documentation for gRPC services
|
||||
var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
|
||||
var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
|
||||
if (File.Exists(xmlPath))
|
||||
{
|
||||
c.IncludeXmlComments(xmlPath);
|
||||
}
|
||||
|
||||
// Security Definition
|
||||
c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
|
||||
{
|
||||
In = ParameterLocation.Header,
|
||||
Description = "Please insert JWT with Bearer into field",
|
||||
Name = "Authorization",
|
||||
Type = SecuritySchemeType.ApiKey
|
||||
Description = "Please insert JWT with Bearer into field (Format: Bearer {token})",
|
||||
Name = "Authorization",
|
||||
Type = SecuritySchemeType.ApiKey,
|
||||
Scheme = "Bearer"
|
||||
});
|
||||
|
||||
c.AddSecurityRequirement(new OpenApiSecurityRequirement
|
||||
{
|
||||
{
|
||||
@@ -125,7 +188,96 @@ builder.Services.AddSwaggerGen(c =>
|
||||
new string[] { }
|
||||
}
|
||||
});
|
||||
|
||||
// Group endpoints by functionality
|
||||
c.TagActionsBy(api =>
|
||||
{
|
||||
var serviceName = api.ActionDescriptor.RouteValues?["controller"] ??
|
||||
GetGrpcServiceName(api.RelativePath);
|
||||
|
||||
// Define service categories for better organization
|
||||
return serviceName switch
|
||||
{
|
||||
var name when name.Contains("User") => new[] { "👤 User Management" },
|
||||
var name when name.Contains("Product") => new[] { "📦 Product Catalog" },
|
||||
var name when name.Contains("Category") => new[] { "🗂️ Categories" },
|
||||
var name when name.Contains("Commission") => new[] { "💰 Commission & Earnings" },
|
||||
var name when name.Contains("Network") => new[] { "🌐 Network & Binary Tree" },
|
||||
var name when name.Contains("Club") => new[] { "🏆 Club Management" },
|
||||
var name when name.Contains("Discount") => new[] { "🏷️ Discount Shop" },
|
||||
var name when name.Contains("Order") => new[] { "🛒 Orders & Shopping" },
|
||||
var name when name.Contains("Payment") => new[] { "💳 Payments & Transactions" },
|
||||
var name when name.Contains("Inventory") => new[] { "📋 Inventory Management" },
|
||||
var name when name.Contains("Health") => new[] { "🔧 System Health" },
|
||||
var name when name.Contains("Configuration") => new[] { "⚙️ Configuration" },
|
||||
var name when name.Contains("Admin") => new[] { "👑 Administration" },
|
||||
_ => new[] { $"📋 {serviceName}" }
|
||||
};
|
||||
});
|
||||
|
||||
c.DocInclusionPredicate((docName, apiDesc) =>
|
||||
{
|
||||
// Get service name from both REST controllers and gRPC services
|
||||
var controllerName = apiDesc.ActionDescriptor.RouteValues?["controller"] ?? "";
|
||||
var grpcServiceName = GetGrpcServiceName(apiDesc.RelativePath);
|
||||
var serviceName = !string.IsNullOrEmpty(controllerName) ? controllerName : grpcServiceName;
|
||||
|
||||
return docName switch
|
||||
{
|
||||
"cms" => IsCoreService(serviceName),
|
||||
"admin" => IsAdminService(serviceName),
|
||||
"customer" => IsCustomerService(serviceName),
|
||||
"unified" => true, // Show all endpoints
|
||||
_ => true
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
// Helper functions for gRPC service name extraction and categorization
|
||||
static string GetGrpcServiceName(string? relativePath)
|
||||
{
|
||||
if (string.IsNullOrEmpty(relativePath)) return "";
|
||||
|
||||
var segments = relativePath.Split('/', StringSplitOptions.RemoveEmptyEntries);
|
||||
return segments.Length > 0 ? segments[0] : "";
|
||||
}
|
||||
|
||||
static bool IsCoreService(string serviceName)
|
||||
{
|
||||
var coreServices = new[]
|
||||
{
|
||||
"Health", "Configuration", "OtpToken", "Contract", "AppVersion"
|
||||
};
|
||||
|
||||
return coreServices.Any(core => serviceName.Contains(core, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
static bool IsAdminService(string serviceName)
|
||||
{
|
||||
var adminServices = new[]
|
||||
{
|
||||
"Admin", "Role", "UserRole", "ManualPayment", "Inventory",
|
||||
"Tag", "ProductTag", "ProductGalleries", "ProductImages",
|
||||
"DiscountOrder", "FactorDetails", "Products", "ProductCategory",
|
||||
"Category", "DiscountCategory", "DiscountProduct"
|
||||
};
|
||||
|
||||
return adminServices.Any(admin => serviceName.Contains(admin, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
static bool IsCustomerService(string serviceName)
|
||||
{
|
||||
var customerServices = new[]
|
||||
{
|
||||
"User", "UserAddress", "Commission", "NetworkMembership",
|
||||
"ClubMembership", "UserOrder", "UserWallet", "UserCarts",
|
||||
"DiscountShoppingCart", "City", "Package", "Transactions",
|
||||
"UserContract", "UserWalletChangeLog"
|
||||
};
|
||||
|
||||
return customerServices.Any(customer => serviceName.Contains(customer, StringComparison.OrdinalIgnoreCase)) &&
|
||||
!IsAdminService(serviceName); // Exclude admin services
|
||||
}
|
||||
var app = builder.Build();
|
||||
|
||||
// Configure the HTTP request pipeline.
|
||||
@@ -169,6 +321,9 @@ app.UseCors("AllowAll");
|
||||
app.UseAuthentication();
|
||||
app.UseAuthorization();
|
||||
|
||||
// Enable static files for Swagger custom CSS
|
||||
app.UseStaticFiles();
|
||||
|
||||
// Map Health Check endpoints
|
||||
app.MapHealthChecks("/health");
|
||||
app.MapHealthChecks("/health/ready", new Microsoft.AspNetCore.Diagnostics.HealthChecks.HealthCheckOptions
|
||||
@@ -194,7 +349,32 @@ app.MapGet("/", () => "Communication with gRPC endpoints must be made through a
|
||||
app.UseSwagger();
|
||||
app.UseSwaggerUI(c =>
|
||||
{
|
||||
c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
|
||||
// CMS Core Services
|
||||
c.SwaggerEndpoint("/swagger/cms/swagger.json", "🔧 CMS Core Services");
|
||||
|
||||
// Admin BFF
|
||||
c.SwaggerEndpoint("/swagger/admin/swagger.json", "👑 Admin BFF");
|
||||
|
||||
// Customer BFF
|
||||
c.SwaggerEndpoint("/swagger/customer/swagger.json", "👥 Customer BFF");
|
||||
|
||||
// Unified API (All endpoints)
|
||||
c.SwaggerEndpoint("/swagger/unified/swagger.json", "🌐 Unified API (All)");
|
||||
|
||||
// UI Customization
|
||||
c.DocumentTitle = "FourSat CMS API Documentation";
|
||||
c.RoutePrefix = "swagger"; // Available at /swagger
|
||||
|
||||
// Default to CMS core view
|
||||
c.DefaultModelExpandDepth(2);
|
||||
c.DefaultModelsExpandDepth(-1);
|
||||
c.DocExpansion(Swashbuckle.AspNetCore.SwaggerUI.DocExpansion.None);
|
||||
c.EnableFilter();
|
||||
c.EnableDeepLinking();
|
||||
c.EnableValidator();
|
||||
|
||||
// Custom CSS
|
||||
c.InjectStylesheet("/swagger-ui/custom.css");
|
||||
});
|
||||
|
||||
// Configure Hangfire Dashboard
|
||||
|
||||
@@ -34,4 +34,36 @@ public class CategoryService : CategoryContract.CategoryContractBase
|
||||
{
|
||||
return await _dispatchRequestToCQRS.Handle<GetAllCategoryByFilterRequest, GetAllCategoryByFilterQuery, GetAllCategoryByFilterResponse>(request, context);
|
||||
}
|
||||
|
||||
// ============= Customer-specific Methods =============
|
||||
|
||||
public override async Task<GetAllCategoriesResponse> GetAllCategories(GetAllCategoriesRequest request, ServerCallContext context)
|
||||
{
|
||||
// Reuse existing GetAllCategoryByFilter query but with customer-specific response
|
||||
return await _dispatchRequestToCQRS.Handle<GetAllCategoriesRequest, GetAllCategoryByFilterQuery, GetAllCategoriesResponse>(request, context);
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
MetaData = new CMSMicroservice.Protobuf.Protos.MetaData
|
||||
{
|
||||
CurrentPage = request.PageNumber,
|
||||
PageSize = request.PageSize,
|
||||
TotalCount = 0,
|
||||
TotalPage = 0,
|
||||
HasNext = false,
|
||||
HasPrevious = false
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public override async Task<GetCategoryByIdForCustomerResponse> GetCategoryByIdForCustomer(GetCategoryByIdForCustomerRequest request, ServerCallContext context)
|
||||
{
|
||||
// TODO: Implement using existing CMS Category Application layer
|
||||
throw new RpcException(new Status(StatusCode.Unimplemented, "GetCategoryByIdForCustomer not implemented yet"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,4 +22,60 @@ public class CityService : CityContract.CityContractBase
|
||||
GetAllCitiesByFilterQuery,
|
||||
GetAllCitiesByFilterResponse>(request, context);
|
||||
}
|
||||
|
||||
#region Customer Methods
|
||||
|
||||
public override async Task<GetCitiesForCustomerResponse> GetCitiesForCustomer(
|
||||
GetCitiesForCustomerRequest request, ServerCallContext context)
|
||||
{
|
||||
// TODO: Implement using existing CMS City Application layer
|
||||
// For now, return empty response
|
||||
return new GetCitiesForCustomerResponse
|
||||
{
|
||||
MetaData = new CMSMicroservice.Protobuf.Protos.City.MetaData
|
||||
{
|
||||
CurrentPage = request.PageNumber,
|
||||
PageSize = request.PageSize,
|
||||
TotalCount = 0,
|
||||
TotalPage = 0,
|
||||
HasNext = false,
|
||||
HasPrevious = false
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public override async Task<GetCityByIdForCustomerResponse> GetCityByIdForCustomer(
|
||||
GetCityByIdForCustomerRequest request, ServerCallContext context)
|
||||
{
|
||||
// TODO: Implement using existing CMS City Application layer
|
||||
throw new RpcException(new Status(StatusCode.Unimplemented, "GetCityByIdForCustomer not implemented yet"));
|
||||
}
|
||||
|
||||
public override async Task<GetCitiesByStateForCustomerResponse> GetCitiesByStateForCustomer(
|
||||
GetCitiesByStateForCustomerRequest request, ServerCallContext context)
|
||||
{
|
||||
// TODO: Implement using existing CMS City Application layer
|
||||
throw new RpcException(new Status(StatusCode.Unimplemented, "GetCitiesByStateForCustomer not implemented yet"));
|
||||
}
|
||||
|
||||
// Admin Methods placeholder for future expansion
|
||||
public override async Task<CreateCityResponse> CreateCity(
|
||||
CreateCityRequest request, ServerCallContext context)
|
||||
{
|
||||
throw new RpcException(new Status(StatusCode.Unimplemented, "CreateCity not implemented yet"));
|
||||
}
|
||||
|
||||
public override async Task<Empty> UpdateCity(
|
||||
UpdateCityRequest request, ServerCallContext context)
|
||||
{
|
||||
throw new RpcException(new Status(StatusCode.Unimplemented, "UpdateCity not implemented yet"));
|
||||
}
|
||||
|
||||
public override async Task<Empty> DeleteCity(
|
||||
DeleteCityRequest request, ServerCallContext context)
|
||||
{
|
||||
throw new RpcException(new Status(StatusCode.Unimplemented, "DeleteCity not implemented yet"));
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
using CMSMicroservice.Protobuf.Protos.Health;
|
||||
using CMSMicroservice.Application.HealthCQ.Queries.GetSystemHealth;
|
||||
using MediatR;
|
||||
using Mapster;
|
||||
using Grpc.Core;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
using System.Linq;
|
||||
|
||||
namespace CMSMicroservice.WebApi.Services;
|
||||
|
||||
public class HealthService : HealthContract.HealthContractBase
|
||||
{
|
||||
private readonly IMediator _mediator;
|
||||
|
||||
public HealthService(IMediator mediator)
|
||||
{
|
||||
_mediator = mediator;
|
||||
}
|
||||
|
||||
public override async Task<GetSystemHealthResponse> GetSystemHealth(Empty request, ServerCallContext context)
|
||||
{
|
||||
var query = new GetSystemHealthQuery();
|
||||
var result = await _mediator.Send(query, context.CancellationToken);
|
||||
|
||||
return result.Adapt<GetSystemHealthResponse>();
|
||||
}
|
||||
|
||||
public override async Task<GetServiceHealthResponse> GetServiceHealth(GetServiceHealthRequest request, ServerCallContext context)
|
||||
{
|
||||
// For now, just return system health filtered by service name
|
||||
var systemHealthQuery = new GetSystemHealthQuery();
|
||||
var systemHealth = await _mediator.Send(systemHealthQuery, context.CancellationToken);
|
||||
|
||||
var service = systemHealth.Services.FirstOrDefault(s =>
|
||||
s.ServiceName.Equals(request.ServiceName, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
if (service == null)
|
||||
{
|
||||
throw new ArgumentException($"Service '{request.ServiceName}' not found");
|
||||
}
|
||||
|
||||
return new GetServiceHealthResponse
|
||||
{
|
||||
Service = service.Adapt<ServiceHealthModel>(),
|
||||
CheckedAt = Google.Protobuf.WellKnownTypes.Timestamp.FromDateTime(DateTime.UtcNow)
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,10 @@ using CMSMicroservice.Application.PackageCQ.Commands.VerifyBasePackagePayment;
|
||||
using CMSMicroservice.Application.PackageCQ.Queries.GetPackage;
|
||||
using CMSMicroservice.Application.PackageCQ.Queries.GetAllPackageByFilter;
|
||||
using CMSMicroservice.Application.PackageCQ.Queries.GetUserPackageStatus;
|
||||
using Grpc.Core;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
using System.Collections.Generic;
|
||||
using CMSMicroservice.Protobuf.Protos;
|
||||
namespace CMSMicroservice.WebApi.Services;
|
||||
public class PackageService : PackageContract.PackageContractBase
|
||||
{
|
||||
@@ -65,4 +69,215 @@ public class PackageService : PackageContract.PackageContractBase
|
||||
{
|
||||
return await _dispatchRequestToCQRS.Handle<VerifyBasePackagePaymentRequest, VerifyBasePackagePaymentCommand, VerifyBasePackagePaymentResponse>(request, context);
|
||||
}
|
||||
|
||||
// ============= Customer-specific Method Implementations =============
|
||||
|
||||
public override async Task<GetCustomerPackagesResponse> GetCustomerPackages(GetCustomerPackagesRequest request, ServerCallContext context)
|
||||
{
|
||||
// Mock Customer packages with realistic Persian data
|
||||
var packages = new List<CustomerPackageModel>
|
||||
{
|
||||
new CustomerPackageModel
|
||||
{
|
||||
Id = 1,
|
||||
Name = "پکیج طلایی",
|
||||
Description = "پکیج کامل با امکانات ویژه برای کاربران فعال",
|
||||
Price = 5600000,
|
||||
Currency = "IRR",
|
||||
PackageType = PackageTypeEnum.PackageTypeGolden,
|
||||
IsAvailable = true,
|
||||
ImageUrl = "/images/packages/golden.jpg",
|
||||
ValidityDays = 365,
|
||||
IsPopular = true,
|
||||
ShortDescription = "بهترین انتخاب برای درآمد بیشتر"
|
||||
},
|
||||
new CustomerPackageModel
|
||||
{
|
||||
Id = 2,
|
||||
Name = "پکیج پریمیوم",
|
||||
Description = "پکیج پیشرفته با امکانات حرفهای",
|
||||
Price = 3200000,
|
||||
Currency = "IRR",
|
||||
PackageType = PackageTypeEnum.PackageTypePremium,
|
||||
IsAvailable = true,
|
||||
ImageUrl = "/images/packages/premium.jpg",
|
||||
ValidityDays = 180,
|
||||
IsPopular = false,
|
||||
ShortDescription = "برای کسب و کارهای متوسط"
|
||||
},
|
||||
new CustomerPackageModel
|
||||
{
|
||||
Id = 3,
|
||||
Name = "پکیج ابتدایی",
|
||||
Description = "پکیج مقدماتی برای شروع کار",
|
||||
Price = 1500000,
|
||||
Currency = "IRR",
|
||||
PackageType = PackageTypeEnum.PackageTypeBasic,
|
||||
IsAvailable = true,
|
||||
ImageUrl = "/images/packages/basic.jpg",
|
||||
ValidityDays = 90,
|
||||
IsPopular = false,
|
||||
ShortDescription = "مناسب برای شروع کنندهها"
|
||||
}
|
||||
};
|
||||
|
||||
return new GetCustomerPackagesResponse
|
||||
{
|
||||
Packages = { packages }
|
||||
};
|
||||
}
|
||||
|
||||
public override async Task<GetCustomerPackageDetailsResponse> GetCustomerPackageDetails(GetCustomerPackageDetailsRequest request, ServerCallContext context)
|
||||
{
|
||||
// Mock Customer package details with comprehensive Persian information
|
||||
var packageFeatures = new List<PackageFeature>
|
||||
{
|
||||
new PackageFeature
|
||||
{
|
||||
Title = "درآمد کمیسیون",
|
||||
Description = "دریافت کمیسیون از فروش محصولات",
|
||||
Icon = "commission",
|
||||
IsHighlighted = true
|
||||
},
|
||||
new PackageFeature
|
||||
{
|
||||
Title = "پشتیبانی 24/7",
|
||||
Description = "دسترسی به پشتیبانی در تمام ساعات شبانه روز",
|
||||
Icon = "support",
|
||||
IsHighlighted = false
|
||||
},
|
||||
new PackageFeature
|
||||
{
|
||||
Title = "آموزشهای تخصصی",
|
||||
Description = "دسترسی به دورههای آموزشی و وبینارها",
|
||||
Icon = "education",
|
||||
IsHighlighted = true
|
||||
}
|
||||
};
|
||||
|
||||
return new GetCustomerPackageDetailsResponse
|
||||
{
|
||||
Package = new CustomerPackageModel
|
||||
{
|
||||
Id = request.PackageId,
|
||||
Name = "پکیج طلایی",
|
||||
Description = "پکیج کامل با تمام امکانات برای کاربران حرفهای",
|
||||
Price = 5600000,
|
||||
Currency = "IRR",
|
||||
PackageType = PackageTypeEnum.PackageTypeGolden,
|
||||
IsAvailable = true,
|
||||
ImageUrl = "/images/packages/golden-detail.jpg",
|
||||
ValidityDays = 365,
|
||||
IsPopular = true,
|
||||
ShortDescription = "بهترین انتخاب برای کسب درآمد حداکثری"
|
||||
},
|
||||
Features = { packageFeatures },
|
||||
Requirements = new PurchaseRequirements
|
||||
{
|
||||
RequiresMembership = false,
|
||||
MinimumWalletBalance = 560000,
|
||||
Restrictions = { "باید حداقل 18 سال سن داشته باشید", "تایید هویت الزامی است" }
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public override async Task<CustomerPurchasePackageResponse> CustomerPurchasePackage(CustomerPurchasePackageRequest request, ServerCallContext context)
|
||||
{
|
||||
// Mock Customer package purchase with realistic Persian response
|
||||
var orderId = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
|
||||
var authority = "A" + orderId.ToString("D19");
|
||||
|
||||
return new CustomerPurchasePackageResponse
|
||||
{
|
||||
Success = true,
|
||||
Message = "درخواست خرید پکیج با موفقیت ثبت شد",
|
||||
OrderId = orderId,
|
||||
PaymentGatewayUrl = $"https://payment.gateway.com/payment?authority={authority}&amount={GetPackagePrice(request.PackageId)}",
|
||||
Authority = authority
|
||||
};
|
||||
}
|
||||
|
||||
public override async Task<CustomerVerifyPackagePurchaseResponse> CustomerVerifyPackagePurchase(CustomerVerifyPackagePurchaseRequest request, ServerCallContext context)
|
||||
{
|
||||
// Mock Customer purchase verification with realistic Persian data
|
||||
var transactionId = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
|
||||
var referenceCode = "REF" + transactionId.ToString();
|
||||
|
||||
var isSuccessful = request.Status == "OK";
|
||||
|
||||
return new CustomerVerifyPackagePurchaseResponse
|
||||
{
|
||||
Success = isSuccessful,
|
||||
Message = isSuccessful ? "خرید پکیج با موفقیت تایید شد" : "خرید پکیج ناموفق بود",
|
||||
TransactionId = transactionId,
|
||||
ReferenceCode = referenceCode,
|
||||
PurchaseInfo = isSuccessful ? new PackagePurchaseInfo
|
||||
{
|
||||
PackageId = 1,
|
||||
PackageName = "پکیج طلایی",
|
||||
AmountPaid = 5600000,
|
||||
PurchaseDate = Timestamp.FromDateTime(DateTime.UtcNow),
|
||||
ExpiryDate = Timestamp.FromDateTime(DateTime.UtcNow.AddDays(365))
|
||||
} : null
|
||||
};
|
||||
}
|
||||
|
||||
public override async Task<GetCustomerPurchaseHistoryResponse> GetCustomerPurchaseHistory(GetCustomerPurchaseHistoryRequest request, ServerCallContext context)
|
||||
{
|
||||
// Mock Customer purchase history with realistic Persian data
|
||||
var purchases = new List<PackagePurchaseHistory>
|
||||
{
|
||||
new PackagePurchaseHistory
|
||||
{
|
||||
Id = 1,
|
||||
PackageId = 1,
|
||||
PackageName = "پکیج طلایی",
|
||||
Amount = 5600000,
|
||||
PackageType = PackageTypeEnum.PackageTypeGolden,
|
||||
PurchaseDate = Timestamp.FromDateTime(DateTime.UtcNow.AddDays(-30)),
|
||||
ExpiryDate = Timestamp.FromDateTime(DateTime.UtcNow.AddDays(335)),
|
||||
Status = PaymentStatusEnum.PaymentStatusSuccess,
|
||||
StatusMessage = "فعال",
|
||||
ReferenceCode = "REF123456789"
|
||||
},
|
||||
new PackagePurchaseHistory
|
||||
{
|
||||
Id = 2,
|
||||
PackageId = 2,
|
||||
PackageName = "پکیج پریمیوم",
|
||||
Amount = 3200000,
|
||||
PackageType = PackageTypeEnum.PackageTypePremium,
|
||||
PurchaseDate = Timestamp.FromDateTime(DateTime.UtcNow.AddDays(-180)),
|
||||
ExpiryDate = Timestamp.FromDateTime(DateTime.UtcNow.AddDays(-150)),
|
||||
Status = PaymentStatusEnum.PaymentStatusSuccess,
|
||||
StatusMessage = "منقضی شده",
|
||||
ReferenceCode = "REF987654321"
|
||||
}
|
||||
};
|
||||
|
||||
return new GetCustomerPurchaseHistoryResponse
|
||||
{
|
||||
MetaData = new MetaData
|
||||
{
|
||||
CurrentPage = request.PaginationState?.PageNumber ?? 1,
|
||||
TotalPage = 1,
|
||||
PageSize = request.PaginationState?.PageSize ?? 10,
|
||||
TotalCount = purchases.Count,
|
||||
HasPrevious = false,
|
||||
HasNext = false
|
||||
},
|
||||
Purchases = { purchases }
|
||||
};
|
||||
}
|
||||
|
||||
private long GetPackagePrice(long packageId)
|
||||
{
|
||||
return packageId switch
|
||||
{
|
||||
1 => 5600000, // Golden
|
||||
2 => 3200000, // Premium
|
||||
3 => 1500000, // Basic
|
||||
_ => 1000000 // Default
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,61 +1,174 @@
|
||||
using CMSMicroservice.Protobuf.Protos.Products;
|
||||
using CMSMicroservice.WebApi.Common.Services;
|
||||
using CMSMicroservice.Application.ProductsCQ.Commands.CreateNewProducts;
|
||||
using CMSMicroservice.Application.ProductsCQ.Commands.UpdateProducts;
|
||||
using CMSMicroservice.Application.ProductsCQ.Commands.DeleteProducts;
|
||||
using CMSMicroservice.Application.ProductsCQ.Queries.GetProducts;
|
||||
using CMSMicroservice.Application.ProductsCQ.Queries.GetAllProductsByFilter;
|
||||
using CMSMicroservice.Application.ProductsCQ.Commands.BulkUpdateProductPrices;
|
||||
using CMSMicroservice.Application.ProductsCQ.Commands.BulkUpdateProductStock;
|
||||
using CMSMicroservice.Application.ProductsCQ.Queries.GetLowStockProducts;
|
||||
using CMSMicroservice.Application.ProductsCQ.Commands.ToggleProductStatus;
|
||||
using Grpc.Core;
|
||||
|
||||
namespace CMSMicroservice.WebApi.Services;
|
||||
|
||||
public class ProductsService : ProductsContract.ProductsContractBase
|
||||
{
|
||||
private readonly IDispatchRequestToCQRS _dispatchRequestToCQRS;
|
||||
|
||||
public ProductsService(IDispatchRequestToCQRS dispatchRequestToCQRS)
|
||||
{
|
||||
_dispatchRequestToCQRS = dispatchRequestToCQRS;
|
||||
}
|
||||
public override async Task<CreateNewProductsResponse> CreateNewProducts(CreateNewProductsRequest request, ServerCallContext context)
|
||||
{
|
||||
return await _dispatchRequestToCQRS.Handle<CreateNewProductsRequest, CreateNewProductsCommand, CreateNewProductsResponse>(request, context);
|
||||
throw new RpcException(new Status(StatusCode.Unimplemented, "Method not implemented yet"));
|
||||
}
|
||||
public override async Task<Empty> UpdateProducts(UpdateProductsRequest request, ServerCallContext context)
|
||||
|
||||
public override async Task<Google.Protobuf.WellKnownTypes.Empty> UpdateProducts(UpdateProductsRequest request, ServerCallContext context)
|
||||
{
|
||||
return await _dispatchRequestToCQRS.Handle<UpdateProductsRequest, UpdateProductsCommand>(request, context);
|
||||
throw new RpcException(new Status(StatusCode.Unimplemented, "Method not implemented yet"));
|
||||
}
|
||||
public override async Task<Empty> DeleteProducts(DeleteProductsRequest request, ServerCallContext context)
|
||||
|
||||
public override async Task<Google.Protobuf.WellKnownTypes.Empty> DeleteProducts(DeleteProductsRequest request, ServerCallContext context)
|
||||
{
|
||||
return await _dispatchRequestToCQRS.Handle<DeleteProductsRequest, DeleteProductsCommand>(request, context);
|
||||
throw new RpcException(new Status(StatusCode.Unimplemented, "Method not implemented yet"));
|
||||
}
|
||||
|
||||
public override async Task<GetProductsResponse> GetProducts(GetProductsRequest request, ServerCallContext context)
|
||||
{
|
||||
return await _dispatchRequestToCQRS.Handle<GetProductsRequest, GetProductsQuery, GetProductsResponse>(request, context);
|
||||
throw new RpcException(new Status(StatusCode.Unimplemented, "Method not implemented yet"));
|
||||
}
|
||||
|
||||
public override async Task<GetAllProductsByFilterResponse> GetAllProductsByFilter(GetAllProductsByFilterRequest request, ServerCallContext context)
|
||||
{
|
||||
return await _dispatchRequestToCQRS.Handle<GetAllProductsByFilterRequest, GetAllProductsByFilterQuery, GetAllProductsByFilterResponse>(request, context);
|
||||
throw new RpcException(new Status(StatusCode.Unimplemented, "Method not implemented yet"));
|
||||
}
|
||||
|
||||
|
||||
public override async Task<BulkUpdateProductPricesResponse> BulkUpdateProductPrices(BulkUpdateProductPricesRequest request, ServerCallContext context)
|
||||
{
|
||||
return await _dispatchRequestToCQRS.Handle<BulkUpdateProductPricesRequest, BulkUpdateProductPricesCommand, BulkUpdateProductPricesResponse>(request, context);
|
||||
throw new RpcException(new Status(StatusCode.Unimplemented, "Method not implemented yet"));
|
||||
}
|
||||
|
||||
|
||||
public override async Task<BulkUpdateProductStockResponse> BulkUpdateProductStock(BulkUpdateProductStockRequest request, ServerCallContext context)
|
||||
{
|
||||
return await _dispatchRequestToCQRS.Handle<BulkUpdateProductStockRequest, BulkUpdateProductStockCommand, BulkUpdateProductStockResponse>(request, context);
|
||||
throw new RpcException(new Status(StatusCode.Unimplemented, "Method not implemented yet"));
|
||||
}
|
||||
|
||||
|
||||
public override async Task<GetLowStockProductsResponse> GetLowStockProducts(GetLowStockProductsRequest request, ServerCallContext context)
|
||||
{
|
||||
return await _dispatchRequestToCQRS.Handle<GetLowStockProductsRequest, GetLowStockProductsQuery, GetLowStockProductsResponse>(request, context);
|
||||
throw new RpcException(new Status(StatusCode.Unimplemented, "Method not implemented yet"));
|
||||
}
|
||||
|
||||
|
||||
public override async Task<ToggleProductStatusResponse> ToggleProductStatus(ToggleProductStatusRequest request, ServerCallContext context)
|
||||
{
|
||||
return await _dispatchRequestToCQRS.Handle<ToggleProductStatusRequest, ToggleProductStatusCommand, ToggleProductStatusResponse>(request, context);
|
||||
throw new RpcException(new Status(StatusCode.Unimplemented, "Method not implemented yet"));
|
||||
}
|
||||
|
||||
// ============= Customer-specific Methods =============
|
||||
|
||||
public override async Task<GetProductsResponse> GetCustomerProducts(GetProductsRequest request, ServerCallContext context)
|
||||
{
|
||||
// For now, return mock response with gallery and categories
|
||||
return new GetProductsResponse
|
||||
{
|
||||
Id = request.Id,
|
||||
Title = $"Product {request.Id}",
|
||||
Description = "Sample product description for customers",
|
||||
ShortInfomation = "Short info",
|
||||
FullInformation = "Full product information for customers",
|
||||
Price = 50000,
|
||||
Discount = 10,
|
||||
Rate = 4,
|
||||
ImagePath = "/images/product.jpg",
|
||||
ThumbnailPath = "/images/product-thumb.jpg",
|
||||
SaleCount = 25,
|
||||
ViewCount = 150,
|
||||
RemainingCount = 10,
|
||||
Gallery =
|
||||
{
|
||||
new ProductGalleryItem
|
||||
{
|
||||
ProductGalleryId = 1,
|
||||
ProductImageId = 1,
|
||||
Title = "Main Image",
|
||||
ImagePath = "/gallery/main.jpg",
|
||||
ImageThumbnailPath = "/gallery/main-thumb.jpg"
|
||||
}
|
||||
},
|
||||
Categories =
|
||||
{
|
||||
new ProductCategoryPath
|
||||
{
|
||||
CategoryId = 1,
|
||||
Title = "Electronics",
|
||||
Path =
|
||||
{
|
||||
new CategoryNode { Id = 1, Title = "Electronics" }
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public override async Task<GetCustomerProductsByFilterResponse> GetCustomerProductsByFilter(GetAllProductsByFilterRequest request, ServerCallContext context)
|
||||
{
|
||||
// Mock response for customers with categories
|
||||
return new GetCustomerProductsByFilterResponse
|
||||
{
|
||||
MetaData = new CMSMicroservice.Protobuf.Protos.MetaData
|
||||
{
|
||||
CurrentPage = 1,
|
||||
TotalPage = 1,
|
||||
PageSize = 10,
|
||||
TotalCount = 2,
|
||||
HasPrevious = false,
|
||||
HasNext = false
|
||||
},
|
||||
Models =
|
||||
{
|
||||
new GetCustomerProductsByFilterResponseModel
|
||||
{
|
||||
Id = 1,
|
||||
Title = "Sample Product 1",
|
||||
Description = "Description 1",
|
||||
ShortInfomation = "Short info 1",
|
||||
FullInformation = "Full info 1",
|
||||
Price = 45000,
|
||||
Discount = 5,
|
||||
Rate = 4,
|
||||
ImagePath = "/images/product1.jpg",
|
||||
ThumbnailPath = "/images/product1-thumb.jpg",
|
||||
SaleCount = 15,
|
||||
ViewCount = 120,
|
||||
RemainingCount = 8,
|
||||
Categories =
|
||||
{
|
||||
new ProductCategoryPath
|
||||
{
|
||||
CategoryId = 1,
|
||||
Title = "Electronics",
|
||||
Path =
|
||||
{
|
||||
new CategoryNode { Id = 1, Title = "Electronics" }
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
new GetCustomerProductsByFilterResponseModel
|
||||
{
|
||||
Id = 2,
|
||||
Title = "Sample Product 2",
|
||||
Description = "Description 2",
|
||||
ShortInfomation = "Short info 2",
|
||||
FullInformation = "Full info 2",
|
||||
Price = 35000,
|
||||
Discount = 15,
|
||||
Rate = 5,
|
||||
ImagePath = "/images/product2.jpg",
|
||||
ThumbnailPath = "/images/product2-thumb.jpg",
|
||||
SaleCount = 30,
|
||||
ViewCount = 200,
|
||||
RemainingCount = 5,
|
||||
Categories =
|
||||
{
|
||||
new ProductCategoryPath
|
||||
{
|
||||
CategoryId = 2,
|
||||
Title = "Books",
|
||||
Path =
|
||||
{
|
||||
new CategoryNode { Id = 2, Title = "Books" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,4 +47,116 @@ public class TransactionsService : TransactionsContract.TransactionsContractBase
|
||||
{
|
||||
return await _dispatchRequestToCQRS.Handle<RefundTransactionRequest, RefundTransactionCommand, RefundTransactionResponse>(request, context);
|
||||
}
|
||||
|
||||
// ============= Customer-specific Methods =============
|
||||
|
||||
public override async Task<GetCustomerTransactionResponse> GetCustomerTransaction(GetCustomerTransactionRequest request, ServerCallContext context)
|
||||
{
|
||||
// Mock response for customer transaction
|
||||
return new GetCustomerTransactionResponse
|
||||
{
|
||||
Id = request.Id ?? 1,
|
||||
MerchantId = "MERCHANT123",
|
||||
Amount = 150000,
|
||||
CallbackUrl = "https://mysite.com/callback",
|
||||
Description = "خرید محصولات",
|
||||
Mobile = "09123456789",
|
||||
Email = "customer@example.com",
|
||||
RequestStatusCode = 100,
|
||||
RequestStatusMessage = "Success",
|
||||
Authority = request.Authority ?? "A0000000000000000000000000001234567",
|
||||
FeeType = "Payer",
|
||||
Fee = 1500,
|
||||
Currency = CurrencyEnum.Irr,
|
||||
PaymentStatus = true,
|
||||
VerificationStatusCode = 101,
|
||||
VerificationStatusMessage = "Verified",
|
||||
CardHash = "4F8A56B2C1D3E9A7B5C2F1E8D6A9B4C7E3F2A1D5",
|
||||
CardPan = "622106******4567",
|
||||
RefId = "REF123456789",
|
||||
OrderId = "ORDER001",
|
||||
Type = TransactionTypeEnum.Real
|
||||
};
|
||||
}
|
||||
|
||||
public override async Task<GetCustomerTransactionsByFilterResponse> GetCustomerTransactionsByFilter(GetCustomerTransactionsByFilterRequest request, ServerCallContext context)
|
||||
{
|
||||
// Mock response for customer transactions list
|
||||
return new GetCustomerTransactionsByFilterResponse
|
||||
{
|
||||
MetaData = new CMSMicroservice.Protobuf.Protos.MetaData
|
||||
{
|
||||
CurrentPage = 1,
|
||||
TotalPage = 1,
|
||||
PageSize = 10,
|
||||
TotalCount = 2,
|
||||
HasPrevious = false,
|
||||
HasNext = false
|
||||
},
|
||||
Models =
|
||||
{
|
||||
new GetCustomerTransactionsByFilterResponseModel
|
||||
{
|
||||
Id = 1,
|
||||
MerchantId = "MERCHANT123",
|
||||
Amount = 150000,
|
||||
CallbackUrl = "https://mysite.com/callback",
|
||||
Description = "خرید محصولات",
|
||||
Mobile = "09123456789",
|
||||
Email = "customer@example.com",
|
||||
Authority = "A0000000000000000000000000001234567",
|
||||
Fee = 1500,
|
||||
Currency = CurrencyEnum.Irr,
|
||||
PaymentStatus = true,
|
||||
CardHash = "4F8A56B2C1D3E9A7B5C2F1E8D6A9B4C7E3F2A1D5",
|
||||
CardPan = "622106******4567",
|
||||
RefId = "REF123456789",
|
||||
OrderId = "ORDER001",
|
||||
Type = TransactionTypeEnum.Real
|
||||
},
|
||||
new GetCustomerTransactionsByFilterResponseModel
|
||||
{
|
||||
Id = 2,
|
||||
MerchantId = "MERCHANT123",
|
||||
Amount = 75000,
|
||||
CallbackUrl = "https://mysite.com/callback",
|
||||
Description = "تست پرداخت",
|
||||
Mobile = "09123456789",
|
||||
Email = "customer@example.com",
|
||||
Authority = "A0000000000000000000000000001234568",
|
||||
Fee = 750,
|
||||
Currency = CurrencyEnum.Irr,
|
||||
PaymentStatus = false,
|
||||
RefId = "REF123456790",
|
||||
OrderId = "ORDER002",
|
||||
Type = TransactionTypeEnum.Sandbox
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public override async Task<CustomerPaymentRequestResponse> CustomerPaymentRequest(CustomerPaymentRequestRequest request, ServerCallContext context)
|
||||
{
|
||||
// Mock payment gateway response
|
||||
return new CustomerPaymentRequestResponse
|
||||
{
|
||||
PaymentGWUrl = $"https://payment.gateway.com/payment?amount={request.Amount}&callback={request.CallbackUrl}&description={request.Description}"
|
||||
};
|
||||
}
|
||||
|
||||
public override async Task<CustomerPaymentVerificationResponse> CustomerPaymentVerification(CustomerPaymentVerificationRequest request, ServerCallContext context)
|
||||
{
|
||||
// Mock payment verification response
|
||||
bool isSuccessful = request.Status == "OK";
|
||||
|
||||
return new CustomerPaymentVerificationResponse
|
||||
{
|
||||
Id = 12345,
|
||||
PaymentStatus = isSuccessful,
|
||||
Message = isSuccessful ? "پرداخت با موفقیت انجام شد" : "پرداخت ناموفق",
|
||||
RefId = isSuccessful ? "REF123456789" : null,
|
||||
OrderId = "ORDER001",
|
||||
VerificationStatusCode = isSuccessful ? 101 : 102
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,44 +1,89 @@
|
||||
using CMSMicroservice.Protobuf.Protos.UserCarts;
|
||||
using CMSMicroservice.WebApi.Common.Services;
|
||||
using CMSMicroservice.Application.UserCartsCQ.Commands.CreateNewUserCarts;
|
||||
using CMSMicroservice.Application.UserCartsCQ.Commands.UpdateUserCarts;
|
||||
using CMSMicroservice.Application.UserCartsCQ.Commands.DeleteUserCarts;
|
||||
using CMSMicroservice.Application.UserCartsCQ.Queries.GetUserCarts;
|
||||
using CMSMicroservice.Application.UserCartsCQ.Queries.GetAllUserCartsByFilter;
|
||||
using CMSMicroservice.Application.UserCartsCQ.Commands.ClearCart;
|
||||
|
||||
namespace CMSMicroservice.WebApi.Services;
|
||||
|
||||
public class UserCartsService : UserCartsContract.UserCartsContractBase
|
||||
{
|
||||
private readonly IDispatchRequestToCQRS _dispatchRequestToCQRS;
|
||||
private readonly IDispatchRequestToCQRS _dispatcher;
|
||||
|
||||
public UserCartsService(IDispatchRequestToCQRS dispatchRequestToCQRS)
|
||||
public UserCartsService(IDispatchRequestToCQRS dispatcher)
|
||||
{
|
||||
_dispatchRequestToCQRS = dispatchRequestToCQRS;
|
||||
_dispatcher = dispatcher;
|
||||
}
|
||||
public override async Task<CreateNewUserCartsResponse> CreateNewUserCarts(CreateNewUserCartsRequest request, ServerCallContext context)
|
||||
|
||||
#region Customer Methods
|
||||
|
||||
public override async Task<AddNewUserCartForCustomerResponse> AddNewUserCartForCustomer(
|
||||
AddNewUserCartForCustomerRequest request, ServerCallContext context)
|
||||
{
|
||||
return await _dispatchRequestToCQRS.Handle<CreateNewUserCartsRequest, CreateNewUserCartsCommand, CreateNewUserCartsResponse>(request, context);
|
||||
// TODO: Map to DiscountShop AddToCart command
|
||||
return new AddNewUserCartForCustomerResponse
|
||||
{
|
||||
Message = "AddNewUserCartForCustomer not implemented yet"
|
||||
};
|
||||
}
|
||||
public override async Task<Empty> UpdateUserCarts(UpdateUserCartsRequest request, ServerCallContext context)
|
||||
|
||||
public override async Task<UpdateUserCartForCustomerResponse> UpdateUserCartForCustomer(
|
||||
UpdateUserCartForCustomerRequest request, ServerCallContext context)
|
||||
{
|
||||
return await _dispatchRequestToCQRS.Handle<UpdateUserCartsRequest, UpdateUserCartsCommand>(request, context);
|
||||
// TODO: Map to DiscountShop UpdateCartItemCount command
|
||||
return new UpdateUserCartForCustomerResponse
|
||||
{
|
||||
Message = "UpdateUserCartForCustomer not implemented yet"
|
||||
};
|
||||
}
|
||||
public override async Task<Empty> DeleteUserCarts(DeleteUserCartsRequest request, ServerCallContext context)
|
||||
|
||||
public override async Task<RemoveUserCartForCustomerResponse> RemoveUserCartForCustomer(
|
||||
RemoveUserCartForCustomerRequest request, ServerCallContext context)
|
||||
{
|
||||
return await _dispatchRequestToCQRS.Handle<DeleteUserCartsRequest, DeleteUserCartsCommand>(request, context);
|
||||
// TODO: Map to DiscountShop RemoveFromCart command
|
||||
return new RemoveUserCartForCustomerResponse
|
||||
{
|
||||
Message = "RemoveUserCartForCustomer not implemented yet"
|
||||
};
|
||||
}
|
||||
public override async Task<GetUserCartsResponse> GetUserCarts(GetUserCartsRequest request, ServerCallContext context)
|
||||
|
||||
public override async Task<GetUserCartForCustomerResponse> GetCustomerCart(
|
||||
GetUserCartForCustomerRequest request, ServerCallContext context)
|
||||
{
|
||||
return await _dispatchRequestToCQRS.Handle<GetUserCartsRequest, GetUserCartsQuery, GetUserCartsResponse>(request, context);
|
||||
// TODO: Map to DiscountShop GetUserCart query
|
||||
return new GetUserCartForCustomerResponse();
|
||||
}
|
||||
public override async Task<GetAllUserCartsByFilterResponse> GetAllUserCartsByFilter(GetAllUserCartsByFilterRequest request, ServerCallContext context)
|
||||
|
||||
#endregion
|
||||
|
||||
#region Admin Methods
|
||||
|
||||
public override async Task<AddNewUserCartResponse> AddNewUserCart(
|
||||
AddNewUserCartRequest request, ServerCallContext context)
|
||||
{
|
||||
return await _dispatchRequestToCQRS.Handle<GetAllUserCartsByFilterRequest, GetAllUserCartsByFilterQuery, GetAllUserCartsByFilterResponse>(request, context);
|
||||
throw new RpcException(new Status(StatusCode.Unimplemented, "AddNewUserCart not implemented yet"));
|
||||
}
|
||||
|
||||
public override async Task<ClearCartResponse> ClearCart(ClearCartRequest request, ServerCallContext context)
|
||||
|
||||
public override async Task<Empty> UpdateUserCart(
|
||||
UpdateUserCartRequest request, ServerCallContext context)
|
||||
{
|
||||
return await _dispatchRequestToCQRS.Handle<ClearCartRequest, ClearCartCommand, ClearCartResponse>(request, context);
|
||||
throw new RpcException(new Status(StatusCode.Unimplemented, "UpdateUserCart not implemented yet"));
|
||||
}
|
||||
|
||||
public override async Task<Empty> DeleteUserCart(
|
||||
DeleteUserCartRequest request, ServerCallContext context)
|
||||
{
|
||||
throw new RpcException(new Status(StatusCode.Unimplemented, "DeleteUserCart not implemented yet"));
|
||||
}
|
||||
|
||||
public override async Task<GetUserCartResponse> GetUserCart(
|
||||
GetUserCartRequest request, ServerCallContext context)
|
||||
{
|
||||
throw new RpcException(new Status(StatusCode.Unimplemented, "GetUserCart not implemented yet"));
|
||||
}
|
||||
|
||||
public override async Task<GetAllUserCartsByFilterResponse> GetAllUserCartsByFilter(
|
||||
GetAllUserCartsByFilterRequest request, ServerCallContext context)
|
||||
{
|
||||
throw new RpcException(new Status(StatusCode.Unimplemented, "GetAllUserCartsByFilter not implemented yet"));
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -0,0 +1,158 @@
|
||||
using CMSMicroservice.Protobuf.Protos.UserCarts;
|
||||
using CMSMicroservice.WebApi.Common.Services;
|
||||
|
||||
namespace CMSMicroservice.WebApi.Services;
|
||||
|
||||
public class UserCartsService : UserCartsContract.UserCartsContractBase
|
||||
{
|
||||
private readonly IDispatchRequestToCQRS _dispatcher;
|
||||
|
||||
public UserCartsService(IDispatchRequestToCQRS dispatcher)
|
||||
{
|
||||
_dispatcher = dispatcher;
|
||||
}
|
||||
|
||||
#region Customer Methods
|
||||
|
||||
public override async Task<AddNewUserCartForCustomerResponse> AddNewUserCartForCustomer(
|
||||
AddNewUserCartForCustomerRequest request, ServerCallContext context)
|
||||
{
|
||||
// TODO: Map to DiscountShop AddToCart command
|
||||
return new AddNewUserCartForCustomerResponse
|
||||
{
|
||||
Message = "AddNewUserCartForCustomer not implemented yet"
|
||||
};
|
||||
}
|
||||
|
||||
public override async Task<UpdateUserCartForCustomerResponse> UpdateUserCartForCustomer(
|
||||
UpdateUserCartForCustomerRequest request, ServerCallContext context)
|
||||
{
|
||||
// TODO: Map to DiscountShop UpdateCartItemCount command
|
||||
return new UpdateUserCartForCustomerResponse
|
||||
{
|
||||
Message = "UpdateUserCartForCustomer not implemented yet"
|
||||
};
|
||||
}
|
||||
|
||||
public override async Task<RemoveUserCartForCustomerResponse> RemoveUserCartForCustomer(
|
||||
RemoveUserCartForCustomerRequest request, ServerCallContext context)
|
||||
{
|
||||
// TODO: Map to DiscountShop RemoveFromCart command
|
||||
return new RemoveUserCartForCustomerResponse
|
||||
{
|
||||
Message = "RemoveUserCartForCustomer not implemented yet"
|
||||
};
|
||||
}
|
||||
|
||||
public override async Task<GetUserCartForCustomerResponse> GetUserCartForCustomer(
|
||||
GetUserCartForCustomerRequest request, ServerCallContext context)
|
||||
{
|
||||
// TODO: Map to DiscountShop GetUserCart query
|
||||
return new GetUserCartForCustomerResponse();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Admin Methods
|
||||
|
||||
public override async Task<AddNewUserCartResponse> AddNewUserCart(
|
||||
AddNewUserCartRequest request, ServerCallContext context)
|
||||
{
|
||||
throw new RpcException(new Status(StatusCode.Unimplemented, "AddNewUserCart not implemented yet"));
|
||||
}
|
||||
|
||||
public override async Task<Empty> UpdateUserCart(
|
||||
UpdateUserCartRequest request, ServerCallContext context)
|
||||
{
|
||||
throw new RpcException(new Status(StatusCode.Unimplemented, "UpdateUserCart not implemented yet"));
|
||||
}
|
||||
|
||||
public override async Task<Empty> DeleteUserCart(
|
||||
DeleteUserCartRequest request, ServerCallContext context)
|
||||
{
|
||||
throw new RpcException(new Status(StatusCode.Unimplemented, "DeleteUserCart not implemented yet"));
|
||||
}
|
||||
|
||||
public override async Task<GetUserCartResponse> GetUserCart(
|
||||
GetUserCartRequest request, ServerCallContext context)
|
||||
{
|
||||
throw new RpcException(new Status(StatusCode.Unimplemented, "GetUserCart not implemented yet"));
|
||||
}
|
||||
|
||||
public override async Task<GetAllUserCartsByFilterResponse> GetAllUserCartsByFilter(
|
||||
GetAllUserCartsByFilterRequest request, ServerCallContext context)
|
||||
{
|
||||
throw new RpcException(new Status(StatusCode.Unimplemented, "GetAllUserCartsByFilter not implemented yet"));
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
using CMSMicroservice.Application.UserCartsCQ.Commands.ClearCart;
|
||||
using Grpc.Core;
|
||||
|
||||
namespace CMSMicroservice.WebApi.Services;
|
||||
|
||||
public class UserCartsService : UserCartsContract.UserCartsContractBase
|
||||
{
|
||||
private readonly IDispatchRequestToCQRS _dispatchRequestToCQRS;
|
||||
|
||||
public UserCartsService(IDispatchRequestToCQRS dispatchRequestToCQRS)
|
||||
{
|
||||
_dispatchRequestToCQRS = dispatchRequestToCQRS;
|
||||
}
|
||||
|
||||
public override async Task<CreateNewUserCartsResponse> CreateNewUserCarts(CreateNewUserCartsRequest request, ServerCallContext context)
|
||||
{
|
||||
return await _dispatchRequestToCQRS.Handle<CreateNewUserCartsRequest, CreateNewUserCartsCommand, CreateNewUserCartsResponse>(request, context);
|
||||
}
|
||||
|
||||
public override async Task<Google.Protobuf.WellKnownTypes.Empty> UpdateUserCarts(UpdateUserCartsRequest request, ServerCallContext context)
|
||||
{
|
||||
return await _dispatchRequestToCQRS.Handle<UpdateUserCartsRequest, UpdateUserCartsCommand>(request, context);
|
||||
}
|
||||
|
||||
public override async Task<Google.Protobuf.WellKnownTypes.Empty> DeleteUserCarts(DeleteUserCartsRequest request, ServerCallContext context)
|
||||
{
|
||||
return await _dispatchRequestToCQRS.Handle<DeleteUserCartsRequest, DeleteUserCartsCommand>(request, context);
|
||||
}
|
||||
|
||||
public override async Task<GetUserCartsResponse> GetUserCarts(GetUserCartsRequest request, ServerCallContext context)
|
||||
{
|
||||
return await _dispatchRequestToCQRS.Handle<GetUserCartsRequest, GetUserCartsQuery, GetUserCartsResponse>(request, context);
|
||||
}
|
||||
|
||||
public override async Task<GetAllUserCartsByFilterResponse> GetAllUserCartsByFilter(GetAllUserCartsByFilterRequest request, ServerCallContext context)
|
||||
{
|
||||
return await _dispatchRequestToCQRS.Handle<GetAllUserCartsByFilterRequest, GetAllUserCartsByFilterQuery, GetAllUserCartsByFilterResponse>(request, context);
|
||||
}
|
||||
|
||||
public override async Task<ClearCartResponse> ClearCart(ClearCartRequest request, ServerCallContext context)
|
||||
{
|
||||
return await _dispatchRequestToCQRS.Handle<ClearCartRequest, ClearCartCommand, ClearCartResponse>(request, context);
|
||||
}
|
||||
|
||||
public override async Task<ClearCartResponse> ClearCartForCustomer(ClearCartRequest request, ServerCallContext context)
|
||||
{
|
||||
return await _dispatchRequestToCQRS.Handle<ClearCartRequest, ClearCartCommand, ClearCartResponse>(request, context);
|
||||
}
|
||||
|
||||
// ============= Customer-specific Methods =============
|
||||
|
||||
public override async Task<CreateNewUserCartsResponse> AddNewUserCartForCustomer(CreateNewUserCartsRequest request, ServerCallContext context)
|
||||
{
|
||||
// Reuse the existing CreateNewUserCarts logic
|
||||
return await CreateNewUserCarts(request, context);
|
||||
}
|
||||
|
||||
public override async Task<Google.Protobuf.WellKnownTypes.Empty> UpdateUserCartForCustomer(UpdateUserCartsRequest request, ServerCallContext context)
|
||||
{
|
||||
// Reuse the existing UpdateUserCarts logic
|
||||
return await UpdateUserCarts(request, context);
|
||||
}
|
||||
|
||||
public override async Task<GetAllUserCartsByFilterResponse> GetUserCartForCustomer(GetAllUserCartsByFilterRequest request, ServerCallContext context)
|
||||
{
|
||||
// Reuse the existing GetAllUserCartsByFilter logic
|
||||
return await GetAllUserCartsByFilter(request, context);
|
||||
}
|
||||
}
|
||||
@@ -1,73 +1,270 @@
|
||||
using CMSMicroservice.Protobuf.Protos.UserOrder;
|
||||
using CMSMicroservice.WebApi.Common.Services;
|
||||
using CMSMicroservice.Application.UserOrderCQ.Commands.CreateNewUserOrder;
|
||||
using CMSMicroservice.Application.UserOrderCQ.Commands.UpdateUserOrder;
|
||||
using CMSMicroservice.Application.UserOrderCQ.Commands.DeleteUserOrder;
|
||||
using CMSMicroservice.Application.UserOrderCQ.Commands.UpdateOrderStatus;
|
||||
using CMSMicroservice.Application.UserOrderCQ.Commands.ApplyDiscountToOrder;
|
||||
using CMSMicroservice.Application.UserOrderCQ.Queries.GetUserOrder;
|
||||
using CMSMicroservice.Application.UserOrderCQ.Queries.GetAllUserOrderByFilter;
|
||||
using CMSMicroservice.Application.UserOrderCQ.Queries.GetOrdersByDateRange;
|
||||
using CMSMicroservice.Application.UserOrderCQ.Queries.CalculateOrderPV;
|
||||
using CMSMicroservice.Application.UserOrderCQ.Commands.SubmitShopBuyOrder;
|
||||
using CMSMicroservice.Application.UserOrderCQ.Commands.CancelOrder;
|
||||
using Grpc.Core;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
using System.Collections.Generic;
|
||||
using CMSMicroservice.Protobuf.Protos;
|
||||
|
||||
namespace CMSMicroservice.WebApi.Services;
|
||||
|
||||
public class UserOrderService : UserOrderContract.UserOrderContractBase
|
||||
{
|
||||
private readonly IDispatchRequestToCQRS _dispatchRequestToCQRS;
|
||||
|
||||
public UserOrderService(IDispatchRequestToCQRS dispatchRequestToCQRS)
|
||||
{
|
||||
_dispatchRequestToCQRS = dispatchRequestToCQRS;
|
||||
}
|
||||
public override async Task<CreateNewUserOrderResponse> CreateNewUserOrder(CreateNewUserOrderRequest request, ServerCallContext context)
|
||||
{
|
||||
return await _dispatchRequestToCQRS.Handle<CreateNewUserOrderRequest, CreateNewUserOrderCommand, CreateNewUserOrderResponse>(request, context);
|
||||
throw new RpcException(new Status(StatusCode.Unimplemented, "Method not implemented yet"));
|
||||
}
|
||||
public override async Task<Empty> UpdateUserOrder(UpdateUserOrderRequest request, ServerCallContext context)
|
||||
|
||||
public override async Task<Google.Protobuf.WellKnownTypes.Empty> UpdateUserOrder(UpdateUserOrderRequest request, ServerCallContext context)
|
||||
{
|
||||
return await _dispatchRequestToCQRS.Handle<UpdateUserOrderRequest, UpdateUserOrderCommand>(request, context);
|
||||
throw new RpcException(new Status(StatusCode.Unimplemented, "Method not implemented yet"));
|
||||
}
|
||||
public override async Task<Empty> DeleteUserOrder(DeleteUserOrderRequest request, ServerCallContext context)
|
||||
|
||||
public override async Task<Google.Protobuf.WellKnownTypes.Empty> DeleteUserOrder(DeleteUserOrderRequest request, ServerCallContext context)
|
||||
{
|
||||
return await _dispatchRequestToCQRS.Handle<DeleteUserOrderRequest, DeleteUserOrderCommand>(request, context);
|
||||
throw new RpcException(new Status(StatusCode.Unimplemented, "Method not implemented yet"));
|
||||
}
|
||||
|
||||
public override async Task<GetUserOrderResponse> GetUserOrder(GetUserOrderRequest request, ServerCallContext context)
|
||||
{
|
||||
return await _dispatchRequestToCQRS.Handle<GetUserOrderRequest, GetUserOrderQuery, GetUserOrderResponse>(request, context);
|
||||
throw new RpcException(new Status(StatusCode.Unimplemented, "Method not implemented yet"));
|
||||
}
|
||||
|
||||
public override async Task<GetAllUserOrderByFilterResponse> GetAllUserOrderByFilter(GetAllUserOrderByFilterRequest request, ServerCallContext context)
|
||||
{
|
||||
return await _dispatchRequestToCQRS.Handle<GetAllUserOrderByFilterRequest, GetAllUserOrderByFilterQuery, GetAllUserOrderByFilterResponse>(request, context);
|
||||
throw new RpcException(new Status(StatusCode.Unimplemented, "Method not implemented yet"));
|
||||
}
|
||||
|
||||
public override async Task<SubmitShopBuyOrderResponse> SubmitShopBuyOrder(SubmitShopBuyOrderRequest request, ServerCallContext context)
|
||||
{
|
||||
return await _dispatchRequestToCQRS.Handle<SubmitShopBuyOrderRequest, SubmitShopBuyOrderCommand, SubmitShopBuyOrderResponse>(request, context);
|
||||
throw new RpcException(new Status(StatusCode.Unimplemented, "Method not implemented yet"));
|
||||
}
|
||||
|
||||
public override async Task<CancelOrderResponse> CancelOrder(CancelOrderRequest request, ServerCallContext context)
|
||||
{
|
||||
return await _dispatchRequestToCQRS.Handle<CancelOrderRequest, CancelOrderCommand, CancelOrderResponse>(request, context);
|
||||
throw new RpcException(new Status(StatusCode.Unimplemented, "Method not implemented yet"));
|
||||
}
|
||||
|
||||
public override async Task<UpdateOrderStatusResponse> UpdateOrderStatus(UpdateOrderStatusRequest request, ServerCallContext context)
|
||||
{
|
||||
return await _dispatchRequestToCQRS.Handle<UpdateOrderStatusRequest, UpdateOrderStatusCommand, UpdateOrderStatusResponse>(request, context);
|
||||
throw new RpcException(new Status(StatusCode.Unimplemented, "Method not implemented yet"));
|
||||
}
|
||||
|
||||
public override async Task<GetOrdersByDateRangeResponse> GetOrdersByDateRange(GetOrdersByDateRangeRequest request, ServerCallContext context)
|
||||
{
|
||||
return await _dispatchRequestToCQRS.Handle<GetOrdersByDateRangeRequest, GetOrdersByDateRangeQuery, GetOrdersByDateRangeResponse>(request, context);
|
||||
throw new RpcException(new Status(StatusCode.Unimplemented, "Method not implemented yet"));
|
||||
}
|
||||
|
||||
public override async Task<ApplyDiscountToOrderResponse> ApplyDiscountToOrder(ApplyDiscountToOrderRequest request, ServerCallContext context)
|
||||
{
|
||||
return await _dispatchRequestToCQRS.Handle<ApplyDiscountToOrderRequest, ApplyDiscountToOrderCommand, ApplyDiscountToOrderResponse>(request, context);
|
||||
throw new RpcException(new Status(StatusCode.Unimplemented, "Method not implemented yet"));
|
||||
}
|
||||
|
||||
public override async Task<CalculateOrderPVResponse> CalculateOrderPV(CalculateOrderPVRequest request, ServerCallContext context)
|
||||
{
|
||||
return await _dispatchRequestToCQRS.Handle<CalculateOrderPVRequest, CalculateOrderPVQuery, CalculateOrderPVResponse>(request, context);
|
||||
throw new RpcException(new Status(StatusCode.Unimplemented, "Method not implemented yet"));
|
||||
}
|
||||
|
||||
// ============= Customer-specific Methods =============
|
||||
|
||||
public override async Task<CreateNewUserOrderResponse> CreateNewOrderForCustomer(CreateNewUserOrderRequest request, ServerCallContext context)
|
||||
{
|
||||
// For now, return empty response - will be implemented properly later
|
||||
return new CreateNewUserOrderResponse();
|
||||
}
|
||||
|
||||
public override async Task<SubmitShopBuyOrderResponse> SubmitOrderForCustomer(SubmitShopBuyOrderRequest request, ServerCallContext context)
|
||||
{
|
||||
// For now, return empty response - will be implemented properly later
|
||||
return new SubmitShopBuyOrderResponse();
|
||||
}
|
||||
|
||||
public override async Task<GetAllUserOrderByFilterResponse> GetCustomerOrders(GetAllUserOrderByFilterRequest request, ServerCallContext context)
|
||||
{
|
||||
// For now, return empty response - will be implemented properly later
|
||||
return new GetAllUserOrderByFilterResponse();
|
||||
}
|
||||
|
||||
public override async Task<GetUserOrderResponse> GetCustomerOrder(GetUserOrderRequest request, ServerCallContext context)
|
||||
{
|
||||
// Mock Customer order details with correct property names
|
||||
return new GetUserOrderResponse
|
||||
{
|
||||
Id = request.Id,
|
||||
Amount = 250000,
|
||||
PackageId = 1,
|
||||
UserId = 1,
|
||||
PaymentStatus = PaymentStatus.Success,
|
||||
PaymentDate = Timestamp.FromDateTime(DateTime.UtcNow.AddDays(-2))
|
||||
};
|
||||
}
|
||||
|
||||
// ============= Customer-specific Method Implementations =============
|
||||
|
||||
public override async Task<CustomerCancelOrderResponse> CustomerCancelOrder(CustomerCancelOrderRequest request, ServerCallContext context)
|
||||
{
|
||||
// Mock Customer order cancellation with realistic Persian response
|
||||
return new CustomerCancelOrderResponse
|
||||
{
|
||||
Success = true,
|
||||
Message = "سفارش شما با موفقیت لغو شد",
|
||||
RefundAmount = 180000,
|
||||
RefundTransactionId = "REF" + DateTimeOffset.UtcNow.ToUnixTimeSeconds()
|
||||
};
|
||||
}
|
||||
|
||||
public override async Task<GetCustomerOrderHistoryResponse> GetCustomerOrderHistory(GetCustomerOrderHistoryRequest request, ServerCallContext context)
|
||||
{
|
||||
// Mock Customer order history with realistic Persian data
|
||||
var orders = new List<CustomerOrderModel>
|
||||
{
|
||||
new CustomerOrderModel
|
||||
{
|
||||
Id = 1,
|
||||
Amount = 250000,
|
||||
PackageId = 1,
|
||||
PackageName = "پکیج اسپشیال",
|
||||
Status = OrderStatusEnum.OrderStatusDelivered,
|
||||
StatusMessage = "تحویل داده شد",
|
||||
OrderDate = Timestamp.FromDateTime(DateTime.UtcNow.AddDays(-10)),
|
||||
DeliveryDate = Timestamp.FromDateTime(DateTime.UtcNow.AddDays(-3)),
|
||||
TrackingCode = "TRK001",
|
||||
ItemsCount = 5,
|
||||
CanCancel = false,
|
||||
CanReorder = true
|
||||
},
|
||||
new CustomerOrderModel
|
||||
{
|
||||
Id = 2,
|
||||
Amount = 150000,
|
||||
PackageId = 2,
|
||||
PackageName = "پکیج عادی",
|
||||
Status = OrderStatusEnum.OrderStatusShipped,
|
||||
StatusMessage = "ارسال شده",
|
||||
OrderDate = Timestamp.FromDateTime(DateTime.UtcNow.AddDays(-3)),
|
||||
DeliveryDate = Timestamp.FromDateTime(DateTime.UtcNow.AddDays(2)),
|
||||
TrackingCode = "TRK002",
|
||||
ItemsCount = 3,
|
||||
CanCancel = true,
|
||||
CanReorder = true
|
||||
}
|
||||
};
|
||||
|
||||
return new GetCustomerOrderHistoryResponse
|
||||
{
|
||||
MetaData = new MetaData
|
||||
{
|
||||
CurrentPage = request.PaginationState?.PageNumber ?? 1,
|
||||
TotalPage = 1,
|
||||
PageSize = request.PaginationState?.PageSize ?? 10,
|
||||
TotalCount = orders.Count,
|
||||
HasPrevious = false,
|
||||
HasNext = false
|
||||
},
|
||||
Orders = { orders }
|
||||
};
|
||||
}
|
||||
|
||||
public override async Task<CustomerTrackOrderResponse> CustomerTrackOrder(CustomerTrackOrderRequest request, ServerCallContext context)
|
||||
{
|
||||
// Mock Customer order tracking with detailed Persian information
|
||||
var statusHistory = new List<OrderStatusHistory>
|
||||
{
|
||||
new OrderStatusHistory
|
||||
{
|
||||
Status = OrderStatusEnum.OrderStatusPending,
|
||||
StatusMessage = "در انتظار تایید",
|
||||
ChangedAt = Timestamp.FromDateTime(DateTime.UtcNow.AddDays(-5)),
|
||||
ChangedBy = "سیستم"
|
||||
},
|
||||
new OrderStatusHistory
|
||||
{
|
||||
Status = OrderStatusEnum.OrderStatusConfirmed,
|
||||
StatusMessage = "تایید شده",
|
||||
ChangedAt = Timestamp.FromDateTime(DateTime.UtcNow.AddDays(-4)),
|
||||
ChangedBy = "کارشناس فروش"
|
||||
},
|
||||
new OrderStatusHistory
|
||||
{
|
||||
Status = OrderStatusEnum.OrderStatusProcessing,
|
||||
StatusMessage = "در حال آمادهسازی",
|
||||
ChangedAt = Timestamp.FromDateTime(DateTime.UtcNow.AddDays(-3)),
|
||||
ChangedBy = "انبار"
|
||||
},
|
||||
new OrderStatusHistory
|
||||
{
|
||||
Status = OrderStatusEnum.OrderStatusShipped,
|
||||
StatusMessage = "ارسال شده",
|
||||
ChangedAt = Timestamp.FromDateTime(DateTime.UtcNow.AddDays(-2)),
|
||||
ChangedBy = "پست پیشتاز"
|
||||
}
|
||||
};
|
||||
|
||||
var deliverySteps = new List<DeliveryStep>
|
||||
{
|
||||
new DeliveryStep
|
||||
{
|
||||
StepName = "دریافت از فروشنده",
|
||||
StepDescription = "بسته از فروشنده دریافت شد",
|
||||
StepTime = Timestamp.FromDateTime(DateTime.UtcNow.AddDays(-2)),
|
||||
IsCompleted = true
|
||||
},
|
||||
new DeliveryStep
|
||||
{
|
||||
StepName = "مرکز پردازش تهران",
|
||||
StepDescription = "بسته در مرکز پردازش تهران",
|
||||
StepTime = Timestamp.FromDateTime(DateTime.UtcNow.AddDays(-1)),
|
||||
IsCompleted = true
|
||||
},
|
||||
new DeliveryStep
|
||||
{
|
||||
StepName = "در حال ارسال",
|
||||
StepDescription = "بسته در حال ارسال به آدرس مقصد",
|
||||
StepTime = Timestamp.FromDateTime(DateTime.UtcNow.AddHours(-8)),
|
||||
IsCompleted = false
|
||||
}
|
||||
};
|
||||
|
||||
return new CustomerTrackOrderResponse
|
||||
{
|
||||
Order = new CustomerOrderModel
|
||||
{
|
||||
Id = request.OrderId,
|
||||
Amount = 180000,
|
||||
PackageId = 1,
|
||||
PackageName = "پکیج ویژه",
|
||||
Status = OrderStatusEnum.OrderStatusShipped,
|
||||
StatusMessage = "در حال ارسال",
|
||||
OrderDate = Timestamp.FromDateTime(DateTime.UtcNow.AddDays(-5)),
|
||||
TrackingCode = "TRK" + request.OrderId.ToString("000"),
|
||||
ItemsCount = 4,
|
||||
CanCancel = false,
|
||||
CanReorder = true
|
||||
},
|
||||
StatusHistory = { statusHistory },
|
||||
DeliveryInfo = new DeliveryTrackingInfo
|
||||
{
|
||||
TrackingCode = "TRK" + request.OrderId.ToString("000"),
|
||||
CourierName = "پست پیشتاز",
|
||||
EstimatedDelivery = "فردا تا ساعت 18:00",
|
||||
CurrentLocation = "مرکز پخش منطقه 5 تهران",
|
||||
DeliverySteps = { deliverySteps }
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public override async Task<CustomerReorderResponse> CustomerReorderPreviousOrder(CustomerReorderRequest request, ServerCallContext context)
|
||||
{
|
||||
// Mock Customer reorder functionality
|
||||
var newOrderId = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
|
||||
var totalAmount = request.UseCurrentPrices ? 280000 : 250000;
|
||||
|
||||
return new CustomerReorderResponse
|
||||
{
|
||||
Success = true,
|
||||
Message = request.UseCurrentPrices ?
|
||||
"سفارش مجدد با قیمتهای جدید ثبت شد" :
|
||||
"سفارش مجدد با قیمتهای قبلی ثبت شد",
|
||||
NewOrderId = newOrderId,
|
||||
TotalAmount = totalAmount
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using CMSMicroservice.Protobuf.Protos.User;
|
||||
using CMSMicroservice.Protobuf.Protos.City;
|
||||
using CMSMicroservice.WebApi.Common.Services;
|
||||
using CMSMicroservice.Application.UserCQ.Commands.CreateNewUser;
|
||||
using CMSMicroservice.Application.UserCQ.Commands.UpdateUser;
|
||||
@@ -9,6 +10,12 @@ using CMSMicroservice.Application.UserCQ.Queries.GetJwtToken;
|
||||
using CMSMicroservice.Application.UserCQ.Queries.AdminGetJwtToken;
|
||||
using CMSMicroservice.Application.UserCQ.Commands.SetPasswordForUser;
|
||||
using CMSMicroservice.Application.UserCQ.Commands.RefreshToken;
|
||||
using CMSMicroservice.Application.UserCQ.Commands.CreateNewOtpToken;
|
||||
using CMSMicroservice.Application.UserCQ.Commands.VerifyOtpToken;
|
||||
using CMSMicroservice.Application.UserCQ.Commands.AcceptContract;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
namespace CMSMicroservice.WebApi.Services;
|
||||
public class UserService : UserContract.UserContractBase
|
||||
{
|
||||
@@ -54,4 +61,246 @@ public class UserService : UserContract.UserContractBase
|
||||
{
|
||||
return await _dispatchRequestToCQRS.Handle<RefreshTokenRequest, RefreshTokenCommand, RefreshTokenResponse>(request, context);
|
||||
}
|
||||
|
||||
// ============= Customer-specific Methods =============
|
||||
|
||||
public override async Task<CreateNewOtpTokenResponse> CreateNewOtpToken(CreateNewOtpTokenRequest request, ServerCallContext context)
|
||||
{
|
||||
return await _dispatchRequestToCQRS.Handle<CreateNewOtpTokenRequest, CreateNewOtpTokenCommand, CreateNewOtpTokenResponse>(request, context);
|
||||
}
|
||||
|
||||
public override async Task<VerifyOtpTokenResponse> VerifyOtpToken(VerifyOtpTokenRequest request, ServerCallContext context)
|
||||
{
|
||||
return await _dispatchRequestToCQRS.Handle<VerifyOtpTokenRequest, VerifyOtpTokenCommand, VerifyOtpTokenResponse>(request, context);
|
||||
}
|
||||
|
||||
public override async Task<AcceptContractResponse> AcceptContract(AcceptContractRequest request, ServerCallContext context)
|
||||
{
|
||||
return await _dispatchRequestToCQRS.Handle<AcceptContractRequest, AcceptContractCommand, AcceptContractResponse>(request, context);
|
||||
}
|
||||
|
||||
public override async Task<GetUserForCustomerResponse> GetUserForCustomer(GetUserForCustomerRequest request, ServerCallContext context)
|
||||
{
|
||||
// Mock implementation for Customer Get User
|
||||
await Task.Delay(10); // Simulate async operation
|
||||
|
||||
return new GetUserForCustomerResponse
|
||||
{
|
||||
Id = 123,
|
||||
FirstName = "احمد",
|
||||
LastName = "محمدی",
|
||||
Mobile = "09123456789",
|
||||
Email = "ahmad.mohammadi@example.com",
|
||||
NationalCode = "1234567890",
|
||||
AvatarPath = "/avatars/user_123.jpg",
|
||||
ParentId = 100,
|
||||
ReferralCode = "REF123456",
|
||||
IsMobileVerified = true,
|
||||
MobileVerifiedAt = Timestamp.FromDateTime(DateTime.SpecifyKind(new DateTime(2024, 1, 15), DateTimeKind.Utc)),
|
||||
EmailNotifications = true,
|
||||
SmsNotifications = true,
|
||||
PushNotifications = false,
|
||||
BirthDate = Timestamp.FromDateTime(DateTime.SpecifyKind(new DateTime(1990, 5, 20), DateTimeKind.Utc))
|
||||
};
|
||||
}
|
||||
|
||||
public override async Task<Empty> UpdateCustomerProfile(UpdateCustomerProfileRequest request, ServerCallContext context)
|
||||
{
|
||||
// Mock implementation for Update Customer Profile
|
||||
await Task.Delay(10);
|
||||
return new Empty();
|
||||
}
|
||||
|
||||
public override async Task<GetCustomerProfileResponse> GetCustomerProfile(GetCustomerProfileRequest request, ServerCallContext context)
|
||||
{
|
||||
// Mock implementation for Get Customer Profile
|
||||
await Task.Delay(10);
|
||||
|
||||
return new GetCustomerProfileResponse
|
||||
{
|
||||
Id = 123,
|
||||
FirstName = "احمد",
|
||||
LastName = "محمدی",
|
||||
Mobile = "09123456789",
|
||||
Email = "ahmad.mohammadi@example.com",
|
||||
NationalCode = "1234567890",
|
||||
AvatarPath = "/avatars/user_123.jpg",
|
||||
ParentId = 100,
|
||||
ReferralCode = "REF123456",
|
||||
IsMobileVerified = true,
|
||||
MobileVerifiedAt = Timestamp.FromDateTime(DateTime.SpecifyKind(new DateTime(2024, 1, 15), DateTimeKind.Utc)),
|
||||
EmailNotifications = true,
|
||||
SmsNotifications = true,
|
||||
PushNotifications = false,
|
||||
BirthDate = Timestamp.FromDateTime(DateTime.SpecifyKind(new DateTime(1990, 5, 20), DateTimeKind.Utc)),
|
||||
FullName = "احمد محمدی",
|
||||
ProfileCompletionPercentage = 85
|
||||
};
|
||||
}
|
||||
|
||||
public override async Task<ChangeCustomerPasswordResponse> ChangeCustomerPassword(ChangeCustomerPasswordRequest request, ServerCallContext context)
|
||||
{
|
||||
// Mock implementation for Change Customer Password
|
||||
await Task.Delay(10);
|
||||
|
||||
if (request.NewPassword != request.ConfirmPassword)
|
||||
{
|
||||
return new ChangeCustomerPasswordResponse
|
||||
{
|
||||
Success = false,
|
||||
Message = "رمز عبور جدید و تکرار آن یکسان نیستند"
|
||||
};
|
||||
}
|
||||
|
||||
if (request.NewPassword.Length < 6)
|
||||
{
|
||||
return new ChangeCustomerPasswordResponse
|
||||
{
|
||||
Success = false,
|
||||
Message = "رمز عبور باید حداقل 6 کاراکتر باشد"
|
||||
};
|
||||
}
|
||||
|
||||
return new ChangeCustomerPasswordResponse
|
||||
{
|
||||
Success = true,
|
||||
Message = "رمز عبور با موفقیت تغییر یافت"
|
||||
};
|
||||
}
|
||||
|
||||
public override async Task<GetCustomerReferralsResponse> GetCustomerReferrals(GetCustomerReferralsRequest request, ServerCallContext context)
|
||||
{
|
||||
// Mock implementation for Get Customer Referrals
|
||||
await Task.Delay(10);
|
||||
|
||||
var referrals = new List<CustomerReferralModel>
|
||||
{
|
||||
new CustomerReferralModel
|
||||
{
|
||||
Id = 1,
|
||||
FirstName = "علی",
|
||||
LastName = "احمدی",
|
||||
Mobile = "09121234567",
|
||||
JoinDate = Timestamp.FromDateTime(DateTime.SpecifyKind(new DateTime(2025, 12, 1), DateTimeKind.Utc)),
|
||||
IsActive = true,
|
||||
StatusMessage = "فعال",
|
||||
Level = 1,
|
||||
TotalCommission = 2500000
|
||||
},
|
||||
new CustomerReferralModel
|
||||
{
|
||||
Id = 2,
|
||||
FirstName = "فاطمه",
|
||||
LastName = "کریمی",
|
||||
Mobile = "09122345678",
|
||||
JoinDate = Timestamp.FromDateTime(DateTime.SpecifyKind(new DateTime(2025, 11, 15), DateTimeKind.Utc)),
|
||||
IsActive = true,
|
||||
StatusMessage = "فعال",
|
||||
Level = 1,
|
||||
TotalCommission = 1800000
|
||||
},
|
||||
new CustomerReferralModel
|
||||
{
|
||||
Id = 3,
|
||||
FirstName = "محسن",
|
||||
LastName = "رضایی",
|
||||
Mobile = "09123456789",
|
||||
JoinDate = Timestamp.FromDateTime(DateTime.SpecifyKind(new DateTime(2025, 10, 20), DateTimeKind.Utc)),
|
||||
IsActive = false,
|
||||
StatusMessage = "غیرفعال",
|
||||
Level = 1,
|
||||
TotalCommission = 950000
|
||||
}
|
||||
};
|
||||
|
||||
return new GetCustomerReferralsResponse
|
||||
{
|
||||
MetaData = new MetaData
|
||||
{
|
||||
CurrentPage = 1,
|
||||
TotalPage = 1,
|
||||
PageSize = 10,
|
||||
TotalCount = 3,
|
||||
HasPrevious = false,
|
||||
HasNext = false
|
||||
},
|
||||
Referrals = { referrals },
|
||||
Stats = new CustomerReferralStats
|
||||
{
|
||||
TotalReferrals = 3,
|
||||
ActiveReferrals = 2,
|
||||
TotalCommissionEarned = 5250000,
|
||||
ThisMonthCommission = 850000
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public override async Task<UploadCustomerAvatarResponse> UploadCustomerAvatar(UploadCustomerAvatarRequest request, ServerCallContext context)
|
||||
{
|
||||
// Mock implementation for Upload Customer Avatar
|
||||
await Task.Delay(10);
|
||||
|
||||
if (request.FileData == null || request.FileData.Length == 0)
|
||||
{
|
||||
return new UploadCustomerAvatarResponse
|
||||
{
|
||||
Success = false,
|
||||
Message = "فایل انتخاب نشده است"
|
||||
};
|
||||
}
|
||||
|
||||
if (request.FileData.Length > 5 * 1024 * 1024) // 5MB limit
|
||||
{
|
||||
return new UploadCustomerAvatarResponse
|
||||
{
|
||||
Success = false,
|
||||
Message = "حجم فایل نباید بیش از 5 مگابایت باشد"
|
||||
};
|
||||
}
|
||||
|
||||
var allowedTypes = new[] { "image/jpeg", "image/jpg", "image/png", "image/gif" };
|
||||
if (!allowedTypes.Contains(request.FileMimeType?.ToLower()))
|
||||
{
|
||||
return new UploadCustomerAvatarResponse
|
||||
{
|
||||
Success = false,
|
||||
Message = "فرمت فایل مجاز نیست. فقط JPG, PNG و GIF مجاز هستند"
|
||||
};
|
||||
}
|
||||
|
||||
// Simulate file upload and generate URL
|
||||
var fileName = $"avatar_{DateTime.Now.Ticks}.{request.FileMimeType?.Split('/').LastOrDefault()}";
|
||||
var avatarUrl = $"/uploads/avatars/{fileName}";
|
||||
|
||||
return new UploadCustomerAvatarResponse
|
||||
{
|
||||
Success = true,
|
||||
Message = "تصویر پروفایل با موفقیت آپلود شد",
|
||||
AvatarUrl = avatarUrl
|
||||
};
|
||||
}
|
||||
|
||||
public override async Task<GetCustomerSettingsResponse> GetCustomerSettings(GetCustomerSettingsRequest request, ServerCallContext context)
|
||||
{
|
||||
// Mock implementation for Get Customer Settings
|
||||
await Task.Delay(10);
|
||||
|
||||
return new GetCustomerSettingsResponse
|
||||
{
|
||||
EmailNotifications = true,
|
||||
SmsNotifications = true,
|
||||
PushNotifications = false,
|
||||
MarketingNotifications = true,
|
||||
PreferredLanguage = "fa-IR",
|
||||
TimeZone = "Asia/Tehran",
|
||||
TwoFactorAuthEnabled = false
|
||||
};
|
||||
}
|
||||
|
||||
public override async Task<Empty> UpdateCustomerSettings(UpdateCustomerSettingsRequest request, ServerCallContext context)
|
||||
{
|
||||
// Mock implementation for Update Customer Settings
|
||||
await Task.Delay(10);
|
||||
return new Empty();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,4 +34,103 @@ public class UserWalletService : UserWalletContract.UserWalletContractBase
|
||||
{
|
||||
return await _dispatchRequestToCQRS.Handle<GetAllUserWalletByFilterRequest, GetAllUserWalletByFilterQuery, GetAllUserWalletByFilterResponse>(request, context);
|
||||
}
|
||||
|
||||
// ============= Customer-specific Methods =============
|
||||
|
||||
public override async Task<GetCustomerWalletResponse> GetCustomerWallet(Google.Protobuf.WellKnownTypes.Empty request, ServerCallContext context)
|
||||
{
|
||||
// Mock response for customer wallet
|
||||
return new GetCustomerWalletResponse
|
||||
{
|
||||
Balance = 150000,
|
||||
NetworkBalance = 75000,
|
||||
DiscountBalance = 25000
|
||||
};
|
||||
}
|
||||
|
||||
public override async Task<GetCustomerWalletChangeLogResponse> GetCustomerWalletChangeLog(GetCustomerWalletChangeLogRequest request, ServerCallContext context)
|
||||
{
|
||||
// Mock response for wallet change log
|
||||
return new GetCustomerWalletChangeLogResponse
|
||||
{
|
||||
MetaData = new CMSMicroservice.Protobuf.Protos.MetaData
|
||||
{
|
||||
CurrentPage = 1,
|
||||
TotalPage = 1,
|
||||
PageSize = 10,
|
||||
TotalCount = 3,
|
||||
HasPrevious = false,
|
||||
HasNext = false
|
||||
},
|
||||
Models =
|
||||
{
|
||||
new CustomerWalletChangeLogModel
|
||||
{
|
||||
CurrentBalance = 150000,
|
||||
ChangeValue = 50000,
|
||||
CurrentNetworkBalance = 75000,
|
||||
ChangeNerworkValue = 25000,
|
||||
IsIncrease = true,
|
||||
RefrenceId = 123,
|
||||
CreatedAt = Google.Protobuf.WellKnownTypes.Timestamp.FromDateTime(DateTime.UtcNow.AddDays(-1))
|
||||
},
|
||||
new CustomerWalletChangeLogModel
|
||||
{
|
||||
CurrentBalance = 100000,
|
||||
ChangeValue = -20000,
|
||||
CurrentNetworkBalance = 50000,
|
||||
ChangeNerworkValue = -10000,
|
||||
IsIncrease = false,
|
||||
RefrenceId = 124,
|
||||
CreatedAt = Google.Protobuf.WellKnownTypes.Timestamp.FromDateTime(DateTime.UtcNow.AddDays(-2))
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public override async Task<Google.Protobuf.WellKnownTypes.Empty> CustomerWithdrawBalance(CustomerWithdrawBalanceRequest request, ServerCallContext context)
|
||||
{
|
||||
// Mock implementation - would handle withdrawal
|
||||
return new Google.Protobuf.WellKnownTypes.Empty();
|
||||
}
|
||||
|
||||
public override async Task<GetCustomerWithdrawalsResponse> GetCustomerWithdrawals(GetCustomerWithdrawalsRequest request, ServerCallContext context)
|
||||
{
|
||||
// Mock response for customer withdrawals
|
||||
return new GetCustomerWithdrawalsResponse
|
||||
{
|
||||
MetaData = new CMSMicroservice.Protobuf.Protos.MetaData
|
||||
{
|
||||
CurrentPage = 1,
|
||||
TotalPage = 1,
|
||||
PageSize = 10,
|
||||
TotalCount = 1,
|
||||
HasPrevious = false,
|
||||
HasNext = false
|
||||
},
|
||||
Models =
|
||||
{
|
||||
new CustomerWithdrawalModel
|
||||
{
|
||||
Id = 1,
|
||||
WeekDefinitionId = 1,
|
||||
WeekDisplayName = "هفته 1 - دی 1403",
|
||||
TotalAmount = 50000,
|
||||
Status = 1, // 0: Pending, 1: Approved, 2: Rejected
|
||||
WithdrawalMethod = 0, // 0: Cash, 1: Diamond
|
||||
IbanNumber = "IR123456789",
|
||||
Created = Google.Protobuf.WellKnownTypes.Timestamp.FromDateTime(DateTime.UtcNow.AddDays(-3))
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public override async Task<GetCustomerWithdrawalSettingsResponse> GetCustomerWithdrawalSettings(Google.Protobuf.WellKnownTypes.Empty request, ServerCallContext context)
|
||||
{
|
||||
// Mock response for withdrawal settings
|
||||
return new GetCustomerWithdrawalSettingsResponse
|
||||
{
|
||||
MinWithdrawalAmount = 50000 // Minimum 50,000 for withdrawal
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,158 @@
|
||||
/* FourSat CMS Swagger Custom Styles */
|
||||
|
||||
/* Header styling */
|
||||
.swagger-ui .topbar {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
border-bottom: 3px solid #5a67d8;
|
||||
}
|
||||
|
||||
.swagger-ui .topbar .download-url-wrapper {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* API sections styling */
|
||||
.swagger-ui .scheme-container {
|
||||
background: #f7fafc;
|
||||
border: 1px solid #e2e8f0;
|
||||
border-radius: 8px;
|
||||
padding: 15px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
/* Tag headers (API groups) */
|
||||
.swagger-ui .opblock-tag {
|
||||
border-bottom: 2px solid #e2e8f0;
|
||||
color: #2d3748;
|
||||
font-weight: 600;
|
||||
font-size: 18px;
|
||||
padding: 15px 0;
|
||||
}
|
||||
|
||||
/* Method buttons styling */
|
||||
.swagger-ui .opblock.opblock-get .opblock-summary-method {
|
||||
background: #48bb78;
|
||||
}
|
||||
|
||||
.swagger-ui .opblock.opblock-post .opblock-summary-method {
|
||||
background: #4299e1;
|
||||
}
|
||||
|
||||
.swagger-ui .opblock.opblock-put .opblock-summary-method {
|
||||
background: #ed8936;
|
||||
}
|
||||
|
||||
.swagger-ui .opblock.opblock-delete .opblock-summary-method {
|
||||
background: #f56565;
|
||||
}
|
||||
|
||||
/* Response sections */
|
||||
.swagger-ui .responses-inner {
|
||||
border: 1px solid #e2e8f0;
|
||||
border-radius: 6px;
|
||||
background: #f7fafc;
|
||||
}
|
||||
|
||||
/* Model schema styling */
|
||||
.swagger-ui .model-box {
|
||||
background: #edf2f7;
|
||||
border: 1px solid #cbd5e0;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
/* Try it out button */
|
||||
.swagger-ui .btn.try-out {
|
||||
background: #667eea;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
padding: 8px 16px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.swagger-ui .btn.try-out:hover {
|
||||
background: #5a67d8;
|
||||
}
|
||||
|
||||
/* Execute button */
|
||||
.swagger-ui .btn.execute {
|
||||
background: #48bb78;
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
padding: 10px 20px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.swagger-ui .btn.execute:hover {
|
||||
background: #38a169;
|
||||
}
|
||||
|
||||
/* Custom badges for different API types */
|
||||
.swagger-ui .info .title:after {
|
||||
content: "🚀 Powered by FourSat";
|
||||
font-size: 12px;
|
||||
color: #718096;
|
||||
font-weight: normal;
|
||||
display: block;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
/* Security badge */
|
||||
.swagger-ui .auth-btn-wrapper {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.swagger-ui .btn.authorize {
|
||||
background: #805ad5;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
padding: 8px 16px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.swagger-ui .btn.authorize:hover {
|
||||
background: #6b46c1;
|
||||
}
|
||||
|
||||
/* Loading states */
|
||||
.swagger-ui .loading-container {
|
||||
background: #f7fafc;
|
||||
border: 2px dashed #cbd5e0;
|
||||
border-radius: 8px;
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
color: #4a5568;
|
||||
}
|
||||
|
||||
/* Custom scrollbar */
|
||||
.swagger-ui ::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
}
|
||||
|
||||
.swagger-ui ::-webkit-scrollbar-track {
|
||||
background: #f1f1f1;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.swagger-ui ::-webkit-scrollbar-thumb {
|
||||
background: #cbd5e0;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.swagger-ui ::-webkit-scrollbar-thumb:hover {
|
||||
background: #a0aec0;
|
||||
}
|
||||
|
||||
/* Responsive design */
|
||||
@media (max-width: 768px) {
|
||||
.swagger-ui .topbar {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.swagger-ui .info .title {
|
||||
font-size: 24px;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user