From 7361bd1d9740c3cd9cb3fb9fc5425e11048cd4e6 Mon Sep 17 00:00:00 2001 From: peng <peng.com> Date: 星期日, 28 九月 2025 11:35:27 +0800 Subject: [PATCH] 店铺优惠卷调整 --- framework/src/main/java/cn/lili/modules/lmk/service/impl/StoreCouponClaimRecordServiceImpl.java | 296 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 295 insertions(+), 1 deletions(-) diff --git a/framework/src/main/java/cn/lili/modules/lmk/service/impl/StoreCouponClaimRecordServiceImpl.java b/framework/src/main/java/cn/lili/modules/lmk/service/impl/StoreCouponClaimRecordServiceImpl.java index 375b685..5fa4568 100644 --- a/framework/src/main/java/cn/lili/modules/lmk/service/impl/StoreCouponClaimRecordServiceImpl.java +++ b/framework/src/main/java/cn/lili/modules/lmk/service/impl/StoreCouponClaimRecordServiceImpl.java @@ -1,21 +1,58 @@ package cn.lili.modules.lmk.service.impl; +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.date.DateUtil; +import cn.lili.common.exception.ServiceException; +import cn.lili.common.security.AuthUser; +import cn.lili.common.security.context.UserContext; +import cn.lili.modules.lmk.domain.entity.StoreCoupon; +import cn.lili.modules.lmk.domain.entity.StoreCouponSingle; +import cn.lili.modules.lmk.enums.general.PrizeStatusEnum; +import cn.lili.modules.lmk.enums.general.StoreCouponStausEnum; +import cn.lili.modules.lmk.service.StoreCouponService; +import cn.lili.modules.lmk.service.StoreCouponSingleService; +import cn.lili.modules.order.order.entity.dto.CouponExportDetailDTO; +import cn.lili.modules.order.order.entity.dto.StoreCouponClaimRecordDTO; +import cn.lili.modules.order.order.entity.enums.ClaimStatusEnum; +import cn.lili.modules.promotion.entity.dos.MemberCoupon; +import cn.lili.modules.promotion.entity.dto.search.MemberCouponSearchParams; +import cn.lili.modules.promotion.entity.vos.MemberCouponVO; +import cn.lili.modules.promotion.service.MemberCouponService; +import cn.lili.rocketmq.RocketmqSendCallbackBuilder; +import com.alibaba.fastjson.JSON; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import cn.lili.modules.lmk.domain.entity.StoreCouponClaimRecord; import cn.lili.modules.lmk.mapper.StoreCouponClaimRecordMapper; import cn.lili.modules.lmk.service.StoreCouponClaimRecordService; import cn.lili.base.Result; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import cn.lili.modules.lmk.domain.form.StoreCouponClaimRecordForm; import cn.lili.modules.lmk.domain.vo.StoreCouponClaimRecordVO; import cn.lili.modules.lmk.domain.query.StoreCouponClaimRecordQuery; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; +import org.redisson.api.RLock; +import org.redisson.api.RedissonClient; import org.springframework.stereotype.Service; import lombok.RequiredArgsConstructor; import cn.lili.utils.PageUtil; import org.springframework.beans.BeanUtils; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.transaction.support.TransactionSynchronization; +import org.springframework.transaction.support.TransactionSynchronizationManager; import org.springframework.util.Assert; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletResponse; +import java.net.URLEncoder; +import java.util.ArrayList; import java.util.List; +import java.util.Objects; import java.util.stream.Collectors; /** @@ -29,7 +66,11 @@ public class StoreCouponClaimRecordServiceImpl extends ServiceImpl<StoreCouponClaimRecordMapper, StoreCouponClaimRecord> implements StoreCouponClaimRecordService { private final StoreCouponClaimRecordMapper storeCouponClaimRecordMapper; - + private final RedissonClient redissonClient; + private static final String STORE_COUPON_CLAIM = "store_coupon_claim:"; + private final MemberCouponService memberCouponService; + private final StoreCouponService storeCouponService; + private final StoreCouponSingleService storeCouponSingleService; /** * 娣诲姞 * @param form @@ -116,4 +157,257 @@ .collect(Collectors.toList()); return Result.ok().data(vos); } + + @Override + @Transactional(rollbackFor = Exception.class) + public Result claimCoupon(String id) { + AuthUser currentUser = UserContext.getCurrentUser(); + if (currentUser == null) { + throw new ServiceException("褰撳墠鐢ㄦ埛娌℃湁鐧诲綍鏃犳硶棰嗗彇"); + } + String userId = currentUser.getId(); + String nickName = currentUser.getNickName(); + + //閿佷綇绀煎搧鐮乮d + RLock redissonLock = redissonClient.getLock(STORE_COUPON_CLAIM + id); + try { + redissonLock.lock(); + LambdaQueryWrapper<StoreCouponSingle> forUpdate = Wrappers.<StoreCouponSingle>lambdaQuery() + .eq(StoreCouponSingle::getId, id).last("FOR UPDATE"); + StoreCouponSingle storeCouponSingle = storeCouponSingleService.getOne(forUpdate); + if (storeCouponSingle == null) { + throw new ServiceException("褰撳墠绀煎搧鐮佷笉瀛樺湪"); + } + if (!ClaimStatusEnum.NOT_CLAIM.name().equals(storeCouponSingle.getClaimStatus())) { + throw new ServiceException("褰撳墠绀煎搧鐮佺姸鎬佸紓甯�"); + } + LambdaQueryWrapper<StoreCouponSingle> claimListQuery = Wrappers.<StoreCouponSingle>lambdaQuery() + .eq(StoreCouponSingle::getClaimUserId, userId) + .eq(StoreCouponSingle::getStoreCoupRef, storeCouponSingle.getStoreCoupRef()) + .eq(StoreCouponSingle::getClaimStatus, ClaimStatusEnum.CLAIM.name()); + List<StoreCouponSingle> claimList = storeCouponSingleService.list(claimListQuery); + if (!claimList.isEmpty()) { + throw new ServiceException("宸茬粡棰嗗彇杩囪绫诲瀷鐨勭ぜ鍝佺爜鏃犳硶棰嗗彇"); + } + //澶勭悊骞傜瓑闂闄愬埗涓�涓敤鎴峰彧鑳借搴楅摵棰嗗彇涓�绉嶄紭鎯犲嵎 + LambdaQueryWrapper<StoreCouponClaimRecord> memCoupon = Wrappers.<StoreCouponClaimRecord>lambdaQuery() + .eq(StoreCouponClaimRecord::getUserId, userId) + .eq(StoreCouponClaimRecord::getCouponId, storeCouponSingle.getCouponId()); + List<StoreCouponClaimRecord> list = this.list(memCoupon); + if (!list.isEmpty()){ + throw new ServiceException("褰撳墠鐢ㄦ埛宸茬粡棰嗗彇杩囦簡鏃犳硶鍐嶆棰嗗彇"); + } + //鏇存柊鍗曞搧琚鍙栫殑璁板綍 + storeCouponSingle.setClaimStatus(ClaimStatusEnum.CLAIM.name()); + storeCouponSingle.setClaimUserId(userId); + storeCouponSingle.setClaimUserName(nickName); + //鏍¢獙鏄惁鍦ㄥ崟鍝佸嵎绫婚鍙栬繃 + LambdaQueryWrapper<StoreCoupon> storeCoupQuery = Wrappers.<StoreCoupon>lambdaQuery() + .eq(StoreCoupon::getId, storeCouponSingle.getStoreCoupRef()).last("FOR UPDATE"); + StoreCoupon storeCoupon = storeCouponService.getOne(storeCoupQuery); + if (storeCoupon == null) { + throw new ServiceException("褰撳墠搴楅摵浼樻儬鍗蜂笉瀛樺湪"); + } + if (!StoreCouponStausEnum.ENABLE.name().equals(storeCoupon.getStatus())) { + throw new ServiceException("褰撳墠搴楅摵浼樻儬鍗风姸鎬佸紓甯�"); + } + //棰嗗彇瀵瑰簲鐨勪紭鎯犲嵎鍐欏叆璁板綍 + MemberCoupon memberCoupon = memberCouponService.receiveCoupon(storeCouponSingle.getCouponId(), userId, nickName); + String memberCouponId = memberCoupon.getId(); + storeCouponSingle.setMemberCouponId(memberCouponId); + storeCouponSingleService.updateById(storeCouponSingle); + StoreCouponClaimRecord storeCouponClaimRecord = getStoreCouponClaimRecord(storeCouponSingle, userId); + storeCouponClaimRecord.setMemberCouponId(memberCouponId); + this.save(storeCouponClaimRecord); + LambdaUpdateWrapper<StoreCoupon> updateStoreCoupon = Wrappers.<StoreCoupon>lambdaUpdate().eq(StoreCoupon::getId, storeCoupon.getId()) + .set(StoreCoupon::getCouponClaimNum, storeCoupon.getCouponClaimNum() + 1) + .ge(StoreCoupon::getCouponNum, storeCoupon.getCouponClaimNum() + 1); + boolean update = storeCouponService.update(updateStoreCoupon); + if (!update) { + throw new ServiceException("鏇存柊澶辫触"); + } + //棰嗗彇鎴愬姛杩斿洖浼樻儬鍗穒d鐢ㄤ簬璺宠浆璐墿浣跨敤 + return Result.ok().data(storeCouponSingle.getCouponId()); + + } finally { + TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() { + @Override + public void afterCommit() { + if (redissonLock.isHeldByCurrentThread()) { + redissonLock.unlock(); + } + } + + @Override + public void afterCompletion(int status) { + // 纭繚鍗充娇鍦ㄤ簨鍔″洖婊氱殑鎯呭喌涓嬩篃鑳介噴鏀鹃攣 + if (redissonLock.isHeldByCurrentThread()) { + redissonLock.unlock(); + } + } + + }); + + } + } + private XSSFWorkbook initCouponExportData(List<StoreCouponClaimRecordVO> list) { + // 杞崲VO涓篋TO锛堝鏋淒TO涓嶸O瀛楁涓�鑷达紝鍙洿鎺ヤ娇鐢╒O绠�鍖栦唬鐮侊級 + List<StoreCouponClaimRecordDTO> dtos = new ArrayList<>(); + for (StoreCouponClaimRecordVO vo : list) { + StoreCouponClaimRecordDTO dto = new StoreCouponClaimRecordDTO(); + BeanUtil.copyProperties(vo, dto); + dtos.add(dto); + } + System.out.println("-----------------------"); + System.out.println(dtos); + XSSFWorkbook workbook = new XSSFWorkbook(); + Sheet sheet = workbook.createSheet("浼樻儬鍒搁鍙栬褰�"); + // 鍒涘缓琛ㄥご + Row header = sheet.createRow(0); + String[] headers = { + "浼氬憳鍚嶇О", "浼樻儬鍒稿悕绉�", "鍙戝竷搴楅摵", "闈㈤/鎶樻墸", + "鑾峰彇鏂瑰紡", "浼氬憳浼樻儬鍒哥姸鎬�", "浼樻儬鍒哥被鍨�", + "浣跨敤璧峰鏃堕棿", "鎴鏃堕棿" + }; + for (int i = 0; i < headers.length; i++) { + Cell cell = header.createCell(i); + cell.setCellValue(headers[i]); + } + + // 濉厖鏁版嵁锛堝鍔犵┖鍊煎鐞嗭紝閬垮厤NPE锛� + for (int i = 0; i < dtos.size(); i++) { + StoreCouponClaimRecordDTO dto = dtos.get(i); + Row row = sheet.createRow(i + 1); + + // 1. 浼氬憳鍚嶇О锛堝彲鑳戒负null锛� + row.createCell(0).setCellValue(Objects.nonNull(dto.getMemberName()) ? dto.getMemberName() : ""); + + // 2. 浼樻儬鍒稿悕绉帮紙鍙兘涓簄ull锛� + row.createCell(1).setCellValue(Objects.nonNull(dto.getCouponName()) ? dto.getCouponName() : ""); + + // 3. 鍙戝竷搴楅摵锛堝鐞唒latform鐗规畩鍊硷紝榛樿绌哄瓧绗︿覆锛� + String storeName = dto.getStoreName(); + if ("platform".equals(storeName)) { + row.createCell(2).setCellValue("骞冲彴"); + } else { + row.createCell(2).setCellValue(Objects.nonNull(storeName) ? storeName : ""); + } + + // 4. 闈㈤/鎶樻墸锛堜紭鍏堟樉绀烘姌鎵o紝鍏舵鏄剧ず闈㈤锛岄伩鍏嶈鐩栵級 + Cell amountCell = row.createCell(3); + if (Objects.nonNull(dto.getDiscount())) { + amountCell.setCellValue(dto.getDiscount() + "鎶�"); + } else if (Objects.nonNull(dto.getPrice())) { + amountCell.setCellValue(dto.getPrice() + "鍏�"); // 缁熶竴鐢�"鍏�"鏇磋鑼� + } else { + amountCell.setCellValue(""); // 鍧囦负绌烘椂鏄剧ず绌� + } + + + // 4. 鑾峰彇鏂瑰紡锛堣ˉ鍏呴粯璁ゆ湭鐭ョ姸鎬侊紝瑕嗙洊鎵�鏈夋灇涓惧�硷級 + String getType = dto.getGetType(); + String getTypeDesc; + switch (getType) { + case "FREE": + getTypeDesc = "鍏嶈垂鑾峰彇"; + break; + case "ACTIVITY": + getTypeDesc = "娲诲姩鑾峰彇"; + break; + case "INSIDE": // 娉ㄦ剰锛氬師浠g爜lime鏄鑹诧紝瀹為檯鏋氫妇搴斾负INSIDE + getTypeDesc = "鍐呰喘"; + break; + default: + getTypeDesc = "鏈煡"; + } + row.createCell(4).setCellValue(getTypeDesc); + + // 5. 浼氬憳浼樻儬鍒哥姸鎬侊紙瑕嗙洊鎵�鏈夊彲鑳界姸鎬侊級 + String status = dto.getMemberCouponStatus(); + String statusDesc; + switch (status) { + case "NEW": + statusDesc = "宸查鍙�"; + break; + case "USED": + statusDesc = "宸蹭娇鐢�"; + break; + case "EXPIRE": + statusDesc = "宸茶繃鏈�"; + break; + case "CLOSED": + statusDesc = "宸蹭綔搴�"; + break; + default: + statusDesc = "鏈煡鐘舵��"; + } + row.createCell(5).setCellValue(statusDesc); + + // 6. 浼樻儬鍒哥被鍨嬶紙琛ュ厖榛樿澶勭悊锛� + String couponType = dto.getCouponType(); + String couponTypeDesc; + if ("DISCOUNT".equals(couponType)) { + couponTypeDesc = "鎵撴姌"; + } else if ("PRICE".equals(couponType)) { + couponTypeDesc = "鍑忓厤鐜伴噾"; + } else { + couponTypeDesc = "鏈煡绫诲瀷"; + } + row.createCell(6).setCellValue(couponTypeDesc); + + + // 10. 浣跨敤璧峰鏃堕棿锛堝鐞唍ull锛屾牸寮忓寲鏃堕棿锛� + Cell startTimeCell = row.createCell(7); + if (Objects.nonNull(dto.getStartTime())) { + startTimeCell.setCellValue(DateUtil.formatDateTime(dto.getStartTime())); + } else { + startTimeCell.setCellValue(""); + } + + // 11. 鎴鏃堕棿锛堝悓涓婏級 + Cell endTimeCell = row.createCell(8); + if (Objects.nonNull(dto.getEndTime())) { + endTimeCell.setCellValue(DateUtil.formatDateTime(dto.getEndTime())); + } else { + endTimeCell.setCellValue(""); + } + } + + return workbook; + } + + @Override + public void queryExportCoupon(HttpServletResponse response, StoreCouponClaimRecordQuery query) { + List<StoreCouponClaimRecordVO> exportData = baseMapper.getExportData(query); + XSSFWorkbook workbook = initCouponExportData(exportData); + + try { + // 璁剧疆鍝嶅簲澶� + String fileName = URLEncoder.encode("浼樻儬鍒搁鍙栬褰�", "UTF-8"); + response.setContentType("application/vnd.ms-excel;charset=UTF-8"); + response.setHeader("Content-Disposition", "attachment;filename=" + fileName + ".xlsx"); + + ServletOutputStream out = response.getOutputStream(); + workbook.write(out); + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + workbook.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + private static StoreCouponClaimRecord getStoreCouponClaimRecord(StoreCouponSingle storeCouponSingle, String userId) { + StoreCouponClaimRecord storeCouponClaimRecord = new StoreCouponClaimRecord(); + storeCouponClaimRecord.setCouponId(storeCouponSingle.getCouponId()); + storeCouponClaimRecord.setCouponName(storeCouponSingle.getCouponName()); + storeCouponClaimRecord.setStoreId(storeCouponSingle.getStoreId()); + storeCouponClaimRecord.setStoreName(storeCouponSingle.getStoreName()); + storeCouponClaimRecord.setUserId(userId); + storeCouponClaimRecord.setStoreCouponId(storeCouponSingle.getStoreCoupRef()); + return storeCouponClaimRecord; + } } -- Gitblit v1.8.0