Merge branch 'dev' into main
This commit is contained in:
@@ -10,6 +10,7 @@ import com.sb.web.account.dto.NetWorthPoint;
|
||||
import com.sb.web.account.dto.NetWorthResponse;
|
||||
import com.sb.web.account.dto.PeriodStat;
|
||||
import com.sb.web.account.dto.RepaymentRequest;
|
||||
import com.sb.web.account.dto.WalletReorderRequest;
|
||||
import com.sb.web.account.dto.WalletRequest;
|
||||
import com.sb.web.account.dto.WalletResponse;
|
||||
import com.sb.web.account.service.AccountService;
|
||||
@@ -69,6 +70,14 @@ public class AccountController {
|
||||
return ResponseEntity.noContent().build();
|
||||
}
|
||||
|
||||
/** 계좌/카드 순서 변경 (드래그앤드랍) */
|
||||
@PutMapping("/wallets/reorder")
|
||||
public List<WalletResponse> reorderWallets(
|
||||
@RequestBody WalletReorderRequest req,
|
||||
@RequestAttribute(AuthInterceptor.CURRENT_MEMBER) SessionUser current) {
|
||||
return accountService.reorderWallets(current.getId(), req.getType(), req.getIds());
|
||||
}
|
||||
|
||||
@GetMapping("/networth")
|
||||
public NetWorthResponse netWorth(
|
||||
@RequestAttribute(AuthInterceptor.CURRENT_MEMBER) SessionUser current) {
|
||||
|
||||
@@ -28,19 +28,23 @@ public class BudgetController {
|
||||
private final BudgetService budgetService;
|
||||
private final AccountSettingService settingService;
|
||||
|
||||
/** 월 예상 수입 조회 */
|
||||
/** 월 예상 수입 조회 (연·월별) */
|
||||
@GetMapping("/income")
|
||||
public ExpectedIncomeRequest getIncome(
|
||||
@RequestParam int year,
|
||||
@RequestParam int month,
|
||||
@RequestAttribute(AuthInterceptor.CURRENT_MEMBER) SessionUser current) {
|
||||
return new ExpectedIncomeRequest(settingService.getExpectedIncome(current.getId()));
|
||||
return new ExpectedIncomeRequest(settingService.getExpectedIncome(current.getId(), year, month));
|
||||
}
|
||||
|
||||
/** 월 예상 수입 설정 */
|
||||
/** 월 예상 수입 설정 (연·월별) */
|
||||
@PutMapping("/income")
|
||||
public ExpectedIncomeRequest setIncome(
|
||||
@RequestParam int year,
|
||||
@RequestParam int month,
|
||||
@Valid @RequestBody ExpectedIncomeRequest req,
|
||||
@RequestAttribute(AuthInterceptor.CURRENT_MEMBER) SessionUser current) {
|
||||
settingService.setExpectedIncome(current.getId(), req.getExpectedIncome());
|
||||
settingService.setExpectedIncome(current.getId(), year, month, req.getExpectedIncome());
|
||||
return req;
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ public class Wallet implements Serializable {
|
||||
private Long openingBalance; // 초기 잔액(부호있음: 자산+, 부채-)
|
||||
private LocalDate openingDate;
|
||||
private Long currentValue; // 현재 평가금액 (INVEST 전용, 수동 갱신)
|
||||
private Integer sortOrder; // 표시 순서 (타입 내 정렬)
|
||||
private LocalDateTime createdAt;
|
||||
private LocalDateTime updatedAt;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.sb.web.account.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 계좌/카드 순서 변경 요청. ids 순서대로 sort_order 를 재설정한다.
|
||||
*/
|
||||
@Data
|
||||
public class WalletReorderRequest {
|
||||
|
||||
private String type; // BANK / CARD / LOAN / INVEST
|
||||
private List<Long> ids; // 새 순서의 wallet id 목록
|
||||
}
|
||||
@@ -4,14 +4,19 @@ import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
/**
|
||||
* 사용자별 가계부 설정 매퍼 (account_setting).
|
||||
* 월 예상 수입 매퍼 (budget_income, 월별).
|
||||
*/
|
||||
@Mapper
|
||||
public interface AccountSettingMapper {
|
||||
|
||||
/** 월 예상 수입 (없으면 null) */
|
||||
Long findExpectedIncome(@Param("memberId") Long memberId);
|
||||
/** 해당 연·월의 예상 수입 (없으면 null) */
|
||||
Long findExpectedIncome(@Param("memberId") Long memberId,
|
||||
@Param("year") int year,
|
||||
@Param("month") int month);
|
||||
|
||||
/** 월 예상 수입 upsert */
|
||||
int upsertExpectedIncome(@Param("memberId") Long memberId, @Param("expectedIncome") Long expectedIncome);
|
||||
/** 해당 연·월 예상 수입 upsert */
|
||||
int upsertExpectedIncome(@Param("memberId") Long memberId,
|
||||
@Param("year") int year,
|
||||
@Param("month") int month,
|
||||
@Param("expectedIncome") Long expectedIncome);
|
||||
}
|
||||
|
||||
@@ -25,4 +25,10 @@ public interface WalletMapper {
|
||||
int update(Wallet wallet);
|
||||
|
||||
int delete(@Param("id") Long id, @Param("memberId") Long memberId);
|
||||
|
||||
/** 순서(sort_order) 변경 */
|
||||
int updateSortOrder(@Param("id") Long id, @Param("memberId") Long memberId, @Param("sortOrder") int sortOrder);
|
||||
|
||||
/** 해당 타입의 현재 최대 sort_order (신규 계좌를 맨 뒤에 배치) */
|
||||
Integer maxSortOrder(@Param("memberId") Long memberId, @Param("type") String type);
|
||||
}
|
||||
|
||||
@@ -301,10 +301,25 @@ public class AccountService {
|
||||
public WalletResponse createWallet(WalletRequest req, Long memberId) {
|
||||
Wallet wallet = toWallet(req);
|
||||
wallet.setMemberId(memberId);
|
||||
Integer max = walletMapper.maxSortOrder(memberId, req.getType());
|
||||
wallet.setSortOrder(max == null ? 0 : max + 1); // 같은 타입의 맨 뒤
|
||||
walletMapper.insert(wallet);
|
||||
return WalletResponse.from(wallet, wallet.getOpeningBalance()); // 신규 → 잔액=초기잔액
|
||||
}
|
||||
|
||||
/** 드래그앤드랍 순서 변경: 전달된 id 순서대로 sort_order 재설정 (본인·동일 타입만) */
|
||||
@Transactional
|
||||
public List<WalletResponse> reorderWallets(Long memberId, String type, List<Long> ids) {
|
||||
int i = 0;
|
||||
for (Long id : ids) {
|
||||
Wallet w = walletMapper.findByIdAndMember(id, memberId);
|
||||
if (w != null && w.getType().equals(type)) {
|
||||
walletMapper.updateSortOrder(id, memberId, i++);
|
||||
}
|
||||
}
|
||||
return listWallets(memberId);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public WalletResponse updateWallet(Long id, WalletRequest req, Long memberId) {
|
||||
Wallet wallet = mustFindWallet(id, memberId);
|
||||
|
||||
@@ -6,7 +6,7 @@ import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* 사용자별 가계부 설정 서비스 (월 예상 수입 등).
|
||||
* 월 예상 수입 설정 서비스 (월별).
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@@ -14,12 +14,12 @@ public class AccountSettingService {
|
||||
|
||||
private final AccountSettingMapper settingMapper;
|
||||
|
||||
public Long getExpectedIncome(Long memberId) {
|
||||
return settingMapper.findExpectedIncome(memberId);
|
||||
public Long getExpectedIncome(Long memberId, int year, int month) {
|
||||
return settingMapper.findExpectedIncome(memberId, year, month);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void setExpectedIncome(Long memberId, Long expectedIncome) {
|
||||
settingMapper.upsertExpectedIncome(memberId, expectedIncome);
|
||||
public void setExpectedIncome(Long memberId, int year, int month, Long expectedIncome) {
|
||||
settingMapper.upsertExpectedIncome(memberId, year, month, expectedIncome);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ CREATE TABLE IF NOT EXISTS wallet (
|
||||
ALTER TABLE wallet ADD COLUMN IF NOT EXISTS opening_balance BIGINT NOT NULL DEFAULT 0;
|
||||
ALTER TABLE wallet ADD COLUMN IF NOT EXISTS opening_date DATE NULL;
|
||||
ALTER TABLE wallet ADD COLUMN IF NOT EXISTS current_value BIGINT NULL;
|
||||
ALTER TABLE wallet ADD COLUMN IF NOT EXISTS sort_order INT NOT NULL DEFAULT 0;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS account_entry (
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
@@ -123,12 +124,14 @@ CREATE TABLE IF NOT EXISTS account_entry_tag (
|
||||
KEY idx_aet_tag (tag_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- 사용자별 가계부 설정 (예: 월 예상 수입)
|
||||
CREATE TABLE IF NOT EXISTS account_setting (
|
||||
-- 사용자별 월 예상 수입 (월별 저장)
|
||||
CREATE TABLE IF NOT EXISTS budget_income (
|
||||
member_id BIGINT NOT NULL COMMENT '소유자 member.id',
|
||||
`year` INT NOT NULL,
|
||||
`month` INT NOT NULL,
|
||||
expected_income BIGINT NULL COMMENT '월 예상 수입',
|
||||
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (member_id)
|
||||
PRIMARY KEY (member_id, `year`, `month`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- 투자 보유 종목 (INVEST 지갑별 · 사용자별)
|
||||
|
||||
@@ -4,12 +4,13 @@
|
||||
<mapper namespace="com.sb.web.account.mapper.AccountSettingMapper">
|
||||
|
||||
<select id="findExpectedIncome" resultType="java.lang.Long">
|
||||
SELECT expected_income FROM account_setting WHERE member_id = #{memberId}
|
||||
SELECT expected_income FROM budget_income
|
||||
WHERE member_id = #{memberId} AND `year` = #{year} AND `month` = #{month}
|
||||
</select>
|
||||
|
||||
<update id="upsertExpectedIncome">
|
||||
INSERT INTO account_setting (member_id, expected_income, updated_at)
|
||||
VALUES (#{memberId}, #{expectedIncome}, NOW())
|
||||
INSERT INTO budget_income (member_id, `year`, `month`, expected_income, updated_at)
|
||||
VALUES (#{memberId}, #{year}, #{month}, #{expectedIncome}, NOW())
|
||||
ON DUPLICATE KEY UPDATE expected_income = #{expectedIncome}, updated_at = NOW()
|
||||
</update>
|
||||
|
||||
|
||||
@@ -14,17 +14,18 @@
|
||||
<result property="openingBalance" column="opening_balance"/>
|
||||
<result property="openingDate" column="opening_date"/>
|
||||
<result property="currentValue" column="current_value"/>
|
||||
<result property="sortOrder" column="sort_order"/>
|
||||
<result property="createdAt" column="created_at"/>
|
||||
<result property="updatedAt" column="updated_at"/>
|
||||
</resultMap>
|
||||
|
||||
<sql id="cols">id, member_id, type, name, issuer, account_number, card_type,
|
||||
opening_balance, opening_date, current_value, created_at, updated_at</sql>
|
||||
opening_balance, opening_date, current_value, sort_order, created_at, updated_at</sql>
|
||||
|
||||
<select id="findByMember" parameterType="long" resultMap="walletResultMap">
|
||||
SELECT <include refid="cols"/> FROM wallet
|
||||
WHERE member_id = #{memberId}
|
||||
ORDER BY type, name
|
||||
ORDER BY type, sort_order, name
|
||||
</select>
|
||||
|
||||
<select id="findByIdAndMember" resultMap="walletResultMap">
|
||||
@@ -35,9 +36,9 @@
|
||||
<insert id="insert" parameterType="com.sb.web.account.domain.Wallet"
|
||||
useGeneratedKeys="true" keyProperty="id">
|
||||
INSERT INTO wallet (member_id, type, name, issuer, account_number, card_type,
|
||||
opening_balance, opening_date, current_value, created_at, updated_at)
|
||||
opening_balance, opening_date, current_value, sort_order, created_at, updated_at)
|
||||
VALUES (#{memberId}, #{type}, #{name}, #{issuer}, #{accountNumber}, #{cardType},
|
||||
#{openingBalance}, #{openingDate}, #{currentValue}, NOW(), NOW())
|
||||
#{openingBalance}, #{openingDate}, #{currentValue}, #{sortOrder}, NOW(), NOW())
|
||||
</insert>
|
||||
|
||||
<update id="update" parameterType="com.sb.web.account.domain.Wallet">
|
||||
@@ -70,4 +71,13 @@
|
||||
DELETE FROM wallet WHERE id = #{id} AND member_id = #{memberId}
|
||||
</delete>
|
||||
|
||||
<update id="updateSortOrder">
|
||||
UPDATE wallet SET sort_order = #{sortOrder}
|
||||
WHERE id = #{id} AND member_id = #{memberId}
|
||||
</update>
|
||||
|
||||
<select id="maxSortOrder" resultType="java.lang.Integer">
|
||||
SELECT MAX(sort_order) FROM wallet WHERE member_id = #{memberId} AND type = #{type}
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
|
||||
Reference in New Issue
Block a user