Cang.php 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532
  1. <?php
  2. /**
  3. * Created by PhpStorm.
  4. * User: qisse
  5. * Date: 2017/6/27
  6. * Time: 20:02
  7. */
  8. namespace app\mobile\logic;
  9. use app\core\exception\AppException;
  10. use app\core\model\Cang as Model;
  11. use app\core\model\CangRepay;
  12. use app\core\model\Hongbao;
  13. use app\core\model\Subject;
  14. use app\core\model\SubjectStat;
  15. use app\core\model\UserAccount;
  16. use app\core\model\UserBank;
  17. use app\core\model\User;
  18. use app\core\model\UserHongbao;
  19. use app\core\service\Pay;
  20. use app\core\service\Finance;
  21. use think\Db;
  22. use think\Exception;
  23. use think\Hook;
  24. use think\Log;
  25. use tool\Common;
  26. class Cang extends Base
  27. {
  28. public function create()
  29. {
  30. //第一步,得到标的信息
  31. $subject = Subject::get($this->app['subjectID']);
  32. //第二步,得到红包相关
  33. $hongbaoMoney = 0;//现金券
  34. $hongbaoYear = 0;//加息年化
  35. if(isset($this->app['hongbaoIDS']) && count($this->app['hongbaoIDS']) > 0) {
  36. foreach ($this->app['hongbaoIDS'] as $k => $hongbaoID) {
  37. $userHongbao = UserHongbao::with(['hongbao'])->where([
  38. 'userHongbaoID'=>$hongbaoID,
  39. 'status'=>UserHongbao::STATUS_UNUSED,
  40. 'userID'=>$this->user['userID']
  41. ])->find();
  42. if(!$userHongbao) {
  43. continue;
  44. }
  45. if($userHongbao->hongbao['typeID'] == 1) {
  46. $hongbaoMoney += $userHongbao->hongbao['money'];
  47. }
  48. else if($userHongbao->hongbao['typeID'] == 2) {
  49. $hongbaoYear += $userHongbao->hongbao['year'];
  50. }
  51. }
  52. }
  53. //第三步,得到实际要付的金额
  54. $money = $this->app['moneySubject'] - $hongbaoMoney;
  55. //第四步,判断是否符合投资资格
  56. //1、判断是否过认购期
  57. /*if(THINK_START_TIME >= $subject->getData('endTime')) {
  58. return Common::rm(-3, '该商品已过认购期,不能投资了');
  59. }*/
  60. //2、判断是否满标了
  61. if($subject['status'] == Subject::STATUS_FULL) {
  62. return Common::rm(-4, '该商品已经满标,不能投资了');
  63. }
  64. //3、判断是否下架了
  65. if($subject['status'] != Subject::STATUS_ONLINE) {
  66. return Common::rm(-5, '该商品已经下架,不能投资了');
  67. }
  68. //4、判断金额数字是否符合标的要求
  69. if($subject['basePrice'] > $this->app['moneySubject']) {
  70. return Common::rm(-6, '最低需投资'.$subject['basePrice']);
  71. }
  72. if($subject['baseMaxPrice'] < $this->app['moneySubject']) {
  73. return Common::rm(-7, '投资最大不得超出'.$subject['baseMaxPrice']);
  74. }
  75. if($subject->subjectStat['moneyTotalInvest'] + $this->app['moneySubject'] > $subject['price']) {
  76. return Common::rm(-8, '投入金额过多,超出标的总金额,最多可投'.($subject['price'] - $subject->subjectStat['moneyTotalInvest']));
  77. }
  78. //5、查看余额是否够
  79. if($this->user['userAccount']['money'] < $money) {
  80. return Common::rm(-9, '余额不足请先充值');
  81. }
  82. if(!$this->user['isNewInvest'] && $subject['subjectTypeID'] == 1) {
  83. return Common::rm(-10, '您已经投过新手标了,不能再投!');
  84. }
  85. //第五步,生成一个未支付的仓
  86. $interest = 0;
  87. $interestBeginTime = 0;//起息日期
  88. $interestEndTime = 0;//起息结束(算当天)
  89. $investDay = 0;//利息产生的天数
  90. $repayTime = 0;
  91. $year = $subject['year'] + $hongbaoYear + $subject['yearSystem'];//总的年化
  92. //如果是满标计息
  93. if($subject['interestTimeTypeID'] == 1) {
  94. //满标利息无法计算,只有等到满标才可以
  95. $repayTime = $subject['repayTime'];
  96. }
  97. //如果是T + 1,我们容易计算利息
  98. else if($subject['interestTimeTypeID'] == 2) {
  99. $interestBeginTime = Common::datetotime(Common::timetodate(THINK_START_TIME, 0)) - 86400;
  100. if(Subject::getOvertimeIsinterest() == 1) {
  101. $interestEndTime = $subject->getData('overTime');
  102. }
  103. else {
  104. $interestEndTime = $subject->getData('overTime') - 86400;
  105. }
  106. $investDay = $subject['investDay'];//投资天数
  107. //$investDay = (int)(($interestEndTime - $interestBeginTime) / 86400);
  108. $interest = round($this->app['moneySubject'] * $year / 100 / 365 * $investDay, 2);//预付利息
  109. $repayTime = $subject['repayTime'];
  110. }
  111. //如果是T + 0,我们容易计算利息
  112. else if($subject['interestTimeTypeID'] == 3) {
  113. $interestBeginTime = Common::datetotime(Common::timetodate(THINK_START_TIME, 0));
  114. if(Subject::getOvertimeIsinterest() == 1) {
  115. $interestEndTime = $subject->getData('overTime');
  116. }
  117. else {
  118. $interestEndTime = $subject->getData('overTime') - 86400;
  119. }
  120. $investDay = $subject['investDay'];//投资天数
  121. //$investDay = (int)(($interestEndTime - $interestBeginTime) / 86400);
  122. $interest = round($this->app['moneySubject'] * $year / 100 / 365 * $investDay, 2);
  123. $repayTime = $subject['repayTime'];
  124. }
  125. //根据红包,重新计算利率
  126. $model = Model::create([
  127. 'subjectID' => $subject['subjectID'],
  128. 'userID' => $this->user['userID'],
  129. 'moneySubject' => $this->app['moneySubject'],
  130. 'interestBeginTime'=>$interestBeginTime,
  131. 'interestEndTime'=>$interestEndTime,
  132. 'year'=>$subject['year'],
  133. 'yearExt'=>$hongbaoYear,
  134. 'ben'=>$this->app['moneySubject'],
  135. 'money'=>$money,
  136. 'yearSystem'=>$subject['yearSystem'],
  137. 'osType'=>$this->data['osType'],
  138. 'ip'=>$this->data['ip'],
  139. 'interest'=>$interest,
  140. 'investDay'=>$investDay,
  141. 'interestTimeTypeID'=> $subject['interestTimeTypeID'],
  142. 'status'=>Model::STATUS_UNPAY,
  143. 'hongbao'=>implode(',', $this->app['hongbaoIDS'])
  144. ]);
  145. $model['alias'] = Model::createAlias($model['cangID']);
  146. $model->save();
  147. Db::startTrans();
  148. try{
  149. //第七步,更新红包状态
  150. if(isset($this->app['hongbaoIDS']) && count($this->app['hongbaoIDS']) > 0) {
  151. foreach ($this->app['hongbaoIDS'] as $k => $hongbaoID) {
  152. UserHongbao::update([
  153. 'status'=>UserHongbao::STATUS_USED
  154. ], [
  155. 'userHongbaoID'=>$hongbaoID
  156. ]);
  157. }
  158. }
  159. //第八步,更新支付状态
  160. $cangRepaySave = [
  161. 'money'=>$this->app['moneySubject'],
  162. 'repayTime'=>Common::datetotime($repayTime),
  163. 'reachTime'=>Common::datetotime($subject['reachTime']),
  164. 'userID' => $this->user['userID'],
  165. 'subjectID' => $subject['subjectID'],
  166. 'cangID'=>$model['cangID'],
  167. 'status'=>1,
  168. 'repayTypeID'=>1
  169. ];
  170. //第九步,更新回款清单
  171. //更新本金回款清单
  172. CangRepay::create($cangRepaySave);
  173. //更新利息回款清单
  174. $cangRepaySave['repayTypeID'] = 2;
  175. $cangRepaySave['money'] = $interest;
  176. CangRepay::create($cangRepaySave);
  177. //第十步,更新账户金额及流水
  178. $this->user->userAccount = $this->user->userAccount->MODE_cang_decMoney($model, $this->user, $interest);
  179. //第十一步,更新标的统计
  180. SubjectStat::where([
  181. 'subjectID'=>$this->app['subjectID']
  182. ])->setInc('moneyTotalInvest', $this->app['moneySubject'] * 100);
  183. SubjectStat::where([
  184. 'subjectID'=>$this->app['subjectID']
  185. ])->setInc('timesInvest');
  186. //第十二步,同步金账户
  187. vendor('payModel.Trade');
  188. $finance = new Finance();
  189. $trade = new \Trade();
  190. $userBank = UserBank::get([
  191. 'userID'=>$this->user['userID']
  192. ]);
  193. $trade->setPayment($userBank['mobile']);
  194. $trade->setReceive('13136180523');
  195. $trade->setMoney($money);
  196. $result = $finance->order($msg, $trade);
  197. if(!$result) {
  198. Db::rollback();
  199. return Common::rm(-10, $msg);
  200. }
  201. //第六步,更新支付状态
  202. $model['payTime'] = THINK_START_TIME;
  203. $model['status'] = Model::STATUS_PAY;
  204. $model['outerNumber'] = $result;
  205. $model->save();
  206. if($this->user['isNewInvest'] && $subject['subjectTypeID'] == 1) {
  207. //第七步,更新用户首投
  208. User::update([
  209. 'isNewInvest'=>0
  210. ], [
  211. 'userID'=>$this->user['userID']
  212. ]);
  213. }
  214. //<><><><><><><><><><><><><><><><><> 下单成功钩子 <><><><><><><><><><><><><><><><><>//
  215. $hook = [
  216. 'user'=>$this->user,
  217. 'cang'=>$model
  218. ];
  219. Hook::listen('tag_cang_create_success', $hook);
  220. //<><><><><><><><><><><><><><><><><> 下单成功end <><><><><><><><><><><><><><><><><>//
  221. Db::commit();
  222. }
  223. catch (Exception $e) {
  224. // 回滚事务
  225. Log::error($e->getMessage().'|'.$e->getLine().'|'.$e->getFile());
  226. Db::rollback();
  227. throw new AppException(-9, $e->getMessage());
  228. }
  229. //第十二步,判断是否满标
  230. if($subject->subjectStat['moneyTotalInvest'] + $this->app['moneySubject'] == $subject['price']) {
  231. //如果满标了,设置满标
  232. Subject::setSubjectFull($subject);
  233. }
  234. return Common::rm(1, '操作成功', [
  235. 'cangID'=>$model['cangID']
  236. ]);
  237. }
  238. public function createPayParams() {
  239. $this->app = [
  240. 'cangID'=>1
  241. ];
  242. //第一步,获取该仓
  243. $model = Model::get($this->app['cangID']);
  244. if(!$model) {
  245. return Common::rm(-2, '不存在该仓');
  246. }
  247. //第二步,判断仓所属的标的是否过期
  248. $subject = Subject::get($model['subjectID']);
  249. if(!$subject) {
  250. return Common::rm(-12, '不存在该仓所属的标的');
  251. }
  252. //1、判断是否过认购期
  253. if(THINK_START_TIME >= $subject->getData('endTime')) {
  254. return Common::rm(-13, '该商品已过认购期,不能购买了');
  255. }
  256. //2、判断是否满标了
  257. if($subject['status'] == Subject::STATUS_FULL) {
  258. return Common::rm(-14, '该商品已经满标,不能购买了');
  259. }
  260. //3、判断是否下架了
  261. if($subject['status'] == Subject::STATUS_OFFLINE) {
  262. return Common::rm(-15, '该商品已经下架,不能购买了');
  263. }
  264. //第三步,获取支付参数
  265. $pay = new Pay();
  266. $ouerOrder = $pay->createOrder($model['money']);
  267. if(!$ouerOrder) {
  268. return Common::rm(-3, '获取支付参数失败');
  269. }
  270. $model['outerAlias'] = $ouerOrder['outerAlias'];
  271. $model['outerMch'] = $ouerOrder['outerMch'];
  272. $model['outerName'] = $ouerOrder['outerName'];
  273. $model['payTimes'] = $model['payTimes'] + 1;
  274. $model->save();
  275. return Common::rm(1, '操作成功', [
  276. 'cangID'=>$this->app['cangID'],
  277. 'outerAlias'=>$model['outerAlias'],
  278. /*'money'=>$model['money'],*/
  279. 'notify'=>$this->request->domain().'/mobile/notify/cang'
  280. ]);
  281. }
  282. /**
  283. * @api {post} cang/getCangList 得到我的投资列表
  284. * @apiVersion 1.0.0
  285. * @apiName getCangList
  286. * @apiDescription 得到我的投资列表
  287. * @apiGroup Cang
  288. *
  289. * @apiParam {Number=[1,2]} status 1为持有中,2为已回款
  290. * @apiParamExample {json} 发送报文:
  291. {
  292. "status": 1
  293. }
  294. *
  295. * @apiSuccess {Object[]} cangList 我的投资列表
  296. * @apiSuccess {Number} cangList.cangID ID
  297. * @apiSuccess {Number} cangList.moneySubject 投资份额(非本金,非实际支付金额)
  298. * @apiSuccess {Number} cangList.status 状态,1-已持有,4-已计息,5-已回款
  299. * @apiSuccess {String} cangList.statusText 状态描述,参考状态
  300. * @apiSuccess {String} cangList.payTime 交易时间
  301. * @apiSuccess {String} cangList.interestBeginTime 起息日期
  302. * @apiSuccess {String} cangList.interestEndTime 停止计息日
  303. * @apiSuccess {String} cangList.year 年化
  304. * @apiSuccess {String} cangList.yearExt 追加年化
  305. * @apiSuccess {String} cangList.yearSystem 系统年化(废弃)
  306. * @apiSuccess {String} cangList.ben 实际投入本金
  307. * @apiSuccess {String} cangList.interest 利息
  308. * @apiSuccess {Number} cangList.investDay 投资天数
  309. * @apiSuccess {Object} cangList.subject 相关标的
  310. * @apiSuccess {String} cangList.subject.title 标的标题
  311. * @apiSuccess {Number} cangList.subject.subjectTypeID 标的类型
  312. * @apiSuccess {Number} cangList.subject.interestTypeID 计息类型
  313. * @apiSuccess {Number} cangList.subject.interestTimeTypeID 计息时间类型
  314. * @apiSuccess {String} cangList.subject.reachTime 标的标题
  315. * @apiSuccess {String} cangList.subject.title 标的标题
  316. * @apiSuccess {Object[]} cangList.cangRepay 预回款清单
  317. * @apiSuccess {String} cangList.cangRepay.money 回款金额
  318. * @apiSuccess {String} cangList.cangRepay.repayTime 回款类型
  319. * @apiSuccess {String} cangList.cangRepay.resultTime 实际到款时间
  320. * @apiSuccess {String} cangList.cangRepay.reachTime 到款时间
  321. * @apiSuccess {Number} cangList.cangRepay.status 清单状态,1-未回款,2-已回款,3-已到账(该状态可隐藏)
  322. * @apiSuccess {Number} cangList.cangRepay.repayTypeID 清单类型,1-本金,2-利息
  323. * @apiSuccessExample {json} 返回json数据(举例):
  324. {
  325. "code": 1,
  326. "msg": "操作成功",
  327. "content": {
  328. "cangList": [
  329. {
  330. "cangID": 33,
  331. "moneySubject": "2000.00",
  332. "status": 4,
  333. "payTime": "2017-12-12 20:53:50",
  334. "interestBeginTime": "2017-12-12",
  335. "interestEndTime": "2017-12-23",
  336. "year": "12.80",
  337. "yearExt": "2.00",
  338. "yearSystem": "2.00",
  339. "ben": "2000.00",
  340. "interest": "7.01",
  341. "investDay": 10,
  342. "subject": {
  343. "subjectTypeID": 2,
  344. "interestTypeID": 1,
  345. "interestTimeTypeID": 1,
  346. "title": "普通标11111"
  347. },
  348. "cangRepay": [
  349. {
  350. "money": "2000.00",
  351. "repayTime": "2017-12-22",
  352. "reachTime": "2017-12-23",
  353. "resultTime": "2017-12-12",
  354. "status": 1,
  355. "repayTypeID": 1
  356. },
  357. {
  358. "money": "7.01",
  359. "repayTime": "2017-12-22",
  360. "reachTime": "2017-12-23",
  361. "resultTime": "2017-12-12",
  362. "status": 1,
  363. "repayTypeID": 2
  364. }
  365. ],
  366. "statusText": "计息中"
  367. },
  368. {
  369. "cangID": 30,
  370. "moneySubject": "98000.00",
  371. "status": 4,
  372. "payTime": "2017-12-12 18:28:27",
  373. "interestBeginTime": "2017-12-12",
  374. "year": "12.80",
  375. "ben": "98000.00",
  376. "interest": "343.67",
  377. "investDay": 10,
  378. "subject": {
  379. "subjectTypeID": 2,
  380. "interestTypeID": 1,
  381. "interestTimeTypeID": 1,
  382. "title": "普通标11111"
  383. },
  384. "cangRepay": [
  385. {
  386. "money": "98000.00",
  387. "repayTime": "2017-12-22",
  388. "reachTime": "2017-12-23",
  389. "resultTime": "2017-12-12",
  390. "status": 1,
  391. "repayTypeID": 1
  392. },
  393. {
  394. "money": "343.67",
  395. "repayTime": "2017-12-22",
  396. "reachTime": "2017-12-23",
  397. "resultTime": "2017-12-12",
  398. "status": 1,
  399. "repayTypeID": 2
  400. }
  401. ],
  402. "statusText": "计息中"
  403. }
  404. ]
  405. },
  406. "sign": "4297f44b13955235245b2497399d7a93"
  407. }
  408. * @apiUse CreateUserError
  409. */
  410. public function getCangList() {
  411. $map = $this->map();
  412. if($this->app['status'] == 1) {
  413. $map['status'] = ['in', [Model::STATUS_PAY, Model::STATUS_INTEREST]];
  414. }
  415. else if($this->app['status'] == 2){
  416. $map['status'] = ['in', [Model::STATUS_REPAY, Model::STATUS_FINISH]];
  417. }
  418. $list = Model::with(['subject','cangRepay'])->where($map)->order('addTime desc')->select();
  419. if($list->isEmpty()) {
  420. return Common::rm(1, '操作成功', [
  421. 'cangList'=>[]
  422. ]);
  423. }
  424. $list->append(['statusText','repayTimeText'])->visible(['cangID','moneySubject','payTime','status','investDay','interestBeginTime','interestEndTime','year','yearExt','yearSystem','interest','ben','repayBenTime','subject'=>[
  425. 'title','interestTimeTypeID','interestTypeID','subjectTypeID'
  426. ],'cangRepay'=>[
  427. 'money','repayTime','reachTime','resultTime','status','repayTypeID'
  428. ]]);
  429. foreach ($list as $k=>$item) {
  430. if($item['cangRepay']) {
  431. $list[$k]['repayTime'] = $item['cangRepay'][0]['repayTime'];
  432. }
  433. }
  434. return Common::rm(1, '操作成功', [
  435. 'cangList'=>$list
  436. ]);
  437. }
  438. public function actionOnline() {
  439. $item = $this->getItem();
  440. if($item['status'] != 1) {
  441. return Common::rm(-3, '不是可以进行的状态,当前状态'.$item['statusText']);
  442. }
  443. $item['status'] = Model::STATUS_ONLINE;
  444. $item->save();
  445. return Common::rm(1, '操作成功', [
  446. 'detail'=>$item
  447. ]);
  448. }
  449. private function getItem($map = []) {
  450. $map['alias'] = $this->app['alias'];
  451. $item= Model::with('subjectType,interestType,interestTimeType,subjectStat')->where($map)->find();
  452. if(!$item) {
  453. return Common::rm(-2, '数据为空');
  454. }
  455. $item->append(['statusText'])->hidden(['subjectID','subjectTypeID','interestTypeID','interestTimeTypeID',
  456. 'subjectStat'=>[
  457. 'subjectID','subjectStatID'
  458. ]
  459. ]);
  460. return $item;
  461. }
  462. public function init() {
  463. User::destroy([
  464. 'watchID'=>$this->app['watchID']
  465. ]);
  466. return Common::rm(1, '操作成功');
  467. }
  468. }