payment_provider_service.py 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. # app/services/payment_provider.py
  2. from typing import List, Optional
  3. from sqlalchemy.ext.asyncio import AsyncSession
  4. from sqlalchemy import select
  5. from app.core.biz_exception import NotFoundError, BizLogicError
  6. from app.models.payment_provider import VasPaymentProvider
  7. from app.schemas.payment_provider import (
  8. VasPaymentProviderCreate,
  9. VasPaymentProviderUpdate,
  10. )
  11. class PaymentProviderService:
  12. # --------------------------------------------------
  13. # 创建支付提供商(防重复)
  14. # --------------------------------------------------
  15. @staticmethod
  16. async def create(
  17. db: AsyncSession,
  18. data: VasPaymentProviderCreate,
  19. ) -> VasPaymentProvider:
  20. stmt = select(VasPaymentProvider).where(
  21. VasPaymentProvider.name == data.name,
  22. VasPaymentProvider.channel == data.channel,
  23. VasPaymentProvider.currency == data.currency,
  24. )
  25. exists = (await db.execute(stmt)).scalar_one_or_none()
  26. if exists:
  27. raise BizLogicError("Payment provider already exists")
  28. provider = VasPaymentProvider(
  29. name=data.name,
  30. channel=data.channel,
  31. currency=data.currency,
  32. icon=data.icon,
  33. enabled=data.enabled if data.enabled is not None else 1,
  34. config=data.config,
  35. )
  36. db.add(provider)
  37. await db.commit()
  38. await db.refresh(provider)
  39. return provider
  40. # --------------------------------------------------
  41. # 更新支付提供商(禁止修改 name/channel/currency)
  42. # --------------------------------------------------
  43. @staticmethod
  44. async def update(
  45. db: AsyncSession,
  46. provider_id: int,
  47. data: VasPaymentProviderUpdate,
  48. ) -> VasPaymentProvider:
  49. stmt = select(VasPaymentProvider).where(
  50. VasPaymentProvider.id == provider_id
  51. )
  52. provider = (await db.execute(stmt)).scalar_one_or_none()
  53. if not provider:
  54. raise NotFoundError("Payment provider not found")
  55. update_data = data.dict(exclude_unset=True)
  56. # 🚫 禁止修改三元组
  57. for forbidden in ("name", "channel", "currency"):
  58. update_data.pop(forbidden, None)
  59. for key, value in update_data.items():
  60. setattr(provider, key, value)
  61. await db.commit()
  62. await db.refresh(provider)
  63. return provider
  64. # --------------------------------------------------
  65. # 删除支付提供商
  66. # --------------------------------------------------
  67. @staticmethod
  68. async def delete(
  69. db: AsyncSession,
  70. provider_id: int,
  71. ) -> bool:
  72. stmt = select(VasPaymentProvider).where(
  73. VasPaymentProvider.id == provider_id
  74. )
  75. provider = (await db.execute(stmt)).scalar_one_or_none()
  76. if not provider:
  77. raise NotFoundError("Provider not exist")
  78. await db.delete(provider)
  79. await db.commit()
  80. return True
  81. # --------------------------------------------------
  82. # 所有支付提供商
  83. # --------------------------------------------------
  84. @staticmethod
  85. async def list_all(
  86. db: AsyncSession,
  87. ) -> List[VasPaymentProvider]:
  88. result = await db.execute(select(VasPaymentProvider))
  89. return result.scalars().all()
  90. # --------------------------------------------------
  91. # 可用的支付提供商(可按币种)
  92. # --------------------------------------------------
  93. @staticmethod
  94. async def list_enabled(
  95. db: AsyncSession,
  96. currency: Optional[str] = None,
  97. ) -> List[VasPaymentProvider]:
  98. stmt = select(VasPaymentProvider).where(
  99. VasPaymentProvider.enabled == 1
  100. )
  101. if currency:
  102. stmt = stmt.where(VasPaymentProvider.currency == currency)
  103. result = await db.execute(stmt)
  104. return result.scalars().all()
  105. # --------------------------------------------------
  106. # 根据 name 获取(只返回 enabled)
  107. # --------------------------------------------------
  108. @staticmethod
  109. async def get_by_name(
  110. db: AsyncSession,
  111. name: str,
  112. ) -> Optional[VasPaymentProvider]:
  113. stmt = select(VasPaymentProvider).where(
  114. VasPaymentProvider.enabled == 1,
  115. VasPaymentProvider.name == name,
  116. )
  117. return (await db.execute(stmt)).scalar_one_or_none()