Withdraw.php 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641
  1. <?php
  2. /**
  3. * Niushop商城系统 - 团队十年电商经验汇集巨献!
  4. * =========================================================
  5. * Copy right 2019-2029 杭州牛之云科技有限公司, 保留所有权利。
  6. * ----------------------------------------------
  7. * 官方网址: https://www.niushop.com
  8. * =========================================================
  9. */
  10. namespace app\model\member;
  11. use app\model\BaseModel;
  12. use app\model\message\Message;
  13. use app\model\message\Sms;
  14. use app\model\shop\ShopAcceptMessage;
  15. use app\model\system\Config as ConfigModel;
  16. use app\model\system\Pay;
  17. use app\model\system\Stat;
  18. use think\facade\Cache;
  19. use addon\memberwithdraw\model\Withdraw as MemberWithdraw;
  20. use addon\wechat\model\Message as WechatMessage;
  21. use addon\weapp\model\Message as WeappMessage;
  22. use think\facade\Db;
  23. /**
  24. * 会员提现
  25. */
  26. class Withdraw extends BaseModel
  27. {
  28. /**************************************************************************** 会员提现设置 *************************************************************/
  29. /**
  30. * 会员提现设置
  31. * array $data
  32. */
  33. public function setConfig($data, $is_use, $site_id = 0, $app_module = 'shop')
  34. {
  35. $config = new ConfigModel();
  36. $res = $config->setConfig($data, '会员提现设置', $is_use, [['site_id', '=', $site_id], ['app_module', '=', $app_module], ['config_key', '=', 'MEMBER_WITHDRAW_CONFIG']]);
  37. return $res;
  38. }
  39. /**
  40. * 会员提现设置
  41. */
  42. public function getConfig($site_id = 0, $app_module = 'shop')
  43. {
  44. $config = new ConfigModel();
  45. $res = $config->getConfig([['site_id', '=', $site_id], ['app_module', '=', $app_module], ['config_key', '=', 'MEMBER_WITHDRAW_CONFIG']]);
  46. if (empty($res['data']['value'])) {
  47. $res['data']['value'] = [
  48. 'is_auto_audit' => 0,
  49. 'rate' => 0,
  50. 'transfer_type' => '',
  51. 'is_auto_transfer' => 0,
  52. 'min' => 0,
  53. 'max' =>0,
  54. ];
  55. }
  56. return $res;
  57. }
  58. /**************************************************************************** 会员提现设置 *************************************************************/
  59. /**
  60. * 申请提现
  61. * @param $data
  62. */
  63. public function apply($data, $site_id = 0, $app_module = 'shop')
  64. {
  65. $config_result = $this->getConfig($site_id, $app_module);
  66. $config = $config_result["data"]['value'];
  67. if ($config_result["data"]["is_use"] == 0)
  68. return $this->error([], "提现未开启");
  69. $withdraw_no = $this->createWithdrawNo();
  70. $apply_money = round($data["apply_money"], 2);
  71. if ($apply_money < $config["min"])
  72. return $this->error([], "申请提现金额不能小于最低提现额度" . $config["min"]);
  73. if($apply_money > $config['max']) return $this->error([], "申请提现金额不能大于最高提现额度" . $config["max"]);
  74. $member_id = $data["member_id"];
  75. $member_model = new Member();
  76. $member_info_result = $member_model->getMemberInfo([["member_id", "=", $member_id]], "balance_money,headimg,wx_openid,username,mobile,weapp_openid,nickname");
  77. $member_info = $member_info_result["data"];
  78. if (empty($member_info))
  79. return $this->error([], "MEMBER_NOT_EXIST");
  80. $balance_money = $member_info["balance_money"];
  81. if ($apply_money > $balance_money)
  82. return $this->error([], "申请提现金额不能大于会员可提现金额");
  83. $transfer_type = $data["transfer_type"];
  84. $transfer_type_list = $this->getTransferType($site_id, $app_module);
  85. $transfer_type_name = $transfer_type_list[$transfer_type] ?? '';
  86. if (empty($transfer_type_name))
  87. return $this->error([], "不支持的提现方式");
  88. model('member_withdraw')->startTrans();
  89. try {
  90. $rate = $config["rate"];
  91. $bank_name = "";
  92. $account_number = "";
  93. $applet_type = 0;
  94. switch ($transfer_type) {
  95. case "bank":
  96. $bank_name = $data["bank_name"];
  97. $account_number = $data["account_number"];
  98. break;
  99. case "alipay":
  100. $bank_name = '';
  101. $account_number = $data["account_number"];
  102. break;
  103. case "wechatpay":
  104. $bank_name = '';
  105. if(empty($member_info["wx_openid"]) && empty($member_info["weapp_openid"])){
  106. return $this->error('','请绑定微信或更换提现账户');
  107. }
  108. if(!empty($member_info["wx_openid"])){
  109. $account_number = $member_info["wx_openid"];
  110. $applet_type = 0; // 公众号
  111. } else {
  112. $account_number = $member_info["weapp_openid"];
  113. $applet_type = 1; // 小程序
  114. }
  115. break;
  116. }
  117. $service_money = round($apply_money * $rate / 100, 2);//手续费
  118. $money = $apply_money - $service_money;
  119. $data = array(
  120. "site_id" => $site_id,
  121. "withdraw_no" => $withdraw_no,
  122. "member_name" => $member_info["username"] == '' ? $member_info["mobile"] : $member_info["username"],
  123. "member_id" => $data["member_id"],
  124. "transfer_type" => $data["transfer_type"],
  125. "transfer_type_name" => $transfer_type_name,
  126. "apply_money" => $apply_money,
  127. "service_money" => $service_money,
  128. "rate" => $rate,
  129. "money" => $money,
  130. "apply_time" => time(),
  131. "status" => 0,
  132. "status_name" => "待审核",
  133. "member_headimg" => $member_info["headimg"],
  134. "realname" => $data["realname"],
  135. "bank_name" => $bank_name,
  136. "account_number" => $account_number,
  137. "mobile" => $data["mobile"],
  138. "applet_type" => $applet_type
  139. );
  140. //减少现金余额
  141. $member_account = new MemberAccount();
  142. $account_res = $member_account->addMemberAccount($site_id, $member_id, 'balance_money', -$apply_money, 'withdraw', '会员提现', '会员提现扣除');
  143. if ($account_res['code'] < 0){
  144. model('member_withdraw')->rollback();
  145. return $account_res;
  146. }
  147. //增加提现中余额
  148. model("member")->setInc([["member_id", "=", $member_id]], "balance_withdraw_apply", $apply_money);
  149. $result = model("member_withdraw")->add($data);
  150. //是否启用自动通过审核(必须是微信)
  151. if ($config["is_auto_audit"] == 0) {
  152. $this->agree([["id", "=", $result],['site_id', '=',$site_id ]]);
  153. }
  154. model('member_withdraw')->commit();
  155. //申请提现发送消息
  156. $data['keywords'] = 'USER_WITHDRAWAL_APPLY';
  157. $data['member_name'] = $member_info['nickname'];
  158. $message_model = new Message();
  159. $message_model->sendMessage($data);
  160. return $this->success();
  161. } catch (\Exception $e) {
  162. model('member_withdraw')->rollback();
  163. return $this->error('', $e->getMessage());
  164. }
  165. }
  166. /**
  167. * 同意提现申请
  168. * @param $condition
  169. */
  170. public function agree($condition)
  171. {
  172. $check_condition = array_column($condition, 2, 0);
  173. $site_id = $check_condition['site_id'];
  174. $app_module = $check_condition['app_module'] ?? 'shop';
  175. if (empty($site_id)) {
  176. return $this->error(-1, '参数错误');
  177. }
  178. $info = model("member_withdraw")->getInfo($condition);
  179. if (empty($info))
  180. return $this->error();
  181. $config_result = $this->getConfig($site_id, $app_module);
  182. $config = $config_result["data"];
  183. model('member_withdraw')->startTrans();
  184. try {
  185. $data = array(
  186. "status" => 1,
  187. "status_name" => "待转账",
  188. "audit_time" => time(),
  189. );
  190. $result = model("member_withdraw")->update($data, $condition);
  191. //是否启用自动转账(必须是微信或支付宝)
  192. if ($config["value"]["is_auto_transfer"] == 1) {
  193. $member_withdraw_model = new MemberWithdraw();
  194. $member_withdraw_model->transfer($info["id"]);
  195. /*if ($transfer_res['code'] == 0) {
  196. //提现成功发送消息
  197. $info['keywords'] = 'USER_WITHDRAWAL_SUCCESS';
  198. $message_model = new Message();
  199. $res = $message_model->sendMessage($info);
  200. }*/
  201. }
  202. model('member_withdraw')->commit();
  203. return $this->success();
  204. } catch (\Exception $e) {
  205. model('member_withdraw')->rollback();
  206. return $this->error('', $e->getMessage());
  207. }
  208. }
  209. /**
  210. * 拒绝提现申请
  211. * @param $condition
  212. */
  213. public function refuse($condition, $param)
  214. {
  215. $info = model("member_withdraw")->getInfo($condition, "site_id,transfer_type,member_id,apply_money");
  216. if (empty($info))
  217. return $this->error();
  218. model('member_withdraw')->startTrans();
  219. try {
  220. $data = array(
  221. "status" => -1,
  222. "status_name" => "已拒绝",
  223. "refuse_reason" => $param["refuse_reason"],
  224. "audit_time" => time(),
  225. );
  226. $result = model("member_withdraw")->update($data, $condition);
  227. //增加现金余额
  228. $member_account = new MemberAccount();
  229. $account_res = $member_account->addMemberAccount($info['site_id'], $info['member_id'], 'balance_money', $info["apply_money"], 'withdraw', '会员提现申请未通过', '提现申请未通过返还');
  230. if ($account_res['code'] != 0) {
  231. model('member_withdraw')->rollback();
  232. return $account_res;
  233. }
  234. //减少提现中余额
  235. model("member")->setDec([["member_id", "=", $info["member_id"]]], "balance_withdraw_apply", $info["apply_money"]);
  236. model('member_withdraw')->commit();
  237. return $this->success();
  238. } catch (\Exception $e) {
  239. model('member_withdraw')->rollback();
  240. return $this->error('', $e->getMessage());
  241. }
  242. }
  243. /**
  244. * 提现转账完成
  245. * @param $id
  246. */
  247. public function transferFinish($param = [])
  248. {
  249. $condition = [
  250. ['id', '=', $param['id'] ],
  251. ['site_id', '=', $param['site_id'] ],
  252. ['status', '=', 1]
  253. ];
  254. $info = model("member_withdraw")->getInfo($condition);
  255. if (empty($info)) return $this->error();
  256. $payment_time = time();
  257. model('member_withdraw')->startTrans();
  258. try {
  259. $data = [
  260. 'status' => 2,
  261. 'status_name' => '已转账',
  262. 'payment_time' => $payment_time,
  263. 'certificate' => $param['certificate'] ?? '',
  264. 'certificate_remark' => $param['certificate_remark'] ?? ''
  265. ];
  266. $result = model("member_withdraw")->update($data, $condition);
  267. //增加已提现余额
  268. model("member")->setInc([["member_id", "=", $info["member_id"]]], "balance_withdraw", $info["apply_money"]);
  269. //减少提现中余额
  270. model("member")->setDec([["member_id", "=", $info["member_id"]]], "balance_withdraw_apply", $info["apply_money"]);
  271. model('member_withdraw')->commit();
  272. $member_info = model("member")->getInfo([["member_id", "=", $info["member_id"]]], 'nickname');
  273. //提现成功发送消息
  274. $info['keywords'] = 'USER_WITHDRAWAL_SUCCESS';
  275. $info['payment_time'] = $payment_time;
  276. $info['member_name'] = $member_info['nickname'];
  277. $message_model = new Message();
  278. $message_model->sendMessage($info);
  279. $stat_model = new Stat();
  280. $stat_model->switchStat(['type' => 'member_withdraw', 'data' => ['site_id' => $info['site_id'], 'id' => $info['id']]]);
  281. return $this->success();
  282. } catch (\Exception $e) {
  283. model('member_withdraw')->rollback();
  284. return $this->error('', $e->getMessage());
  285. }
  286. }
  287. /**
  288. * @param $condition
  289. * @param string $field
  290. */
  291. public function getMemberWithdrawInfo($condition, $field = "*")
  292. {
  293. $info = model('member_withdraw')->getInfo($condition, $field);
  294. return $this->success($info);
  295. }
  296. /**
  297. * 提现详情
  298. * @param $condition
  299. * @return array
  300. */
  301. public function getMemberWithdrawDetail($condition)
  302. {
  303. $info = model('member_withdraw')->getInfo($condition, "*");
  304. return $this->success($info);
  305. }
  306. /**
  307. * 提现单数
  308. * @param $condition
  309. */
  310. public function getMemberWithdrawCount($condition)
  311. {
  312. $count = model('member_withdraw')->getCount($condition, "id");
  313. return $this->success($count);
  314. }
  315. /**
  316. * 提现总和
  317. * @param $condition
  318. */
  319. public function getMemberWithdrawSum($condition, $field = 'apply_money')
  320. {
  321. $count = model('member_withdraw')->getSum($condition, $field);
  322. return $this->success($count);
  323. }
  324. /**
  325. * 获取会员提现分页列表
  326. * @param array $condition
  327. * @param int $page
  328. * @param int $page_size
  329. * @param string $order
  330. * @param string $field
  331. * @return array
  332. */
  333. public function getMemberWithdrawPageList($condition = [], $page = 1, $page_size = PAGE_LIST_ROWS, $order = '', $field = '*')
  334. {
  335. $list = model('member_withdraw')->pageList($condition, $field, $order, $page, $page_size, '', '', '');
  336. return $this->success($list);
  337. }
  338. /**
  339. * 获取会员提现列表
  340. * @param array $where
  341. * @param bool $field
  342. * @param string $order
  343. * @param string $alias
  344. * @param array $join
  345. * @param string $group
  346. * @param null $limit
  347. * @return array
  348. */
  349. public function getMemberWithdrawList($where = [], $field = true, $order = '', $alias = 'a', $join = [], $group = '', $limit = null)
  350. {
  351. $res = model('member_withdraw')->getList($where, $field, $order, $alias, $join, $group, $limit);
  352. return $this->success($res);
  353. }
  354. /**
  355. * 提现流水号
  356. */
  357. private function createWithdrawNo()
  358. {
  359. $cache = Cache::get("member_withdraw_no" . time());
  360. if (empty($cache)) {
  361. Cache::set("niutk" . time(), 1000);
  362. $cache = Cache::get("member_withdraw_no" . time());
  363. } else {
  364. $cache = $cache + 1;
  365. Cache::set("member_withdraw_no" . time(), $cache);
  366. }
  367. $no = date('Ymdhis', time()) . rand(1000, 9999) . $cache;
  368. return $no;
  369. }
  370. /**
  371. * 转账方式
  372. */
  373. public function getTransferType($site_id = 0, $app_module = 'shop')
  374. {
  375. $pay_model = new Pay();
  376. $transfer_type_list = $pay_model->getTransferType($site_id);
  377. $config_result = $this->getConfig($site_id, $app_module);
  378. $config = $config_result["data"]['value'];
  379. $data = [];
  380. $support_type = explode(",", $config["transfer_type"]);
  381. foreach ($transfer_type_list as $k => $v) {
  382. if (in_array($k, $support_type)) {
  383. $data[$k] = $v;
  384. }
  385. }
  386. return $data;
  387. }
  388. /**
  389. * 会员提现成功通知
  390. * @param $data
  391. */
  392. public function messageUserWithdrawalSuccess($data)
  393. {
  394. //发送短信
  395. $sms_model = new Sms();
  396. $var_parse = array(
  397. 'username' => $data["member_name"],//会员名
  398. 'money' => $data['apply_money']
  399. );
  400. $data["sms_account"] = $data["mobile"];//手机号
  401. $data["var_parse"] = $var_parse;
  402. $sms_model->sendMessage($data);
  403. $member_model = new Member();
  404. $member_info_result = $member_model->getMemberInfo([["member_id", "=", $data["member_id"]]]);
  405. $member_info = $member_info_result["data"];
  406. //绑定微信公众号才发送
  407. if (!empty($member_info) && !empty($member_info["wx_openid"])) {
  408. $wechat_model = new WechatMessage();
  409. $data["openid"] = $member_info["wx_openid"];
  410. $data["template_data"] = [
  411. 'keyword1' => $data['apply_money'],
  412. 'keyword2' => time_to_date($data['payment_time']),
  413. ];
  414. $data["page"] = "";
  415. $wechat_model->sendMessage($data);
  416. }
  417. //发送订阅消息
  418. if (!empty($member_info) && !empty($member_info["weapp_openid"])) {
  419. $weapp_model = new WeappMessage();
  420. $data["openid"] = $member_info["weapp_openid"];
  421. $data["template_data"] = [
  422. 'amount6' => [
  423. 'value' => $data['apply_money']
  424. ],
  425. 'date3' => [
  426. 'value' => time_to_date(time())
  427. ]
  428. ];
  429. $data["page"] = "";
  430. $weapp_model->sendMessage($data);
  431. }
  432. }
  433. /**
  434. * 会员提现失败通知
  435. * @param $data
  436. */
  437. public function messageUserWithdrawalError($data)
  438. {
  439. //发送短信
  440. $sms_model = new Sms();
  441. $var_parse = array(
  442. 'username' => $data["member_name"],//会员名
  443. 'money' => $data['apply_money']
  444. );
  445. $data["sms_account"] = $data["mobile"];//手机号
  446. $data["var_parse"] = $var_parse;
  447. $sms_model->sendMessage($data);
  448. $member_model = new Member();
  449. $member_info_result = $member_model->getMemberInfo([["member_id", "=", $data["member_id"]]]);
  450. $member_info = $member_info_result["data"];
  451. //绑定微信公众号才发送
  452. if (!empty($member_info) && !empty($member_info["wx_openid"])) {
  453. $wechat_model = new WechatMessage();
  454. $data["openid"] = $member_info["wx_openid"];
  455. $data["template_data"] = [
  456. 'keyword1' => time_to_date($data['create_time']),
  457. 'keyword2' => '审核失败',
  458. 'keyword3' => '会员申请提现',
  459. 'keyword4' => $data['apply_money'],
  460. ];
  461. $data["page"] = "";
  462. $wechat_model->sendMessage($data);
  463. }
  464. //发送订阅消息
  465. if (!empty($member_info) && !empty($member_info["weapp_openid"])) {
  466. $weapp_model = new WeappMessage();
  467. $data["openid"] = $member_info["weapp_openid"];
  468. $data["template_data"] = [
  469. 'amount3' => [
  470. 'value' => $data['apply_money']
  471. ],
  472. 'phrase4' => [
  473. 'value' => '审核失败'
  474. ],
  475. 'date2' => [
  476. 'value' => time_to_date(time())
  477. ]
  478. ];
  479. $data["page"] = "";
  480. $weapp_model->sendMessage($data);
  481. }
  482. }
  483. /**
  484. * 会员申请提现通知,卖家通知
  485. * @param $data
  486. */
  487. public function messageUserWithdrawalApply($data)
  488. {
  489. //发送短信
  490. $sms_model = new Sms();
  491. $var_parse = array(
  492. "username" => replaceSpecialChar($data["member_name"]),//会员名
  493. "money" => $data["apply_money"],//退款申请金额
  494. );
  495. // $site_id = $data['site_id'];
  496. // $shop_info = model("shop")->getInfo([["site_id", "=", $site_id]], "mobile,email");
  497. // $message_data["sms_account"] = $shop_info["mobile"];//手机号
  498. $data["var_parse"] = $var_parse;
  499. $shop_accept_message_model = new ShopAcceptMessage();
  500. $result = $shop_accept_message_model->getShopAcceptMessageList();
  501. $list = $result['data'];
  502. if (!empty($list)) {
  503. foreach ($list as $v) {
  504. $message_data = $data;
  505. $message_data["sms_account"] = $v["mobile"];//手机号
  506. $sms_model->sendMessage($message_data);
  507. if($v['wx_openid'] != ""){
  508. $wechat_model = new WechatMessage();
  509. $data["openid"] = $v['wx_openid'];
  510. $data["template_data"] = [
  511. 'keyword1' => replaceSpecialChar($data["member_name"]),
  512. 'keyword2' => time_to_date($data['apply_time']),
  513. 'keyword3' => $data["apply_money"]
  514. ];
  515. $data["page"] = "";
  516. $wechat_model->sendMessage($data);
  517. }
  518. }
  519. }
  520. }
  521. public function exportWithdraw($condition, $order){
  522. try {
  523. $file_name = date('Y年m月d日-余额提现', time()) . '.csv';
  524. // $file_name = date('YmdHis').'.csv';//csv文件名
  525. //通过分批次执行数据导出(防止内存超出配置设置的)
  526. set_time_limit(0);
  527. ini_set('memory_limit', '256M');
  528. //设置header头
  529. header('Content-Description: File Transfer');
  530. header('Content-Type: application/vnd.ms-excel');
  531. header('Content-Disposition: attachment; filename="' . $file_name . '"');
  532. header('Expires: 0');
  533. header('Cache-Control: must-revalidate');
  534. header('Pragma: public');
  535. //打开php数据输入缓冲区
  536. $fp = fopen('php://output', 'a');
  537. // fwrite($fp, chr(0xEF).chr(0xBB).chr(0xBF)); // 添加 BOM
  538. $heade = [ '会员账号', '提现方式', '申请提现金额', '提现手续费', '实际转账金额', '提现状态', '申请时间', '银行名称', '收款账号', '真实姓名', '手机号' ];
  539. //将数据编码转换成GBK格式
  540. mb_convert_variables('GBK', 'UTF-8', $heade);
  541. //将数据格式化为CSV格式并写入到output流中
  542. fputcsv($fp, $heade);
  543. //写入第一行表头
  544. Db::name('member_withdraw')->where($condition)->order($order)->chunk(500, function($item_list) use ($fp) {
  545. //写入导出信息
  546. foreach ($item_list as $k => $item_v) {
  547. $temp_data = [
  548. $item_v['member_name'] . "\t",
  549. $item_v[ 'transfer_type_name' ] . "\t",
  550. (float) $item_v[ 'apply_money' ] . "\t",
  551. (float) $item_v[ 'service_money' ] . "\t",
  552. (float) $item_v[ 'money' ] . "\t",
  553. $item_v[ 'status_name' ] . "\t",
  554. time_to_date($item_v[ 'apply_time' ]) . "\t",
  555. $item_v['bank_name']. "\t" ,
  556. $item_v['account_number']. "\t",
  557. $item_v['realname']. "\t",
  558. $item_v['mobile']. "\t",
  559. ];
  560. mb_convert_variables('GBK', 'UTF-8', $temp_data);
  561. fputcsv($fp, $temp_data);
  562. //将已经存储到csv中的变量数据销毁,释放内存
  563. unset($item_v);
  564. }
  565. unset($item_list);
  566. });
  567. //关闭句柄
  568. fclose($fp);
  569. die;
  570. } catch (\Exception $e) {
  571. return $this->error([], $e->getMessage() . $e->getFile() . $e->getLine());
  572. }
  573. }
  574. }