diff --git a/addons/shopro/model/split/SplitOrder.php b/addons/shopro/model/split/SplitOrder.php index f07bc02..1c3aeef 100644 --- a/addons/shopro/model/split/SplitOrder.php +++ b/addons/shopro/model/split/SplitOrder.php @@ -15,4 +15,9 @@ class SplitOrder extends Model { return $this->hasMany(SplitOrderReceiver::class, 'split_order_id', 'id'); } + + public function order() + { + return $this->belongsTo(\app\admin\model\shopro\order\Order::class, 'order_id', 'id'); + } } diff --git a/application/admin/controller/shopro/split/Order.php b/application/admin/controller/shopro/split/Order.php index 8706f4d..8daf25e 100644 --- a/application/admin/controller/shopro/split/Order.php +++ b/application/admin/controller/shopro/split/Order.php @@ -6,11 +6,21 @@ use app\admin\controller\shopro\Base; use addons\shopro\library\split\Config as SplitConfig; use addons\shopro\library\split\SplitExecutor; use addons\shopro\library\split\ProfitSharingService; +use app\admin\model\shopro\order\Order as ShopOrder; +use app\admin\model\shopro\user\User as ShopUser; class Order extends Base { protected $model = null; + protected $statusMap = [ + 0 => '待分账', + 1 => '分账中', + 2 => '成功', + 3 => '部分成功', + 4 => '失败', + ]; + public function _initialize() { parent::_initialize(); @@ -21,14 +31,143 @@ class Order extends Base { $this->request->filter(['strip_tags']); if ($this->request->isAjax()) { - list($where, $sort, $order, $offset, $limit) = $this->custombuildparams(); - $total = $this->model->where($where)->count(); - $list = $this->model->with('receivers')->where($where)->order($sort, $order)->limit($offset, $limit)->select(); + $nobuildfields = ['buyer_keyword', 'order_sn', 'status', 'channel', 'createtime']; + list($where, $sort, $order, $offset, $limit) = $this->custombuildparams(null, $nobuildfields); + + $query = $this->buildSearch(); + $total = $query->where($where)->count(); + $list = $this->buildSearch() + ->with([ + 'receivers', + 'order' => function ($q) { + $q->field('id,order_sn,user_id,pay_fee,paytime,status'); + }, + 'order.user' => function ($q) { + $q->field('id,nickname,mobile'); + }, + ]) + ->where($where) + ->order($sort, $order) + ->limit($offset, $limit) + ->select(); + + $list = $this->formatSplitOrderList($list); + return $this->success('操作成功', null, ['total' => $total, 'rows' => $list]); } + $this->assignconfig('splitHuifuOnly', (new SplitConfig())->isHuifuMode()); return $this->view->fetch(); } + protected function buildSearch() + { + $filter = (array) json_decode($this->request->get('filter', ''), true); + $query = $this->model; + + if (!empty($filter['order_sn'])) { + $orderIds = ShopOrder::where('order_sn', 'like', '%' . trim($filter['order_sn']) . '%')->column('id'); + $query = $query->where('order_id', 'in', $orderIds ?: [0]); + } + if (!empty($filter['buyer_keyword'])) { + $kw = trim($filter['buyer_keyword']); + $userIds = ShopUser::where('nickname|mobile', 'like', '%' . $kw . '%')->column('id'); + $orderIds = $userIds + ? ShopOrder::where('user_id', 'in', $userIds)->column('id') + : []; + $query = $query->where('order_id', 'in', $orderIds ?: [0]); + } + if (isset($filter['status']) && $filter['status'] !== '') { + $query = $query->where('status', intval($filter['status'])); + } + if (!empty($filter['channel'])) { + $query = $query->where('channel', $filter['channel']); + } + if (!empty($filter['createtime'])) { + $parts = explode(' - ', $filter['createtime']); + if (count($parts) === 2) { + $start = strtotime($parts[0]); + $end = strtotime($parts[1] . ' 23:59:59'); + if ($start && $end) { + $query = $query->where('createtime', 'between', [$start, $end]); + } + } + } + + return $query; + } + + protected function formatSplitOrderList($list) + { + $rows = []; + foreach ($list as $item) { + $data = is_array($item) ? $item : $item->toArray(); + + $order = $data['order'] ?? null; + $user = is_array($order) ? ($order['user'] ?? null) : null; + + $status = intval($data['status'] ?? 0); + $channel = $data['channel'] ?? 'wechat'; + $buyerNickname = $user['nickname'] ?? ''; + $buyerMobile = $user['mobile'] ?? ''; + + $receivers = $data['receivers'] ?? []; + $lines = []; + foreach ($receivers as $recv) { + $r = is_array($recv) ? $recv : (method_exists($recv, 'toArray') ? $recv->toArray() : []); + $lines[] = sprintf( + '%s ¥%s', + $this->roleTypeLabel($r['role_type'] ?? ''), + number_format(floatval($r['amount'] ?? 0), 2, '.', '') + ); + } + + $data['buyer_nickname'] = $buyerNickname; + $data['buyer_mobile'] = $buyerMobile; + $data['buyer_display'] = $this->formatBuyerDisplay( + $buyerNickname, + $buyerMobile, + is_array($order) ? intval($order['user_id'] ?? 0) : 0 + ); + $data['status_text'] = $this->statusMap[$status] ?? '-'; + $data['channel_text'] = $channel === 'huifu' ? '汇付' : '微信'; + $data['createtime_text'] = !empty($data['createtime']) + ? date('Y-m-d H:i:s', $data['createtime']) + : '-'; + $data['order_paytime_text'] = (is_array($order) && !empty($order['paytime'])) + ? date('Y-m-d H:i:s', $order['paytime']) + : '-'; + $data['receiver_summary'] = $lines ? implode(';', $lines) : '—'; + + unset($data['order']); + $rows[] = $data; + } + + return $rows; + } + + protected function formatBuyerDisplay($nickname, $mobile, $userId) + { + $nickname = trim((string) $nickname); + $mobile = trim((string) $mobile); + if ($nickname !== '') { + return $mobile !== '' ? ($nickname . '(' . $mobile . ')') : $nickname; + } + if ($mobile !== '') { + return $mobile; + } + return $userId ? ('用户#' . $userId) : '—'; + } + + protected function roleTypeLabel($type) + { + $map = [ + 'platform' => '平台', + 'promoter' => '推广员', + 'regional_agent' => '区域公司', + ]; + return $map[$type] ?? ($type ?: '接收方'); + } + public function retry($ids = null) { $id = $ids ?: $this->request->post('id'); diff --git a/application/admin/view/shopro/split/order/index.html b/application/admin/view/shopro/split/order/index.html index 8a28c8e..f89c967 100644 --- a/application/admin/view/shopro/split/order/index.html +++ b/application/admin/view/shopro/split/order/index.html @@ -1,19 +1,154 @@ -
+ 分账记录展示向支付通道(微信/汇付)发起的网关分账结果,与「分销佣金」「区域差价」钱包入账是不同链路。 + 仅已支付且触发分账的订单会出现记录;列表为空时请先确认分账已开启并完成一笔测试支付。 +
++ 「重试分账」仅对失败记录有效,会向通道重新发起分账;「同步通道状态」只拉取最新结果并更新本页,不会重复扣款。 +
+