casa-reoc-0.1.0.0: src/ReOC/Amendment.hs
{-# OPTIONS_GHC -Wall #-}
{- | The amendment record of an operations manual. The first entry gives its
version and date; each revision follows the entry before it, so the versions
increase and the dates do not go backwards.
-}
module ReOC.Amendment (
AmendmentEntry,
amendmentRecord,
manualVersion,
manualDate,
manualReviewDate,
addMonths,
) where
import Control.Lens (cloneLens, view)
import Data.List.NonEmpty (NonEmpty)
import qualified Data.List.NonEmpty as NonEmpty
import Data.Time.Calendar.Month (Month)
import qualified Data.Time.Calendar.Month as Month
import Numeric.Natural (Natural)
import ReOC.Model
-- | An entry of the amendment record: version, date, effective date, parts and details.
type AmendmentEntry = (Version, Month, Text1, Text1, Text1)
{- | A month a number of months later.
>>> addMonths 12 (Month.YearMonth 2026 10)
2027-10
-}
addMonths :: Natural -> Month -> Month
addMonths n (Month.YearMonth y m) =
let total = y * 12 + fromIntegral (m - 1) + fromIntegral n
in Month.YearMonth (total `div` 12) (fromIntegral (total `mod` 12) + 1)
-- | The entries of the amendment record, in order.
amendmentRecord :: OperationsManual -> NonEmpty AmendmentEntry
amendmentRecord m =
let f = view (cloneLens firstIssue) m
first = (view (cloneLens version) f, view (cloneLens issueDate) f, view (cloneLens effective) f, view (cloneLens parts) f, view (cloneLens details) f)
next :: AmendmentEntry -> Revision -> AmendmentEntry
next (v, d, _, _, _) r =
( case view (cloneLens versionIncrement) r of
MajorRevision -> Version' (view (cloneLens majorVersion) v + 1) 0
MinorRevision -> Version' (view (cloneLens majorVersion) v) (view (cloneLens minorVersion) v + 1)
, addMonths (view (cloneLens monthsAfter) r) d
, view (cloneLens effective) r
, view (cloneLens parts) r
, view (cloneLens details) r
)
in NonEmpty.scanl next first (view (cloneLens revisions) m)
-- | The version of the manual: the version of its last amendment.
manualVersion :: OperationsManual -> Version
manualVersion m =
let (v, _, _, _, _) = NonEmpty.last (amendmentRecord m) in v
-- | The date of the manual: the date of its last amendment.
manualDate :: OperationsManual -> Month
manualDate m =
let (_, d, _, _, _) = NonEmpty.last (amendmentRecord m) in d
-- | The date by which the manual is next reviewed: 12 months after its date.
manualReviewDate :: OperationsManual -> Month
manualReviewDate =
addMonths 12 . manualDate