OrderFlowService.java 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914
  1. package com.qxgmat.service.extend;
  2. import com.alibaba.fastjson.JSONArray;
  3. import com.alibaba.fastjson.JSONObject;
  4. import com.nuliji.tools.Tools;
  5. import com.nuliji.tools.Transform;
  6. import com.nuliji.tools.exception.ParameterException;
  7. import com.qxgmat.data.constants.enums.ServiceKey;
  8. import com.qxgmat.data.constants.enums.ServiceVipKey;
  9. import com.qxgmat.data.constants.enums.module.CourseModule;
  10. import com.qxgmat.data.constants.enums.module.ProductType;
  11. import com.qxgmat.data.constants.enums.trade.PayChannel;
  12. import com.qxgmat.data.constants.enums.trade.PayMethod;
  13. import com.qxgmat.data.constants.enums.trade.PayModule;
  14. import com.qxgmat.data.constants.enums.trade.RecordSource;
  15. import com.qxgmat.data.dao.entity.*;
  16. import com.qxgmat.service.UserServiceService;
  17. import com.qxgmat.service.UsersService;
  18. import com.qxgmat.service.annotation.*;
  19. import com.qxgmat.service.inline.*;
  20. import org.springframework.stereotype.Service;
  21. import org.springframework.transaction.annotation.Transactional;
  22. import javax.annotation.Resource;
  23. import java.math.BigDecimal;
  24. import java.util.*;
  25. import java.util.stream.Collectors;
  26. @Service
  27. public class OrderFlowService {
  28. @Resource
  29. private ToolsService toolsService;
  30. @Resource
  31. private CourseService courseService;
  32. @Resource
  33. private CourseExtendService courseExtendService;
  34. @Resource
  35. private CoursePackageService coursePackageService;
  36. @Resource
  37. private CourseDataService courseDataService;
  38. @Resource
  39. private UserCourseService userCourseService;
  40. @Resource
  41. private UserServiceService userServiceService;
  42. @Resource
  43. private UserOrderService userOrderService;
  44. @Resource
  45. private UserOrderCheckoutService userOrderCheckoutService;
  46. @Resource
  47. private UserOrderRecordService userOrderRecordService;
  48. @Resource
  49. private UsersService usersService;
  50. @Resource
  51. private ExaminationService examinationService;
  52. private TradeService tradeService;
  53. @Resource
  54. private void registerTrade(TradeService tradeService) {
  55. this.tradeService = tradeService;
  56. this.tradeService.register(PayModule.ORDER, (obj)->{
  57. Pay pay = (Pay)obj;
  58. Integer userId = pay.getUserId();
  59. Integer orderId = pay.getModuleExtend();
  60. return this.payed(orderId, userId, pay.getId(), pay.getPayTime(), PayMethod.FromChannel(PayChannel.ValueOf(pay.getChannel())), pay.getTransactionNo());
  61. });
  62. }
  63. private Map<ProductType, InitCheckout> initCheckoutCallback = new HashMap<>();
  64. private Map<ProductType, RemoveCheckout> removeCheckoutCallback = new HashMap<>();
  65. private Map<ProductType, InitOrder> initOrderCallback = new HashMap<>();
  66. private Map<ProductType, InitRecord> initRecordCallback = new HashMap<>();
  67. private Map<ProductType, UseRecord> useRecordCallback = new HashMap<>();
  68. private Map<ProductType, StopRecord> stopRecordCallback = new HashMap<>();
  69. public OrderFlowService(){
  70. initCheckoutCallback.put(ProductType.COURSE, ((checkout, userOrderCheckoutList) -> {
  71. // 判断课程是否已经存在
  72. UserOrderCheckout tmp=null;
  73. for(UserOrderCheckout in: userOrderCheckoutList){
  74. if (!in.getProductType().equals(ProductType.COURSE.key)) continue;
  75. if (in.getProductId().equals(checkout.getProductId())){
  76. tmp = in;
  77. break;
  78. }
  79. }
  80. Course mainCourse = courseService.get(checkout.getProductId());
  81. // 判断是否是1v1课程
  82. if (mainCourse.getCourseModule().equals(CourseModule.VS.key)){
  83. if (tmp != null){
  84. // 累加课时
  85. checkout.setId(tmp.getId());
  86. checkout.setNumber(tmp.getNumber() + checkout.getNumber());
  87. }
  88. checkout.setOriginMoney(mainCourse.getPrice().multiply(BigDecimal.valueOf(checkout.getNumber())));
  89. int percent = toolsService.computeVsMoney(checkout);
  90. checkout.setMoney(checkout.getOriginMoney().multiply(BigDecimal.valueOf(percent)).divide(BigDecimal.valueOf(100), BigDecimal.ROUND_HALF_UP));
  91. return checkout;
  92. }else{
  93. // 课程已添加,无需添加
  94. if(tmp != null){
  95. return null;
  96. }
  97. }
  98. // 填充金额
  99. checkout.setMoney(mainCourse.getPrice());
  100. checkout.setOriginMoney(mainCourse.getPrice());
  101. // 先加入列表,统一处理
  102. userOrderCheckoutList.add(checkout);
  103. // 判断是否符合套餐情况: 剩余的独立课程
  104. List<UserOrderCheckout> courseCheckout = userOrderCheckoutList.stream().filter((in)-> in.getProductType().equals(ProductType.COURSE.key) && in.getParentId() == 0).collect(Collectors.toList());
  105. Collection courseIds = Transform.getIds(courseCheckout, UserOrderCheckout.class, "productId");
  106. CoursePackage coursePackage = coursePackageService.combineCourse(courseIds);
  107. if(coursePackage != null){
  108. List<Course> courseList = courseService.select(coursePackage.getCourseIds());
  109. BigDecimal originMoney = BigDecimal.valueOf(0);
  110. for(Course course : courseList){
  111. originMoney = originMoney.add(course.getPrice());
  112. }
  113. // 加入套餐
  114. UserOrderCheckout packageCheckout = UserOrderCheckout.builder()
  115. .productType(ProductType.COURSE_PACKAGE.key)
  116. .productId(coursePackage.getId())
  117. .money(coursePackage.getPrice())
  118. .originMoney(originMoney)
  119. .build();
  120. packageCheckout = userOrderCheckoutService.add(packageCheckout);
  121. // 绑定所属
  122. List<Integer> ids = Arrays.stream(coursePackage.getCourseIds()).collect(Collectors.toList());
  123. for(UserOrderCheckout c:courseCheckout){
  124. if (ids.contains(c.getProductId())){
  125. if (c.getId() !=null && c.getId() > 0){
  126. userOrderCheckoutService.edit(UserOrderCheckout.builder()
  127. .id(c.getId())
  128. .parentId(packageCheckout.getId())
  129. .build());
  130. }else{
  131. c.setParentId(packageCheckout.getId());
  132. userOrderCheckoutService.add(c);
  133. }
  134. }
  135. }
  136. return null;
  137. }
  138. // 正常添加
  139. return checkout;
  140. }));
  141. initCheckoutCallback.put(ProductType.COURSE_PACKAGE, ((checkout, userOrderCheckoutList)->{
  142. for(UserOrderCheckout in: userOrderCheckoutList){
  143. if (!in.getProductType().equals(ProductType.COURSE_PACKAGE.key)) continue;
  144. if (in.getProductId().equals(checkout.getProductId())) return null;
  145. }
  146. CoursePackage coursePackage = coursePackageService.get(checkout.getProductId());
  147. List<Course> courseList = courseService.select(coursePackage.getCourseIds());
  148. Map<Integer, Course> courseMap = new HashMap<>();
  149. for(Course course : courseList){
  150. courseMap.put(course.getId(), course);
  151. }
  152. BigDecimal originMoney = BigDecimal.valueOf(0);
  153. for(Course course : courseList){
  154. originMoney = originMoney.add(course.getPrice());
  155. }
  156. checkout.setMoney(coursePackage.getPrice());
  157. checkout.setOriginMoney(originMoney);
  158. checkout = userOrderCheckoutService.add(checkout);
  159. // 转移课程包含的独立课程
  160. List<Integer> ids = Arrays.stream(coursePackage.getCourseIds()).collect(Collectors.toList());
  161. List<UserOrderCheckout> courseCheckout = userOrderCheckoutList.stream().filter((in)-> in.getProductType().equals(ProductType.COURSE.key) && in.getParentId() == 0).collect(Collectors.toList());
  162. for(UserOrderCheckout in : courseCheckout){
  163. if (ids.contains(in.getProductId())){
  164. // 转移该购物车记录
  165. userOrderCheckoutService.edit(UserOrderCheckout.builder()
  166. .id(in.getId())
  167. .parentId(checkout.getId())
  168. .build());
  169. ids.remove(in.getProductId());
  170. }
  171. }
  172. // 添加还未添加的课程记录
  173. for(Integer id : ids){
  174. Course course = courseMap.get(id);
  175. userOrderCheckoutService.add(UserOrderCheckout.builder()
  176. .parentId(checkout.getId())
  177. .productType(ProductType.COURSE.key)
  178. .productId(id)
  179. .money(course.getPrice())
  180. .originMoney(course.getPrice())
  181. .build());
  182. }
  183. return null;
  184. }));
  185. initCheckoutCallback.put(ProductType.DATA, ((checkout, userOrderCheckoutList)->{
  186. for(UserOrderCheckout in: userOrderCheckoutList){
  187. if (!in.getProductType().equals(ProductType.DATA.key)) continue;
  188. if (in.getProductId().equals(checkout.getProductId())) return null;
  189. }
  190. CourseData courseData = courseDataService.get(checkout.getProductId());
  191. checkout.setMoney(courseData.getPrice());
  192. checkout.setOriginMoney(courseData.getPrice());
  193. return checkout;
  194. }));
  195. initCheckoutCallback.put(ProductType.SERVICE, ((checkout, userOrderCheckoutList)->{
  196. for(UserOrderCheckout in: userOrderCheckoutList){
  197. if (!in.getProductType().equals(ProductType.SERVICE.key)) continue;
  198. if (in.getService().equals(checkout.getService())){
  199. checkout.setId(in.getId());
  200. break;
  201. }
  202. }
  203. BigDecimal money = BigDecimal.valueOf(toolsService.getServicePrice(checkout.getService(), checkout.getParam()));
  204. checkout.setOriginMoney(money);
  205. ServiceKey serviceKey = ServiceKey.ValueOf(checkout.getService());
  206. if (serviceKey == ServiceKey.TEXTBOOK){
  207. // 是否存在半价机经券
  208. User user = usersService.get(checkout.getId());
  209. checkout.setMoney(user.getTextbookHalf() > 0 ? money.divide(BigDecimal.valueOf(2), BigDecimal.ROUND_HALF_UP):money);
  210. }else{
  211. checkout.setMoney(money);
  212. }
  213. return checkout;
  214. }));
  215. removeCheckoutCallback.put(ProductType.COURSE, ((checkout, userOrderCheckoutList)->{
  216. // 子项目不允许参数,则无需处理
  217. }));
  218. removeCheckoutCallback.put(ProductType.COURSE_PACKAGE, ((checkout, userOrderCheckoutList)->{
  219. // 删除对应子项目
  220. }));
  221. removeCheckoutCallback.put(ProductType.DATA, ((checkout, userOrderCheckoutList)->{
  222. // miss
  223. }));
  224. removeCheckoutCallback.put(ProductType.SERVICE, ((checkout, userOrderCheckoutList)->{
  225. // miss
  226. }));
  227. initOrderCallback.put(ProductType.SERVICE, ((order, userOrderCheckoutList) -> {
  228. // 累计金额
  229. BigDecimal money = order.getMoney();
  230. BigDecimal originMoney = order.getOriginMoney();
  231. for(UserOrderCheckout checkout:userOrderCheckoutList){
  232. ServiceKey serviceKey = ServiceKey.ValueOf(checkout.getService());
  233. if (serviceKey == ServiceKey.TEXTBOOK){
  234. // 是否存在半价机经券
  235. if (!checkout.getMoney().equals(checkout.getOriginMoney())){
  236. JSONObject info = new JSONObject();
  237. info.put("originMoney", originMoney);
  238. info.put("money", money);
  239. info.put("key", "half");
  240. JSONObject promote = order.getPromote();
  241. promote.put("textbook", info);
  242. }
  243. }
  244. money = money.add(checkout.getMoney());
  245. originMoney = originMoney.add(checkout.getMoney());
  246. }
  247. order.setMoney(money);
  248. order.setOriginMoney(originMoney);
  249. }));
  250. initOrderCallback.put(ProductType.DATA, ((order, userOrderCheckoutList) -> {
  251. // 累计金额
  252. BigDecimal money = order.getMoney();
  253. BigDecimal originMoney = order.getOriginMoney();
  254. for(UserOrderCheckout checkout:userOrderCheckoutList){
  255. money = money.add(checkout.getMoney());
  256. originMoney = originMoney.add(checkout.getMoney());
  257. }
  258. order.setMoney(money);
  259. order.setOriginMoney(originMoney);
  260. }));
  261. initOrderCallback.put(ProductType.COURSE, ((order, userOrderCheckoutList) -> {
  262. BigDecimal money = order.getMoney();
  263. BigDecimal originMoney = order.getOriginMoney();
  264. // 独立课程信息: 排除套餐内的
  265. List<UserOrderCheckout> courseCheckout = userOrderCheckoutList.stream().filter((checkout)-> checkout.getProductType().equals(ProductType.COURSE.key) && checkout.getParentId() == 0).collect(Collectors.toList());
  266. Collection courseIds = Transform.getIds(courseCheckout, UserOrderCheckout.class, "productId");
  267. List<Course> courseList = courseService.select(courseIds);
  268. Map<Integer, Course> courseMap = new HashMap<>();
  269. for(Course course : courseList){
  270. courseMap.put(course.getId(), course);
  271. }
  272. BigDecimal courseMoney = BigDecimal.valueOf(0);
  273. // 视频课程优惠
  274. List<UserOrderCheckout> videoCheckout = courseCheckout.stream().filter((checkout)-> courseMap.get(checkout.getProductId()).getCourseModule().equals(CourseModule.VIDEO.key)).collect(Collectors.toList());
  275. BigDecimal videoMoney = BigDecimal.valueOf(0);
  276. for(UserOrderCheckout checkout : videoCheckout){
  277. videoMoney = videoMoney.add(checkout.getMoney());
  278. }
  279. int percent = toolsService.computeVideoMoney(courseCheckout);
  280. if (percent < 100){
  281. BigDecimal promoteVideoMoney = videoMoney.multiply(BigDecimal.valueOf(percent)).divide(BigDecimal.valueOf(100), BigDecimal.ROUND_HALF_UP);
  282. courseMoney = courseMoney.add(promoteVideoMoney);
  283. money = money.add(promoteVideoMoney);
  284. // 添加视频优惠记录
  285. JSONObject info = new JSONObject();
  286. info.put("originMoney", videoMoney);
  287. info.put("money", promoteVideoMoney);
  288. info.put("message", toolsService.videoMoneyMessage());
  289. JSONObject promote = order.getPromote();
  290. promote.put("video", info);
  291. }else{
  292. courseMoney = courseMoney.add(videoMoney);
  293. money = money.add(videoMoney);
  294. }
  295. originMoney = originMoney.add(videoMoney);
  296. // 1v1课程优惠: 添加时计算
  297. List<UserOrderCheckout> vsCheckout = courseCheckout.stream().filter((checkout)-> courseMap.get(checkout.getProductId()).getCourseModule().equals(CourseModule.VS.key)).collect(Collectors.toList());
  298. for(UserOrderCheckout checkout: vsCheckout){
  299. courseMoney = courseMoney.add(checkout.getMoney());
  300. money = money.add(checkout.getMoney());
  301. originMoney = originMoney.add(checkout.getMoney());
  302. }
  303. // 套餐费用: 添加时计算
  304. List<UserOrderCheckout> packageCheckout = userOrderCheckoutList.stream().filter((checkout)-> checkout.getProductType().equals(ProductType.COURSE_PACKAGE.key)).collect(Collectors.toList());
  305. for(UserOrderCheckout checkout : packageCheckout){
  306. courseMoney = courseMoney.add(checkout.getMoney());
  307. money = money.add(checkout.getMoney());
  308. originMoney = originMoney.add(checkout.getMoney());
  309. // 套餐优惠记录 - 不参与总价,单独展示逻辑
  310. }
  311. // 满金额处理
  312. Integer ask = toolsService.getAskTime(courseMoney);
  313. order.setAskTime(ask * 3600);
  314. JSONArray gift = order.getGift();
  315. if (ask> 0){
  316. JSONObject info = new JSONObject();
  317. info.put("key", "ask");
  318. info.put("message", toolsService.askTimeMessage().replace("{}", ask.toString()));
  319. gift.add(info);
  320. }
  321. order.setMoney(money);
  322. order.setOriginMoney(originMoney);
  323. // 课程金额进行开票处理
  324. order.setInvoiceMoney(courseMoney);
  325. }));
  326. initRecordCallback.put(ProductType.COURSE, ((order, record) -> {
  327. Course course = courseService.get(record.getProductId());
  328. CourseModule courseModule = CourseModule.ValueOf(course.getCourseModule());
  329. // 小班课程不会存在记录,在线视频和1v1授课都有有效期
  330. Date startTime = new Date();
  331. Date endTime = Tools.addDate(startTime, courseModule.expireDay);
  332. record.setStartTime(startTime);
  333. record.setEndTime(endTime);
  334. // 绑定订单的回复时长
  335. record.setAskTime(order.getAskTime());
  336. // 计算vs课程编号
  337. if (courseModule == CourseModule.VS){
  338. Integer no = userOrderRecordService.maxVsNo(order.getUserId());
  339. record.setVsNo(no+1);
  340. }
  341. return record;
  342. }));
  343. initRecordCallback.put(ProductType.COURSE_PACKAGE, ((order, record)->{
  344. // 资料无需开启,也没有有效期
  345. record.setIsUsed(1);
  346. Date time = new Date();
  347. record.setUseTime(time);
  348. return record;
  349. }));
  350. initRecordCallback.put(ProductType.DATA, ((order, record)->{
  351. // 资料无需开启,也没有有效期
  352. record.setIsUsed(1);
  353. Date time = new Date();
  354. record.setUseTime(time);
  355. return record;
  356. }));
  357. initRecordCallback.put(ProductType.SERVICE, ((order, record)->{
  358. if(record.getService().equals(ServiceKey.VIP.key)){
  359. // VIP直接开通
  360. record = useRecordCallback.get(ProductType.SERVICE).callback(record);
  361. }else{
  362. ServiceKey serviceKey = ServiceKey.ValueOf(record.getService());
  363. Date startTime = new Date();
  364. Date endTime = Tools.addMonth(startTime, serviceKey.expireDay);
  365. record.setStartTime(startTime);
  366. record.setEndTime(endTime);
  367. // 如果使用半价优惠券,则扣除
  368. if (serviceKey == ServiceKey.TEXTBOOK){
  369. User user = usersService.get(record.getUserId());
  370. if (user.getTextbookHalf() == 0) {
  371. // todo 支付存在问题
  372. }
  373. usersService.edit(User.builder().id(user.getId()).textbookHalf(user.getTextbookHalf() - 1).build());
  374. }
  375. }
  376. return record;
  377. }));
  378. useRecordCallback.put(ProductType.COURSE, (record->{
  379. record.setIsUsed(1);
  380. Date time = new Date();
  381. record.setUseTime(time);
  382. Course course = courseService.get(record.getProductId());
  383. Integer expireDay = 0;
  384. if (course.getCourseModule().equals(CourseModule.VS.key)){
  385. // 根据课时数进行计算
  386. expireDay = courseExtendService.computeExpire(record.getNumber(), course);
  387. }else{
  388. // 根据设置进行计算
  389. expireDay = courseExtendService.computeExpire(course);
  390. }
  391. Date startTime = time;
  392. Date endTime = Tools.addDate(startTime, expireDay);
  393. UserCourse userCourse = userCourseService.getCourseBase(record.getUserId(), record.getProductId());
  394. if(userCourse == null){
  395. userCourse = UserCourse.builder()
  396. .userId(record.getUserId())
  397. .courseId(course.getId())
  398. .recordId(record.getId())
  399. .startTime(startTime)
  400. .expireTime(endTime)
  401. .build();
  402. userCourse = userCourseService.add(userCourse);
  403. }else{
  404. if (userCourse.getExpireTime().before(time)){
  405. // 已到期 - 续期
  406. userCourse.setStartTime(startTime);
  407. userCourse.setExpireTime(endTime);
  408. userCourse.setRecordId(record.getId());
  409. }else{
  410. // 未到期 - 报错
  411. throw new ParameterException("已开通当前课程");
  412. }
  413. userCourse = userCourseService.edit(userCourse);
  414. }
  415. record.setUseStartTime(startTime);
  416. record.setUseEndTime(endTime);
  417. return record;
  418. }));
  419. useRecordCallback.put(ProductType.COURSE_PACKAGE, (record->{
  420. // miss
  421. throw new ParameterException("套餐无需开通");
  422. }));
  423. useRecordCallback.put(ProductType.DATA, (record->{
  424. // miss
  425. throw new ParameterException("资料无需开通");
  426. }));
  427. useRecordCallback.put(ProductType.SERVICE, (record->{
  428. record.setIsUsed(1);
  429. Date time = new Date();
  430. record.setUseTime(time);
  431. ServiceKey serviceKey = ServiceKey.ValueOf(record.getService());
  432. Integer expireDay = serviceKey.useExpireDay;
  433. if(serviceKey == ServiceKey.VIP){
  434. ServiceVipKey vipKey = ServiceVipKey.ValueOf(record.getParam());
  435. expireDay = vipKey.useExpireDay;
  436. }
  437. Date startTime = time;
  438. Date endTime = null;
  439. if(expireDay > 0){
  440. // 设置结束有效期
  441. endTime = Tools.addDate(startTime, expireDay);
  442. }
  443. UserService userService = userServiceService.getServiceBase(record.getUserId(), serviceKey);
  444. if (userService == null){
  445. userService = UserService.builder()
  446. .userId(record.getUserId())
  447. .isSubscribe(record.getIsSubscribe())
  448. .isReset(0)
  449. .startTime(startTime)
  450. .expireTime(endTime)
  451. .build();
  452. userService = userServiceService.add(userService);
  453. }else{
  454. if (serviceKey == ServiceKey.QX_CAT){
  455. // cat逻辑独立
  456. if (userService.getExpireTime().after(time)){
  457. // 有效期内
  458. if (userService.getIsReset() == 0) throw new ParameterException("已开通当前服务");
  459. // 第二次还未做完
  460. if (userService.getIsReset() == 1 && examinationService.isFinishCat(record.getUserId())) throw new ParameterException("已开通当前服务");
  461. }
  462. // 重置
  463. userService.setIsReset(0);
  464. examinationService.resetCat(record.getUserId(), true);
  465. }else if (userService.getExpireTime() != null && userService.getExpireTime().before(time)){
  466. // 已到期 - 续期
  467. userService.setStartTime(startTime);
  468. userService.setExpireTime(endTime);
  469. }else{
  470. // 未到期 - 延长有效期
  471. startTime = userService.getExpireTime();
  472. if (expireDay > 0){
  473. endTime = Tools.addDate(userService.getExpireTime(), expireDay);
  474. userService.setExpireTime(endTime);
  475. }
  476. }
  477. userService.setIsSubscribe(record.getIsSubscribe());
  478. userService = userServiceService.edit(userService);
  479. }
  480. record.setUseStartTime(startTime);
  481. record.setUseEndTime(endTime);
  482. return record;
  483. }));
  484. stopRecordCallback.put(ProductType.COURSE, (record->{
  485. record.setIsUsed(1);
  486. Date time = new Date();
  487. record.setUseTime(time);
  488. Course course = courseService.get(record.getProductId());
  489. Integer expireDay = 0;
  490. if (course.getCourseModule().equals(CourseModule.VS.key)){
  491. // 根据课时数进行计算
  492. expireDay = courseExtendService.computeExpire(record.getNumber(), course);
  493. }else{
  494. // 根据设置进行计算
  495. }
  496. Date startTime = time;
  497. Date endTime = Tools.addDate(startTime, expireDay);
  498. UserCourse userCourse = userCourseService.getCourseBase(record.getUserId(), record.getProductId());
  499. if(userCourse == null){
  500. userCourse = UserCourse.builder()
  501. .userId(record.getUserId())
  502. .recordId(record.getId())
  503. .startTime(startTime)
  504. .expireTime(endTime)
  505. .build();
  506. userCourse = userCourseService.add(userCourse);
  507. }else{
  508. if (userCourse.getExpireTime().before(time)){
  509. // 已到期 - 续期
  510. userCourse.setStartTime(startTime);
  511. userCourse.setExpireTime(endTime);
  512. userCourse.setRecordId(record.getId());
  513. }else{
  514. // 未到期 - 报错
  515. throw new ParameterException("已开通当前课程");
  516. }
  517. userCourse = userCourseService.edit(userCourse);
  518. }
  519. record.setUseStartTime(startTime);
  520. record.setUseEndTime(endTime);
  521. return record;
  522. }));
  523. stopRecordCallback.put(ProductType.COURSE_PACKAGE, (record->{
  524. // miss
  525. throw new ParameterException("套餐无需停用");
  526. }));
  527. stopRecordCallback.put(ProductType.DATA, (record->{
  528. // 停用后无法查看
  529. record.setIsStop(1);
  530. return record;
  531. }));
  532. stopRecordCallback.put(ProductType.SERVICE, (record->{
  533. record.setIsUsed(1);
  534. Date time = new Date();
  535. record.setUseTime(time);
  536. ServiceKey serviceKey = ServiceKey.ValueOf(record.getService());
  537. Integer expireDay = serviceKey.useExpireDay;
  538. if(serviceKey == ServiceKey.VIP){
  539. ServiceVipKey vipKey = ServiceVipKey.ValueOf(record.getParam());
  540. expireDay = vipKey.useExpireDay;
  541. }
  542. Date startTime = time;
  543. Date endTime = Tools.addDate(startTime, expireDay);
  544. UserService userService = userServiceService.getServiceBase(record.getUserId(), serviceKey);
  545. if (userService == null){
  546. userService = UserService.builder()
  547. .userId(record.getUserId())
  548. .isSubscribe(record.getIsSubscribe())
  549. .startTime(startTime)
  550. .expireTime(endTime)
  551. .build();
  552. userService = userServiceService.add(userService);
  553. }else{
  554. if (userService.getExpireTime().before(time)){
  555. // 已到期 - 续期
  556. userService.setStartTime(startTime);
  557. userService.setExpireTime(endTime);
  558. }else{
  559. if (serviceKey == ServiceKey.QX_CAT){
  560. // 未到期 - 报错
  561. throw new ParameterException("已开通当前服务");
  562. }
  563. // 未到期 - 延长有效期
  564. startTime = userService.getExpireTime();
  565. endTime = Tools.addDate(userService.getExpireTime(), expireDay);
  566. userService.setExpireTime(endTime);
  567. }
  568. userService.setIsSubscribe(record.getIsSubscribe());
  569. userService = userServiceService.edit(userService);
  570. }
  571. record.setUseStartTime(startTime);
  572. record.setUseEndTime(endTime);
  573. return record;
  574. }));
  575. }
  576. /**
  577. * 完成订单支付
  578. * @param orderId
  579. * @param userId
  580. * @param payTime
  581. * @param payMethod
  582. * @return
  583. */
  584. @Transactional
  585. public boolean payed(Integer orderId, Integer userId, Long payId, Date payTime, PayMethod payMethod, String transactionNo){
  586. UserOrder userOrder = userOrderService.get(orderId);
  587. if (userOrder == null) return false;
  588. if (userOrder.getPayStatus() > 0) return false;
  589. userOrder = userOrderService.edit(UserOrder.builder()
  590. .id(userOrder.getId())
  591. .payId(payId)
  592. .payMethod(payMethod.key)
  593. .payTime(payTime)
  594. .transactionNo(transactionNo)
  595. .payStatus(1)
  596. .build());
  597. // 转换购物车记录为购买记录
  598. List<UserOrderCheckout> checkoutList = userOrderCheckoutService.allByUser(userId, orderId);
  599. List<UserOrderCheckout> pList = checkoutList.stream().filter((checkout)-> checkout.getParentId() == 0).collect(Collectors.toList());
  600. List<UserOrderCheckout> cList = checkoutList.stream().filter((checkout)-> checkout.getParentId() > 0).collect(Collectors.toList());
  601. Map<Integer, Integer> pMap = new HashMap<>();
  602. for(UserOrderCheckout checkout : pList){
  603. UserOrderRecord record = Transform.convert(checkout, UserOrderRecord.class);
  604. record.setSource(RecordSource.FromPayModule(payMethod).key);
  605. InitRecord callback = initRecordCallback.get(ProductType.ValueOf(record.getProductType()));
  606. callback.callback(userOrder, record);
  607. record = userOrderRecordService.add(record);
  608. // 建立新旧id关系
  609. pMap.put(checkout.getId(), record.getId());
  610. }
  611. for(UserOrderCheckout checkout : cList){
  612. UserOrderRecord record = Transform.convert(checkout, UserOrderRecord.class);
  613. // 记录parentid
  614. record.setParentId(pMap.get(checkout.getParentId()));
  615. record.setSource(RecordSource.FromPayModule(payMethod).key);
  616. InitRecord callback = initRecordCallback.get(ProductType.ValueOf(record.getProductType()));
  617. callback.callback(userOrder, record);
  618. userOrderRecordService.add(record);
  619. }
  620. userOrderCheckoutService.deleteByUser(userId, orderId);
  621. // 累加用户支付信息
  622. usersService.accumulation(userOrder.getUserId(), userOrder.getMoney());
  623. return true;
  624. }
  625. /**
  626. * 添加购物车
  627. * @param userId
  628. * @param checkout
  629. * @return
  630. */
  631. @Transactional
  632. public int addCheckout(Integer userId, UserOrderCheckout checkout){
  633. List<UserOrderCheckout> list = userOrderCheckoutService.allByUser(userId, 0);
  634. InitCheckout callback = initCheckoutCallback.get(ProductType.ValueOf(checkout.getProductType()));
  635. checkout = callback.callback(checkout, list);
  636. if (checkout == null){
  637. // 无需操作
  638. }else if(checkout.getId() > 0){
  639. userOrderCheckoutService.edit(checkout);
  640. }else{
  641. userOrderCheckoutService.add(checkout);
  642. }
  643. // 计算购物车数量
  644. return userOrderCheckoutService.allByUser(userId, 0).size();
  645. }
  646. /**
  647. * 删除购物车
  648. * @param checkoutId
  649. * @param userId
  650. * @return
  651. */
  652. @Transactional
  653. public int removeCheckout(Integer checkoutId, Integer userId){
  654. UserOrderCheckout in = userOrderCheckoutService.get(checkoutId);
  655. if (in == null){
  656. throw new ParameterException("记录不存在");
  657. }
  658. if (!in.getUserId().equals(userId)){
  659. throw new ParameterException("记录不存在");
  660. }
  661. if (in.getParentId() != null && in.getParentId() > 0){
  662. // 如果能删除子项目,要处理删除父项目,转移其他子项目
  663. throw new ParameterException("套餐内,不允许单独删除");
  664. }
  665. userOrderCheckoutService.delete(checkoutId);
  666. List<UserOrderCheckout> list = userOrderCheckoutService.allByUser(userId, 0);
  667. // 删除子项目
  668. for(UserOrderCheckout checkout: list){
  669. if (checkout.getParentId()==null || checkout.getParentId() == 0) continue;
  670. if (checkout.getParentId().equals(in.getId())){
  671. userOrderCheckoutService.delete(checkout.getId());
  672. }
  673. }
  674. RemoveCheckout callback = removeCheckoutCallback.get(ProductType.ValueOf(in.getProductType()));
  675. callback.callback(in, list);
  676. // 计算购物车数量
  677. return userOrderCheckoutService.allByUser(userId, 0).size();
  678. }
  679. /**
  680. * 根据购物车生成对应订单信息
  681. * @param list
  682. * @return
  683. */
  684. public UserOrder preOrderWithCheckout(Integer userId, List<UserOrderCheckout> list){
  685. UserOrder order = UserOrder.builder()
  686. .userId(userId)
  687. .originMoney(BigDecimal.valueOf(0))
  688. .money(BigDecimal.valueOf(0))
  689. .build();
  690. // 记录订单优惠
  691. JSONObject promote = new JSONObject();
  692. order.setPromote(promote);
  693. // 记录订单类型
  694. JSONArray productTypes = new JSONArray();
  695. order.setProductTypes(productTypes);
  696. // 记录赠品信息
  697. JSONArray gift = new JSONArray();
  698. order.setGift(gift);
  699. InitOrder callback;
  700. // 课程: 并包含套餐
  701. List<UserOrderCheckout> courseCheckout = list.stream().filter((checkout)-> checkout.getProductType().equals(ProductType.COURSE.key) || checkout.getProductType().equals(ProductType.COURSE_PACKAGE.key)).collect(Collectors.toList());
  702. callback = initOrderCallback.get(ProductType.COURSE);
  703. callback.callback(order, courseCheckout);
  704. if(courseCheckout.size() > 0){
  705. productTypes.add(ProductType.COURSE.key);
  706. }
  707. // 资料
  708. List<UserOrderCheckout> dataCheckout = list.stream().filter((checkout)-> checkout.getProductType().equals(ProductType.DATA.key)).collect(Collectors.toList());
  709. callback = initOrderCallback.get(ProductType.DATA);
  710. callback.callback(order, courseCheckout);
  711. if (dataCheckout.size() > 0){
  712. productTypes.add(ProductType.DATA.key);
  713. }
  714. // 服务
  715. List<UserOrderCheckout> serviceCheckout = list.stream().filter((checkout)-> checkout.getProductType().equals(ProductType.SERVICE.key)).collect(Collectors.toList());
  716. callback = initOrderCallback.get(ProductType.SERVICE);
  717. callback.callback(order, courseCheckout);
  718. if(serviceCheckout.size() > 0){
  719. productTypes.add(ProductType.SERVICE.key);
  720. }
  721. return order;
  722. }
  723. /**
  724. * 支付购物车
  725. * @param userId
  726. * @return
  727. */
  728. @Transactional
  729. public UserOrder makeOrder(Integer userId){
  730. List<UserOrderCheckout> list = userOrderCheckoutService.allByUser(userId, 0);
  731. UserOrder order = preOrderWithCheckout(userId, list);
  732. order = userOrderService.add(order);
  733. // 转移购物车信息
  734. userOrderCheckoutService.changeByUser(userId, 0, UserOrderCheckout.builder().orderId(order.getId()).build());
  735. return order;
  736. }
  737. /**
  738. * 立即购买
  739. * @param userId
  740. * @param checkout
  741. * @return
  742. */
  743. @Transactional
  744. public UserOrder makeOrderWithProduct(Integer userId, UserOrderCheckout checkout){
  745. List<UserOrderCheckout> list = new ArrayList<UserOrderCheckout>(){{add(checkout);}};
  746. UserOrder order = preOrderWithCheckout(userId, list);
  747. order = userOrderService.add(order);
  748. checkout.setOrderId(order.getId());
  749. userOrderCheckoutService.add(checkout);
  750. return order;
  751. }
  752. /**
  753. * 后台直接添加记录
  754. * @param record
  755. * @return
  756. */
  757. @Transactional
  758. public UserOrderRecord addRecord(UserOrderRecord record){
  759. InitRecord callback = initRecordCallback.get(ProductType.ValueOf(record.getProductType()));
  760. // 虚拟order
  761. callback.callback(UserOrder.builder().build(), record);
  762. return userOrderRecordService.add(record);
  763. }
  764. /**
  765. * 开通记录
  766. * @param userId
  767. * @param recordId
  768. * @return
  769. */
  770. @Transactional
  771. public UserOrderRecord useRecord(Integer userId, Integer recordId){
  772. UserOrderRecord in = userOrderRecordService.get(recordId);
  773. if (in == null){
  774. throw new ParameterException("记录不存在");
  775. }
  776. if (!in.getUserId().equals(userId)){
  777. throw new ParameterException("记录不存在");
  778. }
  779. UseRecord callback = useRecordCallback.get(ProductType.ValueOf(in.getProductType()));
  780. callback.callback(in);
  781. return in;
  782. }
  783. public void stopRecord(Integer recordId){
  784. UserOrderRecord in = userOrderRecordService.get(recordId);
  785. if (in == null){
  786. throw new ParameterException("记录不存在");
  787. }
  788. if (in.getIsStop()> 0){
  789. throw new ParameterException("已停用");
  790. }
  791. UseRecord callback = useRecordCallback.get(ProductType.ValueOf(in.getProductType()));
  792. callback.callback(in);
  793. }
  794. /**
  795. * 给用户邀请奖励: 7天vip
  796. * @param userId
  797. */
  798. public void giveInvite(Integer userId){
  799. UserOrderRecord record = UserOrderRecord.builder()
  800. .userId(userId)
  801. .service(ServiceKey.VIP.key)
  802. .param(ServiceVipKey.DAY7.key)
  803. .source(RecordSource.INVITE.key)
  804. .build();
  805. // 虚拟order
  806. record = initRecordCallback.get(ProductType.SERVICE).callback(UserOrder.builder().build(), record);
  807. userOrderRecordService.add(record);
  808. }
  809. /**
  810. * 给用户备考奖励: 7天vip
  811. * @param userId
  812. */
  813. public void givePrepare(Integer userId){
  814. UserOrderRecord record = UserOrderRecord.builder()
  815. .userId(userId)
  816. .service(ServiceKey.VIP.key)
  817. .param(ServiceVipKey.DAY7.key)
  818. .source(RecordSource.PREPARE.key)
  819. .build();
  820. // 虚拟order
  821. record = initRecordCallback.get(ProductType.SERVICE).callback(UserOrder.builder().build(), record);
  822. userOrderRecordService.add(record);
  823. }
  824. /**
  825. * 给用户实名认证奖励: 180天vip
  826. * @param userId
  827. */
  828. public void giveReal(Integer userId){
  829. UserOrderRecord record = UserOrderRecord.builder()
  830. .userId(userId)
  831. .service(ServiceKey.VIP.key)
  832. .param(ServiceVipKey.MONTH3.key)
  833. .source(RecordSource.REAL.key)
  834. .build();
  835. // 虚拟order
  836. record = initRecordCallback.get(ProductType.SERVICE).callback(UserOrder.builder().build(), record);
  837. userOrderRecordService.add(record);
  838. }
  839. }