Ver código fonte

feat: 用户端堂食/自取开放现金支付(原仅商家可用)

qmj 21 horas atrás
pai
commit
31bb384

+ 1 - 1
ruoyi-admin/src/main/java/com/ruoyi/app/order/OrderLifecycleService.java

@@ -32,7 +32,7 @@ public class OrderLifecycleService {
 
     public static final String PAY_TYPE_OFFLINE = "1";
     public static final String PAY_TYPE_OMG = "2";
-    /** 现金支付:仅商家创建订单可用(客户端下单拒绝);创建时未支付,商家App确认收款后置已支付 */
+    /** 现金支付:堂食/自取用户可直接下单;外送仅商家创建订单可用。创建时未支付,商家App确认收款后置已支付 */
     public static final String PAY_TYPE_CASH = "4";
     /** 線下轉賬支付:用户线下银行转账,商家确认收款(payStatus 从 0 置 1)后解锁骑手接单 */
     public static final String PAY_TYPE_TRANSFER = "6";

+ 2 - 2
ruoyi-admin/src/main/java/com/ruoyi/app/order/PosOrderShOprateController.java

@@ -644,9 +644,9 @@ public class PosOrderShOprateController extends BaseController {
         switch (tab == null ? "" : tab) {
             case "pending":
                 wrapper.eq(PosOrder::getState, 0L)
-                       // 现金自取/堂食可直接待受理;在线支付的自取/堂食必须先完成付款。
+                       // 到付/现金自取/堂食可直接待受理;在线支付的自取/堂食必须先完成付款。
                        .and(w -> w.eq(PosOrder::getPayStatus, 1L)
-                               .or(cash -> cash.eq(PosOrder::getPayType, "1")
+                               .or(cash -> cash.in(PosOrder::getPayType, "1", "4")
                                        .in(PosOrder::getType, 1L, 2L)));
                 break;
             case "preparing":

+ 5 - 4
ruoyi-admin/src/main/java/com/ruoyi/app/order/UserOrderController.java

@@ -162,8 +162,9 @@ public class UserOrderController extends BaseController {
             }
             shdz= JSON.toJSONString(usadd);
         }
-        // 现金支付(4)仅商家创建订单可用,客户端下单直接拒绝
-        if (OrderLifecycleService.PAY_TYPE_CASH.equals(input.getPaymentMethod())) {
+        // 现金支付(4):堂食/自取用户可直接下单线下收款;外送仍仅商家创建订单可用
+        if (OrderLifecycleService.PAY_TYPE_CASH.equals(input.getPaymentMethod())
+                && input.getType() != 1 && input.getType() != 2) {
             throw new ServiceException(MessageUtils.message("no.paytype.cash.merchant.only"));
         }
         // === 发票意图(010 Phase 11)===
@@ -563,9 +564,9 @@ public class UserOrderController extends BaseController {
             case "active":
                 wrapper.in(PosOrder::getState, 0L, 1L, 2L)
                        .eq(PosOrder::getAfterSaleStatus, 0L)
-                       // 现金自取/堂食可以线下收款;OMG、LINE Pay 等在线订单必须已付款才能履约。
+                       // 到付/现金自取/堂食可以线下收款;OMG、LINE Pay 等在线订单必须已付款才能履约。
                        .and(w -> w.eq(PosOrder::getPayStatus, 1L)
-                               .or(cash -> cash.eq(PosOrder::getPayType, "1")
+                               .or(cash -> cash.in(PosOrder::getPayType, "1", "4")
                                        .in(PosOrder::getType, 1L, 2L)));
                 break;
             case "completed":

+ 6 - 6
ruoyi-admin/src/main/java/com/ruoyi/app/unifiedorder/UnifiedOrderTab.java

@@ -29,9 +29,9 @@ public enum UnifiedOrderTab {
 
     /** 在线支付方式(OMG、LINE Pay),待付款 tab 仅认这两种。 */
     private static final List<String> ONLINE_PAY_TYPES = List.of("2", "3");
-    /** 货到付款支付方式标记。 */
-    private static final String CASH_PAY_TYPE = "1";
-    /** 货到付款可线下收款的订单类型:自取、堂食。 */
+    /** 可线下收款的支付方式:到付(1)、现金(4)。 */
+    private static final List<String> OFFLINE_PAYABLE_PAY_TYPES = List.of("1", "4");
+    /** 可线下收款的订单类型:自取、堂食。 */
     private static final List<Long> CASH_PAYABLE_TYPES = List.of(1L, 2L);
     /** 进行中的外卖订单状态:待处理、已接单、已出餐。 */
     private static final List<Long> ACTIVE_STATES = List.of(0L, 1L, 2L);
@@ -92,9 +92,9 @@ public enum UnifiedOrderTab {
             case ACTIVE:
                 wrapper.in(PosOrder::getState, ACTIVE_STATES)
                         .eq(PosOrder::getAfterSaleStatus, NO_AFTER_SALE)
-                        // 现金自取/堂食可以线下收款;在线订单必须已付款才能履约。
+                        // 到付/现金自取/堂食可以线下收款;在线订单必须已付款才能履约。
                         .and(w -> w.eq(PosOrder::getPayStatus, PAID)
-                                .or(cash -> cash.eq(PosOrder::getPayType, CASH_PAY_TYPE)
+                                .or(cash -> cash.in(PosOrder::getPayType, OFFLINE_PAYABLE_PAY_TYPES)
                                         .in(PosOrder::getType, CASH_PAYABLE_TYPES)));
                 break;
             case COMPLETED:
@@ -127,7 +127,7 @@ public enum UnifiedOrderTab {
                 return order.getState() != null && ACTIVE_STATES.contains(order.getState())
                         && longEq(order.getAfterSaleStatus(), NO_AFTER_SALE)
                         && (longEq(order.getPayStatus(), PAID)
-                                || (CASH_PAY_TYPE.equals(order.getPayType())
+                                || (order.getPayType() != null && OFFLINE_PAYABLE_PAY_TYPES.contains(order.getPayType())
                                         && order.getType() != null && CASH_PAYABLE_TYPES.contains(order.getType())));
             case COMPLETED:
                 return longEq(order.getState(), COMPLETED_STATE)

+ 4 - 2
ruoyi-admin/src/test/java/com/ruoyi/app/order/OrderListPaymentFilterTest.java

@@ -81,9 +81,10 @@ class OrderListPaymentFilterTest {
         String sql = query.getSqlSegment();
         Collection<Object> parameters = new ArrayList<>(query.getParamNameValuePairs().values());
         assertTrue(sql.contains("(pay_status ="));
-        assertTrue(sql.contains("OR (pay_type ="));
+        assertTrue(sql.contains("OR (pay_type IN"));
         assertTrue(sql.contains("AND type IN"));
         assertEquals(1, Collections.frequency(parameters, "1"));
+        assertEquals(1, Collections.frequency(parameters, "4"));
     }
 
     @Test
@@ -109,9 +110,10 @@ class OrderListPaymentFilterTest {
         String sql = query.getSqlSegment();
         Collection<Object> parameters = new ArrayList<>(query.getParamNameValuePairs().values());
         assertTrue(sql.contains("(pay_status ="));
-        assertTrue(sql.contains("OR (pay_type ="));
+        assertTrue(sql.contains("OR (pay_type IN"));
         assertTrue(sql.contains("AND type IN"));
         assertEquals(1, Collections.frequency(parameters, "1"));
+        assertEquals(1, Collections.frequency(parameters, "4"));
     }
 
     @ParameterizedTest

+ 9 - 3
ruoyi-admin/src/test/java/com/ruoyi/app/unifiedorder/UnifiedOrderTabTest.java

@@ -81,10 +81,13 @@ class UnifiedOrderTabTest {
         // 在线已付履约中
         assertTrue(UnifiedOrderTab.ACTIVE.matches(pos(0L, 0L, 1L, "2", 0L)));
         assertTrue(UnifiedOrderTab.ACTIVE.matches(pos(2L, 0L, 1L, "3", 0L)));
-        // 货到付款(payType=1)仅自取/堂食可履约
+        // 货到付款(payType=1)/现金(payType=4)仅自取/堂食可履约
         assertTrue(UnifiedOrderTab.ACTIVE.matches(pos(1L, 1L, 0L, "1", 0L)));
         assertTrue(UnifiedOrderTab.ACTIVE.matches(pos(2L, 2L, 0L, "1", 0L)));
         assertFalse(UnifiedOrderTab.ACTIVE.matches(pos(0L, 0L, 0L, "1", 0L)));
+        assertTrue(UnifiedOrderTab.ACTIVE.matches(pos(1L, 1L, 0L, "4", 0L)));
+        assertTrue(UnifiedOrderTab.ACTIVE.matches(pos(2L, 2L, 0L, "4", 0L)));
+        assertFalse(UnifiedOrderTab.ACTIVE.matches(pos(0L, 0L, 0L, "4", 0L)));
         // 在线未付不履约
         assertFalse(UnifiedOrderTab.ACTIVE.matches(pos(0L, 0L, 0L, "2", 0L)));
         // 终态不进进行中
@@ -195,12 +198,15 @@ class UnifiedOrderTabTest {
 
     @Test
     void activeWrapperCarriesStateAndPaymentConditions() {
-        String sql = UnifiedOrderTab.ACTIVE.posOrderWrapper().getSqlSegment();
+        LambdaQueryWrapper<PosOrder> wrapper = UnifiedOrderTab.ACTIVE.posOrderWrapper();
+        String sql = wrapper.getSqlSegment();
         assertTrue(sql.contains("state IN"), sql);
         assertTrue(sql.contains("after_sale_status ="), sql);
         assertTrue(sql.contains("(pay_status ="), sql);
-        assertTrue(sql.contains("OR (pay_type ="), sql);
+        assertTrue(sql.contains("OR (pay_type IN"), sql);
         assertTrue(sql.contains("type IN"), sql);
+        assertTrue(wrapper.getParamNameValuePairs().values()
+                .containsAll(java.util.List.of("1", "4")), wrapper.getParamNameValuePairs().toString());
     }
 
     @Test