diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4b540d8..2c6a067 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -3,8 +3,9 @@ name: gradle build on: pull_request: branches: - - main - - dev + - main + - dev + # 권한 설정 permissions: write-all @@ -27,10 +28,6 @@ jobs: - name: Set up Environment run: echo "${{ secrets.ENV_PROPERTIES_LOCAL }}" > ./.env - # docker로 Test용 mysql 띄우기 - - name: Create Mysql Docker Container - run: sudo docker run -d -p 3306:3306 --env MYSQL_DATABASE="${{ secrets.TEST_DATABASE }}" --env MYSQL_ROOT_PASSWORD="${{ secrets.TEST_DATASOURCE_PASSWORD }}" mysql:8.0.31 - # 빌드시 캐시 적용 - name: Cache Gradle Packages uses: actions/cache@v3 diff --git a/.github/workflows/deploy-dev.yml b/.github/workflows/deploy-dev.yml index b746944..3b03cc6 100644 --- a/.github/workflows/deploy-dev.yml +++ b/.github/workflows/deploy-dev.yml @@ -4,7 +4,7 @@ on: push: branches: - dev - - feat/** + # 권한 설정 permissions: contents: read @@ -30,16 +30,12 @@ jobs: - name: Send env file uses: appleboy/scp-action@master with: - username: ${{ secrets.USERNAME }} - host: ${{ secrets.NCP_HOST }} + username: root + host: ${{ secrets.NCP_DEV_IP }} password: ${{ secrets.NCP_PASSWORD }} source: "./.env" target: "/home/ubuntu" - # 도커 MYSQL 이미지 실행 - - name: Create Mysql Docker Container - run: sudo docker run -d -p 3306:3306 --env MYSQL_DATABASE="${{ secrets.TEST_DATABASE }}" --env MYSQL_ROOT_PASSWORD="${{ secrets.TEST_DATASOURCE_PASSWORD }}" mysql:8.0.31 - # 빌드 - name: Build with Gradle run: ./gradlew clean bootJar @@ -55,8 +51,8 @@ jobs: - name: Send docker-compose.yml uses: appleboy/scp-action@master with: - username: ${{ secrets.USERNAME }} - host: ${{ secrets.NCP_HOST }} + username: root + host: ${{ secrets.NCP_DEV_IP }} password: ${{ secrets.NCP_PASSWORD }} port: 22 source: "./.docker/docker-compose.yml" @@ -66,8 +62,8 @@ jobs: - name: Deploy to Dev uses: appleboy/ssh-action@master with: - username: ${{ secrets.USERNAME }} - host: ${{ secrets.NCP_HOST }} + username: root + host: ${{ secrets.NCP_DEV_IP }} password: ${{ secrets.NCP_PASSWORD }} script: | sudo cp /home/ubuntu/.docker/docker-compose.yml /home/ubuntu diff --git a/.github/workflows/deploy-prod.yml b/.github/workflows/deploy-prod.yml index b87946b..64946e8 100644 --- a/.github/workflows/deploy-prod.yml +++ b/.github/workflows/deploy-prod.yml @@ -30,16 +30,12 @@ jobs: - name: Send env file uses: appleboy/scp-action@master with: - username: ${{ secrets.USERNAME }} - host: ${{ secrets.NCP_PROD_HOST }} + username: root + host: ${{ secrets.NCP_PROD_IP }} password: ${{ secrets.NCP_PROD_PASSWORD }} source: "./.env" target: "/home/ubuntu" - # 도커 MYSQL 이미지 실행 - - name: Create Mysql Docker Container - run: sudo docker run -d -p 3306:3306 --env MYSQL_DATABASE="${{ secrets.TEST_DATABASE }}" --env MYSQL_ROOT_PASSWORD="${{ secrets.TEST_DATASOURCE_PASSWORD }}" mysql:8.0.31 - # 빌드 - name: Build with Gradle run: ./gradlew clean bootJar @@ -55,19 +51,19 @@ jobs: - name: Send docker-compose.yml uses: appleboy/scp-action@master with: - username: ${{ secrets.USERNAME }} - host: ${{ secrets.NCP_PROD_HOST }} + username: root + host: ${{ secrets.NCP_PROD_IP }} password: ${{ secrets.NCP_PROD_PASSWORD }} port: 22 source: "./.docker/docker-compose.yml" target: "/home/ubuntu/" # 도커 컴포즈 실행 - - name: Deploy to Dev + - name: Deploy to Prod uses: appleboy/ssh-action@master with: - username: ${{ secrets.USERNAME }} - host: ${{ secrets.NCP_PROD_HOST }} + username: root + host: ${{ secrets.NCP_PROD_IP }} password: ${{ secrets.NCP_PROD_PASSWORD }} script: | sudo cp /home/ubuntu/.docker/docker-compose.yml /home/ubuntu diff --git a/src/main/java/com/moneymong/domain/ledger/api/request/UpdateLedgerRequest.java b/src/main/java/com/moneymong/domain/ledger/api/request/UpdateLedgerRequest.java index b4976b6..fee63ce 100644 --- a/src/main/java/com/moneymong/domain/ledger/api/request/UpdateLedgerRequest.java +++ b/src/main/java/com/moneymong/domain/ledger/api/request/UpdateLedgerRequest.java @@ -6,7 +6,6 @@ import java.time.ZonedDateTime; import lombok.Getter; import lombok.NoArgsConstructor; -import org.hibernate.validator.constraints.Length; @Getter @NoArgsConstructor diff --git a/src/main/java/com/moneymong/domain/ledger/entity/LedgerDetail.java b/src/main/java/com/moneymong/domain/ledger/entity/LedgerDetail.java index 731a514..73d4323 100644 --- a/src/main/java/com/moneymong/domain/ledger/entity/LedgerDetail.java +++ b/src/main/java/com/moneymong/domain/ledger/entity/LedgerDetail.java @@ -84,6 +84,18 @@ public void updateBalance(int balance) { this.balance = balance; } + public void updateLedgerDetailInfo( + String storeInfo, + int amount, + String description, + ZonedDateTime paymentDate + ) { + this.storeInfo = storeInfo; + this.amount = amount; + this.description = description; + this.paymentDate = paymentDate; + } + public static LedgerDetail of( final Ledger ledger, final User user, diff --git a/src/main/java/com/moneymong/domain/ledger/repository/LedgerDetailRepository.java b/src/main/java/com/moneymong/domain/ledger/repository/LedgerDetailRepository.java index 18a44d5..4029158 100644 --- a/src/main/java/com/moneymong/domain/ledger/repository/LedgerDetailRepository.java +++ b/src/main/java/com/moneymong/domain/ledger/repository/LedgerDetailRepository.java @@ -4,6 +4,10 @@ import com.moneymong.domain.ledger.entity.LedgerDetail; import org.springframework.data.jpa.repository.JpaRepository; +import java.util.List; + public interface LedgerDetailRepository extends JpaRepository, LedgerDetailCustom { boolean existsByLedger(Ledger ledger); + + List findAllByLedger(Ledger ledger); } diff --git a/src/main/java/com/moneymong/domain/ledger/repository/impl/LedgerDetailCustomImpl.java b/src/main/java/com/moneymong/domain/ledger/repository/impl/LedgerDetailCustomImpl.java index f3190ea..7389ce1 100644 --- a/src/main/java/com/moneymong/domain/ledger/repository/impl/LedgerDetailCustomImpl.java +++ b/src/main/java/com/moneymong/domain/ledger/repository/impl/LedgerDetailCustomImpl.java @@ -7,7 +7,10 @@ import com.moneymong.domain.ledger.entity.enums.FundType; import com.moneymong.domain.ledger.repository.LedgerDetailCustom; import com.querydsl.jpa.impl.JPAQueryFactory; + +import java.time.LocalTime; import java.time.ZonedDateTime; +import java.time.temporal.TemporalAdjusters; import java.util.List; import java.util.Optional; @@ -62,9 +65,12 @@ public List searchByPeriod( ZonedDateTime to, PageRequest pageable ) { + ZonedDateTime endOfMonth = to.with(TemporalAdjusters.lastDayOfMonth()) + .with(LocalTime.MAX); + return jpaQueryFactory.selectFrom(ledgerDetail) .where(ledgerDetail.ledger.eq(ledger)) - .where(ledgerDetail.paymentDate.between(from, to)) + .where(ledgerDetail.paymentDate.between(from, endOfMonth)) .orderBy(ledgerDetail.paymentDate.desc()) .offset((long) pageable.getPageNumber() * pageable.getPageSize()) .limit(pageable.getPageSize()) @@ -79,10 +85,13 @@ public List searchByPeriodAndFundType( FundType fundType, PageRequest pageable ) { + ZonedDateTime endOfMonth = to.with(TemporalAdjusters.lastDayOfMonth()) + .with(LocalTime.MAX); + return jpaQueryFactory.selectFrom(ledgerDetail) .where(ledgerDetail.ledger.eq(ledger)) .where(ledgerDetail.fundType.eq(fundType)) - .where(ledgerDetail.paymentDate.between(from, to)) + .where(ledgerDetail.paymentDate.between(from, endOfMonth)) .orderBy(ledgerDetail.paymentDate.desc()) .offset((long) pageable.getPageNumber() * pageable.getPageSize()) .limit(pageable.getPageSize()) diff --git a/src/main/java/com/moneymong/domain/ledger/service/manager/LedgerDetailService.java b/src/main/java/com/moneymong/domain/ledger/service/manager/LedgerDetailService.java index 2f0cf84..44ef8b4 100644 --- a/src/main/java/com/moneymong/domain/ledger/service/manager/LedgerDetailService.java +++ b/src/main/java/com/moneymong/domain/ledger/service/manager/LedgerDetailService.java @@ -13,6 +13,7 @@ import com.moneymong.domain.ledger.repository.LedgerDetailRepository; import com.moneymong.domain.ledger.repository.LedgerDocumentRepository; import com.moneymong.domain.ledger.repository.LedgerReceiptRepository; +import com.moneymong.domain.ledger.repository.LedgerRepository; import com.moneymong.domain.ledger.service.mapper.LedgerAssembler; import com.moneymong.domain.ledger.service.reader.LedgerDocumentReader; import com.moneymong.domain.ledger.service.reader.LedgerReceiptReader; @@ -22,8 +23,8 @@ import com.moneymong.global.exception.custom.NotFoundException; import com.moneymong.global.exception.enums.ErrorCode; import java.time.ZonedDateTime; +import java.util.Comparator; import java.util.List; -import java.util.Optional; import com.moneymong.utils.AmountCalculatorByFundType; import lombok.RequiredArgsConstructor; @@ -31,10 +32,13 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import static com.moneymong.domain.ledger.entity.enums.FundType.INCOME; + @Service @Slf4j @RequiredArgsConstructor public class LedgerDetailService { + private final LedgerRepository ledgerRepository; private final LedgerAssembler ledgerAssembler; private final LedgerReceiptReader ledgerReceiptReader; private final LedgerDocumentReader ledgerDocumentReader; @@ -69,51 +73,44 @@ public LedgerDetail createLedgerDetail( int newAmount = AmountCalculatorByFundType.calculate(fundType, amount); - /** - * 가장 오래된 장부 내역인 경우 잔고를 amount 값으로 설정한다. - * 이전 내역이 있는 경우, 가장 가까운 시일에 생성된 장부 내역을 기준으로 잔고를 저장한다. - */ - Optional mostRecentLedgerDetail = ledgerDetailRepository.findMostRecentLedgerDetail(ledger, paymentDate); - - if (mostRecentLedgerDetail.isPresent()) { - LedgerDetail recentDetail = mostRecentLedgerDetail.get(); - - int newBalance = recentDetail.getBalance() + newAmount; - ledgerDetail.updateBalance(newBalance); - }else { - ledgerDetail.updateBalance(newAmount); - } - ledger.updateTotalBalance(newAmount); - ledgerDetailRepository.bulkUpdateLedgerDetailBalance( - ledger, - paymentDate, - newAmount - ); + ledgerDetailRepository.save(ledgerDetail); - return ledgerDetailRepository.save(ledgerDetail); + updateBalance(ledger); + + return ledgerDetail; } @Transactional public LedgerDetailInfoView updateLedgerDetail( User user, - Ledger ledger, LedgerDetail ledgerDetail, UpdateLedgerRequest updateLedgerRequest ) { + long ledgerDetailId = ledgerDetail.getId(); -// LedgerDetail createdLedgerDetail = createLedgerDetail(ledger, -// user, -// updateLedgerRequest.getStoreInfo(), -// ledgerDetail.getFundType(), -// updateLedgerRequest.getAmount(), -// ledger.getTotalBalance(), -// updateLedgerRequest.getDescription(), -// updateLedgerRequest.getPaymentDate() -// ); + Ledger ledger = ledgerDetail.getLedger(); - long ledgerDetailId = ledgerDetail.getId(); + int newAmount = AmountCalculatorByFundType.calculate( + ledgerDetail.getFundType(), + ledgerDetail.getAmount() - updateLedgerRequest.getAmount() + ); + + ledger.updateTotalBalance(-newAmount); + + ledgerDetail.updateLedgerDetailInfo( + updateLedgerRequest.getStoreInfo(), + updateLedgerRequest.getAmount(), + updateLedgerRequest.getDescription(), + updateLedgerRequest.getPaymentDate() + ); + + AgencyUser agencyUser = getAgencyUser(user, ledgerDetail); + + validateStaffUserRole(agencyUser.getAgencyUserRole()); + + updateBalance(ledger); // 2. 장부 상세 내역 조회 List ledgerReceipts = ledgerReceiptReader.getLedgerReceipts(ledgerDetailId); @@ -151,13 +148,9 @@ public void removeLedgerDetail( int newAmount = AmountCalculatorByFundType.calculate(ledgerDetail.getFundType(), ledgerDetail.getAmount()); - ledgerDetailRepository.bulkUpdateLedgerDetailBalance( - ledger, - ledgerDetail.getPaymentDate(), - -newAmount - ); - ledger.updateTotalBalance(-newAmount); + + updateBalance(ledger); } private void validateStaffUserRole(AgencyUserRole userRole) { @@ -183,4 +176,24 @@ private User getUser(Long userId) { .findById(userId) .orElseThrow(() -> new NotFoundException(ErrorCode.USER_NOT_FOUND)); } + + private void updateBalance(Ledger ledger) { + List ledgerDetails = ledgerDetailRepository.findAllByLedger(ledger); + + ledgerDetails.sort(Comparator.comparing(LedgerDetail::getPaymentDate)); + + int previousBalance = 0; + + for (int i = 0; i < ledgerDetails.size(); i++) { + LedgerDetail detail = ledgerDetails.get(i); + + if (detail.getFundType() == INCOME) { + previousBalance += detail.getAmount(); + } else { + previousBalance -= detail.getAmount(); + } + + detail.updateBalance(previousBalance); + } + } } diff --git a/src/main/java/com/moneymong/domain/ledger/service/manager/LedgerService.java b/src/main/java/com/moneymong/domain/ledger/service/manager/LedgerService.java index 691a379..f31a77b 100644 --- a/src/main/java/com/moneymong/domain/ledger/service/manager/LedgerService.java +++ b/src/main/java/com/moneymong/domain/ledger/service/manager/LedgerService.java @@ -17,7 +17,6 @@ import com.moneymong.global.exception.custom.InvalidAccessException; import com.moneymong.global.exception.custom.NotFoundException; import com.moneymong.global.exception.enums.ErrorCode; -import com.moneymong.utils.AmountCalculatorByFundType; import java.util.List; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -53,14 +52,6 @@ public LedgerDetailInfoView createLedger( // === 권한 === validateStaffUserRole(agencyUser.getAgencyUserRole()); - // 장부 totalBalance 업데이트 - int newAmount = AmountCalculatorByFundType.calculate( - createLedgerRequest.getFundType(), - createLedgerRequest.getAmount() - ); - - ledger.updateTotalBalance(newAmount); - // 장부 내역 등록 LedgerDetail ledgerDetail = ledgerDetailService.createLedgerDetail( ledger, @@ -108,36 +99,12 @@ public LedgerDetailInfoView updateLedger( final Long ledgerDetailId, final UpdateLedgerRequest updateLedgerRequest ) { - // === 유저 === User user = getUser(userId); - // === 장부 === LedgerDetail ledgerDetail = getLedgerDetail(ledgerDetailId); - Ledger ledger = ledgerDetail.getLedger(); - - // === 소속 === - AgencyUser agencyUser = getAgencyUser(userId, ledger); - - // === 권한 === - validateStaffUserRole(agencyUser.getAgencyUserRole()); - - ledgerDetailService.createLedgerDetail( - ledger, - user, - updateLedgerRequest.getStoreInfo(), - ledgerDetail.getFundType(), - updateLedgerRequest.getAmount(), - ledger.getTotalBalance(), - updateLedgerRequest.getDescription(), - updateLedgerRequest.getPaymentDate() - ); - - ledgerDetailService.removeLedgerDetail(userId, ledgerDetailId); - return ledgerDetailService.updateLedgerDetail( user, - ledger, ledgerDetail, updateLedgerRequest );