Compare commits

..

2 Commits

Author SHA1 Message Date
2ee8bde397
Add simple computation of utilization to workload overview report
This way, it should be easier to spot days where utilzation is too high
to take any more work.
2024-10-03 10:14:30 +02:00
f948f3dca3
Make skip-matches also skip computations in workload overview report
This avoids unnecessary computations.
2024-10-03 09:54:15 +02:00

View File

@ -749,7 +749,12 @@ PARAMS is a property list of the following parameters:
weekends, use \"Sat\\|Sun\" as regular expression. weekends, use \"Sat\\|Sun\" as regular expression.
This can also be a function taking a formatted timestamp as This can also be a function taking a formatted timestamp as
argument and returning non-nil when the date should be skipped." argument and returning non-nil when the date should be skipped.
`:work-hours'
The time available per day for work, given as duration string.
Defauls to \"8:00\"."
(let* ((start-date (org-read-date t t (let* ((start-date (org-read-date t t
(or (plist-get params :start-date) (or (plist-get params :start-date)
"00:00"))) "00:00")))
@ -767,47 +772,56 @@ PARAMS is a property list of the following parameters:
#'(lambda (x) (string-match arg x))) #'(lambda (x) (string-match arg x)))
((and (pred functionp) fun) fun) ((and (pred functionp) fun) fun)
(_ (user-error "Invalid argument to :skip-matches: %s" arg)))) (_ (user-error "Invalid argument to :skip-matches: %s" arg))))
(work-hours (or (plist-get params :work-hours)
"8:00"))
date-range) date-range)
;; Check input ;; Check input
(unless (string-match-p (rx bos "+" (+ digit) (in "dwmy") eos) (unless (string-match-p (rx bos "+" (+ digit) (in "dwmy") eos)
increment) increment)
(user-error "Increment must be of the form +1d, +2m, +3y, …, but it's %s" increment)) (user-error "Increment must be of the form +1d, +2m, +3y, …, but it's %s" increment))
(unless (org-duration-p work-hours)
(user-error "Work hours must be a duration string, but it's %s" work-hours))
;; Compute range of dates to check; simple but potentially costly approach ;; Compute range of dates to check; simple but potentially costly approach
;; taken from https://sachachua.com/blog/2015/08/org-mode-date-arithmetic/; ;; taken from https://sachachua.com/blog/2015/08/org-mode-date-arithmetic/;
;; maybe consider `org-read-date-get-relative' as well? ;; maybe consider `org-read-date-get-relative' as well?
(let ((current start-date)) (let ((current start-date)
current-formatted)
(while (or (time-less-p current end-date) (while (or (time-less-p current end-date)
(time-equal-p current end-date)) (time-equal-p current end-date))
(setq current (org-read-date t t (setq current (org-read-date t t
;; Add an extra + to ensure we increase the ;; Add an extra + to ensure we increase the amount of time
;; amount of time relative to the given ;; relative to the given default time string.
;; default time string.
(format "+%s" increment) (format "+%s" increment)
nil current)) nil current)
(push current date-range))) current-formatted (format-time-string timestamp-format current))
(unless (funcall skipper current-formatted)
(push current-formatted date-range))))
(setq date-range (nreverse (cdr date-range))) (setq date-range (nreverse (cdr date-range)))
(insert (format "#+CAPTION: Workload Overview Report at [%s] with start date [%s]\n" (insert (format "#+CAPTION: Workload Overview Report at [%s] with start date [%s]\n"
(format-time-string timestamp-format (current-time)) (format-time-string timestamp-format (current-time))
(format-time-string timestamp-format start-date))) (format-time-string timestamp-format start-date)))
(insert "| End Time | Planned Total |\n| <r> | <r> |\n|---|\n") (insert "| End Time | Planned Total | Utilization |\n| <r> | <r> | <r> |\n|---|\n")
;; Compute workload report for each date and record the total time; ;; Compute workload report for each date and record the total time;
;; XXX: this might be slow, try to reduce the calls to ;; XXX: this might be slow, try to reduce the calls to `db/org-planned-tasks-in-range'.
;; `db/org-planned-tasks-in-range'. (let ((days 0))
(dolist (interval-end-date date-range) (dolist (interval-end-date date-range)
(let ((total-time (car (db/org-planned-tasks-in-range (let ((total-time (car (db/org-planned-tasks-in-range
;; Set start date to nil to also include tasks ;; Set start date to nil to also include tasks scheduled or deadlined
;; scheduled or deadlined before `start-date', as ;; before `start-date', as those are also still open and need to be
;; those are also still open and need to be done ;; done somewhen.
;; somewhen.
nil nil
(format-time-string timestamp-format interval-end-date) interval-end-date
org-ql-match)))) org-ql-match))))
(let ((interval-end-date (format-time-string timestamp-format interval-end-date))) (let ((utilization (* (/ (org-duration-to-minutes total-time)
(unless (funcall skipper interval-end-date) (* (cl-incf days)
(insert (format "| [%s] | %s |\n" interval-end-date total-time)))))) (org-duration-to-minutes work-hours)))
100)))
(insert (format "| [%s] | %s | %.2f%% |\n" interval-end-date total-time utilization))))))
(insert "|--|") (insert "|--|")
(org-table-align))) (org-table-align)))