| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220 |
- <?php
- namespace plugin\saiadmin\app\logic\user;
- use DateTimeImmutable;
- use plugin\saiadmin\app\service\user\WechatPayComplaintService;
- use plugin\saiadmin\basic\think\BaseLogic;
- use plugin\saiadmin\exception\ApiException;
- use support\think\Db;
- /** 微信支付用户投诉查询与处理。 */
- class UserComplaintLogic extends BaseLogic
- {
- private WechatPayComplaintService $wechat;
- public function __construct(?WechatPayComplaintService $wechat = null)
- {
- $this->wechat = $wechat ?? new WechatPayComplaintService();
- }
- public function configOptions(): array
- {
- return $this->configQuery()
- ->field('id,partner_id,mini_program_name,appid,mchid')
- ->order('id', 'asc')
- ->select()
- ->toArray();
- }
- public function indexList(array $filters): array
- {
- $config = $this->resolveConfig((int) ($filters['config_id'] ?? 0));
- [$startDate, $endDate] = $this->dateRange(
- (string) ($filters['start_date'] ?? ''),
- (string) ($filters['end_date'] ?? '')
- );
- $page = max(1, (int) request()->input('page', 1));
- $limit = min(50, max(1, (int) request()->input('limit', 20)));
- $result = $this->wechat->complaints($config, [
- 'begin_date' => $startDate,
- 'end_date' => $endDate,
- 'limit' => $limit,
- 'offset' => ($page - 1) * $limit,
- ]);
- $rows = array_map(fn (array $row): array => $this->formatComplaint($row), $result['data'] ?? []);
- $this->appendRefundRemarks($rows);
- return [
- 'data' => $rows,
- 'total' => (int) ($result['total_count'] ?? count($rows)),
- 'current_page' => $page,
- 'per_page' => $limit,
- 'config' => $this->publicConfig($config),
- ];
- }
- public function detail(int $configId, string $complaintId): array
- {
- $complaintId = $this->complaintId($complaintId);
- $config = $this->resolveConfig($configId);
- $result = $this->wechat->detail($config, $complaintId);
- if (!empty($result['payer_phone'])) {
- $result['payer_phone'] = $this->wechat->decryptSensitive(
- (string) $result['payer_phone'],
- (string) $config['apiclient_key']
- );
- }
- return $this->formatComplaint($result);
- }
- public function history(int $configId, string $complaintId): array
- {
- $config = $this->resolveConfig($configId);
- $result = $this->wechat->history($config, $this->complaintId($complaintId));
- return array_map(function (array $item): array {
- $item['complaint_media_list'] = array_values((array) ($item['complaint_media_list'] ?? []));
- return $item;
- }, $result['data'] ?? []);
- }
- public function reply(array $data): array
- {
- $content = trim((string) ($data['content'] ?? ''));
- if ($content === '' || mb_strlen($content) > 200) {
- throw new ApiException('回复内容不能为空且不能超过 200 个字');
- }
- $config = $this->resolveConfig((int) ($data['config_id'] ?? 0));
- $this->wechat->reply($config, $this->complaintId((string) ($data['complaint_id'] ?? '')), $content);
- return [];
- }
- public function complete(array $data): array
- {
- $config = $this->resolveConfig((int) ($data['config_id'] ?? 0));
- $this->wechat->complete($config, $this->complaintId((string) ($data['complaint_id'] ?? '')));
- return [];
- }
- private function configQuery()
- {
- $query = Db::table('sa_wechat_mini_program')->whereNull('delete_time');
- if (!$this->isSuperAdmin()) {
- $query->where('partner_id', $this->currentAdminId());
- }
- return $query;
- }
- private function resolveConfig(int $configId): array
- {
- $query = $this->configQuery();
- if ($configId > 0) {
- $query->where('id', $configId);
- }
- $config = $query->order('id', 'asc')->find();
- if (!$config) {
- throw new ApiException($configId > 0 ? '微信小程序配置不存在或无权访问' : '请先绑定微信小程序并完善微信支付配置');
- }
- return $config;
- }
- /** @return array{0:string,1:string} */
- private function dateRange(string $startDate, string $endDate): array
- {
- if ($startDate === '' || $endDate === '') {
- throw new ApiException('请选择投诉查询日期范围');
- }
- $start = DateTimeImmutable::createFromFormat('!Y-m-d', $startDate);
- $end = DateTimeImmutable::createFromFormat('!Y-m-d', $endDate);
- if (!$start || !$end || $start->format('Y-m-d') !== $startDate || $end->format('Y-m-d') !== $endDate) {
- throw new ApiException('投诉查询日期格式错误');
- }
- if ($start > $end) {
- throw new ApiException('开始日期不能晚于结束日期');
- }
- if ((int) $start->diff($end)->days > 30) {
- throw new ApiException('单次最多查询连续 31 天的投诉记录');
- }
- return [$startDate, $endDate];
- }
- private function complaintId(string $complaintId): string
- {
- $complaintId = trim($complaintId);
- if ($complaintId === '' || mb_strlen($complaintId) > 64) {
- throw new ApiException('投诉单号错误');
- }
- return $complaintId;
- }
- private function formatComplaint(array $row): array
- {
- $orders = [];
- foreach ((array) ($row['complaint_order_info'] ?? []) as $order) {
- if (!is_array($order)) {
- continue;
- }
- if (isset($order['amount'])) {
- $order['amount'] = round(((float) $order['amount']) / 100, 2);
- }
- $orders[] = $order;
- }
- $row['complaint_order_info'] = $orders;
- $row['complaint_media_list'] = array_values((array) ($row['complaint_media_list'] ?? []));
- $row['refund_remark'] = (string) ($row['refund_remark'] ?? '');
- return $row;
- }
- private function appendRefundRemarks(array &$rows): void
- {
- $transactionIds = [];
- foreach ($rows as $row) {
- foreach ($row['complaint_order_info'] ?? [] as $order) {
- if (!empty($order['transaction_id'])) {
- $transactionIds[] = (string) $order['transaction_id'];
- }
- }
- }
- $transactionIds = array_values(array_unique($transactionIds));
- if ($transactionIds === []) {
- return;
- }
- $orders = Db::table('sa_rental_order')->whereIn('transaction_id', $transactionIds)
- ->whereNull('delete_time')->field('transaction_id,refund_amount,remark')->select()->toArray();
- $map = [];
- foreach ($orders as $order) {
- if ((float) ($order['refund_amount'] ?? 0) > 0 || trim((string) ($order['remark'] ?? '')) !== '') {
- $map[(string) $order['transaction_id']] = (string) (($order['remark'] ?? '') ?: '已退款');
- }
- }
- foreach ($rows as &$row) {
- foreach ($row['complaint_order_info'] ?? [] as $order) {
- $transactionId = (string) ($order['transaction_id'] ?? '');
- if (isset($map[$transactionId])) {
- $row['refund_remark'] = $map[$transactionId];
- break;
- }
- }
- }
- unset($row);
- }
- private function publicConfig(array $config): array
- {
- return [
- 'id' => (int) $config['id'],
- 'mini_program_name' => (string) $config['mini_program_name'],
- 'appid' => (string) $config['appid'],
- 'mchid' => (string) $config['mchid'],
- ];
- }
- private function currentAdminId(): int
- {
- return (int) ($this->adminInfo['id'] ?? 0);
- }
- private function isSuperAdmin(): bool
- {
- return $this->currentAdminId() === 1 || (int) ($this->adminInfo['is_super'] ?? 0) === 1;
- }
- }
|