Trai60

UpdateSummary-UK Version

Nov 24th, 2024 (edited)
34
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 60.91 KB | None | 0 0
  1. Option Explicit
  2.  
  3. Public Sub UpdateSummary()
  4. ' This macro creates the Summary sheet and pivot tables
  5. ' Run this SECOND after ProcessProlificData
  6.  
  7. Dim wsData As Worksheet
  8. Dim wsSummary As Worksheet
  9.  
  10. ' Prevent screen updating during calculations
  11. Application.ScreenUpdating = False
  12.  
  13. Application.DisplayAlerts = False
  14.  
  15. ' Check if Processed_Data exists
  16. On Error Resume Next
  17. Set wsData = ThisWorkbook.Sheets("Processed_Data")
  18. If wsData Is Nothing Then
  19. MsgBox "Processed_Data sheet not found! Run ProcessProlificData first.", vbExclamation
  20. Exit Sub
  21. End If
  22. On Error GoTo 0
  23.  
  24. ' Delete existing Summary sheet if it exists
  25. On Error Resume Next
  26. ThisWorkbook.Sheets("Summary").Delete
  27. On Error GoTo 0
  28.  
  29. ' Create new Summary sheet
  30. Set wsSummary = ThisWorkbook.Sheets.Add(After:=wsData)
  31. wsSummary.Name = "Summary"
  32.  
  33. ' Create summary sheet and pivot tables
  34. CreateSummarySheet
  35.  
  36. ' Create hourly rate data and chart
  37. TestHourlyRateCalculation
  38. CreateYearlyRateAnalysis
  39. CreateHourlyRateChartOnSummary
  40.  
  41. ' Add these lines at the end, just before End Sub
  42. Application.DisplayAlerts = True
  43. Application.ScreenUpdating = True
  44. wsSummary.Activate ' This will make the Summary sheet active
  45. ThisWorkbook.Sheets("TempData").Visible = False ' This will hide the TempData sheet
  46. End Sub
  47.  
  48. Private Sub CreateSummarySheet()
  49. Dim wsData As Worksheet
  50. Dim wsSummary As Worksheet
  51. Dim lastRow As Long
  52.  
  53. ' Reference the processed data sheet
  54. Set wsData = ThisWorkbook.Sheets("Processed_Data")
  55. Set wsSummary = ThisWorkbook.Sheets("Summary")
  56.  
  57. lastRow = wsData.Cells(wsData.Rows.count, "A").End(xlUp).row
  58.  
  59. ' Clear existing content
  60. wsSummary.Cells.Clear
  61.  
  62. ' Add headers and labels
  63. With wsSummary
  64. .Cells(1, 1).Value = "Prolific Summary"
  65. .Cells(3, 1).Value = "Study Status Breakdown"
  66. .Cells(4, 1).Value = "Approved Studies"
  67. .Cells(5, 1).Value = "Returned Studies"
  68. .Cells(6, 1).Value = "Awaiting Review Studies"
  69. .Cells(7, 1).Value = "Rejected Studies"
  70. .Cells(8, 1).Value = "Approval Rating"
  71.  
  72. .Cells(10, 1).Value = "Financial Summary"
  73. .Cells(11, 1).Value = "Total Reward (£)"
  74. .Cells(12, 1).Value = "Total Bonus (£)"
  75. .Cells(13, 1).Value = "Total Reward ($)"
  76. .Cells(14, 1).Value = "Total Bonus ($)"
  77. .Cells(15, 1).Value = "Total Returned Bonus (£)"
  78. .Cells(16, 1).Value = "Total Returned Bonus ($)"
  79.  
  80. .Cells(18, 1).Value = "Exchange Rate (USD to GBP) "
  81. .Cells(19, 1).Value = "Total USD Converted to GBP"
  82. .Cells(20, 1).Value = "Total Combined GBP"
  83.  
  84. .Cells(22, 1).Value = "Time and Rate Analysis"
  85. .Cells(23, 1).Value = "Total Hours"
  86. .Cells(24, 1).Value = "Hourly Rate (£)"
  87.  
  88. ' Add exchange rate input cell with default value
  89. .Cells(18, 2).Value = 0.760967 ' Average exchange rate 2015 - 2024
  90. End With
  91.  
  92. ' Calculate status counts
  93. With wsData.Range("J2:J" & lastRow) ' Status column
  94. wsSummary.Cells(4, 2).Value = Application.CountIf(.Cells, "APPROVED")
  95. wsSummary.Cells(5, 2).Value = Application.CountIf(.Cells, "RETURNED")
  96. wsSummary.Cells(6, 2).Value = Application.CountIf(.Cells, "AWAITING REVIEW")
  97. wsSummary.Cells(7, 2).Value = Application.CountIf(.Cells, "REJECTED")
  98. End With
  99.  
  100. ' Calculate approval rating
  101. Dim approvedCount As Long, rejectedCount As Long
  102. approvedCount = wsSummary.Cells(4, 2).Value
  103. rejectedCount = wsSummary.Cells(7, 2).Value
  104. If (approvedCount + rejectedCount) > 0 Then
  105. wsSummary.Cells(8, 2).Value = approvedCount / (approvedCount + rejectedCount)
  106. wsSummary.Cells(8, 2).NumberFormat = "0.00%"
  107. End If
  108.  
  109. ' Calculate financial totals
  110. With Application.WorksheetFunction
  111. ' Approved studies totals
  112. wsSummary.Cells(11, 2).Value = .SumIfs(wsData.Range("B2:B" & lastRow), _
  113. wsData.Range("J2:J" & lastRow), "APPROVED") ' Reward GBP
  114. wsSummary.Cells(12, 2).Value = .SumIfs(wsData.Range("C2:C" & lastRow), _
  115. wsData.Range("J2:J" & lastRow), "APPROVED") ' Bonus GBP
  116. wsSummary.Cells(13, 2).Value = .SumIfs(wsData.Range("D2:D" & lastRow), _
  117. wsData.Range("J2:J" & lastRow), "APPROVED") ' Reward USD
  118. wsSummary.Cells(14, 2).Value = .SumIfs(wsData.Range("E2:E" & lastRow), _
  119. wsData.Range("J2:J" & lastRow), "APPROVED") ' Bonus USD
  120.  
  121. ' Returned bonus totals
  122. wsSummary.Cells(15, 2).Value = .SumIfs(wsData.Range("C2:C" & lastRow), _
  123. wsData.Range("J2:J" & lastRow), "RETURNED") ' Returned Bonus GBP
  124. wsSummary.Cells(16, 2).Value = .SumIfs(wsData.Range("E2:E" & lastRow), _
  125. wsData.Range("J2:J" & lastRow), "RETURNED") ' Returned Bonus USD
  126. End With
  127.  
  128. ' Calculate USD to GBP conversion
  129. Dim totalUSD As Double
  130. totalUSD = wsSummary.Cells(13, 2).Value + wsSummary.Cells(14, 2).Value + wsSummary.Cells(16, 2).Value
  131. wsSummary.Cells(19, 2).Formula = "=(" & wsSummary.Cells(13, 2).Address & "+" & _
  132. wsSummary.Cells(14, 2).Address & "+" & _
  133. wsSummary.Cells(16, 2).Address & ")*" & _
  134. wsSummary.Cells(18, 2).Address
  135.  
  136. ' Calculate total combined GBP
  137. wsSummary.Cells(20, 2).Value = wsSummary.Cells(11, 2).Value + wsSummary.Cells(12, 2).Value + _
  138. wsSummary.Cells(15, 2).Value + wsSummary.Cells(19, 2).Value
  139.  
  140. ' Calculate total duration for approved and valid returned studies
  141. Dim totalSeconds As Double
  142. totalSeconds = 0
  143.  
  144. Dim i As Long
  145. For i = 2 To lastRow
  146. If (wsData.Cells(i, "J").Value = "APPROVED" Or wsData.Cells(i, "J").Value = "RETURNED") And _
  147. Not IsEmpty(wsData.Cells(i, "F").Value) And Not IsEmpty(wsData.Cells(i, "G").Value) Then
  148. ' Convert duration to seconds
  149. totalSeconds = totalSeconds + (wsData.Cells(i, "H").Value * 86400) ' 86400 seconds in a day
  150. End If
  151. Next i
  152.  
  153. ' Convert total seconds to duration format
  154. wsSummary.Cells(23, 2).Value = totalSeconds / 86400 ' Convert back to Excel time format
  155.  
  156. ' Calculate hourly rate
  157. If totalSeconds > 0 Then
  158. wsSummary.Cells(24, 2).Value = wsSummary.Cells(20, 2).Value / (totalSeconds / 3600) ' Convert seconds to hours
  159. End If
  160.  
  161. ' Format numbers
  162. With wsSummary
  163. .Range("B11:B12,B15,B19:B20").NumberFormat = "£#,##0.00"
  164. .Range("B13:B14,B16").NumberFormat = "[$$-en-US]#,##0.00"
  165. .Range("B23").NumberFormat = "[h]:mm:ss"
  166. .Range("B24").NumberFormat = "£#,##0.00"
  167. .Range("B18").NumberFormat = "0.000000"
  168. End With
  169.  
  170. ' Add styling to the summary sheet
  171. With wsSummary
  172. ' Set dark background and remove gridlines
  173. .Cells.Interior.Color = RGB(32, 32, 32)
  174. ActiveWindow.DisplayGridlines = False
  175. .Cells.Font.Color = RGB(255, 255, 255)
  176.  
  177. ' AutoFit columns
  178. .Columns("A").ColumnWidth = 30
  179. .Columns("B").AutoFit
  180.  
  181. ' Main title formatting
  182. With .Range("A1:B1")
  183. .Merge
  184. .Font.Size = 14
  185. .Font.Bold = True
  186. .HorizontalAlignment = xlCenter
  187. .Interior.Color = RGB(64, 64, 64)
  188. End With
  189.  
  190. ' Section headers formatting
  191. With .Range("A3,A10,A22")
  192. .Font.Bold = True
  193. .Font.Size = 12
  194. .Interior.Color = RGB(64, 64, 64)
  195. End With
  196.  
  197. ' Add borders to the data ranges
  198. With .Range("A4:B8,A11:B16,A18:B20,A23:B24")
  199. .Borders(xlEdgeLeft).LineStyle = xlContinuous
  200. .Borders(xlEdgeLeft).Color = RGB(128, 128, 128)
  201. .Borders(xlEdgeRight).LineStyle = xlContinuous
  202. .Borders(xlEdgeRight).Color = RGB(128, 128, 128)
  203. .Borders(xlEdgeTop).LineStyle = xlContinuous
  204. .Borders(xlEdgeTop).Color = RGB(128, 128, 128)
  205. .Borders(xlEdgeBottom).LineStyle = xlContinuous
  206. .Borders(xlEdgeBottom).Color = RGB(128, 128, 128)
  207. .Borders(xlInsideHorizontal).LineStyle = xlContinuous
  208. .Borders(xlInsideHorizontal).Color = RGB(128, 128, 128)
  209. End With
  210.  
  211. ' Alternate row coloring for better readability
  212. With .Range("A4:B8")
  213. .Interior.Color = RGB(45, 45, 45)
  214. End With
  215. With .Range("A11:B16")
  216. .Interior.Color = RGB(45, 45, 45)
  217. End With
  218. With .Range("A23:B24")
  219. .Interior.Color = RGB(45, 45, 45)
  220. End With
  221.  
  222. ' Exchange rate cell special formatting
  223. With .Range("B18")
  224. .Interior.Color = RGB(0, 100, 0) ' Darker green
  225. .Borders.LineStyle = xlContinuous
  226. .Borders.Color = RGB(128, 128, 128)
  227. End With
  228.  
  229. ' Indent labels slightly
  230. .Range("A4:A8,A11:A16,A18:A20,A23:A24").IndentLevel = 1
  231.  
  232. ' Bold totals and important figures
  233. .Range("B8,B20,B24").Font.Bold = True
  234.  
  235. ' Add a thin border around the entire summary
  236. With .Range(.Cells(1, 1), .Cells(24, 2))
  237. .BorderAround Weight:=xlThin, Color:=RGB(128, 128, 128)
  238. End With
  239.  
  240. ' Select A1 and zoom to 100%
  241. .Range("A1").Select
  242. ActiveWindow.Zoom = 100
  243. End With
  244.  
  245. ' Add tax year summary
  246. CreateTaxYearSummary wsData, wsSummary
  247.  
  248. ' Create trend line chart
  249. Dim chtTrends As Chart
  250. Dim tempWs As Worksheet
  251.  
  252. ' Create temporary worksheet for data
  253. On Error Resume Next
  254. ThisWorkbook.Sheets("TempData").Delete
  255. Set tempWs = ThisWorkbook.Sheets.Add
  256. tempWs.Name = "TempData"
  257. On Error GoTo 0
  258.  
  259. ' Create data table for Approved studies by year and month
  260. With tempWs
  261. ' Headers
  262. .Cells(1, 1).Value = "Year"
  263. .Cells(1, 2).Value = "Month"
  264. .Cells(1, 3).Value = "Number of Approved Studies"
  265. .Cells(1, 4).Value = "X-Axis Label"
  266. .Cells(1, 5).Value = "MonthNum"
  267. .Cells(1, 6).Value = "Number of Returned Studies"
  268. .Cells(1, 7).Value = "Number of Rejected Studies"
  269.  
  270. Dim chartRow As Long
  271. chartRow = 2
  272.  
  273. Dim yearMonth As Object
  274. Set yearMonth = CreateObject("Scripting.Dictionary")
  275.  
  276. Dim rowNum As Long
  277. For rowNum = 2 To lastRow
  278. Dim monthNum As Long
  279. monthNum = wsData.Cells(rowNum, "M").Value
  280.  
  281. ' Convert month number to name
  282. Dim monthName As String
  283. Select Case monthNum
  284. Case 1: monthName = "Jan"
  285. Case 2: monthName = "Feb"
  286. Case 3: monthName = "Mar"
  287. Case 4: monthName = "Apr"
  288. Case 5: monthName = "May"
  289. Case 6: monthName = "Jun"
  290. Case 7: monthName = "Jul"
  291. Case 8: monthName = "Aug"
  292. Case 9: monthName = "Sep"
  293. Case 10: monthName = "Oct"
  294. Case 11: monthName = "Nov"
  295. Case 12: monthName = "Dec"
  296. End Select
  297.  
  298. Dim key As String
  299. key = wsData.Cells(rowNum, "L").Value & "-" & Format(monthNum, "00")
  300.  
  301. If Not yearMonth.Exists(key) Then
  302. yearMonth.Add key, 1
  303.  
  304. ' Write data immediately
  305. .Cells(chartRow, 1).Value = wsData.Cells(rowNum, "L").Value ' Year
  306. .Cells(chartRow, 2).Value = monthName ' Month name
  307. .Cells(chartRow, 3).Value = 0 ' Approved count
  308. .Cells(chartRow, 6).Value = 0 ' Returned count
  309. .Cells(chartRow, 7).Value = 0 ' Rejected count
  310.  
  311. ' Increment appropriate counter
  312. Select Case wsData.Cells(rowNum, "J").Value
  313. Case "APPROVED": .Cells(chartRow, 3).Value = 1
  314. Case "RETURNED": .Cells(chartRow, 6).Value = 1
  315. Case "REJECTED": .Cells(chartRow, 7).Value = 1
  316. End Select
  317.  
  318. chartRow = chartRow + 1
  319. Else
  320. ' Find the row with matching year and month and update count
  321. Dim findRow As Long
  322. For findRow = 2 To chartRow - 1
  323. If .Cells(findRow, 1).Value = wsData.Cells(rowNum, "L").Value And _
  324. .Cells(findRow, 2).Value = monthName Then
  325. ' Increment appropriate counter
  326. Select Case wsData.Cells(rowNum, "J").Value
  327. Case "APPROVED": .Cells(findRow, 3).Value = .Cells(findRow, 3).Value + 1
  328. Case "RETURNED": .Cells(findRow, 6).Value = .Cells(findRow, 6).Value + 1
  329. Case "REJECTED": .Cells(findRow, 7).Value = .Cells(findRow, 7).Value + 1
  330. End Select
  331. Exit For
  332. End If
  333. Next findRow
  334. End If
  335. Next rowNum
  336.  
  337. ' Add helper column for month numbers
  338. .Cells(1, 5).Value = "MonthNum"
  339.  
  340. ' Fill in month numbers
  341. For i = 2 To chartRow - 1
  342. Select Case .Cells(i, 2).Value
  343. Case "Jan": .Cells(i, 5).Value = 1
  344. Case "Feb": .Cells(i, 5).Value = 2
  345. Case "Mar": .Cells(i, 5).Value = 3
  346. Case "Apr": .Cells(i, 5).Value = 4
  347. Case "May": .Cells(i, 5).Value = 5
  348. Case "Jun": .Cells(i, 5).Value = 6
  349. Case "Jul": .Cells(i, 5).Value = 7
  350. Case "Aug": .Cells(i, 5).Value = 8
  351. Case "Sep": .Cells(i, 5).Value = 9
  352. Case "Oct": .Cells(i, 5).Value = 10
  353. Case "Nov": .Cells(i, 5).Value = 11
  354. Case "Dec": .Cells(i, 5).Value = 12
  355. End Select
  356. Next i
  357.  
  358. ' Sort the data by year and month number
  359. .Range("A2:G" & chartRow - 1).Sort _
  360. Key1:=.Range("A2"), Order1:=xlAscending, _
  361. Key2:=.Range("E2"), Order2:=xlAscending, _
  362. Header:=xlNo
  363.  
  364. ' Create formatted X-axis labels
  365. Dim prevYear As String
  366. Dim currYear As String
  367.  
  368. For i = 2 To chartRow - 1
  369. currYear = .Cells(i, 1).Value
  370.  
  371. If currYear <> prevYear Then
  372. ' If it's a new year, include the year
  373. .Cells(i, 4).Value = currYear & " - " & .Cells(i, 2).Value
  374. Else
  375. ' If it's the same year, just show month
  376. .Cells(i, 4).Value = .Cells(i, 2).Value
  377. End If
  378.  
  379. prevYear = currYear
  380. Next i
  381. End With
  382.  
  383. ' Create the chart
  384. Set chtTrends = wsSummary.Shapes.AddChart2(227, xlLine).Chart
  385.  
  386. ' First, modify the data in tempWs to replace zeros with empty cells
  387. For i = 2 To chartRow - 1
  388. If tempWs.Cells(i, 6).Value = 0 Then tempWs.Cells(i, 6).ClearContents
  389. If tempWs.Cells(i, 7).Value = 0 Then tempWs.Cells(i, 7).ClearContents
  390. Next i
  391.  
  392. With chtTrends
  393. ' Clear any existing series
  394. Do While .SeriesCollection.count > 0
  395. .SeriesCollection(1).Delete
  396. Loop
  397.  
  398. ' Format chart area
  399. .ChartArea.Format.Fill.ForeColor.RGB = RGB(32, 32, 32)
  400. .PlotArea.Format.Fill.ForeColor.RGB = RGB(32, 32, 32)
  401.  
  402. ' Add Approved Studies series
  403. With .SeriesCollection.NewSeries
  404. .XValues = tempWs.Range("D2:D" & chartRow - 1)
  405. .values = tempWs.Range("C2:C" & chartRow - 1)
  406. .Format.Line.ForeColor.RGB = RGB(0, 255, 0) ' Green
  407. .Format.Line.Weight = 1.5
  408. .MarkerStyle = xlMarkerStyleCircle
  409. .MarkerSize = 4
  410. .Name = "Approved Studies"
  411.  
  412. .HasDataLabels = True
  413. With .DataLabels
  414. .ShowSeriesName = False
  415. .ShowValue = True
  416. .Position = xlLabelPositionAbove
  417. .Format.TextFrame2.TextRange.Font.Fill.ForeColor.RGB = RGB(255, 255, 255)
  418. End With
  419. End With
  420.  
  421. ' Add Returned Studies series
  422. With .SeriesCollection.NewSeries
  423. .XValues = tempWs.Range("D2:D" & chartRow - 1)
  424. .values = tempWs.Range("F2:F" & chartRow - 1)
  425. .Format.Line.ForeColor.RGB = RGB(255, 165, 0) ' Orange
  426. .Format.Line.Weight = 1.5
  427. .MarkerStyle = xlMarkerStyleCircle
  428. .MarkerSize = 4
  429. .Name = "Returned Studies"
  430.  
  431. .HasDataLabels = True
  432. With .DataLabels
  433. .ShowSeriesName = False
  434. .ShowValue = True
  435. .Position = xlLabelPositionAbove
  436. .Format.TextFrame2.TextRange.Font.Fill.ForeColor.RGB = RGB(255, 255, 255)
  437. End With
  438. End With
  439.  
  440. ' Add Rejected Studies series
  441. With .SeriesCollection.NewSeries
  442. .XValues = tempWs.Range("D2:D" & chartRow - 1)
  443. .values = tempWs.Range("G2:G" & chartRow - 1)
  444. .Format.Line.ForeColor.RGB = RGB(255, 0, 0) ' Red
  445. .Format.Line.Weight = 1.5
  446. .MarkerStyle = xlMarkerStyleCircle
  447. .MarkerSize = 3
  448. .Name = "Rejected Studies"
  449.  
  450. .HasDataLabels = True
  451. With .DataLabels
  452. .ShowSeriesName = False
  453. .ShowValue = True
  454. .Position = xlLabelPositionAbove
  455. .Format.TextFrame2.TextRange.Font.Fill.ForeColor.RGB = RGB(255, 255, 255)
  456. End With
  457. End With
  458.  
  459. ' Add legend
  460. .HasLegend = True
  461. With .Legend
  462. .Position = xlBottom
  463. .Format.TextFrame2.TextRange.Font.Fill.ForeColor.RGB = RGB(255, 255, 255)
  464. End With
  465.  
  466. ' Format Y axis
  467. With .Axes(xlValue)
  468. .HasTitle = True
  469. With .AxisTitle
  470. .Text = "Number of Studies"
  471. .Orientation = 90
  472. .Format.TextFrame2.TextRange.Font.Fill.ForeColor.RGB = RGB(255, 255, 255)
  473. End With
  474. .TickLabels.Font.Color = RGB(255, 255, 255)
  475. .Format.Line.ForeColor.RGB = RGB(255, 255, 255)
  476. .MajorGridlines.Format.Line.ForeColor.RGB = RGB(64, 64, 64)
  477. .MinimumScale = 0
  478. End With
  479.  
  480. ' Format X axis
  481. With .Axes(xlCategory)
  482. .TickLabels.Font.Color = RGB(255, 255, 255)
  483. .Format.Line.ForeColor.RGB = RGB(255, 255, 255)
  484. .TickLabelSpacing = 1
  485. .TickLabels.Orientation = 90
  486. End With
  487.  
  488. ' Add title
  489. .HasTitle = True
  490. With .ChartTitle
  491. .Text = "Number of Studies a Month"
  492. .Format.TextFrame2.TextRange.Font.Fill.ForeColor.RGB = RGB(255, 255, 255)
  493. End With
  494.  
  495. ' Position the chart
  496. With .Parent
  497. .Left = wsSummary.Range("D2").Left
  498. .Top = wsSummary.Range("D2").Top
  499. .Width = 800
  500. .Height = 400
  501. End With
  502. End With
  503.  
  504. ' Create pivot tables on a new sheet
  505. Application.DisplayAlerts = False
  506.  
  507. ' Create new Pivot sheet
  508. Dim wsPivot As Worksheet
  509. On Error Resume Next
  510. ThisWorkbook.Sheets("Pivot_Analysis").Delete
  511. Set wsPivot = ThisWorkbook.Sheets.Add(After:=wsSummary)
  512. wsPivot.Name = "Pivot_Analysis"
  513. wsPivot.Parent.Windows(1).DisplayGridlines = False
  514. On Error GoTo 0
  515.  
  516. ' Create pivot tables on the new sheet
  517. CreateApprovedPivotTable wsData, wsPivot
  518. CreateReturnedPivotTable wsData, wsPivot
  519. Application.DisplayAlerts = True
  520.  
  521. ' Create bar chart after pivot tables exist
  522. CreateBarChart tempWs, wsSummary, chartRow
  523. End Sub
  524.  
  525. Private Sub CreateTaxYearSummary(wsData As Worksheet, wsSummary As Worksheet)
  526. ' Add header at A27
  527. With wsSummary
  528. .Cells(27, 1).Value = "Tax Year 6th Apr - 5th Apr Breakdown"
  529. .Range("A27:B27").Merge
  530. .Range("A27").Font.Size = 12
  531. .Range("A27").Font.Bold = True
  532. .Range("A27").Interior.Color = RGB(64, 64, 64)
  533. .Range("A27").HorizontalAlignment = xlCenter
  534. End With
  535.  
  536. ' Get last row of data
  537. Dim lastRow As Long
  538. lastRow = wsData.Cells(wsData.Rows.count, "A").End(xlUp).row
  539.  
  540. ' Create dictionary to store tax year totals
  541. Dim taxYearDict As Object
  542. Set taxYearDict = CreateObject("Scripting.Dictionary")
  543.  
  544. ' Exchange rate from cell B18 on summary sheet
  545. Dim exchangeRate As Double
  546. exchangeRate = wsSummary.Range("B18").Value
  547.  
  548. ' Loop through data
  549. Dim i As Long
  550. For i = 2 To lastRow
  551. If (wsData.Cells(i, "J").Value = "APPROVED" Or _
  552. (wsData.Cells(i, "J").Value = "RETURNED" And _
  553. Not IsEmpty(wsData.Cells(i, "F").Value) And _
  554. Not IsEmpty(wsData.Cells(i, "G").Value))) Then
  555.  
  556. ' Get date from columns L (Year) and M (Month)
  557. Dim studyDate As Date
  558. studyDate = DateSerial(wsData.Cells(i, "L").Value, wsData.Cells(i, "M").Value, 1)
  559.  
  560. ' Determine tax year (April 6th to April 5th)
  561. Dim taxYear As String
  562. If Month(studyDate) <= 3 Then
  563. taxYear = CStr(year(studyDate) - 1) & "/" & CStr(year(studyDate))
  564. ElseIf Month(studyDate) >= 4 Then
  565. taxYear = CStr(year(studyDate)) & "/" & CStr(year(studyDate) + 1)
  566. End If
  567.  
  568. ' Calculate total for this entry
  569. Dim entryTotal As Double
  570. If wsData.Cells(i, "J").Value = "APPROVED" Then
  571. entryTotal = wsData.Cells(i, "B").Value + _
  572. wsData.Cells(i, "C").Value + _
  573. (wsData.Cells(i, "D").Value * exchangeRate) + _
  574. (wsData.Cells(i, "E").Value * exchangeRate)
  575. Else ' RETURNED
  576. entryTotal = wsData.Cells(i, "C").Value + _
  577. (wsData.Cells(i, "E").Value * exchangeRate)
  578. End If
  579.  
  580. ' Add to dictionary
  581. If taxYearDict.Exists(taxYear) Then
  582. taxYearDict(taxYear) = taxYearDict(taxYear) + entryTotal
  583. Else
  584. taxYearDict.Add taxYear, entryTotal
  585. End If
  586. End If
  587. Next i
  588.  
  589. ' Output results
  590. Dim row As Long
  591. row = 28
  592. Dim key As Variant
  593.  
  594. ' Sort keys
  595. Dim keys() As String
  596. ReDim keys(0 To taxYearDict.count - 1)
  597. Dim k As Long
  598. k = 0
  599. For Each key In taxYearDict.keys
  600. keys(k) = key
  601. k = k + 1
  602. Next key
  603.  
  604. ' Simple bubble sort for tax years
  605. Dim j As Long
  606. For i = LBound(keys) To UBound(keys) - 1
  607. For j = i + 1 To UBound(keys)
  608. If keys(i) > keys(j) Then
  609. Dim temp As String
  610. temp = keys(i)
  611. keys(i) = keys(j)
  612. keys(j) = temp
  613. End If
  614. Next j
  615. Next i
  616.  
  617. ' Output sorted results with formatting
  618. For i = 0 To UBound(keys)
  619. With wsSummary
  620. .Cells(row + i, 1).Value = "Tax Year " & keys(i)
  621. .Cells(row + i, 2).Value = taxYearDict(keys(i))
  622. .Cells(row + i, 2).NumberFormat = "£#,##0.00"
  623.  
  624. ' Apply formatting
  625. .Range("A" & row + i & ":B" & row + i).Interior.Color = RGB(45, 45, 45)
  626. .Cells(row + i, 1).IndentLevel = 1
  627.  
  628. ' Add borders
  629. With .Range("A" & row + i & ":B" & row + i)
  630. .Borders(xlEdgeLeft).LineStyle = xlContinuous
  631. .Borders(xlEdgeLeft).Color = RGB(128, 128, 128)
  632. .Borders(xlEdgeRight).LineStyle = xlContinuous
  633. .Borders(xlEdgeRight).Color = RGB(128, 128, 128)
  634. .Borders(xlEdgeTop).LineStyle = xlContinuous
  635. .Borders(xlEdgeTop).Color = RGB(128, 128, 128)
  636. .Borders(xlEdgeBottom).LineStyle = xlContinuous
  637. .Borders(xlEdgeBottom).Color = RGB(128, 128, 128)
  638. End With
  639. End With
  640. Next i
  641.  
  642. ' Add border around entire section
  643. With wsSummary.Range("A27:B" & row + UBound(keys))
  644. .BorderAround Weight:=xlThin, Color:=RGB(128, 128, 128)
  645. End With
  646. End Sub
  647.  
  648. Public Sub CreateApprovedPivotTable(wsData As Worksheet, wsPivot As Worksheet)
  649. Dim pvtCache As PivotCache
  650. Dim pvt As PivotTable
  651. Dim lastRow As Long
  652.  
  653. ' Delete existing pivot table if it exists
  654. On Error Resume Next
  655. wsPivot.PivotTables("ApprovedPivotTable").TableRange2.Clear
  656. wsPivot.PivotTables("ApprovedPivotTable").Delete
  657. On Error GoTo 0
  658.  
  659. ' Create pivot cache from data
  660. lastRow = wsData.Cells(wsData.Rows.count, "A").End(xlUp).row
  661. Set pvtCache = ThisWorkbook.PivotCaches.Create( _
  662. SourceType:=xlDatabase, _
  663. SourceData:=wsData.Range("A1:M" & lastRow), _
  664. Version:=xlPivotTableVersion15)
  665.  
  666. ' Create Approved Studies pivot table starting at A4
  667. Set pvt = pvtCache.CreatePivotTable( _
  668. TableDestination:=wsPivot.Range("A4"), _
  669. TableName:="ApprovedPivotTable", _
  670. DefaultVersion:=xlPivotTableVersion15)
  671.  
  672. ' Change Row Labels caption to Year
  673. On Error Resume Next
  674. pvt.RowAxisLayout xlTabularRow
  675. pvt.PivotFields("Row Labels").Name = "Year"
  676. On Error GoTo 0
  677.  
  678. ' Add title above pivot table after creation
  679. With wsPivot.Range("A3")
  680. .Value = "Approved Studies Breakdown Analysis"
  681. .Font.Bold = True
  682. .Font.Size = 12
  683. End With
  684.  
  685. ' Configure pivot table
  686. With pvt
  687. ' Add Year field to rows
  688. .PivotFields("Year").Orientation = xlRowField
  689. .PivotFields("Year").Position = 1
  690.  
  691. ' Add Month field to rows and format
  692. With .PivotFields("Month")
  693. .Orientation = xlRowField
  694. .Position = 2
  695.  
  696. ' Create month names array
  697. Dim monthNames(1 To 12) As String
  698. monthNames(1) = "January"
  699. monthNames(2) = "February"
  700. monthNames(3) = "March"
  701. monthNames(4) = "April"
  702. monthNames(5) = "May"
  703. monthNames(6) = "June"
  704. monthNames(7) = "July"
  705. monthNames(8) = "August"
  706. monthNames(9) = "September"
  707. monthNames(10) = "October"
  708. monthNames(11) = "November"
  709. monthNames(12) = "December"
  710.  
  711. ' Apply month names to pivot items
  712. Dim i As Long
  713. For i = 1 To 12
  714. On Error Resume Next
  715. .PivotItems(CStr(i)).Caption = monthNames(i)
  716. On Error GoTo 0
  717. Next i
  718.  
  719. ' Group by quarters
  720. On Error Resume Next
  721. .Group Start:=1, End:=12, By:=3
  722. On Error GoTo 0
  723. End With
  724.  
  725. ' Add value fields
  726. With .AddDataField(.PivotFields("Reward (£)"), "Total Reward (£)", xlSum)
  727. .NumberFormat = "£#,##0.00"
  728. End With
  729.  
  730. With .AddDataField(.PivotFields("Reward ($)"), "Total Reward ($)", xlSum)
  731. .NumberFormat = "[$$-en-US]#,##0.00"
  732. End With
  733.  
  734. With .AddDataField(.PivotFields("Bonus (£)"), "Total Bonus (£)", xlSum)
  735. .NumberFormat = "£#,##0.00"
  736. End With
  737.  
  738. With .AddDataField(.PivotFields("Bonus ($)"), "Total Bonus ($)", xlSum)
  739. .NumberFormat = "[$$-en-US]#,##0.00"
  740. End With
  741.  
  742. With .AddDataField(.PivotFields("Duration"), "Total Duration", xlSum)
  743. .NumberFormat = "[h]:mm:ss"
  744. End With
  745.  
  746. ' Filter for APPROVED studies only
  747. On Error Resume Next
  748. With .PivotFields("Status")
  749. .Orientation = xlPageField
  750. .CurrentPage = "APPROVED"
  751. .EnableMultiplePageItems = False
  752. End With
  753. On Error GoTo 0
  754.  
  755. ' Format pivot table
  756. .ShowTableStyleRowStripes = True
  757. .TableStyle2 = "PivotStyleMedium15"
  758.  
  759. ' Collapse all field items
  760. .PivotFields("Year").ShowDetail = False
  761. End With
  762. End Sub
  763.  
  764. Public Sub CreateReturnedPivotTable(wsData As Worksheet, wsPivot As Worksheet)
  765. Dim pvtCache As PivotCache
  766. Dim pvt As PivotTable
  767. Dim lastRow As Long
  768.  
  769. ' Delete existing pivot table if it exists
  770. On Error Resume Next
  771. wsPivot.PivotTables("ReturnedPivotTable").TableRange2.Clear
  772. wsPivot.PivotTables("ReturnedPivotTable").Delete
  773. On Error GoTo 0
  774.  
  775. ' Create pivot cache from data
  776. lastRow = wsData.Cells(wsData.Rows.count, "A").End(xlUp).row
  777. Set pvtCache = ThisWorkbook.PivotCaches.Create( _
  778. SourceType:=xlDatabase, _
  779. SourceData:=wsData.Range("A1:M" & lastRow), _
  780. Version:=xlPivotTableVersion15)
  781.  
  782. ' Create Returned Studies pivot table starting at J4
  783. Set pvt = pvtCache.CreatePivotTable( _
  784. TableDestination:=wsPivot.Range("J4"), _
  785. TableName:="ReturnedPivotTable", _
  786. DefaultVersion:=xlPivotTableVersion15)
  787.  
  788. ' Change Row Labels caption to Year
  789. On Error Resume Next
  790. pvt.RowAxisLayout xlTabularRow
  791. pvt.PivotFields("Row Labels").Name = "Year"
  792. On Error GoTo 0
  793.  
  794. ' Add title above pivot table after creation
  795. With wsPivot.Range("J3")
  796. .Value = "Returned Studies Breakdown Analysis"
  797. .Font.Bold = True
  798. .Font.Size = 12
  799. End With
  800.  
  801. ' Configure pivot table
  802. With pvt
  803. ' Add Year field to rows
  804. .PivotFields("Year").Orientation = xlRowField
  805. .PivotFields("Year").Position = 1
  806.  
  807. ' Add Month field to rows and format
  808. With .PivotFields("Month")
  809. .Orientation = xlRowField
  810. .Position = 2
  811.  
  812. ' Create month names array
  813. Dim monthNames(1 To 12) As String
  814. monthNames(1) = "January"
  815. monthNames(2) = "February"
  816. monthNames(3) = "March"
  817. monthNames(4) = "April"
  818. monthNames(5) = "May"
  819. monthNames(6) = "June"
  820. monthNames(7) = "July"
  821. monthNames(8) = "August"
  822. monthNames(9) = "September"
  823. monthNames(10) = "October"
  824. monthNames(11) = "November"
  825. monthNames(12) = "December"
  826.  
  827. ' Apply month names to pivot items
  828. Dim i As Long
  829. For i = 1 To 12
  830. On Error Resume Next
  831. .PivotItems(CStr(i)).Caption = monthNames(i)
  832. On Error GoTo 0
  833. Next i
  834.  
  835. ' Group by quarters
  836. On Error Resume Next
  837. .Group Start:=1, End:=12, By:=3
  838. On Error GoTo 0
  839. End With
  840.  
  841. ' Add only Bonus fields
  842. With .AddDataField(.PivotFields("Bonus (£)"), "Total Bonus (£)", xlSum)
  843. .NumberFormat = "£#,##0.00"
  844. End With
  845.  
  846. With .AddDataField(.PivotFields("Bonus ($)"), "Total Bonus ($)", xlSum)
  847. .NumberFormat = "[$$-en-US]#,##0.00"
  848. End With
  849.  
  850. With .AddDataField(.PivotFields("Duration"), "Total Duration", xlSum)
  851. .NumberFormat = "[h]:mm:ss"
  852. End With
  853.  
  854. ' Filter for RETURNED studies only
  855. On Error Resume Next
  856. With .PivotFields("Status")
  857. .Orientation = xlPageField
  858. .CurrentPage = "RETURNED"
  859. .EnableMultiplePageItems = False
  860. End With
  861. On Error GoTo 0
  862.  
  863. ' Format pivot table
  864. .ShowTableStyleRowStripes = True
  865. .TableStyle2 = "PivotStyleMedium15"
  866.  
  867. ' Collapse all field items
  868. .PivotFields("Year").ShowDetail = False
  869. End With
  870. End Sub
  871.  
  872. Private Sub CreateBarChart(tempWs As Worksheet, wsSummary As Worksheet, chartRow As Long)
  873. Dim wsData As Worksheet
  874. Set wsData = ThisWorkbook.Sheets("Processed_Data")
  875.  
  876. ' Get last row
  877. Dim lastRow As Long
  878. lastRow = wsData.Cells(wsData.Rows.count, "A").End(xlUp).row
  879.  
  880. ' Create chart first
  881. Dim chtBars As Chart
  882. Set chtBars = wsSummary.Shapes.AddChart2(227, xlColumnStacked).Chart
  883.  
  884. ' Create dictionary for our data
  885. Dim monthDict As Object
  886. Set monthDict = CreateObject("Scripting.Dictionary")
  887.  
  888. ' First pass - collect data
  889. Dim i As Long
  890. For i = 2 To lastRow
  891. If wsData.Cells(i, "J").Value = "APPROVED" Or _
  892. (wsData.Cells(i, "J").Value = "RETURNED" And _
  893. Not IsEmpty(wsData.Cells(i, "F").Value) And _
  894. Not IsEmpty(wsData.Cells(i, "G").Value)) Then
  895.  
  896. Dim key As String
  897. key = Format(wsData.Cells(i, "L").Value, "0000") & Format(wsData.Cells(i, "M").Value, "00")
  898.  
  899. If Not monthDict.Exists(key) Then
  900. Dim monthLabel As String
  901. monthLabel = Format(DateSerial(wsData.Cells(i, "L").Value, wsData.Cells(i, "M").Value, 1), "mmm")
  902. monthDict.Add key, Array(monthLabel, 0, 0, 0, 0)
  903. End If
  904.  
  905. Dim values As Variant
  906. values = monthDict(key)
  907.  
  908. If wsData.Cells(i, "J").Value = "APPROVED" Then
  909. values(1) = values(1) + wsData.Cells(i, "B").Value ' Reward GBP
  910. values(2) = values(2) + wsData.Cells(i, "C").Value ' Bonus GBP
  911. values(3) = values(3) + wsData.Cells(i, "D").Value ' Reward USD
  912. values(4) = values(4) + wsData.Cells(i, "E").Value ' Bonus USD
  913. Else ' RETURNED
  914. values(2) = values(2) + wsData.Cells(i, "C").Value ' Bonus GBP
  915. values(4) = values(4) + wsData.Cells(i, "E").Value ' Bonus USD
  916. End If
  917.  
  918. monthDict(key) = values
  919. End If
  920. Next i
  921.  
  922. ' Convert dictionary to arrays
  923. Dim monthCount As Long
  924. monthCount = monthDict.count
  925.  
  926. Dim monthLabels() As String
  927. Dim rewardGBP() As Double
  928. Dim bonusGBP() As Double
  929. Dim rewardUSD() As Double
  930. Dim bonusUSD() As Double
  931.  
  932. ReDim monthLabels(0 To monthCount - 1)
  933. ReDim rewardGBP(0 To monthCount - 1)
  934. ReDim bonusGBP(0 To monthCount - 1)
  935. ReDim rewardUSD(0 To monthCount - 1)
  936. ReDim bonusUSD(0 To monthCount - 1)
  937.  
  938. ' Sort keys
  939. Dim keys() As String
  940. ReDim keys(0 To monthCount - 1)
  941. Dim k As Long
  942. k = 0
  943. Dim keyVar As Variant
  944. For Each keyVar In monthDict.keys
  945. keys(k) = keyVar
  946. k = k + 1
  947. Next keyVar
  948.  
  949. ' Sort the keys array
  950. Call QuickSort(keys, 0, monthCount - 1)
  951.  
  952. ' Fill arrays in sorted order
  953. Dim isFirstEntry As Boolean
  954. isFirstEntry = True
  955. Dim yearNum As Long, monthNum As Long
  956.  
  957. For i = 0 To monthCount - 1
  958. values = monthDict(keys(i))
  959.  
  960. ' Get year and month from the key
  961. yearNum = CLng(Left(keys(i), 4))
  962. monthNum = CLng(Right(keys(i), 2))
  963.  
  964. ' Format label
  965. If isFirstEntry Then
  966. ' First entry - always show year
  967. monthLabels(i) = yearNum & " - " & values(0)
  968. isFirstEntry = False
  969. ElseIf monthNum = 1 Then
  970. ' January - show year
  971. monthLabels(i) = yearNum & " - " & values(0)
  972. Else
  973. ' Other months - just show month
  974. monthLabels(i) = values(0)
  975. End If
  976.  
  977. rewardGBP(i) = values(1)
  978. bonusGBP(i) = values(2)
  979. rewardUSD(i) = values(3)
  980. bonusUSD(i) = values(4)
  981. Next i
  982.  
  983. ' Create the chart
  984. With chtBars
  985. .ChartType = xlColumnStacked
  986.  
  987. ' Clear any existing series
  988. Do While .SeriesCollection.count > 0
  989. .SeriesCollection(1).Delete
  990. Loop
  991.  
  992. ' Add series
  993. With .SeriesCollection.NewSeries
  994. .Name = "Total Reward (£)"
  995. .values = rewardGBP
  996. .XValues = monthLabels
  997. .Format.Fill.ForeColor.RGB = RGB(0, 176, 80) ' Dark Green
  998. End With
  999.  
  1000. With .SeriesCollection.NewSeries
  1001. .Name = "Total Bonus (£)"
  1002. .values = bonusGBP
  1003. .XValues = monthLabels
  1004. .Format.Fill.ForeColor.RGB = RGB(146, 208, 80) ' Light Green
  1005. End With
  1006.  
  1007. With .SeriesCollection.NewSeries
  1008. .Name = "Total Reward ($)"
  1009. .values = rewardUSD
  1010. .XValues = monthLabels
  1011. .Format.Fill.ForeColor.RGB = RGB(0, 112, 192) ' Dark Blue
  1012. End With
  1013.  
  1014. With .SeriesCollection.NewSeries
  1015. .Name = "Total Bonus ($)"
  1016. .values = bonusUSD
  1017. .XValues = monthLabels
  1018. .Format.Fill.ForeColor.RGB = RGB(91, 155, 213) ' Light Blue
  1019. End With
  1020.  
  1021. ' Format chart
  1022. .ChartArea.Format.Fill.ForeColor.RGB = RGB(32, 32, 32)
  1023. .PlotArea.Format.Fill.ForeColor.RGB = RGB(32, 32, 32)
  1024.  
  1025. ' Format axes
  1026. With .Axes(xlValue)
  1027. .HasTitle = True
  1028. .AxisTitle.Text = "Amount"
  1029. .AxisTitle.Format.TextFrame2.TextRange.Font.Fill.ForeColor.RGB = RGB(255, 255, 255)
  1030. .TickLabels.Font.Color = RGB(255, 255, 255)
  1031. .Format.Line.ForeColor.RGB = RGB(255, 255, 255)
  1032. .TickLabels.NumberFormat = "#,##0.00" ' Removed £ symbol
  1033. .MajorGridlines.Format.Line.ForeColor.RGB = RGB(64, 64, 64)
  1034. End With
  1035.  
  1036. With .Axes(xlCategory)
  1037. .TickLabels.Font.Color = RGB(255, 255, 255)
  1038. .Format.Line.ForeColor.RGB = RGB(255, 255, 255)
  1039. .TickLabelSpacing = 1 ' Show all labels
  1040. .TickLabels.Orientation = 90 ' Vertical labels
  1041. End With
  1042.  
  1043. ' Add title and legend
  1044. .HasTitle = True
  1045. .ChartTitle.Text = "Monthly Rewards and Bonuses"
  1046. .ChartTitle.Format.TextFrame2.TextRange.Font.Fill.ForeColor.RGB = RGB(255, 255, 255)
  1047.  
  1048. .HasLegend = True
  1049. .Legend.Position = xlBottom
  1050. .Legend.Format.TextFrame2.TextRange.Font.Fill.ForeColor.RGB = RGB(255, 255, 255)
  1051.  
  1052. ' Position the chart
  1053. With .Parent
  1054. .Left = wsSummary.Range("D29").Left
  1055. .Top = wsSummary.Range("D29").Top
  1056. .Width = 800
  1057. .Height = 400
  1058. End With
  1059. End With
  1060. End Sub
  1061.  
  1062. ' Helper function for sorting
  1063. Private Sub QuickSort(arr() As String, low As Long, high As Long)
  1064. Dim pivot As String
  1065. Dim tmp As String
  1066. Dim i As Long
  1067. Dim j As Long
  1068.  
  1069. If low < high Then
  1070. pivot = arr((low + high) \ 2)
  1071. i = low
  1072. j = high
  1073.  
  1074. Do
  1075. Do While arr(i) < pivot
  1076. i = i + 1
  1077. Loop
  1078.  
  1079. Do While arr(j) > pivot
  1080. j = j - 1
  1081. Loop
  1082.  
  1083. If i <= j Then
  1084. tmp = arr(i)
  1085. arr(i) = arr(j)
  1086. arr(j) = tmp
  1087. i = i + 1
  1088. j = j - 1
  1089. End If
  1090. Loop Until i > j
  1091.  
  1092. If low < j Then QuickSort arr, low, j
  1093. If i < high Then QuickSort arr, i, high
  1094. End If
  1095. End Sub
  1096.  
  1097. Private Sub TestHourlyRateCalculation()
  1098. ' Prevent screen updating
  1099. Application.ScreenUpdating = False
  1100.  
  1101. Dim wsData As Worksheet
  1102. Dim wsSummary As Worksheet
  1103.  
  1104. ' Get the required worksheets
  1105. Set wsData = ThisWorkbook.Sheets("Processed_Data")
  1106. Set wsSummary = ThisWorkbook.Sheets("Summary")
  1107.  
  1108. ' Create temporary storage for our calculations
  1109. Dim tempWs As Worksheet
  1110.  
  1111. ' Create/recreate temp worksheet
  1112. On Error Resume Next
  1113. ThisWorkbook.Sheets("TempHourlyRate").Delete
  1114. Set tempWs = ThisWorkbook.Sheets.Add
  1115. tempWs.Name = "TempHourlyRate"
  1116. On Error GoTo 0
  1117.  
  1118. ' Setup headers with separate currency columns
  1119. With tempWs
  1120. .Cells(1, 1).Value = "Year"
  1121. .Cells(1, 2).Value = "Month"
  1122. .Cells(1, 3).Value = "Total Hours"
  1123. .Cells(1, 4).Value = "Total GBP"
  1124. .Cells(1, 5).Value = "Total USD"
  1125. .Cells(1, 6).Value = "Hourly Rate"
  1126. End With
  1127.  
  1128. ' Create dictionary to store monthly data
  1129. Dim monthData As Object
  1130. Set monthData = CreateObject("Scripting.Dictionary")
  1131.  
  1132. ' Get last row
  1133. Dim lastRow As Long
  1134. lastRow = wsData.Cells(wsData.Rows.Count, "A").End(xlUp).Row
  1135.  
  1136. ' Process each row
  1137. Dim i As Long
  1138. For i = 2 To lastRow
  1139. Dim hasValidTimes As Boolean
  1140. hasValidTimes = Not IsEmpty(wsData.Cells(i, "F").Value) And _
  1141. Not IsEmpty(wsData.Cells(i, "G").Value)
  1142.  
  1143. ' Calculate earnings and hours based on status
  1144. If wsData.Cells(i, "J").Value = "APPROVED" Or _
  1145. (wsData.Cells(i, "J").Value = "RETURNED" And hasValidTimes) Then
  1146.  
  1147. ' Create key for year-month
  1148. Dim key As String
  1149. key = Format(wsData.Cells(i, "L").Value, "0000") & Format(wsData.Cells(i, "M").Value, "00")
  1150.  
  1151. ' Calculate earnings for this entry
  1152. Dim entryGBP As Double, entryUSD As Double
  1153. If wsData.Cells(i, "J").Value = "APPROVED" Then
  1154. ' For Approved: Include all rewards and bonuses
  1155. entryGBP = wsData.Cells(i, "B").Value + wsData.Cells(i, "C").Value
  1156. entryUSD = wsData.Cells(i, "D").Value + wsData.Cells(i, "E").Value
  1157. Else ' RETURNED with valid times
  1158. ' For Returned: Only include bonuses
  1159. entryGBP = wsData.Cells(i, "C").Value
  1160. entryUSD = wsData.Cells(i, "E").Value
  1161. End If
  1162.  
  1163. ' Only add hours if we have valid times
  1164. Dim entryHours As Double
  1165. If hasValidTimes Then
  1166. entryHours = wsData.Cells(i, "H").Value * 24 ' Convert to hours
  1167. End If
  1168.  
  1169. ' Add or update dictionary entry
  1170. If Not monthData.Exists(key) Then
  1171. monthData.Add key, Array(wsData.Cells(i, "L").Value, _
  1172. wsData.Cells(i, "M").Value, _
  1173. entryHours, _
  1174. entryGBP, _
  1175. entryUSD)
  1176. Else
  1177. Dim existingData As Variant
  1178. existingData = monthData(key)
  1179. existingData(2) = existingData(2) + entryHours
  1180. existingData(3) = existingData(3) + entryGBP
  1181. existingData(4) = existingData(4) + entryUSD
  1182. monthData(key) = existingData
  1183. End If
  1184. End If
  1185. Next i
  1186.  
  1187. ' Write sorted data
  1188. Dim row As Long
  1189. row = 2
  1190.  
  1191. ' Create and populate keys array
  1192. Dim keys() As String
  1193. ReDim keys(0 To monthData.Count - 1)
  1194. Dim k As Long
  1195. k = 0
  1196. Dim keyVar As Variant
  1197. For Each keyVar In monthData.keys
  1198. keys(k) = keyVar
  1199. k = k + 1
  1200. Next keyVar
  1201.  
  1202. ' Sort keys array
  1203. QuickSort keys, LBound(keys), UBound(keys)
  1204.  
  1205. ' Get exchange rate
  1206. Dim exchangeRate As Double
  1207. exchangeRate = wsSummary.Range("B18").Value
  1208.  
  1209. ' Write sorted data
  1210. For k = LBound(keys) To UBound(keys)
  1211. Dim data As Variant
  1212. data = monthData(keys(k))
  1213.  
  1214. With tempWs
  1215. .Cells(row, 1).Value = data(0) ' Year
  1216. .Cells(row, 2).Value = monthName(data(1), True) ' Month
  1217. .Cells(row, 3).Value = data(2) / 24 ' Convert hours back to Excel time format
  1218. .Cells(row, 4).Value = data(3) ' GBP
  1219. .Cells(row, 5).Value = data(4) ' USD
  1220.  
  1221. ' Calculate hourly rate including converted USD
  1222. If data(2) > 0 Then
  1223. .Cells(row, 6).Value = (data(3) + (data(4) * exchangeRate)) / data(2)
  1224. Else
  1225. .Cells(row, 6).Value = 0
  1226. End If
  1227.  
  1228. ' Format cells
  1229. .Cells(row, 3).NumberFormat = "[h]:mm:ss"
  1230. .Cells(row, 4).NumberFormat = "£#,##0.00"
  1231. .Cells(row, 5).NumberFormat = "[$$-en-US]#,##0.00"
  1232. .Cells(row, 6).NumberFormat = "£#,##0.00"
  1233. End With
  1234. row = row + 1
  1235. Next k
  1236.  
  1237. ' Autofit columns
  1238. tempWs.Columns("A:F").AutoFit
  1239.  
  1240. ' Hide sheet
  1241. tempWs.Visible = xlSheetVeryHidden
  1242. End Sub
  1243.  
  1244. Private Sub CreateHourlyRateChartOnSummary()
  1245. Dim tempWs As Worksheet
  1246. Dim wsSummary As Worksheet
  1247. Dim cht As Chart
  1248. Dim cboYear As Shape
  1249. Dim years As Collection
  1250. Dim yr As Variant
  1251.  
  1252. ' Get the required worksheets
  1253. Set tempWs = ThisWorkbook.Sheets("TempHourlyRate")
  1254. Set wsSummary = ThisWorkbook.Sheets("Summary")
  1255.  
  1256. ' Get years collection first
  1257. Set years = GetUniqueYears(tempWs)
  1258.  
  1259. ' Add combobox for year selection at W1
  1260. Set cboYear = wsSummary.Shapes.AddFormControl(xlDropDown, _
  1261. wsSummary.Range("W1").Left, _
  1262. wsSummary.Range("W1").Top, _
  1263. 80, 20)
  1264.  
  1265. ' Style the combobox and its surroundings
  1266. With cboYear
  1267. .OnAction = "YearSelected"
  1268.  
  1269. ' Add a label for the dropdown with dark background
  1270. With wsSummary.Range("V1")
  1271. .Value = "Select Year:"
  1272. .Font.Color = RGB(255, 255, 255)
  1273. .Font.Bold = True
  1274. .Interior.Color = RGB(32, 32, 32) ' Match dropdown background
  1275. .HorizontalAlignment = xlRight
  1276. End With
  1277.  
  1278. ' Add background cell styling for dropdown
  1279. With wsSummary.Range("W1")
  1280. .Interior.Color = RGB(64, 64, 64)
  1281. End With
  1282.  
  1283. ' Populate years
  1284. For Each yr In years
  1285. .ControlFormat.AddItem yr
  1286. Next yr
  1287. .ControlFormat.ListIndex = 1
  1288.  
  1289. ' Position carefully
  1290. .Left = wsSummary.Range("W1").Left + 1 ' Slight offset to align with cell
  1291. .Top = wsSummary.Range("W1").Top + 1
  1292. .Width = wsSummary.Range("W1").Width - 2
  1293. .Height = wsSummary.Range("W1").Height - 2
  1294. End With
  1295.  
  1296. ' Create the chart
  1297. Set cht = wsSummary.Shapes.AddChart2(227, xlColumnClustered).Chart
  1298.  
  1299. ' Store chart name for reference in change event
  1300. cht.Parent.Name = "HourlyRateChart"
  1301.  
  1302. ' Format chart
  1303. With cht
  1304. ' Position the chart
  1305. .Parent.Left = wsSummary.Range("U2").Left
  1306. .Parent.Top = wsSummary.Range("U2").Top
  1307. .Parent.Width = 900
  1308. .Parent.Height = 500
  1309.  
  1310. .ChartArea.Format.Fill.ForeColor.RGB = RGB(32, 32, 32)
  1311. .PlotArea.Format.Fill.ForeColor.RGB = RGB(32, 32, 32)
  1312.  
  1313. ' Clear any existing series first
  1314. Do While .SeriesCollection.count > 0
  1315. .SeriesCollection(1).Delete
  1316. Loop
  1317.  
  1318. ' Add series for hourly rate
  1319. With .SeriesCollection.NewSeries
  1320. .Name = "Hourly Rate"
  1321. .Format.Fill.ForeColor.RGB = RGB(0, 176, 80) ' Green
  1322.  
  1323. ' Add data labels
  1324. .HasDataLabels = True
  1325. With .DataLabels
  1326. .ShowValue = False
  1327. .Position = xlLabelPositionOutsideEnd
  1328. .Format.TextFrame2.TextRange.Font.Fill.ForeColor.RGB = RGB(255, 255, 255)
  1329. .Format.TextFrame2.TextRange.Font.Size = 9
  1330. .Format.Fill.ForeColor.RGB = RGB(64, 64, 64)
  1331. .Format.Fill.Transparency = 0.7
  1332. End With
  1333. End With
  1334.  
  1335. ' Format axes
  1336. With .Axes(xlValue)
  1337. .HasTitle = True
  1338. .AxisTitle.Text = "Hourly Rate (£)"
  1339. .AxisTitle.Format.TextFrame2.TextRange.Font.Fill.ForeColor.RGB = RGB(255, 255, 255)
  1340. .TickLabels.Font.Color = RGB(255, 255, 255)
  1341. .Format.Line.ForeColor.RGB = RGB(255, 255, 255)
  1342. .TickLabels.NumberFormat = "£#,##0.00"
  1343. .MajorGridlines.Format.Line.ForeColor.RGB = RGB(64, 64, 64)
  1344. End With
  1345.  
  1346. With .Axes(xlCategory)
  1347. .TickLabels.Font.Color = RGB(255, 255, 255)
  1348. .Format.Line.ForeColor.RGB = RGB(255, 255, 255)
  1349. End With
  1350.  
  1351. ' Add title
  1352. .HasTitle = True
  1353. .ChartTitle.Text = "Monthly Hourly Rate Analysis"
  1354. .ChartTitle.Format.TextFrame2.TextRange.Font.Fill.ForeColor.RGB = RGB(255, 255, 255)
  1355. .ChartTitle.Format.TextFrame2.TextRange.Font.Size = 14
  1356.  
  1357. ' Remove legend completely
  1358. .HasLegend = False ' Changed from True to False
  1359. End With
  1360.  
  1361. ' Add initial data for first year in list
  1362. If years.count > 0 Then
  1363. UpdateChartData cht, tempWs, years(1)
  1364. End If
  1365. End Sub
  1366.  
  1367. Private Function GetUniqueYears(ws As Worksheet) As Collection
  1368. Dim dict As Object
  1369. Dim cell As Range
  1370. Dim lastRow As Long
  1371.  
  1372. Set dict = CreateObject("Scripting.Dictionary")
  1373. lastRow = ws.Cells(ws.Rows.count, "A").End(xlUp).row
  1374.  
  1375. ' Get unique years from column A
  1376. For Each cell In ws.Range("A2:A" & lastRow)
  1377. If Not dict.Exists(cell.Value) Then
  1378. dict.Add cell.Value, cell.Value
  1379. End If
  1380. Next cell
  1381.  
  1382. ' Convert to collection and sort
  1383. Set GetUniqueYears = New Collection
  1384. Dim yearArray() As Variant
  1385. yearArray = dict.Items
  1386.  
  1387. ' Sort years
  1388. Dim i As Long, j As Long, temp As Variant
  1389. For i = LBound(yearArray) To UBound(yearArray) - 1
  1390. For j = i + 1 To UBound(yearArray)
  1391. If yearArray(i) > yearArray(j) Then
  1392. temp = yearArray(i)
  1393. yearArray(i) = yearArray(j)
  1394. yearArray(j) = temp
  1395. End If
  1396. Next j
  1397. Next i
  1398.  
  1399. ' Add sorted years to collection
  1400. For i = LBound(yearArray) To UBound(yearArray)
  1401. GetUniqueYears.Add yearArray(i)
  1402. Next i
  1403. End Function
  1404.  
  1405. Private Sub UpdateChartData(cht As Chart, dataWs As Worksheet, selectedYear As Integer)
  1406. ' Filter data for selected year
  1407. Dim lastRow As Long
  1408. Dim monthValues() As String
  1409. Dim hourlyRates() As Double
  1410. Dim customLabels() As String
  1411. Dim count As Long
  1412. Dim i As Long
  1413.  
  1414. lastRow = dataWs.Cells(dataWs.Rows.count, "A").End(xlUp).row
  1415.  
  1416. ' First count matching rows
  1417. count = 0
  1418. For i = 2 To lastRow
  1419. If dataWs.Cells(i, "A").Value = selectedYear Then
  1420. count = count + 1
  1421. End If
  1422. Next i
  1423.  
  1424. ' Size arrays
  1425. ReDim monthValues(1 To count)
  1426. ReDim hourlyRates(1 To count)
  1427. ReDim customLabels(1 To count)
  1428.  
  1429. ' Fill arrays
  1430. count = 0
  1431. For i = 2 To lastRow
  1432. If dataWs.Cells(i, "A").Value = selectedYear Then
  1433. count = count + 1
  1434. monthValues(count) = dataWs.Cells(i, "B").Value
  1435. hourlyRates(count) = dataWs.Cells(i, "F").Value
  1436.  
  1437. ' Create custom label text
  1438. Dim timeValue As Double
  1439. timeValue = dataWs.Cells(i, "C").Value * 24 ' Convert to hours
  1440.  
  1441. customLabels(count) = "Hours: " & Format(timeValue, "0") & ":" & _
  1442. Format(timeValue * 60 Mod 60, "00") & ":" & _
  1443. Format(timeValue * 3600 Mod 60, "00") & vbNewLine & _
  1444. "Earned: " & Format(dataWs.Cells(i, "D").Value, "£#,##0.00") & vbNewLine & _
  1445. "Rate: " & Format(dataWs.Cells(i, "F").Value, "£#,##0.00")
  1446. End If
  1447. Next i
  1448.  
  1449. ' Find maximum hourly rate for scaling
  1450. Dim maxRate As Double
  1451. maxRate = 0
  1452. For i = 1 To count
  1453. If hourlyRates(i) > maxRate Then maxRate = hourlyRates(i)
  1454. Next i
  1455.  
  1456. ' Round up to next whole number and add buffer
  1457. maxRate = Application.WorksheetFunction.Ceiling(maxRate + 2, 1)
  1458.  
  1459. ' Update chart data
  1460. With cht.SeriesCollection(1)
  1461. .values = hourlyRates
  1462. .XValues = monthValues
  1463.  
  1464. ' Update data labels
  1465. .HasDataLabels = False
  1466. .HasDataLabels = True
  1467.  
  1468. With .DataLabels
  1469. .Position = xlLabelPositionOutsideEnd
  1470. .Format.TextFrame2.TextRange.Font.Fill.ForeColor.RGB = RGB(255, 255, 255)
  1471. .Format.TextFrame2.TextRange.Font.Size = 9
  1472. .Format.Fill.ForeColor.RGB = RGB(64, 64, 64)
  1473. .Format.Fill.Transparency = 0.7
  1474. End With
  1475.  
  1476. ' Set individual label text
  1477. Dim j As Long
  1478. For j = 1 To count
  1479. .Points(j).DataLabel.Text = customLabels(j)
  1480. Next j
  1481. End With
  1482.  
  1483. ' Adjust the plot area and chart formatting
  1484. With cht
  1485. ' Increase overall chart height to accommodate labels
  1486. .Parent.Height = 600
  1487.  
  1488. ' Position plot area using relative coordinates
  1489. With .PlotArea
  1490. .Format.Fill.ForeColor.RGB = RGB(32, 32, 32)
  1491. ' Move the plot area down more
  1492. .Top = .Top + 100 ' Increased from 50 to 100 points
  1493. End With
  1494.  
  1495. ' Set the value axis scaling with different increments
  1496. With .Axes(xlValue)
  1497. .MinimumScale = 6 ' Keep minimum at £6
  1498.  
  1499. ' Adjust maximum scale based on the highest rate
  1500. If maxRate <= 20 Then
  1501. .MaximumScale = WorksheetFunction.Ceiling(maxRate + 2, 1)
  1502. .MajorUnit = 1 ' £1 increments up to £20
  1503. .MinorUnit = 0.5 ' £0.50 minor units
  1504. Else
  1505. ' For rates above £20, round up to next £5 increment
  1506. Dim adjustedMax As Double
  1507. adjustedMax = WorksheetFunction.Ceiling(maxRate, 5) ' Round to nearest £5
  1508. If adjustedMax = maxRate Then adjustedMax = adjustedMax + 5 ' Add another £5 if exactly divisible
  1509.  
  1510. .MaximumScale = adjustedMax
  1511. .MinimumScale = 0 ' Start from 0 for better scale visibility
  1512. .MajorUnit = 5 ' £5 increments (25, 30, 35, etc.)
  1513. .MinorUnit = 1 ' £1 minor units
  1514. End If
  1515.  
  1516. ' Format axis
  1517. .HasTitle = True
  1518. .AxisTitle.Text = "Hourly Rate (£)"
  1519. .AxisTitle.Format.TextFrame2.TextRange.Font.Fill.ForeColor.RGB = RGB(255, 255, 255)
  1520. .TickLabels.Font.Color = RGB(255, 255, 255)
  1521. .Format.Line.ForeColor.RGB = RGB(255, 255, 255)
  1522. .TickLabels.NumberFormat = "£#,##0.00"
  1523. .MajorGridlines.Format.Line.ForeColor.RGB = RGB(64, 64, 64)
  1524. End With
  1525. End With
  1526. End Sub
  1527.  
  1528. Private Sub CreateYearlyRateAnalysis()
  1529. Dim wsSummary As Worksheet
  1530. Set wsSummary = ThisWorkbook.Sheets("Summary")
  1531.  
  1532. ' Find the last used row in column A
  1533. Dim lastRow As Long
  1534. lastRow = wsSummary.Cells(wsSummary.Rows.Count, "A").End(xlUp).Row
  1535.  
  1536. ' Add Yearly Rate Analysis section
  1537. With wsSummary
  1538. ' Insert two blank rows for spacing
  1539. .Rows(lastRow + 1).Insert Shift:=xlDown, CopyOrigin:=xlFormatFromLeftOrAbove
  1540. .Rows(lastRow + 1).Insert Shift:=xlDown, CopyOrigin:=xlFormatFromLeftOrAbove
  1541.  
  1542. ' Start our section
  1543. .Cells(lastRow + 2, 1).Value = "Yearly Hourly Rate Analysis"
  1544. .Range("A" & lastRow + 2 & ":B" & lastRow + 2).Merge
  1545. .Range("A" & lastRow + 2).Font.Size = 12
  1546. .Range("A" & lastRow + 2).Font.Bold = True
  1547. .Range("A" & lastRow + 2).Interior.Color = RGB(64, 64, 64)
  1548. .Range("A" & lastRow + 2).HorizontalAlignment = xlCenter
  1549.  
  1550. ' Get data from TempHourlyRate sheet
  1551. Dim tempWs As Worksheet
  1552. Set tempWs = ThisWorkbook.Sheets("TempHourlyRate")
  1553.  
  1554. ' Get exchange rate
  1555. Dim exchangeRate As Double
  1556. exchangeRate = wsSummary.Range("B18").Value
  1557.  
  1558. ' Create dictionary to store yearly totals
  1559. Dim yearlyData As Object
  1560. Set yearlyData = CreateObject("Scripting.Dictionary")
  1561.  
  1562. ' Calculate yearly totals
  1563. Dim lastTempRow As Long
  1564. lastTempRow = tempWs.Cells(tempWs.Rows.Count, "A").End(xlUp).Row
  1565.  
  1566. Dim i As Long
  1567. For i = 2 To lastTempRow
  1568. If Not IsEmpty(tempWs.Cells(i, 3).Value) Then
  1569. Dim year As Long
  1570. year = tempWs.Cells(i, 1).Value
  1571.  
  1572. If Not yearlyData.Exists(year) Then
  1573. yearlyData.Add year, Array(0, 0, 0) ' hours, GBP, USD
  1574. End If
  1575.  
  1576. Dim data As Variant
  1577. data = yearlyData(year)
  1578. data(0) = data(0) + tempWs.Cells(i, 3).Value ' Hours
  1579. data(1) = data(1) + tempWs.Cells(i, 4).Value ' GBP
  1580. data(2) = data(2) + tempWs.Cells(i, 5).Value ' USD
  1581. yearlyData(year) = data
  1582. End If
  1583. Next i
  1584.  
  1585. ' Output yearly data
  1586. Dim row As Long
  1587. row = lastRow + 3
  1588.  
  1589. ' Sort and output years
  1590. Dim years() As Long
  1591. ReDim years(0 To yearlyData.Count - 1)
  1592. Dim k As Long
  1593. k = 0
  1594. Dim yearKey As Variant
  1595. For Each yearKey In yearlyData.keys
  1596. years(k) = yearKey
  1597. k = k + 1
  1598. Next yearKey
  1599.  
  1600. ' Sort years
  1601. Dim j As Long, temp As Long
  1602. For i = LBound(years) To UBound(years) - 1
  1603. For j = i + 1 To UBound(years)
  1604. If years(i) > years(j) Then
  1605. temp = years(i)
  1606. years(i) = years(j)
  1607. years(j) = temp
  1608. End If
  1609. Next j
  1610. Next i
  1611.  
  1612. ' Output sorted data
  1613. For i = LBound(years) To UBound(years)
  1614. data = yearlyData(years(i))
  1615.  
  1616. ' Convert hours from days to actual hours for calculation
  1617. Dim totalHours As Double
  1618. totalHours = data(0) * 24 ' Convert days to hours
  1619.  
  1620. ' Calculate total earnings (GBP + converted USD)
  1621. Dim totalEarnings As Double
  1622. totalEarnings = data(1) + (data(2) * exchangeRate)
  1623.  
  1624. .Cells(row, 1).Value = "Year " & years(i)
  1625. .Cells(row + 1, 1).Value = "Hours"
  1626. .Cells(row + 1, 2).Value = data(0)
  1627. .Cells(row + 1, 2).NumberFormat = "[h]:mm:ss"
  1628.  
  1629. .Cells(row + 2, 1).Value = "Earnings"
  1630. .Cells(row + 2, 2).Value = totalEarnings
  1631. .Cells(row + 2, 2).NumberFormat = "£#,##0.00"
  1632.  
  1633. .Cells(row + 3, 1).Value = "Hourly Rate"
  1634. If totalHours > 0 Then
  1635. .Cells(row + 3, 2).Value = totalEarnings / totalHours
  1636. Else
  1637. .Cells(row + 3, 2).Value = 0
  1638. End If
  1639. .Cells(row + 3, 2).NumberFormat = "£#,##0.00"
  1640.  
  1641. ' Format cells
  1642. .Range("A" & row & ":B" & row + 3).Interior.Color = RGB(45, 45, 45)
  1643. .Range("A" & row + 1 & ":A" & row + 3).IndentLevel = 1
  1644.  
  1645. ' Add borders
  1646. With .Range("A" & row & ":B" & row + 3)
  1647. .Borders(xlEdgeLeft).LineStyle = xlContinuous
  1648. .Borders(xlEdgeLeft).Color = RGB(128, 128, 128)
  1649. .Borders(xlEdgeRight).LineStyle = xlContinuous
  1650. .Borders(xlEdgeRight).Color = RGB(128, 128, 128)
  1651. .Borders(xlEdgeTop).LineStyle = xlContinuous
  1652. .Borders(xlEdgeTop).Color = RGB(128, 128, 128)
  1653. .Borders(xlEdgeBottom).LineStyle = xlContinuous
  1654. .Borders(xlEdgeBottom).Color = RGB(128, 128, 128)
  1655. .Borders(xlInsideHorizontal).LineStyle = xlContinuous
  1656. .Borders(xlInsideHorizontal).Color = RGB(128, 128, 128)
  1657. End With
  1658.  
  1659. row = row + 5
  1660. Next i
  1661.  
  1662. ' Add border around entire section
  1663. With .Range("A" & (lastRow + 2) & ":B" & row - 1)
  1664. .BorderAround Weight:=xlThin, Color:=RGB(128, 128, 128)
  1665. End With
  1666.  
  1667. ' Insert a blank row after the section
  1668. .Rows(row).Insert Shift:=xlDown, CopyOrigin:=xlFormatFromLeftOrAbove
  1669. End With
  1670. End Sub
  1671.  
  1672. Public Sub YearSelected()
  1673. Dim ws As Worksheet
  1674. Dim cht As Chart
  1675. Dim cboYear As Shape
  1676.  
  1677. Set ws = ActiveSheet
  1678. Set cht = ws.Shapes("HourlyRateChart").Chart
  1679. Set cboYear = ws.Shapes.Range(Array(Application.Caller))(1)
  1680.  
  1681. ' Get selected year
  1682. Dim selectedYear As Integer
  1683. selectedYear = cboYear.ControlFormat.List(cboYear.ControlFormat.ListIndex)
  1684.  
  1685. ' Update chart with selected year
  1686. UpdateChartData cht, ThisWorkbook.Sheets("TempHourlyRate"), selectedYear
  1687. End Sub
Advertisement
Add Comment
Please, Sign In to add comment