package com.kaidi.oa.web;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.kaidi.oa.common.ApiException;
import com.kaidi.oa.common.ApiResp;
import com.kaidi.oa.common.DeclCrypto;
import com.kaidi.oa.common.NotFoundException;
import com.kaidi.oa.domain.DeclSubmission;
import com.kaidi.oa.domain.SysUser;
import com.kaidi.oa.repository.DeclSubmissionRepository;
import com.kaidi.oa.repository.DeclarationRepository;
import com.kaidi.oa.service.AuthorizationService;
import com.kaidi.oa.service.NotificationService;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.time.Instant;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* 申报外部提交工作流(创新研发中心·申报服务部,需求 §2 内部审核流程 + 外部申报提交)。
*
* 补齐审计点名的多处缺口(PARTIAL · high):
*
* - 真会签链状态机(非单纯线性):草稿 → 申报专员 → 部门负责人 → 技术会签 → 财务会签 → 法务会签
* → 高管核准 → 已提交;每一步 /{id}/approve 通过、/{id}/reject 驳回回草稿,意见全程留痕;
* - 外部账号密码加密存储:portalPassword 落库前经 {@link DeclCrypto} 可逆加密,列表/详情仅回掩码,
* 仅 /{id}/reveal-credential(ADMIN/APPROVER)才解密返回明文,杜绝明文入库/越权读取;
* - 电子签章 + 外部提交:/{id}/esign 标记已签章,/{id}/submit 在「高管核准且已签章」后置「已提交」、
* 回填政务平台受理回执 receiptNo 与提交日,并通知发起人。
*
*
* 受 AuthInterceptor 默认保护;含凭据,归入敏感读写门禁(见 sharedFileSnippets)。
*/
@RestController
@RequestMapping("/api/oa/decl-submissions")
public class DeclSubmissionController {
/** 会签链(草稿为起点,已提交为终点)。 */
static final List CHAIN = List.of(
"草稿", "申报专员", "部门负责人", "技术会签", "财务会签", "法务会签", "高管核准", "已提交");
private static final String ST_DRAFT = "草稿";
private static final String ST_APPROVED = "高管核准";
private static final String ST_SUBMITTED = "已提交";
private static final String ESIGN_SIGNED = "已签章";
private static final Set REVEAL_ROLES = Set.of("ADMIN", "APPROVER");
private final DeclSubmissionRepository repo;
private final DeclarationRepository declRepo;
private final CurrentUserResolver currentUser;
private final AuthorizationService authz;
private final NotificationService notifications;
private final ObjectMapper objectMapper;
public DeclSubmissionController(DeclSubmissionRepository repo,
DeclarationRepository declRepo,
CurrentUserResolver currentUser,
AuthorizationService authz,
NotificationService notifications,
ObjectMapper objectMapper) {
this.repo = repo;
this.declRepo = declRepo;
this.currentUser = currentUser;
this.authz = authz;
this.notifications = notifications;
this.objectMapper = objectMapper;
}
// ---------- 列表/详情(口令永不出现在响应中) ----------
public record SubmissionView(Long id, String code, Long declarationId, String projectName,
String declType, String reviewStage, String govPlatform,
String portalAccount, String passwordMask, String esignStatus,
String receiptNo, String submittedDate, String owner,
List