casa-reoc-0.1.0.0: src/ReOC/Render/OperationsManual/Holes.hs
{-# LANGUAGE OverloadedStrings #-}
{-# OPTIONS_GHC -Wall #-}
{- | The holes of the operations manual template. The hole @{{legal-name}}@
in @template/rpas-operations-manual.fodt@ is filled by 'holeLegalName', and so
on for every hole; the template is read when the package is compiled, and a
hole without a function fails to compile (see "ReOC.Render.Template").
Every function gives XML: text is escaped, and the holes of rows and
paragraphs give whole elements.
-}
module ReOC.Render.OperationsManual.Holes (
holeAbn,
holeAircraftRows,
holeAlcoholHours,
holeAmendmentRows,
holeAssociatedEquipment,
holeBackupInterval,
holeBatteryReserve,
holeCeoArn,
holeCeoName,
holeCheckingMonths,
holeCheckingOnlyRp,
holeChiefReplInstructorRow,
holeCrewing,
holeCrpArn,
holeCrpDateApproved,
holeCrpName,
holeCrpRadio,
holeDutyHours,
holeFleetOverview,
holeFlightTermination,
holeIndependentReview,
holeIndependentReviewYears,
holeInspectionHours,
holeInspectionMonths,
holeKeyPersonnelQualifications,
holeKeyPersonnelVacancy,
holeLegalName,
holeManufacturerInstructions,
holeManufacturerMaintenance,
holeMcArn,
holeMcName,
holeMultipleKeyPositions,
holeOperationalHeadquarters,
holeOrganisationArn,
holeOrganisationEmail,
holeOrganisationName,
holeOrganisationPhone,
holeOrganisationStructure,
holeOrganisationalDiagram,
holeOrganisationalDiagramNote,
holePeriodicInspectionItems,
holePersonnelPreface,
holePersonnelReference,
holeRecencyDays,
holeRecencyFlights,
holeRefresherMonths,
holeRegisteredOffice,
holeReplTrainingInternal,
holeReplTrainingOverview,
holeRestHours,
holeReviewDate,
holeRiskRegisterRows,
holeRpaRegisterRows,
holeServices,
holeTradingName,
holeTransponderFit,
holeTypeSpecificProcedures,
holeVersion,
holeVersionDate,
singlePersonOrganisation,
weightLimitText,
) where
import Data.Foldable (toList)
import Data.List (nub)
import Data.Maybe (isJust, mapMaybe)
import Data.Text (Text)
import qualified Data.Text as Text
import Numeric.Natural (Natural)
import ReOC.Aircraft (heaviestGrams, operatedTypes, rpaName, rpaTypes)
import ReOC.Amendment (amendmentRecord, manualDate, manualReviewDate, manualVersion)
import ReOC.Model
import ReOC.Personnel (holders, keyPositions, nominatedCEO, nominatedCRI, nominatedCRP, nominatedMC, soleHolder)
import ReOC.Render.Odf (bulletList, cell, heading, nestedBulletList, paragraph, paragraphXml, row)
import ReOC.Render.OperationsManual.Diagram (organisationalDiagramFrame)
import ReOC.Render.Text
import ReOC.Risk (consequenceValue, keyPositionAbbreviation, likelihoodValue, riskLevelOf, riskRating, riskReviewDue)
-- | Escaped text.
text :: Text -> Text
text =
escapeXml
organisationName :: ReOC -> Text
organisationName =
formTextText . get (operator . company . companyName)
nameOf :: Nominee -> Text
nameOf =
formTextText . get (person . fullName)
arnOf :: Nominee -> Text
arnOf =
arnText . get (person . arn)
{- | Whether the operator is one person: one person holds every key position,
is the only remote pilot, and conducts only solo operations.
-}
singlePersonOrganisation :: ReOC -> Bool
singlePersonOrganisation r =
isJust (soleHolder r)
&& get (operationsManual . pilots) r == CRPIsOnlyRemotePilot
&& get (operationsManual . crew) r == SoloOperationsOnly
-- The key positions, abbreviated, for the sentences that list them.
positionsAbbreviated :: ReOC -> Text
positionsAbbreviated =
andList . map (\(a, _, _) -> a) . keyPositions
-- | The legal name of the company.
holeLegalName :: ReOC -> Text
holeLegalName =
text . legalName . get (operator . company)
-- | The name of the company, without @Pty Ltd@.
holeOrganisationName :: ReOC -> Text
holeOrganisationName =
text . organisationName
-- | The version of the manual: the version of its last amendment.
holeVersion :: ReOC -> Text
holeVersion =
text . versionText . manualVersion . get operationsManual
-- | The date of the manual: the date of its last amendment.
holeVersionDate :: ReOC -> Text
holeVersionDate =
text . monthText . manualDate . get operationsManual
-- | The date by which the manual is next reviewed: 12 months after its date.
holeReviewDate :: ReOC -> Text
holeReviewDate =
text . monthText . manualReviewDate . get operationsManual
holeCeoName, holeCeoArn, holeCrpName, holeCrpArn, holeMcName, holeMcArn :: ReOC -> Text
holeCeoName = text . nameOf . nominatedCEO . get (operator . keyPersonnel)
holeCeoArn = text . arnOf . nominatedCEO . get (operator . keyPersonnel)
holeCrpName = text . nameOf . nominatedCRP . get (operator . keyPersonnel)
holeCrpArn = text . arnOf . nominatedCRP . get (operator . keyPersonnel)
holeMcName = text . nameOf . nominatedMC . get (operator . keyPersonnel)
holeMcArn = text . arnOf . nominatedMC . get (operator . keyPersonnel)
-- | The ARN of the company.
holeOrganisationArn :: ReOC -> Text
holeOrganisationArn =
text . arnText . get (operator . company . arn)
-- | The phone number of the company.
holeOrganisationPhone :: ReOC -> Text
holeOrganisationPhone =
text . phoneNumberFormatted . get (operator . company . phoneNumber)
-- | The email address of the company.
holeOrganisationEmail :: ReOC -> Text
holeOrganisationEmail =
text . emailAddressText . get (operator . company . emailAddress)
-- | The registered office of the company.
holeRegisteredOffice :: ReOC -> Text
holeRegisteredOffice =
text . addressText . get (operator . company . registeredOffice)
-- | The ABN of the company.
holeAbn :: ReOC -> Text
holeAbn =
text . abnFormatted . get (operator . company . abn)
-- | The operational headquarters of the company.
holeOperationalHeadquarters :: ReOC -> Text
holeOperationalHeadquarters r =
text $ case get (operator . company . operationalHeadquarters) r of
AtRegisteredOffice -> "As for the registered office address"
OperationalHeadquartersAddress a -> addressText a
-- | The trading name of the company: its registered business name, if it has one.
holeTradingName :: ReOC -> Text
holeTradingName r =
text (maybe "Nil – operates under the name of the legal entity" formTextText (get (operator . company . businessName) r))
-- | The date on which CASA approved the chief remote pilot: an application is not yet approved.
holeCrpDateApproved :: ReOC -> Text
holeCrpDateApproved _ =
text "Pending CASA approval"
-- | The categories of RPA of the ReOC, in prose.
fleetCategories :: ReOC -> Text
fleetCategories =
listing . nub . map (rpaCategoryProse . get category) . toList . rpaTypes
{- | The weight that no RPA of the ReOC is heavier than: 2 kg, 7 kg or 25 kg,
the limits that the regulations and the RePL weight classes use.
>>> weightLimitText 1999
"2 kg"
>>> weightLimitText 6500
"7 kg"
-}
weightLimitText :: Natural -> Text
weightLimitText g
| g <= 2000 = "2 kg"
| g <= 7000 = "7 kg"
| otherwise = "25 kg"
-- | The RPA of the operator, in the sentence of the organisational overview: "using ...".
holeFleetOverview :: ReOC -> Text
holeFleetOverview r =
let airframeCount = sum (map (length . get airframes) (toList (operatedTypes r)))
limit = weightLimitText (heaviestGrams r)
in text $
if airframeCount == 1
then "a " <> fleetCategories r <> " RPA with a gross weight of not more than " <> limit
else fleetCategories r <> " RPA with gross weights of not more than " <> limit
-- | The end of the sentence of the organisational overview that lists what the operator does not do.
holeReplTrainingOverview :: ReOC -> Text
holeReplTrainingOverview r =
let limit = weightLimitText (heaviestGrams r)
in text $ case get maybeTrainingMaterial r of
Nothing -> "does not operate RPA heavier than " <> limit <> ", and does not conduct RePL training."
Just _ ->
"and does not operate RPA heavier than "
<> limit
<> ". "
<> organisationName r
<> " conducts RePL training under its RePL Training Manual, which sets out its RePL training documented practices and procedures, and the syllabus and curriculum of each course."
-- | The sentence of Section 1.5.1 about RePL training.
holeReplTrainingInternal :: ReOC -> Text
holeReplTrainingInternal r =
text $ case get maybeTrainingMaterial r of
Nothing -> "Internal training is not RePL training; " <> organisationName r <> " does not conduct training for the grant of a RePL."
Just _ -> "Internal training is not RePL training; RePL training is conducted under the RePL Training Manual of " <> organisationName r <> "."
-- | The paragraph of the preface about who holds the key positions.
holePersonnelPreface :: ReOC -> Text
holePersonnelPreface r =
let titles = andList [t <> " (" <> a <> ")" | (a, t, _) <- keyPositions r]
in paragraph "Standard" $
if singlePersonOrganisation r
then
organisationName r
<> " is a single-person organisation. At the date of this version, one individual holds the positions of "
<> titles
<> ", and is the organisation’s only remote pilot (RP). Where this manual allocates a duty to a position, that individual must perform the duty in the capacity of that position. Holding more than one position does not remove, combine or reduce any duty."
else
"At the date of this version, the positions of "
<> titles
<> " are held as set out in Section 1.2.1. "
<> ( case get (operationsManual . pilots) r of
CRPIsOnlyRemotePilot -> "The CRP is the organisation’s only remote pilot (RP). "
OtherRemotePilots -> organisationName r <> " also engages remote pilots (RP) other than the CRP. "
)
<> "Where this manual allocates a duty to a position, the holder of the position must perform the duty in the capacity of that position. Holding more than one position does not remove, combine or reduce any duty."
-- | The paragraph of the preface about whom the requirements of personnel apply to.
holePersonnelReference :: ReOC -> Text
holePersonnelReference r =
paragraph "Standard" $
if singlePersonOrganisation r
then "Where this manual refers to personnel, an RP or an operational crew member (OC), the requirement applies to the CRP when acting in that capacity and to any person subsequently engaged by " <> organisationName r <> "."
else "Where this manual refers to personnel, an RP or an operational crew member (OC), the requirement applies to every person engaged by " <> organisationName r <> " in that capacity, including key personnel when acting in that capacity."
-- | The paragraph of the organisational overview about the people of the operator.
holeOrganisationStructure :: ReOC -> Text
holeOrganisationStructure r =
let o = organisationName r
maintenance = "Maintenance beyond the user-level tasks listed in Section 3.2.1 is carried out by the RPA manufacturer or its approved service agents."
ceoIs =
case get (operator . keyPersonnel . chiefExecutive . directorStatus) r of
SoleDirector -> "Its sole director"
Director -> "One of its directors"
NotADirector -> "One individual"
in paragraph "Standard" $
if singlePersonOrganisation r
then
o
<> " is a single-person organisation. "
<> ceoIs
<> " holds the positions of "
<> positionsAbbreviated r
<> " and is the organisation’s only RP. There are no employees, ground crew or contracted remote pilots, so all operations are solo operations. "
<> maintenance
else
Text.unwords [nameOf n <> " holds the " <> positionWord ps <> " " <> andList ps <> "." | (n, ps) <- holders r]
<> " "
<> ( case get (operationsManual . pilots) r of
CRPIsOnlyRemotePilot -> "The CRP is the organisation’s only RP. "
OtherRemotePilots -> o <> " also engages RPs, who report to the CRP. "
)
<> ( case get (operationsManual . crew) r of
SoloOperationsOnly -> "All operations are solo operations. "
SoloAndMultiCrewOperations -> "Operations are conducted as solo operations or with operational crew members (multi-crew operations). "
)
<> maintenance
where
positionWord ps = if length ps == 1 then "position of" else "positions of"
-- | The organisational diagram.
holeOrganisationalDiagram :: ReOC -> Text
holeOrganisationalDiagram =
organisationalDiagramFrame
-- | The paragraph under the organisational diagram.
holeOrganisationalDiagramNote :: ReOC -> Text
holeOrganisationalDiagramNote r =
let o = organisationName r
in paragraph "Standard" $
case (soleHolder r, get (operationsManual . pilots) r) of
(Just _, CRPIsOnlyRemotePilot) ->
"All positions shown in Figure 1 are held by the one individual listed in Section 1.2.1. The remote pilot position is held by the CRP; any additional RP engaged by " <> o <> " reports to the CRP."
(_, CRPIsOnlyRemotePilot) ->
"The holder of each position shown in Figure 1 is listed in Section 1.2.1. The remote pilot position is held by the CRP; any additional RP engaged by " <> o <> " reports to the CRP."
(_, OtherRemotePilots) ->
"The holder of each position shown in Figure 1 is listed in Section 1.2.1. Each RP engaged by " <> o <> " reports to the CRP."
-- The licences and qualifications of a holder, with the RePL of the chief remote pilot first.
qualificationsOf :: ReOC -> Nominee -> [Text] -> [Text]
qualificationsOf r n ps =
let origin =
case get (operator . keyPersonnel . chiefPilot . rePLOrigin) r of
PPLTheory -> "on the basis of private pilot licence (PPL) theory"
RePLTraining o -> "through RePL training with " <> formTextText o
repl = "a remote pilot licence (RePL) for " <> fleetCategories r <> " RPA, obtained " <> origin
in [repl | "CRP" `elem` ps] <> map text1Text (get otherQualifications n)
-- | The paragraphs about the qualifications and experience of each holder of a key position.
holeKeyPersonnelQualifications :: ReOC -> Text
holeKeyPersonnelQualifications r =
let legal = legalName (get (operator . company) r)
ceo = nominatedCEO (get (operator . keyPersonnel) r)
directorOf n =
if n == ceo
then case get (operator . keyPersonnel . chiefExecutive . directorStatus) r of
SoleDirector -> Just ("the sole director of " <> legal)
Director -> Just ("a director of " <> legal)
NotADirector -> Nothing
else Nothing
sentence subject n ps =
let quals = qualificationsOf r n ps
experience = text1Text (get aviationExperience n)
has =
if null quals
then "has " <> experience
else "holds " <> listing quals <> ", with " <> experience
in subject <> " " <> maybe has (\d -> "is " <> d <> " and " <> has) (directorOf n) <> "."
in case (singlePersonOrganisation r, holders r) of
(True, [(n, ps)]) -> paragraph "Standard" (sentence "The nominated individual" n ps)
(_, hs) -> Text.concat [paragraph "Standard" (sentence (nameOf n <> " (" <> andList ps <> ")") n ps) | (n, ps) <- hs]
-- | The section about holding more than one key position, if anyone does.
holeMultipleKeyPositions :: ReOC -> Text
holeMultipleKeyPositions r =
let multiple = [(n, ps) | (n, ps) <- holders r, length ps > 1]
who =
case multiple of
[(_, ps)] | isJust (soleHolder r) -> "One individual holds the " <> andList ps <> " positions. That individual must:"
[(n, ps)] -> nameOf n <> " holds the " <> andList ps <> " positions, and must:"
_ -> Text.unwords [nameOf n <> " holds the " <> andList ps <> " positions." | (n, ps) <- multiple] <> " Each of them must:"
in if null multiple
then ""
else
heading 4 "Holding of multiple key positions"
<> paragraph "Standard" who
<> bulletList
[ "perform each duty in the capacity of the relevant position and record the decision in the relevant record – for example, the MC’s release to service in the RPAS Technical Log and the CRP’s flight authorisation in the Flight Record"
, "not omit a check on the assumption that it has been completed in another capacity"
, "plan workload so that there is enough time to perform the duties of each position before, during and after operations"
, "seek an independent review by a suitably experienced person (for example, the CRP of another ReOC holder) where a conflict of interest, or an occurrence, makes self-review unreliable"
, "cease operations while unable to perform the duties of any key position."
]
-- | The sentence of Section 1.2.3 about a vacant key position.
holeKeyPersonnelVacancy :: ReOC -> Text
holeKeyPersonnelVacancy r =
text $
if isJust (soleHolder r)
then "Because one individual holds all key positions, " <> organisationName r <> " must not conduct operations under the ReOC while any key position is vacant or its holder is unable to perform the duties of the position."
else organisationName r <> " must not conduct operations under the ReOC while any key position is vacant, unless approved by CASA."
-- | The start of the sentence of Section 1.6.1 about the independent review of the audit.
holeIndependentReview :: ReOC -> Text
holeIndependentReview r =
text $ case get (operationsManual . pilots) r of
CRPIsOnlyRemotePilot -> "Because the CRP audits activities they perform themselves, the CRP should arrange"
OtherRemotePilots -> "The CRP should arrange"
-- | The sentence of Section 1.6.2 about the checking event of a CRP who is the only RP.
holeCheckingOnlyRp :: ReOC -> Text
holeCheckingOnlyRp r =
text $ case get (operationsManual . pilots) r of
CRPIsOnlyRemotePilot -> "While the CRP is the only RP, the checking event is a proficiency check flight flown by the CRP against the flight exercises at Appendix G2. "
OtherRemotePilots -> ""
-- | The sentence of Section 2.4.1 that names the manufacturer’s instructions of each type of RPA.
holeManufacturerInstructions :: ReOC -> Text
holeManufacturerInstructions r =
let ts = toList (rpaTypes r)
instructions :: RPAType -> Text
instructions t = "the current " <> text1Text (get userManual t)
in text $ case ts of
[t] -> "For the " <> rpaName t <> ", the manufacturer’s instructions are " <> instructions t <> ", a copy of which (electronic or printed) must be available to the RP during operations."
_ ->
"The manufacturer’s instructions are: "
<> Text.intercalate "; " ["for the " <> rpaName t <> ", " <> instructions t | t <- ts]
<> ". A copy of the instructions for the RPA being operated (electronic or printed) must be available to the RP during operations."
-- | The sentence of Section 2.4.3 about the chief remote pilot’s qualification to use an aeronautical radio.
holeCrpRadio :: ReOC -> Text
holeCrpRadio r =
text $ case get (operator . keyPersonnel . chiefPilot . radio) r of
FlightCrewLicence -> "The CRP holds a flight crew licence issued under Part 61 of CASR and is qualified to use an aeronautical radio."
RadioOperatorCertificate -> "The CRP holds an aeronautical radio operator certificate issued under Part 64 of CASR and is qualified to use an aeronautical radio."
NoRadioQualification -> "The CRP is not qualified to use an aeronautical radio. An operation that requires an aeronautical radio must be conducted by an RP who is qualified under Part 61 or Part 64 of CASR."
-- Which types of RPA have a property, as a sentence: all, none, or some.
typesSentence :: ReOC -> (RPAType -> Bool) -> Text -> Text -> Text -> Text
typesSentence r p oneHas oneHasNot verb =
let ts = toList (rpaTypes r)
yes = [rpaName t | t <- ts, p t]
no = [rpaName t | t <- ts, not (p t)]
o = organisationName r
in case (ts, yes, no) of
([_], [], _) -> "The RPA operated by " <> o <> " " <> oneHasNot <> "."
([_], _, []) -> "The RPA operated by " <> o <> " " <> oneHas <> "."
(_, [], _) -> "No RPA operated by " <> o <> " " <> verb <> "."
_ -> "The " <> listing yes <> " " <> (if length yes == 1 then oneHas else Text.replace "is " "are " oneHas) <> (if null no then "." else "; the " <> listing no <> " " <> (if length no == 1 then oneHasNot else Text.replace "is " "are " oneHasNot) <> ".")
-- | The sentence of Section 2.4.4 about the transponders fitted to the RPA.
holeTransponderFit :: ReOC -> Text
holeTransponderFit r =
text $
typesSentence
r
(\t -> get transponderCarriage t == TransponderFitted)
"is fitted with a transponder or ADS-B (out)"
"is not fitted with a transponder or ADS-B (out)"
"is fitted with a transponder or ADS-B (out)"
-- | The sentence of Section 2.6.1 about solo and multi-crew operations.
holeCrewing :: ReOC -> Text
holeCrewing r =
text $ case get (operationsManual . crew) r of
SoloOperationsOnly -> "All " <> organisationName r <> " operations are currently solo operations, and ANCA applies."
SoloAndMultiCrewOperations -> organisationName r <> " conducts solo and multi-crew operations; ANCA applies to solo operations and CANCA to multi-crew operations."
-- | The sentence of Section 2.6.2 about the flight termination systems fitted to the RPA.
holeFlightTermination :: ReOC -> Text
holeFlightTermination r =
let fitted t =
case get flightTermination t of
NoFlightTerminationSystem -> Nothing
FlightTerminationSystem d -> Just (rpaName t, text1Text d)
systems = mapMaybe fitted (toList (rpaTypes r))
in text $
typesSentence
r
(isJust . fitted)
"is fitted with a dedicated flight termination system"
"is not fitted with a dedicated flight termination system"
"is fitted with a dedicated flight termination system"
<> Text.concat [" The flight termination system of the " <> t <> ": " <> d <> "." | (t, d) <- systems]
-- | The sentence of Section 3.1.1 that lists what the periodic inspection covers.
holePeriodicInspectionItems :: ReOC -> Text
holePeriodicInspectionItems r =
let items :: RPAType -> Text
items t = listing (map text1Text (toList (get inspectionItems t)))
in text $ case toList (rpaTypes r) of
[t] -> "The periodic inspection covers " <> items t <> "."
ts -> "The periodic inspection covers, " <> Text.intercalate "; " ["for the " <> rpaName t <> ", " <> items t | t <- ts] <> "."
-- | Who carries out maintenance beyond the items authorised for an RP: the manufacturers.
holeManufacturerMaintenance :: ReOC -> Text
holeManufacturerMaintenance r =
text $ case nub (map (text1Text . get rpaMake) (toList (rpaTypes r))) of
[m] -> m <> " or its approved service agents"
ms -> "the manufacturer of the RPA (" <> listing ms <> ") or its approved service agents"
-- | Appendix C: the type-specific procedures of each type of RPA.
holeTypeSpecificProcedures :: ReOC -> Text
holeTypeSpecificProcedures r =
let ts = toList (rpaTypes r)
reserve = percentageText (get (operationsManual . policies . batteryReserve) r)
procedures t =
let battery = "Plan each flight to land with not less than " <> reserve <> " battery remaining." <> maybe "" ((" " <>) . text1Text) (get batteryWarnings t)
actions = get emergencyActions t
in (if length ts > 1 then paragraphXml "Standard" ("<text:span text:style-name=\"Strong_20_Emphasis\">" <> text (rpaName t) <> "</text:span>") else "")
<> paragraph "Standard" (organisationName r <> " operates the " <> rpaName t <> " IAW the " <> text1Text (get userManual t) <> ". No alternative operating procedures have been approved. The following requirements supplement the manufacturer’s instructions.")
<> paragraph "Standard" "Before flight:"
<> bulletList (map text1Text (get beforeFlight t) <> [battery])
<> ( if null actions
then ""
else
paragraph "Standard" "Emergency actions:"
<> nestedBulletList
[ (text1Text (get situation a) <> " – " <> text1Text (get response a), map text1Text (get actionSteps a))
| a <- actions
]
)
in Text.concat (map procedures ts)
holeRecencyFlights, holeRecencyDays, holeRefresherMonths, holeAlcoholHours, holeRestHours, holeDutyHours :: ReOC -> Text
holeRecencyFlights = text . quantity "flight" "flights" . get (operationsManual . policies . recencyFlights)
holeRecencyDays = text . quantity "day" "days" . get (operationsManual . policies . recencyDays)
holeRefresherMonths = text . quantity "month" "months" . get (operationsManual . policies . refresherMonths)
holeAlcoholHours = text . quantity "hour" "hours" . get (operationsManual . policies . alcoholHours)
holeRestHours = text . quantity "consecutive hour" "consecutive hours" . get (operationsManual . policies . restHours)
holeDutyHours = text . quantity "hour" "hours" . get (operationsManual . policies . dutyHours)
holeInspectionMonths, holeInspectionHours, holeBatteryReserve, holeBackupInterval :: ReOC -> Text
holeInspectionMonths = text . quantity "month" "months" . get (operationsManual . policies . inspectionMonths)
holeInspectionHours = text . quantity "hour" "hours" . get (operationsManual . policies . inspectionHours)
holeBatteryReserve = text . percentageText . get (operationsManual . policies . batteryReserve)
holeBackupInterval = text . backupIntervalText . get (operationsManual . policies . backupFrequency)
holeIndependentReviewYears, holeCheckingMonths :: ReOC -> Text
holeIndependentReviewYears = text . quantity "year" "years" . get (operationsManual . policies . independentReviewYears)
holeCheckingMonths = text . quantity "month" "months" . get (operationsManual . policies . checkingMonths)
-- | The services of the operator.
holeServices :: ReOC -> Text
holeServices =
text . listing . map text1Text . toList . get (operationsManual . services)
-- | The rows of the amendment record.
holeAmendmentRows :: ReOC -> Text
holeAmendmentRows =
foldMap amendmentRow . amendmentRecord . get operationsManual
where
amendmentRow (v, d, e, p, x) =
row "Table1.1" $
map
(cell "Table1.A2" "P29")
[versionText v, monthText d, text1Text e, text1Text p, text1Text x]
-- | The row of the chief RePL instructor in the list of key personnel, where RePL training is conducted.
holeChiefReplInstructorRow :: ReOC -> Text
holeChiefReplInstructorRow r =
case get maybeTrainingMaterial r of
Nothing -> ""
Just t ->
let n = nominatedCRI (get (operator . keyPersonnel) r) t
in row
"Table5.4"
[ cell "Table5.A2" "Table_20_text" "Chief RePL instructor"
, cell "Table5.B2" "Table_20_text" (nameOf n)
, cell "Table5.B2" "Table_20_text" (arnOf n)
, cell "Table5.D2" "Table_20_text" "Pending CASA approval"
]
-- | The rows of the risk register: one for each risk, then blank rows, to at least 27 rows.
holeRiskRegisterRows :: ReOC -> Text
holeRiskRegisterRows r =
let risks = toList (get (operationsManual . riskRegister) r)
in Text.concat (zipWith riskRow [1 :: Int ..] risks)
<> Text.concat (replicate (27 - length risks) blankRiskRow)
where
riskRow :: Int -> Risk -> Text
riskRow i k =
let initial = get initialRisk k
residual = get residualRisk k
rating a =
cell
( case riskLevelOf a of
High -> "ReOCRiskHigh"
Medium -> "ReOCRiskMedium"
Low -> "ReOCRiskLow"
)
"P28"
(riskRating a)
plain column = cell ("Table17." <> column <> "2") "P28"
in row
"Table17.2"
[ plain "A" (Text.pack ('R' : (if i < 10 then "0" else "") <> show i))
, plain "B" (monthText (get dateEntered k))
, plain "C" (text1Text (get hazard k))
, plain "D" (text1Text (get riskDescription k))
, plain "E" (text1Text (get existingControls k))
, plain "F" (likelihoodValue (get riskLikelihood initial))
, plain "G" (consequenceValue (get riskConsequence initial))
, rating initial
, plain "I" (text1Text (get additionalControls k))
, plain "J" (likelihoodValue (get riskLikelihood residual))
, plain "K" (consequenceValue (get riskConsequence residual))
, rating residual
, plain "M" (keyPositionAbbreviation (get riskOwner k))
, plain "N" (monthText (riskReviewDue k))
]
blankRiskRow =
row "Table17.4" [cell ("Table17." <> column <> "14") "P28" "" | column <- map Text.singleton ['A' .. 'N']]
-- Each RPA of the ReOC, with its type.
aircraftOf :: ReOC -> [(RPAType, Aircraft)]
aircraftOf r =
nub [(get rpaType o, a) | o <- toList (operatedTypes r), a <- toList (get airframes o)]
-- | The rows of the list of RPA in Appendix B.
holeAircraftRows :: ReOC -> Text
holeAircraftRows =
foldMap aircraftRow . aircraftOf
where
aircraftRow :: (RPAType, Aircraft) -> Text
aircraftRow (t, a) =
row "SFTable1.1" $
zipWith
(\column v -> cell ("SFTable1." <> column <> "2") "P33" v)
["A", "B", "C", "D", "E"]
[ text1Text (get rpaMake t)
, text1Text (get rpaModel t)
, rpaCategoryText (get category t)
, weightText (grossWeightGrams (get maximumGrossWeight t))
, text1Text (get serialNumber a)
]
-- | The paragraphs of the equipment associated with each RPA, in Appendix B.
holeAssociatedEquipment :: ReOC -> Text
holeAssociatedEquipment r =
let all' = aircraftOf r
described :: Aircraft -> Text
described a =
Text.intercalate
"; "
[ text1Text (get equipmentDescription e) <> ", serial number " <> text1Text (get serialNumber e)
| e <- get associatedEquipment a
]
in Text.concat
[ paragraph "Standard" $
( if length all' == 1
then "Associated equipment: "
else "Associated equipment of the " <> rpaName t <> " with serial number " <> text1Text (get serialNumber a) <> ": "
)
<> described a
<> "."
| (t, a) <- all'
, not (null (get associatedEquipment a))
]
-- | The rows of the RPA register (Form F9): one for each RPA, then 4 blank rows.
holeRpaRegisterRows :: ReOC -> Text
holeRpaRegisterRows r =
foldMap registerRow (aircraftOf r) <> Text.concat (replicate 4 (registerCells (replicate 7 "")))
where
registerRow :: (RPAType, Aircraft) -> Text
registerRow (t, a) =
registerCells
[ text1Text (get rpaMake t)
, text1Text (get rpaModel t)
, text1Text (get serialNumber a)
, weightText (grossWeightGrams (get maximumGrossWeight t))
, ""
, ""
, ""
]
registerCells =
row "SFTable12.1"
. zipWith (\column v -> cell ("SFTable12." <> column <> "2") "P33" v) ["A", "B", "C", "D", "D", "D", "G"]