zoujiajian 2 тижнів тому
батько
коміт
2a8b54cc10

+ 2 - 2
netflix-dao/src/main/java/com/cyksj/mapper/order/OrderDonTicketQueryMapper.java

@@ -10,7 +10,7 @@ public interface OrderDonTicketQueryMapper {
 
     @Select({
             "<script>",
-            "select r.item_index as itemIndex, r.relation_id as relationId,",
+            "select r.item_index as itemIndex, r.active_relation_id as relationId,",
             "r.status as deliveryStatus, gr.status as relationStatus,",
             "gr.start_time as startTime, gr.expiry_time as expiryTime,",
             "<choose>",
@@ -25,7 +25,7 @@ public interface OrderDonTicketQueryMapper {
             "<otherwise>null as account, null as password</otherwise>",
             "</choose>",
             "from order_don_ticket_record r",
-            "left join groups_relation gr on gr.id = r.relation_id",
+            "left join groups_relation gr on gr.id = r.active_relation_id",
             "left join groups_trips gt on gt.id = gr.groups_id",
             "left join account a on a.id = gt.account_id",
             "where r.order_id = #{orderId}",

+ 14 - 6
netflix-dao/src/main/java/com/cyksj/mapper/order/OrderDonTicketRecordMapper.java

@@ -63,7 +63,9 @@ public interface OrderDonTicketRecordMapper extends BaseMapper<OrderDonTicketRec
     OrderDonTicketRecord lockClaim(@Param("id") Long id,
                                    @Param("workerToken") String workerToken);
 
-    @Update("update order_don_ticket_record set status = 'success', relation_id = #{relationId}, worker_token = null, processing_time = null, error_msg = null, update_time = now() where id = #{id} and status = 'processing' and worker_token = #{workerToken}")
+    @Update("update order_don_ticket_record set status = 'success', relation_id = #{relationId}, " +
+            "worker_token = null, processing_time = null, error_msg = null, update_time = now() " +
+            "where id = #{id} and status = 'processing' and worker_token = #{workerToken}")
     int markSuccess(@Param("id") Long id, @Param("relationId") Long relationId, @Param("workerToken") String workerToken);
 
     @Update("update order_don_ticket_record set status = 'failed', worker_token = null, processing_time = null, error_msg = #{errorMsg}, update_time = now() where id = #{id} and status = 'processing' and worker_token = #{workerToken}")
@@ -117,23 +119,29 @@ public interface OrderDonTicketRecordMapper extends BaseMapper<OrderDonTicketRec
     int replaceActiveRelation(@Param("oldRelationId") Long oldRelationId,
                               @Param("newRelationId") Long newRelationId);
 
-    @Select("select r.* from order_don_ticket_record r inner join groups_relation gr on gr.id = r.relation_id where gr.groups_id = #{groupsId} and r.status = 'success' order by r.item_index")
+    @Select("select r.* from order_don_ticket_record r inner join groups_relation gr " +
+            "on gr.id = r.active_relation_id where gr.groups_id = #{groupsId} " +
+            "and r.status = 'success' order by r.item_index")
     List<OrderDonTicketRecord> selectSuccessfulByGroupsId(@Param("groupsId") Long groupsId);
 
     @Select("select distinct r.order_id from order_don_ticket_record r " +
             "inner join order_don o on o.id = r.order_id " +
-            "inner join groups_relation gr on gr.id = r.relation_id " +
+            "inner join groups_relation gr on gr.id = r.active_relation_id " +
             "where gr.groups_id = #{groupsId} and r.status = 'success' " +
             "and o.status in ('hasPayment', 'complete') order by r.order_id")
     List<Long> selectSuccessfulOrderIdsByGroupsId(@Param("groupsId") Long groupsId);
 
-    @Update("update order_don_ticket_record set status = 'cleared', worker_token = null, processing_time = null, error_msg = null, update_time = now() where active_relation_id = #{relationId} and status = 'success'")
+    @Update("update order_don_ticket_record set status = 'cleared', worker_token = null, " +
+            "processing_time = null, error_msg = null, update_time = now() " +
+            "where active_relation_id = #{relationId} and status = 'success'")
     int clearActiveRelation(@Param("relationId") Long relationId);
 
-    @Select("select * from order_don_ticket_record where active_relation_id = #{relationId} limit 1")
+    @Select("select * from order_don_ticket_record where active_relation_id = #{relationId} " +
+            "and status in ('success', 'refunding')")
     OrderDonTicketRecord selectActiveByRelationId(@Param("relationId") Long relationId);
 
-    @Select("select * from order_don_ticket_record where active_relation_id = #{relationId} limit 1 for update")
+    @Select("select * from order_don_ticket_record where active_relation_id = #{relationId} " +
+            "and status in ('success', 'refunding') for update")
     OrderDonTicketRecord selectActiveByRelationIdForUpdate(@Param("relationId") Long relationId);
 
     @Select("select count(*) from order_don_ticket_record where order_id = #{orderId} and status = #{status}")

+ 9 - 1
netflix-dao/src/main/resources/mapper/GroupRelationMapper.xml

@@ -156,6 +156,10 @@
         where groups_id = #{groupsId}
           and user_id = 0
           and status = 'none'
+          and not exists (
+              select 1 from order_don_ticket_record ticket
+              where ticket.active_relation_id = groups_relation.id
+          )
         order by rand() limit 1
     </select>
 
@@ -177,6 +181,10 @@
           and user_id = 0
           and num > #{relationNum}
           and status = 'outside'
+          and not exists (
+              select 1 from order_don_ticket_record ticket
+              where ticket.active_relation_id = groups_relation.id
+          )
         order by rand() limit 1
     </select>
 
@@ -502,4 +510,4 @@
         group by gur.operator
         order by num desc
     </select>
-</mapper>
+</mapper>

+ 1 - 1
netflix-service/src/main/java/com/cyksj/service/mange/impl/CmsOrderDonServiceImpl.java

@@ -848,7 +848,7 @@ public class CmsOrderDonServiceImpl extends ServiceImpl<OrderDonMapper,OrderDon>
         if (!isMultiQuantityTicketOwner(orderDon, relation)) {
             throw BusinessRuntimeException.getInstance("车票归属异常,relationId: {0}", relation.getId());
         }
-        relationClearService.clearTicket(relation, UserTicketClearedRecord.Source.refund);
+        relationClearService.clearRefundTicket(relation, activeRecord);
     }
 
     private Long currentTicketRelationId(OrderDonTicketRecord record) {

+ 9 - 0
netflix-service/src/main/java/com/cyksj/service/relation/GroupRelationClearService.java

@@ -1,6 +1,7 @@
 package com.cyksj.service.relation;
 
 import com.cyksj.model.entity.GroupsRelation;
+import com.cyksj.model.entity.OrderDonTicketRecord;
 import com.cyksj.model.entity.UserTicketClearedRecord;
 
 /*
@@ -16,6 +17,14 @@ public interface GroupRelationClearService {
 	 */
 	void clearTicket(GroupsRelation relation, UserTicketClearedRecord.Source source);
 
+	/**
+	 * Clears one ticket as part of a frozen multi-quantity whole-order refund.
+	 * The caller supplies the already locked slot so ownership is checked once
+	 * without issuing a duplicate FOR UPDATE query. This method must be called
+	 * inside the same transaction that acquired that slot lock.
+	 */
+	void clearRefundTicket(GroupsRelation relation, OrderDonTicketRecord refundingTicket);
+
 	/**
 	 * 续费换车票,清理之前的车票
 	 */

+ 1 - 0
netflix-service/src/main/java/com/cyksj/service/relation/impl/CmsGroupsRelationServiceImpl.java

@@ -152,6 +152,7 @@ public class CmsGroupsRelationServiceImpl implements CmsGroupsRelationService {
 				.eq(GroupsRelation::getGroupsId, groupsId)
 				.eq(GroupsRelation::getStatus, GroupsRelation.Status.none)
 				.eq(GroupsRelation::getUserId, 0)
+				.apply("not exists (select 1 from order_don_ticket_record ticket where ticket.active_relation_id = groups_relation.id)")
 				.orderByAsc(GroupsRelation::getNum)
 				.last("limit 1"));
 		if (relation != null) {

+ 21 - 4
netflix-service/src/main/java/com/cyksj/service/relation/impl/GroupRelationClearServiceImpl.java

@@ -64,16 +64,33 @@ public class GroupRelationClearServiceImpl implements GroupRelationClearService
 
 	@Override
 	public void clearTicket(GroupsRelation relation, UserTicketClearedRecord.Source source) {
+		clearTicket(relation, source, null);
+	}
+
+	@Override
+	public void clearRefundTicket(GroupsRelation relation, OrderDonTicketRecord refundingTicket) {
+		if (relation == null || relation.getId() == null || refundingTicket == null
+				|| refundingTicket.getId() == null
+				|| refundingTicket.getStatus() != OrderDonTicketRecord.Status.refunding
+				|| !relation.getId().equals(refundingTicket.getRelationId())) {
+			throw new IllegalArgumentException("valid refunding ticket is required");
+		}
+		clearTicket(relation, UserTicketClearedRecord.Source.refund, refundingTicket);
+	}
+
+	private void clearTicket(GroupsRelation relation, UserTicketClearedRecord.Source source,
+							 OrderDonTicketRecord lockedActiveTicket) {
 		Long relationId = relation.getId();
 		Long newRelationId = relation.getNewRelationId();
 		Integer num = relation.getNum();
 		final GroupsRelation.Status relationStatus = relation.getStatus();
-		OrderDonTicketRecord activeTicket = orderDonTicketRecordService
-				.getActiveByRelationIdForUpdate(relationId);
+		OrderDonTicketRecord activeTicket = lockedActiveTicket != null
+				? lockedActiveTicket
+				: orderDonTicketRecordService.getActiveByRelationIdForUpdate(relationId);
 		if (activeTicket != null
 				&& activeTicket.getStatus() == OrderDonTicketRecord.Status.refunding
-				&& source != UserTicketClearedRecord.Source.refund) {
-			throw new IllegalStateException("ticket refund is processing");
+				&& (source != UserTicketClearedRecord.Source.refund || lockedActiveTicket == null)) {
+			throw new IllegalStateException("refunding ticket must be cleared by its locked slot");
 		}
 		//记录用户被清除车票历史记录
 		GroupsRelationView groupsRelation = beanSearcher.searchFirst(GroupsRelationView.class,

+ 3 - 1
netflix-service/src/main/java/com/cyksj/service/relation/impl/GroupRelationFrontServiceImpl.java

@@ -294,7 +294,7 @@ public class GroupRelationFrontServiceImpl implements GroupRelationFrontService
 			Long orderId = orderDon != null ? orderDon.getId() : 0l;
 			conditionSql += String.format(" and (exists(select 1 from order_don o where o.relation_id = gr.id and o.user_id = gr.user_id and o.id = %s)" +
 					" or exists(select 1 from order_don_ticket_record r inner join order_don o on o.id = r.order_id" +
-					" where r.relation_id = gr.id and r.status = 'success' and o.user_id = gr.user_id and o.id = %s))",
+					" where r.active_relation_id = gr.id and r.status = 'success' and o.user_id = gr.user_id and o.id = %s))",
 					orderId, orderId);
 		}
 		SearchResult<RenewalView> list = beanSearcher.search(RenewalView.class, builder
@@ -643,6 +643,7 @@ public class GroupRelationFrontServiceImpl implements GroupRelationFrontService
 				.eq(GroupsRelation::getGroupsId, groupsId)
 				.eq(GroupsRelation::getStatus, GroupsRelation.Status.none)
 				.eq(GroupsRelation::getUserId, 0)
+				.apply("not exists (select 1 from order_don_ticket_record ticket where ticket.active_relation_id = groups_relation.id)")
 				.orderByAsc(GroupsRelation::getNum)
 				.last("limit 1"));
 		if (relation != null) {
@@ -725,6 +726,7 @@ public class GroupRelationFrontServiceImpl implements GroupRelationFrontService
 							.eq(GroupsRelation::getGroupsId, groupsId)
 							.eq(GroupsRelation::getUserId, 0)
 							.eq(GroupsRelation::getStatus, GroupsRelation.Status.outside)
+							.apply("not exists (select 1 from order_don_ticket_record ticket where ticket.active_relation_id = groups_relation.id)")
 							.last("limit 1"));
 					if (relation == null) {
 						relation = new GroupsRelation();

+ 2 - 0
netflix-service/src/main/java/com/cyksj/service/relation/impl/GroupsRelationChangeServiceImpl.java

@@ -77,6 +77,8 @@ public class GroupsRelationChangeServiceImpl implements GroupsRelationChangeServ
 			relation = relationMapper.selectOne(Wrappers.lambdaQuery(GroupsRelation.class)
 					.eq(GroupsRelation::getGroupsId, groupsTrips.getId())
 					.eq(GroupsRelation::getStatus, GroupsRelation.Status.none)
+					.eq(GroupsRelation::getUserId, 0)
+					.apply("not exists (select 1 from order_don_ticket_record ticket where ticket.active_relation_id = groups_relation.id)")
 					.last("limit 1"));
 		}
 		if (relation == null) {