OrderFlowService.java 45 KB

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