OrderFlowService.java 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892
  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 promote = order.getPromote();
  237. promote.put("textbook", "half");
  238. }
  239. }
  240. money = money.add(checkout.getMoney());
  241. originMoney = originMoney.add(checkout.getMoney());
  242. }
  243. order.setMoney(money);
  244. order.setOriginMoney(originMoney);
  245. }));
  246. initOrderCallback.put(ProductType.DATA, ((order, userOrderCheckoutList) -> {
  247. // 累计金额
  248. BigDecimal money = order.getMoney();
  249. BigDecimal originMoney = order.getOriginMoney();
  250. for(UserOrderCheckout checkout:userOrderCheckoutList){
  251. money = money.add(checkout.getMoney());
  252. originMoney = originMoney.add(checkout.getMoney());
  253. }
  254. order.setMoney(money);
  255. order.setOriginMoney(originMoney);
  256. }));
  257. initOrderCallback.put(ProductType.COURSE, ((order, userOrderCheckoutList) -> {
  258. BigDecimal money = order.getMoney();
  259. BigDecimal originMoney = order.getOriginMoney();
  260. // 独立课程信息: 排除套餐内的
  261. List<UserOrderCheckout> courseCheckout = userOrderCheckoutList.stream().filter((checkout)-> checkout.getProductType().equals(ProductType.COURSE.key) && checkout.getParentId() == 0).collect(Collectors.toList());
  262. Collection courseIds = Transform.getIds(courseCheckout, UserOrderCheckout.class, "productId");
  263. List<Course> courseList = courseService.select(courseIds);
  264. Map<Integer, Course> courseMap = new HashMap<>();
  265. for(Course course : courseList){
  266. courseMap.put(course.getId(), course);
  267. }
  268. BigDecimal courseMoney = BigDecimal.valueOf(0);
  269. // 视频课程优惠
  270. List<UserOrderCheckout> videoCheckout = courseCheckout.stream().filter((checkout)-> courseMap.get(checkout.getProductId()).getCourseModule().equals(CourseModule.VIDEO.key)).collect(Collectors.toList());
  271. BigDecimal videoMoney = BigDecimal.valueOf(0);
  272. for(UserOrderCheckout checkout : videoCheckout){
  273. videoMoney = videoMoney.add(checkout.getMoney());
  274. }
  275. int percent = toolsService.computeVideoMoney(courseCheckout);
  276. if (percent < 100){
  277. BigDecimal promoteVideoMoney = videoMoney.multiply(BigDecimal.valueOf(percent)).divide(BigDecimal.valueOf(100), BigDecimal.ROUND_HALF_UP);
  278. courseMoney = courseMoney.add(promoteVideoMoney);
  279. money = money.add(promoteVideoMoney);
  280. // 添加视频优惠记录
  281. JSONObject promote = order.getPromote();
  282. promote.put("video", percent);
  283. }else{
  284. courseMoney = courseMoney.add(videoMoney);
  285. money = money.add(videoMoney);
  286. }
  287. originMoney = originMoney.add(videoMoney);
  288. // 1v1课程优惠: 添加时计算
  289. List<UserOrderCheckout> vsCheckout = courseCheckout.stream().filter((checkout)-> courseMap.get(checkout.getProductId()).getCourseModule().equals(CourseModule.VS.key)).collect(Collectors.toList());
  290. for(UserOrderCheckout checkout: vsCheckout){
  291. courseMoney = courseMoney.add(checkout.getMoney());
  292. money = money.add(checkout.getMoney());
  293. originMoney = originMoney.add(checkout.getMoney());
  294. }
  295. // 套餐费用: 添加时计算
  296. List<UserOrderCheckout> packageCheckout = userOrderCheckoutList.stream().filter((checkout)-> checkout.getProductType().equals(ProductType.COURSE_PACKAGE.key)).collect(Collectors.toList());
  297. for(UserOrderCheckout checkout : packageCheckout){
  298. courseMoney = courseMoney.add(checkout.getMoney());
  299. money = money.add(checkout.getMoney());
  300. originMoney = originMoney.add(checkout.getMoney());
  301. }
  302. // 满金额处理
  303. Integer ask = toolsService.getAskTime(courseMoney);
  304. order.setAskTime(ask);
  305. order.setMoney(money);
  306. order.setOriginMoney(originMoney);
  307. }));
  308. initRecordCallback.put(ProductType.COURSE, ((order, record) -> {
  309. Course course = courseService.get(record.getProductId());
  310. CourseModule courseModule = CourseModule.ValueOf(course.getCourseModule());
  311. // 小班课程不会存在记录,在线视频和1v1授课都有有效期
  312. Date startTime = new Date();
  313. Date endTime = Tools.addDate(startTime, courseModule.expireDay);
  314. record.setStartTime(startTime);
  315. record.setEndTime(endTime);
  316. // 绑定订单的回复时长
  317. record.setAskTime(order.getAskTime());
  318. // 计算vs课程编号
  319. if (courseModule == CourseModule.VS){
  320. Integer no = userOrderRecordService.maxVsNo(order.getUserId());
  321. record.setVsNo(no+1);
  322. }
  323. return record;
  324. }));
  325. initRecordCallback.put(ProductType.COURSE_PACKAGE, ((order, record)->{
  326. // 资料无需开启,也没有有效期
  327. record.setIsUsed(1);
  328. Date time = new Date();
  329. record.setUseTime(time);
  330. return record;
  331. }));
  332. initRecordCallback.put(ProductType.DATA, ((order, record)->{
  333. // 资料无需开启,也没有有效期
  334. record.setIsUsed(1);
  335. Date time = new Date();
  336. record.setUseTime(time);
  337. return record;
  338. }));
  339. initRecordCallback.put(ProductType.SERVICE, ((order, record)->{
  340. if(record.getService().equals(ServiceKey.VIP.key)){
  341. // VIP直接开通
  342. record = useRecordCallback.get(ProductType.SERVICE).callback(record);
  343. }else{
  344. ServiceKey serviceKey = ServiceKey.ValueOf(record.getService());
  345. Date startTime = new Date();
  346. Date endTime = Tools.addMonth(startTime, serviceKey.expireDay);
  347. record.setStartTime(startTime);
  348. record.setEndTime(endTime);
  349. // 如果使用半价优惠券,则扣除
  350. if (serviceKey == ServiceKey.TEXTBOOK){
  351. User user = usersService.get(record.getUserId());
  352. if (user.getTextbookHalf() == 0) {
  353. // todo 支付存在问题
  354. }
  355. usersService.edit(User.builder().id(user.getId()).textbookHalf(user.getTextbookHalf() - 1).build());
  356. }
  357. }
  358. return record;
  359. }));
  360. useRecordCallback.put(ProductType.COURSE, (record->{
  361. record.setIsUsed(1);
  362. Date time = new Date();
  363. record.setUseTime(time);
  364. Course course = courseService.get(record.getProductId());
  365. Integer expireDay = 0;
  366. if (course.getCourseModule().equals(CourseModule.VS.key)){
  367. // 根据课时数进行计算
  368. expireDay = courseExtendService.computeExpire(record.getNumber(), course);
  369. }else{
  370. // 根据设置进行计算
  371. expireDay = courseExtendService.computeExpire(course);
  372. }
  373. Date startTime = time;
  374. Date endTime = Tools.addDate(startTime, expireDay);
  375. UserCourse userCourse = userCourseService.getCourseBase(record.getUserId(), record.getProductId());
  376. if(userCourse == null){
  377. userCourse = UserCourse.builder()
  378. .userId(record.getUserId())
  379. .courseId(course.getId())
  380. .recordId(record.getId())
  381. .startTime(startTime)
  382. .expireTime(endTime)
  383. .build();
  384. userCourse = userCourseService.add(userCourse);
  385. }else{
  386. if (userCourse.getExpireTime().before(time)){
  387. // 已到期 - 续期
  388. userCourse.setStartTime(startTime);
  389. userCourse.setExpireTime(endTime);
  390. userCourse.setRecordId(record.getId());
  391. }else{
  392. // 未到期 - 报错
  393. throw new ParameterException("已开通当前课程");
  394. }
  395. userCourse = userCourseService.edit(userCourse);
  396. }
  397. record.setUseStartTime(startTime);
  398. record.setUseEndTime(endTime);
  399. return record;
  400. }));
  401. useRecordCallback.put(ProductType.COURSE_PACKAGE, (record->{
  402. // miss
  403. throw new ParameterException("套餐无需开通");
  404. }));
  405. useRecordCallback.put(ProductType.DATA, (record->{
  406. // miss
  407. throw new ParameterException("资料无需开通");
  408. }));
  409. useRecordCallback.put(ProductType.SERVICE, (record->{
  410. record.setIsUsed(1);
  411. Date time = new Date();
  412. record.setUseTime(time);
  413. ServiceKey serviceKey = ServiceKey.ValueOf(record.getService());
  414. Integer expireDay = serviceKey.useExpireDay;
  415. if(serviceKey == ServiceKey.VIP){
  416. ServiceVipKey vipKey = ServiceVipKey.ValueOf(record.getParam());
  417. expireDay = vipKey.useExpireDay;
  418. }
  419. Date startTime = time;
  420. Date endTime = null;
  421. if(expireDay > 0){
  422. // 设置结束有效期
  423. endTime = Tools.addDate(startTime, expireDay);
  424. }
  425. UserService userService = userServiceService.getServiceBase(record.getUserId(), serviceKey);
  426. if (userService == null){
  427. userService = UserService.builder()
  428. .userId(record.getUserId())
  429. .isSubscribe(record.getIsSubscribe())
  430. .isReset(0)
  431. .startTime(startTime)
  432. .expireTime(endTime)
  433. .build();
  434. userService = userServiceService.add(userService);
  435. }else{
  436. if (serviceKey == ServiceKey.QX_CAT){
  437. // cat逻辑独立
  438. if (userService.getExpireTime().after(time)){
  439. // 有效期内
  440. if (userService.getIsReset() == 0) throw new ParameterException("已开通当前服务");
  441. // 第二次还未做完
  442. if (userService.getIsReset() == 1 && examinationService.isFinishCat(record.getUserId())) throw new ParameterException("已开通当前服务");
  443. }
  444. // 重置
  445. userService.setIsReset(0);
  446. examinationService.resetCat(record.getUserId(), true);
  447. }else if (userService.getExpireTime() != null && userService.getExpireTime().before(time)){
  448. // 已到期 - 续期
  449. userService.setStartTime(startTime);
  450. userService.setExpireTime(endTime);
  451. }else{
  452. // 未到期 - 延长有效期
  453. startTime = userService.getExpireTime();
  454. if (expireDay > 0){
  455. endTime = Tools.addDate(userService.getExpireTime(), expireDay);
  456. userService.setExpireTime(endTime);
  457. }
  458. }
  459. userService.setIsSubscribe(record.getIsSubscribe());
  460. userService = userServiceService.edit(userService);
  461. }
  462. record.setUseStartTime(startTime);
  463. record.setUseEndTime(endTime);
  464. return record;
  465. }));
  466. stopRecordCallback.put(ProductType.COURSE, (record->{
  467. record.setIsUsed(1);
  468. Date time = new Date();
  469. record.setUseTime(time);
  470. Course course = courseService.get(record.getProductId());
  471. Integer expireDay = 0;
  472. if (course.getCourseModule().equals(CourseModule.VS.key)){
  473. // 根据课时数进行计算
  474. expireDay = courseExtendService.computeExpire(record.getNumber(), course);
  475. }else{
  476. // 根据设置进行计算
  477. }
  478. Date startTime = time;
  479. Date endTime = Tools.addDate(startTime, expireDay);
  480. UserCourse userCourse = userCourseService.getCourseBase(record.getUserId(), record.getProductId());
  481. if(userCourse == null){
  482. userCourse = UserCourse.builder()
  483. .userId(record.getUserId())
  484. .recordId(record.getId())
  485. .startTime(startTime)
  486. .expireTime(endTime)
  487. .build();
  488. userCourse = userCourseService.add(userCourse);
  489. }else{
  490. if (userCourse.getExpireTime().before(time)){
  491. // 已到期 - 续期
  492. userCourse.setStartTime(startTime);
  493. userCourse.setExpireTime(endTime);
  494. userCourse.setRecordId(record.getId());
  495. }else{
  496. // 未到期 - 报错
  497. throw new ParameterException("已开通当前课程");
  498. }
  499. userCourse = userCourseService.edit(userCourse);
  500. }
  501. record.setUseStartTime(startTime);
  502. record.setUseEndTime(endTime);
  503. return record;
  504. }));
  505. stopRecordCallback.put(ProductType.COURSE_PACKAGE, (record->{
  506. // miss
  507. throw new ParameterException("套餐无需停用");
  508. }));
  509. stopRecordCallback.put(ProductType.DATA, (record->{
  510. // 停用后无法查看
  511. record.setIsStop(1);
  512. return record;
  513. }));
  514. stopRecordCallback.put(ProductType.SERVICE, (record->{
  515. record.setIsUsed(1);
  516. Date time = new Date();
  517. record.setUseTime(time);
  518. ServiceKey serviceKey = ServiceKey.ValueOf(record.getService());
  519. Integer expireDay = serviceKey.useExpireDay;
  520. if(serviceKey == ServiceKey.VIP){
  521. ServiceVipKey vipKey = ServiceVipKey.ValueOf(record.getParam());
  522. expireDay = vipKey.useExpireDay;
  523. }
  524. Date startTime = time;
  525. Date endTime = Tools.addDate(startTime, expireDay);
  526. UserService userService = userServiceService.getServiceBase(record.getUserId(), serviceKey);
  527. if (userService == null){
  528. userService = UserService.builder()
  529. .userId(record.getUserId())
  530. .isSubscribe(record.getIsSubscribe())
  531. .startTime(startTime)
  532. .expireTime(endTime)
  533. .build();
  534. userService = userServiceService.add(userService);
  535. }else{
  536. if (userService.getExpireTime().before(time)){
  537. // 已到期 - 续期
  538. userService.setStartTime(startTime);
  539. userService.setExpireTime(endTime);
  540. }else{
  541. if (serviceKey == ServiceKey.QX_CAT){
  542. // 未到期 - 报错
  543. throw new ParameterException("已开通当前服务");
  544. }
  545. // 未到期 - 延长有效期
  546. startTime = userService.getExpireTime();
  547. endTime = Tools.addDate(userService.getExpireTime(), expireDay);
  548. userService.setExpireTime(endTime);
  549. }
  550. userService.setIsSubscribe(record.getIsSubscribe());
  551. userService = userServiceService.edit(userService);
  552. }
  553. record.setUseStartTime(startTime);
  554. record.setUseEndTime(endTime);
  555. return record;
  556. }));
  557. }
  558. /**
  559. * 完成订单支付
  560. * @param orderId
  561. * @param userId
  562. * @param payTime
  563. * @param payMethod
  564. * @return
  565. */
  566. @Transactional
  567. public boolean payed(Integer orderId, Integer userId, Long payId, Date payTime, PayMethod payMethod, String transactionNo){
  568. UserOrder userOrder = userOrderService.get(orderId);
  569. if (userOrder == null) return false;
  570. if (userOrder.getPayStatus() > 0) return false;
  571. userOrder = userOrderService.edit(UserOrder.builder()
  572. .id(userOrder.getId())
  573. .payId(payId)
  574. .payMethod(payMethod.key)
  575. .payTime(payTime)
  576. .transactionNo(transactionNo)
  577. .payStatus(1)
  578. .build());
  579. // 转换购物车记录为购买记录
  580. List<UserOrderCheckout> checkoutList = userOrderCheckoutService.allByUser(userId, orderId);
  581. List<UserOrderCheckout> pList = checkoutList.stream().filter((checkout)-> checkout.getParentId() == 0).collect(Collectors.toList());
  582. List<UserOrderCheckout> cList = checkoutList.stream().filter((checkout)-> checkout.getParentId() > 0).collect(Collectors.toList());
  583. Map<Integer, Integer> pMap = new HashMap<>();
  584. for(UserOrderCheckout checkout : pList){
  585. UserOrderRecord record = Transform.convert(checkout, UserOrderRecord.class);
  586. record.setSource(RecordSource.FromPayModule(payMethod).key);
  587. InitRecord callback = initRecordCallback.get(ProductType.ValueOf(record.getProductType()));
  588. callback.callback(userOrder, record);
  589. record = userOrderRecordService.add(record);
  590. // 建立新旧id关系
  591. pMap.put(checkout.getId(), record.getId());
  592. }
  593. for(UserOrderCheckout checkout : cList){
  594. UserOrderRecord record = Transform.convert(checkout, UserOrderRecord.class);
  595. // 记录parentid
  596. record.setParentId(pMap.get(checkout.getParentId()));
  597. record.setSource(RecordSource.FromPayModule(payMethod).key);
  598. InitRecord callback = initRecordCallback.get(ProductType.ValueOf(record.getProductType()));
  599. callback.callback(userOrder, record);
  600. userOrderRecordService.add(record);
  601. }
  602. userOrderCheckoutService.deleteByUser(userId, orderId);
  603. // 累加用户支付信息
  604. usersService.accumulation(userOrder.getUserId(), userOrder.getMoney());
  605. return true;
  606. }
  607. /**
  608. * 添加购物车
  609. * @param userId
  610. * @param checkout
  611. * @return
  612. */
  613. @Transactional
  614. public int addCheckout(Integer userId, UserOrderCheckout checkout){
  615. List<UserOrderCheckout> list = userOrderCheckoutService.allByUser(userId, 0);
  616. InitCheckout callback = initCheckoutCallback.get(ProductType.ValueOf(checkout.getProductType()));
  617. checkout = callback.callback(checkout, list);
  618. if (checkout == null){
  619. // 无需操作
  620. }else if(checkout.getId() > 0){
  621. userOrderCheckoutService.edit(checkout);
  622. }else{
  623. userOrderCheckoutService.add(checkout);
  624. }
  625. // 计算购物车数量
  626. return userOrderCheckoutService.allByUser(userId, 0).size();
  627. }
  628. /**
  629. * 删除购物车
  630. * @param checkoutId
  631. * @param userId
  632. * @return
  633. */
  634. @Transactional
  635. public int removeCheckout(Integer checkoutId, Integer userId){
  636. UserOrderCheckout in = userOrderCheckoutService.get(checkoutId);
  637. if (in == null){
  638. throw new ParameterException("记录不存在");
  639. }
  640. if (!in.getUserId().equals(userId)){
  641. throw new ParameterException("记录不存在");
  642. }
  643. if (in.getParentId() != null && in.getParentId() > 0){
  644. // 如果能删除子项目,要处理删除父项目,转移其他子项目
  645. throw new ParameterException("套餐内,不允许单独删除");
  646. }
  647. userOrderCheckoutService.delete(checkoutId);
  648. List<UserOrderCheckout> list = userOrderCheckoutService.allByUser(userId, 0);
  649. // 删除子项目
  650. for(UserOrderCheckout checkout: list){
  651. if (checkout.getParentId()==null || checkout.getParentId() == 0) continue;
  652. if (checkout.getParentId().equals(in.getId())){
  653. userOrderCheckoutService.delete(checkout.getId());
  654. }
  655. }
  656. RemoveCheckout callback = removeCheckoutCallback.get(ProductType.ValueOf(in.getProductType()));
  657. callback.callback(in, list);
  658. // 计算购物车数量
  659. return userOrderCheckoutService.allByUser(userId, 0).size();
  660. }
  661. /**
  662. * 根据购物车生成对应订单信息
  663. * @param list
  664. * @return
  665. */
  666. public UserOrder preOrderWithCheckout(Integer userId, List<UserOrderCheckout> list){
  667. UserOrder order = UserOrder.builder()
  668. .userId(userId)
  669. .originMoney(BigDecimal.valueOf(0))
  670. .money(BigDecimal.valueOf(0))
  671. .build();
  672. // 记录订单优惠
  673. JSONObject promote = new JSONObject();
  674. order.setPromote(promote);
  675. // 记录订单类型
  676. JSONArray productTypes = new JSONArray();
  677. order.setProductTypes(productTypes);
  678. InitOrder callback;
  679. // 课程: 并包含套餐
  680. List<UserOrderCheckout> courseCheckout = list.stream().filter((checkout)-> checkout.getProductType().equals(ProductType.COURSE.key) || checkout.getProductType().equals(ProductType.COURSE_PACKAGE.key)).collect(Collectors.toList());
  681. callback = initOrderCallback.get(ProductType.COURSE);
  682. callback.callback(order, courseCheckout);
  683. if(courseCheckout.size() > 0){
  684. productTypes.add(ProductType.COURSE.key);
  685. }
  686. // 资料
  687. List<UserOrderCheckout> dataCheckout = list.stream().filter((checkout)-> checkout.getProductType().equals(ProductType.DATA.key)).collect(Collectors.toList());
  688. callback = initOrderCallback.get(ProductType.DATA);
  689. callback.callback(order, courseCheckout);
  690. if (dataCheckout.size() > 0){
  691. productTypes.add(ProductType.DATA.key);
  692. }
  693. // 服务
  694. List<UserOrderCheckout> serviceCheckout = list.stream().filter((checkout)-> checkout.getProductType().equals(ProductType.SERVICE.key)).collect(Collectors.toList());
  695. callback = initOrderCallback.get(ProductType.SERVICE);
  696. callback.callback(order, courseCheckout);
  697. if(serviceCheckout.size() > 0){
  698. productTypes.add(ProductType.SERVICE.key);
  699. }
  700. return order;
  701. }
  702. /**
  703. * 支付购物车
  704. * @param userId
  705. * @return
  706. */
  707. @Transactional
  708. public UserOrder makeOrder(Integer userId){
  709. List<UserOrderCheckout> list = userOrderCheckoutService.allByUser(userId, 0);
  710. UserOrder order = preOrderWithCheckout(userId, list);
  711. order = userOrderService.add(order);
  712. // 转移购物车信息
  713. userOrderCheckoutService.changeByUser(userId, 0, UserOrderCheckout.builder().orderId(order.getId()).build());
  714. return order;
  715. }
  716. /**
  717. * 立即购买
  718. * @param userId
  719. * @param checkout
  720. * @return
  721. */
  722. @Transactional
  723. public UserOrder makeOrderWithProduct(Integer userId, UserOrderCheckout checkout){
  724. List<UserOrderCheckout> list = new ArrayList<UserOrderCheckout>(){{add(checkout);}};
  725. UserOrder order = preOrderWithCheckout(userId, list);
  726. order = userOrderService.add(order);
  727. checkout.setOrderId(order.getId());
  728. userOrderCheckoutService.add(checkout);
  729. return order;
  730. }
  731. /**
  732. * 后台直接添加记录
  733. * @param record
  734. * @return
  735. */
  736. @Transactional
  737. public UserOrderRecord addRecord(UserOrderRecord record){
  738. InitRecord callback = initRecordCallback.get(ProductType.ValueOf(record.getProductType()));
  739. // 虚拟order
  740. callback.callback(UserOrder.builder().build(), record);
  741. return userOrderRecordService.add(record);
  742. }
  743. /**
  744. * 开通记录
  745. * @param userId
  746. * @param recordId
  747. * @return
  748. */
  749. @Transactional
  750. public UserOrderRecord useRecord(Integer userId, Integer recordId){
  751. UserOrderRecord in = userOrderRecordService.get(recordId);
  752. if (in == null){
  753. throw new ParameterException("记录不存在");
  754. }
  755. if (!in.getUserId().equals(userId)){
  756. throw new ParameterException("记录不存在");
  757. }
  758. UseRecord callback = useRecordCallback.get(ProductType.ValueOf(in.getProductType()));
  759. callback.callback(in);
  760. return in;
  761. }
  762. public void stopRecord(Integer recordId){
  763. UserOrderRecord in = userOrderRecordService.get(recordId);
  764. if (in == null){
  765. throw new ParameterException("记录不存在");
  766. }
  767. if (in.getIsStop()> 0){
  768. throw new ParameterException("已停用");
  769. }
  770. UseRecord callback = useRecordCallback.get(ProductType.ValueOf(in.getProductType()));
  771. callback.callback(in);
  772. }
  773. /**
  774. * 给用户邀请奖励: 7天vip
  775. * @param userId
  776. */
  777. public void giveInvite(Integer userId){
  778. UserOrderRecord record = UserOrderRecord.builder()
  779. .userId(userId)
  780. .service(ServiceKey.VIP.key)
  781. .param(ServiceVipKey.DAY7.key)
  782. .source(RecordSource.INVITE.key)
  783. .build();
  784. // 虚拟order
  785. record = initRecordCallback.get(ProductType.SERVICE).callback(UserOrder.builder().build(), record);
  786. userOrderRecordService.add(record);
  787. }
  788. /**
  789. * 给用户备考奖励: 7天vip
  790. * @param userId
  791. */
  792. public void givePrepare(Integer userId){
  793. UserOrderRecord record = UserOrderRecord.builder()
  794. .userId(userId)
  795. .service(ServiceKey.VIP.key)
  796. .param(ServiceVipKey.DAY7.key)
  797. .source(RecordSource.PREPARE.key)
  798. .build();
  799. // 虚拟order
  800. record = initRecordCallback.get(ProductType.SERVICE).callback(UserOrder.builder().build(), record);
  801. userOrderRecordService.add(record);
  802. }
  803. /**
  804. * 给用户实名认证奖励: 180天vip
  805. * @param userId
  806. */
  807. public void giveReal(Integer userId){
  808. UserOrderRecord record = UserOrderRecord.builder()
  809. .userId(userId)
  810. .service(ServiceKey.VIP.key)
  811. .param(ServiceVipKey.MONTH3.key)
  812. .source(RecordSource.REAL.key)
  813. .build();
  814. // 虚拟order
  815. record = initRecordCallback.get(ProductType.SERVICE).callback(UserOrder.builder().build(), record);
  816. userOrderRecordService.add(record);
  817. }
  818. }