trim((string)$this->request->post('name')), 'license_no' => trim((string)$this->request->post('license_no')), 'license_image' => (string)$this->request->post('license_image'), 'legal_person' => trim((string)$this->request->post('legal_person')), 'contact' => trim((string)$this->request->post('contact')), 'mobile' => trim((string)$this->request->post('mobile')), 'province' => trim((string)$this->request->post('province')), 'city' => trim((string)$this->request->post('city')), 'district' => trim((string)$this->request->post('district')), 'address' => trim((string)$this->request->post('address')), 'invoice_title' => trim((string)$this->request->post('invoice_title')), 'invoice_tax_no' => trim((string)$this->request->post('invoice_tax_no')), 'invoice_bank' => trim((string)$this->request->post('invoice_bank')), 'invoice_account' => trim((string)$this->request->post('invoice_account')), 'settle_type' => $this->request->post('settle_type', 'prepay'), ]; if ($data['name'] === '' || $data['license_no'] === '' || $data['contact'] === '' || $data['mobile'] === '') { $this->error('请填写企业名称、统一社会信用代码、联系人和电话'); } if (!preg_match('/^1\d{10}$/', $data['mobile'])) { $this->error('联系电话格式不正确'); } if (!in_array($data['settle_type'], ['prepay', 'monthly'], true)) { $data['settle_type'] = 'prepay'; } $exist = Db::name('merchant')->where('user_id', $this->uid())->find(); if ($exist && $exist['verify_status'] === 'pass') { $this->error('您已是认证商家,无需重复入驻'); } $save = array_merge($data, [ 'verify_status' => 'pending', 'audit_msg' => '', 'updatetime' => time(), ]); if ($exist) { Db::name('merchant')->where('id', $exist['id'])->update($save); $id = (int)$exist['id']; } else { $save['user_id'] = $this->uid(); $save['createtime'] = time(); $id = Db::name('merchant')->insertGetId($save); } $this->success('提交成功,请等待审核', ['merchant_id' => $id]); } /** * 商家档案与经营数据 */ public function info() { $merchant = $this->merchantInfo(); if (!$merchant) { $this->success('未入驻', ['applied' => false]); return; } $uid = $this->uid(); $orderCount = (int)Db::name('order')->where('user_id', $uid)->where('pay_status', 1)->count(); $totalAmount = (float)Db::name('order')->where('user_id', $uid)->where('pay_status', 1)->sum('pay_amount'); $invoiced = (float)Db::name('invoice')->where('merchant_id', $merchant['id'])->where('status', 'issued')->sum('amount'); $this->success('', [ 'applied' => true, 'merchant' => [ 'id' => (int)$merchant['id'], 'name' => $merchant['name'], 'license_no' => $merchant['license_no'], 'legal_person' => $merchant['legal_person'], 'contact' => $merchant['contact'], 'mobile' => $merchant['mobile'], 'address' => $merchant['province'] . $merchant['city'] . $merchant['district'] . $merchant['address'], 'invoice_title' => $merchant['invoice_title'], 'invoice_tax_no' => $merchant['invoice_tax_no'], 'settle_type' => $merchant['settle_type'], 'verify_status' => $merchant['verify_status'], 'audit_msg' => $merchant['audit_msg'], 'order_count' => $orderCount, 'total_amount' => round($totalAmount, 2), 'invoiced_amount' => round($invoiced, 2), 'invoiceable' => round(max(0, $totalAmount - $invoiced), 2), ], ]); } /** * 维护资料(联系人 / 地址 / 开票信息) * @ApiMethod (POST) */ public function update() { $merchant = $this->requireMerchant(); $fields = ['contact', 'mobile', 'province', 'city', 'district', 'address', 'invoice_title', 'invoice_tax_no', 'invoice_bank', 'invoice_account']; $data = ['updatetime' => time()]; foreach ($fields as $f) { $v = $this->request->post($f, null); if ($v !== null) { $data[$f] = trim((string)$v); } } if (isset($data['mobile']) && $data['mobile'] !== '' && !preg_match('/^1\d{10}$/', $data['mobile'])) { $this->error('联系电话格式不正确'); } Db::name('merchant')->where('id', $merchant['id'])->update($data); $this->success('已保存'); } /** * 账单中心:按月汇总 + 近期订单 */ public function bills() { $this->requireMerchant(); $uid = $this->uid(); $months = Db::name('order') ->field("FROM_UNIXTIME(createtime,'%Y-%m') as month, count(*) as cnt, sum(pay_amount) as amount") ->where('user_id', $uid)->where('pay_status', 1) ->group('month')->order('month desc')->limit(12)->select(); foreach ($months as &$m) { $m['amount'] = round((float)$m['amount'], 2); $m['cnt'] = (int)$m['cnt']; } unset($m); $orders = Db::name('order')->field('id,order_no,service_name,pay_amount,status,createtime') ->where('user_id', $uid)->order('id desc')->limit(20)->select(); foreach ($orders as &$o) { $o['pay_amount'] = (float)$o['pay_amount']; $o['status_text'] = \app\common\library\OrderStatus::label($o['status']); $o['time_text'] = date('Y-m-d H:i', (int)$o['createtime']); } unset($o); $this->success('', ['months' => $months, 'orders' => $orders]); } /** * 开票记录 */ public function invoices() { $merchant = $this->requireMerchant(); $list = Db::name('invoice')->where('merchant_id', $merchant['id'])->order('id desc')->limit(30)->select(); $statusText = ['wait' => '开票中', 'issued' => '已开票', 'reject' => '已驳回']; foreach ($list as &$row) { $row['amount'] = (float)$row['amount']; $row['status_text'] = isset($statusText[$row['status']]) ? $statusText[$row['status']] : $row['status']; $row['type_text'] = $row['type'] === 'special' ? '专用发票' : '普通发票'; $row['time_text'] = date('Y-m-d H:i', (int)$row['createtime']); } unset($row); $this->success('', ['list' => $list]); } /** * 申请开票 * @ApiMethod (POST) */ public function invoice() { $merchant = $this->requireMerchant(); $amount = round((float)$this->request->post('amount'), 2); $type = $this->request->post('type', 'normal'); $email = trim((string)$this->request->post('email')); if ($amount <= 0) { $this->error('请填写开票金额'); } if (!in_array($type, ['normal', 'special'], true)) { $this->error('发票类型错误'); } $paid = (float)Db::name('order')->where('user_id', $this->uid())->where('pay_status', 1)->sum('pay_amount'); $used = (float)Db::name('invoice')->where('merchant_id', $merchant['id'])->where('status', 'in', ['wait', 'issued'])->sum('amount'); $available = round(max(0, $paid - $used), 2); if ($amount > $available) { $this->error('可开票金额不足,当前可开 ¥' . $available); } Db::name('invoice')->insert([ 'merchant_id' => (int)$merchant['id'], 'user_id' => $this->uid(), 'amount' => $amount, 'type' => $type, 'title' => $merchant['invoice_title'] ?: $merchant['name'], 'tax_no' => $merchant['invoice_tax_no'], 'email' => $email, 'status' => 'wait', 'createtime' => time(), 'updatetime' => time(), ]); $this->success('开票申请已提交,3 个工作日内开具'); } /** * 批量下单后绑定批次(订单本身走已验收的 /order/create) * @ApiMethod (POST) */ public function bindBatch() { $merchant = $this->requireMerchant(); // 兼容三种入参:数组 / 逗号串 / 混合 $raw = $this->request->post('order_ids'); $orderIds = []; foreach ((array)$raw as $v) { foreach (explode(',', (string)$v) as $one) { $one = (int)$one; if ($one > 0) { $orderIds[] = $one; } } } $orderIds = array_values(array_unique($orderIds)); $batchNo = trim((string)$this->request->post('batch_no', '')); if (empty($orderIds)) { $this->error('缺少订单'); } if ($batchNo === '') { $batchNo = date('YmdHis') . mt_rand(100, 999); } $ok = 0; foreach ($orderIds as $oid) { $oid = (int)$oid; if (!Db::name('order')->where('id', $oid)->where('user_id', $this->uid())->find()) { continue; } if (Db::name('merchant_order')->where('order_id', $oid)->find()) { continue; } Db::name('merchant_order')->insert([ 'merchant_id' => (int)$merchant['id'], 'order_id' => $oid, 'batch_no' => $batchNo, 'createtime' => time(), ]); $ok++; } $this->success('已归属到批次', ['batch_no' => $batchNo, 'count' => $ok]); } /** * 当前用户商家档案 */ protected function merchantInfo() { return Db::name('merchant')->where('user_id', $this->uid())->find(); } /** * 要求已通过审核的商家 */ protected function requireMerchant() { $m = $this->merchantInfo(); if (!$m) { $this->error('请先完成商家入驻', ['need_apply' => 1], 2001); } if ($m['verify_status'] === 'pending') { $this->error('商家资质审核中,请耐心等待', ['verify_status' => 'pending'], 2002); } if ($m['verify_status'] === 'reject') { $this->error('资质未通过:' . $m['audit_msg'], ['verify_status' => 'reject'], 2003); } return $m; } }