浏览代码

feat(lakala): 新增分账订单查询功能

- 新增分账订单定时任务 ProfitShareOrderCron
- 在 ProfitShareOrderEntity 中实现分账结果查询逻辑
- 集成分账查询接口 SACSService 并更新调用地址
- 添加 ProfitShareOrderCron 的测试用例
- 注册 ProfitShareOrderCron 到扩展配置中
- 引入 SACSService 门面类以简化服务调用
runphp 3 月之前
父节点
当前提交
5f9fe8b05e

+ 32 - 0
src/Cron/ProfitShareOrderCron.php

@@ -0,0 +1,32 @@
+<?php
+declare(strict_types=1);
+
+namespace SixShop\Lakala\Cron;
+
+use SixShop\Core\Attribute\Cron;
+use SixShop\Lakala\Entity\ProfitShareOrderEntity;
+use SixShop\Lakala\Enum\ProfitShareOrderStatusEnum;
+use function Symfony\Component\Translation\t;
+
+class ProfitShareOrderCron
+{
+    public function __construct(private ProfitShareOrderEntity $profitShareOrderEntity)
+    {
+    }
+
+    /**
+     * 查询分账结果
+     */
+    #[Cron('10 */10 * * * *', 'lakala.query_profit_share_order_result')]
+    public function queryProfitShareOrderResult(): void
+    {
+        foreach ($this->profitShareOrderEntity->where([
+            'status' => [
+                ProfitShareOrderStatusEnum::PROCESSING,
+                ProfitShareOrderStatusEnum::ACCEPTED
+            ]
+        ])->cursor() as $profitShareOrder) {
+            $this->profitShareOrderEntity->queryProfitShareOrderResult($profitShareOrder->id);
+        }
+    }
+}

+ 33 - 2
src/Entity/ProfitShareOrderEntity.php

@@ -10,6 +10,7 @@ use SixShop\Lakala\Enum\ReceiverStatusEnum;
 use SixShop\Lakala\Facade\Config;
 use SixShop\Lakala\Facade\LaepIndustryService;
 use SixShop\Lakala\Facade\LedgerService;
+use SixShop\Lakala\Facade\SACSService;
 use SixShop\Lakala\Model\ProfitShareOrderModel;
 use SixShop\Lakala\Model\ProfitShareReceiverModel;
 use think\db\Query;
@@ -23,13 +24,20 @@ class ProfitShareOrderEntity extends BaseEntity
 {
     public function getOrderList(array $params, array $pageAndLimit): Paginator
     {
-        return $this->withSearch(['out_separate_no', 'status'], $params)
+        $paginate = $this->withSearch(['out_separate_no', 'status'], $params)
             ->with(['user' => function (Query $query) {
                 $query->field(['id', 'nickname', 'avatar', 'username', 'mobile']);
             }])
             ->append(['status_text'])
             ->order('id', 'desc')
             ->paginate($pageAndLimit);
+        $paginate->each(function (self $entity) {
+            if ($entity->status == ProfitShareOrderStatusEnum::PROCESSING || $entity->status == ProfitShareOrderStatusEnum::ACCEPTED) {
+                $this->queryProfitShareOrderResult($entity->id);
+            }
+        });
+
+        return $paginate;
     }
 
     /**
@@ -93,7 +101,7 @@ class ProfitShareOrderEntity extends BaseEntity
 
     public function getStats()
     {
-        $stats =  $this->whereIn('status',['SUCCESS', 'PENDING'])->field([
+        $stats = $this->whereIn('status', ['SUCCESS', 'PENDING'])->field([
             "COALESCE(SUM(CASE WHEN status = 'SUCCESS' THEN total_amt ELSE 0 END), 0) AS total_amount", // 总分账金额
             "COALESCE(SUM(CASE WHEN status = 'SUCCESS' THEN separate_value ELSE 0 END), 0) AS user_total_amount", // 用户分账总金额
             "COALESCE(SUM(CASE WHEN status = 'PENDING' THEN separate_value ELSE 0 END), 0) AS user_pending_amount", // 用户待分账总金额
@@ -104,4 +112,27 @@ class ProfitShareOrderEntity extends BaseEntity
             'user_pending_amount' => (float)$stats['user_pending_amount'],
         ];
     }
+
+    public function queryProfitShareOrderResult(int $id): self
+    {
+        $entity = $this->findOrEmpty($id);
+        if ($entity->isEmpty()) {
+            throw_logic_exception('分账订单不存在');
+        }
+        if ($entity->status == ProfitShareOrderStatusEnum::PROCESSING || $entity->status == ProfitShareOrderStatusEnum::ACCEPTED) {
+            $resData = SACSService::balanceSeparateQuery(merchantNo: $entity->merchant_no, separateNo: $entity->separate_no);
+            if ($resData->status == 'SUCCESS') {
+                $entity->status = ProfitShareOrderStatusEnum::SUCCESS;
+            }
+            $entity->status = match ($resData->status) {
+                'ACCEPTED' => ProfitShareOrderStatusEnum::ACCEPTED,
+                'SUCCESS' => ProfitShareOrderStatusEnum::SUCCESS,
+                'FAIL' => ProfitShareOrderStatusEnum::FAIL,
+                default => throw_logic_exception('分账状态异常')
+            };
+            $resData->acc_result_desc && $entity->fail_reason = $resData->acc_result_desc;
+            $entity->save();
+        }
+        return $entity;
+    }
 }

+ 2 - 1
src/Extension.php

@@ -4,7 +4,7 @@ declare(strict_types=1);
 namespace SixShop\Lakala;
 
 use SixShop\Core\ExtensionAbstract;
-use SixShop\Lakala\Cron\WechatOrderCron;
+use SixShop\Lakala\Cron\{ProfitShareOrderCron, WechatOrderCron};
 use SixShop\Lakala\Hook\LakalaHook;
 use SixShop\Lakala\Hook\OrderHook;
 use SixShop\Payment\Contracts\PaymentExtensionInterface;
@@ -38,6 +38,7 @@ class Extension extends ExtensionAbstract implements PaymentExtensionInterface
     #[\Override] public function getCronJobs(): array
     {
         return [
+            ProfitShareOrderCron::class,
             WechatOrderCron::class,
         ];
     }

+ 16 - 0
src/Facade/SACSService.php

@@ -0,0 +1,16 @@
+<?php
+declare(strict_types=1);
+namespace SixShop\Lakala\Facade;
+
+use think\Facade;
+
+/**
+ * @mixin \SixShop\Lakala\Service\SACSService
+ */
+class SACSService extends Facade
+{
+    protected static function getFacadeClass()
+    {
+        return \SixShop\Lakala\Service\SACSService::class;
+    }
+}

+ 1 - 1
src/Service/SACSService.php

@@ -60,7 +60,7 @@ class SACSService
             $reqData['out_separate_no'] = $outSeparateNo;
         }
         $request->setReqData($reqData);
-        $response = $this->lakalaApi->tradeApi('/api/v3/sacs/balanceSeparateQuery', $request);
+        $response = $this->lakalaApi->tradeApi('/api/v3/sacs/balance_separate_query_plus', $request);
         if ($response->getCode() == 'SACS0000') {
             return $response->getRespData();
         } else {

+ 25 - 0
tests/Cron/ProfitShareOrderCronTest.php

@@ -0,0 +1,25 @@
+<?php
+declare(strict_types=1);
+namespace SixShop\Lakala\Cron;
+
+use PHPUnit\Framework\Attributes\Test;
+use PHPUnit\Framework\TestCase;
+use think\facade\Db;
+
+class ProfitShareOrderCronTest extends TestCase
+{
+    private ProfitShareOrderCron $profitShareOrderCron;
+    protected function setUp(): void
+    {
+        Db::listen(function ($sql, $time, $explain) {
+            dump($sql);
+        });
+        $this->profitShareOrderCron = app(ProfitShareOrderCron::class);
+    }
+
+    #[Test]
+    public function queryProfitShareOrderResult()
+    {
+        $this->profitShareOrderCron->queryProfitShareOrderResult();
+    }
+}

+ 22 - 0
tests/Service/SACSServiceTest.php

@@ -0,0 +1,22 @@
+<?php
+declare(strict_types=1);
+namespace SixShop\Lakala\Service;
+
+use PHPUnit\Framework\Attributes\Test;
+use PHPUnit\Framework\TestCase;
+
+class SACSServiceTest extends TestCase
+{
+    private SACSService $sassService;
+    protected function setUp(): void
+    {
+        $this->sassService = app(SACSService::class);
+    }
+
+    #[Test]
+    public function balanceSeparateQuery():void
+    {
+        $response = $this->sassService->balanceSeparateQuery('822451048160BXH','20251204770188018888533600');
+        dump($response);
+    }
+}