doge 2 روز پیش
والد
کامیت
7590ba14fd

+ 24 - 0
app/Http/Controllers/admin/Agent.php

@@ -329,6 +329,30 @@ class Agent extends AgentApiController
         });
     }
 
+    /** 入股购买记录(全部代理)。 */
+    public function equityOrders(Request $request, \App\Services\Agent\AgentEquityService $service)
+    {
+        return $this->execute(function () use ($request, $service) {
+            $data = $request->validate([
+                'page' => ['nullable', 'integer', 'min:1'], 'limit' => ['nullable', 'integer', 'min:1', 'max:100'],
+                'agent_id' => ['nullable', 'integer'], 'username' => ['nullable', 'string', 'max:64'],
+                'order_no' => ['nullable', 'string', 'max:40'], 'status' => ['nullable', 'in:pending_payment,completed,cancelled'],
+                'date_type' => ['nullable', 'in:created_at,completed_at'],
+                'start_date' => ['nullable', 'date_format:Y-m-d'], 'end_date' => ['nullable', 'date_format:Y-m-d', 'after_or_equal:start_date'],
+            ]);
+            return $service->paginate($data);
+        });
+    }
+
+    /** 取消代理的待付款入股订单。 */
+    public function cancelEquityOrder(Request $request, \App\Services\Agent\AgentEquityService $service)
+    {
+        return $this->execute(function () use ($request, $service) {
+            $data = $request->validate(['id' => ['required', 'integer'], 'remark' => ['required', 'string', 'max:255']]);
+            return $service->adminCancel((int) $data['id'], (int) request()->user->id, (string) $data['remark']);
+        });
+    }
+
     public function recharges(Request $request)
     {
         return $this->execute(function () use ($request) {

+ 1 - 1
app/Models/Agent/AgentEquityOrder.php

@@ -16,7 +16,7 @@ class AgentEquityOrder extends BaseModel
     protected $appends = ['status_text'];
     protected $casts = [
         'agent_id' => 'integer', 'percent' => 'decimal:4', 'price_per_percent' => 'decimal:4',
-        'amount' => 'decimal:4', 'completed_at' => 'datetime',
+        'amount' => 'decimal:4', 'completed_at' => 'datetime', 'cancelled_by' => 'integer',
     ];
 
     public function agent()

+ 56 - 2
app/Services/Agent/AgentEquityService.php

@@ -69,15 +69,69 @@ class AgentEquityService
 
     public function cancel(Agent $agent, int $orderId): AgentEquityOrder
     {
-        return DB::transaction(function () use ($agent, $orderId) {
-            $order = AgentEquityOrder::query()->where('agent_id', $agent->id)->lockForUpdate()->findOrFail($orderId);
+        return $this->cancelOrder(fn ($query) => $query->where('agent_id', $agent->id), $orderId, null, '');
+    }
+
+    /** 总后台取消待付款订单(如代理长期不充值),需填写原因。 */
+    public function adminCancel(int $orderId, int $adminId, string $remark): AgentEquityOrder
+    {
+        $remark = trim($remark);
+        if ($remark === '') throw new \InvalidArgumentException('请填写取消原因');
+        return $this->cancelOrder(fn ($query) => $query, $orderId, $adminId, $remark);
+    }
+
+    private function cancelOrder(callable $scope, int $orderId, ?int $adminId, string $remark): AgentEquityOrder
+    {
+        return DB::transaction(function () use ($scope, $orderId, $adminId, $remark) {
+            $order = $scope(AgentEquityOrder::query())->lockForUpdate()->findOrFail($orderId);
             if ($order->status !== AgentEquityOrder::STATUS_PENDING) throw new \RuntimeException('只有待付款订单可以取消');
             $order->status = AgentEquityOrder::STATUS_CANCELLED;
+            $order->cancelled_by = $adminId;
+            $order->cancel_remark = $remark;
             $order->save();
             return $order;
         });
     }
 
+    /**
+     * 总后台:全部代理的入股购买记录。summary 按当前筛选条件汇总:
+     * 已开通的比例和金额、待付款笔数和金额。
+     */
+    public function paginate(array $params): array
+    {
+        $page = max(1, (int) ($params['page'] ?? 1));
+        $limit = min(100, max(1, (int) ($params['limit'] ?? 20)));
+        $query = AgentEquityOrder::query();
+        if (!empty($params['agent_id'])) $query->where('agent_id', (int) $params['agent_id']);
+        if (!empty($params['username'])) {
+            $query->whereIn('agent_id', Agent::query()->where('username', 'like', '%' . $params['username'] . '%')->select('id'));
+        }
+        if (!empty($params['order_no'])) $query->where('order_no', $params['order_no']);
+        if (!empty($params['status'])) $query->where('status', $params['status']);
+        $dateColumn = ($params['date_type'] ?? '') === 'completed_at' ? 'completed_at' : 'created_at';
+        if (!empty($params['start_date'])) $query->where($dateColumn, '>=', $params['start_date'] . ' 00:00:00');
+        if (!empty($params['end_date'])) $query->where($dateColumn, '<=', $params['end_date'] . ' 23:59:59');
+
+        $sums = (clone $query)->selectRaw(
+            'COALESCE(SUM(CASE WHEN status = ? THEN percent ELSE 0 END), 0) AS completed_percent, '
+            . 'COALESCE(SUM(CASE WHEN status = ? THEN amount ELSE 0 END), 0) AS completed_amount, '
+            . 'COALESCE(SUM(CASE WHEN status = ? THEN 1 ELSE 0 END), 0) AS pending_count, '
+            . 'COALESCE(SUM(CASE WHEN status = ? THEN amount ELSE 0 END), 0) AS pending_amount',
+            [AgentEquityOrder::STATUS_COMPLETED, AgentEquityOrder::STATUS_COMPLETED, AgentEquityOrder::STATUS_PENDING, AgentEquityOrder::STATUS_PENDING]
+        )->first();
+        $total = (clone $query)->count();
+        $list = $query->with('agent:id,username,real_name,type,equity_percent,balance')->orderByDesc('id')->forPage($page, $limit)->get();
+        $summary = [
+            'completed_percent' => bcadd((string) $sums->completed_percent, '0', 4),
+            'completed_amount' => bcadd((string) $sums->completed_amount, '0', 4),
+            'pending_count' => (int) $sums->pending_count,
+            'pending_amount' => bcadd((string) $sums->pending_amount, '0', 4),
+            // 全平台入股代理当前持股合计(不受筛选影响)
+            'total_equity_percent' => bcadd((string) Agent::query()->where('type', Agent::TYPE_EQUITY)->sum('equity_percent'), '0', 4),
+        ];
+        return compact('total', 'page', 'limit', 'list', 'summary');
+    }
+
     /** 余额足够时完成待付款订单(下单后、充值到账后调用)。 */
     public function fulfillPending(int $agentId): int
     {

+ 52 - 0
database/migrations/2026_11_08_180000_add_agent_equity_order_admin.php

@@ -0,0 +1,52 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\DB;
+use Illuminate\Support\Facades\Schema;
+
+/**
+ * 总后台「入股购买记录」:菜单 agentEquityOrders(挂在「代理充值记录」同一父菜单下)和取消按钮;
+ * agent_equity_orders 记录取消人和原因(代理自己取消时 cancelled_by 为空)。
+ */
+return new class extends Migration {
+    private const BUTTON = 'admin/agent/equity-orders/cancel';
+
+    public function up(): void
+    {
+        Schema::table('agent_equity_orders', function (Blueprint $t) {
+            if (!Schema::hasColumn('agent_equity_orders', 'cancelled_by')) $t->unsignedBigInteger('cancelled_by')->nullable()->comment('取消的管理员ID,代理自己取消为空');
+            if (!Schema::hasColumn('agent_equity_orders', 'cancel_remark')) $t->string('cancel_remark', 255)->default('');
+        });
+        if (!Schema::hasTable('menus')) return;
+        $now = date('Y-m-d H:i:s');
+        $parentId = (int) DB::table('menus')->where('uri', 'agentRecharges')->where('type', 1)->value('parent_id');
+        $menuId = DB::table('menus')->where('uri', 'agentEquityOrders')->where('type', 1)->value('id');
+        if (!$menuId) {
+            $menuId = DB::table('menus')->insertGetId([
+                'parent_id' => $parentId, 'title' => '入股购买记录', 'icon' => null, 'uri' => 'agentEquityOrders',
+                'permission_name' => 'agent.agentEquityOrders', 'sort' => 24, 'status' => 1, 'type' => 1,
+                'created_at' => $now, 'updated_at' => $now,
+            ]);
+        }
+        if (!DB::table('menus')->where('uri', self::BUTTON)->exists()) {
+            DB::table('menus')->insert(['parent_id' => $menuId, 'title' => '入股购买记录-取消', 'icon' => null, 'uri' => self::BUTTON,
+                'permission_name' => str_replace('/', '.', self::BUTTON), 'sort' => 0, 'status' => 1, 'type' => 2,
+                'created_at' => $now, 'updated_at' => $now]);
+        }
+    }
+
+    public function down(): void
+    {
+        if (Schema::hasTable('menus')) {
+            $ids = DB::table('menus')->whereIn('uri', ['agentEquityOrders', self::BUTTON])->pluck('id');
+            if (Schema::hasTable('role_menu')) DB::table('role_menu')->whereIn('menu_id', $ids)->delete();
+            DB::table('menus')->whereIn('id', $ids)->delete();
+        }
+        Schema::table('agent_equity_orders', function (Blueprint $t) {
+            foreach (['cancelled_by', 'cancel_remark'] as $column) {
+                if (Schema::hasColumn('agent_equity_orders', $column)) $t->dropColumn($column);
+            }
+        });
+    }
+};

+ 1 - 0
docs/后端/代理合营与入股-部署说明.md

@@ -14,6 +14,7 @@ php artisan migrate --force
 | `2026_11_07_130000_add_agent_joint_venture_admin_menus.php` | 总后台菜单:入股配置、分成方案申请、代理充值记录、会员盈亏日报,以及保存/审核按钮。代理菜单挂在标题含「代理」的一级菜单下;找不到时挂到根节点,需要手动调整 |
 | `2026_11_08_150000_add_type_to_agent_applications.php` | `agent_applications.type`(1 合营,默认 / 2 入股):会员申请时选择的代理类型,由 melbet_sport-api 的 `POST /api/agent/apply` 写入。**需要先于 melbet 新代码执行**,否则会员提交申请会因缺少该列报错 |
 | `2026_11_08_170000_add_agent_withdrawal_channels.php` | 代理提现支持全部提现通道:`agent_withdrawals` 新增 `pay_no`、`pay_data`、`callback_data`(三方代付)。通道存在原有的 `account_type`,提现账户沿用 `agent_withdraw_accounts`(`type` = 通道,`details` 存开户行/收款码/收款方式) |
+| `2026_11_08_180000_add_agent_equity_order_admin.php` | 总后台「入股购买记录」菜单 `agentEquityOrders` 和取消按钮;`agent_equity_orders` 新增 `cancelled_by`、`cancel_remark`。**代理取消入股订单也会写这两列,需要和代码一起上线** |
 | `2026_11_08_120000_create_agent_payment_orders.php` | 代理人民币充值:新表 `agent_payment_orders`(字段和状态码同 `payment_orders`)、`agent_settings.recharge_channel_group_id`(默认 1),以及「代理人民币充值」菜单和 4 个按钮(挂在「代理充值记录」同一个父菜单下) |
 
 `2026_11_07_120000_agent_joint_venture_and_equity.php` 的内容:

+ 116 - 0
docs/总后台/代理入股购买记录-前端接入.md

@@ -0,0 +1,116 @@
+# 总后台-入股购买记录(前端接入)
+
+入股代理在代理后台按比例购买股份(`POST /agent/equity/orders`),这里查看全部代理的购买记录,并可以取消长期未付款的订单。
+
+沿用总后台登录凭证,`/admin/agent/*` 只对 `AGENT_ADMIN_IDS` 里的管理员开放。返回结构:`{"code":0,"timestamp":…,"msg":"OK","data":…}`,业务错误时 `code` 非 0,`msg` 可以直接展示。金额、比例都是 4 位小数的字符串,比例单位是 %。
+
+## 0. 菜单与权限
+
+迁移 `2026_11_08_180000_add_agent_equity_order_admin.php` 已写入:
+
+| 类型 | uri | 标题 |
+|---|---|---|
+| 菜单 | `agentEquityOrders` | 入股购买记录(和「代理充值记录」在同一个父菜单下) |
+| 按钮 | `admin/agent/equity-orders/cancel` | 入股购买记录-取消 |
+
+## 1. 购买流程(页面说明用)
+
+- 代理选择比例下单,应付金额 = 比例 × 每 1% 价格(下单时的价格会记录在订单上,之后改价不影响已下的单)。
+- 代理余额足够:立即扣款,订单 `completed`(已开通),代理持股比例增加。
+- 余额不够:订单 `pending_payment`(待付款),代理充值到账后系统自动扣款开通,不需要审核。
+- 每个代理同时只能有 1 笔待付款订单;代理可以自己取消,总后台也可以取消。
+- 分红每月由平台人工发放(「代理列表」的人工加款),不在这里处理。
+
+## 2. 购买记录列表
+
+### `GET /admin/agent/equity-orders`
+
+| 参数 | 类型 | 必填 | 说明 |
+|---|---|---:|---|
+| `page` / `limit` | int | 否 | 默认 1 / 20,`limit` 最大 100 |
+| `agent_id` | int | 否 | 代理 ID |
+| `username` | string | 否 | 代理账号,模糊查询 |
+| `order_no` | string | 否 | 订单号(`AE` 开头) |
+| `status` | string | 否 | `pending_payment` 待付款 / `completed` 已开通 / `cancelled` 已取消 |
+| `date_type` | string | 否 | 日期筛选按哪个时间:`created_at` 下单时间(默认)/ `completed_at` 开通时间 |
+| `start_date` / `end_date` | Y-m-d | 否 | 日期范围 |
+
+```json
+{
+  "total": 2,
+  "page": 1,
+  "limit": 20,
+  "list": [
+    {
+      "id": 12,
+      "order_no": "AE20261108120000ABC123",
+      "agent_id": 5,
+      "percent": "0.5000",
+      "price_per_percent": "10000.0000",
+      "amount": "5000.0000",
+      "status": "pending_payment",
+      "status_text": "待付款",
+      "completed_at": null,
+      "cancelled_by": null,
+      "cancel_remark": "",
+      "created_at": "2026-11-08 12:00:00",
+      "updated_at": "2026-11-08 12:00:00",
+      "agent": {"id":5,"username":"agent5","real_name":"","type":2,"type_text":"入股","equity_percent":"0.0000","balance":"1200.0000"}
+    }
+  ],
+  "summary": {
+    "completed_percent": "0.3000",
+    "completed_amount": "3000.0000",
+    "pending_count": 1,
+    "pending_amount": "5000.0000",
+    "total_equity_percent": "0.3000"
+  }
+}
+```
+
+列表字段:
+
+| 字段 | 说明 |
+|---|---|
+| `order_no` | 订单号 |
+| `agent` | 代理:`id`、`username`、`real_name`、`type`/`type_text`、`equity_percent`(**当前**累计持股 %)、`balance`(当前余额,待付款订单可据此判断还差多少) |
+| `percent` | 本次购买比例(%) |
+| `price_per_percent` | 下单时每 1% 的价格 |
+| `amount` | 应付金额 = `percent` × `price_per_percent` |
+| `status` / `status_text` | `pending_payment` 待付款 / `completed` 已开通 / `cancelled` 已取消 |
+| `completed_at` | 开通(扣款)时间 |
+| `cancelled_by` | 取消的管理员 ID;代理自己取消为 `null` |
+| `cancel_remark` | 总后台取消时填写的原因 |
+| `created_at` | 下单时间 |
+
+`summary`(按当前筛选条件统计,不受分页影响):
+
+| 字段 | 说明 |
+|---|---|
+| `completed_percent` | 已开通的比例合计(%) |
+| `completed_amount` | 已开通的金额合计 |
+| `pending_count` | 待付款笔数 |
+| `pending_amount` | 待付款金额合计 |
+| `total_equity_percent` | 全平台入股代理**当前**持股合计(%),不受筛选影响 |
+
+页面建议:列表上方展示 `summary`;`pending_payment` 的行显示「取消」按钮(需要按钮权限)。
+
+## 3. 取消待付款订单
+
+### `POST /admin/agent/equity-orders/cancel`
+
+| 参数 | 必填 | 说明 |
+|---|---:|---|
+| `id` | 是 | 订单 ID |
+| `remark` | 是 | 取消原因,最多 255 字 |
+
+返回取消后的订单(`status=cancelled`,`cancelled_by` 为当前管理员 ID)。只能取消 `pending_payment`,其他状态返回 `只有待付款订单可以取消`。取消后代理可以重新下单;已开通的股份不能在这里撤销。
+
+## 4. 相关接口
+
+| 用途 | 接口 |
+|---|---|
+| 入股价格、比例区间、开关 | `GET/POST /admin/agent/settings`(入股配置) |
+| 代理当前持股 | `GET /admin/agent` 列表的 `equity_percent`,可用 `type=2` 筛选入股代理 |
+| 月度分红发放 | `POST /admin/agent/adjust` 人工加款 |
+| 购股扣款流水 | 代理资金流水类型 `equity_purchase` |

+ 2 - 1
docs/总后台/代理合营与入股-前端接入.md

@@ -16,13 +16,14 @@
 | 分成方案申请(新菜单) | 审核合营代理提交的方案申请 |
 | 代理充值记录(新菜单) | 代理 USDT 充值列表;人工确认模式下审核凭证 |
 | 代理人民币充值(新菜单) | 代理在线充值(808/NO/JD/三斤等)和人工充值;发送收款信息、审核、拒绝、查单 |
+| 入股购买记录(新菜单) | 全部代理的购股订单、汇总,取消待付款订单,见 [代理入股购买记录-前端接入.md](代理入股购买记录-前端接入.md) |
 | 代理返佣记录 | 改为「合营分成记录」:只有盈亏分成,金额可为负;新增分成注单明细 |
 | 代理提现列表 | 仅 USDT,新增 USDT 数量和汇率 |
 | 会员列表 → 会员盈亏日报(新菜单) | 每个会员每天一行,可按代理和代理类型筛选 |
 | 返佣配置(分享) | 游戏分类改为 8 类,去掉「彩票(三方)」 |
 | 绑定/解绑会员 | **删除**。`POST /admin/agent/bind-member` 已移除,会员的所属代理不能修改 |
 
-新菜单已经由迁移写入 `menus` 表,uri 分别是 `agentSettings`、`agentPlanApplications`、`agentRecharges`、`agentPaymentOrders`、`memberDailyReport`。按钮权限有 `admin/agent/settings/save`、`admin/agent/plan-applications/audit`、`admin/agent/recharges/audit`、`admin/agent/payment-orders/pay-data`、`admin/agent/payment-orders/audit`、`admin/agent/payment-orders/reject`、`admin/agent/payment-orders/query`。
+新菜单已经由迁移写入 `menus` 表,uri 分别是 `agentSettings`、`agentPlanApplications`、`agentRecharges`、`agentPaymentOrders`、`agentEquityOrders`、`memberDailyReport`。按钮权限有 `admin/agent/settings/save`、`admin/agent/plan-applications/audit`、`admin/agent/recharges/audit`、`admin/agent/payment-orders/pay-data`、`admin/agent/payment-orders/audit`、`admin/agent/payment-orders/reject`、`admin/agent/payment-orders/query`、`admin/agent/equity-orders/cancel`。
 
 ## 业务规则(页面文案需要用到)
 

+ 2 - 0
routes/admin.php

@@ -182,6 +182,8 @@ Route::middleware(['admin.jwt'])->group(function () {
             Route::post('/payment-orders/reject', [AgentAdmin::class, 'rejectPaymentOrder'])->defaults('permission_uri', 'admin/agent/payment-orders/reject');
             Route::post('/payment-orders/query', [AgentAdmin::class, 'queryPaymentOrder'])->defaults('permission_uri', 'admin/agent/payment-orders/query');
             Route::get('/profit-entries', [AgentAdmin::class, 'profitEntries'])->defaults('permission_uri', 'admin/agent/commissions');
+            Route::get('/equity-orders', [AgentAdmin::class, 'equityOrders'])->defaults('permission_uri', 'admin/agent/equity-orders');
+            Route::post('/equity-orders/cancel', [AgentAdmin::class, 'cancelEquityOrder'])->defaults('permission_uri', 'admin/agent/equity-orders/cancel');
         });
 
         Route::get('/menu/mineMenu', [Menu::class, 'mineMenu']); // 我的菜单

+ 65 - 0
tests/Integration/AgentEquityOrderAdminTest.php

@@ -0,0 +1,65 @@
+<?php
+
+namespace Tests\Integration;
+
+use App\Http\Controllers\admin\Agent as AdminAgent;
+use App\Models\Agent\Agent;
+use App\Models\Agent\AgentEquityOrder;
+use App\Models\Agent\AgentSetting;
+use App\Services\Agent\AgentEquityService;
+use App\Services\Agent\AgentWalletService;
+use Illuminate\Http\Request;
+use PHPUnit\Framework\TestCase;
+use Tests\Support\AgentTestEnvironment;
+
+/** 总后台入股购买记录:列表筛选、汇总、取消待付款订单。 */
+class AgentEquityOrderAdminTest extends TestCase
+{
+    use AgentTestEnvironment;
+
+    private function call(string $method, array $params)
+    {
+        $request = Request::create('/admin/agent/equity-orders', $method === 'cancelEquityOrder' ? 'POST' : 'GET', $params);
+        $request->user = (object) ['id' => 7];
+        $this->app->instance('request', $request);
+        return (new AdminAgent())->{$method}($request, new AgentEquityService(new AgentWalletService()))->getData(true);
+    }
+
+    public function test_admin_lists_all_purchases_with_summary_and_cancels_pending_orders(): void
+    {
+        AgentSetting::current()->update(['equity_enabled' => 1, 'equity_price_per_percent' => 10000,
+            'equity_min_percent' => 0.1, 'equity_max_percent' => 1]);
+        $equity = new AgentEquityService(new AgentWalletService());
+        $rich = $this->agent(Agent::TYPE_EQUITY);
+        Agent::query()->whereKey($rich->id)->update(['balance' => 5000, 'realtime_balance' => 5000]);
+        $poor = $this->agent(Agent::TYPE_EQUITY);
+        $done = $equity->order($rich->fresh(), '0.3');   // 3000,余额够,直接开通
+        $pending = $equity->order($poor, '0.5');         // 5000,待付款
+        $this->assertSame(AgentEquityOrder::STATUS_COMPLETED, $done->status);
+
+        $all = $this->call('equityOrders', []);
+        $this->assertSame(0, $all['code'], (string) $all['msg']);
+        $this->assertSame(2, $all['data']['total']);
+        $this->assertSame(['0.3000', '3000.0000', 1, '5000.0000', '0.3000'], [
+            $all['data']['summary']['completed_percent'], $all['data']['summary']['completed_amount'],
+            $all['data']['summary']['pending_count'], $all['data']['summary']['pending_amount'], $all['data']['summary']['total_equity_percent'],
+        ]);
+        $first = $all['data']['list'][0];
+        $this->assertSame($pending->id, $first['id']);
+        $this->assertSame($poor->username, $first['agent']['username']);
+        $this->assertSame('待付款', $first['status_text']);
+
+        $this->assertSame(1, $this->call('equityOrders', ['username' => $rich->username])['data']['total']);
+        $this->assertSame(1, $this->call('equityOrders', ['status' => 'completed'])['data']['total']);
+        $this->assertSame(0, $this->call('equityOrders', ['date_type' => 'completed_at', 'start_date' => '2026-09-08'])['data']['total']);
+
+        $this->assertNotSame(0, $this->call('cancelEquityOrder', ['id' => $pending->id])['code'], 'remark required');
+        $this->assertSame('只有待付款订单可以取消', $this->call('cancelEquityOrder', ['id' => $done->id, 'remark' => 'x'])['msg']);
+        $cancelled = $this->call('cancelEquityOrder', ['id' => $pending->id, 'remark' => '长期未充值']);
+        $this->assertSame(0, $cancelled['code']);
+        $this->assertSame(['cancelled', 7, '长期未充值'], [$cancelled['data']['status'], $cancelled['data']['cancelled_by'], $cancelled['data']['cancel_remark']]);
+
+        $own = $equity->order($poor, '0.2');
+        $this->assertNull($equity->cancel($poor, $own->id)->cancelled_by, 'agent self-cancel has no admin');
+    }
+}

+ 1 - 0
tests/Support/AgentTestEnvironment.php

@@ -90,6 +90,7 @@ trait AgentTestEnvironment
         DB::table('share_policies')->insert(['effective_date' => '1970-01-01',
             'rules' => json_encode(['third:1' => [], 'third:3' => [], 'self:lottery' => []])]);
         (require dirname(__DIR__, 2) . '/database/migrations/2026_11_07_120000_agent_joint_venture_and_equity.php')->up();
+        (require dirname(__DIR__, 2) . '/database/migrations/2026_11_08_180000_add_agent_equity_order_admin.php')->up();
 
         foreach (['recharges', 'withdraws', 'payment_orders'] as $table) {
             Schema::create($table, function (Blueprint $t) {