feat: add coupon checkout support

This commit is contained in:
xiong
2026-07-26 20:04:24 +08:00
parent a4621df728
commit 7139da766a
6 changed files with 673 additions and 9 deletions

View File

@@ -164,6 +164,87 @@ public sealed class CommerceEndpointTests
Assert.Equal(firstPayment!.Id, secondPayment!.Id);
}
[Fact]
public async Task Student_can_claim_and_check_coupon()
{
await using var factory = new ApiTestFactory(paymentProviderGateway: new FakePaymentGateway());
var seed = await SeedLoginUserAsync(factory);
await factory.SeedAsync(new Coupon
{
TenantId = seed.TenantId,
Code = "SAVE5",
PlanId = seed.PlanId,
DiscountType = DiscountType.Fixed,
DiscountValue = 5,
MaxUses = 10
});
using var client = factory.CreateClient();
await LoginAsync(client, seed);
var claimResponse = await client.PostAsJsonAsync(
"/api/commerce/coupons/claim",
new ClaimCommerceCouponDto { CouponCode = "SAVE5" });
var coupons = await (await client.GetAsync("/api/commerce/coupons"))
.Content
.ReadFromJsonAsync<CommerceCouponList>();
var check = await (await client.PostAsJsonAsync(
"/api/commerce/coupons/check",
new CheckCommerceCouponDto
{
CouponCode = "SAVE5",
PlanId = seed.PlanId,
Quantity = 1
}))
.Content
.ReadFromJsonAsync<CommerceCouponCheckResult>();
Assert.Equal(HttpStatusCode.OK, claimResponse.StatusCode);
Assert.Contains(coupons!.Items, item => item.CouponCode == "SAVE5" && item.Status == "Claimed");
Assert.True(check!.Valid);
Assert.Equal(500, check.DiscountCents);
Assert.Equal(499, check.PayableAmountCents);
}
[Fact]
public async Task Coupon_can_make_order_zero_amount_and_grant_entitlement()
{
await using var factory = new ApiTestFactory(paymentProviderGateway: new FakePaymentGateway());
var seed = await SeedLoginUserAsync(factory);
await factory.SeedAsync(new Coupon
{
TenantId = seed.TenantId,
Code = "FREE",
PlanId = seed.PlanId,
DiscountType = DiscountType.Fixed,
DiscountValue = 9.99m,
MaxUses = 10
});
using var client = factory.CreateClient();
await LoginAsync(client, seed);
var response = await client.PostAsJsonAsync(
"/api/commerce/orders",
new CreateCommerceOrderDto
{
PlanId = seed.PlanId,
Quantity = 1,
CouponCode = "FREE"
});
var order = await response.Content.ReadFromJsonAsync<CommerceOrderItem>();
var entitlement = await (await client.GetAsync("/api/commerce/entitlements/current"))
.Content
.ReadFromJsonAsync<CurrentEntitlementItem>();
var coupons = await (await client.GetAsync("/api/commerce/coupons?status=used"))
.Content
.ReadFromJsonAsync<CommerceCouponList>();
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.Equal(0, order!.AmountCents);
Assert.Equal("Paid", order.Status);
Assert.True(entitlement!.IsActive);
Assert.Contains(coupons!.Items, item => item.CouponCode == "FREE" && item.DiscountPreviewCents == 999);
}
[Fact]
public async Task Payment_notification_marks_order_paid_once()
{