diff --git a/src/main/java/com/sb/web/account/controller/InvestController.java b/src/main/java/com/sb/web/account/controller/InvestController.java index 745b44a..5e1f66f 100644 --- a/src/main/java/com/sb/web/account/controller/InvestController.java +++ b/src/main/java/com/sb/web/account/controller/InvestController.java @@ -23,6 +23,7 @@ import java.util.List; * DELETE /api/account/invest/holdings/{id} 종목 삭제(매매이력 포함) * GET /api/account/invest/holdings/{id}/trades 매매이력 * POST /api/account/invest/holdings/{id}/trades 매수/매도 + * PUT /api/account/invest/trades/{id} 매매 수정 * DELETE /api/account/invest/trades/{id} 매매 삭제 */ @RestController @@ -93,6 +94,14 @@ public class InvestController { return ResponseEntity.status(HttpStatus.CREATED).body(investService.addTrade(id, req, current.getId())); } + @PutMapping("/trades/{id}") + public TradeResponse updateTrade( + @PathVariable Long id, + @Valid @RequestBody TradeRequest req, + @RequestAttribute(AuthInterceptor.CURRENT_MEMBER) SessionUser current) { + return investService.updateTrade(id, req, current.getId()); + } + @DeleteMapping("/trades/{id}") public ResponseEntity deleteTrade( @PathVariable Long id, diff --git a/src/main/java/com/sb/web/account/mapper/InvestMapper.java b/src/main/java/com/sb/web/account/mapper/InvestMapper.java index 11b24a5..4ed85f5 100644 --- a/src/main/java/com/sb/web/account/mapper/InvestMapper.java +++ b/src/main/java/com/sb/web/account/mapper/InvestMapper.java @@ -38,6 +38,8 @@ public interface InvestMapper { int insertTrade(InvestTrade trade); + int updateTrade(InvestTrade trade); + int deleteTrade(@Param("id") Long id, @Param("memberId") Long memberId); int deleteTradesByHolding(@Param("holdingId") Long holdingId, @Param("memberId") Long memberId); diff --git a/src/main/java/com/sb/web/account/service/InvestService.java b/src/main/java/com/sb/web/account/service/InvestService.java index 6a26755..176b966 100644 --- a/src/main/java/com/sb/web/account/service/InvestService.java +++ b/src/main/java/com/sb/web/account/service/InvestService.java @@ -138,6 +138,50 @@ public class InvestService { return TradeResponse.from(t); } + @Transactional + public TradeResponse updateTrade(Long id, TradeRequest req, Long memberId) { + InvestTrade existing = investMapper.findTradeByIdAndMember(id, memberId); + if (existing == null) { + throw new ApiException(HttpStatus.NOT_FOUND, "매매 내역을 찾을 수 없습니다."); + } + Long holdingId = existing.getHoldingId(); + String type = "SELL".equals(req.getTradeType()) ? "SELL" : "BUY"; + long fee = req.getFee() != null ? req.getFee() : 0L; + + // 편집을 반영한 시점별 시뮬레이션 — 어느 시점에도 보유수량이 음수가 되면 거부 + java.util.List sim = new java.util.ArrayList<>(); + for (InvestTrade t : investMapper.findTradesByHolding(holdingId, memberId)) { + if (t.getId().equals(id)) { + sim.add(InvestTrade.builder().id(id).tradeType(type).tradeDate(req.getTradeDate()) + .quantity(req.getQuantity()).price(req.getPrice()).fee(fee).build()); + } else { + sim.add(t); + } + } + sim.sort(java.util.Comparator.comparing(InvestTrade::getTradeDate) + .thenComparing(InvestTrade::getId)); + BigDecimal running = BigDecimal.ZERO; + for (InvestTrade t : sim) { + if ("BUY".equals(t.getTradeType())) { + running = running.add(t.getQuantity()); + } else { + running = running.subtract(t.getQuantity()); + if (running.signum() < 0) { + throw new ApiException(HttpStatus.BAD_REQUEST, + "수정하면 보유수량이 음수가 됩니다. 매도 수량/순서를 확인하세요."); + } + } + } + + existing.setTradeType(type); + existing.setTradeDate(req.getTradeDate()); + existing.setQuantity(req.getQuantity()); + existing.setPrice(req.getPrice()); + existing.setFee(fee); + investMapper.updateTrade(existing); + return TradeResponse.from(existing); + } + @Transactional public void deleteTrade(Long id, Long memberId) { if (investMapper.findTradeByIdAndMember(id, memberId) == null) { diff --git a/src/main/resources/mapper/InvestMapper.xml b/src/main/resources/mapper/InvestMapper.xml index 65ddfa4..d68f428 100644 --- a/src/main/resources/mapper/InvestMapper.xml +++ b/src/main/resources/mapper/InvestMapper.xml @@ -87,6 +87,13 @@ VALUES (#{memberId}, #{holdingId}, #{tradeType}, #{tradeDate}, #{quantity}, #{price}, #{fee}, NOW()) + + UPDATE invest_trade + SET trade_type = #{tradeType}, trade_date = #{tradeDate}, + quantity = #{quantity}, price = #{price}, fee = #{fee} + WHERE id = #{id} AND member_id = #{memberId} + + DELETE FROM invest_trade WHERE id = #{id} AND member_id = #{memberId}