OrderFlowService.java 48 KB

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