동기화
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
package com.ga.common.code;
|
||||
|
||||
import com.ga.common.annotation.RequirePermission;
|
||||
import com.ga.common.model.ApiResponse;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Tag(name = "계정코드")
|
||||
@RestController
|
||||
@RequestMapping("/api/common/account-codes")
|
||||
@RequiredArgsConstructor
|
||||
public class AccountCodeController {
|
||||
|
||||
private final AccountCodeService service;
|
||||
|
||||
/** 활성 계정코드 목록 — 드롭다운/배치 참조용. accountType 파라미터로 DEBIT/CREDIT/BOTH 필터 가능 */
|
||||
@GetMapping
|
||||
public ApiResponse<List<AccountCodeVO>> getActiveCodes(
|
||||
@RequestParam(required = false) String accountType) {
|
||||
return ApiResponse.ok(service.getActiveCodes(accountType));
|
||||
}
|
||||
|
||||
// ----- 시스템관리 -----
|
||||
|
||||
@GetMapping("/all")
|
||||
@RequirePermission(menu = "SYSTEM_CODE", perm = "READ")
|
||||
public ApiResponse<List<AccountCodeVO>> listAll(
|
||||
@RequestParam(required = false) String accountType) {
|
||||
return ApiResponse.ok(service.listAll(accountType));
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
@RequirePermission(menu = "SYSTEM_CODE", perm = "CREATE")
|
||||
public ApiResponse<Void> create(@RequestBody AccountCodeVO vo) {
|
||||
service.create(vo);
|
||||
return ApiResponse.ok();
|
||||
}
|
||||
|
||||
@PutMapping("/{accountCode}")
|
||||
@RequirePermission(menu = "SYSTEM_CODE", perm = "UPDATE")
|
||||
public ApiResponse<Void> update(@PathVariable String accountCode, @RequestBody AccountCodeVO vo) {
|
||||
vo.setAccountCode(accountCode);
|
||||
service.update(vo);
|
||||
return ApiResponse.ok();
|
||||
}
|
||||
|
||||
@DeleteMapping("/{accountCode}")
|
||||
@RequirePermission(menu = "SYSTEM_CODE", perm = "DELETE")
|
||||
public ApiResponse<Void> delete(@PathVariable String accountCode) {
|
||||
service.delete(accountCode);
|
||||
return ApiResponse.ok();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.ga.common.code;
|
||||
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mapper
|
||||
public interface AccountCodeMapper {
|
||||
|
||||
List<AccountCodeVO> selectAll(@Param("accountType") String accountType);
|
||||
List<AccountCodeVO> selectActive(@Param("accountType") String accountType);
|
||||
AccountCodeVO selectOne(@Param("accountCode") String accountCode);
|
||||
int insert(AccountCodeVO vo);
|
||||
int update(AccountCodeVO vo);
|
||||
int delete(@Param("accountCode") String accountCode);
|
||||
int existsByCode(@Param("accountCode") String accountCode);
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package com.ga.common.code;
|
||||
|
||||
import com.ga.common.exception.BizException;
|
||||
import com.ga.common.exception.ErrorCode;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class AccountCodeService {
|
||||
|
||||
private final AccountCodeMapper mapper;
|
||||
|
||||
public List<AccountCodeVO> getActiveCodes(String accountType) {
|
||||
return mapper.selectActive(accountType);
|
||||
}
|
||||
|
||||
public AccountCodeVO getCode(String accountCode) {
|
||||
AccountCodeVO vo = mapper.selectOne(accountCode);
|
||||
if (vo == null) throw new BizException(ErrorCode.NOT_FOUND);
|
||||
return vo;
|
||||
}
|
||||
|
||||
public List<AccountCodeVO> listAll(String accountType) {
|
||||
return mapper.selectAll(accountType);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void create(AccountCodeVO vo) {
|
||||
if (mapper.existsByCode(vo.getAccountCode()) > 0) {
|
||||
throw new BizException(ErrorCode.DUPLICATE_DATA);
|
||||
}
|
||||
mapper.insert(vo);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void update(AccountCodeVO vo) {
|
||||
getCode(vo.getAccountCode());
|
||||
mapper.update(vo);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void delete(String accountCode) {
|
||||
getCode(accountCode);
|
||||
mapper.delete(accountCode);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.ga.common.code;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Data
|
||||
public class AccountCodeVO {
|
||||
private String accountCode;
|
||||
private String accountName;
|
||||
private String accountType; // DEBIT / CREDIT / BOTH
|
||||
private String isActive;
|
||||
private Integer sortOrder;
|
||||
private String description;
|
||||
private LocalDateTime createdAt;
|
||||
private Long createdBy;
|
||||
private LocalDateTime updatedAt;
|
||||
private Long updatedBy;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
-- V63: 설계사 연말 사업소득 집계 테이블
|
||||
|
||||
CREATE TABLE agent_annual_income (
|
||||
agent_id BIGINT NOT NULL REFERENCES agent(agent_id),
|
||||
settle_year INT NOT NULL,
|
||||
total_commission NUMERIC(18,2) NOT NULL DEFAULT 0,
|
||||
total_tax_withheld NUMERIC(18,2) NOT NULL DEFAULT 0,
|
||||
total_local_tax NUMERIC(18,2) NOT NULL DEFAULT 0,
|
||||
business_income NUMERIC(18,2) NOT NULL DEFAULT 0,
|
||||
generated_at TIMESTAMP NOT NULL DEFAULT now(),
|
||||
created_at TIMESTAMP NOT NULL DEFAULT now(),
|
||||
updated_at TIMESTAMP,
|
||||
PRIMARY KEY (agent_id, settle_year)
|
||||
);
|
||||
|
||||
COMMENT ON TABLE agent_annual_income IS '설계사 연말 사업소득 집계';
|
||||
COMMENT ON COLUMN agent_annual_income.business_income IS 'total_commission - total_tax_withheld - total_local_tax';
|
||||
|
||||
CREATE INDEX idx_aai_year ON agent_annual_income(settle_year);
|
||||
|
||||
-- EXPLAIN ANALYZE: settle_year 단독 집계 — idx_aai_year Index Scan 확인
|
||||
-- EXPLAIN ANALYZE
|
||||
-- SELECT settle_year, SUM(business_income)
|
||||
-- FROM agent_annual_income
|
||||
-- GROUP BY settle_year;
|
||||
@@ -0,0 +1,24 @@
|
||||
-- V64: 계약 회계분개 엔트리 테이블
|
||||
|
||||
CREATE TABLE contract_accounting_entry (
|
||||
entry_id BIGSERIAL PRIMARY KEY,
|
||||
contract_id BIGINT NOT NULL REFERENCES contract(contract_id),
|
||||
payment_id BIGINT REFERENCES payment(payment_id),
|
||||
entry_date DATE NOT NULL,
|
||||
debit_account VARCHAR(20) NOT NULL,
|
||||
credit_account VARCHAR(20) NOT NULL,
|
||||
amount NUMERIC(18,2) NOT NULL,
|
||||
description VARCHAR(200),
|
||||
journal_no VARCHAR(30),
|
||||
created_at TIMESTAMP NOT NULL DEFAULT now()
|
||||
);
|
||||
|
||||
COMMENT ON TABLE contract_accounting_entry IS '계약 회계 분개 엔트리';
|
||||
COMMENT ON COLUMN contract_accounting_entry.debit_account IS '차변 계정코드 (예: 8350 지급수수료)';
|
||||
COMMENT ON COLUMN contract_accounting_entry.credit_account IS '대변 계정코드 (예: 2530 미지급금)';
|
||||
COMMENT ON COLUMN contract_accounting_entry.journal_no IS '마감 시 채번. NULL=미전기';
|
||||
|
||||
CREATE INDEX idx_cae_journal ON contract_accounting_entry(journal_no);
|
||||
CREATE INDEX idx_cae_date ON contract_accounting_entry(entry_date);
|
||||
CREATE INDEX idx_cae_contract ON contract_accounting_entry(contract_id, entry_date);
|
||||
CREATE INDEX idx_cae_unposted ON contract_accounting_entry(entry_date) WHERE journal_no IS NULL;
|
||||
@@ -0,0 +1,122 @@
|
||||
-- V65: P5-W1 테스트 데이터 (agent_annual_income, contract_accounting_entry, 메뉴)
|
||||
|
||||
-- ============================================================
|
||||
-- 1. agent_annual_income: 설계사 10명 / 2025년
|
||||
-- ============================================================
|
||||
INSERT INTO agent_annual_income (agent_id, settle_year, total_commission, total_tax_withheld, total_local_tax, business_income)
|
||||
SELECT
|
||||
a.agent_id,
|
||||
2025,
|
||||
v.total_commission,
|
||||
v.total_commission * 0.033,
|
||||
v.total_commission * 0.033 * 0.1,
|
||||
v.total_commission - (v.total_commission * 0.033) - (v.total_commission * 0.033 * 0.1)
|
||||
FROM (
|
||||
SELECT agent_id, ROW_NUMBER() OVER (ORDER BY agent_id) AS rn
|
||||
FROM agent
|
||||
LIMIT 10
|
||||
) a
|
||||
JOIN (VALUES
|
||||
(1, 42000000.00),
|
||||
(2, 38500000.00),
|
||||
(3, 55000000.00),
|
||||
(4, 29800000.00),
|
||||
(5, 61200000.00),
|
||||
(6, 47300000.00),
|
||||
(7, 33600000.00),
|
||||
(8, 52100000.00),
|
||||
(9, 28400000.00),
|
||||
(10, 44700000.00)
|
||||
) AS v(rn, total_commission) ON a.rn = v.rn
|
||||
ON CONFLICT (agent_id, settle_year) DO NOTHING;
|
||||
|
||||
-- ============================================================
|
||||
-- 2. contract_accounting_entry: payment 10건 기반
|
||||
-- journal_no NULL 5건 (미전기) + 채번 5건 (전기완료)
|
||||
-- ============================================================
|
||||
INSERT INTO contract_accounting_entry (contract_id, payment_id, entry_date, debit_account, credit_account, amount, description, journal_no)
|
||||
SELECT
|
||||
c.contract_id,
|
||||
p.payment_id,
|
||||
COALESCE(p.pay_date, CURRENT_DATE),
|
||||
'8350',
|
||||
'2530',
|
||||
p.pay_amount,
|
||||
'지급수수료 자동분개 #' || p.payment_id,
|
||||
CASE WHEN p.payment_id % 2 = 0 THEN 'JNL-2025-' || LPAD(p.payment_id::text, 5, '0') ELSE NULL END
|
||||
FROM (
|
||||
SELECT py.payment_id, py.pay_amount, py.pay_date, sm.agent_id
|
||||
FROM payment py
|
||||
JOIN settle_master sm ON sm.settle_id = py.settle_id
|
||||
ORDER BY py.payment_id
|
||||
LIMIT 10
|
||||
) p
|
||||
JOIN LATERAL (
|
||||
SELECT c.contract_id
|
||||
FROM contract c
|
||||
WHERE c.agent_id = p.agent_id
|
||||
ORDER BY c.contract_id
|
||||
LIMIT 1
|
||||
) c ON true;
|
||||
|
||||
-- ============================================================
|
||||
-- 3. 메뉴: ANNUAL_INCOME + ACCOUNTING_JOURNAL (GRP_COMMISSION 하위)
|
||||
-- ============================================================
|
||||
INSERT INTO menu (parent_menu_id, menu_code, menu_name, menu_type, menu_path, component_path, menu_level, sort_order, is_visible, is_active)
|
||||
SELECT p.menu_id, x.code, x.name, 'PAGE', x.path, x.cmpt, 2, x.sort, 'Y', 'Y'
|
||||
FROM menu p
|
||||
JOIN (VALUES
|
||||
('ANNUAL_INCOME', '연말 사업소득 명세서', '/commission/annual-income', 'commission/AnnualIncome', 80),
|
||||
('ACCOUNTING_JOURNAL', '회계 분개장', '/commission/accounting-journal', 'commission/AccountingJournal', 90)
|
||||
) AS x(code, name, path, cmpt, sort) ON p.menu_code = 'GRP_COMMISSION'
|
||||
WHERE NOT EXISTS (SELECT 1 FROM menu WHERE menu_code = x.code);
|
||||
|
||||
-- ============================================================
|
||||
-- 4. 권한 항목 등록
|
||||
-- ============================================================
|
||||
INSERT INTO menu_permission (menu_id, perm_code, perm_name, sort_order)
|
||||
SELECT m.menu_id, p.code, p.name, p.sort
|
||||
FROM menu m
|
||||
CROSS JOIN (VALUES
|
||||
('READ', '조회', 10),
|
||||
('CREATE', '등록', 20),
|
||||
('UPDATE', '수정', 30),
|
||||
('EXPORT', '엑셀', 60)
|
||||
) AS p(code, name, sort)
|
||||
WHERE m.menu_code IN ('ANNUAL_INCOME', 'ACCOUNTING_JOURNAL')
|
||||
ON CONFLICT (menu_id, perm_code) DO NOTHING;
|
||||
|
||||
-- ============================================================
|
||||
-- 5. 역할별 권한 부여
|
||||
-- ============================================================
|
||||
-- SUPER_ADMIN / ADMIN: 전체
|
||||
INSERT INTO role_menu_permission (role_id, menu_id, perm_code, is_granted)
|
||||
SELECT r.role_id, mp.menu_id, mp.perm_code, 'Y'
|
||||
FROM role r
|
||||
CROSS JOIN menu_permission mp
|
||||
JOIN menu m ON m.menu_id = mp.menu_id
|
||||
WHERE r.role_code IN ('SUPER_ADMIN', 'ADMIN')
|
||||
AND m.menu_code IN ('ANNUAL_INCOME', 'ACCOUNTING_JOURNAL')
|
||||
ON CONFLICT (role_id, menu_id, perm_code) DO NOTHING;
|
||||
|
||||
-- MANAGER: READ + EXPORT
|
||||
INSERT INTO role_menu_permission (role_id, menu_id, perm_code, is_granted)
|
||||
SELECT r.role_id, mp.menu_id, mp.perm_code, 'Y'
|
||||
FROM role r
|
||||
CROSS JOIN menu_permission mp
|
||||
JOIN menu m ON m.menu_id = mp.menu_id
|
||||
WHERE r.role_code = 'MANAGER'
|
||||
AND mp.perm_code IN ('READ', 'EXPORT')
|
||||
AND m.menu_code IN ('ANNUAL_INCOME', 'ACCOUNTING_JOURNAL')
|
||||
ON CONFLICT (role_id, menu_id, perm_code) DO NOTHING;
|
||||
|
||||
-- AGENT: READ (본인 연말명세서)
|
||||
INSERT INTO role_menu_permission (role_id, menu_id, perm_code, is_granted)
|
||||
SELECT r.role_id, mp.menu_id, mp.perm_code, 'Y'
|
||||
FROM role r
|
||||
CROSS JOIN menu_permission mp
|
||||
JOIN menu m ON m.menu_id = mp.menu_id
|
||||
WHERE r.role_code = 'AGENT'
|
||||
AND mp.perm_code = 'READ'
|
||||
AND m.menu_code = 'ANNUAL_INCOME'
|
||||
ON CONFLICT (role_id, menu_id, perm_code) DO NOTHING;
|
||||
@@ -0,0 +1,26 @@
|
||||
-- V66: 회계 계정코드 마스터 신설
|
||||
-- contract_accounting_entry.debit_account / credit_account 참조용
|
||||
-- FK 추가는 PL 별도 논의 후 진행
|
||||
|
||||
CREATE TABLE account_code (
|
||||
account_code VARCHAR(20) PRIMARY KEY,
|
||||
account_name VARCHAR(100) NOT NULL,
|
||||
account_type VARCHAR(10) NOT NULL CHECK (account_type IN ('DEBIT','CREDIT','BOTH')),
|
||||
is_active CHAR(1) NOT NULL DEFAULT 'Y',
|
||||
sort_order INTEGER NOT NULL DEFAULT 0,
|
||||
description VARCHAR(200),
|
||||
created_at TIMESTAMP NOT NULL DEFAULT now(),
|
||||
created_by BIGINT,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT now(),
|
||||
updated_by BIGINT
|
||||
);
|
||||
|
||||
COMMENT ON TABLE account_code IS '회계 계정코드 마스터';
|
||||
COMMENT ON COLUMN account_code.account_type IS 'DEBIT=차변전용, CREDIT=대변전용, BOTH=겸용';
|
||||
|
||||
INSERT INTO account_code (account_code, account_name, account_type, sort_order) VALUES
|
||||
('8350', '지급수수료', 'DEBIT', 10),
|
||||
('2530', '미지급금', 'CREDIT', 20),
|
||||
('1130', '미수수수료', 'DEBIT', 30),
|
||||
('4110', '수수료수익', 'CREDIT', 40)
|
||||
ON CONFLICT (account_code) DO NOTHING;
|
||||
@@ -0,0 +1,23 @@
|
||||
-- V67: 원천세 분기신고 테이블
|
||||
|
||||
CREATE TABLE withholding_tax_report (
|
||||
report_id BIGSERIAL PRIMARY KEY,
|
||||
settle_quarter VARCHAR(7) NOT NULL,
|
||||
agent_id BIGINT NOT NULL REFERENCES agent(agent_id),
|
||||
total_income NUMERIC(18,2),
|
||||
total_withheld NUMERIC(18,2),
|
||||
total_local_tax NUMERIC(18,2),
|
||||
generated_at TIMESTAMP,
|
||||
filed_at TIMESTAMP,
|
||||
file_status VARCHAR(20) NOT NULL DEFAULT 'DRAFT',
|
||||
created_at TIMESTAMP NOT NULL DEFAULT now(),
|
||||
updated_at TIMESTAMP,
|
||||
UNIQUE (agent_id, settle_quarter),
|
||||
CONSTRAINT chk_wtr_status CHECK (file_status IN ('DRAFT','FILED','AMENDED'))
|
||||
);
|
||||
|
||||
COMMENT ON TABLE withholding_tax_report IS '원천세 분기신고';
|
||||
COMMENT ON COLUMN withholding_tax_report.settle_quarter IS '정산 분기 (예: 2025-Q1)';
|
||||
COMMENT ON COLUMN withholding_tax_report.file_status IS 'DRAFT=작성중, FILED=신고완료, AMENDED=수정신고';
|
||||
|
||||
CREATE INDEX idx_wtr_quarter ON withholding_tax_report(settle_quarter);
|
||||
@@ -0,0 +1,22 @@
|
||||
-- V68: 부가세 분기신고 테이블
|
||||
|
||||
CREATE TABLE vat_report (
|
||||
vat_id BIGSERIAL PRIMARY KEY,
|
||||
settle_quarter VARCHAR(7) NOT NULL,
|
||||
total_sales NUMERIC(18,2),
|
||||
total_purchase NUMERIC(18,2),
|
||||
total_vat_payable NUMERIC(18,2),
|
||||
tax_invoice_count INT,
|
||||
generated_at TIMESTAMP,
|
||||
filed_at TIMESTAMP,
|
||||
file_status VARCHAR(20) NOT NULL DEFAULT 'DRAFT',
|
||||
created_at TIMESTAMP NOT NULL DEFAULT now(),
|
||||
updated_at TIMESTAMP,
|
||||
UNIQUE (settle_quarter),
|
||||
CONSTRAINT chk_vat_status CHECK (file_status IN ('DRAFT','FILED','AMENDED'))
|
||||
);
|
||||
|
||||
COMMENT ON TABLE vat_report IS '부가세 분기신고';
|
||||
COMMENT ON COLUMN vat_report.settle_quarter IS '정산 분기 (예: 2025-Q1)';
|
||||
COMMENT ON COLUMN vat_report.total_vat_payable IS '납부 부가세 = total_sales * 0.1 - 매입세액';
|
||||
COMMENT ON COLUMN vat_report.file_status IS 'DRAFT=작성중, FILED=신고완료, AMENDED=수정신고';
|
||||
@@ -0,0 +1,87 @@
|
||||
-- V69: P5-W2 테스트 데이터 (withholding_tax_report, vat_report, 메뉴)
|
||||
|
||||
-- ============================================================
|
||||
-- 1. withholding_tax_report: agent 5명 × 2025 Q1~Q4 = 20건
|
||||
-- ============================================================
|
||||
INSERT INTO withholding_tax_report (settle_quarter, agent_id, total_income, total_withheld, total_local_tax, generated_at, file_status)
|
||||
SELECT
|
||||
q.quarter,
|
||||
a.agent_id,
|
||||
q.base_income,
|
||||
q.base_income * 0.033,
|
||||
q.base_income * 0.033 * 0.1,
|
||||
now(),
|
||||
CASE WHEN q.quarter IN ('2025-Q1','2025-Q2') THEN 'FILED' ELSE 'DRAFT' END
|
||||
FROM (
|
||||
SELECT agent_id, ROW_NUMBER() OVER (ORDER BY agent_id) AS rn
|
||||
FROM agent LIMIT 5
|
||||
) a
|
||||
CROSS JOIN (VALUES
|
||||
('2025-Q1', 10500000.00),
|
||||
('2025-Q2', 11200000.00),
|
||||
('2025-Q3', 10800000.00),
|
||||
('2025-Q4', 12300000.00)
|
||||
) AS q(quarter, base_income)
|
||||
ON CONFLICT (agent_id, settle_quarter) DO NOTHING;
|
||||
|
||||
-- ============================================================
|
||||
-- 2. vat_report: 2025 Q1~Q4 = 4건
|
||||
-- ============================================================
|
||||
INSERT INTO vat_report (settle_quarter, total_sales, total_purchase, total_vat_payable, tax_invoice_count, generated_at, file_status)
|
||||
VALUES
|
||||
('2025-Q1', 850000000.00, 120000000.00, 73000000.00, 142, now(), 'FILED'),
|
||||
('2025-Q2', 920000000.00, 135000000.00, 78500000.00, 158, now(), 'FILED'),
|
||||
('2025-Q3', 880000000.00, 128000000.00, 75200000.00, 151, now(), 'DRAFT'),
|
||||
('2025-Q4', 960000000.00, 140000000.00, 82000000.00, 167, now(), 'DRAFT')
|
||||
ON CONFLICT (settle_quarter) DO NOTHING;
|
||||
|
||||
-- ============================================================
|
||||
-- 3. 메뉴: WITHHOLDING_TAX + VAT_REPORT (GRP_COMMISSION 하위)
|
||||
-- ============================================================
|
||||
INSERT INTO menu (parent_menu_id, menu_code, menu_name, menu_type, menu_path, component_path, menu_level, sort_order, is_visible, is_active)
|
||||
SELECT p.menu_id, x.code, x.name, 'PAGE', x.path, x.cmpt, 2, x.sort, 'Y', 'Y'
|
||||
FROM menu p
|
||||
JOIN (VALUES
|
||||
('WITHHOLDING_TAX', '원천세 신고', '/commission/withholding-tax', 'commission/WithholdingTax', 100),
|
||||
('VAT_REPORT', '부가세 신고', '/commission/vat-report', 'commission/VatReport', 110)
|
||||
) AS x(code, name, path, cmpt, sort) ON p.menu_code = 'GRP_COMMISSION'
|
||||
WHERE NOT EXISTS (SELECT 1 FROM menu WHERE menu_code = x.code);
|
||||
|
||||
-- ============================================================
|
||||
-- 4. 권한 항목 등록
|
||||
-- ============================================================
|
||||
INSERT INTO menu_permission (menu_id, perm_code, perm_name, sort_order)
|
||||
SELECT m.menu_id, p.code, p.name, p.sort
|
||||
FROM menu m
|
||||
CROSS JOIN (VALUES
|
||||
('READ', '조회', 10),
|
||||
('CREATE', '등록', 20),
|
||||
('UPDATE', '수정', 30),
|
||||
('EXPORT', '엑셀', 60)
|
||||
) AS p(code, name, sort)
|
||||
WHERE m.menu_code IN ('WITHHOLDING_TAX', 'VAT_REPORT')
|
||||
ON CONFLICT (menu_id, perm_code) DO NOTHING;
|
||||
|
||||
-- ============================================================
|
||||
-- 5. 역할별 권한 부여
|
||||
-- ============================================================
|
||||
-- SUPER_ADMIN / ADMIN: 전체
|
||||
INSERT INTO role_menu_permission (role_id, menu_id, perm_code, is_granted)
|
||||
SELECT r.role_id, mp.menu_id, mp.perm_code, 'Y'
|
||||
FROM role r
|
||||
CROSS JOIN menu_permission mp
|
||||
JOIN menu m ON m.menu_id = mp.menu_id
|
||||
WHERE r.role_code IN ('SUPER_ADMIN', 'ADMIN')
|
||||
AND m.menu_code IN ('WITHHOLDING_TAX', 'VAT_REPORT')
|
||||
ON CONFLICT (role_id, menu_id, perm_code) DO NOTHING;
|
||||
|
||||
-- MANAGER: READ + EXPORT
|
||||
INSERT INTO role_menu_permission (role_id, menu_id, perm_code, is_granted)
|
||||
SELECT r.role_id, mp.menu_id, mp.perm_code, 'Y'
|
||||
FROM role r
|
||||
CROSS JOIN menu_permission mp
|
||||
JOIN menu m ON m.menu_id = mp.menu_id
|
||||
WHERE r.role_code = 'MANAGER'
|
||||
AND mp.perm_code IN ('READ', 'EXPORT')
|
||||
AND m.menu_code IN ('WITHHOLDING_TAX', 'VAT_REPORT')
|
||||
ON CONFLICT (role_id, menu_id, perm_code) DO NOTHING;
|
||||
@@ -0,0 +1,29 @@
|
||||
-- V70: rule 도메인 5개 테이블 감사 컬럼 보강
|
||||
-- commission_rate / payout_rule: created_at/created_by 존재, updated_at/updated_by 누락
|
||||
-- override_rule / chargeback_rule / exception_type_code: 감사 컬럼 전체 누락
|
||||
|
||||
ALTER TABLE commission_rate
|
||||
ADD COLUMN IF NOT EXISTS updated_at TIMESTAMP,
|
||||
ADD COLUMN IF NOT EXISTS updated_by BIGINT;
|
||||
|
||||
ALTER TABLE payout_rule
|
||||
ADD COLUMN IF NOT EXISTS updated_at TIMESTAMP,
|
||||
ADD COLUMN IF NOT EXISTS updated_by BIGINT;
|
||||
|
||||
ALTER TABLE override_rule
|
||||
ADD COLUMN IF NOT EXISTS created_at TIMESTAMP NOT NULL DEFAULT now(),
|
||||
ADD COLUMN IF NOT EXISTS created_by BIGINT,
|
||||
ADD COLUMN IF NOT EXISTS updated_at TIMESTAMP,
|
||||
ADD COLUMN IF NOT EXISTS updated_by BIGINT;
|
||||
|
||||
ALTER TABLE chargeback_rule
|
||||
ADD COLUMN IF NOT EXISTS created_at TIMESTAMP NOT NULL DEFAULT now(),
|
||||
ADD COLUMN IF NOT EXISTS created_by BIGINT,
|
||||
ADD COLUMN IF NOT EXISTS updated_at TIMESTAMP,
|
||||
ADD COLUMN IF NOT EXISTS updated_by BIGINT;
|
||||
|
||||
ALTER TABLE exception_type_code
|
||||
ADD COLUMN IF NOT EXISTS created_at TIMESTAMP NOT NULL DEFAULT now(),
|
||||
ADD COLUMN IF NOT EXISTS created_by BIGINT,
|
||||
ADD COLUMN IF NOT EXISTS updated_at TIMESTAMP,
|
||||
ADD COLUMN IF NOT EXISTS updated_by BIGINT;
|
||||
@@ -0,0 +1,13 @@
|
||||
-- V71: payment 테이블 세무 컬럼 누락 보강
|
||||
-- V23 세무처리.sql 체크섬 미스매치로 income_tax_amount 등 미적용 → idempotent 추가
|
||||
|
||||
ALTER TABLE payment
|
||||
ADD COLUMN IF NOT EXISTS income_tax_amount NUMERIC(15,2) NOT NULL DEFAULT 0,
|
||||
ADD COLUMN IF NOT EXISTS local_tax_amount NUMERIC(15,2) NOT NULL DEFAULT 0,
|
||||
ADD COLUMN IF NOT EXISTS vat_amount NUMERIC(15,2) NOT NULL DEFAULT 0,
|
||||
ADD COLUMN IF NOT EXISTS net_amount NUMERIC(15,2);
|
||||
|
||||
COMMENT ON COLUMN payment.income_tax_amount IS '원천세 (소득세 3%)';
|
||||
COMMENT ON COLUMN payment.local_tax_amount IS '지방소득세 (소득세의 10%)';
|
||||
COMMENT ON COLUMN payment.vat_amount IS '부가세';
|
||||
COMMENT ON COLUMN payment.net_amount IS '실수령액 (pay_amount - income_tax - local_tax)';
|
||||
@@ -0,0 +1,29 @@
|
||||
-- V72: P5-W1 ANNUAL_INCOME 메뉴 EXECUTE 권한 누락 보강
|
||||
-- V65에서 READ/CREATE/UPDATE/EXPORT만 등록되어 regenerate 엔드포인트 403 발생
|
||||
-- SUPER_ADMIN / ADMIN 역할에 EXECUTE 권한 부여
|
||||
|
||||
-- 1. menu_permission에 EXECUTE 항목 추가
|
||||
INSERT INTO menu_permission (menu_id, perm_code, perm_name, sort_order)
|
||||
SELECT m.menu_id, 'EXECUTE', '재집계', 70
|
||||
FROM menu m
|
||||
WHERE m.menu_code = 'ANNUAL_INCOME'
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM menu_permission mp2
|
||||
WHERE mp2.menu_id = m.menu_id AND mp2.perm_code = 'EXECUTE'
|
||||
);
|
||||
|
||||
-- 2. SUPER_ADMIN / ADMIN에 EXECUTE 권한 부여
|
||||
INSERT INTO role_menu_permission (role_id, menu_id, perm_code, is_granted)
|
||||
SELECT r.role_id, mp.menu_id, mp.perm_code, 'Y'
|
||||
FROM role r
|
||||
CROSS JOIN menu_permission mp
|
||||
JOIN menu m ON m.menu_id = mp.menu_id
|
||||
WHERE r.role_code IN ('SUPER_ADMIN', 'ADMIN')
|
||||
AND mp.perm_code = 'EXECUTE'
|
||||
AND m.menu_code = 'ANNUAL_INCOME'
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM role_menu_permission rmp2
|
||||
WHERE rmp2.role_id = r.role_id
|
||||
AND rmp2.menu_id = mp.menu_id
|
||||
AND rmp2.perm_code = 'EXECUTE'
|
||||
);
|
||||
@@ -0,0 +1,70 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.ga.common.code.AccountCodeMapper">
|
||||
|
||||
<resultMap id="AccountCodeMap" type="com.ga.common.code.AccountCodeVO"/>
|
||||
|
||||
<sql id="Columns">
|
||||
account_code, account_name, account_type, is_active, sort_order, description,
|
||||
created_at, created_by, updated_at, updated_by
|
||||
</sql>
|
||||
|
||||
<select id="selectAll" resultMap="AccountCodeMap">
|
||||
SELECT <include refid="Columns"/>
|
||||
FROM account_code
|
||||
<where>
|
||||
<if test="accountType != null and accountType != ''">
|
||||
AND account_type = #{accountType}
|
||||
</if>
|
||||
</where>
|
||||
ORDER BY sort_order, account_code
|
||||
</select>
|
||||
|
||||
<select id="selectActive" resultMap="AccountCodeMap">
|
||||
SELECT <include refid="Columns"/>
|
||||
FROM account_code
|
||||
WHERE is_active = 'Y'
|
||||
<if test="accountType != null and accountType != ''">
|
||||
AND account_type = #{accountType}
|
||||
</if>
|
||||
ORDER BY sort_order, account_code
|
||||
</select>
|
||||
|
||||
<select id="selectOne" resultMap="AccountCodeMap">
|
||||
SELECT <include refid="Columns"/>
|
||||
FROM account_code WHERE account_code = #{accountCode}
|
||||
</select>
|
||||
|
||||
<insert id="insert" parameterType="com.ga.common.code.AccountCodeVO">
|
||||
INSERT INTO account_code (
|
||||
account_code, account_name, account_type, is_active, sort_order, description,
|
||||
created_at, created_by
|
||||
) VALUES (
|
||||
#{accountCode}, #{accountName}, #{accountType},
|
||||
COALESCE(#{isActive},'Y'), COALESCE(#{sortOrder},0), #{description},
|
||||
now(), #{createdBy}
|
||||
)
|
||||
</insert>
|
||||
|
||||
<update id="update" parameterType="com.ga.common.code.AccountCodeVO">
|
||||
UPDATE account_code SET
|
||||
account_name = #{accountName},
|
||||
account_type = #{accountType},
|
||||
is_active = #{isActive},
|
||||
sort_order = #{sortOrder},
|
||||
description = #{description},
|
||||
updated_at = now(),
|
||||
updated_by = #{updatedBy}
|
||||
WHERE account_code = #{accountCode}
|
||||
</update>
|
||||
|
||||
<delete id="delete">
|
||||
DELETE FROM account_code WHERE account_code = #{accountCode}
|
||||
</delete>
|
||||
|
||||
<select id="existsByCode" resultType="int">
|
||||
SELECT COUNT(*) FROM account_code WHERE account_code = #{accountCode}
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
Reference in New Issue
Block a user