package com.kaidi.oa.web; import com.kaidi.oa.common.Money; import com.kaidi.oa.common.ApiException; import com.kaidi.oa.common.ApiResp; import com.kaidi.oa.common.NotFoundException; import com.kaidi.oa.domain.RdExpense; import com.kaidi.oa.repository.RdExpenseRepository; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PutMapping; 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.util.List; /** * R&D expense collection (研发费用归集) forming the evidence chain * 研发立项-费用-凭证 of business chain 6. category is one of 人工费 / 直接投入 / * 折旧费用 / 无形资产摊销 / 设计费 / 其他; status is one of 待审核 / 已归集 / * 已驳回. */ @RestController @RequestMapping("/api/oa/rd-expenses") public class RdExpenseController { private final RdExpenseRepository expenseRepo; public RdExpenseController(RdExpenseRepository expenseRepo) { this.expenseRepo = expenseRepo; } @GetMapping public ApiResp> list(@RequestParam(required = false) Long rdProjectId, @RequestParam(required = false) String status) { List list; if (rdProjectId != null) { list = expenseRepo.findByRdProjectId(rdProjectId); } else if (status != null && !status.isBlank()) { list = expenseRepo.findByStatus(status); } else { list = expenseRepo.findAll(); } return ApiResp.ok(list); } @GetMapping("/{id}") public ApiResp get(@PathVariable Long id) { return ApiResp.ok(expenseRepo.findById(id) .orElseThrow(() -> new NotFoundException("rd expense not found: " + id))); } public record CreateRdExpenseRequest( Long rdProjectId, String rdProjectName, String category, String description, Double amount, String occurDate, String voucher, String status, String recorder) { } @PostMapping public ApiResp create(@RequestBody CreateRdExpenseRequest req) { if (req.rdProjectId() == null) { throw new ApiException(400, "rdProjectId is required"); } RdExpense e = new RdExpense(); e.setRdProjectId(req.rdProjectId()); e.setRdProjectName(req.rdProjectName()); e.setCategory(req.category()); e.setDescription(req.description()); e.setAmount(Money.of(req.amount() == null ? 0d : req.amount())); e.setOccurDate(req.occurDate()); e.setVoucher(req.voucher()); e.setStatus(req.status() == null || req.status().isBlank() ? "待审核" : req.status()); e.setRecorder(req.recorder()); e.setCreatedAt(Instant.now()); return ApiResp.ok(expenseRepo.save(e)); } /** PUT /{id} -> 编辑研发费用归集; 只覆盖请求体里给出的字段。 */ @PutMapping("/{id}") public ApiResp update(@PathVariable Long id, @RequestBody CreateRdExpenseRequest req) { RdExpense e = expenseRepo.findById(id) .orElseThrow(() -> new NotFoundException("rd expense not found: " + id)); if (req.rdProjectId() != null) e.setRdProjectId(req.rdProjectId()); if (req.rdProjectName() != null) e.setRdProjectName(req.rdProjectName()); if (req.category() != null) e.setCategory(req.category()); if (req.description() != null) e.setDescription(req.description()); if (req.amount() != null) e.setAmount(Money.of(req.amount())); if (req.occurDate() != null) e.setOccurDate(req.occurDate()); if (req.voucher() != null) e.setVoucher(req.voucher()); if (req.status() != null && !req.status().isBlank()) e.setStatus(req.status()); if (req.recorder() != null) e.setRecorder(req.recorder()); return ApiResp.ok(expenseRepo.save(e)); } /** DELETE /{id} -> 删除研发费用归集。 */ @DeleteMapping("/{id}") public ApiResp delete(@PathVariable Long id) { if (!expenseRepo.existsById(id)) { throw new NotFoundException("rd expense not found: " + id); } expenseRepo.deleteById(id); return ApiResp.ok(null); } }