Merge branch 'master' of http://101.132.182.216:3000/cgx/petwash
This commit is contained in:
@@ -9,10 +9,12 @@ namespace PetWash.Api.Controllers;
|
||||
public class OrdersController : ControllerBase
|
||||
{
|
||||
private readonly OrderService _orderService;
|
||||
private readonly WeChatPayService _weChatPayService;
|
||||
|
||||
public OrdersController(OrderService orderService)
|
||||
public OrdersController(OrderService orderService, WeChatPayService weChatPayService)
|
||||
{
|
||||
_orderService = orderService;
|
||||
_weChatPayService = weChatPayService;
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
@@ -21,12 +23,24 @@ public class OrdersController : ControllerBase
|
||||
try
|
||||
{
|
||||
var order = await _orderService.CreateOrderAsync(request.PackageId);
|
||||
return Ok(order);
|
||||
var payment = await _weChatPayService.CreateNativePayAsync(order, HttpContext.RequestAborted);
|
||||
|
||||
return Ok(new CreateOrderResponse
|
||||
{
|
||||
Order = order,
|
||||
CodeUrl = payment.CodeUrl,
|
||||
OutTradeNo = payment.OutTradeNo,
|
||||
ExpiresAt = payment.ExpiresAt
|
||||
});
|
||||
}
|
||||
catch (ArgumentException ex)
|
||||
{
|
||||
return BadRequest(ex.Message);
|
||||
}
|
||||
catch (InvalidOperationException ex)
|
||||
{
|
||||
return StatusCode(StatusCodes.Status502BadGateway, ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
[HttpPost("{id}/payment")]
|
||||
@@ -39,6 +53,56 @@ public class OrdersController : ControllerBase
|
||||
return Ok(order);
|
||||
}
|
||||
|
||||
[HttpGet("{id}/payment-status")]
|
||||
public async Task<IActionResult> GetPaymentStatus(int id, [FromQuery] string outTradeNo)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(outTradeNo))
|
||||
{
|
||||
return BadRequest("outTradeNo is required.");
|
||||
}
|
||||
|
||||
var order = await _orderService.GetOrderAsync(id);
|
||||
if (order == null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
if (order.IsPaid)
|
||||
{
|
||||
return Ok(new PaymentStatusResponse
|
||||
{
|
||||
Order = order,
|
||||
IsPaid = true,
|
||||
TradeState = "SUCCESS",
|
||||
OutTradeNo = outTradeNo,
|
||||
Message = "Order already confirmed."
|
||||
});
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var payment = await _weChatPayService.QueryOrderByOutTradeNoAsync(outTradeNo, HttpContext.RequestAborted);
|
||||
if (string.Equals(payment.TradeState, "SUCCESS", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
order = await _orderService.ConfirmPaymentAsync(id) ?? order;
|
||||
}
|
||||
|
||||
return Ok(new PaymentStatusResponse
|
||||
{
|
||||
Order = order,
|
||||
IsPaid = order.IsPaid,
|
||||
TradeState = payment.TradeState,
|
||||
OutTradeNo = payment.OutTradeNo,
|
||||
TransactionId = payment.TransactionId,
|
||||
Message = order.IsPaid ? "Payment confirmed." : "Waiting for payment."
|
||||
});
|
||||
}
|
||||
catch (InvalidOperationException ex)
|
||||
{
|
||||
return StatusCode(StatusCodes.Status502BadGateway, ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
[HttpGet("{id}")]
|
||||
public async Task<IActionResult> GetOrder(int id)
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using PetWash.Api.Data;
|
||||
using PetWash.Api.Models;
|
||||
|
||||
namespace PetWash.Api.Controllers;
|
||||
|
||||
@@ -18,7 +19,9 @@ public class PackagesController : ControllerBase
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> GetPackages()
|
||||
{
|
||||
var packages = await _context.Packages.ToListAsync();
|
||||
var packages = await _context.Packages
|
||||
.OrderBy(x => x.Id)
|
||||
.ToListAsync();
|
||||
return Ok(packages);
|
||||
}
|
||||
|
||||
@@ -31,4 +34,71 @@ public class PackagesController : ControllerBase
|
||||
|
||||
return Ok(package);
|
||||
}
|
||||
|
||||
[HttpPut("{id}")]
|
||||
public async Task<IActionResult> UpdatePackage(int id, [FromBody] UpdatePackageRequest request)
|
||||
{
|
||||
var package = await _context.Packages.FindAsync(id);
|
||||
if (package == null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
if (request.Price <= 0)
|
||||
{
|
||||
return BadRequest("套餐金额必须大于 0。");
|
||||
}
|
||||
|
||||
if (request.FirstSprayWaterTime <= 0 ||
|
||||
request.AfterShampoo1SprayTime <= 0 ||
|
||||
request.AfterShampoo2SprayTime <= 0 ||
|
||||
request.AfterShampoo3SprayTime <= 0 ||
|
||||
request.SprayShampoo1Time <= 0 ||
|
||||
request.SprayShampoo2Time <= 0 ||
|
||||
request.SprayShampoo3Time <= 0 ||
|
||||
request.HotAirTime <= 0 ||
|
||||
request.ColdAirTime <= 0 ||
|
||||
request.UvSterilizationTime <= 0)
|
||||
{
|
||||
return BadRequest("套餐流程时间必须全部大于 0。");
|
||||
}
|
||||
|
||||
package.Price = request.Price;
|
||||
package.FirstSprayWaterTime = request.FirstSprayWaterTime;
|
||||
package.AfterShampoo1SprayTime = request.AfterShampoo1SprayTime;
|
||||
package.AfterShampoo2SprayTime = request.AfterShampoo2SprayTime;
|
||||
package.AfterShampoo3SprayTime = request.AfterShampoo3SprayTime;
|
||||
package.SprayShampoo1Time = request.SprayShampoo1Time;
|
||||
package.SprayShampoo2Time = request.SprayShampoo2Time;
|
||||
package.SprayShampoo3Time = request.SprayShampoo3Time;
|
||||
package.HotAirTime = request.HotAirTime;
|
||||
package.ColdAirTime = request.ColdAirTime;
|
||||
package.UvSterilizationTime = request.UvSterilizationTime;
|
||||
package.DurationMinutes = request.FirstSprayWaterTime
|
||||
+ request.AfterShampoo1SprayTime
|
||||
+ request.AfterShampoo2SprayTime
|
||||
+ request.AfterShampoo3SprayTime
|
||||
+ request.SprayShampoo1Time
|
||||
+ request.SprayShampoo2Time
|
||||
+ request.SprayShampoo3Time
|
||||
+ request.HotAirTime
|
||||
+ request.ColdAirTime
|
||||
+ request.UvSterilizationTime;
|
||||
|
||||
await _context.SaveChangesAsync();
|
||||
return Ok(package);
|
||||
}
|
||||
}
|
||||
|
||||
public record UpdatePackageRequest(
|
||||
decimal Price,
|
||||
int FirstSprayWaterTime,
|
||||
int AfterShampoo1SprayTime,
|
||||
int AfterShampoo2SprayTime,
|
||||
int AfterShampoo3SprayTime,
|
||||
int SprayShampoo1Time,
|
||||
int SprayShampoo2Time,
|
||||
int SprayShampoo3Time,
|
||||
int HotAirTime,
|
||||
int ColdAirTime,
|
||||
int UvSterilizationTime);
|
||||
|
||||
57
PetWash.Api/Controllers/PaymentsController.cs
Normal file
57
PetWash.Api/Controllers/PaymentsController.cs
Normal file
@@ -0,0 +1,57 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using PetWash.Api.Services;
|
||||
|
||||
namespace PetWash.Api.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/payments/wechat")]
|
||||
public class PaymentsController : ControllerBase
|
||||
{
|
||||
private readonly OrderService _orderService;
|
||||
private readonly WeChatPayService _weChatPayService;
|
||||
private readonly ILogger<PaymentsController> _logger;
|
||||
|
||||
public PaymentsController(
|
||||
OrderService orderService,
|
||||
WeChatPayService weChatPayService,
|
||||
ILogger<PaymentsController> logger)
|
||||
{
|
||||
_orderService = orderService;
|
||||
_weChatPayService = weChatPayService;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
[HttpPost("notify")]
|
||||
public async Task<IActionResult> Notify(CancellationToken cancellationToken)
|
||||
{
|
||||
using var reader = new StreamReader(Request.Body);
|
||||
var body = await reader.ReadToEndAsync(cancellationToken);
|
||||
|
||||
try
|
||||
{
|
||||
var notification = await _weChatPayService.ParsePaymentNotificationAsync(
|
||||
body,
|
||||
Request.Headers,
|
||||
cancellationToken);
|
||||
|
||||
if (string.Equals(notification.TradeState, "SUCCESS", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var order = await _orderService.ConfirmPaymentAsync(notification.OrderId);
|
||||
if (order == null)
|
||||
{
|
||||
_logger.LogWarning(
|
||||
"WeChat payment notification references a missing order. OrderId={OrderId}, OutTradeNo={OutTradeNo}",
|
||||
notification.OrderId,
|
||||
notification.OutTradeNo);
|
||||
}
|
||||
}
|
||||
|
||||
return Ok(new { code = "SUCCESS", message = "成功" });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Failed to process WeChat payment notification.");
|
||||
return BadRequest(new { code = "FAIL", message = ex.Message });
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user