144 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			144 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
using DysonNetwork.Shared.Models;
 | 
						|
using DysonNetwork.Shared.Proto;
 | 
						|
using Microsoft.AspNetCore.Authorization;
 | 
						|
using Microsoft.AspNetCore.Mvc;
 | 
						|
using Microsoft.EntityFrameworkCore;
 | 
						|
 | 
						|
namespace DysonNetwork.Pass.Wallet;
 | 
						|
 | 
						|
[ApiController]
 | 
						|
[Route("/api/orders")]
 | 
						|
public class OrderController(
 | 
						|
    PaymentService payment,
 | 
						|
    Pass.Auth.AuthService auth,
 | 
						|
    AppDatabase db,
 | 
						|
    CustomAppService.CustomAppServiceClient customApps
 | 
						|
) : ControllerBase
 | 
						|
{
 | 
						|
    public class CreateOrderRequest
 | 
						|
    {
 | 
						|
        public string Currency { get; set; } = null!;
 | 
						|
        public decimal Amount { get; set; }
 | 
						|
        public string? Remarks { get; set; }
 | 
						|
        public string? ProductIdentifier { get; set; }
 | 
						|
        public Dictionary<string, object>? Meta { get; set; }
 | 
						|
        public int DurationHours { get; set; } = 24;
 | 
						|
 | 
						|
        public string ClientId { get; set; } = null!;
 | 
						|
        public string ClientSecret { get; set; } = null!;
 | 
						|
    }
 | 
						|
 | 
						|
    [HttpPost]
 | 
						|
    public async Task<ActionResult<SnWalletOrder>> CreateOrder([FromBody] CreateOrderRequest request)
 | 
						|
    {
 | 
						|
        var clientResp = await customApps.GetCustomAppAsync(new GetCustomAppRequest { Slug = request.ClientId });
 | 
						|
        if (clientResp.App is null) return BadRequest("Client not found");
 | 
						|
        var client = SnCustomApp.FromProtoValue(clientResp.App);
 | 
						|
 | 
						|
        var secret = await customApps.CheckCustomAppSecretAsync(new CheckCustomAppSecretRequest
 | 
						|
        {
 | 
						|
            AppId = client.Id.ToString(),
 | 
						|
            Secret = request.ClientSecret,
 | 
						|
        });
 | 
						|
        if (!secret.Valid) return BadRequest("Invalid client secret");
 | 
						|
 | 
						|
        var order = await payment.CreateOrderAsync(
 | 
						|
            default,
 | 
						|
            request.Currency,
 | 
						|
            request.Amount,
 | 
						|
            NodaTime.Duration.FromHours(request.DurationHours),
 | 
						|
            request.ClientId,
 | 
						|
            request.ProductIdentifier,
 | 
						|
            request.Remarks,
 | 
						|
            request.Meta
 | 
						|
        );
 | 
						|
 | 
						|
        return Ok(order);
 | 
						|
    }
 | 
						|
 | 
						|
    [HttpGet("{id:guid}")]
 | 
						|
    public async Task<ActionResult<SnWalletOrder>> GetOrderById(Guid id)
 | 
						|
    {
 | 
						|
        var order = await db.PaymentOrders.FindAsync(id);
 | 
						|
 | 
						|
        if (order == null)
 | 
						|
            return NotFound();
 | 
						|
 | 
						|
        return Ok(order);
 | 
						|
    }
 | 
						|
 | 
						|
    public class PayOrderRequest
 | 
						|
    {
 | 
						|
        public string PinCode { get; set; } = string.Empty;
 | 
						|
    }
 | 
						|
 | 
						|
    [HttpPost("{id:guid}/pay")]
 | 
						|
    [Authorize]
 | 
						|
    public async Task<ActionResult<SnWalletOrder>> PayOrder(Guid id, [FromBody] PayOrderRequest request)
 | 
						|
    {
 | 
						|
        if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
 | 
						|
 | 
						|
        // Validate PIN code
 | 
						|
        if (!await auth.ValidatePinCode(currentUser.Id, request.PinCode))
 | 
						|
            return StatusCode(403, "Invalid PIN Code");
 | 
						|
 | 
						|
        try
 | 
						|
        {
 | 
						|
            // Get the wallet for the current user
 | 
						|
            var wallet = await db.Wallets.FirstOrDefaultAsync(w => w.AccountId == currentUser.Id);
 | 
						|
            if (wallet == null)
 | 
						|
                return BadRequest("Wallet was not found.");
 | 
						|
 | 
						|
            // Pay the order
 | 
						|
            var paidOrder = await payment.PayOrderAsync(id, wallet);
 | 
						|
            return Ok(paidOrder);
 | 
						|
        }
 | 
						|
        catch (InvalidOperationException ex)
 | 
						|
        {
 | 
						|
            return BadRequest(new { error = ex.Message });
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    public class UpdateOrderStatusRequest
 | 
						|
    {
 | 
						|
        public string ClientId { get; set; } = null!;
 | 
						|
        public string ClientSecret { get; set; } = null!;
 | 
						|
        public Shared.Models.OrderStatus Status { get; set; }
 | 
						|
    }
 | 
						|
 | 
						|
    [HttpPatch("{id:guid}/status")]
 | 
						|
    public async Task<ActionResult<SnWalletOrder>> UpdateOrderStatus(Guid id, [FromBody] UpdateOrderStatusRequest request)
 | 
						|
    {
 | 
						|
        var clientResp = await customApps.GetCustomAppAsync(new GetCustomAppRequest { Slug = request.ClientId });
 | 
						|
        if (clientResp.App is null) return BadRequest("Client not found");
 | 
						|
        var client = SnCustomApp.FromProtoValue(clientResp.App);
 | 
						|
 | 
						|
        var secret = await customApps.CheckCustomAppSecretAsync(new CheckCustomAppSecretRequest
 | 
						|
        {
 | 
						|
            AppId = client.Id.ToString(),
 | 
						|
            Secret = request.ClientSecret,
 | 
						|
        });
 | 
						|
        if (!secret.Valid) return BadRequest("Invalid client secret");
 | 
						|
 | 
						|
        var order = await db.PaymentOrders.FindAsync(id);
 | 
						|
 | 
						|
        if (order == null)
 | 
						|
            return NotFound();
 | 
						|
 | 
						|
        if (order.AppIdentifier != request.ClientId)
 | 
						|
        {
 | 
						|
            return BadRequest("Order does not belong to this client.");
 | 
						|
        }
 | 
						|
 | 
						|
        if (request.Status != Shared.Models.OrderStatus.Finished && request.Status != Shared.Models.OrderStatus.Cancelled)
 | 
						|
            return BadRequest("Invalid status. Available statuses are Finished, Cancelled.");
 | 
						|
 | 
						|
 | 
						|
        order.Status = request.Status;
 | 
						|
        await db.SaveChangesAsync();
 | 
						|
 | 
						|
        return Ok(order);
 | 
						|
    }
 | 
						|
}
 | 
						|
 |