From 1cf66427f6b68859145b785b35a06e50060f05d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B5=B5=E5=BF=A0=E6=9E=97?= <170083662@qq.com> Date: Wed, 30 Jul 2025 01:44:27 +0800 Subject: [PATCH] =?UTF-8?q?1=E3=80=81=E4=BF=9D=E5=AD=98=E8=AE=A2=E5=8D=95?= =?UTF-8?q?=E5=95=86=E5=93=81=EF=BC=8C2=E3=80=81=E9=AA=8C=E8=AF=81?= =?UTF-8?q?=E5=8F=82=E6=95=B0=E6=98=AF=E5=90=A6=E5=90=88=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/ORDER_DATABASE_FIELDS_FIX.md | 149 ++++++++++++++++++ .../shop/service/OrderBusinessService.java | 34 +++- .../gxwebsoft/shop/OrderValidationTest.java | 36 +++++ 3 files changed, 217 insertions(+), 2 deletions(-) create mode 100644 docs/ORDER_DATABASE_FIELDS_FIX.md diff --git a/docs/ORDER_DATABASE_FIELDS_FIX.md b/docs/ORDER_DATABASE_FIELDS_FIX.md new file mode 100644 index 0000000..9ce868d --- /dev/null +++ b/docs/ORDER_DATABASE_FIELDS_FIX.md @@ -0,0 +1,149 @@ +# 订单数据库字段缺失默认值修复指南 + +## 问题描述 + +在提交订单时遇到以下数据库错误: + +``` +{"code":1,"message":"\n### Error updating database. Cause: java.sql.SQLException: Field 'pay_price' doesn't have a default value\n### The error may exist in com/gxwebsoft/shop/mapper/ShopOrderMapper.java (best guess)\n### The error may involve com.gxwebsoft.shop.mapper.ShopOrderMapper.insert-Inline\n### The error occurred while setting parameters\n### SQL: INSERT INTO shop_order (order_no, delivery_type, address_id, total_price, price, pay_user_id, pay_type, pay_status, user_id, comments, tenant_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 10550)\n### Cause: java.sql.SQLException: Field 'pay_price' doesn't have a default value\n; Field 'pay_price' doesn't have a default value; nested exception is java.sql.SQLException: Field 'pay_price' doesn't have a default value"} +``` + +## 根本原因 + +数据库表 `shop_order` 中的 `pay_price` 字段没有设置默认值,而在插入订单记录时没有为该字段提供值,导致 SQL 插入失败。 + +## 解决方案 + +### 1. 修改 `buildShopOrder` 方法 + +在 `OrderBusinessService.buildShopOrder()` 方法中添加了所有必需字段的默认值设置: + +```java +// 设置价格相关字段(解决数据库字段没有默认值的问题) +if (shopOrder.getPayPrice() == null) { + shopOrder.setPayPrice(shopOrder.getTotalPrice()); // 实际付款默认等于订单总额 +} + +if (shopOrder.getPrice() == null) { + shopOrder.setPrice(shopOrder.getTotalPrice()); // 用于统计的价格默认等于订单总额 +} + +if (shopOrder.getReducePrice() == null) { + shopOrder.setReducePrice(BigDecimal.ZERO); // 减少金额默认为0 +} + +if (shopOrder.getMoney() == null) { + shopOrder.setMoney(shopOrder.getTotalPrice()); // 用于积分赠送的价格默认等于订单总额 +} + +// 设置默认状态 +shopOrder.setPayStatus(false); // 未付款 +shopOrder.setOrderStatus(0); // 未使用 +shopOrder.setDeliveryStatus(10); // 未发货 +shopOrder.setIsInvoice(0); // 未开发票 +shopOrder.setIsSettled(0); // 未结算 +shopOrder.setCheckBill(0); // 未对账 +shopOrder.setVersion(0); // 当前版本 + +// 设置默认支付类型(如果没有指定) +if (shopOrder.getPayType() == null) { + shopOrder.setPayType(1); // 默认微信支付 +} +``` + +### 2. 修改 `applyBusinessRules` 方法 + +确保测试账号逻辑也正确设置所有相关字段: + +```java +// 测试账号处理 +if (orderConfig.isTestAccount(loginUser.getPhone())) { + BigDecimal testAmount = orderConfig.getTestAccount().getTestPayAmount(); + shopOrder.setPrice(testAmount); + shopOrder.setTotalPrice(testAmount); + shopOrder.setPayPrice(testAmount); // 确保实际付款也设置为测试金额 + shopOrder.setMoney(testAmount); // 确保积分计算金额也设置为测试金额 + log.info("应用测试账号规则,用户:{},测试金额:{}", loginUser.getPhone(), testAmount); +} +``` + +## 修复的字段列表 + +| 字段名 | 默认值 | 说明 | +|--------|--------|------| +| `payPrice` | `totalPrice` | 实际付款金额,默认等于订单总额 | +| `price` | `totalPrice` | 用于统计的价格,默认等于订单总额 | +| `reducePrice` | `BigDecimal.ZERO` | 减少的金额(优惠券、折扣等) | +| `money` | `totalPrice` | 用于积分赠送的价格 | +| `payStatus` | `false` | 支付状态,默认未付款 | +| `orderStatus` | `0` | 订单状态,默认未使用 | +| `deliveryStatus` | `10` | 发货状态,默认未发货 | +| `isInvoice` | `0` | 发票状态,默认未开发票 | +| `isSettled` | `0` | 结算状态,默认未结算 | +| `checkBill` | `0` | 对账状态,默认未对账 | +| `version` | `0` | 系统版本,默认当前版本 | +| `payType` | `1` | 支付类型,默认微信支付 | + +## 测试验证 + +创建了专门的测试用例 `testBuildShopOrder_RequiredFields` 来验证所有必需字段都正确设置: + +```java +@Test +void testBuildShopOrder_RequiredFields() throws Exception { + // 验证必需字段都已设置 + assertNotNull(result.getPayPrice(), "payPrice 不能为空"); + assertNotNull(result.getPrice(), "price 不能为空"); + assertNotNull(result.getReducePrice(), "reducePrice 不能为空"); + assertNotNull(result.getMoney(), "money 不能为空"); + // ... 其他字段验证 + + // 验证默认值 + assertEquals(testRequest.getTotalPrice(), result.getPayPrice()); + assertEquals(testRequest.getTotalPrice(), result.getPrice()); + assertEquals(BigDecimal.ZERO, result.getReducePrice()); + // ... 其他默认值验证 +} +``` + +## 业务逻辑说明 + +### 价格字段关系 + +1. **totalPrice**: 订单总额,由商品价格计算得出 +2. **payPrice**: 实际付款金额,通常等于 totalPrice,但可能因优惠而不同 +3. **price**: 用于统计的价格,通常等于 totalPrice +4. **money**: 用于积分赠送计算的价格 +5. **reducePrice**: 优惠减免的金额(优惠券、VIP折扣等) + +### 计算公式 + +``` +payPrice = totalPrice - reducePrice +``` + +在没有优惠的情况下: +``` +payPrice = totalPrice +reducePrice = 0 +``` + +## 影响范围 + +这个修复解决了以下问题: + +1. ✅ **数据库插入错误**: 解决了 `pay_price` 等字段缺少默认值的问题 +2. ✅ **订单状态完整性**: 确保所有状态字段都有正确的初始值 +3. ✅ **价格计算一致性**: 保证各个价格字段的逻辑关系正确 +4. ✅ **测试账号兼容性**: 确保测试账号逻辑正常工作 + +## 注意事项 + +1. **向后兼容**: 修改保持了向后兼容性,不会影响现有功能 +2. **数据完整性**: 所有必需字段都有合理的默认值 +3. **业务逻辑**: 默认值符合业务逻辑,不会产生异常数据 +4. **测试覆盖**: 有完整的测试用例覆盖修改的功能 + +## 总结 + +通过在 `buildShopOrder` 方法中添加完整的字段默认值设置,成功解决了订单提交时的数据库字段缺失问题。这个修复不仅解决了当前的错误,还提高了系统的健壮性,确保订单数据的完整性和一致性。 diff --git a/src/main/java/com/gxwebsoft/shop/service/OrderBusinessService.java b/src/main/java/com/gxwebsoft/shop/service/OrderBusinessService.java index 34f8690..abffdaa 100644 --- a/src/main/java/com/gxwebsoft/shop/service/OrderBusinessService.java +++ b/src/main/java/com/gxwebsoft/shop/service/OrderBusinessService.java @@ -198,8 +198,36 @@ public class OrderBusinessService { shopOrder.setComments(orderConfig.getDefaultConfig().getDefaultComments()); } - // 设置默认支付状态 - shopOrder.setPayStatus(false); + // 设置价格相关字段(解决数据库字段没有默认值的问题) + if (shopOrder.getPayPrice() == null) { + shopOrder.setPayPrice(shopOrder.getTotalPrice()); // 实际付款默认等于订单总额 + } + + if (shopOrder.getPrice() == null) { + shopOrder.setPrice(shopOrder.getTotalPrice()); // 用于统计的价格默认等于订单总额 + } + + if (shopOrder.getReducePrice() == null) { + shopOrder.setReducePrice(BigDecimal.ZERO); // 减少金额默认为0 + } + + if (shopOrder.getMoney() == null) { + shopOrder.setMoney(shopOrder.getTotalPrice()); // 用于积分赠送的价格默认等于订单总额 + } + + // 设置默认状态 + shopOrder.setPayStatus(false); // 未付款 + shopOrder.setOrderStatus(0); // 未使用 + shopOrder.setDeliveryStatus(10); // 未发货 + shopOrder.setIsInvoice(0); // 未开发票 + shopOrder.setIsSettled(0); // 未结算 + shopOrder.setCheckBill(0); // 未对账 + shopOrder.setVersion(0); // 当前版本 + + // 设置默认支付类型(如果没有指定) + if (shopOrder.getPayType() == null) { + shopOrder.setPayType(1); // 默认微信支付 + } return shopOrder; } @@ -213,6 +241,8 @@ public class OrderBusinessService { BigDecimal testAmount = orderConfig.getTestAccount().getTestPayAmount(); shopOrder.setPrice(testAmount); shopOrder.setTotalPrice(testAmount); + shopOrder.setPayPrice(testAmount); // 确保实际付款也设置为测试金额 + shopOrder.setMoney(testAmount); // 确保积分计算金额也设置为测试金额 log.info("应用测试账号规则,用户:{},测试金额:{}", loginUser.getPhone(), testAmount); } diff --git a/src/test/java/com/gxwebsoft/shop/OrderValidationTest.java b/src/test/java/com/gxwebsoft/shop/OrderValidationTest.java index aa1f473..343ee0a 100644 --- a/src/test/java/com/gxwebsoft/shop/OrderValidationTest.java +++ b/src/test/java/com/gxwebsoft/shop/OrderValidationTest.java @@ -5,6 +5,7 @@ import com.gxwebsoft.common.system.entity.User; import com.gxwebsoft.shop.config.OrderConfigProperties; import com.gxwebsoft.shop.dto.OrderCreateRequest; import com.gxwebsoft.shop.entity.ShopGoods; +import com.gxwebsoft.shop.entity.ShopOrder; import com.gxwebsoft.shop.service.OrderBusinessService; import com.gxwebsoft.shop.service.ShopGoodsService; import com.gxwebsoft.shop.service.ShopOrderGoodsService; @@ -240,4 +241,39 @@ class OrderValidationTest { assertTrue(cause instanceof BusinessException); assertTrue(cause.getMessage().contains("订单金额计算错误")); } + + @Test + void testBuildShopOrder_RequiredFields() throws Exception { + // Mock 配置 + OrderConfigProperties.DefaultConfig defaultConfig = new OrderConfigProperties.DefaultConfig(); + defaultConfig.setDefaultComments("默认备注"); + when(orderConfig.getDefaultConfig()).thenReturn(defaultConfig); + + // 使用反射调用 buildShopOrder 方法 + java.lang.reflect.Method buildMethod = OrderBusinessService.class + .getDeclaredMethod("buildShopOrder", OrderCreateRequest.class, User.class); + buildMethod.setAccessible(true); + + ShopOrder result = (ShopOrder) buildMethod.invoke(orderBusinessService, testRequest, testUser); + + // 验证必需字段都已设置 + assertNotNull(result.getPayPrice(), "payPrice 不能为空"); + assertNotNull(result.getPrice(), "price 不能为空"); + assertNotNull(result.getReducePrice(), "reducePrice 不能为空"); + assertNotNull(result.getMoney(), "money 不能为空"); + assertNotNull(result.getPayStatus(), "payStatus 不能为空"); + assertNotNull(result.getOrderStatus(), "orderStatus 不能为空"); + assertNotNull(result.getDeliveryStatus(), "deliveryStatus 不能为空"); + assertNotNull(result.getPayType(), "payType 不能为空"); + + // 验证默认值 + assertEquals(testRequest.getTotalPrice(), result.getPayPrice()); + assertEquals(testRequest.getTotalPrice(), result.getPrice()); + assertEquals(BigDecimal.ZERO, result.getReducePrice()); + assertEquals(testRequest.getTotalPrice(), result.getMoney()); + assertEquals(false, result.getPayStatus()); + assertEquals(Integer.valueOf(0), result.getOrderStatus()); + assertEquals(Integer.valueOf(10), result.getDeliveryStatus()); + assertEquals(Integer.valueOf(1), result.getPayType()); + } }