MerchantApplymentsRepository.php 21 KB

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