@@ -9,8 +9,13 @@ export class IncomeDashboardService {
99
1010 const { start, end, normalizedMonth } = this . getMonthRange ( month ) ;
1111
12- const [ workLogs , userAlbas , user ] = await Promise . all ( [
12+ // 전월 month + range 계산
13+ const previousMonth = this . getPreviousMonth ( normalizedMonth ) ;
14+ const { start : prevStart , end : prevEnd } = this . getMonthRange ( previousMonth ) ;
15+
16+ const [ workLogs , prevWorkLogs , userAlbas , user ] = await Promise . all ( [
1317 incomeDashboardRepository . findWorkLogsForMonth ( userIdBin , start , end ) ,
18+ incomeDashboardRepository . findWorkLogsForMonth ( userIdBin , prevStart , prevEnd ) ,
1419 incomeDashboardRepository . findUserAlbaSettlementStatuses ( userIdBin ) ,
1520 incomeDashboardRepository . findUserIncomeGoal ( userIdBin ) ,
1621 ] ) ;
@@ -22,6 +27,31 @@ export class IncomeDashboardService {
2227 settlementMap . set ( Buffer . from ( ua . alba_id ) . toString ( 'hex' ) , ua . settlement_status ?? null ) ;
2328 }
2429
30+ const current = this . calculateMonthlyIncome ( workLogs , settlementMap ) ;
31+ const prev = this . calculateMonthlyIncome ( prevWorkLogs , settlementMap ) ;
32+
33+ // 전월 대비 증감률(%)
34+ // 전월 actualIncome이 0이면 0으로
35+ const incomeChangeRate =
36+ prev . actualIncome > 0
37+ ? ( ( current . actualIncome - prev . actualIncome ) / prev . actualIncome ) * 100
38+ : 0 ;
39+
40+ return {
41+ month : normalizedMonth ,
42+ incomeGoal,
43+ expectedIncome : current . expectedIncome ,
44+ actualIncome : current . actualIncome ,
45+ breakdown : current . breakdown ,
46+ incomeChangeRate,
47+ } ;
48+ }
49+
50+ // 월별 expected/actual/breakdown 계산 공통 함수
51+ private calculateMonthlyIncome (
52+ workLogs : any [ ] ,
53+ settlementMap : Map < string , user_alba_settlement_status | null > ,
54+ ) {
2555 let expectedIncome = 0 ;
2656 let actualIncome = 0 ;
2757
@@ -37,7 +67,6 @@ export class IncomeDashboardService {
3767 expectedIncome += income ;
3868
3969 const settlement = settlementMap . get ( Buffer . from ( log . alba_id ) . toString ( 'hex' ) ) ?? null ;
40-
4170 const isCompleted = settlement === user_alba_settlement_status . paid ;
4271 if ( ! isCompleted ) continue ;
4372
@@ -53,13 +82,15 @@ export class IncomeDashboardService {
5382 . map ( ( [ key , income ] ) => ( { key, income } ) )
5483 . sort ( ( a , b ) => b . income - a . income ) ;
5584
56- return {
57- month : normalizedMonth ,
58- incomeGoal,
59- expectedIncome,
60- actualIncome,
61- breakdown,
62- } ;
85+ return { expectedIncome, actualIncome, breakdown } ;
86+ }
87+
88+ private getPreviousMonth ( month : string ) : string {
89+ const [ year , mon ] = month . split ( '-' ) . map ( Number ) ;
90+ const date = new Date ( year , mon - 2 ) ; // 전월
91+ const y = date . getFullYear ( ) ;
92+ const m = String ( date . getMonth ( ) + 1 ) . padStart ( 2 , '0' ) ;
93+ return `${ y } -${ m } ` ;
6394 }
6495
6596 private getMonthRange ( month ?: string ) {
0 commit comments