feat(payment): 优化套餐配置和支付服务

- 简化套餐配置结构,删除冗余的 default.yaml 和 us.yaml
- 优化 Apple IAP 服务和验证逻辑
- 更新套餐数据模型和协议文档
- 添加支付相关测试用例
This commit is contained in:
ZL-Q
2026-04-28 17:21:14 +08:00
parent a940f2ea47
commit 295dbc09ab
23 changed files with 285 additions and 304 deletions
@@ -30,6 +30,7 @@ class _FakePaymentRepository:
self.inserted_transactions: list[AppleIapTransaction] = []
self.claim: RegisterBonusClaims | None = None
self.claim_starter_pack_called: bool = False
self.commit_count = 0
async def get_or_create_user_points_for_update(self, *, user_id: UUID) -> _FakeAccount:
return self.account
@@ -59,6 +60,9 @@ class _FakePaymentRepository:
self.claim.has_purchased_starter_pack = True
return self.claim
async def commit(self) -> None:
self.commit_count += 1
class _FakePointsRepository:
def __init__(self) -> None:
@@ -78,14 +82,17 @@ class _FakeVerifier:
*,
expected_bundle_id: str,
expected_product_id: str,
expected_environment: str,
) -> VerifiedTransaction | VerificationError:
del signed_transaction_info, expected_bundle_id, expected_product_id
del expected_environment
return self._result
def _make_verified_transaction(
*,
transaction_id: str = "2000000123456789",
product_id: str = "com.meeyao.qianwen.basic_pack",
product_id: str = "com.meeyao.qianwen.starter_pack",
environment: str = "Sandbox",
) -> VerifiedTransaction:
return VerifiedTransaction(
@@ -134,7 +141,7 @@ class TestPaymentServiceProductMismatch:
verifier=_FakeVerifier(result=_make_verified_transaction()),
)
request = VerifyTransactionRequest(
productCode="basic_pack",
productCode="starter_pack",
appStoreProductId="com.meeyao.qianwen.wrong_pack",
transactionId="2000000123456789",
signedTransactionInfo="fake_jws",
@@ -162,8 +169,8 @@ class TestPaymentServiceVerificationFailed:
),
)
request = VerifyTransactionRequest(
productCode="basic_pack",
appStoreProductId="com.meeyao.qianwen.basic_pack",
productCode="starter_pack",
appStoreProductId="com.meeyao.qianwen.starter_pack",
transactionId="2000000123456789",
signedTransactionInfo="fake_jws",
)
@@ -183,8 +190,8 @@ class TestPaymentServiceAlreadyGranted:
existing = AppleIapTransaction(
id=uuid4(),
user_id=user_id,
product_code="basic_pack",
app_store_product_id="com.meeyao.qianwen.basic_pack",
product_code="starter_pack",
app_store_product_id="com.meeyao.qianwen.starter_pack",
transaction_id="2000000123456789",
original_transaction_id="2000000123456789",
environment="Sandbox",
@@ -202,8 +209,8 @@ class TestPaymentServiceAlreadyGranted:
verifier=_FakeVerifier(result=_make_verified_transaction()),
)
request = VerifyTransactionRequest(
productCode="basic_pack",
appStoreProductId="com.meeyao.qianwen.basic_pack",
productCode="starter_pack",
appStoreProductId="com.meeyao.qianwen.starter_pack",
transactionId="2000000123456789",
signedTransactionInfo="fake_jws",
)
@@ -222,8 +229,8 @@ class TestPaymentServiceTransactionConflict:
existing = AppleIapTransaction(
id=uuid4(),
user_id=uuid4(),
product_code="basic_pack",
app_store_product_id="com.meeyao.qianwen.basic_pack",
product_code="starter_pack",
app_store_product_id="com.meeyao.qianwen.starter_pack",
transaction_id="2000000123456789",
original_transaction_id="2000000123456789",
environment="Sandbox",
@@ -241,8 +248,8 @@ class TestPaymentServiceTransactionConflict:
verifier=_FakeVerifier(result=_make_verified_transaction()),
)
request = VerifyTransactionRequest(
productCode="basic_pack",
appStoreProductId="com.meeyao.qianwen.basic_pack",
productCode="starter_pack",
appStoreProductId="com.meeyao.qianwen.starter_pack",
transactionId="2000000123456789",
signedTransactionInfo="fake_jws",
)
@@ -266,8 +273,8 @@ class TestPaymentServiceSuccessfulGrant:
verifier=_FakeVerifier(result=_make_verified_transaction()),
)
request = VerifyTransactionRequest(
productCode="basic_pack",
appStoreProductId="com.meeyao.qianwen.basic_pack",
productCode="starter_pack",
appStoreProductId="com.meeyao.qianwen.starter_pack",
transactionId="2000000123456789",
signedTransactionInfo="fake_jws",
)
@@ -368,6 +375,7 @@ class _FakePaymentRepoForRefund:
self._transaction = transaction
self.account = account or _FakeAccountForRefund()
self.inserted_transactions: list[AppleIapTransaction] = []
self.commit_count = 0
async def get_transaction_by_transaction_id(self, *, transaction_id: str) -> AppleIapTransaction | None:
return self._transaction
@@ -389,6 +397,9 @@ class _FakePaymentRepoForRefund:
) -> None:
pass
async def commit(self) -> None:
self.commit_count += 1
class TestProcessRefundUnknownTransaction:
@pytest.mark.asyncio
@@ -407,8 +418,8 @@ class TestProcessRefundNotGranted:
txn = AppleIapTransaction(
id=uuid4(),
user_id=uuid4(),
product_code="basic_pack",
app_store_product_id="com.meeyao.qianwen.basic_pack",
product_code="starter_pack",
app_store_product_id="com.meeyao.qianwen.starter_pack",
transaction_id="2000000999999999",
original_transaction_id="2000000999999999",
environment="Sandbox",
@@ -435,8 +446,8 @@ class TestProcessRefundSufficientBalance:
txn = AppleIapTransaction(
id=uuid4(),
user_id=user_id,
product_code="basic_pack",
app_store_product_id="com.meeyao.qianwen.basic_pack",
product_code="starter_pack",
app_store_product_id="com.meeyao.qianwen.starter_pack",
transaction_id="2000000999999999",
original_transaction_id="2000000999999999",
environment="Sandbox",
@@ -473,8 +484,8 @@ class TestProcessRefundInsufficientBalance:
txn = AppleIapTransaction(
id=uuid4(),
user_id=user_id,
product_code="basic_pack",
app_store_product_id="com.meeyao.qianwen.basic_pack",
product_code="starter_pack",
app_store_product_id="com.meeyao.qianwen.starter_pack",
transaction_id="2000000999999998",
original_transaction_id="2000000999999998",
environment="Sandbox",
@@ -509,8 +520,8 @@ class TestProcessRefundIdempotency:
txn = AppleIapTransaction(
id=uuid4(),
user_id=user_id,
product_code="basic_pack",
app_store_product_id="com.meeyao.qianwen.basic_pack",
product_code="starter_pack",
app_store_product_id="com.meeyao.qianwen.starter_pack",
transaction_id="2000000999999997",
original_transaction_id="2000000999999997",
environment="Sandbox",
@@ -539,8 +550,8 @@ class TestHandleServerNotificationRefund:
txn = AppleIapTransaction(
id=uuid4(),
user_id=user_id,
product_code="basic_pack",
app_store_product_id="com.meeyao.qianwen.basic_pack",
product_code="starter_pack",
app_store_product_id="com.meeyao.qianwen.starter_pack",
transaction_id="2000000999999001",
original_transaction_id="2000000999999001",
environment="Sandbox",