Update order system with new gRPC services and wallet integration

This commit is contained in:
masoodafar-web
2025-11-28 05:12:55 +03:30
parent 973beb9e2f
commit d8e1fe77b3
20 changed files with 502 additions and 209 deletions

View File

@@ -1,11 +1,16 @@
using DateTimeConverterCL;
using FrontOffice.BFF.ShopingCart.Protobuf.Protos.ShopingCart;
using Google.Protobuf.WellKnownTypes;
namespace FrontOffice.Main.Utilities;
public record CartItem(long ProductId, string Title, string ImageUrl, long UnitPrice, int Quantity)
public record CartItem(long cartId,long ProductId, string Title, string ImageUrl, long UnitPrice, int Quantity)
{
public long LineTotal => UnitPrice * Quantity;
public long DiscountValue => (Discount*(UnitPrice * Quantity))/100;
public int Discount { get; init; }
public string Created { get; init; } = string.Empty;
public string Description { get; init; } = string.Empty;
}
public class CartService
@@ -22,30 +27,52 @@ public class CartService
public IReadOnlyList<CartItem> Items => _items.AsReadOnly();
public long Total => _items.Sum(i => i.LineTotal);
public long TotalDiscount => _items.Sum(i => i.DiscountValue);
public int Count => _items.Sum(i => i.Quantity);
public async Task Add(Product product, int quantity = 1)
{
if (quantity <= 0) return;
var existing = _items.FirstOrDefault(i => i.ProductId == product.Id);
int newQuantity;
if (existing is null)
{
_items.Add(new CartItem(product.Id, product.Title, product.ImageUrl, product.Price, quantity));
newQuantity = quantity;
_items.Add(new CartItem(0,product.Id, product.Title, product.ImageUrl, product.Price, newQuantity)
{
Discount = product.Discount,
Created = DateTime.Now.MiladiToJalali(),
Description = product.Description
});
}
else
{
var idx = _items.IndexOf(existing);
_items[idx] = existing with { Quantity = existing.Quantity + quantity };
newQuantity = existing.Quantity + quantity;
_items[idx] = existing with { Quantity = newQuantity };
}
Notify();
try
{
await _client.AddNewUserCartAsync(new AddNewUserCartRequest
if (existing is null)
{
ProductId = product.Id,
Count = quantity
});
await _client.AddNewUserCartAsync(new AddNewUserCartRequest
{
ProductId = product.Id,
Count = newQuantity
});
await LoadFromServerAsync();
}
else
{
await _client.UpdateUserCartAsync(new UpdateUserCartRequest
{
UserCartId = existing.cartId,
Count = newQuantity
});
}
}
catch
{
@@ -59,7 +86,7 @@ public class CartService
if (existing is null) return;
if (quantity <= 0)
{
Remove(productId);
Remove(existing.cartId);
return;
}
var idx = _items.IndexOf(existing);
@@ -70,7 +97,7 @@ public class CartService
{
await _client.UpdateUserCartAsync(new UpdateUserCartRequest
{
UserCartId = productId,
UserCartId = existing.cartId,
Count = quantity
});
}
@@ -80,9 +107,9 @@ public class CartService
}
}
public async Task Remove(long productId)
public async Task Remove(long cartId)
{
_items.RemoveAll(i => i.ProductId == productId);
_items.RemoveAll(i => i.cartId == cartId);
Notify();
try
@@ -90,7 +117,7 @@ public class CartService
// Interpret Count=0 as remove from cart
await _client.UpdateUserCartAsync(new UpdateUserCartRequest
{
UserCartId = productId,
UserCartId = cartId,
Count = 0
});
}
@@ -131,14 +158,20 @@ public class CartService
{
var response = await _client.GetAllUserCartAsync(new Empty());
_items.Clear();
foreach (var m in response.Models)
foreach (var model in response.Models)
{
var item = new CartItem(
ProductId: m.Id,
Title: m.Title ?? string.Empty,
ImageUrl: string.IsNullOrWhiteSpace(m.ImagePath) ? string.Empty : UrlUtility.DownloadUrl + m.ImagePath,
UnitPrice: m.Price,
Quantity: m.SaleCount > 0 ? m.SaleCount : 1);
cartId:model.Id,
ProductId: model.ProductId,
Title: model.ProductTitle ?? string.Empty,
ImageUrl: string.IsNullOrWhiteSpace(model.ProductThumbnailPath) ? string.Empty : UrlUtility.DownloadUrl + model.ProductThumbnailPath,
UnitPrice: model.ProductPrice,
Quantity: model.Count > 0 ? model.Count : 1)
{
Discount = model.ProductDiscount,
Created = model.Created.ToDateTime().MiladiToJalali(),
Description = model.ProductShortInfomation
};
_items.Add(item);
}
Notify();

View File

@@ -1,47 +1,64 @@
using FrontOffice.BFF.UserOrder.Protobuf.Protos.UserOrder;
namespace FrontOffice.Main.Utilities;
public enum PaymentMethod
{
Wallet = 1,
}
// public enum PaymentMethod
// {
// Wallet = 1,
// }
//
// public enum OrderStatus
// {
// Pending = 0,
// Paid = 1,
// }
public enum OrderStatus
{
Pending = 0,
Paid = 1,
}
public record OrderItem(long ProductId, string Title, string ImageUrl, long UnitPrice, int Quantity)
{
public long LineTotal => UnitPrice * Quantity;
}
public class Order
{
public long Id { get; set; }
public DateTime CreatedAt { get; set; } = DateTime.Now;
public OrderStatus Status { get; set; } = OrderStatus.Pending;
public PaymentMethod PaymentMethod { get; set; } = PaymentMethod.Wallet;
public long AddressId { get; set; }
public string AddressSummary { get; set; } = string.Empty;
public List<OrderItem> Items { get; set; } = new();
public long Total => Items.Sum(i => i.LineTotal);
}
// public record OrderItem(long ProductId, string Title, string ImageUrl, long UnitPrice, int Quantity)
// {
// public long LineTotal => UnitPrice * Quantity;
// }
//
// public class Order
// {
// public long Id { get; set; }
// public DateTime CreatedAt { get; set; } = DateTime.Now;
// public OrderStatus Status { get; set; } = OrderStatus.Pending;
// public PaymentMethod PaymentMethod { get; set; } = PaymentMethod.Wallet;
// public long AddressId { get; set; }
// public string AddressSummary { get; set; } = string.Empty;
// public List<OrderItem> Items { get; set; } = new();
// public long Total => Items.Sum(i => i.LineTotal);
// }
public class OrderService
{
private long _seq = 1000;
private readonly List<Order> _orders = new();
private readonly List<GetUserOrderResponse> _orders = new();
private readonly UserOrderContract.UserOrderContractClient _userOrderContractClient;
public Task<List<Order>> GetOrdersAsync() => Task.FromResult(_orders.OrderByDescending(o => o.CreatedAt).ToList());
public Task<Order?> GetOrderAsync(long id) => Task.FromResult(_orders.FirstOrDefault(o => o.Id == id));
public Task<long> CreateOrderAsync(Order order)
public OrderService(UserOrderContract.UserOrderContractClient userOrderContractClient)
{
order.Id = Interlocked.Increment(ref _seq);
_orders.Add(order);
return Task.FromResult(order.Id);
_userOrderContractClient = userOrderContractClient;
}
}
public Task<List<GetUserOrderResponse>> GetOrdersAsync()
{
return Task.FromResult(_orders.OrderByDescending(o => o.PaymentDate).ToList());
}
public async Task<GetUserOrderResponse?> GetOrderAsync(long id)
{
var order = _orders.FirstOrDefault(o => o.Id == id);
if (order == null)
{
var result = await _userOrderContractClient.GetUserOrderAsync(new GetUserOrderRequest()
{
Id = id
});
_orders.Add(result);
return result;
}
return order;
}
}

View File

@@ -3,7 +3,15 @@ using FrontOffice.BFF.Products.Protobuf.Protos.Products;
namespace FrontOffice.Main.Utilities;
public record Product(long Id, string Title, string Description, string ImageUrl, long Price);
public record Product(
long Id,
string Title,
string Description,
string ImageUrl,
long Price,
int Discount = 0,
int Rate = 0,
int RemainingCount = 0);
public class ProductService
{
@@ -81,7 +89,10 @@ public class ProductService
Title: m.Title ?? string.Empty,
Description: m.Description ?? string.Empty,
ImageUrl: string.IsNullOrWhiteSpace(m.ImagePath) ? string.Empty : UrlUtility.DownloadUrl + m.ImagePath,
Price: m.Price
Price: m.Price,
Discount: m.Discount,
Rate: m.Rate,
RemainingCount: m.RemainingCount
);
_cache[p.Id] = p;
list.Add(p);

View File

@@ -1,3 +1,6 @@
using FrontOffice.BFF.UserWallet.Protobuf.Protos.UserWallet;
using Google.Protobuf.WellKnownTypes;
namespace FrontOffice.Main.Utilities;
public record WalletBalances(long CreditBalance, long NetworkBalance);
@@ -5,16 +8,48 @@ public record WalletTransaction(DateTime Date, long Amount, string Channel, stri
public class WalletService
{
private WalletBalances _balances = new(350_000, 1_250_000);
private readonly List<WalletTransaction> _transactions = new()
{
new(DateTime.Now.AddDays(-1), 500_000, "درگاه بانکی", "شارژ کیف پول"),
new(DateTime.Now.AddDays(-2), 200_000, "شبکه/معرف", "پاداش شبکه"),
new(DateTime.Now.AddDays(-4), -120_000, "خرید", "برداشت بابت سفارش #1452"),
new(DateTime.Now.AddDays(-9), 900_000, "کیف پول شرکای تجاری", "اعتبار خرید"),
};
private readonly UserWalletContract.UserWalletContractClient _client;
public Task<WalletBalances> GetBalancesAsync() => Task.FromResult(_balances);
public Task<List<WalletTransaction>> GetTransactionsAsync() => Task.FromResult(_transactions.OrderByDescending(t => t.Date).ToList());
public WalletService(UserWalletContract.UserWalletContractClient client)
{
_client = client;
}
public async Task<WalletBalances> GetBalancesAsync()
{
try
{
var response = await _client.GetUserWalletAsync(new Empty());
return new WalletBalances(response.Balance, response.NetworkBalance);
}
catch
{
// Fallback to mock data if backend is unavailable
return new WalletBalances(350_000, 1_250_000);
}
}
public async Task<List<WalletTransaction>> GetTransactionsAsync()
{
try
{
var response = await _client.GetAllUserWalletChangeLogAsync(new Empty());
return response.Models.Select(t => new WalletTransaction(DateTime.Now, t.CurrentBalance,t.RefrenceId.Value.ToString(),t.IsIncrease?"شارژ کیف پول":"برداشت از کیف پول")
).ToList();
}
catch
{
// Fallback to mock data if backend is unavailable
var _transactions = new List<WalletTransaction>
{
new(DateTime.Now.AddDays(-1), 500_000, "درگاه بانکی", "شارژ کیف پول"),
new(DateTime.Now.AddDays(-2), 200_000, "شبکه/معرف", "پاداش شبکه"),
new(DateTime.Now.AddDays(-4), -120_000, "خرید", "برداشت بابت سفارش #1452"),
new(DateTime.Now.AddDays(-9), 900_000, "کیف پول شرکای تجاری", "اعتبار خرید"),
};
return _transactions.OrderByDescending(t => t.Date).ToList();
}
}
}