@@ -860,16 +860,20 @@ export const TimeTrackingProvider: React.FC<{ children: React.ReactNode }> = ({
860860 filteredDays . forEach ( ( day ) => {
861861 day . tasks . forEach ( ( task ) => {
862862 if ( task . project && task . duration && task . category ) {
863- // Check if the category is billable
864- const category = categories . find ( ( c ) => c . name === task . category ) ;
865- const isBillable = category ?. isBillable !== false ; // Default to billable if not specified
866-
867- if ( isBillable ) {
868- const project = projects . find ( ( p ) => p . name === task . project ) ;
869- if ( project ?. hourlyRate ) {
870- const hours = task . duration / ( 1000 * 60 * 60 ) ;
871- totalRevenue += hours * project . hourlyRate ;
872- }
863+ // Check if both the project and category are billable
864+ const project = projects . find ( ( p ) => p . name === task . project ) ;
865+ // Fix: Look up category by ID, not name
866+ const category = categories . find ( ( c ) => c . id === task . category ) ;
867+
868+ const projectIsBillable = project ?. isBillable !== false ; // Default to billable if not specified
869+ const categoryIsBillable = category ?. isBillable !== false ; // Default to billable if not specified
870+
871+ // Task is billable only if BOTH project AND category are billable
872+ const isBillable = projectIsBillable && categoryIsBillable ;
873+
874+ if ( isBillable && project ?. hourlyRate ) {
875+ const hours = task . duration / ( 1000 * 60 * 60 ) ;
876+ totalRevenue += hours * project . hourlyRate ;
873877 }
874878 }
875879 } ) ;
@@ -894,11 +898,25 @@ export const TimeTrackingProvider: React.FC<{ children: React.ReactNode }> = ({
894898
895899 const getRevenueForDay = ( day : DayRecord ) : number => {
896900 let totalRevenue = 0 ;
901+ console . log ( '💰 Calculating revenue for day:' , day . date , 'with' , day . tasks . length , 'tasks' ) ;
902+
897903 day . tasks . forEach ( ( task ) => {
898904 if ( task . project && task . duration && task . category ) {
899905 // Check if both the project and category are billable
900906 const project = projects . find ( ( p ) => p . name === task . project ) ;
901- const category = categories . find ( ( c ) => c . name === task . category ) ;
907+ // Fix: Look up category by ID, not name
908+ const category = categories . find ( ( c ) => c . id === task . category ) ;
909+
910+ console . log ( '🔍 Revenue check for task:' , {
911+ title : task . title ,
912+ category : task . category ,
913+ project : task . project ,
914+ foundCategory : ! ! category ,
915+ categoryIsBillable : category ?. isBillable ,
916+ foundProject : ! ! project ,
917+ projectIsBillable : project ?. isBillable ,
918+ hourlyRate : project ?. hourlyRate
919+ } ) ;
902920
903921 const projectIsBillable = project ?. isBillable !== false ; // Default to billable if not specified
904922 const categoryIsBillable = category ?. isBillable !== false ; // Default to billable if not specified
@@ -908,28 +926,52 @@ export const TimeTrackingProvider: React.FC<{ children: React.ReactNode }> = ({
908926
909927 if ( isBillable && project ?. hourlyRate ) {
910928 const hours = task . duration / ( 1000 * 60 * 60 ) ;
911- totalRevenue += hours * project . hourlyRate ;
929+ const revenue = hours * project . hourlyRate ;
930+ totalRevenue += revenue ;
931+ console . log ( '💰 Adding revenue:' , revenue , 'for task:' , task . title ) ;
932+ } else {
933+ console . log ( '🚫 No revenue for task:' , task . title , 'because:' ,
934+ ! isBillable ? 'not billable' : 'no hourly rate' ) ;
912935 }
913936 }
914937 } ) ;
915938
939+ console . log ( '💰 Total revenue for day:' , totalRevenue ) ;
916940 return Math . round ( totalRevenue * 100 ) / 100 ;
917- } ;
918-
919- const getBillableHoursForDay = ( day : DayRecord ) : number => {
941+ } ; const getBillableHoursForDay = ( day : DayRecord ) : number => {
920942 let billableTime = 0 ;
921943 day . tasks . forEach ( ( task ) => {
922944 if ( task . duration && task . category && task . project ) {
923945 // Check if both the project and category are billable
924946 const project = projects . find ( ( p ) => p . name === task . project ) ;
925- const category = categories . find ( ( c ) => c . name === task . category ) ;
947+ // Fix: Look up category by ID, not name
948+ const category = categories . find ( ( c ) => c . id === task . category ) ;
949+
950+ // Debug logging
951+ console . log ( '🔍 Checking task billability:' , {
952+ taskTitle : task . title ,
953+ taskCategory : task . category ,
954+ projectName : task . project ,
955+ foundProject : ! ! project ,
956+ foundCategory : ! ! category ,
957+ projectIsBillable : project ?. isBillable ,
958+ categoryIsBillable : category ?. isBillable ,
959+ availableCategories : categories . map ( c => ( { name : c . name , id : c . id , isBillable : c . isBillable } ) )
960+ } ) ;
926961
927962 const projectIsBillable = project ?. isBillable !== false ; // Default to billable if not specified
928963 const categoryIsBillable = category ?. isBillable !== false ; // Default to billable if not specified
929964
930965 // Task is billable only if BOTH project AND category are billable
931966 const isBillable = projectIsBillable && categoryIsBillable ;
932967
968+ console . log ( '💰 Task billability result:' , {
969+ taskTitle : task . title ,
970+ projectIsBillable,
971+ categoryIsBillable,
972+ finalIsBillable : isBillable
973+ } ) ;
974+
933975 if ( isBillable ) {
934976 billableTime += task . duration ;
935977 }
@@ -945,7 +987,8 @@ export const TimeTrackingProvider: React.FC<{ children: React.ReactNode }> = ({
945987 if ( task . duration && task . category && task . project ) {
946988 // Check if both the project and category are billable
947989 const project = projects . find ( ( p ) => p . name === task . project ) ;
948- const category = categories . find ( ( c ) => c . name === task . category ) ;
990+ // Fix: Look up category by ID, not name
991+ const category = categories . find ( ( c ) => c . id === task . category ) ;
949992
950993 const projectIsBillable = project ?. isBillable !== false ; // Default to billable if not specified
951994 const categoryIsBillable = category ?. isBillable !== false ; // Default to billable if not specified
@@ -999,7 +1042,8 @@ export const TimeTrackingProvider: React.FC<{ children: React.ReactNode }> = ({
9991042 day . tasks . forEach ( ( task ) => {
10001043 if ( task . duration ) {
10011044 const project = projects . find ( ( p ) => p . name === task . project ) ;
1002- const category = categories . find ( ( c ) => c . name === task . category ) ;
1045+ // Fix: Look up category by ID, not name
1046+ const category = categories . find ( ( c ) => c . id === task . category ) ;
10031047
10041048 // Format timestamps as ISO strings for database compatibility
10051049 const startTimeISO = task . startTime . toISOString ( ) ;
@@ -1077,7 +1121,26 @@ export const TimeTrackingProvider: React.FC<{ children: React.ReactNode }> = ({
10771121 } ) ;
10781122
10791123 const clientTasks = filteredDays . flatMap ( ( day ) =>
1080- day . tasks . filter ( ( task ) => task . client === clientName && task . duration )
1124+ day . tasks . filter ( ( task ) => {
1125+ if ( ! task . client || task . client !== clientName || ! task . duration ) {
1126+ return false ;
1127+ }
1128+
1129+ // Only include billable tasks in invoices
1130+ if ( task . project && task . category ) {
1131+ const project = projects . find ( ( p ) => p . name === task . project ) ;
1132+ // Fix: Look up category by ID, not name
1133+ const category = categories . find ( ( c ) => c . id === task . category ) ;
1134+
1135+ const projectIsBillable = project ?. isBillable !== false ;
1136+ const categoryIsBillable = category ?. isBillable !== false ;
1137+
1138+ // Task must be billable to appear on invoice
1139+ return projectIsBillable && categoryIsBillable ;
1140+ }
1141+
1142+ return false ;
1143+ } )
10811144 ) ;
10821145
10831146 const projectSummary : {
0 commit comments