MerchantApplymentsRepository.php 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2016~2024 https://www.crmeb.com All rights reserved.
  6. // +----------------------------------------------------------------------
  7. // | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
  8. // +----------------------------------------------------------------------
  9. // | Author: CRMEB Team <admin@crmeb.com>
  10. // +----------------------------------------------------------------------
  11. namespace app\common\repositories\system\merchant;
  12. use app\common\dao\system\merchant\MerchantAppymentsDao;
  13. use app\common\model\system\merchant\MerchantApplyments;
  14. use app\common\repositories\BaseRepository;
  15. use crmeb\jobs\SendSmsJob;
  16. use crmeb\services\ImageWaterMarkService;
  17. use crmeb\services\SmsService;
  18. use crmeb\services\UploadService;
  19. use crmeb\services\WechatService;
  20. use crmeb\services\YunxinSmsService;
  21. use FormBuilder\Factory\Elm;
  22. use function Symfony\Component\String\b;
  23. use think\db\concern\Transaction;
  24. use think\Exception;
  25. use think\exception\ValidateException;
  26. use think\facade\Cache;
  27. use think\facade\Db;
  28. use think\facade\Queue;
  29. use think\facade\Route;
  30. /**
  31. * 商户分账账户申请
  32. */
  33. class MerchantApplymentsRepository extends BaseRepository
  34. {
  35. const IDCARD = 'IDENTIFICATION_TYPE_MAINLAND_IDCARD'; //:中国大陆居民-身份证
  36. const PASSPORT = 'IDENTIFICATION_TYPE_OVERSEA_PASSPORT'; //:其他国家或地区居民-护照
  37. const HONGKONG = 'IDENTIFICATION_TYPE_HONGKONG'; //:中国香港居民–来往内地通行证
  38. const MACAO = 'IDENTIFICATION_TYPE_MACAO'; //:中国澳门居民–来往内地通行证
  39. const TAIWAN = 'IDENTIFICATION_TYPE_TAIWAN'; //:中国台湾居民–来往大陆通行证
  40. const FOREIGN_RESIDENT = 'IDENTIFICATION_TYPE_FOREIGN_RESIDENT'; //:外国人居留证
  41. const MACAO_RESIDENT = 'IDENTIFICATION_TYPE_HONGKONG_MACAO_RESIDENT'; //:港澳居民证
  42. const TAIWAN_RESIDENT = 'IDENTIFICATION_TYPE_TAIWAN_RESIDENT'; //:台湾居民证
  43. public function __construct(MerchantAppymentsDao $dao)
  44. {
  45. $this->dao = $dao;
  46. }
  47. /**
  48. * 申请
  49. * @param array $data
  50. * @param $merId
  51. * @return mixed
  52. * @author Qinii
  53. * @day 6/23/21
  54. */
  55. public function create(array $data,$merId)
  56. {
  57. $count = $this->dao->getSearch(['mer_id' => $merId])->count('*');
  58. if($count) throw new ValidateException('此商户已存在申请信息');
  59. $out_request_no = $this->getOutRequestNo($merId);
  60. $ret['mer_name'] = $data['merchant_shortname'];
  61. $ret['out_request_no'] = $out_request_no;
  62. $data['out_request_no'] = $out_request_no;
  63. $ret['info'] = json_encode($data,JSON_UNESCAPED_UNICODE);
  64. $ret['mer_id'] = $merId;
  65. $this->dao->create($ret);
  66. }
  67. /**
  68. * 整理请求数据
  69. * @param $info
  70. * @return mixed
  71. * @author Qinii
  72. * @day 6/24/21
  73. */
  74. public function sltData($info)
  75. {
  76. foreach ($info as $key => $value){
  77. if(is_object($value)){
  78. $value = (array)$value;
  79. }
  80. $data[$key] = $value;
  81. }
  82. if (isset($data['need_account_info'])) unset($data['need_account_info']);
  83. $data['id_doc_type'] = $this->getIdDocType($data['id_doc_type']);
  84. //营业执照
  85. if(isset($data['business_license_info'])){
  86. if(isset($data['business_license_info']['business_license_copy'])) {
  87. $business_license_copy = $data['business_license_info']['business_license_copy']->media_id;
  88. unset($data['business_license_info']['business_license_copy']);
  89. $data['business_license_info']['business_license_copy'] = $business_license_copy;
  90. }
  91. if(isset($data['business_license_info']['business_time'])){
  92. $organization_time = json_encode($data['business_license_info']['business_time'],JSON_UNESCAPED_UNICODE);
  93. $data['business_license_info']['business_time'] = $organization_time;
  94. }
  95. }
  96. //组织机构代码
  97. if(isset($data['organization_cert_info'])){
  98. if(isset($data['organization_cert_info']['organization_copy'])) {
  99. $organization_copy = $data['organization_cert_info']['organization_copy']->media_id;
  100. unset($data['organization_cert_info']['organization_copy']);
  101. $data['organization_cert_info']['organization_copy'] = $organization_copy;
  102. }
  103. if(isset($data['organization_cert_info']['organization_time'])){
  104. $organization_time = json_encode($data['organization_cert_info']['organization_time'],JSON_UNESCAPED_UNICODE);
  105. $data['organization_cert_info']['organization_time'] = $organization_time;
  106. }
  107. }
  108. //身份证
  109. if(isset($data['id_card_info'])){
  110. if(isset($data['id_card_info']['id_card_copy'])) {
  111. $id_card_copy = $data['id_card_info']['id_card_copy']->media_id;
  112. unset($data['id_card_info']['id_card_copy']);
  113. $data['id_card_info']['id_card_copy'] = $id_card_copy;
  114. }
  115. if(isset($data['id_card_info']['id_card_national'])) {
  116. $id_card_national = $data['id_card_info']['id_card_national']->media_id;
  117. unset($data['id_card_info']['id_card_national']);
  118. $data['id_card_info']['id_card_national'] = $id_card_national;
  119. }
  120. }
  121. //银行
  122. if(isset($data['account_info'])) {
  123. if(is_array($data['account_info']['bank_address_code'])){
  124. $bank_address_code = (string)$data['account_info']['bank_address_code'][2];
  125. unset($data['account_infoaccount_info']['bank_address_code']);
  126. $data['account_info']['bank_address_code'] = $bank_address_code;
  127. }
  128. $data['account_info']['bank_account_type'] = (string)$data['account_info']['bank_account_type'];
  129. }
  130. //管理员
  131. if(isset($data['contact_info'])) {
  132. $data['contact_info']['contact_type'] = (string)$data['contact_info']['contact_type'];
  133. if ($data['contact_info']['contact_type'] == 65) {
  134. unset(
  135. $data['contact_info']['contact_id_doc_copy'],
  136. $data['contact_info']['contact_id_doc_copy_back'],
  137. $data['contact_info']['contact_id_doc_period_begin'],
  138. $data['contact_info']['contact_id_doc_period_end'],
  139. $data['contact_info']['business_authorization_letter'],
  140. $data['contact_info']['contact_id_doc_type']
  141. );
  142. }
  143. //if(isset($data['contact_info']['contact_id_doc_period_end']))
  144. //{
  145. // $doc_ = json_encode($data['contact_info']['contact_id_doc_period_end'],JSON_UNESCAPED_UNICODE);
  146. // $data['contact_info']['contact_id_doc_period_end'] = $doc_;
  147. //}
  148. if(isset($data['contact_info']['contact_id_doc_type']))
  149. {
  150. $data['contact_info']['contact_id_doc_type'] = $this->getIdDocType($data['contact_info']['contact_id_doc_type']);
  151. }
  152. if(isset($data['contact_info']['contact_id_doc_copy'])) {
  153. $contact_id_doc_copy = $data['contact_info']['contact_id_doc_copy']->media_id;
  154. unset($data['contact_info']['contact_id_doc_copy']);
  155. $data['contact_info']['contact_id_doc_copy'] = $contact_id_doc_copy;
  156. }
  157. if(isset($data['contact_info']['contact_id_doc_copy_back'])) {
  158. $contact_id_doc_copy_back = $data['contact_info']['contact_id_doc_copy_back']->media_id;
  159. unset($data['contact_info']['contact_id_doc_copy_back']);
  160. $data['contact_info']['contact_id_doc_copy_back'] = $contact_id_doc_copy_back;
  161. }
  162. if(isset($data['contact_info']['business_authorization_letter'])) {
  163. $business_authorization_letter = $data['contact_info']['business_authorization_letter']->media_id;
  164. unset($data['contact_info']['business_authorization_letter']);
  165. $data['contact_info']['business_authorization_letter'] = $business_authorization_letter;
  166. }
  167. }
  168. //其他证件
  169. if(isset($data['id_doc_info'])){
  170. $doc_ = json_encode($data['id_doc_info']['doc_period_end'],JSON_UNESCAPED_UNICODE);
  171. $data['id_doc_info']['doc_period_end'] = $doc_;
  172. if(isset($data['id_doc_info']['id_doc_copy'])) {
  173. $id_doc_copy = $data['id_doc_info']['id_doc_copy']->media_id;
  174. unset($data['id_doc_info']['id_doc_copy']);
  175. $data['id_doc_info']['id_doc_copy'] = $id_doc_copy;
  176. }
  177. if(isset($data['id_doc_info']['id_doc_copy_back'])) {
  178. $id_doc_copy_back = $data['id_doc_info']['id_doc_copy_back']->media_id;
  179. unset($data['id_doc_info']['id_doc_copy_back']);
  180. $data['id_doc_info']['id_doc_copy_back'] = $id_doc_copy_back;
  181. }
  182. }
  183. //店铺信息
  184. if(isset($data['sales_scene_info']['store_qr_code']) && $data['sales_scene_info']['store_qr_code']){
  185. $store_qr_code= $data['sales_scene_info']['store_qr_code']->media_id;
  186. unset($data['sales_scene_info']['store_qr_code']);
  187. $data['sales_scene_info']['store_qr_code'] = $store_qr_code;
  188. }
  189. //特殊资质
  190. if(isset($data['qualifications']) && !empty($data['qualifications'])){
  191. $qualifications = [];
  192. foreach ($data['qualifications'] as $item){
  193. $qualifications[] = $item->media_id;
  194. }
  195. unset($data['qualifications']);
  196. $data['qualifications'] = json_encode($qualifications,JSON_UNESCAPED_UNICODE);
  197. }
  198. //补充材料
  199. if(isset($data['business_addition_pics']) && !empty($data['business_addition_pics'])){
  200. $business_addition_pics = [];
  201. foreach ($data['business_addition_pics'] as $item){
  202. $business_addition_pics[] = $item->media_id;
  203. }
  204. unset($data['business_addition_pics']);
  205. $data['business_addition_pics'] = json_encode($business_addition_pics,JSON_UNESCAPED_UNICODE);
  206. }
  207. $data['organization_type'] = (string)$data['organization_type'];
  208. return $data;
  209. }
  210. /**
  211. * 生成申请单
  212. * @param $merId
  213. * @return string
  214. * @author Qinii
  215. * @day 6/24/21
  216. */
  217. public function getOutRequestNo($merId)
  218. {
  219. list($msec, $sec) = explode(' ', microtime());
  220. $msectime = number_format((floatval($msec) + floatval($sec)) * 1000, 0, '', '');
  221. $key = 'MERCHANT' . $merId . '_' . $msectime . mt_rand(10000, max(intval($msec * 10000) + 10000, 98369));
  222. do{
  223. $ret = $this->dao->getSearch(['out_request_no' => $key])->count();
  224. }while($ret);
  225. return $key;
  226. }
  227. /**
  228. * 详情
  229. * @param $id
  230. * @param $merId
  231. * @return array|\think\Model|null
  232. * @author Qinii
  233. * @day 6/22/21
  234. */
  235. public function detail(int $merId)
  236. {
  237. if($merId) $where['mer_id'] = $merId;
  238. $data = $this->dao->getSearch($where)->find();
  239. if(!$data) return [];
  240. $data['info'] = json_decode($data['info']);
  241. return $data;
  242. }
  243. /**
  244. * 编辑
  245. * @param $id
  246. * @param $data
  247. * @author Qinii
  248. * @day 6/22/21
  249. */
  250. public function edit($id,$data)
  251. {
  252. //申请状态: 0.平台未提交,-1.平台驳回,10.平台提交审核中,11.需用户操作 ,20.已完成,30.已冻结,40.驳回
  253. $get = $this->dao->get($id);
  254. if(!$get) throw new ValidateException('数据不存在');
  255. if(!in_array($get['status'],[-1,0,40])) throw new ValidateException('数据当前状态不可编辑');
  256. $out_request_no = $this->getOutRequestNo($get->mer_id);
  257. $data['out_request_no'] = $out_request_no;
  258. $ret['info'] = json_encode($data,JSON_UNESCAPED_UNICODE);
  259. $ret['status'] = 0;
  260. $ret['message'] = '';
  261. $ret['out_request_no'] = $out_request_no;
  262. $ret['applyment_id'] = '';
  263. $this->dao->update($id,$ret);
  264. }
  265. /**
  266. * 查询申请状态
  267. * @param $merId
  268. * @author Qinii
  269. * @day 6/23/21
  270. */
  271. public function check($merId)
  272. {
  273. $ret = $this->dao->getSearch(['mer_id' => $merId])->find();
  274. $data = [];
  275. if($ret['status'] < 10) throw new ValidateException('平台审核中...');
  276. if($ret['status'] == 20) throw new ValidateException('申请已完成,请勿重复查询');
  277. try{
  278. $data = WechatService::create()->applyments()->getApplicationById($ret->applyment_id);
  279. }catch (\Exception $exception){
  280. }
  281. if(!$data){
  282. $data = WechatService::create()->applyments()->getApplicationByNo($ret->out_request_no);
  283. if($data){
  284. $ret->applyment_id = $data['applyment_id'];
  285. $ret->save();
  286. }
  287. }
  288. if($data) {
  289. $result = $this->getApplymentState($data);
  290. $this->sendSms($ret,$result['status']);
  291. return Db::transaction(function () use ($merId, $ret, $result) {
  292. if (isset($result['sub_mchid'])) $this->profitsharingAdd($ret,$result);
  293. $this->dao->update($ret->mer_applyments_id, $result);
  294. });
  295. }else{
  296. return ;
  297. }
  298. }
  299. /**
  300. * 添加分账商户
  301. * @param MerchantApplyments $ret
  302. * @param $result
  303. * @author Qinii
  304. * @day 6/24/21
  305. */
  306. public function profitsharingAdd(MerchantApplyments $ret,$result)
  307. {
  308. $info = json_decode($ret['info']);
  309. $profitsharing = [
  310. "type" => 'MERCHANT_ID',
  311. "account" => $result['sub_mchid'],
  312. // "name" => $info->account_info->account_name,
  313. "relation_type" => "PLATFORM"
  314. ];
  315. $res = WechatService::create()->applyments()->profitsharingAdd($profitsharing);
  316. if(isset($res['account'])) app()->make(MerchantRepository::class)->update($ret->mer_id, ['sub_mchid' => $res['account'] ]);
  317. }
  318. /**
  319. * 查询返回的状态整理
  320. * @param $data
  321. * @return array
  322. * @author Qinii
  323. * @day 6/23/21
  324. */
  325. public function getApplymentState($data)
  326. {
  327. //CHECKING:资料校验中
  328. //ACCOUNT_NEED_VERIFY:待账户验证
  329. //AUDITING:审核中
  330. //REJECTED:已驳回
  331. //NEED_SIGN:待签约
  332. //FINISH:完成
  333. //FROZEN:已冻结
  334. $result = [];
  335. $message = '';
  336. $status = 10;
  337. switch (($data['applyment_state']))
  338. {
  339. //申请状态: 0.平台未提交,-1.平台驳回,10.平台提交审核中,11.需用户操作 ,20.已完成,30.已冻结,40.驳回
  340. case 'ACCOUNT_NEED_VERIFY':
  341. $status = 11;
  342. if(isset($data['account_validation'])){
  343. $ret = $data['account_validation'];
  344. $message = '通过申请银行账号向以下信息汇款完成验证,'.PHP_EOL;
  345. $message .= '收款方信息:'.PHP_EOL;
  346. $message .= "汇款金额:".$ret['pay_amount'].'(单位:分);'.PHP_EOL;
  347. $message .= "收款卡号:".$ret['destination_account_number'].';'.PHP_EOL;
  348. $message .= "收款户名:".$ret['destination_account_name'].';'.PHP_EOL;
  349. $message .= "开户银行:".$ret['destination_account_bank'].';'.PHP_EOL;
  350. $message .= "省市信息:".$ret['city'].';'.PHP_EOL;
  351. $message .= "备注信息:".$ret['remark'].';'.PHP_EOL;
  352. $message .= "汇款截止时间:".$ret['deadline'].'。';
  353. }
  354. if(isset($data['legal_validation_url'])){
  355. $message = '商户法人通过此链接完成验证:'.$data['legal_validation_url'];
  356. }
  357. break;
  358. case 'REJECTED':
  359. $message = '';
  360. foreach ($data['audit_detail'] as $datum){
  361. $message .= '参数名称:'.$datum['param_name'].PHP_EOL;
  362. $message .= '驳回原因:'.$datum['reject_reason'].PHP_EOL;
  363. }
  364. $status = 40;
  365. break;
  366. case 'NEED_SIGN':
  367. $status = 11;
  368. $message = $data['sign_url'];
  369. break;
  370. case 'FINISH':
  371. $result['sub_mchid'] = $data['sub_mchid'];
  372. $status = 20;
  373. $message = '完成';
  374. break;
  375. case 'FROZEN':
  376. $status = 30;
  377. break;
  378. default:
  379. break;
  380. }
  381. $result['status'] = $status;
  382. $result['message'] = $message;
  383. return $result;
  384. }
  385. /**
  386. * 上传图片
  387. * @param $field
  388. * @return array
  389. * @author Qinii
  390. * @day 6/21/21
  391. */
  392. public function uploadImage($field,$water)
  393. {
  394. $upload = UploadService::create(1);
  395. $info = $upload->to('def')->move($field);
  396. if ($info === false) throw new ValidateException($upload->getError());
  397. $res = $upload->getUploadInfo();
  398. $res['path'] = app()->getRootPath().'public'.($res['dir']);
  399. $res['dir'] = tidy_url($res['dir']);
  400. if($res['path']) $ret = WechatService::create()->uploadImages([$res]);
  401. if(!$water) app()->make(ImageWaterMarkService::class)->run($res['path']);
  402. return $ret;
  403. }
  404. /**
  405. * 列表
  406. * @param array $where
  407. * @param int $page
  408. * @param int $limit
  409. * @return array
  410. * @author Qinii
  411. * @day 6/24/21
  412. */
  413. public function getList(array $where, int $page, int $limit)
  414. {
  415. $query = $this->dao->getSearch($where)->with(['merchant' => function($query){
  416. $query->field('mer_id,mer_name');
  417. }])->order('create_time DESC');
  418. $count = $query->count();
  419. $list = $query->page($page,$limit)->select();
  420. return compact('count','list');
  421. }
  422. /**
  423. * 审核操作
  424. * @param int $id
  425. * @param array $data
  426. * @author Qinii
  427. * @day 6/23/21
  428. */
  429. public function switchWithStatus(int $id,array $data)
  430. {
  431. $ret = $this->dao->get($id);
  432. if(!$ret) throw new ValidateException('数据不存在');
  433. if($ret['status'] !== 0) throw new ValidateException('请勿重复审核');
  434. if($data['status'] == 10){
  435. $info = $this->sltData(json_decode($ret['info']));
  436. Db::transaction(function() use($id,$info){
  437. WechatService::create()->applyments()->submitApplication($info);
  438. $this->dao->update($id,['status' => 10]);
  439. });
  440. }
  441. if($data['status'] == -1) {
  442. $this->dao->update($id,$data);
  443. $this->sendSms($ret,-1);
  444. }
  445. return ;
  446. }
  447. /**
  448. * 发送短信
  449. * @param MerchantApplyments $ret
  450. * @param $type
  451. * @author Qinii
  452. * @day 7/9/21
  453. */
  454. public function sendSms(MerchantApplyments $ret,$type)
  455. {
  456. if(!systemConfig('applyments_sms')) return ;
  457. $info = json_decode($ret['info']);
  458. switch ($type)
  459. {
  460. case -1:
  461. $tmp = 'APPLYMENTS_FAIL';
  462. break;
  463. case 11:
  464. $tmp = 'APPLYMENTS_SIGN';
  465. break;
  466. case 20:
  467. $tmp = 'APPLYMENTS_SUCCESS';
  468. break;
  469. case 40:
  470. $tmp = 'APPLYMENTS_FAIL';
  471. break;
  472. default:
  473. return ;
  474. break;
  475. }
  476. Queue::push(SendSmsJob::class,['tempId' => $tmp, 'id' => ['phone'=> $info->contact_info->mobile_phone, 'mer_name' => $info->merchant_shortname]]);
  477. }
  478. /**
  479. * 查询商户的分账信息
  480. * @param $merId
  481. * @return mixed
  482. * @author Qinii
  483. * @day 6/24/21
  484. */
  485. public function getMerchant($merId)
  486. {
  487. $data = app()->make(MerchantRepository::class)->get($merId);
  488. if(!$data) throw new ValidateException('数据不存在');
  489. if(!$data['sub_mchid']) throw new ValidateException('该商户不是分账商户');
  490. $ret = WechatService::create()->applyments()->getSubMerchant($data['sub_mchid']);
  491. return $ret;
  492. }
  493. /**
  494. * 备注
  495. * @param $id
  496. * @return \FormBuilder\Form
  497. * @author Qinii
  498. * @day 7/5/21
  499. */
  500. public function markForm($id)
  501. {
  502. $data = $this->dao->get($id);
  503. $form = Elm::createForm(Route::buildUrl('systemMerchantApplymentsMarrkSave', ['id' => $id])->build());
  504. $form->setRule([
  505. Elm::text('mark', '备注:', $data['mark'])->placeholder('请输入备注')->required(),
  506. ]);
  507. return $form->setTitle('修改备注');
  508. }
  509. /**
  510. * 经营者/法人证件类型
  511. * @param $key
  512. * @return array|mixed
  513. * @author Qinii
  514. * @day 6/22/21
  515. */
  516. public function getIdDocType($key)
  517. {
  518. $data = [
  519. 1 => self::IDCARD,
  520. 2 => self::PASSPORT,
  521. 3 => self::HONGKONG,
  522. 4 => self::MACAO,
  523. 5 => self::TAIWAN,
  524. 6 => self::FOREIGN_RESIDENT,
  525. 7 => self::MACAO_RESIDENT,
  526. 8 => self::TAIWAN_RESIDENT,
  527. ];
  528. if($key) return $data[$key];
  529. return $data;
  530. }
  531. }