@@ -3,7 +3,6 @@ package com.gxwebsoft.glt.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper ;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper ;
import com.gxwebsoft.glt.entity.GltTicketTemplate ;
import com.gxwebsoft.glt.entity.GltTicketOrder ;
import com.gxwebsoft.glt.entity.GltUserTicket ;
import com.gxwebsoft.glt.entity.GltUserTicketLog ;
import com.gxwebsoft.glt.entity.GltUserTicketRelease ;
@@ -19,7 +18,6 @@ import org.springframework.transaction.support.TransactionTemplate;
import java.time.LocalDate ;
import java.time.LocalDateTime ;
import java.time.LocalTime ;
import java.time.format.DateTimeFormatter ;
import java.util.ArrayList ;
import java.util.HashSet ;
import java.util.List ;
@@ -57,7 +55,6 @@ public class GltTicketIssueService {
private final GltUserTicketService gltUserTicketService ;
private final GltUserTicketReleaseService gltUserTicketReleaseService ;
private final GltUserTicketLogService gltUserTicketLogService ;
private final GltTicketOrderService gltTicketOrderService ;
private final TransactionTemplate transactionTemplate ;
/**
@@ -220,38 +217,29 @@ public class GltTicketIssueService {
return IssueOutcome . ALREADY_ISSUED ;
}
// water 套餐场景:订单表 totalNum 往往更可信(有些订单商品行会出现 totalNum != 订单总数的情况)
int rawBuyQty = og . getTotalNum ( ) ! = null ? og . getTotalNum ( ) : 0 ;
if ( order . getTotalNum ( ) ! = null & & order . getTotalNum ( ) > 0 & & Objects . equals ( order . getFormId ( ) , og . getGoodsId ( ) ) ) {
rawBuyQty = order . getTotalNum ( ) ;
}
if ( rawBuyQty < = 0 ) {
int buyQty = og . getTotalNum ( ) ! = null ? og . getTotalNum ( ) : 0 ;
if ( buyQty < = 0 ) {
log . warn ( " 套票发放跳过:购买数量无效 - tenantId={}, orderNo={}, orderGoodsId={}, totalNum={} " ,
tenantId , order . getOrderNo ( ) , og . getId ( ) , og . getTotalNum ( ) ) ;
return IssueOutcome . SKIPPED ;
}
Integer minBuyQty = template . getMinBuyQty ( ) ;
if ( minBuyQty ! = null & & minBuyQty > 0 & & rawB uyQty < minBuyQty ) {
if ( minBuyQty ! = null & & minBuyQty > 0 & & b uyQty < minBuyQty ) {
log . info ( " 套票发放跳过:未达到最小购买数量 - tenantId={}, orderNo={}, buyQty={}, minBuyQty={} " ,
tenantId , order . getOrderNo ( ) , rawB uyQty, minBuyQty ) ;
tenantId , order . getOrderNo ( ) , b uyQty, minBuyQty ) ;
return IssueOutcome . SKIPPED ;
}
int giftMultiplier = template . getGiftMultiplier ( ) ! = null ? template . getGiftMultiplier ( ) : 0 ;
int giftQty = rawB uyQty * Math . max ( giftMultiplier , 0 ) ;
int giftQty = b uyQty * Math . max ( giftMultiplier , 0 ) ;
// 默认仅把“赠送量”计入水票账户;如需把购买量也纳入,设置 includeBuyQty=true 。
int buyQtyForTicket = Boolean . TRUE . equals ( template . getIncludeBuyQty ( ) ) ? rawBuyQty : 0 ;
// 购买量( buyQtyForTicket) 应立即可用; 赠送量( giftQty) 进入冻结并按计划释放。
int availableQty = buyQtyForTicket ;
int frozenQty = giftQty ;
int totalQty = availableQty + frozenQty ;
// 购买量( buyQty) 应立即可用; 赠送量( giftQty) 进入冻结并按计划释放 。
int totalQty = buyQty + giftQty ;
if ( totalQty < = 0 ) {
log . info ( " 套票发放跳过: 计算结果为0 - tenantId={}, orderNo={}, buyQty={}, giftMultiplier={}, includeBuyQty={} " ,
tenantId , order . getOrderNo ( ) , rawB uyQty, giftMultiplier , template . getIncludeBuyQty ( ) ) ;
tenantId , order . getOrderNo ( ) , b uyQty, giftMultiplier , template . getIncludeBuyQty ( ) ) ;
return IssueOutcome . SKIPPED ;
}
@@ -264,11 +252,12 @@ public class GltTicketIssueService {
userTicket . setOrderNo ( order . getOrderNo ( ) ) ;
userTicket . setOrderGoodsId ( og . getId ( ) ) ;
userTicket . setTotalQty ( totalQty ) ;
userTicket . setAvailableQty ( available Qty) ;
userTicket . setFrozenQty ( frozen Qty) ;
userTicket . setAvailableQty ( buy Qty) ;
userTicket . setFrozenQty ( gift Qty) ;
userTicket . setUsedQty ( 0 ) ;
// 已释放数量: 仅用于统计“从冻结释放到可用”的累计值; 初始为0( 释放任务会递增它)
userTicket . setReleasedQty ( 0 ) ;
// 初始可用量来自“购买量”,视为 已释放
userTicket . setReleasedQty ( buyQty ) ;
userTicket . setOrderGoodsQty ( og . getTotalNum ( ) ) ;
userTicket . setUserId ( order . getUserId ( ) ) ;
userTicket . setSortNumber ( 0 ) ;
userTicket . setComments ( " 订单发放套票 " ) ;
@@ -280,15 +269,25 @@ public class GltTicketIssueService {
gltUserTicketService . save ( userTicket ) ;
// 生成释放计划(按月)
LocalDateTime baseTime = order . getPayTime ( ) ! = null ? order . getPayTime ( ) : order . getCreateTime ( ) ;
if ( baseTime = = null ) {
baseTime = now ;
}
List < GltUserTicketRelease > releases = buildReleasePlan ( template , userTicket , baseTime , giftQty , now ) ;
if ( ! releases . isEmpty ( ) ) {
gltUserTicketReleaseService . saveBatch ( releases ) ;
}
// 发放流水
GltUserTicketLog issueLog = new GltUserTicketLog ( ) ;
issueLog . setUserTicketId ( userTicket . getId ( ) ) ;
issueLog . setChangeType ( CHANGE_TYPE_ISSUE ) ;
issueLog . setChangeAvailable ( available Qty) ;
issueLog . setChangeFrozen ( frozen Qty) ;
issueLog . setChangeAvailable ( buy Qty) ;
issueLog . setChangeFrozen ( gift Qty) ;
issueLog . setChangeUsed ( 0 ) ;
issueLog . setAvailableAfter ( available Qty) ;
issueLog . setFrozenAfter ( frozen Qty) ;
issueLog . setAvailableAfter ( buy Qty) ;
issueLog . setFrozenAfter ( gift Qty) ;
issueLog . setUsedAfter ( 0 ) ;
issueLog . setOrderId ( order . getOrderId ( ) ) ;
issueLog . setOrderNo ( order . getOrderNo ( ) ) ;
@@ -302,69 +301,31 @@ public class GltTicketIssueService {
issueLog . setUpdateTime ( now ) ;
gltUserTicketLogService . save ( issueLog ) ;
if ( order . getTotalNum ( ) ! = null & & og . getTotalNum ( ) ! = null & & ! Objects . equals ( order . getTotalNum ( ) , og . getTotalNum ( ) ) ) {
log . info ( " 套票发放提示:订单总数量与订单商品数量不一致 - tenantId={}, orderNo={}, orderTotalNum={}, orderGoodsId={}, goodsId={}, orderGoodsTotalNum={} " ,
tenantId , order . getOrderNo ( ) , order . getTotalNum ( ) , og . getId ( ) , og . getGoodsId ( ) , og . getTotalNum ( ) ) ;
}
// 按模板配置:自动“使用掉第一次水票”(起始送水数量)
Integer startSendQtyObj = template . getStartSendQty ( ) ;
int startSendQty = startSendQtyObj ! = null ? startSendQtyObj : 0 ;
if ( startSendQty > 0 ) {
int availableBefore = userTicket . getAvailableQty ( ) ! = null ? userTicket . getAvailableQty ( ) : 0 ;
int frozenBefore = userTicket . getFrozenQty ( ) ! = null ? userTicket . getFrozenQty ( ) : 0 ;
int usedBefore = userTicket . getUsedQty ( ) ! = null ? userTicket . getUsedQty ( ) : 0 ;
int toUse = Math . min ( startSendQty , availableBefore + frozenBefore ) ;
int toUse = Math . min ( startSendQty , availableBefore ) ;
if ( toUse > 0 ) {
int useFromAvailable = Math . min ( toUse , availableBefor e) ;
int useFromFrozen = Math . min ( toUse - useFromAvailable , frozenBefore ) ;
userTicket . setAvailableQty ( availableBefore - useFromAvailable ) ;
userTicket . setFrozenQty ( frozenBefore - useFromFrozen ) ;
userTicket . setAvailableQty ( availableBefore - toUs e) ;
userTicket . setUsedQty ( usedBefore + toUse ) ;
userTicket . setUpdateTime ( now ) ;
if ( ! gltUserTicketService . updateById ( userTicket ) ) {
throw new IllegalStateException ( " 起始送水核销失败:更新用户水票失败 userTicketId= " + userTicket . getId ( ) ) ;
}
// 同步生成一条“送水订单”(待配送),用于承载这次起始送水的核销。
// 这里不走 createWithWriteOff( 它会再次扣减水票) , 而是复用本次已完成的扣减结果。
GltTicketOrder firstOrder = new GltTicketOrder ( ) ;
firstOrder . setUserTicketId ( userTicket . getId ( ) ) ;
firstOrder . setStoreId ( order . getStoreId ( ) ) ;
firstOrder . setWarehouseId ( order . getWarehouseId ( ) ) ;
firstOrder . setAddressId ( order . getAddressId ( ) ) ;
firstOrder . setAddress ( order . getAddress ( ) ) ;
firstOrder . setBuyerRemarks ( order . getBuyerRemarks ( ) ) ;
firstOrder . setPrice ( order . getPrice ( ) ) ;
firstOrder . setTotalNum ( toUse ) ;
LocalDateTime sendTimeBase = order . getPayTime ( ) ! = null ? order . getPayTime ( ) : ( order . getCreateTime ( ) ! = null ? order . getCreateTime ( ) : now ) ;
firstOrder . setSendTime ( sendTimeBase . format ( DateTimeFormatter . ofPattern ( " yyyy-MM-dd HH:mm:ss " ) ) ) ;
firstOrder . setDeliveryStatus ( GltTicketOrderService . DELIVERY_STATUS_WAITING ) ;
firstOrder . setUserId ( order . getUserId ( ) ) ;
firstOrder . setSortNumber ( 0 ) ;
firstOrder . setComments ( " 起始送水自动生成 " ) ;
firstOrder . setStatus ( 0 ) ;
firstOrder . setDeleted ( 0 ) ;
firstOrder . setTenantId ( tenantId ) ;
firstOrder . setCreateTime ( now ) ;
firstOrder . setUpdateTime ( now ) ;
if ( ! gltTicketOrderService . save ( firstOrder ) ) {
throw new IllegalStateException ( " 起始送水核销失败:生成送水订单失败 userTicketId= " + userTicket . getId ( ) ) ;
}
gltUserTicketService . updateById ( userTicket ) ;
GltUserTicketLog writeOffLog = new GltUserTicketLog ( ) ;
writeOffLog . setUserTicketId ( userTicket . getId ( ) ) ;
writeOffLog . setChangeType ( CHANGE_TYPE_START_SEND_WRITE_OFF ) ;
writeOffLog . setChangeAvailable ( - useFromAvailabl e) ;
writeOffLog . setChangeFrozen ( - useFromFrozen ) ;
writeOffLog . setChangeAvailable ( - toUs e) ;
writeOffLog . setChangeFrozen ( 0 ) ;
writeOffLog . setChangeUsed ( toUse ) ;
writeOffLog . setAvailableAfter ( userTicket . getAvailableQty ( ) ) ;
writeOffLog . setFrozenAfter ( userTicket . getFrozenQty ( ) ! = null ? userTicket . getFrozenQty ( ) : 0 ) ;
writeOffLog . setUsedAfter ( userTicket . getUsedQty ( ) ) ;
// 关联本次生成的送水订单(与 createWithWriteOff 行为一致)
writeOffLog . setOrderId ( firstO rder. getId ( ) ) ;
writeOffLog . setOrderNo ( firstO rder. getId ( ) = = null ? null : String . valueOf ( firstOrder . getId ( ) ) ) ;
// 关联原始商城订单,便于追溯该次自动核销来源
writeOffLog . setOrderId ( o rder. getOrder Id ( ) ) ;
writeOffLog . setOrderNo ( o rder. getOrderNo ( ) ) ;
writeOffLog . setUserId ( order . getUserId ( ) ) ;
writeOffLog . setSortNumber ( 0 ) ;
writeOffLog . setComments ( " 起始送水自动核销 " ) ;
@@ -377,19 +338,6 @@ public class GltTicketIssueService {
}
}
// 生成释放计划(按月):以“当前冻结量”为准(若起始送水消耗了冻结票,则相应减少释放计划)
int frozenToRelease = userTicket . getFrozenQty ( ) ! = null ? userTicket . getFrozenQty ( ) : 0 ;
if ( frozenToRelease > 0 ) {
LocalDateTime baseTime = order . getPayTime ( ) ! = null ? order . getPayTime ( ) : order . getCreateTime ( ) ;
if ( baseTime = = null ) {
baseTime = now ;
}
List < GltUserTicketRelease > releases = buildReleasePlan ( template , userTicket , baseTime , frozenToRelease , now ) ;
if ( ! releases . isEmpty ( ) ) {
gltUserTicketReleaseService . saveBatch ( releases ) ;
}
}
log . info ( " 套票发放成功 - tenantId={}, orderNo={}, orderGoodsId={}, templateId={}, userTicketId={}, totalQty={} " ,
tenantId , order . getOrderNo ( ) , og . getId ( ) , template . getId ( ) , userTicket . getId ( ) , totalQty ) ;