FlashDeliveryOrderMapper.xml 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  3. <mapper namespace="com.ruoyi.system.mapper.flash.FlashDeliveryOrderMapper">
  4. <resultMap id="FlashDeliveryOrderResult" type="FlashDeliveryOrder">
  5. <id property="id" column="id"/>
  6. <result property="orderNo" column="order_no"/>
  7. <result property="clientRequestId" column="client_request_id"/>
  8. <result property="userId" column="user_id"/>
  9. <result property="receiverUserId" column="receiver_user_id"/>
  10. <result property="riderId" column="rider_id"/>
  11. <result property="serviceType" column="service_type"/>
  12. <result property="deliveryType" column="delivery_type"/>
  13. <result property="vehicleType" column="vehicle_type"/>
  14. <result property="status" column="status"/>
  15. <!-- canAdminCancel 是服务层按站点计算的只读字段,不映射/写入数据库。 -->
  16. <result property="isDisplay" column="is_display"/>
  17. <result property="deliveryMode" column="delivery_mode"/>
  18. <result property="scheduledPickupStartAt" column="scheduled_pickup_start_at"/>
  19. <result property="scheduledPickupEndAt" column="scheduled_pickup_end_at"/>
  20. <result property="pinRequired" column="pin_required"/>
  21. <result property="deliveryPinCode" column="delivery_pin_code"/>
  22. <result property="pickupName" column="pickup_name"/>
  23. <result property="pickupPhone" column="pickup_phone"/>
  24. <result property="pickupAddress" column="pickup_address"/>
  25. <result property="pickupAddressDetail" column="pickup_address_detail"/>
  26. <result property="pickupCity" column="pickup_city"/>
  27. <result property="pickupArea" column="pickup_area"/>
  28. <result property="pickupHandoffMethod" column="pickup_handoff_method"/>
  29. <result property="pickupLongitude" column="pickup_longitude"/>
  30. <result property="pickupLatitude" column="pickup_latitude"/>
  31. <result property="deliveryName" column="delivery_name"/>
  32. <result property="deliveryPhone" column="delivery_phone"/>
  33. <result property="deliveryAddress" column="delivery_address"/>
  34. <result property="deliveryAddressDetail" column="delivery_address_detail"/>
  35. <result property="deliveryCity" column="delivery_city"/>
  36. <result property="deliveryArea" column="delivery_area"/>
  37. <result property="deliveryHandoffMethod" column="delivery_handoff_method"/>
  38. <result property="deliveryLongitude" column="delivery_longitude"/>
  39. <result property="deliveryLatitude" column="delivery_latitude"/>
  40. <result property="distanceMeters" column="distance_meters"/>
  41. <result property="distanceSource" column="distance_source"/>
  42. <result property="estimatedDurationSeconds" column="estimated_duration_seconds"/>
  43. <result property="amount" column="amount"/>
  44. <result property="currency" column="currency"/>
  45. <result property="payType" column="pay_type"/>
  46. <result property="paymentStatus" column="payment_status"/>
  47. <result property="pricingId" column="pricing_id"/>
  48. <result property="pricingVersion" column="pricing_version"/>
  49. <result property="pricingStartTime" column="pricing_start_time"/>
  50. <result property="pricingEndTime" column="pricing_end_time"/>
  51. <result property="startingDistance" column="starting_distance"/>
  52. <result property="startingFare" column="starting_fare"/>
  53. <result property="distance" column="distance"/>
  54. <result property="freight" column="freight"/>
  55. <result property="distanceFee" column="distance_fee"/>
  56. <result property="baseDeliveryFee" column="base_delivery_fee"/>
  57. <result property="urgentRate" column="urgent_rate"/>
  58. <result property="minimumUrgentFee" column="minimum_urgent_fee"/>
  59. <result property="urgentFee" column="urgent_fee"/>
  60. <result property="tipAmount" column="tip_amount"/>
  61. <result property="userNote" column="user_note"/>
  62. <result property="version" column="version"/>
  63. <result property="acceptedAt" column="accepted_at"/>
  64. <result property="pickedUpAt" column="picked_up_at"/>
  65. <result property="deliveredAt" column="delivered_at"/>
  66. <result property="completedAt" column="completed_at"/>
  67. <result property="cancelledAt" column="cancelled_at"/>
  68. <result property="riderStars" column="rider_stars"/>
  69. <result property="cancelReason" column="cancel_reason"/>
  70. <result property="cancelOperatorType" column="cancel_operator_type"/>
  71. <result property="cancelOperatorId" column="cancel_operator_id"/>
  72. <result property="createTime" column="create_time"/>
  73. <result property="updateTime" column="update_time"/>
  74. <result property="pickupStopCount" column="pickup_stop_count"/>
  75. <result property="pickedUpStopCount" column="picked_up_stop_count"/>
  76. <result property="deliveryStopCount" column="delivery_stop_count"/>
  77. <result property="deliveredStopCount" column="delivered_stop_count"/>
  78. <result property="currentTargetStopId" column="current_target_stop_id"/>
  79. <result property="problemStopId" column="problem_stop_id"/>
  80. <result property="handlingResult" column="handling_result"/>
  81. <result property="pickedGoodsDisposition" column="picked_goods_disposition"/>
  82. </resultMap>
  83. <select id="selectByUserRequestId" resultMap="FlashDeliveryOrderResult">
  84. select * from flash_delivery_order where user_id = #{userId} and client_request_id = #{clientRequestId} limit 1
  85. </select>
  86. <!-- 抢单必须在单条 SQL 中同时校验状态和骑手为空,避免并发查询后重复绑定。 -->
  87. <update id="accept">
  88. update flash_delivery_order
  89. set rider_id=#{riderId}, status='ACCEPTED', accepted_at=#{now}, update_time=#{now}, version = version + 1
  90. where id=#{id} and status = 'WAITING_ACCEPTANCE' and rider_id is null and is_display = true
  91. and (delivery_mode = 'NOW' or (scheduled_pickup_start_at &lt;= #{now}
  92. and scheduled_pickup_end_at &gt; #{now}))
  93. </update>
  94. <!-- 编辑与抢单竞争时,由同一订单行的原子条件更新决定谁先成功。 -->
  95. <update id="updateWaitingAddress">
  96. update flash_delivery_order
  97. set pickup_stop_count = #{order.pickupStopCount}, picked_up_stop_count = 0, current_target_stop_id = null,
  98. delivery_stop_count = #{order.deliveryStopCount}, delivered_stop_count = 0,
  99. pickup_name = #{order.pickupName}, pickup_phone = #{order.pickupPhone},
  100. pickup_address = #{order.pickupAddress}, pickup_address_detail = #{order.pickupAddressDetail},
  101. pickup_city = #{order.pickupCity}, pickup_area = #{order.pickupArea},
  102. pickup_handoff_method = #{order.pickupHandoffMethod},
  103. pickup_longitude = #{order.pickupLongitude}, pickup_latitude = #{order.pickupLatitude},
  104. delivery_name = #{order.deliveryName}, delivery_phone = #{order.deliveryPhone},
  105. delivery_address = #{order.deliveryAddress}, delivery_address_detail = #{order.deliveryAddressDetail},
  106. delivery_city = #{order.deliveryCity}, delivery_area = #{order.deliveryArea},
  107. delivery_handoff_method = #{order.deliveryHandoffMethod},
  108. delivery_longitude = #{order.deliveryLongitude}, delivery_latitude = #{order.deliveryLatitude},
  109. receiver_user_id = #{order.receiverUserId},
  110. distance_meters = #{order.distanceMeters}, distance_source = #{order.distanceSource},
  111. estimated_duration_seconds = #{order.estimatedDurationSeconds},
  112. pricing_id = #{order.pricingId}, pricing_version = #{order.pricingVersion},
  113. pricing_start_time = #{order.pricingStartTime}, pricing_end_time = #{order.pricingEndTime},
  114. starting_distance = #{order.startingDistance}, starting_fare = #{order.startingFare},
  115. distance = #{order.distance}, freight = #{order.freight},
  116. urgent_rate = #{order.urgentRate}, minimum_urgent_fee = #{order.minimumUrgentFee},
  117. distance_fee = #{order.distanceFee}, base_delivery_fee = #{order.baseDeliveryFee},
  118. urgent_fee = #{order.urgentFee}, amount = #{order.amount},
  119. update_time = #{order.updateTime}, version = version + 1
  120. where id = #{order.id} and user_id = #{order.userId}
  121. and status = 'WAITING_ACCEPTANCE' and rider_id is null and version = #{expectedVersion}
  122. </update>
  123. <update id="updateWaitingTip">
  124. update flash_delivery_order
  125. set tip_amount = #{order.tipAmount}, amount = #{order.amount},
  126. update_time = #{order.updateTime}, version = version + 1
  127. where id = #{order.id} and user_id = #{order.userId}
  128. and status = 'WAITING_ACCEPTANCE' and rider_id is null and version = #{expectedVersion}
  129. </update>
  130. <!-- 骑手履约同时校验订单归属和预期状态,只有中单骑手能按顺序推进。 -->
  131. <update id="transitionByRider">
  132. update flash_delivery_order
  133. set status=#{nextStatus},
  134. <choose><when test="timeColumn == 'picked_up_at'">picked_up_at=#{now},</when><otherwise>delivered_at=#{now},</otherwise></choose>
  135. update_time=#{now}, version = version + 1
  136. where id=#{id} and rider_id=#{riderId} and status=#{expectedStatus}
  137. and delivery_stop_count is null
  138. </update>
  139. <!-- 用户确认收货必须同时满足订单归属和已送达状态。 -->
  140. <update id="transitionByParticipant">
  141. update flash_delivery_order
  142. set status=#{nextStatus}, completed_at=#{now}, update_time=#{now}, version = version + 1
  143. where id=#{id} and (user_id=#{userId} or receiver_user_id = #{userId}
  144. or exists (select 1 from flash_delivery_order_stop s where s.order_id=flash_delivery_order.id
  145. and s.stop_type='DELIVERY' and s.receiver_user_id = #{userId})) and status=#{expectedStatus}
  146. and not exists (select 1 from flash_delivery_order_stop s where s.order_id=flash_delivery_order.id
  147. and s.stop_type='DELIVERY' and s.status &lt;&gt; 'DELIVERED')
  148. </update>
  149. <!-- 评分条件更新:仅寄件人的完成态订单、已接骑手且从未评价才成功,并发重复提交返回 0。 -->
  150. <update id="rateRider">
  151. update flash_delivery_order
  152. set rider_stars=#{riderStars}, update_time=#{now}
  153. where id=#{id} and user_id=#{userId} and status='COMPLETED'
  154. and rider_id is not null and rider_stars is null
  155. </update>
  156. <!-- 骑手闪送平均分只统计闪送订单内的评价,与外卖评分体系互不影响。 -->
  157. <select id="selectRiderAverageStars" resultType="java.lang.Double">
  158. select round(avg(rider_stars), 1) from flash_delivery_order
  159. where rider_id = #{riderId} and rider_stars is not null
  160. </select>
  161. <!-- 平台/系统完成同样使用预期状态条件,防止与用户确认并发重复成功。 -->
  162. <update id="transitionByStatus">
  163. update flash_delivery_order
  164. set status=#{nextStatus}, completed_at=#{now}, update_time=#{now}, version = version + 1
  165. where id=#{id} and status=#{expectedStatus}
  166. and not exists (select 1 from flash_delivery_order_stop s where s.order_id=flash_delivery_order.id
  167. and s.stop_type='DELIVERY' and s.status &lt;&gt; 'DELIVERED')
  168. </update>
  169. <!-- 取消仅取件前;服务行锁和站点检查之外再加条件,防止旧入口绕过部分取件事实。 -->
  170. <update id="cancel">
  171. update flash_delivery_order
  172. set status='CANCELLED', cancelled_at=#{now}, cancel_reason=#{reason},
  173. cancel_operator_type=#{operatorType}, cancel_operator_id=#{operatorId},
  174. update_time=#{now}, version = version + 1
  175. where id=#{id} and status=#{expectedStatus}
  176. and status in ('WAITING_ACCEPTANCE','ACCEPTED') and picked_up_at is null
  177. and coalesce(picked_up_stop_count,0)=0
  178. and not exists (select 1 from flash_delivery_order_stop s where s.order_id=#{id}
  179. and s.stop_type='PICKUP' and (s.status='PICKED_UP' or s.picked_up_at is not null))
  180. </update>
  181. <!-- 定时任务只扫描达到 24 小时阈值且仍处于已送达状态的订单。 -->
  182. <select id="selectAutoCompletable" resultMap="FlashDeliveryOrderResult">
  183. select * from flash_delivery_order
  184. where status='DELIVERED' and delivered_at &lt;= #{deadline}
  185. order by delivered_at asc limit #{limit}
  186. </select>
  187. <!-- 先锁订单再读站点,凭证、日志和状态写入全部完成后才释放锁。 -->
  188. <select id="selectByIdForUpdate" resultMap="FlashDeliveryOrderResult">
  189. select * from flash_delivery_order where id = #{id} for update
  190. </select>
  191. <!-- 显式写入空目标恢复默认顺序,避免通用updateById跳过null字段。 -->
  192. <update id="updateFulfilment">
  193. update flash_delivery_order
  194. set status = #{order.status}, picked_up_stop_count = #{order.pickedUpStopCount},
  195. current_target_stop_id = #{order.currentTargetStopId}, picked_up_at = #{order.pickedUpAt},
  196. update_time = #{order.updateTime}, version = version + 1
  197. where id = #{order.id} and rider_id = #{order.riderId}
  198. and status = 'ACCEPTED' and version = #{order.version}
  199. </update>
  200. <!-- 交错送达可能仍处于待取件;行锁内按骑手、可履约状态和版本推进,整单完成时写送达时间。 -->
  201. <update id="updateDeliveryFulfilment">
  202. update flash_delivery_order
  203. set status = #{order.status}, delivered_stop_count = #{order.deliveredStopCount},
  204. current_target_stop_id = #{order.currentTargetStopId},
  205. delivered_at = #{order.deliveredAt}, update_time = #{order.updateTime}, version = version + 1
  206. where id = #{order.id} and rider_id = #{order.riderId}
  207. and status in ('ACCEPTED', 'PICKED_UP') and version = #{order.version}
  208. </update>
  209. <!-- 预约时段结束仍无人接单时,由任务分批收口;只读取仍可取消的待接订单。 -->
  210. <select id="selectExpiredScheduled" resultMap="FlashDeliveryOrderResult">
  211. select * from flash_delivery_order
  212. where status='WAITING_ACCEPTANCE' and rider_id is null and delivery_mode='SCHEDULED'
  213. and scheduled_pickup_end_at &lt;= #{now}
  214. order by scheduled_pickup_end_at asc limit #{limit}
  215. </select>
  216. <!-- 接单、用户取消与定时取消竞争时,以此条件更新决定唯一终态。 -->
  217. <update id="cancelExpiredScheduled">
  218. update flash_delivery_order
  219. set status='CANCELLED', cancelled_at=#{now}, cancel_reason='SCHEDULE_EXPIRED',
  220. cancel_operator_type='SYSTEM', cancel_operator_id=null,
  221. update_time=#{now}, version = version + 1
  222. where id=#{id} and status='WAITING_ACCEPTANCE' and rider_id is null and delivery_mode='SCHEDULED'
  223. and scheduled_pickup_end_at &lt;= #{now}
  224. </update>
  225. <!-- 预约单只有进入取件窗口后才允许向骑手开放;is_display=false 同时充当未领取标记。 -->
  226. <select id="selectScheduledAvailabilityCandidates" resultMap="FlashDeliveryOrderResult">
  227. select * from flash_delivery_order
  228. where status='WAITING_ACCEPTANCE' and rider_id is null and delivery_mode='SCHEDULED'
  229. and is_display = false and scheduled_pickup_start_at &lt;= #{now}
  230. and scheduled_pickup_end_at &gt; #{now}
  231. order by scheduled_pickup_start_at asc limit #{limit}
  232. </select>
  233. <!-- false -> true 的条件更新保证多实例任务只由一个实例开放并推送。 -->
  234. <update id="openScheduledForRiders">
  235. update flash_delivery_order
  236. set is_display = true, update_time = #{now}
  237. where id=#{id} and status='WAITING_ACCEPTANCE' and rider_id is null and delivery_mode='SCHEDULED'
  238. and is_display = false and scheduled_pickup_start_at &lt;= #{now}
  239. and scheduled_pickup_end_at &gt; #{now}
  240. </update>
  241. </mapper>