feat(pay): 添加充值功能

- 新增 RechargeCmd 类用于处理充值命令
- 新增 RechargeDto 类用于表示充值交易数据
- 新增 OrderAction、OrderStatus 和 PayType 枚举类
- 新增 OrderRepoInterface接口和 OrderRepo 实现类,用于处理订单相关操作
- 更新 ConfigProvider,添加新依赖项
- 新增 CreateRechargeOrderTest 测试用例
This commit is contained in:
李东云
2025-08-18 19:12:07 +08:00
parent ca6000a5c8
commit 80dc1a3706
12 changed files with 267 additions and 2 deletions

View File

@@ -0,0 +1,26 @@
<?php
/**
* RechargeCmd.php@Pay
*
* @author 李东云 <Dongyun.Li@LuxCreo.Ai>
* Powered by PhpStorm
* Created on 2025/8/18
*/
declare(strict_types=1);
namespace Singularity\HDK\Pay\Application\Command;
final class RechargeCmd {
public array $items = [];
public function __construct(public string $uid) {}
public function addItem(int $productId, int $quantity = 1): void
{
$this->items[] = [
'product_id' => $productId,
'quantity' => $quantity,
];
}
}

View File

@@ -0,0 +1,46 @@
<?php
/**
* RechargeDto.php@Pay
*
* @author 李东云 <Dongyun.Li@LuxCreo.Ai>
* Powered by PhpStorm
* Created on 2025/8/18
*/
declare(strict_types=1);
namespace Singularity\HDK\Pay\Application\Dto\Transaction;
use Singularity\HDK\Pay\Domain\Transaction\Enum\OrderAction;
use Singularity\HDK\Pay\Domain\Transaction\Enum\OrderStatus;
use Singularity\HDK\Pay\Domain\Transaction\Enum\PayType;
final readonly class RechargeDto
{
public function __construct(
private string $orderNo,
private OrderAction $action,
private PayType $payType,
private OrderStatus $status,
) {}
public function getOrderNo(): string
{
return $this->orderNo;
}
public function getAction(): OrderAction
{
return $this->action;
}
public function getPayType(): PayType
{
return $this->payType;
}
public function getStatus(): OrderStatus
{
return $this->status;
}
}

View File

@@ -9,7 +9,9 @@ use Hyperf\Framework\Logger\StdoutLogger;
use Singularity\HDK\Pay\Domain\Account\Repository\AccountRepoInterface;
use Singularity\HDK\Pay\Domain\Product\Repository\ExchangeRepoInterface;
use Singularity\HDK\Pay\Domain\Product\Repository\RechargeProductRepoInterface;
use Singularity\HDK\Pay\Domain\Transaction\Repository\OrderRepoInterface;
use Singularity\HDK\Pay\Infrastructure\Repository\AccountBalanceRepo;
use Singularity\HDK\Pay\Infrastructure\Repository\OrderRepo;
use Singularity\HDK\Pay\Infrastructure\Repository\ProductRepo;
/**
@@ -28,10 +30,11 @@ class ConfigProvider
'dependencies' => [
StdoutLoggerInterface::class => StdoutLogger::class,
// Repository
// Command
AccountRepoInterface::class => AccountBalanceRepo::class,
ExchangeRepoInterface::class => ProductRepo::class,
RechargeProductRepoInterface::class => ProductRepo::class,
OrderRepoInterface::class => OrderRepo::class,
],
// 合并到 config/autoload/annotations.php 文件
'annotations' => [

View File

@@ -0,0 +1,18 @@
<?php
/**
* OrderAction.php@LuxDesign
*
* @author 李东云 <Dongyun.Li@LuxCreo.Ai>
* Powered by PhpStorm
* Created on 2025/7/30
*/
namespace Singularity\HDK\Pay\Domain\Transaction\Enum;
enum OrderAction: string {
case Recharge = 'recharge';
case Consumption = 'consumption';
case Refund = 'refund';
}

View File

@@ -0,0 +1,58 @@
<?php
/**
* OrderStatus.php@LuxDesign
*
* @author 李东云 <Dongyun.Li@LuxCreo.Ai>
* Powered by PhpStorm
* Created on 2024/11/26
*/
namespace Singularity\HDK\Pay\Domain\Transaction\Enum;
enum OrderStatus
{
case created;
case paid;
case completed;
case refunded;
case cancelled;
case failed;
case closed;
public static function tryFrom(mixed $status): OrderStatus
{
$status = strtolower($status);
return match ($status) {
'paid' => self::paid,
'refunded' => self::refunded,
'cancelled' => self::cancelled,
'completed' => self::completed,
'failed' => self::failed,
'closed' => self::closed,
default => self::created,
};
}
public static function all(): array
{
return [
self::created,
self::paid,
self::completed,
self::refunded,
self::cancelled,
self::closed,
];
}
public static function values(): array
{
return array_column(self::all(), 'value');
}
}

View File

@@ -0,0 +1,18 @@
<?php
/**
* PayType.php@LuxDesign
*
* @author 李东云 <Dongyun.Li@LuxCreo.Ai>
* Powered by PhpStorm
* Created on 2025/7/25
*/
namespace Singularity\HDK\Pay\Domain\Transaction\Enum;
Enum PayType: string {
case Point = 'point';
case Card = 'card';
case Hybrid = 'hybrid';
}

View File

@@ -0,0 +1,15 @@
<?php
/**
* OrderRepoInterface.php@Pay
*
* @author 李东云 <Dongyun.Li@LuxCreo.Ai>
* Powered by PhpStorm
* Created on 2025/8/18
*/
namespace Singularity\HDK\Pay\Domain\Transaction\Repository;
interface OrderRepoInterface
{
public function recharge(string $uid, array $items);
}

View File

@@ -30,6 +30,7 @@ abstract class AbstractRepo
$this->requestService = RequestServiceFactory::make([
'base_uri' => $baseUrl ?? config('payment.base_uri'),
RequestOptions::ALLOW_REDIRECTS => true,
'headers' => $this->headerBuilder(),
]);
}
}

View File

@@ -0,0 +1,53 @@
<?php
/**
* OrderRepo.php@Pay
*
* @author 李东云 <Dongyun.Li@LuxCreo.Ai>
* Powered by PhpStorm
* Created on 2025/8/18
*/
declare(strict_types=1);
namespace Singularity\HDK\Pay\Infrastructure\Repository;
use GuzzleHttp\Exception\GuzzleException;
use Hyperf\Codec\Json;
use Singularity\HDK\Pay\Application\Dto\Transaction\RechargeDto;
use Singularity\HDK\Pay\Domain\Transaction\Enum\OrderAction;
use Singularity\HDK\Pay\Domain\Transaction\Enum\OrderStatus;
use Singularity\HDK\Pay\Domain\Transaction\Enum\PayType;
use Singularity\HDK\Pay\Domain\Transaction\Repository\OrderRepoInterface;
final class OrderRepo extends AbstractRepo implements OrderRepoInterface
{
/**
* @param string $uid
* @param array $items
* @return RechargeDto
* @throws GuzzleException
*/
public function recharge(string $uid, array $items): RechargeDto
{
$response = $this->requestService->requestPost(
url: '/rpc/v2/transaction/orders/recharge',
data: [
'uid' => $uid,
'items' => $items,
],
options: [
'headers' => $this->headerBuilder(),
],
);
$content = $response->getBody()->getContents();
$result = Json::decode($content);
return new RechargeDto(
orderNo: $result['order_no'],
action: OrderAction::tryFrom($result['action']),
payType: PayType::tryFrom($result['pay_type']),
status: OrderStatus::tryFrom($result['status']),
);
}
}

View File

@@ -43,4 +43,4 @@ it('should can query EMA products', function () {
->and($products->getRenew())->toBeInstanceOf(ProductItem::class),
)
->and($products->getPlans())->each->toBeInstanceOf(ProductItem::class);
})->only();
});

View File

@@ -0,0 +1,26 @@
<?php
/**
* CreateRechargeOrderTest.php@Pay
*
* @author 李东云 <Dongyun.Li@LuxCreo.Ai>
* Powered by PhpStorm
* Created on 2025/8/18
*/
use Singularity\HDK\Pay\Application\Dto\Transaction\RechargeDto;
use Singularity\HDK\Pay\Infrastructure\Repository\OrderRepo;
use function Hyperf\Support\make;
it('should can create recharge order', function () {
$uid = 'cn3321';
$items = [
'product_id' => 1,
'quantity' => 2,
];
$repo = make(OrderRepo::class);
$result = $repo->recharge($uid, [$items]);
expect($result)->toBeInstanceOf(RechargeDto::class);
});

View File

@@ -34,6 +34,7 @@ $container = ApplicationContext::setContainer($container);
/** @var Config $config */
$config = make(Config::class, [
[
'app_name' => 'LuxDesign',
'dependencies' => [],
'payment' => [
'base_uri' => env('LUX_PAY_BASE_URI', 'http://test-pay.luxcreo.com'),