Просмотр исходного кода

商家统编调整保存方法

qmj 4 дней назад
Родитель
Сommit
75ecc824e4

Разница между файлами не показана из-за своего большого размера
+ 3 - 0
.claude/homunculus/observations.jsonl


+ 7 - 41
ruoyi-admin/src/main/java/com/ruoyi/app/mendian/PosStoreController.java

@@ -161,6 +161,8 @@ public class PosStoreController extends BaseController {
             List<OperatingHours> hourslist = operatingHoursService.list(wrapper);
             list.getRecords().forEach(posStore -> {
                 posStore.setBusinessHours(getStoreOperatOutput(hourslist, Long.valueOf(posStore.getId())));
+                // 回显统一编号(统编),供商家端编辑门店时显示
+                posStore.setUbn(posStoreEzpayService.getUbn(Long.valueOf(posStore.getId())));
             });
         }
 
@@ -276,53 +278,17 @@ public class PosStoreController extends BaseController {
 
             // 3. 处理营业时间信息
             handlerBusinessHours(posStore, store);
+            // 4. 统一保存统一编号(统编)到 pos_store_ezpay(不再走独立 saveUbn 接口)
+            if (posStore.getUbn() != null) {
+                posStoreEzpayService.uploadUbn(store.getId().longValue(), posStore.getUbn());
+            }
             return success(MessageUtils.message("no.success"), store);
         } catch (Exception e) {
             return error("添加门店失败: " + e.getMessage());
         }
     }
 
-    /**
-     * 商家端:上传门店统一编号(统编)。供运营向 ezPay 申请发票使用。
-     * 仅校验当前商家为该门店归属人;不改 ezPay 状态。
-     */
-    @Anonymous
-    @Auth
-    @PostMapping("/saveUbn")
-    public AjaxResult saveUbn(@RequestHeader String token, @RequestParam Long storeId, @RequestParam String ubn) {
-        if (!ownsStore(token, storeId)) {
-            return error("无权操作该门店");
-        }
-        return toAjax(posStoreEzpayService.uploadUbn(storeId, ubn));
-    }
-
-    /**
-     * 商家端:读取门店已保存的统一编号(编辑时回显)。
-     */
-    @Anonymous
-    @Auth
-    @GetMapping("/getUbn")
-    public AjaxResult getUbn(@RequestHeader String token, @RequestParam Long storeId) {
-        if (!ownsStore(token, storeId)) {
-            return error("无权操作该门店");
-        }
-        return success(posStoreEzpayService.getUbn(storeId));
-    }
-
-    /** 校验当前登录商家为该门店归属人(普通商家匹配 user_id;摊位主 type=4 匹配 storeId)。 */
-    private boolean ownsStore(String token, Long storeId) {
-        JwtUtil jwtUtil = new JwtUtil();
-        String id = jwtUtil.getusid(token);
-        InfoUser loginUser = infoUserService.selectInfoUserByUserId(Long.valueOf(id));
-        PosStore store = posStoreService.getById(storeId);
-        if (store == null) {
-            return false;
-        }
-        if ("4".equals(loginUser.getUserType())) {
-            return loginUser.getStoreId() != null && loginUser.getStoreId().equals(storeId);
-        }
-        return store.getUserId() != null && store.getUserId().equals(Long.valueOf(id));
-    }
+    // 统一编号(统编)已并入 addmendian 保存、storelistlist 回显(存于 pos_store_ezpay),不再有独立 saveUbn/getUbn 接口
 
     /**
      * 更新门店信息处理营业时间

+ 4 - 0
ruoyi-system/src/main/java/com/ruoyi/system/domain/PosStore.java

@@ -169,6 +169,10 @@ public class PosStore
     @TableField(exist = false)
     private Boolean isOperating;
 
+    /** 统一编号(统编):非 pos_store 列,实存于 pos_store_ezpay.ubn;随 addmendian 保存、随列表回显 */
+    @TableField(exist = false)
+    private String ubn;
+
     /** 删除标志(0代表存在 1代表删除) */
     @TableLogic
     private String delFlag;

+ 8 - 0
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/PosStoreEzpayServiceImpl.java

@@ -1,5 +1,6 @@
 package com.ruoyi.system.service.impl;
 
+import cn.hutool.core.util.StrUtil;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.ruoyi.common.exception.ServiceException;
 import com.ruoyi.common.utils.SecurityUtils;
@@ -48,6 +49,13 @@ public class PosStoreEzpayServiceImpl implements IPosStoreEzpayService {
     @Override
     public int apply(Long storeId) {
         PosStoreEzpay row = getOrCreateByStoreId(storeId);
+        // 发起申请前必须先有统编:ezPay 线下申请表统编为必填项
+        if (StrUtil.isBlank(row.getUbn())) {
+            throw new ServiceException("请先让商家在门店设置填写统编");
+        }
+        if (!row.getUbn().matches("\\d{8}")) {
+            throw new ServiceException("统编格式不正确,需为8位数字");
+        }
         if (!Integer.valueOf(STATUS_NOT_APPLIED).equals(row.getEzpayStatus())) {
             throw new ServiceException("当前状态不允许发起申请");
         }

+ 1 - 1
specs/009-ezpay-invoice-onboarding/data-model.md

@@ -93,4 +93,4 @@ CREATE TABLE pos_store_ezpay (
 
 - 录入凭证:`merchant_id` 必填、`hash_key` 必填且 32 字节、`hash_iv` 必填且 16 字节(长度校验,ezPay 固定规格)。
 - 验证调用:超时 10s;网络异常按"未通过"处理,不抛 500,回传可重试提示。
-- 统编 `ubn`:商家端非免用门店建议必填(8 位数字),免用门店不强制。
+- 统编 `ubn`:商家端非免用门店建议必填(8 位数字),免用门店不强制。**发起申请(apply)时强制校验:非空且为 8 位数字,不满足则拒绝推进为"申请中"。**

+ 2 - 1
specs/009-ezpay-invoice-onboarding/spec.md

@@ -91,7 +91,7 @@
 ### Edge Cases
 
 - 门店从"已开通"改为"免用发票"(罕见):保留 ezPay 凭证数据,以免用发票标识为准,不自动删除凭证。
-- 运营对未上传统编的门店发起申请:提示运营先让商家补全统编(或允许先申请、后补)
+- 运营对未上传统编的门店发起申请:系统拒绝推进为"申请中"(统编为发起申请的硬性前置,不可后补),提示运营先让商家在门店设置补全统编。
 - 同一组 ezPay 凭证被录入到多个门店:本期不强制唯一,仅记录与提示。
 - 凭证录入后 ezPay 测试环境不可用:验证失败按"网络异常"分支处理,允许稍后重试,不锁死状态。
 - 夜市(userType=3)本身不开票:其账号不进入门店 ezPay 列表;夜市下的摊位门店(pos_store)正常参与。
@@ -112,6 +112,7 @@
 - **FR-010**: 商家必须在商家端能为门店上传统一编号(统编);免用发票门店的统编不强制。
 - **FR-011**: 只有"已开通且启用"的门店才被视为具备开票前提;本功能仅维护该状态,不含订单完成时的自动开票逻辑。
 - **FR-012**: 平台前端与商家前端所有新增面向用户文字必须实现四语言(vi / zh / tw / en)国际化。
+- **FR-013**: 运营发起申请(未申请→申请中)前,统编为硬性前置:门店未上传统编或统编非 8 位数字时,系统必须拒绝推进、保留"未申请"状态,并返回"请先让商家在门店设置填写统编"提示;平台前端对未上传统编的门店禁用"发起申请"按钮并以 tooltip 说明。
 
 ### Key Entities *(include if feature involves data)*
 

Некоторые файлы не были показаны из-за большого количества измененных файлов