Lesson.php 37 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060
  1. <?php
  2. namespace app\api\controller;
  3. use app\common\controller\Api;
  4. use think\Db;
  5. /**
  6. * 售课
  7. */
  8. class Lesson extends Api
  9. {
  10. // 无需登录的接口,*表示全部
  11. protected $noNeedLogin = [];
  12. // 无需鉴权的接口,*表示全部
  13. protected $noNeedRight = ['*'];
  14. //售课列表
  15. public function lists(){
  16. $list = Db::name('lesson')->where('is_show',1)->order('weigh desc')->autopage()->select();
  17. $list = list_domain_image($list,['image']);
  18. $list = $this->list_lang($list,['name','title','info','shiherenqun','pingjunrenshu','sirenkecheng','daoshi']);
  19. $this->success(1,$list);
  20. }
  21. //售课分类列表
  22. public function lesson_cate(){
  23. $list = Db::name('lesson_cate')->order('id asc')->select();
  24. $list = $this->list_lang($list,['name']);
  25. $this->success(1,$list);
  26. }
  27. //日历列表
  28. //教练列表
  29. public function coach_list(){
  30. $list = Db::name('coach')->field('id,nickname,avatar')->where('status',1)->order('nickname asc')->select();
  31. $list = list_domain_image($list,['avatar']);
  32. $this->success(1,$list);
  33. }
  34. //课时列表首页
  35. //根据年,月获取当月剩余日期,有课程的标记1
  36. public function slot_index(){
  37. $getdate = input('date',date('Y-m'));
  38. if(empty($getdate)){
  39. $getdate = date('Y-m');
  40. }
  41. $year = substr($getdate,0,4);
  42. $month = substr($getdate,-2,2);
  43. //今天是哪日
  44. if($year == date('Y') && $month == date('m')){
  45. //如果是今年今月,默认今天开始
  46. $startday = date('d');
  47. }else{
  48. //从1号开始
  49. $startday = '01';
  50. }
  51. //所有课程点进来的 额外传参
  52. $lesson_id = input('lesson_id',0);
  53. if($lesson_id){
  54. $first_starttime = Db::name('lesson_slot')->where('lesson_id',$lesson_id)->where('status',0)->where('starttime','gt',time())->where('is_show',1)->order('starttime asc')->value('starttime');
  55. // $first_startdate = date('Y-m-d H:i:s',$first_starttime);dump($first_startdate);exit;
  56. if($first_starttime){
  57. $year = date('Y',$first_starttime);
  58. $month = date('m',$first_starttime);
  59. $startday = date('d',$first_starttime);
  60. }
  61. }
  62. //一周
  63. $week_arr = [
  64. 1 => '周一',
  65. 2 => '周二',
  66. 3 => '周三',
  67. 4 => '周四',
  68. 5 => '周五',
  69. 6 => '周六',
  70. 7 => '周日',
  71. ];
  72. //本月结束日
  73. $endday_arr = [
  74. '01' => 31,
  75. '02' => 28,
  76. '03' => 31,
  77. '04' => 30,
  78. '05' => 31,
  79. '06' => 30,
  80. '07' => 31,
  81. '08' => 31,
  82. '09' => 30,
  83. '10' => 31,
  84. '11' => 30,
  85. '12' => 31,
  86. ];
  87. if($year%4 == 0){
  88. $endday_arr['02'] = 29;
  89. }
  90. $endday = $endday_arr[$month];
  91. //拿数据
  92. $startdate = $getdate.'-'.$startday;
  93. $enddate = $getdate.'-'.$endday;
  94. $where = [
  95. 'starttime' => ['BETWEEN',[strtotime($startdate),strtotime($enddate)+86399]],
  96. 'status' => 0,
  97. 'is_show' => 1,
  98. ];
  99. //dump($where);exit;
  100. $slots = Db::name('lesson_slot')->where($where)->field('id,starttime')->select();
  101. $date_arr = [];
  102. for($i=intval($startday);$i<=$endday;$i++){
  103. $j = $i;
  104. if($j < 10){
  105. $j = 0 . $j;
  106. }
  107. $idate = $year.'-'.$month.'-'.$j;
  108. $itime = strtotime($idate);
  109. $week = $this->lang == 'en' ? date('D',$itime) : $week_arr[date('N',$itime)];
  110. $i_data = [
  111. 'yeah' =>$year,
  112. 'month'=>$month,
  113. 'day' => $j.'',
  114. 'date' => $idate,
  115. 'week' => $week,
  116. 'is_today' => 0,
  117. 'slot_num' => 0,
  118. 'date_show'=> $this->lang == 'en' ? $j.'.'.$month : $month.'.'.$j,
  119. ];
  120. foreach($slots as $slot){
  121. if(date('Y-m-d',$slot['starttime']) == $idate)
  122. {
  123. $i_data['slot_num'] += 1;
  124. }
  125. }
  126. if($idate == date('Y-m-d')){
  127. $i_data['is_today'] = 1;
  128. }
  129. $date_arr[] = $i_data;
  130. }
  131. $this->success(1,$date_arr);
  132. }
  133. //某日课时列表
  134. public function slot_list(){
  135. $date = strtotime(input('date',date('Y-m-d')));
  136. $cate_id = input('cate_id',0);
  137. $coach_id = input('coach_id',0);
  138. //所有课程点进来的 额外传参
  139. $lesson_id = input('lesson_id',0);
  140. $where = [
  141. 'slot.starttime' => ['BETWEEN',[$date,$date+86399]],
  142. 'slot.status' => 0,
  143. 'slot.is_show' => 1,
  144. ];
  145. //课时
  146. $list = Db::name('lesson_slot')->alias('slot')
  147. ->field('slot.*,lesson.name,lesson.name_en,lesson.image,lesson.price')
  148. ->join('lesson','slot.lesson_id = lesson.id','LEFT')
  149. ->where($where);
  150. if($lesson_id){
  151. $list->where('slot.lesson_id',$lesson_id);
  152. }else{
  153. if($cate_id){
  154. $list->where('lesson.lessoncate_id',$cate_id);
  155. }
  156. if($coach_id){
  157. $list->where('find_in_set(:coach_ids,coach_ids)', ['coach_ids' => $coach_id]);
  158. }
  159. }
  160. $list = $list->order('slot.starttime asc')->select();
  161. if(empty($list)){
  162. $this->success(1,[]);
  163. }
  164. $list = list_domain_image($list,['image']);
  165. $list = $this->list_lang($list,['name']);
  166. //准备教练数据
  167. $coach_list = Db::name('coach')->column('id,nickname');
  168. foreach($list as $key => &$slot){
  169. //hours转换
  170. $slot['hours'] = floatval($slot['hours']);
  171. //放入教练
  172. $coach_text = '';
  173. $coach_ids = explode(',',$slot['coach_ids']);
  174. foreach($coach_ids as $coach_id){
  175. if(isset($coach_list[$coach_id])){
  176. $coach_text .= $coach_list[$coach_id].',';
  177. }
  178. }
  179. $slot['coach_text'] = substr($coach_text,0,-1);
  180. //剩余空位数量
  181. $pay_number = Db::name('lesson_order')->where('slot_id',$slot['id'])->where('order_status',10)->sum('usernumber');
  182. $slot['num_remain'] = $slot['num_max'] - $pay_number;
  183. if($slot['num_remain'] < 0){
  184. $slot['num_remain'] = 0;
  185. }
  186. //剩余候补数量
  187. $slot['wait_remain'] = 0;
  188. if($slot['waitnum_max'] > 0){
  189. $wait_number = Db::name('lesson_order')->where('slot_id',$slot['id'])->where('jointype',2)->sum('usernumber');
  190. $slot['wait_remain'] = $slot['waitnum_max'] - $wait_number;
  191. if($slot['wait_remain'] < 0){
  192. $slot['wait_remain'] = 0;
  193. }
  194. }
  195. //预约按钮,1能预约,0不能
  196. $slot['button_status'] = 0;
  197. if($slot['status'] == 0 && $slot['num_remain'] > 0){
  198. $slot['button_status'] = 1;//能预约
  199. }
  200. if($slot['status'] == 0 && $slot['wait_remain'] > 0){
  201. $slot['button_status'] = 2;//能候补
  202. }
  203. //右上角备注
  204. if(time() >= $slot['starttime']){
  205. $slot['num_remark'] = __('报名已截止');
  206. $slot['button_status'] = 0;//报名截止了,强制改
  207. }else{
  208. // $slot['num_remark'] = __('剩N个名额',['number'=>$slot['num_remain']]);
  209. $slot['num_remark'] = __('预约:').$pay_number.'/'.$slot['num_max'];
  210. if($slot['waitnum_max'] > 0){
  211. $slot['num_remark'] .= '--'. __('候补:') .$wait_number.'/'.$slot['waitnum_max'];
  212. }
  213. }
  214. }
  215. $this->success(1,$list);
  216. }
  217. public function test(){
  218. echo __('剩N个名额',['number'=>8]);
  219. }
  220. //课时详情
  221. public function slot_info(){
  222. $slot_id = input('slot_id',0);
  223. $number = input('number',1,'intval');
  224. //课时
  225. $info = Db::name('lesson_slot')->alias('slot')
  226. ->field('slot.*,lesson.name,lesson.name_en,lesson.image,lesson.price')
  227. ->join('lesson','slot.lesson_id = lesson.id','LEFT')
  228. ->where('slot.id',$slot_id)->where('slot.is_show',1)->find();
  229. if(empty($info)){
  230. $this->error('课程可能已取消,请刷新重试');
  231. }
  232. $info = info_domain_image($info,['image']);
  233. $info = $this->info_lang($info,['name']);
  234. //准备教练数据
  235. $coach_list = Db::name('coach')->where('id','IN',$info['coach_ids'])->column('nickname');
  236. $info['coach_text'] = implode(',',$coach_list);
  237. //剩余空位数量
  238. $pay_number = Db::name('lesson_order')->where('slot_id',$info['id'])->where('order_status',10)->sum('usernumber');
  239. $info['num_remain'] = $info['num_max'] - $pay_number;
  240. if($info['num_remain'] < 0){
  241. $info['num_remain'] = 0;
  242. }
  243. //剩余候补数量
  244. $info['wait_remain'] = 0;
  245. $info['wait_number'] = 0;
  246. if($info['waitnum_max'] > 0){
  247. $wait_number = Db::name('lesson_order')->where('slot_id',$info['id'])->where('jointype',2)->sum('usernumber');
  248. $info['wait_number'] = $wait_number;
  249. $info['wait_remain'] = $info['waitnum_max'] - $wait_number;
  250. if($info['wait_remain'] < 0){
  251. $info['wait_remain'] = 0;
  252. }
  253. }
  254. //时间
  255. if($this->lang == 'en'){
  256. $info['slot_time'] = date('M d',$info['starttime']).'('.date('D',$info['starttime']).')'.','.date('H:i',$info['starttime']).'-'.date('H:i',$info['endtime']);
  257. }else{
  258. $info['slot_time'] = date('n月d',$info['starttime']).'(周'.date('N',$info['starttime']).')'.','.date('H:i',$info['starttime']).'-'.date('H:i',$info['endtime']);
  259. }
  260. //是否有可买配套
  261. $wait_buy_package = Db::name('lesson_package')
  262. ->where('find_in_set(:lesson_ids,lesson_ids)', ['lesson_ids' => $info['lesson_id']])
  263. ->where('is_show',1)
  264. ->find();
  265. $info['wait_buy_package'] = !empty($wait_buy_package) ? 1 : 0;
  266. //预约按钮,1能预约,0不能
  267. $info['button_status'] = 0;
  268. if($info['status'] == 0 && $info['num_remain'] > 0){
  269. $info['button_status'] = 1;//能预约
  270. }
  271. if($info['status'] == 0 && $info['wait_remain'] > 0){
  272. $info['button_status'] = 2;//能候补
  273. }
  274. //右上角备注
  275. if(time() >= $info['starttime']){
  276. $info['button_status'] = 0;//报名截止了,强制改
  277. }
  278. //总价格乘出来
  279. $info['price'] = bcmul($info['price'],$number,2);
  280. //此课程是否还有未使用的套餐(多个包含赠送的)
  281. $number_hours = bcmul($number,$info['hours'],1);//每日课时按小时扣
  282. $map = [
  283. 'o.user_id' =>$this->auth->id,
  284. 'o.endtime' => ['gt',time()],
  285. 'o.remain' => ['egt',$number_hours], //不能只是大于0,还得大于等于报名人数
  286. 'o.order_status' => 1,
  287. // 'o.use_status' => 1, //已激活的。未激活的也要展示,但是变灰
  288. ];
  289. $package_list = Db::name('package_order')->alias('o')
  290. ->join('lesson_package p','o.package_id = p.id','LEFT')
  291. ->field('o.id,o.remain,o.starttime,o.endtime,o.is_gift,p.name,p.name_en')
  292. ->where($map)
  293. ->where('find_in_set(:lesson_ids,o.lesson_ids)', ['lesson_ids' => $info['lesson_id']])
  294. ->order('o.endtime asc')->select();
  295. $package_list = $this->list_lang($package_list,['name']);
  296. if(!empty($package_list)){
  297. foreach($package_list as $key => &$val){
  298. //转换remain
  299. $val['remain'] = floatval($val['remain']);
  300. if($this->lang == 'zh-cn'){
  301. $val['time_text'] = date('m月d,Y',$val['starttime']).'-'.date('m月d,Y',$val['endtime']);
  302. }else{
  303. $val['time_text'] = date('M d,Y',$val['starttime']).'-'.date('M d,Y',$val['endtime']);
  304. }
  305. }
  306. }
  307. $info['package_list'] = $package_list;
  308. //可用试课
  309. if($number == 1){
  310. $try_map = [
  311. 'o.user_id' => $this->auth->id,
  312. 'o.endtime' => ['gt',time()],
  313. 'o.order_status' => 10,
  314. ];
  315. $tryorder_list = Db::name('trylesson_order')->alias('o')
  316. ->join('trylesson','o.trylesson_id = trylesson.id','LEFT')
  317. ->field('o.id,o.starttime,o.endtime,trylesson.name,trylesson.name_en')
  318. ->where($try_map)
  319. ->where('find_in_set(:lesson_ids,o.lesson_ids)', ['lesson_ids' => $info['lesson_id']])
  320. ->order('o.endtime asc')->select();
  321. $tryorder_list = $this->list_lang($tryorder_list,['name']);
  322. if(!empty($tryorder_list)){
  323. foreach($tryorder_list as $key => &$val){
  324. if($this->lang == 'zh-cn'){
  325. $val['time_text'] = date('m月d,Y',$val['starttime']).'-'.date('m月d,Y',$val['endtime']);
  326. }else{
  327. $val['time_text'] = date('M d,Y',$val['starttime']).'-'.date('M d,Y',$val['endtime']);
  328. }
  329. }
  330. }
  331. }else{
  332. $tryorder_list = [];
  333. }
  334. $info['tryorder_list'] = $tryorder_list;
  335. //hours转换
  336. $info['hours'] = floatval($info['hours']);
  337. $this->success(1,$info);
  338. }
  339. //课时申请报名,提前预判
  340. public function slot_apply_before(){
  341. $this->apiLimit();
  342. $slot_id = input('slot_id',0,'intval');
  343. $number = input('number',1,'intval');
  344. if($number <= 0){
  345. $this->error('预约人数错误');
  346. }
  347. //课时
  348. $info = Db::name('lesson_slot')->alias('slot')
  349. ->field('slot.*,lesson.name,lesson.name_en,lesson.image,lesson.price')
  350. ->join('lesson','slot.lesson_id = lesson.id','LEFT')
  351. ->where('slot.id',$slot_id)->where('slot.status',0)->where('slot.is_show',1)->find();
  352. if(empty($info)){
  353. $this->error('课程可能已取消,请刷新重试');
  354. }
  355. if($info['endtime'] < time()){
  356. $this->error('课程已经结束了,不能再进行预约');
  357. }
  358. //剩余空位数量
  359. $pay_number = Db::name('lesson_order')->where('slot_id',$slot_id)->where('order_status',10)->sum('usernumber');
  360. $num_remain = $info['num_max'] - $pay_number;
  361. if($num_remain < 0){
  362. $num_remain = 0;
  363. }
  364. //预约数量足够
  365. if($num_remain >= $number){
  366. $this->success('success',1);
  367. }
  368. //剩余候补数量
  369. $wait_remain = 0;
  370. if($info['waitnum_max'] > 0){
  371. $wait_number = Db::name('lesson_order')->where('slot_id',$info['id'])->where('jointype',2)->sum('usernumber');
  372. $wait_remain = $info['waitnum_max'] - $wait_number;
  373. if($wait_remain < 0){
  374. $wait_remain = 0;
  375. }
  376. }
  377. //候补数量足够
  378. if($wait_remain >= $number){
  379. $this->success(__('预约空位不足,是否转为候补?'),2);
  380. }
  381. //两者都不够了
  382. $this->error('可预约名额不足');
  383. }
  384. //课时申请报名
  385. public function slot_apply(){
  386. $this->apiLimit();
  387. $slot_id = input('slot_id',0,'intval');
  388. $number = input('number',1,'intval');
  389. $remark = input('remark','','trim');
  390. $paytype = input('paytype',1,'intval');//支付类型:1=课程套餐,2=线上付款,3=购买套餐中,4=试课单,5=候补
  391. $packageorder_id = input('packageorder_id',0,'intval');
  392. $trylessonorder_id = input('trylessonorder_id',0,'intval');
  393. $jointype = input('jointype',1);//预约类型:1=预约,2=候补
  394. if($number <= 0){
  395. $this->error('预约人数错误');
  396. }
  397. if(!in_array($paytype,[1,2,3,4])){
  398. $this->error();
  399. }
  400. if(!in_array($jointype,[1,2])){
  401. $this->error();
  402. }
  403. //课时
  404. $info = Db::name('lesson_slot')->alias('slot')
  405. ->field('slot.*,lesson.name,lesson.name_en,lesson.image,lesson.price')
  406. ->join('lesson','slot.lesson_id = lesson.id','LEFT')
  407. ->where('slot.id',$slot_id)->where('slot.status',0)->where('slot.is_show',1)->find();
  408. if(empty($info)){
  409. $this->error('课程可能已取消,请刷新重试');
  410. }
  411. if($info['endtime'] < time()){
  412. $this->error('课程已经结束了,不能再进行预约');
  413. }
  414. //剩余空位数量
  415. $pay_number = Db::name('lesson_order')->where('slot_id',$slot_id)->where('order_status',10)->sum('usernumber');
  416. $num_remain = $info['num_max'] - $pay_number;
  417. if($num_remain < 0){
  418. $num_remain = 0;
  419. }
  420. //剩余候补数量
  421. $wait_remain = 0;
  422. if($info['waitnum_max'] > 0){
  423. $wait_number = Db::name('lesson_order')->where('slot_id',$info['id'])->where('jointype',2)->sum('usernumber');
  424. $wait_remain = $info['waitnum_max'] - $wait_number;
  425. if($wait_remain < 0){
  426. $wait_remain = 0;
  427. }
  428. }
  429. //报名人数不能超限
  430. if($jointype == 1){
  431. if($num_remain < $number){
  432. $this->error(__('预约名额只剩N名',['number'=>$num_remain]));
  433. }
  434. //可以继续
  435. }else{
  436. /*if($num_remain > 0){
  437. $this->error(__('预约还有名额,不能候补'));
  438. }*/
  439. //候补人数不能超限
  440. if($wait_remain < $number){
  441. $this->error(__('候补名额只剩N名',['number'=>$wait_remain]));
  442. }
  443. //可以继续
  444. $paytype = 5;//强改支付方式,候补
  445. }
  446. //
  447. $number_hours = bcmul($number,$info['hours'],1);//每日课时按小时扣
  448. $lesson_order = [
  449. 'order_no' => createUniqueNo('S',$this->auth->id),
  450. 'user_id' => $this->auth->id,
  451. 'slot_id' => $slot_id,
  452. 'lesson_id' => $info['lesson_id'],
  453. 'order_amount' => bcmul($info['price'],$number,2),
  454. 'order_status' => 0,
  455. 'paytype' => $paytype, //支付类型:1=课程套餐,2=线上付款,3=购买套餐中,4=试课单,5=候补
  456. 'paytime' => 0,
  457. 'createtime' => time(),
  458. // 'updatetime' => ,
  459. // 'finishtime' => ,
  460. 'usernumber' => $number,
  461. 'usernumber_hours' => $number_hours,
  462. 'userremark' => $remark,
  463. 'package_order_id' => 0,
  464. 'package_remark' => '',// 比如:5/30,5-7/30
  465. 'jointype' => $jointype,
  466. ];
  467. //
  468. Db::startTrans();
  469. if($paytype == 1){
  470. //检查已选择套餐
  471. $map = [
  472. 'user_id' =>$this->auth->id,
  473. 'endtime' => ['gt',time()],
  474. 'remain' => ['gt',0],
  475. 'order_status' => 1,
  476. // 'use_status' => 1, //已激活的
  477. 'id' => $packageorder_id,
  478. ];
  479. $package_order = Db::name('package_order')->where($map)->where('find_in_set(:lesson_ids,lesson_ids)', ['lesson_ids' => $info['lesson_id']])->lock(true)->find();
  480. if(!$package_order){
  481. Db::rollback();
  482. $this->error('配套信息不正确,请刷新重试');
  483. }
  484. //课时不足支撑报名人数
  485. if($package_order['remain'] < $number_hours){
  486. Db::rollback();
  487. $this->error('该配套余额不足,可以使用其他支付方式');
  488. }
  489. if($package_order['use_status'] != 1){
  490. Db::rollback();
  491. $this->error('该配套尚未激活');
  492. }
  493. //扣除一节
  494. $update = [
  495. 'remain' => bcsub($package_order['remain'],$number_hours,1),
  496. 'updatetime' => time(),
  497. ];
  498. $rs1 = Db::name('package_order')->where('id',$packageorder_id)->update($update);
  499. if($rs1 === false){
  500. Db::rollback();
  501. $this->error('扣除套餐余额失败');
  502. }
  503. //修改预约单数据
  504. $lesson_order['order_amount'] = 0;
  505. $lesson_order['order_status'] = 10;
  506. $lesson_order['paytime'] = time();
  507. $lesson_order['package_order_id'] = $packageorder_id;
  508. $lesson_order['package_remark'] = ($package_order['sessions'] - $package_order['remain']) . '-' . ($package_order['sessions'] - $package_order['remain'] + $number_hours) .'/'. $package_order['sessions'];
  509. //预约单写入
  510. $lesson_order_id = Db::name('lesson_order')->insertGetId($lesson_order);
  511. if(!$lesson_order_id){
  512. Db::rollback();
  513. $this->error('预约失败');
  514. }
  515. //更新已预约人数
  516. $pay_number = Db::name('lesson_order')->where('slot_id',$slot_id)->where('order_status',10)->sum('usernumber');
  517. $rs_slot = Db::name('lesson_slot')->where('id',$slot_id)->update(['bookednum' => $pay_number]);
  518. if($rs_slot === false){
  519. Db::rollback();
  520. $this->error('预约失败');
  521. }
  522. Db::commit();
  523. $this->success('预约成功',['returntype'=>1]);
  524. }
  525. elseif($paytype == 2)
  526. {
  527. //预约单写入
  528. $lesson_order_id = Db::name('lesson_order')->insertGetId($lesson_order);
  529. if(!$lesson_order_id){
  530. Db::rollback();
  531. $this->error('预约失败');
  532. }
  533. //支付订单下单
  534. $pay_order = [];
  535. $pay_order['user_id'] = $lesson_order['user_id'];
  536. $pay_order['out_trade_no'] = $lesson_order['order_no'];
  537. $pay_order['order_amount'] = $lesson_order['order_amount'];
  538. $pay_order['createtime'] = $lesson_order['createtime'];
  539. $pay_order['pay_type'] = 'hitpay';
  540. $pay_order['platform'] = 'app';
  541. $pay_order['order_status'] = 0;
  542. $pay_order['table_name'] = 'lesson_order';
  543. $pay_order['table_id'] = $lesson_order_id;
  544. $pay_order['args'] = '';
  545. //拉起支付
  546. $notify_url = config('notify_cdnurl');
  547. $redirect_cdnurl = config('hitpay.lesson_redirect_cdnurl').'?out_trade_no='.$pay_order['out_trade_no'].'&lang='.$this->lang;
  548. $hitpay_return = $this->hitpay_payment($pay_order['out_trade_no'],$pay_order['order_amount'],$notify_url,$redirect_cdnurl);
  549. if($hitpay_return['status'] !== true){
  550. $this->error($hitpay_return['msg']);
  551. }
  552. //支付请求id
  553. $pay_order['payment_request_id'] = $hitpay_return['id'];
  554. $pay_order_id = Db::name('pay_order')->insertGetId($pay_order);
  555. if(!$pay_order_id){
  556. Db::rollback();
  557. $this->error('下单失败');
  558. }
  559. Db::commit();
  560. $return = [
  561. 'url' => $hitpay_return['url'],
  562. 'id' => $hitpay_return['id'],
  563. 'returntype' => 2,
  564. ];
  565. $this->success(1,$return);
  566. }
  567. elseif($paytype == 3)
  568. {
  569. //预约单写入
  570. $lesson_order['order_amount'] = 0;
  571. $lesson_order_id = Db::name('lesson_order')->insertGetId($lesson_order);
  572. if(!$lesson_order_id){
  573. Db::rollback();
  574. $this->error('预约失败');
  575. }
  576. Db::commit();
  577. //去购买套餐,参数代入过去
  578. $return = [
  579. 'lesson_order_id' => $lesson_order_id,
  580. 'returntype' => 3,
  581. ];
  582. $this->success(1,$return);
  583. }
  584. elseif($paytype == 4)
  585. {
  586. //使用试课单
  587. $map = [
  588. 'id' => $trylessonorder_id,
  589. 'user_id' =>$this->auth->id,
  590. 'endtime' => ['gt',time()],
  591. 'order_status' => 10,
  592. ];
  593. $trylesson_order = Db::name('trylesson_order')->where($map)->where('find_in_set(:lesson_ids,lesson_ids)', ['lesson_ids' => $info['lesson_id']])->lock(true)->find();
  594. if(!$trylesson_order){
  595. Db::rollback();
  596. $this->error('试课信息不正确,请刷新重试');
  597. }
  598. //修改预约单数据
  599. $lesson_order['order_amount'] = 0;
  600. $lesson_order['order_status'] = 10;
  601. $lesson_order['paytime'] = time();
  602. $lesson_order['trylesson_order_id'] = $trylessonorder_id;
  603. //预约单写入
  604. $lesson_order_id = Db::name('lesson_order')->insertGetId($lesson_order);
  605. if(!$lesson_order_id){
  606. Db::rollback();
  607. $this->error('预约失败');
  608. }
  609. //改掉试课单状态
  610. $update = [
  611. 'order_status' => 20,
  612. 'updatetime' => time(),
  613. 'lesson_order_id' => $lesson_order_id,
  614. ];
  615. $rs1 = Db::name('trylesson_order')->where('id',$trylessonorder_id)->update($update);
  616. if($rs1 === false){
  617. Db::rollback();
  618. $this->error('使用试课失败');
  619. }
  620. //更新已预约人数
  621. $pay_number = Db::name('lesson_order')->where('slot_id',$slot_id)->where('order_status',10)->sum('usernumber');
  622. $rs_slot = Db::name('lesson_slot')->where('id',$slot_id)->update(['bookednum' => $pay_number]);
  623. if($rs_slot === false){
  624. Db::rollback();
  625. $this->error('预约失败');
  626. }
  627. Db::commit();
  628. $this->success('预约成功',['returntype'=>4]);
  629. }
  630. elseif($paytype == 5)
  631. {
  632. //检查可用的套餐,找一个就可以
  633. $map = [
  634. 'user_id' =>$this->auth->id,
  635. 'endtime' => ['gt',time()],
  636. 'remain' => ['gt',$number_hours],
  637. 'order_status' => 1,
  638. 'use_status' => 1, //已激活的
  639. ];
  640. $package_order = Db::name('package_order')->where($map)->where('find_in_set(:lesson_ids,lesson_ids)', ['lesson_ids' => $info['lesson_id']])->find();
  641. if(!$package_order){
  642. Db::rollback();
  643. $this->error('没有找到足够候补人数的配套');
  644. }
  645. //扣除一节。延迟到转正的时候处理
  646. /*$update = [
  647. 'remain' => bcsub($package_order['remain'],$number_hours,1),
  648. 'updatetime' => time(),
  649. ];
  650. $rs1 = Db::name('package_order')->where('id',$packageorder_id)->update($update);
  651. if($rs1 === false){
  652. Db::rollback();
  653. $this->error('扣除套餐余额失败');
  654. }*/
  655. //修改预约单数据。延迟到转正的时候处理
  656. /*$lesson_order['order_amount'] = 0;
  657. $lesson_order['order_status'] = 10;
  658. $lesson_order['paytime'] = time();
  659. $lesson_order['package_order_id'] = $packageorder_id;
  660. $lesson_order['package_remark'] = ($package_order['sessions'] - $package_order['remain']) . '-' . ($package_order['sessions'] - $package_order['remain'] + $number_hours) .'/'. $package_order['sessions'];*/
  661. //预约单写入
  662. $lesson_order_id = Db::name('lesson_order')->insertGetId($lesson_order);
  663. if(!$lesson_order_id){
  664. Db::rollback();
  665. $this->error('预约失败');
  666. }
  667. //更新已预约人数。候补就不需要了
  668. /*$pay_number = Db::name('lesson_order')->where('slot_id',$slot_id)->where('order_status',10)->sum('usernumber');
  669. $rs_slot = Db::name('lesson_slot')->where('id',$slot_id)->update(['bookednum' => $pay_number]);
  670. if($rs_slot === false){
  671. Db::rollback();
  672. $this->error('预约失败');
  673. }*/
  674. Db::commit();
  675. $this->success('预约候补成功',['returntype'=>5]);
  676. }
  677. }
  678. //配套商店 所有套餐列表
  679. public function package_shop(){
  680. $where2 = [];
  681. //排除限购一次的
  682. $map = [
  683. 'o.user_id' => $this->auth->id,
  684. 'o.order_status' => 1,
  685. 'o.is_gift' => 0,
  686. 'p.buytimes' => 1,
  687. ];
  688. $check_first = Db::name('package_order')->alias('o')
  689. ->join('lesson_package p','o.package_id = p.id','LEFT')
  690. ->where($map)->column('o.package_id');
  691. if(!empty($check_first)){
  692. $where2['id'] = ['NOTIN',$check_first];
  693. }
  694. //排除新旧会员群体
  695. if($this->auth->oldstatus == 0){ //新会员
  696. $where2['newuser'] = 1;
  697. }
  698. if($this->auth->oldstatus == 1){ //旧会员
  699. $where2['olduser'] = 1;
  700. }
  701. //套餐列表
  702. $list = Db::name('lesson_package')
  703. ->where('is_show',1)
  704. ->where($where2)
  705. ->order('weigh desc')->select();
  706. $list = list_domain_image($list,['image']);
  707. $list = $this->list_lang($list,['name','validity','activeremark']);
  708. $this->success(1,$list);
  709. }
  710. //从预约过来的 售课套餐列表
  711. public function package_list(){
  712. $lesson_id = input('lesson_id',0);
  713. $where2 = [];
  714. //排除限购一次的
  715. $map = [
  716. 'o.user_id' => $this->auth->id,
  717. 'o.order_status' => 1,
  718. 'o.is_gift' => 0,
  719. 'p.buytimes' => 1,
  720. ];
  721. $check_first = Db::name('package_order')->alias('o')
  722. ->join('lesson_package p','o.package_id = p.id','LEFT')
  723. ->where($map)->column('o.package_id');
  724. if(!empty($check_first)){
  725. $where2['id'] = ['NOTIN',$check_first];
  726. }
  727. //排除新旧会员群体
  728. if($this->auth->oldstatus == 0){ //新会员
  729. $where2['newuser'] = 1;
  730. }
  731. if($this->auth->oldstatus == 1){ //旧会员
  732. $where2['olduser'] = 1;
  733. }
  734. //套餐列表
  735. $list = Db::name('lesson_package')
  736. ->where('find_in_set(:lesson_ids,lesson_ids)', ['lesson_ids' => $lesson_id])
  737. ->where('is_show',1)
  738. ->where($where2)
  739. ->order('weigh desc')->select();
  740. $list = list_domain_image($list,['image']);
  741. $list = $this->list_lang($list,['name','validity','activeremark']);
  742. $this->success(1,$list);
  743. }
  744. //售课套餐详情
  745. public function package_info(){
  746. $package_id = input('package_id',0);
  747. //套餐详情
  748. $list = Db::name('lesson_package')
  749. ->where('id',$package_id)
  750. ->order('weigh desc')->find();
  751. $list = info_domain_image($list,['image']);
  752. $list = $this->info_lang($list,['name','validity','activeremark','content']);
  753. $this->success(1,$list);
  754. }
  755. //下单购买售课套餐
  756. public function package_buy(){
  757. $package_id = input('package_id',0);
  758. $lesson_order_id = input('lesson_order_id',0,'intval');//预约单id
  759. $package_info = Db::name('lesson_package')->where('id',$package_id)->find();
  760. //如果限购,则报错
  761. if($package_info['buytimes'] == 1){
  762. $map = [
  763. 'user_id' => $this->auth->id,
  764. 'order_status' => 1,
  765. 'is_gift' => 0,
  766. 'package_id' => $package_id,
  767. ];
  768. $check_first = Db::name('package_order')->where($map)->find();
  769. if(!empty($check_first)){
  770. $this->error('该配套限购一次,您已经买过了');
  771. }
  772. }
  773. //排除新旧会员群体
  774. if($this->auth->oldstatus == 0 && $package_info['newuser'] != 1 ){ //新会员
  775. $this->error('您不能购买改配套,请刷新并重试');
  776. }
  777. if($this->auth->oldstatus == 1 && $package_info['olduser'] != 1 ){ //旧会员
  778. $this->error('您不能购买改配套,请刷新并重试');
  779. }
  780. //套餐订单
  781. $data = [
  782. 'order_no' => createUniqueNo('P',$this->auth->id),
  783. 'user_id' => $this->auth->id,
  784. 'type' => $package_info['type'],
  785. 'package_id' => $package_id,
  786. 'lesson_ids' => $package_info['lesson_ids'],
  787. 'sessions' => $package_info['sessions'],
  788. 'starttime' => 0,
  789. 'days' => $package_info['days'],
  790. 'endtime' => 0,
  791. 'price' => $package_info['price'],
  792. 'remain' => $package_info['sessions'],
  793. 'order_status'=> 0,
  794. 'use_status' => 0,//默认不激活
  795. 'paytime' => 0,
  796. 'pay_type' => 1, //线上支付
  797. 'createtime' => time(),
  798. 'updatetime' => 0,
  799. 'is_gift' => 0,
  800. ];
  801. //如果有赠品,赠品订单
  802. $gift = [];
  803. if(!empty($package_info['gift_lesson_id']) && !empty($package_info['gift_sessions'])){
  804. $gift = $data;
  805. //订单号不换了
  806. $gift['type'] = $package_info['gift_type'];
  807. $gift['lesson_ids'] = $package_info['gift_lesson_id'];
  808. $gift['sessions'] = $package_info['gift_sessions'];
  809. $gift['remain'] = $package_info['gift_sessions'];
  810. $gift['is_gift'] = 1;
  811. }
  812. //支付订单下单
  813. $pay_order = [];
  814. $pay_order['user_id'] = $data['user_id'];
  815. $pay_order['out_trade_no'] = $data['order_no'];
  816. $pay_order['order_amount'] = $data['price'];
  817. $pay_order['createtime'] = $data['createtime'];
  818. $pay_order['pay_type'] = 'hitpay';
  819. $pay_order['platform'] = 'app';
  820. $pay_order['order_status'] = 0;
  821. $pay_order['table_name'] = 'package_order';
  822. $pay_order['table_id'] = 0;
  823. $pay_order['args'] = json_encode(['lesson_order_id'=>$lesson_order_id]);//用来支付完成回调时,扣除N节课,并改掉预约单的状态
  824. //拉起支付
  825. $notify_url = config('notify_cdnurl');
  826. $redirect_cdnurl = config('hitpay.package_redirect_cdnurl').'?out_trade_no='.$pay_order['out_trade_no'].'&lang='.$this->lang;
  827. $hitpay_return = $this->hitpay_payment($pay_order['out_trade_no'],$pay_order['order_amount'],$notify_url,$redirect_cdnurl);
  828. if($hitpay_return['status'] !== true){
  829. $this->error($hitpay_return['msg']);
  830. }
  831. //支付请求id
  832. $pay_order['payment_request_id'] = $hitpay_return['id'];
  833. //入库
  834. Db::startTrans();
  835. $order_id = Db::name('package_order')->insertGetId($data);
  836. if(!$order_id){
  837. Db::rollback();
  838. $this->error('下单失败');
  839. }
  840. //礼物
  841. if(!empty($gift)){
  842. $gift_order_id = Db::name('package_order')->insertGetId($gift);
  843. if(!$gift_order_id){
  844. Db::rollback();
  845. $this->error('下单失败');
  846. }
  847. }
  848. //支付单
  849. $pay_order['table_id'] = $order_id;
  850. $pay_order_id = Db::name('pay_order')->insertGetId($pay_order);
  851. if(!$pay_order_id){
  852. Db::rollback();
  853. $this->error('下单失败');
  854. }
  855. Db::commit();
  856. $return = [
  857. 'url' => $hitpay_return['url'],
  858. 'id' => $hitpay_return['id'],
  859. ];
  860. $this->success(1,$return);
  861. }
  862. //拉起支付
  863. private function hitpay_payment($out_trade_no,$money,$notifyurl,$redirect_cdnurl)
  864. {
  865. $return = [
  866. 'status' => false,
  867. 'msg' => '',
  868. 'url' => '',
  869. 'id' => 0,
  870. ];
  871. $apiKey = config('hitpay.apikey');
  872. try {
  873. $hitPayClient = new \HitPay\Client($apiKey, true);
  874. $request = new \HitPay\Request\CreatePayment();
  875. $request->setAmount($money)
  876. ->setCurrency('SGD')
  877. ->setRedirectUrl($redirect_cdnurl)
  878. // ->setPaymentMethods(['paynow_online','card'])
  879. ->setPaymentMethods(['paynow_online'])
  880. ->setPurpose('Elin Dance Studio')
  881. ->setWebhook($notifyurl)
  882. ->setReferenceNumber($out_trade_no);
  883. $result = $hitPayClient->createPayment($request);
  884. $return['status'] = true;
  885. $return['url'] = $result->getUrl();
  886. $return['id'] = $result->getId();
  887. //print_r($result);
  888. /*$data = $hitPayClient->getPaymentStatus($result->getId());
  889. dump($data);
  890. dump($data->status);*/
  891. /*$data = $hitPayClient->deletePaymentRequest($data->getId());
  892. print_r($data);*/
  893. } catch (\Exception $e) {
  894. $return['msg'] = $e->getMessage();
  895. }
  896. return $return;
  897. }
  898. }