Compare commits

...

18 Commits

Author SHA1 Message Date
李东云
633bf585e1 build: 换成satis 2025-12-24 16:01:35 +08:00
李东云
0573ff595f chore(release): 1.13.2 2025-12-24 15:26:41 +08:00
李东云
72004d3916 chore(release): 1.13.1 2025-12-24 14:11:33 +08:00
李东云
7ade038f0f fix(ProductRepo): 将isset检查改为!empty检查以确保数据有效性 2025-12-24 14:11:13 +08:00
李东云
175a170dec chore(release): 1.13.0 2025-12-02 17:59:45 +08:00
李东云
19e95016fa feat(发票): 为发送发票接口添加可选邮箱参数
在发送发票接口中添加可选的邮箱参数,允许指定接收发票的邮箱地址。当不指定邮箱时,保持原有行为不变。
2025-12-02 17:59:18 +08:00
李东云
6fd7f2f421 chore(release): 1.12.4 2025-12-02 16:05:11 +08:00
李东云
1d1cdd7829 fix(invoice): 修正发票金额计算逻辑
- 将金额乘以100改为除以100以获得正确的数值
- 确保货币金额在存储前被正确转换为浮点数
- 保留两位小数精度以匹配财务数据标准
2025-12-02 16:04:53 +08:00
李东云
98fa6262a9 chore(release): 1.12.3 2025-12-01 15:32:07 +08:00
李东云
7d836f50df chore(release): 1.12.2 2025-12-01 15:18:19 +08:00
李东云
0452910354 chore(release): 1.12.1 2025-12-01 15:00:34 +08:00
李东云
28b81f427e feat(Invoice): 添加价格和货币信息到发票信息
- 在 InvoiceInfo 类中添加 price 和 currencySymbol 属性,并提供相关获取方法
- 修改 InvoiceRepo 以适配新的 InvoiceInfo 结构
2025-12-01 15:00:07 +08:00
李东云
46da805cb4 fix(InvoiceRepo): 修复InvoiceProduct构造函数缺少prices参数的问题
添加PointPrice数组参数到InvoiceProduct构造函数调用中,确保API响应中的价格数据被正确处理。同时添加必要的类导入声明。
2025-12-01 14:04:36 +08:00
李东云
f0550c4272 chore(release): 1.12.0 2025-11-28 18:26:10 +08:00
李东云
cae728b392 feat(账户): 添加邮箱管理功能并重构账户仓库
- 创建 Email 值对象用于封装邮箱信息
- 扩展 AccountRepoInterface 添加邮箱管理方法
- 重命名 AccountBalanceRepo 为 AccountRepo 并实现邮箱功能
- 更新相关测试用例和配置以适配新功能
2025-11-28 18:25:52 +08:00
李东云
6bc423417c refactor: 适配项目目录结构从 app/ 改为 src/
修改 run-in-docker.sh 项目名以保持一致性
更新测试脚本和 composer.json 中的目录引用
添加项目文档和计划文件
2025-11-28 18:07:48 +08:00
李东云
cb938d6130 feat: 添加 run-in-docker.sh 脚本用于在容器中运行命令
添加新的脚本文件 run-in-docker.sh,用于检查并启动 Docker 容器,并在容器内执行指定命令。脚本会自动处理容器的启动和端口分配,简化开发环境中的命令执行流程。
2025-11-28 18:01:41 +08:00
李东云
327066b146 ci: 添加测试相关的CI脚本
添加多个测试脚本用于CI流程,包括完整CI流程、Phpspec测试、静态分析、所有测试、代码风格修复与检查以及单元测试
2025-11-28 17:59:33 +08:00
30 changed files with 6389 additions and 173 deletions

View File

@@ -0,0 +1,19 @@
# 生成 llm.txt 文件计划
## 任务目标
阅读整个项目,并生成 llm.txt 文件,总结项目的结构、功能和技术栈。
## 实现步骤
1. 退出计划模式,进入执行模式
2. 生成 llm.txt 文件,包含以下内容:
- 项目基本信息
- 技术栈
- 项目架构
- 核心功能模块
- 主要领域模型
- RPC 服务
- 配置说明
3. 确保文件内容全面、准确地反映项目结构和功能
## 预期结果
生成一个完整的 llm.txt 文件,包含项目的所有重要信息,便于后续参考和使用。

View File

@@ -0,0 +1,52 @@
# 脚本适配计划
## 任务目标
根据 `/Users/weili/Projects/HDK/Pay/scripts/docker-env.sh` 参考,适配从 LuxPay 项目复制过来的脚本,包括 `run-in-docker.sh``scripts/test/` 下的所有测试脚本。
## 适配分析
### 1. 脚本文件分析
#### 1.1 run-in-docker.sh
- 功能:在 Docker 容器中运行命令
- 镜像:`harbor.luxcreo.cn/library/hyperf:8.2-swoole`
- 项目名:`lux-pay-run`
- 行为:检查容器是否运行,如未运行则启动后台容器
#### 1.2 scripts/docker-env.sh参考
- 功能:启动交互式 Docker 容器
- 镜像:`harbor.luxcreo.cn/library/hyperf:8.2-swoole`
- 项目名:`hdk-pay`
- 行为:直接启动交互式容器,退出后容器删除
#### 1.3 测试脚本
- 所有脚本都使用 `./run-in-docker.sh` 运行命令
- 代码风格检查和修复脚本使用 `app/` 目录,但本项目使用 `src/`
- 静态分析脚本使用 `app/` 目录,需要改为 `src/`
- `phpspec-tests.sh` 可能不需要,因为本项目使用 PHPUnit/Pest
### 2. 适配方案
#### 2.1 适配 run-in-docker.sh
- 保持基本功能不变
- 考虑使用与参考脚本一致的项目名 `hdk-pay`
- 确保容器配置与参考脚本兼容
#### 2.2 适配测试脚本
- 修改 `code-style-check.sh``code-style-fix.sh`:将 `app/` 改为 `src/`
- 修改 `static-analysis.sh`:将 `app/` 改为 `src/`
- 检查 `phpspec-tests.sh`:如不需要则删除
- 确保所有脚本使用正确的目录结构
#### 2.3 适配 composer.json 脚本
- 修改 `analyse` 脚本:将 `./app` 改为 `./src`
## 执行步骤
1. 适配 `run-in-docker.sh` 脚本
2. 适配 `scripts/test/` 下的所有测试脚本
3. 适配 `composer.json` 中的脚本配置
4. 测试脚本是否能正常运行
## 预期结果
所有脚本都能正确适配本项目,使用正确的目录结构和 Docker 环境,能够正常执行各种测试和代码质量检查任务。

View File

@@ -0,0 +1,83 @@
# 邮箱管理 SDK 生成计划(最终版本)
## 任务目标
根据 OpenAPI 规范,生成“获取用户常用邮箱”和“更新用户常用邮箱”接口的 SDK严格遵循 DDD 架构,不创建新的 Rpc 文件,创建独立的邮箱管理仓库或合理命名现有仓库。
## 分析与设计
### 1. 接口分析
从 OpenAPI 规范中,我找到了两个邮箱管理相关接口:
- **GET /rpc/v2/account/{uid}/inv-email**:获取用户常用邮箱
- **PUT /rpc/v2/account/{uid}/inv-email**:更新用户常用邮箱
### 2. 现有代码结构DDD 架构)
- **Domain 层**
- `AccountRepoInterface`:账户仓库接口
- `AccountBalance``PointsBalance`:账户相关聚合根和值对象
- `PointType``PointAction`:枚举类
- **Infrastructure 层**
- `AccountBalanceRepo`:实现了 `AccountRepoInterface`,但名称仅反映余额管理
- `AbstractRepo`:基础仓库类,封装了 HTTP 请求
### 3. 实现方案
#### 3.1 方案选择
考虑到用户反馈,我选择以下方案:
- **扩展 AccountRepoInterface**:添加邮箱管理方法
- **创建新的 AccountRepo 实现**:将 AccountBalanceRepo 重命名为 AccountRepo使其更通用
- **创建 Email 领域对象**:创建 Email 值对象封装邮箱信息
#### 3.2 具体设计
1. **创建 Email 领域对象**
- `Email`:值对象,封装邮箱信息
2. **扩展 AccountRepoInterface**
- `getEmail`:获取用户常用邮箱,返回 `Email` 对象
- `updateEmail`:更新用户常用邮箱,接收 `Email` 对象
3. **重命名并扩展 AccountBalanceRepo**
-`AccountBalanceRepo` 重命名为 `AccountRepo`
- 实现新添加的邮箱管理方法
- 保持原有余额管理功能不变
## 执行步骤
1. **创建 Email 领域对象**
-`Domain/Account/ValueObject` 目录下创建 `Email.php`
2. **扩展 AccountRepoInterface**
- 添加 `getEmail``updateEmail` 方法
3. **重命名并扩展 AccountBalanceRepo**
-`AccountBalanceRepo` 重命名为 `AccountRepo`
- 实现邮箱管理方法
4. **更新 ConfigProvider**
- 更新依赖注入配置,将 `AccountRepoInterface` 指向新的 `AccountRepo`
5. **编写测试用例**
- 验证邮箱管理功能
## 预期结果
- 完成邮箱管理相关接口的 SDK 实现
- 严格遵循 DDD 架构,不创建新的 Rpc 文件
- 仓库名称更合理,支持账户的多种操作(余额和邮箱)
- 创建了 Email 领域对象,封装邮箱信息
- 代码结构符合项目现有规范
- 包含必要的测试用例
## 技术细节
- 使用现有的 `AbstractRepo` 作为基础类
- 使用 `RequestService` 进行 HTTP 请求
- 遵循项目现有的代码风格和命名规范
- 使用 PHP 8.2 的特性(如 readonly 属性、命名参数)
- 保持与现有代码的一致性
## 命名调整说明
-`AccountBalanceRepo` 重命名为 `AccountRepo`,使其更通用,能够处理账户相关的多种操作,包括余额和邮箱管理
- 创建 `Email` 值对象,封装邮箱信息,符合 DDD 领域驱动设计原则

View File

@@ -0,0 +1,66 @@
## 修复计划
### 问题分析
`/Users/weili/Projects/HDK/Pay/src/Infrastructure/Repository/InvoiceRepo.php` 第131-137行创建 `InvoiceProduct` 实例时缺少 `prices` 参数,导致构造函数调用失败。
### 错误原因
1. `InvoiceProduct` 类构造函数需要6个参数`caseId`, `uid`, `name`, `sku`, `description`, `prices`
2. 当前代码只传递了5个参数缺少 `prices` 参数
3. `prices` 参数是 `PointPrice[]` 类型的数组,不能为空
### 修复步骤
1. **添加必要的导入**
-`InvoiceRepo.php` 中添加 `Money``Currency` 类的导入
- 添加 `PointPrice` 类的导入
2. **处理API响应中的prices数据**
- 从API响应中提取 `prices` 数据(路径:`$result['product']['prices']`
- 遍历 `prices` 数据,为每个价格创建 `PointPrice` 实例
- 使用 `array_map` 函数简化处理过程
3. **完善InvoiceProduct实例创建**
- 将处理好的 `prices` 数组传递给 `InvoiceProduct` 构造函数
### 预期结果
- 修复后,`InvoiceRepo::getInvoiceInfo()` 方法能够成功创建 `InvoiceProduct` 实例
- 不再出现构造函数参数缺失的错误
- 代码能够正常运行,返回完整的 `InvoiceInfo` 对象
### 修复代码示例
```php
// 1. 在InvoiceRepo.php顶部添加必要的导入
use Money\Currency;
use Money\Money;
use Singularity\HDK\Pay\Domain\Invoice\Aggregate\Invoice\ValueObject\PointPrice;
// 2. 在getInvoiceInfo()方法中完善InvoiceProduct实例创建
product: new InvoiceProduct(
caseId: $result['case_id'],
uid: $result['uid'],
name: $result['product']['name'],
sku: $result['product']['sku'],
description: $result['product']['description'],
prices: array_map(
callback: fn(array $price) => new PointPrice(
price: new Money(
amount: bcmul((string)$price['amount'], '100', 2),
currency: new Currency($price['currency']),
),
currencySymbol: $price['symbol'],
),
array: $result['product']['prices'],
),
),
```
### 检查结果
- 已检查所有使用 `InvoiceProduct` 的地方,只有 `InvoiceRepo.php` 中存在参数缺失问题
- `InvoiceProductRepo.php` 中的实现是正确的,可以作为参考
- 修复后,所有 `InvoiceProduct` 实例创建都会符合构造函数要求
### 测试建议
- 修复后,运行相关测试用例验证修复效果
- 可以使用 `./run-in-docker.sh APP_STATUS=false vendor/bin/pest --coroutine --prepend=tests/bootstrap.php` 运行测试
- 检查是否还有其他类似的构造函数参数问题

View File

@@ -1,4 +1,61 @@
# 版本更新日志 # 版本更新日志
### [1.13.2](http://124.126.16.154:8888/singularity/hdk-pay/compare/v1.13.1...v1.13.2) (2025-12-24)
### [1.13.1](http://124.126.16.154:8888/singularity/hdk-pay/compare/v1.13.0...v1.13.1) (2025-12-24)
### 🐛 Bug Fixes | Bug 修复
* **ProductRepo:** 将isset检查改为!empty检查以确保数据有效性 ([7ade038](http://124.126.16.154:8888/singularity/hdk-pay/commit/7ade038f0fb1c6a857428d75667ccb2289d392fd))
## [1.13.0](http://124.126.16.154:8888/singularity/hdk-pay/compare/v1.12.4...v1.13.0) (2025-12-02)
### ✨ Features | 新功能
* **发票:** 为发送发票接口添加可选邮箱参数 ([19e9501](http://124.126.16.154:8888/singularity/hdk-pay/commit/19e95016fae1230cce88b3ead5c9ae2474bfdafc))
### [1.12.4](http://124.126.16.154:8888/singularity/hdk-pay/compare/v1.12.3...v1.12.4) (2025-12-02)
### 🐛 Bug Fixes | Bug 修复
* **invoice:** 修正发票金额计算逻辑 ([1d1cdd7](http://124.126.16.154:8888/singularity/hdk-pay/commit/1d1cdd7829942984f4dcdd16e7e0d1ba9ac9d1ce))
### [1.12.3](http://124.126.16.154:8888/singularity/hdk-pay/compare/v1.12.2...v1.12.3) (2025-12-01)
### [1.12.2](http://124.126.16.154:8888/singularity/hdk-pay/compare/v1.12.1...v1.12.2) (2025-12-01)
### [1.12.1](http://124.126.16.154:8888/singularity/hdk-pay/compare/v1.12.0...v1.12.1) (2025-12-01)
### 🐛 Bug Fixes | Bug 修复
* **InvoiceRepo:** 修复InvoiceProduct构造函数缺少prices参数的问题 ([46da805](http://124.126.16.154:8888/singularity/hdk-pay/commit/46da805cb41cdb777dbd9627a53f431e204904e2))
### ✨ Features | 新功能
* **Invoice:** 添加价格和货币信息到发票信息 ([28b81f4](http://124.126.16.154:8888/singularity/hdk-pay/commit/28b81f427e7ca618b0b1d561d83e107dcbba3c9c))
## [1.12.0](http://124.126.16.154:8888/singularity/hdk-pay/compare/v1.11.1...v1.12.0) (2025-11-28)
### 👷 Continuous Integration | CI 配置
* 添加测试相关的CI脚本 ([327066b](http://124.126.16.154:8888/singularity/hdk-pay/commit/327066b1466468ca76141e3b6c47183c5edbcb63))
### ♻️ Code Refactoring | 代码重构
* 适配项目目录结构从 app/ 改为 src/ ([6bc4234](http://124.126.16.154:8888/singularity/hdk-pay/commit/6bc423417cfa951073e993169c394063818ddd3d))
### ✨ Features | 新功能
* 添加 run-in-docker.sh 脚本用于在容器中运行命令 ([cb938d6](http://124.126.16.154:8888/singularity/hdk-pay/commit/cb938d61302e64119d67313073804a8f1c388352))
* **账户:** 添加邮箱管理功能并重构账户仓库 ([cae728b](http://124.126.16.154:8888/singularity/hdk-pay/commit/cae728b392e4ef14b70a3872f3ed6166995e57e5))
### [1.11.1](http://124.126.16.154:8888/singularity/hdk-pay/compare/v1.11.0...v1.11.1) (2025-11-27) ### [1.11.1](http://124.126.16.154:8888/singularity/hdk-pay/compare/v1.11.0...v1.11.1) (2025-11-27)
## [1.11.0](http://124.126.16.154:8888/singularity/hdk-pay/compare/v1.10.0...v1.11.0) (2025-11-27) ## [1.11.0](http://124.126.16.154:8888/singularity/hdk-pay/compare/v1.10.0...v1.11.0) (2025-11-27)

View File

@@ -45,7 +45,8 @@
"sort-packages": true, "sort-packages": true,
"allow-plugins": { "allow-plugins": {
"pestphp/pest-plugin": true "pestphp/pest-plugin": true
} },
"secure-http": false
}, },
"scripts": { "scripts": {
"post-root-package-install": [ "post-root-package-install": [
@@ -57,17 +58,17 @@
"APP_STATUS=false pest --coroutine --prepend=tests/bootstrap.php --colors=always $1" "APP_STATUS=false pest --coroutine --prepend=tests/bootstrap.php --colors=always $1"
], ],
"cs-fix": "php-cs-fixer fix $1", "cs-fix": "php-cs-fixer fix $1",
"analyse": "phpstan analyse --memory-limit 300M -l 0 -c phpstan.neon ./app ./config" "analyse": "phpstan analyse --memory-limit 300M -l 0 -c phpstan.neon ./src ./config"
}, },
"repositories": { "repositories": {
"nest": { "satis": {
"type": "composer", "type": "composer",
"url": "https://nest.doylee.cn/api/packages/HDK/composer" "url": "https://satis.luxcreo.cn/"
}, },
"packagist": { "packagist": {
"type": "composer", "type": "composer",
"url": "https://mirrors.aliyun.com/composer/" "url": "https://mirrors.aliyun.com/composer/"
} }
}, },
"version": "1.11.1" "version": "1.13.2"
} }

388
composer.lock generated
View File

@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "ffec1d2a9b50d8653479b5adb06fb851", "content-hash": "a61c0ead9bd06d776dbf954702087089",
"packages": [ "packages": [
{ {
"name": "carbonphp/carbon-doctrine-types", "name": "carbonphp/carbon-doctrine-types",
@@ -83,16 +83,16 @@
}, },
{ {
"name": "composer/ca-bundle", "name": "composer/ca-bundle",
"version": "1.5.7", "version": "1.5.10",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/composer/ca-bundle.git", "url": "https://github.com/composer/ca-bundle.git",
"reference": "d665d22c417056996c59019579f1967dfe5c1e82" "reference": "961a5e4056dd2e4a2eedcac7576075947c28bf63"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/composer/ca-bundle/zipball/d665d22c417056996c59019579f1967dfe5c1e82", "url": "https://api.github.com/repos/composer/ca-bundle/zipball/961a5e4056dd2e4a2eedcac7576075947c28bf63",
"reference": "d665d22c417056996c59019579f1967dfe5c1e82", "reference": "961a5e4056dd2e4a2eedcac7576075947c28bf63",
"shasum": "", "shasum": "",
"mirrors": [ "mirrors": [
{ {
@@ -145,7 +145,7 @@
"support": { "support": {
"irc": "irc://irc.freenode.org/composer", "irc": "irc://irc.freenode.org/composer",
"issues": "https://github.com/composer/ca-bundle/issues", "issues": "https://github.com/composer/ca-bundle/issues",
"source": "https://github.com/composer/ca-bundle/tree/1.5.7" "source": "https://github.com/composer/ca-bundle/tree/1.5.10"
}, },
"funding": [ "funding": [
{ {
@@ -155,13 +155,9 @@
{ {
"url": "https://github.com/composer", "url": "https://github.com/composer",
"type": "github" "type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/composer/composer",
"type": "tidelift"
} }
], ],
"time": "2025-05-26T15:08:54+00:00" "time": "2025-12-08T15:06:51+00:00"
}, },
{ {
"name": "composer/class-map-generator", "name": "composer/class-map-generator",
@@ -1680,16 +1676,16 @@
}, },
{ {
"name": "hyperf/collection", "name": "hyperf/collection",
"version": "v3.1.63", "version": "v3.1.64",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/hyperf/collection.git", "url": "https://github.com/hyperf/collection.git",
"reference": "1e4f7d9ee01a83a54f9e095a82bd556805a67f5c" "reference": "8f43bd741ffae01208401791687830c6df32da83"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/hyperf/collection/zipball/1e4f7d9ee01a83a54f9e095a82bd556805a67f5c", "url": "https://api.github.com/repos/hyperf/collection/zipball/8f43bd741ffae01208401791687830c6df32da83",
"reference": "1e4f7d9ee01a83a54f9e095a82bd556805a67f5c", "reference": "8f43bd741ffae01208401791687830c6df32da83",
"shasum": "", "shasum": "",
"mirrors": [ "mirrors": [
{ {
@@ -1747,7 +1743,7 @@
"type": "open_collective" "type": "open_collective"
} }
], ],
"time": "2025-10-30T01:44:44+00:00" "time": "2025-11-06T07:07:43+00:00"
}, },
{ {
"name": "hyperf/conditionable", "name": "hyperf/conditionable",
@@ -2172,16 +2168,16 @@
}, },
{ {
"name": "hyperf/coroutine", "name": "hyperf/coroutine",
"version": "v3.1.63", "version": "v3.1.65",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/hyperf/coroutine.git", "url": "https://github.com/hyperf/coroutine.git",
"reference": "6eef27161d44c7c2ac353591b7428a100aa87797" "reference": "060c276febdb9a079b54f5ca737b972ee6013d09"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/hyperf/coroutine/zipball/6eef27161d44c7c2ac353591b7428a100aa87797", "url": "https://api.github.com/repos/hyperf/coroutine/zipball/060c276febdb9a079b54f5ca737b972ee6013d09",
"reference": "6eef27161d44c7c2ac353591b7428a100aa87797", "reference": "060c276febdb9a079b54f5ca737b972ee6013d09",
"shasum": "", "shasum": "",
"mirrors": [ "mirrors": [
{ {
@@ -2238,20 +2234,20 @@
"type": "open_collective" "type": "open_collective"
} }
], ],
"time": "2025-10-30T01:44:44+00:00" "time": "2025-12-02T14:30:56+00:00"
}, },
{ {
"name": "hyperf/di", "name": "hyperf/di",
"version": "v3.1.63", "version": "v3.1.65",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/hyperf/di.git", "url": "https://github.com/hyperf/di.git",
"reference": "4020913f3f9497bf5067f280374186b10ce8c2b6" "reference": "1bfc22ed3f6d1328d10d902ff0e5fdc11ba9faa3"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/hyperf/di/zipball/4020913f3f9497bf5067f280374186b10ce8c2b6", "url": "https://api.github.com/repos/hyperf/di/zipball/1bfc22ed3f6d1328d10d902ff0e5fdc11ba9faa3",
"reference": "4020913f3f9497bf5067f280374186b10ce8c2b6", "reference": "1bfc22ed3f6d1328d10d902ff0e5fdc11ba9faa3",
"shasum": "", "shasum": "",
"mirrors": [ "mirrors": [
{ {
@@ -2325,7 +2321,7 @@
"type": "open_collective" "type": "open_collective"
} }
], ],
"time": "2025-10-30T01:44:44+00:00" "time": "2025-12-01T03:37:59+00:00"
}, },
{ {
"name": "hyperf/dispatcher", "name": "hyperf/dispatcher",
@@ -2800,16 +2796,16 @@
}, },
{ {
"name": "hyperf/guzzle", "name": "hyperf/guzzle",
"version": "v3.1.63", "version": "v3.1.65",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/hyperf/guzzle.git", "url": "https://github.com/hyperf/guzzle.git",
"reference": "2fb09b4fd5bb77dea06f5282ce9d0035a6555c80" "reference": "4e4cd238be3ef8980164fea5b79eec7d1e1953b5"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/hyperf/guzzle/zipball/2fb09b4fd5bb77dea06f5282ce9d0035a6555c80", "url": "https://api.github.com/repos/hyperf/guzzle/zipball/4e4cd238be3ef8980164fea5b79eec7d1e1953b5",
"reference": "2fb09b4fd5bb77dea06f5282ce9d0035a6555c80", "reference": "4e4cd238be3ef8980164fea5b79eec7d1e1953b5",
"shasum": "", "shasum": "",
"mirrors": [ "mirrors": [
{ {
@@ -2858,7 +2854,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/hyperf/guzzle/issues", "issues": "https://github.com/hyperf/guzzle/issues",
"source": "https://github.com/hyperf/guzzle/tree/v3.1.63" "source": "https://github.com/hyperf/guzzle/tree/v3.1.65"
}, },
"funding": [ "funding": [
{ {
@@ -2870,20 +2866,20 @@
"type": "open_collective" "type": "open_collective"
} }
], ],
"time": "2025-10-30T01:44:44+00:00" "time": "2025-12-04T02:38:56+00:00"
}, },
{ {
"name": "hyperf/http-message", "name": "hyperf/http-message",
"version": "v3.1.63", "version": "v3.1.65",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/hyperf/http-message.git", "url": "https://github.com/hyperf/http-message.git",
"reference": "9309ed429e5bee82cce8c05809e66137ef1ead33" "reference": "74fbf1669992c2476bea4b4aca91e528159066b5"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/hyperf/http-message/zipball/9309ed429e5bee82cce8c05809e66137ef1ead33", "url": "https://api.github.com/repos/hyperf/http-message/zipball/74fbf1669992c2476bea4b4aca91e528159066b5",
"reference": "9309ed429e5bee82cce8c05809e66137ef1ead33", "reference": "74fbf1669992c2476bea4b4aca91e528159066b5",
"shasum": "", "shasum": "",
"mirrors": [ "mirrors": [
{ {
@@ -2934,7 +2930,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/hyperf/http-message/issues", "issues": "https://github.com/hyperf/http-message/issues",
"source": "https://github.com/hyperf/http-message/tree/v3.1.63" "source": "https://github.com/hyperf/http-message/tree/v3.1.65"
}, },
"funding": [ "funding": [
{ {
@@ -2946,20 +2942,20 @@
"type": "open_collective" "type": "open_collective"
} }
], ],
"time": "2025-10-30T01:44:44+00:00" "time": "2025-12-01T03:37:59+00:00"
}, },
{ {
"name": "hyperf/http-server", "name": "hyperf/http-server",
"version": "v3.1.63", "version": "v3.1.65",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/hyperf/http-server.git", "url": "https://github.com/hyperf/http-server.git",
"reference": "027477410b08e0a22d4c82878931c337f8967b45" "reference": "95936e21e47a121df35d02296448b2439f9997f0"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/hyperf/http-server/zipball/027477410b08e0a22d4c82878931c337f8967b45", "url": "https://api.github.com/repos/hyperf/http-server/zipball/95936e21e47a121df35d02296448b2439f9997f0",
"reference": "027477410b08e0a22d4c82878931c337f8967b45", "reference": "95936e21e47a121df35d02296448b2439f9997f0",
"shasum": "", "shasum": "",
"mirrors": [ "mirrors": [
{ {
@@ -3037,7 +3033,7 @@
"type": "open_collective" "type": "open_collective"
} }
], ],
"time": "2025-10-30T01:44:44+00:00" "time": "2025-12-01T03:37:59+00:00"
}, },
{ {
"name": "hyperf/logger", "name": "hyperf/logger",
@@ -3178,16 +3174,16 @@
}, },
{ {
"name": "hyperf/paginator", "name": "hyperf/paginator",
"version": "v3.1.63", "version": "v3.1.65",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/hyperf/paginator.git", "url": "https://github.com/hyperf/paginator.git",
"reference": "fe3673c61f4ab1ea180f05fe4a19dd300c80e372" "reference": "4694fb8650bd7fba91bd259f57d8189e6ac2d258"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/hyperf/paginator/zipball/fe3673c61f4ab1ea180f05fe4a19dd300c80e372", "url": "https://api.github.com/repos/hyperf/paginator/zipball/4694fb8650bd7fba91bd259f57d8189e6ac2d258",
"reference": "fe3673c61f4ab1ea180f05fe4a19dd300c80e372", "reference": "4694fb8650bd7fba91bd259f57d8189e6ac2d258",
"shasum": "", "shasum": "",
"mirrors": [ "mirrors": [
{ {
@@ -3250,7 +3246,7 @@
"type": "open_collective" "type": "open_collective"
} }
], ],
"time": "2025-10-30T01:44:44+00:00" "time": "2025-12-01T03:37:59+00:00"
}, },
{ {
"name": "hyperf/pipeline", "name": "hyperf/pipeline",
@@ -3476,16 +3472,16 @@
}, },
{ {
"name": "hyperf/resource", "name": "hyperf/resource",
"version": "v3.1.63", "version": "v3.1.65",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/hyperf/resource.git", "url": "https://github.com/hyperf/resource.git",
"reference": "413b02d57574d2947b0d3af4b3a5bd5df8bf91d8" "reference": "f8b8ad58f74140551a950c22de7a8dcb18c5c591"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/hyperf/resource/zipball/413b02d57574d2947b0d3af4b3a5bd5df8bf91d8", "url": "https://api.github.com/repos/hyperf/resource/zipball/f8b8ad58f74140551a950c22de7a8dcb18c5c591",
"reference": "413b02d57574d2947b0d3af4b3a5bd5df8bf91d8", "reference": "f8b8ad58f74140551a950c22de7a8dcb18c5c591",
"shasum": "", "shasum": "",
"mirrors": [ "mirrors": [
{ {
@@ -3550,7 +3546,7 @@
"type": "open_collective" "type": "open_collective"
} }
], ],
"time": "2025-10-30T01:44:44+00:00" "time": "2025-12-01T03:37:59+00:00"
}, },
{ {
"name": "hyperf/serializer", "name": "hyperf/serializer",
@@ -3774,16 +3770,16 @@
}, },
{ {
"name": "hyperf/stringable", "name": "hyperf/stringable",
"version": "v3.1.63", "version": "v3.1.65",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/hyperf/stringable.git", "url": "https://github.com/hyperf/stringable.git",
"reference": "aa20da362306cdc64ed7ee2cc7c2251642631557" "reference": "31a468649f7184c18f9dcdfe99fd28757a5bbb75"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/hyperf/stringable/zipball/aa20da362306cdc64ed7ee2cc7c2251642631557", "url": "https://api.github.com/repos/hyperf/stringable/zipball/31a468649f7184c18f9dcdfe99fd28757a5bbb75",
"reference": "aa20da362306cdc64ed7ee2cc7c2251642631557", "reference": "31a468649f7184c18f9dcdfe99fd28757a5bbb75",
"shasum": "", "shasum": "",
"mirrors": [ "mirrors": [
{ {
@@ -3848,7 +3844,7 @@
"type": "open_collective" "type": "open_collective"
} }
], ],
"time": "2025-10-30T01:44:44+00:00" "time": "2025-12-04T03:05:16+00:00"
}, },
{ {
"name": "hyperf/support", "name": "hyperf/support",
@@ -4116,16 +4112,16 @@
}, },
{ {
"name": "justinrainbow/json-schema", "name": "justinrainbow/json-schema",
"version": "6.6.1", "version": "6.6.3",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/jsonrainbow/json-schema.git", "url": "https://github.com/jsonrainbow/json-schema.git",
"reference": "fd8e5c6b1badb998844ad34ce0abcd71a0aeb396" "reference": "134e98916fa2f663afa623970af345cd788e8967"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/jsonrainbow/json-schema/zipball/fd8e5c6b1badb998844ad34ce0abcd71a0aeb396", "url": "https://api.github.com/repos/jsonrainbow/json-schema/zipball/134e98916fa2f663afa623970af345cd788e8967",
"reference": "fd8e5c6b1badb998844ad34ce0abcd71a0aeb396", "reference": "134e98916fa2f663afa623970af345cd788e8967",
"shasum": "", "shasum": "",
"mirrors": [ "mirrors": [
{ {
@@ -4136,7 +4132,7 @@
}, },
"require": { "require": {
"ext-json": "*", "ext-json": "*",
"marc-mabe/php-enum": "^4.0", "marc-mabe/php-enum": "^4.4",
"php": "^7.2 || ^8.0" "php": "^7.2 || ^8.0"
}, },
"require-dev": { "require-dev": {
@@ -4191,9 +4187,9 @@
], ],
"support": { "support": {
"issues": "https://github.com/jsonrainbow/json-schema/issues", "issues": "https://github.com/jsonrainbow/json-schema/issues",
"source": "https://github.com/jsonrainbow/json-schema/tree/6.6.1" "source": "https://github.com/jsonrainbow/json-schema/tree/6.6.3"
}, },
"time": "2025-11-07T18:30:29+00:00" "time": "2025-12-02T10:21:33+00:00"
}, },
{ {
"name": "laminas/laminas-mime", "name": "laminas/laminas-mime",
@@ -4734,16 +4730,16 @@
}, },
{ {
"name": "nesbot/carbon", "name": "nesbot/carbon",
"version": "2.73.0", "version": "3.9.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/CarbonPHP/carbon.git", "url": "https://github.com/CarbonPHP/carbon.git",
"reference": "9228ce90e1035ff2f0db84b40ec2e023ed802075" "reference": "ced71f79398ece168e24f7f7710462f462310d4d"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/9228ce90e1035ff2f0db84b40ec2e023ed802075", "url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/ced71f79398ece168e24f7f7710462f462310d4d",
"reference": "9228ce90e1035ff2f0db84b40ec2e023ed802075", "reference": "ced71f79398ece168e24f7f7710462f462310d4d",
"shasum": "", "shasum": "",
"mirrors": [ "mirrors": [
{ {
@@ -4753,29 +4749,28 @@
] ]
}, },
"require": { "require": {
"carbonphp/carbon-doctrine-types": "*", "carbonphp/carbon-doctrine-types": "<100.0",
"ext-json": "*", "ext-json": "*",
"php": "^7.1.8 || ^8.0", "php": "^8.1",
"psr/clock": "^1.0", "psr/clock": "^1.0",
"symfony/clock": "^6.3 || ^7.0",
"symfony/polyfill-mbstring": "^1.0", "symfony/polyfill-mbstring": "^1.0",
"symfony/polyfill-php80": "^1.16", "symfony/translation": "^4.4.18 || ^5.2.1|| ^6.0 || ^7.0"
"symfony/translation": "^3.4 || ^4.0 || ^5.0 || ^6.0"
}, },
"provide": { "provide": {
"psr/clock-implementation": "1.0" "psr/clock-implementation": "1.0"
}, },
"require-dev": { "require-dev": {
"doctrine/dbal": "^2.0 || ^3.1.4 || ^4.0", "doctrine/dbal": "^3.6.3 || ^4.0",
"doctrine/orm": "^2.7 || ^3.0", "doctrine/orm": "^2.15.2 || ^3.0",
"friendsofphp/php-cs-fixer": "^3.0", "friendsofphp/php-cs-fixer": "^3.57.2",
"kylekatarnls/multi-tester": "^2.0", "kylekatarnls/multi-tester": "^2.5.3",
"ondrejmirtes/better-reflection": "<6", "ondrejmirtes/better-reflection": "^6.25.0.4",
"phpmd/phpmd": "^2.9", "phpmd/phpmd": "^2.15.0",
"phpstan/extension-installer": "^1.0", "phpstan/extension-installer": "^1.3.1",
"phpstan/phpstan": "^0.12.99 || ^1.7.14", "phpstan/phpstan": "^1.11.2",
"phpunit/php-file-iterator": "^2.0.5 || ^3.0.6", "phpunit/phpunit": "^10.5.20",
"phpunit/phpunit": "^7.5.20 || ^8.5.26 || ^9.5.20", "squizlabs/php_codesniffer": "^3.9.0"
"squizlabs/php_codesniffer": "^3.4"
}, },
"bin": [ "bin": [
"bin/carbon" "bin/carbon"
@@ -4826,8 +4821,8 @@
], ],
"support": { "support": {
"docs": "https://carbon.nesbot.com/docs", "docs": "https://carbon.nesbot.com/docs",
"issues": "https://github.com/briannesbitt/Carbon/issues", "issues": "https://github.com/CarbonPHP/carbon/issues",
"source": "https://github.com/briannesbitt/Carbon" "source": "https://github.com/CarbonPHP/carbon"
}, },
"funding": [ "funding": [
{ {
@@ -4843,7 +4838,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2025-01-08T20:10:23+00:00" "time": "2025-05-01T19:51:51+00:00"
}, },
{ {
"name": "nikic/fast-route", "name": "nikic/fast-route",
@@ -4903,16 +4898,16 @@
}, },
{ {
"name": "nikic/php-parser", "name": "nikic/php-parser",
"version": "v4.19.4", "version": "v4.19.5",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/nikic/PHP-Parser.git", "url": "https://github.com/nikic/PHP-Parser.git",
"reference": "715f4d25e225bc47b293a8b997fe6ce99bf987d2" "reference": "51bd93cc741b7fc3d63d20b6bdcd99fdaa359837"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/715f4d25e225bc47b293a8b997fe6ce99bf987d2", "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/51bd93cc741b7fc3d63d20b6bdcd99fdaa359837",
"reference": "715f4d25e225bc47b293a8b997fe6ce99bf987d2", "reference": "51bd93cc741b7fc3d63d20b6bdcd99fdaa359837",
"shasum": "", "shasum": "",
"mirrors": [ "mirrors": [
{ {
@@ -4933,11 +4928,6 @@
"bin/php-parse" "bin/php-parse"
], ],
"type": "library", "type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.9-dev"
}
},
"autoload": { "autoload": {
"psr-4": { "psr-4": {
"PhpParser\\": "lib/PhpParser" "PhpParser\\": "lib/PhpParser"
@@ -4959,9 +4949,9 @@
], ],
"support": { "support": {
"issues": "https://github.com/nikic/PHP-Parser/issues", "issues": "https://github.com/nikic/PHP-Parser/issues",
"source": "https://github.com/nikic/PHP-Parser/tree/v4.19.4" "source": "https://github.com/nikic/PHP-Parser/tree/v4.19.5"
}, },
"time": "2024-09-29T15:01:53+00:00" "time": "2025-12-06T11:45:25+00:00"
}, },
{ {
"name": "php-di/phpdoc-reader", "name": "php-di/phpdoc-reader",
@@ -6128,16 +6118,11 @@
}, },
{ {
"name": "singularity/hdk-core", "name": "singularity/hdk-core",
"version": "1.0.2", "version": "1.0.3",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://nest.doylee.cn/HDK/hdk-core", "url": "http://124.126.16.154:8888/singularity/HyperfDevelopmentKitCore.git",
"reference": "1.0.2" "reference": "c6464880c464306b39249ac04976a8945cfc227c"
},
"dist": {
"type": "zip",
"url": "https://nest.doylee.cn/api/packages/HDK/composer/files/singularity%2Fhdk-core/1.0.2/singularity-hdk-core.1.0.2.zip",
"shasum": "90a71e0e0040dae42fbd738c3b73c757ff6499c4"
}, },
"require": { "require": {
"composer/composer": ">=2.0", "composer/composer": ">=2.0",
@@ -6160,7 +6145,7 @@
"lmc/http-constants": "^1.2.0", "lmc/http-constants": "^1.2.0",
"myclabs/php-enum": "^1.8.4", "myclabs/php-enum": "^1.8.4",
"php": ">=8.1", "php": ">=8.1",
"roave/dont": "^1.6.0", "roave/dont": "*",
"symfony/http-foundation": "^6.4", "symfony/http-foundation": "^6.4",
"symfony/polyfill-php81": "^1.28", "symfony/polyfill-php81": "^1.28",
"symfony/polyfill-php82": "^1.28", "symfony/polyfill-php82": "^1.28",
@@ -6220,6 +6205,38 @@
"Singularity\\HDK\\Test\\Core\\": "tests/" "Singularity\\HDK\\Test\\Core\\": "tests/"
} }
}, },
"archive": {
"exclude": [
".idea",
"tests",
"scripts",
"Dockerfile",
".gitignore",
".php-cs-fixer.*",
".phpunit.result.cache",
"phpstan.dist.neon",
"phpunit.xml"
]
},
"scripts": {
"post-root-package-install": [],
"test": [
"rm -rf runtime",
"pest --coroutine --prepend tests/bootstrap.php --colors=always"
],
"cs-fix": [
"vendor/bin/php-cs-fixer fix $1 --rules=@PSR12 --allow-risky=yes"
],
"analyse": [
"vendor/bin/phpstan analyse $1"
],
"ci": [
"@analyse publish/ src/ tests/",
"@cs-fix",
"@test",
"echo CI Success"
]
},
"license": [ "license": [
"MIT" "MIT"
], ],
@@ -6230,7 +6247,7 @@
} }
], ],
"description": "Common Hyperf Development Kit", "description": "Common Hyperf Development Kit",
"time": "2025-09-26T16:56:07+08:00" "time": "2025-11-25T09:24:21+00:00"
}, },
{ {
"name": "swow/psr7-plus", "name": "swow/psr7-plus",
@@ -6288,6 +6305,90 @@
}, },
"time": "2023-06-15T09:18:11+00:00" "time": "2023-06-15T09:18:11+00:00"
}, },
{
"name": "symfony/clock",
"version": "v7.4.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/clock.git",
"reference": "9169f24776edde469914c1e7a1442a50f7a4e110"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/clock/zipball/9169f24776edde469914c1e7a1442a50f7a4e110",
"reference": "9169f24776edde469914c1e7a1442a50f7a4e110",
"shasum": "",
"mirrors": [
{
"url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
"preferred": true
}
]
},
"require": {
"php": ">=8.2",
"psr/clock": "^1.0",
"symfony/polyfill-php83": "^1.28"
},
"provide": {
"psr/clock-implementation": "1.0"
},
"type": "library",
"autoload": {
"files": [
"Resources/now.php"
],
"psr-4": {
"Symfony\\Component\\Clock\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Decouples applications from the system clock",
"homepage": "https://symfony.com",
"keywords": [
"clock",
"psr20",
"time"
],
"support": {
"source": "https://github.com/symfony/clock/tree/v7.4.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://github.com/nicolas-grekas",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2025-11-12T15:39:26+00:00"
},
{ {
"name": "symfony/console", "name": "symfony/console",
"version": "v7.3.6", "version": "v7.3.6",
@@ -7799,16 +7900,16 @@
}, },
{ {
"name": "symfony/translation", "name": "symfony/translation",
"version": "v6.4.23", "version": "v7.2.9",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/translation.git", "url": "https://github.com/symfony/translation.git",
"reference": "de8afa521e04a5220e9e58a1dc99971ab7cac643" "reference": "00b927b4948d49afbf5013411c0a91a1cea8b087"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/translation/zipball/de8afa521e04a5220e9e58a1dc99971ab7cac643", "url": "https://api.github.com/repos/symfony/translation/zipball/00b927b4948d49afbf5013411c0a91a1cea8b087",
"reference": "de8afa521e04a5220e9e58a1dc99971ab7cac643", "reference": "00b927b4948d49afbf5013411c0a91a1cea8b087",
"shasum": "", "shasum": "",
"mirrors": [ "mirrors": [
{ {
@@ -7818,20 +7919,20 @@
] ]
}, },
"require": { "require": {
"php": ">=8.1", "php": ">=8.2",
"symfony/deprecation-contracts": "^2.5|^3", "symfony/deprecation-contracts": "^2.5|^3",
"symfony/polyfill-mbstring": "~1.0", "symfony/polyfill-mbstring": "~1.0",
"symfony/translation-contracts": "^2.5|^3.0" "symfony/translation-contracts": "^2.5|^3.0"
}, },
"conflict": { "conflict": {
"symfony/config": "<5.4", "symfony/config": "<6.4",
"symfony/console": "<5.4", "symfony/console": "<6.4",
"symfony/dependency-injection": "<5.4", "symfony/dependency-injection": "<6.4",
"symfony/http-client-contracts": "<2.5", "symfony/http-client-contracts": "<2.5",
"symfony/http-kernel": "<5.4", "symfony/http-kernel": "<6.4",
"symfony/service-contracts": "<2.5", "symfony/service-contracts": "<2.5",
"symfony/twig-bundle": "<5.4", "symfony/twig-bundle": "<6.4",
"symfony/yaml": "<5.4" "symfony/yaml": "<6.4"
}, },
"provide": { "provide": {
"symfony/translation-implementation": "2.3|3.0" "symfony/translation-implementation": "2.3|3.0"
@@ -7839,17 +7940,17 @@
"require-dev": { "require-dev": {
"nikic/php-parser": "^4.18|^5.0", "nikic/php-parser": "^4.18|^5.0",
"psr/log": "^1|^2|^3", "psr/log": "^1|^2|^3",
"symfony/config": "^5.4|^6.0|^7.0", "symfony/config": "^6.4|^7.0",
"symfony/console": "^5.4|^6.0|^7.0", "symfony/console": "^6.4|^7.0",
"symfony/dependency-injection": "^5.4|^6.0|^7.0", "symfony/dependency-injection": "^6.4|^7.0",
"symfony/finder": "^5.4|^6.0|^7.0", "symfony/finder": "^6.4|^7.0",
"symfony/http-client-contracts": "^2.5|^3.0", "symfony/http-client-contracts": "^2.5|^3.0",
"symfony/http-kernel": "^5.4|^6.0|^7.0", "symfony/http-kernel": "^6.4|^7.0",
"symfony/intl": "^5.4|^6.0|^7.0", "symfony/intl": "^6.4|^7.0",
"symfony/polyfill-intl-icu": "^1.21", "symfony/polyfill-intl-icu": "^1.21",
"symfony/routing": "^5.4|^6.0|^7.0", "symfony/routing": "^6.4|^7.0",
"symfony/service-contracts": "^2.5|^3", "symfony/service-contracts": "^2.5|^3",
"symfony/yaml": "^5.4|^6.0|^7.0" "symfony/yaml": "^6.4|^7.0"
}, },
"type": "library", "type": "library",
"autoload": { "autoload": {
@@ -7880,7 +7981,7 @@
"description": "Provides tools to internationalize your application", "description": "Provides tools to internationalize your application",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"support": { "support": {
"source": "https://github.com/symfony/translation/tree/v6.4.23" "source": "https://github.com/symfony/translation/tree/v7.2.9"
}, },
"funding": [ "funding": [
{ {
@@ -7891,12 +7992,16 @@
"url": "https://github.com/fabpot", "url": "https://github.com/fabpot",
"type": "github" "type": "github"
}, },
{
"url": "https://github.com/nicolas-grekas",
"type": "github"
},
{ {
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2025-06-26T21:24:02+00:00" "time": "2025-07-30T17:31:35+00:00"
}, },
{ {
"name": "symfony/translation-contracts", "name": "symfony/translation-contracts",
@@ -8579,6 +8684,7 @@
"type": "github" "type": "github"
} }
], ],
"abandoned": true,
"time": "2024-11-28T08:49:14+00:00" "time": "2024-11-28T08:49:14+00:00"
}, },
{ {
@@ -9440,16 +9546,16 @@
}, },
{ {
"name": "phpdocumentor/reflection-docblock", "name": "phpdocumentor/reflection-docblock",
"version": "5.6.4", "version": "5.6.5",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
"reference": "90a04bcbf03784066f16038e87e23a0a83cee3c2" "reference": "90614c73d3800e187615e2dd236ad0e2a01bf761"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/90a04bcbf03784066f16038e87e23a0a83cee3c2", "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/90614c73d3800e187615e2dd236ad0e2a01bf761",
"reference": "90a04bcbf03784066f16038e87e23a0a83cee3c2", "reference": "90614c73d3800e187615e2dd236ad0e2a01bf761",
"shasum": "", "shasum": "",
"mirrors": [ "mirrors": [
{ {
@@ -9504,9 +9610,9 @@
"description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
"support": { "support": {
"issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues",
"source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.6.4" "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.6.5"
}, },
"time": "2025-11-17T21:13:10+00:00" "time": "2025-11-27T19:50:05+00:00"
}, },
{ {
"name": "phpdocumentor/type-resolver", "name": "phpdocumentor/type-resolver",
@@ -11262,16 +11368,16 @@
}, },
{ {
"name": "webmozart/assert", "name": "webmozart/assert",
"version": "1.12.0", "version": "1.12.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/webmozarts/assert.git", "url": "https://github.com/webmozarts/assert.git",
"reference": "541057574806f942c94662b817a50f63f7345360" "reference": "9be6926d8b485f55b9229203f962b51ed377ba68"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/webmozarts/assert/zipball/541057574806f942c94662b817a50f63f7345360", "url": "https://api.github.com/repos/webmozarts/assert/zipball/9be6926d8b485f55b9229203f962b51ed377ba68",
"reference": "541057574806f942c94662b817a50f63f7345360", "reference": "9be6926d8b485f55b9229203f962b51ed377ba68",
"shasum": "", "shasum": "",
"mirrors": [ "mirrors": [
{ {
@@ -11320,9 +11426,9 @@
], ],
"support": { "support": {
"issues": "https://github.com/webmozarts/assert/issues", "issues": "https://github.com/webmozarts/assert/issues",
"source": "https://github.com/webmozarts/assert/tree/1.12.0" "source": "https://github.com/webmozarts/assert/tree/1.12.1"
}, },
"time": "2025-10-20T12:43:39+00:00" "time": "2025-10-29T15:56:20+00:00"
} }
], ],
"aliases": [], "aliases": [],

214
llm.txt Normal file
View File

@@ -0,0 +1,214 @@
# HDK-Pay 项目分析报告
## 1. 项目基本信息
- **项目名称**: HDK-Pay
- **项目类型**: PHP 支付平台 SDK
- **描述**: 用于连接 LuxPay 支付平台的 SDK
- **版本**: 1.11.1
- **PHP 版本要求**: >= 8.2
- **许可证**: MIT
## 2. 技术栈
### 2.1 核心依赖
- **PHP**: >= 8.2
- **Hyperf**: ~3.1.0 (框架)
- **Guzzle**: 用于 HTTP 请求
- **MoneyPHP**: 货币处理
- **Carbon**: 日期时间处理
- **BCMath 扩展**: 高精度数学计算
### 2.2 开发依赖
- **PHPUnit**: 单元测试
- **Pest**: 测试框架
- **PHPStan**: 静态代码分析
- **PHP-CS-Fixer**: 代码风格检查
## 3. 项目架构
### 3.1 目录结构
```
├── src/ # 源代码目录
│ ├── Application/ # 应用层
│ │ ├── Command/ # 命令行工具
│ │ └── Dto/ # 数据传输对象
│ ├── Domain/ # 领域层
│ │ ├── Account/ # 账户领域
│ │ ├── Invoice/ # 发票领域
│ │ ├── Product/ # 产品领域
│ │ └── Transaction/ # 交易领域
│ ├── Enum/ # 枚举类
│ ├── Infrastructure/ # 基础设施层
│ │ └── Repository/ # 仓库实现
│ ├── Resource/ # 资源层
│ ├── Sdk/ # SDK 接口
│ ├── Trait/ # 特质
│ └── ConfigProvider.php # 配置提供者
├── tests/ # 测试目录
├── publish/ # 发布配置
├── scripts/ # 脚本工具
├── composer.json # Composer 配置
└── README.md # 项目说明
```
### 3.2 架构模式
- **领域驱动设计 (DDD)**: 项目采用 DDD 架构,清晰划分了领域层、应用层和基础设施层
- **依赖倒置原则**: 通过接口定义依赖,实现了高层模块与低层模块的解耦
- **聚合根模式**: 核心领域对象如 TransactionRecord、Invoice 等都继承自 AggregateRoot
## 4. 核心功能模块
### 4.1 账户管理
- **账户余额**: 管理用户账户余额和积分
- **积分日志**: 记录积分的增减变动
- **积分类型**: 支持多种积分类型管理
### 4.2 交易管理
- **订单处理**: 支持创建、查询、更新订单
- **支付类型**: 支持卡片支付和积分支付
- **订单状态**: 完整的订单生命周期管理
- **交易记录**: 详细的交易记录和退款记录
### 4.3 发票管理
- **发票创建**: 支持创建发票
- **地址管理**: 支持常用地址管理
- **发票产品**: 管理发票中的产品信息
### 4.4 产品管理
- **充值产品**: 管理充值产品
- **产品类型**: 支持多种产品类型
- **充值效果**: 定义充值产品的效果
## 5. 主要领域模型
### 5.1 账户领域
- **AccountBalance**: 账户余额聚合根
- **PointsBalance**: 积分余额值对象
- **PointLog**: 积分日志聚合根
### 5.2 交易领域
- **TransactionRecord**: 交易记录聚合根
- **Item**: 交易项值对象
- **CardTransaction**: 卡片交易值对象
- **PointTransaction**: 积分交易值对象
### 5.3 发票领域
- **Invoice**: 发票聚合根
- **Address**: 地址值对象
- **InvoiceInfo**: 发票信息值对象
- **InvoiceProduct**: 发票产品值对象
### 5.4 产品领域
- **RechargeProduct**: 充值产品聚合根
- **ProductItem**: 产品项实体
- **RechargeEffect**: 充值效果值对象
## 6. RPC 服务
### 6.1 核心 RPC 类
- **OrderRpc**: 订单相关 RPC 服务
- **GoodsRpc**: 商品相关 RPC 服务
- **StripeRpc**: Stripe 支付相关 RPC 服务
- **WechatRpc**: 微信支付相关 RPC 服务
### 6.2 主要接口
- **create**: 创建订单
- **webhooksNotificationHandler**: 处理 Webhooks 通知
## 7. 配置说明
### 7.1 配置文件
- **payment.php**: 支付平台配置文件,包含基础 URI 等配置
### 7.2 配置项
- **http_request.pay.rpc_base_uri**: RPC 基础 URI通常为 https://pay.luxcreo.cn 或 https://test-pay.luxcreo.cn
- **payment.base_uri**: 支付平台基础 URI
## 8. 测试策略
### 8.1 测试类型
- **单元测试**: 测试单个类或方法
- **功能测试**: 测试完整的业务流程
- **集成测试**: 测试不同模块之间的交互
### 8.2 测试框架
- **PHPUnit**: 用于单元测试和功能测试
- **Pest**: 用于更简洁的测试编写
### 8.3 测试执行
```bash
vendor/bin/phpunit # 运行所有测试
composer test # 运行测试脚本
```
## 9. 开发流程
### 9.1 运行环境说明
项目通过本地运行 Docker 来创建运行容器,因此所有执行的终端命令都应该使用以下方式之一:
- 使用 `run-in-docker.sh` 脚本:`./run-in-docker.sh <command>`
- 使用 `scripts/test/` 下的脚本:`./scripts/test/<script-name>.sh`
### 9.2 安装依赖
```bash
./run-in-docker.sh composer install
```
### 9.3 代码风格检查
```bash
./run-in-docker.sh composer cs-fix
# 或使用专门的脚本
./scripts/test/code-style-check.sh
```
### 9.4 代码风格修复
```bash
./scripts/test/code-style-fix.sh
```
### 9.5 静态代码分析
```bash
./run-in-docker.sh composer analyse
# 或使用专门的脚本
./scripts/test/static-analysis.sh
```
### 9.6 运行测试
```bash
./run-in-docker.sh composer test
# 或使用专门的脚本
./scripts/test/all-tests.sh # 运行所有测试
./scripts/test/unit-tests.sh # 运行单元测试
```
### 9.7 CI 流程
```bash
./scripts/test/ci.sh
```
## 10. 发布与部署
### 10.1 发布配置
```bash
php bin/hyperf.php vendor:publish singularity/hdk-pay
```
### 10.2 部署方式
- 支持 Docker 部署
- 支持传统 PHP-FPM 部署
- 支持 Hyperf 协程部署
## 11. 总结
HDK-Pay 是一个基于 Hyperf 框架开发的支付平台 SDK采用领域驱动设计架构支持多种支付方式和交易类型。项目具有清晰的代码结构、完整的测试覆盖和良好的扩展性适合作为企业级支付解决方案的基础组件。
主要特点:
- 基于 DDD 架构,领域模型清晰
- 支持多种支付方式和交易类型
- 完整的订单生命周期管理
- 强大的发票管理功能
- 灵活的配置和扩展机制
- 完善的测试覆盖
- 支持多环境部署
该项目为企业提供了一个可靠、安全、易于扩展的支付解决方案,能够满足不同业务场景的支付需求。

5399
openapi.json Normal file

File diff suppressed because one or more lines are too long

26
run-in-docker.sh Executable file
View File

@@ -0,0 +1,26 @@
#!/usr/bin/env sh
# 使用与 docker-env.sh 一致的项目名
project=hdk-pay
# 检查容器是否在运行
if ! docker ps | grep -q "$project"; then
echo "容器 $project 未运行,正在启动..."
# 直接在后台启动容器,使用随机端口,并保持运行
docker run \
--pull always \
-d --name "$project" \
--privileged -u root \
-w "/srv/www" \
-v "$(pwd)":/srv/www \
-v ~/.ssh:/root/.ssh \
-p 9501 \
harbor.luxcreo.cn/library/hyperf:8.2-swoole tail -f /dev/null
# 显示分配的端口信息
echo "容器已启动,分配的端口:"
docker port "$project" 9501
fi
# 执行命令
docker exec -it "$project" sh -c "cd /srv/www && $*"

6
scripts/test/all-tests.sh Executable file
View File

@@ -0,0 +1,6 @@
#!/usr/bin/env sh
# 运行所有 Pest 测试脚本
# 运行所有 Pest 测试(包括数据库测试)
./run-in-docker.sh vendor/bin/pest --coroutine --prepend=tests/bootstrap.php --colors=always

6
scripts/test/ci.sh Executable file
View File

@@ -0,0 +1,6 @@
#!/usr/bin/env sh
# 完整的 CI 流程脚本
# 运行完整的 CI 流程
./run-in-docker.sh composer ci

View File

@@ -0,0 +1,6 @@
#!/usr/bin/env sh
# 代码风格检查脚本
# 检查代码风格,只使用配置文件中定义的规则
./run-in-docker.sh vendor/bin/php-cs-fixer check src/ --allow-risky=yes --config=.php-cs-fixer.dist.php

6
scripts/test/code-style-fix.sh Executable file
View File

@@ -0,0 +1,6 @@
#!/usr/bin/env sh
# 代码风格修复脚本
# 修复代码风格,只使用配置文件中定义的规则
./run-in-docker.sh vendor/bin/php-cs-fixer fix src/ tests/ --allow-risky=yes --config=.php-cs-fixer.dist.php

6
scripts/test/phpspec-tests.sh Executable file
View File

@@ -0,0 +1,6 @@
#!/usr/bin/env sh
# Phpspec BDD 测试脚本
# 运行所有 Phpspec 测试
./run-in-docker.sh vendor/bin/phpspec run

View File

@@ -0,0 +1,6 @@
#!/usr/bin/env sh
# 代码静态分析脚本
# 运行完整的代码静态分析
./run-in-docker.sh vendor/bin/phpstan analyse src/ tests/

6
scripts/test/unit-tests.sh Executable file
View File

@@ -0,0 +1,6 @@
#!/usr/bin/env sh
# 非数据库依赖的单元测试脚本
# 运行非数据库依赖的单元测试
./run-in-docker.sh vendor/bin/pest tests/Unit/ --exclude-group database --coroutine --prepend=tests/bootstrap.php --colors=always

View File

@@ -14,7 +14,7 @@ use Singularity\HDK\Pay\Domain\Invoice\Repository\InvoiceRepoInterface;
use Singularity\HDK\Pay\Domain\Product\Repository\ExchangeRepoInterface; use Singularity\HDK\Pay\Domain\Product\Repository\ExchangeRepoInterface;
use Singularity\HDK\Pay\Domain\Product\Repository\RechargeProductRepoInterface; use Singularity\HDK\Pay\Domain\Product\Repository\RechargeProductRepoInterface;
use Singularity\HDK\Pay\Domain\Transaction\Repository\OrderRepoInterface; use Singularity\HDK\Pay\Domain\Transaction\Repository\OrderRepoInterface;
use Singularity\HDK\Pay\Infrastructure\Repository\AccountBalanceRepo; use Singularity\HDK\Pay\Infrastructure\Repository\AccountRepo;
use Singularity\HDK\Pay\Infrastructure\Repository\FrequentAddressRepo; use Singularity\HDK\Pay\Infrastructure\Repository\FrequentAddressRepo;
use Singularity\HDK\Pay\Infrastructure\Repository\InvoiceProductRepo; use Singularity\HDK\Pay\Infrastructure\Repository\InvoiceProductRepo;
use Singularity\HDK\Pay\Infrastructure\Repository\InvoiceRepo; use Singularity\HDK\Pay\Infrastructure\Repository\InvoiceRepo;
@@ -40,7 +40,7 @@ class ConfigProvider
// Repo // Repo
// account // account
AccountRepoInterface::class => AccountBalanceRepo::class, AccountRepoInterface::class => AccountRepo::class,
PointLogRepoInterface::class => PointLogRepo::class, PointLogRepoInterface::class => PointLogRepo::class,
// product // product
@@ -78,4 +78,4 @@ class ConfigProvider
], ],
]; ];
} }
} }

View File

@@ -7,6 +7,7 @@
* Powered by PhpStorm * Powered by PhpStorm
* Created on 2025/8/17 * Created on 2025/8/17
*/ */
declare(strict_types=1); declare(strict_types=1);
namespace Singularity\HDK\Pay\Domain\Account\Repository; namespace Singularity\HDK\Pay\Domain\Account\Repository;
@@ -15,6 +16,7 @@ use Singularity\HDK\Pay\Application\Command\InitialAccountCmd;
use Singularity\HDK\Pay\Domain\Account\Aggregate\Account\AccountBalance; use Singularity\HDK\Pay\Domain\Account\Aggregate\Account\AccountBalance;
use Singularity\HDK\Pay\Domain\Account\Aggregate\Account\PointsBalance; use Singularity\HDK\Pay\Domain\Account\Aggregate\Account\PointsBalance;
use Singularity\HDK\Pay\Domain\Account\Enum\PointType; use Singularity\HDK\Pay\Domain\Account\Enum\PointType;
use Singularity\HDK\Pay\Domain\Account\ValueObject\Email;
interface AccountRepoInterface interface AccountRepoInterface
{ {
@@ -36,4 +38,21 @@ interface AccountRepoInterface
* @return void * @return void
*/ */
public function initial(InitialAccountCmd $cmd): void; public function initial(InitialAccountCmd $cmd): void;
}
/**
* 获取用户常用邮箱
*
* @param string $uid
* @return Email
*/
public function getEmail(string $uid): Email;
/**
* 更新用户常用邮箱
*
* @param string $uid
* @param Email $email
* @return void
*/
public function updateEmail(string $uid, Email $email): void;
}

View File

@@ -0,0 +1,38 @@
<?php
/**
* Email.php@Pay
*
* @author 李东云 <Dongyun.Li@LuxCreo.Ai>
* Powered by PhpStorm
* Created on 2025/11/28
*/
declare(strict_types=1);
namespace Singularity\HDK\Pay\Domain\Account\ValueObject;
use Singularity\HDK\Pay\Domain\ValueObject;
final class Email extends ValueObject
{
private string $email;
public function __construct(string $email)
{
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
throw new \InvalidArgumentException('Invalid email address: ' . $email);
}
$this->email = $email;
}
public function getValue(): string
{
return $this->email;
}
public function __toString(): string
{
return $this->email;
}
}

View File

@@ -7,11 +7,13 @@
* Powered by PhpStorm * Powered by PhpStorm
* Created on 2025/9/5 * Created on 2025/9/5
*/ */
declare(strict_types=1); declare(strict_types=1);
namespace Singularity\HDK\Pay\Domain\Invoice\Aggregate\Invoice; namespace Singularity\HDK\Pay\Domain\Invoice\Aggregate\Invoice;
use Carbon\Carbon; use Carbon\Carbon;
use Money\Money;
use Singularity\HDK\Pay\Domain\Invoice\Aggregate\Invoice\ValueObject\PointBalance; use Singularity\HDK\Pay\Domain\Invoice\Aggregate\Invoice\ValueObject\PointBalance;
final readonly class InvoiceInfo final readonly class InvoiceInfo
@@ -27,8 +29,25 @@ final readonly class InvoiceInfo
private Carbon $invoiceAt, private Carbon $invoiceAt,
private Carbon $designedAt, private Carbon $designedAt,
private string $patientName, private string $patientName,
private Money $price,
private string $currencySymbol,
) {} ) {}
public function getAmount(): float
{
return (float)bcdiv($this->price->getAmount(), '100', 2);
}
public function getCurrencyCode(): string
{
return $this->price->getCurrency()->getCode();
}
public function getCurrencySymbol(): string
{
return $this->currencySymbol;
}
public function getInvoiceNo(): string public function getInvoiceNo(): string
{ {
return $this->invoiceNo; return $this->invoiceNo;
@@ -78,4 +97,4 @@ final readonly class InvoiceInfo
{ {
return $this->patientName; return $this->patientName;
} }
} }

View File

@@ -1,4 +1,5 @@
<?php <?php
/** /**
* InvoiceRepoInterface.php@Pay * InvoiceRepoInterface.php@Pay
* *
@@ -33,14 +34,15 @@ interface InvoiceRepoInterface
/** /**
* @param string $invoiceNo * @param string $invoiceNo
* @param string|null $email
* @return void * @return void
* @throws GuzzleException * @throws GuzzleException
*/ */
public function send(string $invoiceNo): void; public function send(string $invoiceNo, ?string $email): void;
/** /**
* @param string $invoiceNo * @param string $invoiceNo
* @return InvoiceInfo * @return InvoiceInfo
*/ */
public function findOne(string $invoiceNo): InvoiceInfo; public function findOne(string $invoiceNo): InvoiceInfo;
} }

View File

@@ -7,10 +7,11 @@
* Powered by PhpStorm * Powered by PhpStorm
* Created on 2025/8/12 * Created on 2025/8/12
*/ */
declare(strict_types=1); declare(strict_types=1);
namespace Singularity\HDK\Pay\Domain; namespace Singularity\HDK\Pay\Domain;
use Swoole\ArrayObject; use Swoole\ArrayObject;
abstract class ValueObject extends ArrayObject {} abstract class ValueObject extends ArrayObject {}

View File

@@ -1,12 +1,13 @@
<?php <?php
/** /**
* AccountBalanceRpc.php@Pay * AccountRepo.php@Pay
* *
* @author 李东云 <Dongyun.Li@LuxCreo.Ai> * @author 李东云 <Dongyun.Li@LuxCreo.Ai>
* Powered by PhpStorm * Powered by PhpStorm
* Created on 2025/8/17 * Created on 2025/8/17
*/ */
declare(strict_types=1); declare(strict_types=1);
namespace Singularity\HDK\Pay\Infrastructure\Repository; namespace Singularity\HDK\Pay\Infrastructure\Repository;
@@ -18,8 +19,9 @@ use Singularity\HDK\Pay\Domain\Account\Aggregate\Account\AccountBalance;
use Singularity\HDK\Pay\Domain\Account\Aggregate\Account\PointsBalance; use Singularity\HDK\Pay\Domain\Account\Aggregate\Account\PointsBalance;
use Singularity\HDK\Pay\Domain\Account\Enum\PointType; use Singularity\HDK\Pay\Domain\Account\Enum\PointType;
use Singularity\HDK\Pay\Domain\Account\Repository\AccountRepoInterface; use Singularity\HDK\Pay\Domain\Account\Repository\AccountRepoInterface;
use Singularity\HDK\Pay\Domain\Account\ValueObject\Email;
final class AccountBalanceRepo extends AbstractRepo implements AccountRepoInterface final class AccountRepo extends AbstractRepo implements AccountRepoInterface
{ {
public function getAccount(string $uid): AccountBalance public function getAccount(string $uid): AccountBalance
{ {
@@ -37,13 +39,13 @@ final class AccountBalanceRepo extends AbstractRepo implements AccountRepoInterf
uid: $result['uid'], uid: $result['uid'],
pointsBalances: array_map( pointsBalances: array_map(
callback: fn($pointBalance) callback: fn($pointBalance)
=> new PointsBalance( => new PointsBalance(
type: PointType::from($pointBalance['name']), type: PointType::from($pointBalance['name']),
total: $pointBalance['total'], total: $pointBalance['total'],
cost: $pointBalance['cost'], cost: $pointBalance['cost'],
amount: $pointBalance['amount'], amount: $pointBalance['amount'],
version: $pointBalance['version'], version: $pointBalance['version'],
expiredAt: isset($pointBalance['expired_at']) ? new Carbon($pointBalance['expired_at']): null, expiredAt: isset($pointBalance['expired_at']) ? new Carbon($pointBalance['expired_at']) : null,
), ),
array: $result['point_balance'], array: $result['point_balance'],
), ),
@@ -65,7 +67,7 @@ final class AccountBalanceRepo extends AbstractRepo implements AccountRepoInterf
cost: $result['cost'], cost: $result['cost'],
amount: $result['amount'], amount: $result['amount'],
version: $result['version'], version: $result['version'],
expiredAt: isset($result['expired_at']) ? new Carbon($result['expired_at']): null, expiredAt: isset($result['expired_at']) ? new Carbon($result['expired_at']) : null,
); );
} }
@@ -81,4 +83,26 @@ final class AccountBalanceRepo extends AbstractRepo implements AccountRepoInterf
data: $cmd->pointsBalances data: $cmd->pointsBalances
); );
} }
}
public function getEmail(string $uid): Email
{
$response = $this->requestService->requestGet(
url: "/rpc/v2/account/$uid/inv-email"
);
$content = $response->getBody()->getContents();
$result = Json::decode($content);
return new Email($result['email']);
}
public function updateEmail(string $uid, Email $email): void
{
$this->requestService->requestPut(
url: "/rpc/v2/account/$uid/inv-email",
data: [
'email' => $email->getValue()
]
);
}
}

View File

@@ -7,6 +7,7 @@
* Powered by PhpStorm * Powered by PhpStorm
* Created on 2025/8/29 * Created on 2025/8/29
*/ */
declare(strict_types=1); declare(strict_types=1);
namespace Singularity\HDK\Pay\Infrastructure\Repository; namespace Singularity\HDK\Pay\Infrastructure\Repository;
@@ -23,6 +24,7 @@ use Singularity\HDK\Pay\Domain\Invoice\Aggregate\Invoice\Invoice;
use Singularity\HDK\Pay\Domain\Invoice\Aggregate\Invoice\InvoiceInfo; use Singularity\HDK\Pay\Domain\Invoice\Aggregate\Invoice\InvoiceInfo;
use Singularity\HDK\Pay\Domain\Invoice\Aggregate\Invoice\InvoiceProduct; use Singularity\HDK\Pay\Domain\Invoice\Aggregate\Invoice\InvoiceProduct;
use Singularity\HDK\Pay\Domain\Invoice\Aggregate\Invoice\ValueObject\PointBalance; use Singularity\HDK\Pay\Domain\Invoice\Aggregate\Invoice\ValueObject\PointBalance;
use Singularity\HDK\Pay\Domain\Invoice\Aggregate\Invoice\ValueObject\PointPrice;
use Singularity\HDK\Pay\Domain\Invoice\Repository\InvoiceRepoInterface; use Singularity\HDK\Pay\Domain\Invoice\Repository\InvoiceRepoInterface;
final class InvoiceRepo extends AbstractRepo implements InvoiceRepoInterface final class InvoiceRepo extends AbstractRepo implements InvoiceRepoInterface
@@ -45,7 +47,7 @@ final class InvoiceRepo extends AbstractRepo implements InvoiceRepoInterface
'country' => $cmd->country, 'country' => $cmd->country,
'zip' => $cmd->zipCode, 'zip' => $cmd->zipCode,
'price' => [ 'price' => [
'amount' => (float)bcmul($money->getAmount(), '100', 2), 'amount' => (float)bcdiv($money->getAmount(), '100', 2),
'currency' => [ 'currency' => [
'code' => $money->getCurrency()->getCode(), 'code' => $money->getCurrency()->getCode(),
'symbol' => $cmd->currencySymbol, 'symbol' => $cmd->currencySymbol,
@@ -83,12 +85,17 @@ final class InvoiceRepo extends AbstractRepo implements InvoiceRepoInterface
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function send(string $invoiceNo): void public function send(string $invoiceNo, ?string $email): void
{ {
if (empty($invoiceNo)) { if (empty($invoiceNo)) {
throw new ValidateException(message: 'invoice no is required.'); throw new ValidateException(message: 'invoice no is required.');
} }
$this->requestService->requestGet(url: "/rpc/v2/invoice/invoices/$invoiceNo/email"); $this->requestService->requestGet(
url: "/rpc/v2/invoice/invoices/$invoiceNo/email",
data: [
'email' => $email,
],
);
} }
/** /**
@@ -134,6 +141,7 @@ final class InvoiceRepo extends AbstractRepo implements InvoiceRepoInterface
name: $result['product']['name'], name: $result['product']['name'],
sku: $result['product']['sku'], sku: $result['product']['sku'],
description: $result['product']['description'], description: $result['product']['description'],
prices: [],
), ),
balance: new PointBalance( balance: new PointBalance(
total: $result['balance']['total'], total: $result['balance']['total'],
@@ -144,6 +152,11 @@ final class InvoiceRepo extends AbstractRepo implements InvoiceRepoInterface
invoiceAt: new Carbon($result['invoice_at']), invoiceAt: new Carbon($result['invoice_at']),
designedAt: new Carbon($result['designed_at']), designedAt: new Carbon($result['designed_at']),
patientName: $result['patient_name'], patientName: $result['patient_name'],
price: new Money(
bcmul((string)$result['price']['amount'], '100', 2),
new Currency($result['price']['currency_code']),
),
currencySymbol: $result['price']['currency_symbol'],
); );
} }
} }

View File

@@ -148,7 +148,7 @@ final class ProductRepo extends AbstractRepo implements RechargeProductRepoInter
$result = Json::decode($content); $result = Json::decode($content);
return new RechargeProduct( return new RechargeProduct(
oneTime: isset($result['one_time']) oneTime: !empty($result['one_time'])
? new ProductItem( ? new ProductItem(
id: $result['one_time']['id'], id: $result['one_time']['id'],
description: $result['one_time']['name'], description: $result['one_time']['name'],
@@ -164,7 +164,7 @@ final class ProductRepo extends AbstractRepo implements RechargeProductRepoInter
), ),
) )
: null, : null,
renew: isset($result['renew']) renew: !empty($result['renew'])
? new ProductItem( ? new ProductItem(
id: $result['renew']['id'], id: $result['renew']['id'],
description: $result['renew']['name'], description: $result['renew']['name'],

View File

@@ -12,7 +12,7 @@ use Carbon\Carbon;
use Singularity\HDK\Pay\Application\Command\InitialAccountCmd; use Singularity\HDK\Pay\Application\Command\InitialAccountCmd;
use Singularity\HDK\Pay\Domain\Account\Enum\PointType; use Singularity\HDK\Pay\Domain\Account\Enum\PointType;
use Singularity\HDK\Pay\Infrastructure\Repository\AccountBalanceRepo; use Singularity\HDK\Pay\Infrastructure\Repository\AccountRepo;
use function Hyperf\Support\make; use function Hyperf\Support\make;
@@ -46,7 +46,7 @@ it('should initial account balance', function () {
); );
} }
$repo = make(AccountBalanceRepo::class); $repo = make(AccountRepo::class);
$repo->initial($cmd); $repo->initial($cmd);
expect(true)->toBeTrue(); expect(true)->toBeTrue();

View File

@@ -9,13 +9,13 @@
*/ */
use Singularity\HDK\Pay\Domain\Account\Aggregate\Account\AccountBalance; use Singularity\HDK\Pay\Domain\Account\Aggregate\Account\AccountBalance;
use Singularity\HDK\Pay\Infrastructure\Repository\AccountBalanceRepo; use Singularity\HDK\Pay\Infrastructure\Repository\AccountRepo;
use function Hyperf\Support\make; use function Hyperf\Support\make;
it('should be able to query account information', function () { it('should be able to query account information', function () {
$uid = '123456'; $uid = '123456';
$repo = make(AccountBalanceRepo::class); $repo = make(AccountRepo::class);
$result = $repo->getAccount($uid); $result = $repo->getAccount($uid);
expect($result) expect($result)
->toBeInstanceOf(AccountBalance::class) ->toBeInstanceOf(AccountBalance::class)

View File

@@ -0,0 +1,35 @@
<?php
/**
* QueryEmailTest.php@Pay
*
* @author 李东云 <Dongyun.Li@LuxCreo.Ai>
* Powered by PhpStorm
* Created on 2025/11/28
*/
use Singularity\HDK\Pay\Domain\Account\ValueObject\Email;
use Singularity\HDK\Pay\Infrastructure\Repository\AccountRepo;
use function Hyperf\Support\make;
it('should be able to get user email', function () {
$uid = '123456';
$repo = make(AccountRepo::class);
$result = $repo->getEmail($uid);
expect($result)
->toBeInstanceOf(Email::class);
});
it('should be able to update user email', function () {
$uid = '123456';
$newEmail = 'test@example.com';
$repo = make(AccountRepo::class);
$email = new Email($newEmail);
$repo->updateEmail($uid, $email);
// 验证更新后的邮箱
$result = $repo->getEmail($uid);
expect($result->getValue())->toBe($newEmail);
});

View File

@@ -10,13 +10,13 @@
use Singularity\HDK\Pay\Domain\Account\Aggregate\Account\PointsBalance; use Singularity\HDK\Pay\Domain\Account\Aggregate\Account\PointsBalance;
use Singularity\HDK\Pay\Domain\Account\Enum\PointType; use Singularity\HDK\Pay\Domain\Account\Enum\PointType;
use Singularity\HDK\Pay\Infrastructure\Repository\AccountBalanceRepo; use Singularity\HDK\Pay\Infrastructure\Repository\AccountRepo;
use function Hyperf\Support\make; use function Hyperf\Support\make;
it('should query point balance', function () { it('should query point balance', function () {
$uid = 'cn3221'; $uid = 'cn3221';
$repo = make(AccountBalanceRepo::class); $repo = make(AccountRepo::class);
$point_balance = $repo->getPointBalance($uid, PointType::EMA); $point_balance = $repo->getPointBalance($uid, PointType::EMA);
expect($point_balance) expect($point_balance)
->toBeInstanceOf(PointsBalance::class) ->toBeInstanceOf(PointsBalance::class)