diff options
author | Matthew Lemon <lemon@matthewlemon.com> | 2020-12-08 13:35:39 +0000 |
---|---|---|
committer | Matthew Lemon <lemon@matthewlemon.com> | 2020-12-08 13:35:39 +0000 |
commit | 4457cd61f10565c5fa1abafc5e763fb676c4293f (patch) | |
tree | 85903a7131eac2d6b7b10f0ef9d8fb2f123c01fe | |
parent | 4c6a364551196833aef9d4ad74ec29510f5068ae (diff) |
fixed missing datamaps pkg
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | datamaps/config.go | 267 | ||||
-rw-r--r-- | datamaps/config_test.go | 35 | ||||
-rw-r--r-- | datamaps/db.go | 267 | ||||
-rw-r--r-- | datamaps/db_test.go | 235 | ||||
-rwxr-xr-x | datamaps/main | bin | 0 -> 13848736 bytes | |||
-rw-r--r-- | datamaps/reader.go | 293 | ||||
-rw-r--r-- | datamaps/reader_test.go | 251 | ||||
-rw-r--r-- | datamaps/testdata/datamap.csv | 1948 | ||||
-rw-r--r-- | datamaps/testdata/datamap_for_master_test.csv | 19 | ||||
-rw-r--r-- | datamaps/testdata/datamap_matches_test_template.csv | 10 | ||||
-rw-r--r-- | datamaps/testdata/test_template.xlsm | bin | 0 -> 9390 bytes | |||
-rw-r--r-- | datamaps/testdata/test_template.xlsx | bin | 0 -> 9389 bytes | |||
-rw-r--r-- | datamaps/testdata/test_template2.xlsx | bin | 0 -> 9395 bytes | |||
-rw-r--r-- | datamaps/testdata/test_template3.xlsx | bin | 0 -> 9459 bytes | |||
-rw-r--r-- | datamaps/writer.go | 153 | ||||
-rw-r--r-- | datamaps/writer_test.go | 195 |
17 files changed, 3673 insertions, 1 deletions
@@ -2,7 +2,6 @@ .idea/* reader/testdata/test.db go.sum -/datamaps pkg/datamaps/testdata/test.db /main /bin/datamaps diff --git a/datamaps/config.go b/datamaps/config.go new file mode 100644 index 0000000..ec6f91e --- /dev/null +++ b/datamaps/config.go @@ -0,0 +1,267 @@ +package datamaps + +import ( + "log" + "os" + "path/filepath" +) + +const ( + configDirName = "datamaps" + dbName = "datamaps.db" +) + +// Help text. +const Usage = ` +usage: datamaps COMMAND [OPTIONS] + +-Managing datamap files- + +Command: datamap + +All datamap related actions. Before datamaps can do much, it must know about a datamap. +A datamap starts life as a CSV file with the format: + +cell_key,template_sheet,cell_reference,type +key1,sheet1,A10,TEXT +key2,sheet1,A11,NUMBER +... + +Options: + --import PATH Import a datamap the csv datamap at PATH + --datamapname NAME Name for imported datamap +` + +// mocking funcs in go https://stackoverflow.com/questions/19167970/mock-functions-in-go +// we only need the func signature to create the type. This is pretty weird, we're want to mock +// os.UserHomeDir so that we can set it to something like /tmp in our tests. Here we are creating +// two types: getUserConfigDir to represent the os.UserConfigDir function, dbPathChecker as a wrapper +// which which we can assign methods to that holds the value of the func os.UserConfigDir and the +// method, check(), which does the work, using the passed in func to determine the user $HOME/.config +// directory. +// Which is a lot of work for what it is, but it does make this testable and serves as an example +// of how things could be done in Go. + +// getUserConfigDir allows replaces os.UserConfigDir +// for testing purposes. +type getUserConfigDir func() (string, error) + +// DBPathChecker contains the func used to create the user config dir. +type DBPathChecker struct { + userConfig getUserConfigDir +} + +// NewDBPathChecker creates a DBPathChecker using whatever +// func you want as the argument, as long as it matches the +// type os.UserConfigDir. This makes it convenient for testing +// and was done as an experiment here to practice mocking in Go. +func NewDBPathChecker(h getUserConfigDir) *DBPathChecker { + return &DBPathChecker{userConfig: h} +} + +// Check returns true if the necessary config files (including +// the database) are in place - false if not +func (db *DBPathChecker) Check() bool { + userConfig, err := db.userConfig() + if err != nil { + log.Fatal(err) + } + dbPath := filepath.Join(userConfig, "datamaps.db") + if _, err := os.Stat(dbPath); os.IsNotExist(err) { + return false + } + return true +} + +// SetUp creates the config directory and requisite files +func SetUp() (string, error) { + dir, err := os.UserConfigDir() + if err != nil { + return "", err + } + // check if config folder exists + configPath := filepath.Join(dir, configDirName) + dbPath := filepath.Join(configPath, dbName) + if _, err := os.Stat(configPath); os.IsNotExist(err) { + log.Println("Config directory does not exist.") + log.Printf("Creating config directory %s.\n", configPath) + if err := os.Mkdir(filepath.Join(dir, "datamaps"), 0700); err != nil { + return "", err + } + } else { + log.Println("Config directory found.") + } + if _, err := os.Stat(dbPath); os.IsNotExist(err) { + log.Println("Database does not exist.") + _, err = os.Create(dbPath) + if err != nil { + return "", err + } + log.Printf("Creating database file at %s.\n", dbPath) + _, err := setupDB(dbPath) + if err != nil { + return "", err + } + } else { + log.Println("Database file found.") + } + return dir, nil +} + +func userConfigDir() (string, error) { + dir, err := os.UserConfigDir() + if err != nil { + return "", err + } + + configPath := filepath.Join(dir, configDirName) + + return configPath, nil +} + +func defaultDMPath() (string, error) { + dir, err := os.UserHomeDir() + if err != nil { + return "", err + } + + return filepath.Join(dir, "Documents", "datamaps"), nil +} + +func defaultXLSXPath() (string, error) { + dir, err := os.UserHomeDir() + if err != nil { + return "", err + } + + return filepath.Join(dir, "Documents", "datamaps", "import"), nil +} + +// Options for the whole CLI application. +type Options struct { + // Command is the main CLI sub-command (e.g. "datamap" handles all datamap + // operations and the flags that follow pertain only to that operation. + Command string + + // DBPath is the path to the database file. + DBPath string + + // DMPath is the path to a datamap file. + DMPath string + + // DMNane is the name of a datamap, whether setting or querying. + DMName string + + // XLSXPath is the path to a directory containing ".xlsx" files for + // importing. + XLSXPath string + + // ReturnName is the name of a Return, whether setting or querying. + ReturnName string + + // DMOverwrite is currently not used. + DMOverwrite bool + + // DMInitial is currently not used. + DMInitial bool + + // MasterOutPutPath is where the master.xlsx file is to be saved + MasterOutPutPath string +} + +func defaultOptions() *Options { + dbpath, err := userConfigDir() + if err != nil { + log.Fatalf("Unable to get user config directory %v", err) + } + + dmPath, err := defaultDMPath() + if err != nil { + log.Fatalf("unable to get default datamaps directory path: %v", err) + } + + xlsxPath, err := defaultXLSXPath() + if err != nil { + log.Fatalf("unable to get default XLSX directory path: %v", err) + } + + homeDir, err := os.UserHomeDir() + if err != nil { + log.Fatal("unable to get user home directory") + } + + return &Options{ + Command: "help", + DBPath: filepath.Join(dbpath, dbName), + DMPath: dmPath, + DMName: "Unnamed Datamap", + XLSXPath: xlsxPath, + ReturnName: "Unnamed Return", + DMOverwrite: false, + DMInitial: false, + MasterOutPutPath: filepath.Join(homeDir, "Desktop"), + } +} + +// nextString get the next string in a slice. +func nextString(args []string, i *int, message string) string { + if len(args) > *i+1 { + *i++ + } else { + log.Fatal(message) + } + + return args[*i] +} + +func processOptions(opts *Options, allArgs []string) { + if len(allArgs) == 0 { + allArgs = append(allArgs, "help") + } + switch allArgs[0] { + case "import": + opts.Command = "import" + case "help": + opts.Command = "help" + case "datamap": + opts.Command = "datamap" + case "setup": + opts.Command = "setup" + case "server": + opts.Command = "server" + case "createmaster": + opts.Command = "createmaster" + default: + log.Fatal("No relevant command provided.") + } + + restArgs := allArgs[1:] + + for i := 0; i < len(allArgs[1:]); i++ { + arg := restArgs[i] + switch arg { + case "--xlsxpath": + opts.XLSXPath = nextString(restArgs, &i, "xlsx directory path required") + case "--returnname": + opts.ReturnName = nextString(restArgs, &i, "return name required") + case "--import": + opts.DMPath = nextString(restArgs, &i, "import path required") + case "--datamapname": + opts.DMName = nextString(restArgs, &i, "datamap name required") + case "--overwrite": + opts.DMOverwrite = true + case "--initial": + opts.DMInitial = true + case "--masteroutputdir": + opts.MasterOutPutPath = nextString(restArgs, &i, "master output directory required") + } + } +} + +//ParseOptions for CLI. +func ParseOptions() *Options { + opts := defaultOptions() + processOptions(opts, os.Args[1:]) + + return opts +} diff --git a/datamaps/config_test.go b/datamaps/config_test.go new file mode 100644 index 0000000..dadaf6d --- /dev/null +++ b/datamaps/config_test.go @@ -0,0 +1,35 @@ +package datamaps + +import ( + "os" + "path/filepath" + "testing" +) + +// mocking funcs in go https://stackoverflow.com/questions/19167970/mock-functions-in-go + +func mockConfigDir() (string, error) { + return "/tmp/CONFIG/datamaps/", nil +} + +func TestDBDetect(t *testing.T) { + + cPath := filepath.Join("/tmp", "CONFIG", "datamaps") + t.Logf("%s\n", cPath) + if err := os.MkdirAll(cPath, 0700); err != nil { + t.Fatalf("cannot create temporary directory - %v", err) + } + + if _, err := os.Create(filepath.Join("/tmp", "CONFIG", "datamaps", "datamaps.db")); err != nil { + t.Fatalf("cannot open '/tmp/CONFIG/datamaps/databamps.db': %v", err) + } + defer func() { + os.RemoveAll(filepath.Join("/tmp", "CONFIG")) + }() + + dbpc := NewDBPathChecker(mockConfigDir) + h := dbpc.Check() + if !h { + t.Error("the db file should be found but isn't") + } +} diff --git a/datamaps/db.go b/datamaps/db.go new file mode 100644 index 0000000..296b1b2 --- /dev/null +++ b/datamaps/db.go @@ -0,0 +1,267 @@ +package datamaps + +import ( + "database/sql" + "errors" + "fmt" + "log" + "os" + "path" + "time" + + // Needed for the sqlite3 driver + _ "github.com/mattn/go-sqlite3" +) + +// setupDB creates the intitial database +func setupDB(path string) (*sql.DB, error) { + stmtBase := `DROP TABLE IF EXISTS datamap; + DROP TABLE IF EXISTS datamap_line; + DROP TABLE IF EXISTS return; + DROP TABLE IF EXISTS return_data; + + CREATE TABLE datamap( + id INTEGER PRIMARY KEY, + name TEXT, + date_created TEXT); + + CREATE TABLE datamap_line( + id INTEGER PRIMARY KEY, + dm_id INTEGER, + key TEXT NOT NULL, + sheet TEXT NOT NULL, + cellref TEXT, + FOREIGN KEY (dm_id) + REFERENCES datamap(id) + ON DELETE CASCADE + ); + + CREATE TABLE return( + id INTEGER PRIMARY KEY, + name TEXT, + date_created TEXT + ); + + CREATE TABLE return_data( + id INTEGER PRIMARY KEY, + dml_id INTEGER, + ret_id INTEGER, + filename TEXT, + value TEXT, + numfmt TEXT, + vFormatted TEXT, + FOREIGN KEY (dml_id) + REFERENCES datamap_line(id) + ON DELETE CASCADE + FOREIGN KEY (ret_id) + REFERENCES return(id) + ON DELETE CASCADE + ); + ` + if _, err := os.Create(path); err != nil { + return nil, err + } + db, err := sql.Open("sqlite3", path) + if err != nil { + return db, errors.New("Cannot open that damn database file") + } + + // We probably don't need pragma here but we have it for later. + pragma := "PRAGMA foreign_keys = ON;" + _, err = db.Exec(pragma) + if err != nil { + // log.Printf("%q: %s\n", err, pragma) + return nil, err + } + + _, err = db.Exec(stmtBase) + if err != nil { + // log.Printf("%q: %s\n", err, stmt_base) + return nil, err + } + + return db, nil +} + +// ImportToDB imports a directory of xlsx files to the database, using the datamap +// to filter the data. +func ImportToDB(opts *Options) error { + log.Printf("Importing files in %s as return named %s using datamap named %s.", opts.XLSXPath, opts.ReturnName, opts.DMName) + + target, err := getTargetFiles(opts.XLSXPath) + if err != nil { + return err + } + + db, err := sql.Open("sqlite3", opts.DBPath) + if err != nil { + return err + } + + for _, vv := range target { + // TODO: Do the work! + + if err := importXLSXtoDB(opts.DMName, opts.ReturnName, vv, db); err != nil { + return err + } + } + return nil +} + +// DatamapToDB takes a slice of datamapLine and writes it to a sqlite3 db file. +func DatamapToDB(opts *Options) error { + log.Printf("Importing datamap file %s and naming it %s.\n", opts.DMPath, opts.DMName) + + data, err := ReadDML(opts.DMPath) + if err != nil { + log.Fatal(err) + } + + d, err := sql.Open("sqlite3", opts.DBPath) + if err != nil { + return errors.New("Cannot open that damn database file") + } + + tx, err := d.Begin() + if err != nil { + return err + } + + pragma := "PRAGMA foreign_keys = ON;" + _, err = d.Exec(pragma) + if err != nil { + log.Printf("%q: %s\n", err, pragma) + return err + } + + stmtDm, err := tx.Prepare("INSERT INTO datamap (name, date_created) VALUES(?,?)") + if err != nil { + return err + } + + res, err := stmtDm.Exec(opts.DMName, time.Now()) + if err != nil { + return err + } + + lastID, err := res.LastInsertId() + if err != nil { + return err + } + + stmtDml, err := tx.Prepare("INSERT INTO datamap_line (dm_id, key, sheet, cellref) VALUES(?,?,?,?);") + if err != nil { + return err + } + + defer stmtDm.Close() + defer stmtDml.Close() + + for _, dml := range data { + _, err = stmtDml.Exec(lastID, dml.Key, dml.Sheet, dml.Cellref) + if err != nil { + return err + } + } + err = tx.Commit() + if err != nil { + return err + } + + return nil +} + +func importXLSXtoDB(dmName string, returnName string, file string, db *sql.DB) error { + // d, err := ExtractDBDatamap(dmName, file, db) + _, filename := path.Split(file) + d, err := ExtractDBDatamap(dmName, file, db) + if err != nil { + return err + } + log.Printf("Extracting from %s.\n", file) + + // If there is already a return with a matching name, use that. + rtnQuery, err := db.Prepare("select id from return where (return.name=?)") + if err != nil { + fmt.Errorf("cannot create a query to get the return - %v", err) + } + defer rtnQuery.Close() + + var retID int64 + err = rtnQuery.QueryRow(returnName).Scan(&retID) + if err != nil { + log.Printf("Couldn't find an existing return named '%s' so let's create it.\n", returnName) + } + + if retID == 0 { + stmtReturn, err := db.Prepare("insert into return(name, date_created) values(?,?)") + if err != nil { + fmt.Errorf("cannot prepare a statement to create a new return - %v", err) + } + defer stmtReturn.Close() + + res, err := stmtReturn.Exec(returnName, time.Now()) + if err != nil { + err := fmt.Errorf("%v\nCannot create %s", err, returnName) + log.Println(err.Error()) + os.Exit(1) + } + + retID, err = res.LastInsertId() + if err != nil { + fmt.Errorf("cannot get id of return - %v", err) + } + } + + // We're going to need a transaction for the big stuff + tx, err := db.Begin() + if err != nil { + fmt.Errorf("cannot start a database transaction - %v", err) + } + + for sheetName, sheetData := range d { + + for cellRef, cellData := range sheetData { + + dmlQuery, err := db.Prepare("select id from datamap_line where (sheet=? and cellref=?)") + if err != nil { + fmt.Errorf("cannot prepare a statement to get the datamap line - %v", err) + } + defer dmlQuery.Close() + dmlIDRow := dmlQuery.QueryRow(sheetName, cellRef) + + var dmlID *int + + if err := dmlIDRow.Scan(&dmlID); err != nil { + err := fmt.Errorf("cannot find a datamap_line row for %s and %s: %s", sheetName, cellRef, err) + log.Println(err.Error()) + } + + insertStmt, err := db.Prepare("insert into return_data (dml_id, ret_id, filename, value, numfmt, vFormatted) values(?,?,?,?,?,?)") + if err != nil { + fmt.Errorf("cannot insert row into return_data - %v", err) + } + defer insertStmt.Close() + + // Hack to fix bug in Libreoffice numformats for dates + if cellData.NumFmt == "DD/MM/YY" { + cellData.SetFormat("dd/mm/yy") + } + fValue, err := cellData.FormattedValue() + if err != nil { + fmt.Errorf("cannot get the formatted value for %#v, %v", cellData, err) + } + + _, err = insertStmt.Exec(dmlID, retID, filename, cellData.Value, cellData.NumFmt, fValue) + if err != nil { + fmt.Errorf("cannot execute statement to insert return data - %v", err) + } + } + } + + err = tx.Commit() + if err != nil { + return err + } + return nil +} diff --git a/datamaps/db_test.go b/datamaps/db_test.go new file mode 100644 index 0000000..87801a0 --- /dev/null +++ b/datamaps/db_test.go @@ -0,0 +1,235 @@ +package datamaps + +import ( + "database/sql" + "fmt" + "os" + "os/exec" + "strings" + "testing" +) + +var singleTarget string = "./testdata/test_template.xlsm" + +var opts = Options{ + DBPath: "./testdata/test.db", + DMName: "First Datamap", + DMPath: "./testdata/datamap_matches_test_template.csv", + XLSXPath: "./testdata/", +} + +func dbSetup() (*sql.DB, error) { + db, err := setupDB("./testdata/test.db") + if err != nil { + return nil, err + } + return db, nil +} + +func dbTeardown(db *sql.DB) { + db.Close() + os.Remove("./testdata/test.db") +} + +func TestOpenSQLiteFile(t *testing.T) { + + db, err := dbSetup() + if err != nil { + t.Fatal(err) + } + defer dbTeardown(db) + + stmt := `insert into datamap(id, name) values(1,'cock')` + _, err = db.Exec(stmt) + + if err != nil { + t.Errorf("Cannot add record to db") + } + + rows, err := db.Query("select name from datamap") + + if err != nil { + t.Errorf("Cannot run select statement") + } + + defer rows.Close() + + for rows.Next() { + var name string + err = rows.Scan(&name) + if err != nil { + t.Errorf("Cannot scan resulting row") + } + } +} + +func TestDatamapGoesIntoDB(t *testing.T) { + db, err := dbSetup() + if err != nil { + t.Fatal(err) + } + defer dbTeardown(db) + + if err := DatamapToDB(&opts); err != nil { + t.Errorf("unable to write datamap to database file because %v", err) + } +} + +// TestImportSimpleTemplate uses importXLSXtoDB() to import data from a +// populated template and then uses the sqlite3 executible to test the +// contents of the database. This does not test datamaps functionality +// in querying data in the database. +func TestImportSimpleTemplate(t *testing.T) { + + var tests = []struct { + sheet string + cellref string + value string + }{ + {"Introduction", "A1", "10"}, + {"Introduction", "C9", "Test Department"}, + {"Introduction", "C22", "VUNT"}, + {"Introduction", "J9", "Greedy Parrots"}, + {"Summary", "B3", "This is a string"}, + {"Summary", "B4", "2.2"}, + {"Another Sheet", "N34", "23"}, + {"Another Sheet", "DI15", "Rabbit Helga"}, + } + + db, err := dbSetup() + if err != nil { + t.Fatal(err) + } + defer dbTeardown(db) + + // We need a datamap in there. + if err := DatamapToDB(&opts); err != nil { + t.Fatalf("cannot open %s", opts.DMPath) + } + if err := importXLSXtoDB(opts.DMName, "TEST RETURN", singleTarget, db); err != nil { + t.Fatalf("Something wrong: %v", err) + } + + for _, test := range tests { + sql := fmt.Sprintf(`SELECT return_data.value FROM return_data, datamap_line + WHERE + (return_data.filename='test_template.xlsm' + AND datamap_line.cellref=%q + AND datamap_line.sheet=%q + AND return_data.dml_id=datamap_line.id);`, test.cellref, test.sheet) + + got, err := exec.Command("sqlite3", opts.DBPath, sql).Output() + if err != nil { + t.Fatalf("something wrong %v", err) + } + got_s := strings.TrimSuffix(string(got), "\n") + if strings.Compare(got_s, test.value) != 0 { + t.Errorf("we wanted %s in test_template.xlsm but got %s", test.value, got_s) + } + } +} + +// TestImportToDB uses ImportToDB() to import data from a +// directory of populated templates and then uses the sqlite3 executible to test the +// contents of the database. This does not test datamaps functionality +// in querying data in the database. +func TestImportToDB(t *testing.T) { + var tests = []struct { + filename string + sheet string + cellref string + value string + }{ + {"test_template.xlsm", "Introduction", "A1", "10"}, + {"test_template.xlsm", "Introduction", "C9", "Test Department"}, + {"test_template.xlsm", "Introduction", "C22", "VUNT"}, + {"test_template.xlsm", "Introduction", "J9", "Greedy Parrots"}, + {"test_template.xlsm", "Summary", "B3", "This is a string"}, + {"test_template.xlsm", "Summary", "B4", "2.2"}, + {"test_template.xlsm", "Another Sheet", "N34", "23"}, + {"test_template.xlsm", "Another Sheet", "DI15", "Rabbit Helga"}, + + {"test_template.xlsx", "Introduction", "A1", "10"}, + {"test_template.xlsx", "Introduction", "C9", "Test Department"}, + {"test_template.xlsx", "Introduction", "C22", "VUNT"}, + {"test_template.xlsx", "Introduction", "J9", "Greedy Parrots"}, + {"test_template.xlsx", "Summary", "B3", "This is a string"}, + {"test_template.xlsx", "Summary", "B4", "2.2"}, + {"test_template.xlsx", "Another Sheet", "N34", "23"}, + {"test_template.xlsx", "Another Sheet", "DI15", "Rabbit Helga"}, + + {"test_template2.xlsx", "Introduction", "A1", "10"}, + {"test_template2.xlsx", "Introduction", "C9", "Test Department"}, + {"test_template2.xlsx", "Introduction", "C22", "VUNT"}, + {"test_template2.xlsx", "Introduction", "J9", "Greedy Parrots"}, + {"test_template2.xlsx", "Summary", "B3", "This is a string"}, + {"test_template2.xlsx", "Summary", "B4", "2.2"}, + {"test_template2.xlsx", "Another Sheet", "N34", "23"}, + {"test_template2.xlsx", "Another Sheet", "DI15", "Rabbit Helga"}, + + {"test_template3.xlsx", "Introduction", "A1", "10"}, + {"test_template3.xlsx", "Introduction", "C9", "Test Department"}, + {"test_template3.xlsx", "Introduction", "C22", "VUNT"}, + {"test_template3.xlsx", "Introduction", "J9", "Greedy Parrots"}, + {"test_template3.xlsx", "Summary", "B3", "This is a string"}, + {"test_template3.xlsx", "Summary", "B4", "2.2"}, + {"test_template3.xlsx", "Another Sheet", "N34", "23"}, + {"test_template3.xlsx", "Another Sheet", "DI15", + "Printers run amok in the land of carnivores when bacchus rings 1009.ff faiioif !!!]=-=-1290909"}, + } + + db, err := dbSetup() + if err != nil { + t.Fatal(err) + } + + // We need a datamap in there. + if err := DatamapToDB(&opts); err != nil { + t.Fatalf("cannot open %s", opts.DMPath) + } + defer dbTeardown(db) + + if err := ImportToDB(&opts); err != nil { + t.Fatal(err) + } + + for _, test := range tests { + sql := fmt.Sprintf(`SELECT return_data.value FROM return_data, datamap_line + WHERE + (return_data.filename=%q + AND datamap_line.cellref=%q + AND datamap_line.sheet=%q + AND return_data.dml_id=datamap_line.id);`, test.filename, test.cellref, test.sheet) + + got, err := exec.Command("sqlite3", opts.DBPath, sql).Output() + if err != nil { + t.Fatalf("something wrong %v", err) + } + got_s := strings.TrimSuffix(string(got), "\n") + if strings.Compare(got_s, test.value) != 0 { + t.Errorf("we wanted value %q in file %s sheet %s %s but got %s", + test.value, test.filename, test.sheet, test.cellref, got_s) + } + } +} + +// TODO: + +// USING THE INDEX TO tests STRUCT WE COULD DO ALL THESE IN TEST ABOVE + +// Returns useful error messages when querying for stuff not in datamap +// func TestImportSimpleQueryValueNotInDatamap(t *testing.T) { +// var tests = []struct { +// sheet string +// cellref string +// value string +// }{ +// {"Summary", "B2", "20/10/19"}, // this is not referenced in datamap +// } +// } + +// TODO: +// When a date is returned from the spreadsheet it is an integer and needs +// to be handled appropriately. +// func TestValuesReturnedAsDates(t *testing.T) { +// } diff --git a/datamaps/main b/datamaps/main Binary files differnew file mode 100755 index 0000000..a781830 --- /dev/null +++ b/datamaps/main diff --git a/datamaps/reader.go b/datamaps/reader.go new file mode 100644 index 0000000..25e6c99 --- /dev/null +++ b/datamaps/reader.go @@ -0,0 +1,293 @@ +/* datmamaps packages handles datamap files and populated spreadsheets. + */ + +package datamaps + +import ( + "database/sql" + "encoding/csv" + "errors" + "fmt" + "io" + "io/ioutil" + "log" + "path/filepath" + "strings" + + // Required for the sqlite3 driver + _ "github.com/mattn/go-sqlite3" + + "github.com/tealeg/xlsx/v3" +) + +type ( + // sheetData is the data from the sheet. + sheetData map[string]extractedCell + + // FileData is the data from the file. + FileData map[string]sheetData + + // ExtractedData is the Extracted data from the file, filtered by a Datamap. + ExtractedData map[string]map[string]xlsx.Cell +) + +//datamapLine - a line from the datamap. +type datamapLine struct { + Key string + Sheet string + Cellref string +} + +//extractedCell is data pulled from a cell. +type extractedCell struct { + Cell *xlsx.Cell + Col string + Row int + Value string +} + +var ( + inner = make(sheetData) +) + +// ExtractedDatamapFile is a slice of datamapLine structs, each of which encodes a single line +// in the datamap file/database table. +type ExtractedDatamapFile []datamapLine + +//sheetInSlice is a helper which returns true +// if a string is in a slice of strings. +func sheetInSlice(list []string, key string) bool { + for _, x := range list { + if x == key { + return true + } + } + + return false +} + +//getSheetNames returns the number of Sheet field entries +// in a slice of datamapLine structs. +func getSheetNames(dmls ExtractedDatamapFile) []string { + var sheetNames []string + + for _, dml := range dmls { + if !sheetInSlice(sheetNames, dml.Sheet) { + sheetNames = append(sheetNames, dml.Sheet) + } + } + + return sheetNames +} + +// ReadDML returns a slice of datamapLine structs given a +// path to a datamap file. +func ReadDML(path string) (ExtractedDatamapFile, error) { + var s ExtractedDatamapFile + + data, err := ioutil.ReadFile(path) + + if err != nil { + return s, fmt.Errorf("Cannot find file: %s", path) + } + + r := csv.NewReader(strings.NewReader(string(data))) + + for { + record, err := r.Read() + if err == io.EOF { + break + } + + if err != nil { + return s, errors.New("Cannot read line %s") + } + + if record[0] == "cell_key" { + // this must be the header + continue + } + + dml := datamapLine{ + Key: strings.Trim(record[0], " "), + Sheet: strings.Trim(record[1], " "), + Cellref: strings.Trim(record[2], " ")} + s = append(s, dml) + } + + return s, nil +} + +// cellVisitor is used by datamaps.rowVisitor() and is called +// on every cell in the target xlsx file in order to extract +// the data. +func cellVisitor(c *xlsx.Cell) error { + x, y := c.GetCoordinates() + cellref := xlsx.GetCellIDStringFromCoords(x, y) + + // TODO: we need to store the c.NumFmt value here in the + // database so we can reply it again when we write the values + // to the master or elsewhere. We should keep the value itself + // in its unformatted state - i.e a date being something like 488594. + + ex := extractedCell{ + Cell: c, + Value: c.Value, + } + + inner[cellref] = ex + + return nil +} + +// rowVisitor is used as a callback by xlsx.sheet.ForEachRow(). It wraps +// a call to xlsx.Row.ForEachCell() which actually extracts the data. +func rowVisitor(r *xlsx.Row) error { + if err := r.ForEachCell(cellVisitor, xlsx.SkipEmptyCells); err != nil { + return err + } + return nil +} + +// ReadXLSX returns a file at path's data as a map, +// keyed on sheet name. All values are returned as strings. +// Paths to a datamap and the spreadsheet file required. +func ReadXLSX(path string) FileData { + wb, err := xlsx.OpenFile(path) + if err != nil { + fmt.Errorf("cannot open file at %s - %v", path, err) + } + + outer := make(FileData, 1) + + // get the data + for _, sheet := range wb.Sheets { + + if err := sheet.ForEachRow(rowVisitor); err != nil { + fmt.Errorf("cannot call ForEachRow() in sheet %s - %v", sheet.Name, err) + } + outer[sheet.Name] = inner + inner = make(sheetData) + } + + return outer +} + +// DatamapFromDB creates an ExtractedDatamapFile from the database given +// the name of a datamap. Of course, in this instance, the data is not +// coming from a datamap file (such as datamap.csv) but from datamap data +// previous stored in the database by DatamapToDB or similar. +func DatamapFromDB(name string, db *sql.DB) (ExtractedDatamapFile, error) { + + var out ExtractedDatamapFile + + query := ` + select + key, sheet, cellref + from datamap_line + join datamap on datamap_line.dm_id = datamap.id where datamap.name = ?; + ` + rows, err := db.Query(query, name) + if err != nil { + erstr := fmt.Sprintf("cannot query for datamap key, sheet and cellref - %v", err) + return nil, errors.New(erstr) + } + defer rows.Close() + + for rows.Next() { + var ( + key string + sheet string + cellref string + ) + if err := rows.Scan(&key, &sheet, &cellref); err != nil { + return nil, err + } + + out = append(out, datamapLine{Key: key, Sheet: sheet, Cellref: cellref}) + } + + return out, nil +} + +// ExtractDBDatamap uses a datamap named from the database db to extract values +// from the populated spreadsheet file file. +func ExtractDBDatamap(name string, file string, db *sql.DB) (ExtractedData, error) { + ddata, err := DatamapFromDB(name, db) // this will need to return an ExtractedDatamapFile + if err != nil { + erstr := fmt.Sprintf("cannot call DatamapFromDB() - %v", err) + return nil, errors.New(erstr) + } + if len(ddata) == 0 { + return nil, fmt.Errorf("there is no datamap in the database matching name '%s'. Try running 'datamaps datamap --import...'", name) + } + xdata := ReadXLSX(file) + + names := getSheetNames(ddata) + outer := make(ExtractedData, len(names)) + // var inner map[string]xlsx.Cell + + for _, s := range names { + outer[s] = make(map[string]xlsx.Cell) + } + + for _, i := range ddata { + sheet := i.Sheet + cellref := i.Cellref + + if val, ok := xdata[sheet][cellref]; ok { + outer[sheet][cellref] = *val.Cell + } + } + + return outer, nil +} + +// extract returns the file at path's data as a map, +// using the datamap as a filter, keyed on sheet name. All values +// are returned as strings. (Currently deprecated in favour of +// ExtractDBDatamap. +func extract(dm string, path string) ExtractedData { + xdata := ReadXLSX(path) + ddata, err := ReadDML(dm) + + if err != nil { + log.Fatal(err) + } + + names := getSheetNames(ddata) + outer := make(ExtractedData, len(names)) + inner := make(map[string]xlsx.Cell) + + for _, i := range ddata { + sheet := i.Sheet + cellref := i.Cellref + + if val, ok := xdata[sheet][cellref]; ok { + inner[cellref] = *val.Cell + outer[sheet] = inner + } + } + + return outer +} + +//getTargetFiles finds all xlsx and xlsm files in directory. +func getTargetFiles(path string) ([]string, error) { + if lastchar := path[len(path)-1:]; lastchar != string(filepath.Separator) { + return nil, fmt.Errorf("path must end in a %s character", string(filepath.Separator)) + } + + fullpath := strings.Join([]string{path, "*.xls[xm]"}, "") + output, err := filepath.Glob(fullpath) + + if err != nil { + return nil, err + } + + if output == nil { + return nil, fmt.Errorf("cannot find any xlsx files in %s", path) + } + + return output, nil +} diff --git a/datamaps/reader_test.go b/datamaps/reader_test.go new file mode 100644 index 0000000..e214930 --- /dev/null +++ b/datamaps/reader_test.go @@ -0,0 +1,251 @@ +package datamaps + +import ( + "os" + "testing" +) + +func TestReadDML(t *testing.T) { + d, _ := ReadDML("testdata/datamap.csv") + cases := []struct { + idx int + val string + }{ + {0, "Project/Programme Name"}, + {1, "Department"}, + {2, "Delivery Body"}, + } + + for _, c := range cases { + if got := d[c.idx].Key; got != c.val { + t.Errorf("The test expected %s, got %s.", c.val, d[c.idx].Key) + } + } +} + +func TestNoFileReturnsError(t *testing.T) { + // this file does not exist + _, err := ReadDML("/home/bobbins.csv") + // if we get no error, something has gone wrong + + if err == nil { + t.Errorf("Should have thrown error %s", err) + } +} + +func TestBadDMLLine(t *testing.T) { + _, err := ReadDML("/home/lemon/code/python/bcompiler-engine/tests/resources/datamap_empty_cols.csv") + + if err == nil { + t.Errorf("No error so test failed.") + } +} + +func TestGetSheetsFromDM(t *testing.T) { + slice, _ := ReadDML("testdata/datamap.csv") + sheetNames := getSheetNames(slice) + + if len(sheetNames) != 15 { + t.Errorf("The test expected 14 sheets in slice, got %d.", + len(sheetNames)) + } +} + +func TestReadXLSX(t *testing.T) { + d := ReadXLSX("testdata/test_template.xlsx") + cases := []struct { + sheet, cellref, val string + }{ + {"Summary", "A2", "Date:"}, + {"Summary", "IG10", "botticelli"}, + {"Another Sheet", "F5", "4.2"}, + {"Another Sheet", "J22", "18"}, + } + + for _, c := range cases { + got := d[c.sheet][c.cellref].Value + if got != c.val { + t.Errorf("The test expected %s in %s sheet to be %s "+ + " - instead it is %s.", c.cellref, c.sheet, c.val, d[c.sheet][c.cellref].Value) + } + } +} + +// func TestExtractWithDBDatamap(t *testing.T) { +// // setup - we need the datamap in the test database +// db, err := setupDB("./testdata/test.db") +// defer func() { +// db.Close() +// os.Remove("./testdata/test.db") +// }() + +// if err != nil { +// t.Fatal("Expected to be able to set up the database.") +// } + +// opts := Options{ +// DBPath: "./testdata/test.db", +// DMName: "First Datamap", +// DMPath: "./testdata/datamap.csv", +// } + +// if err := DatamapToDB(&opts); err != nil { +// t.Errorf("Unable to write datamap to database file because %v.", err) +// } + +// d := extractDBDatamap("First Datamap", "testdata/test_template.xlsx") +// } + +func TestDMLSliceFromDatabase(t *testing.T) { + // setup - we need the datamap in the test database + db, err := setupDB("./testdata/test.db") + defer func() { + db.Close() + os.Remove("./testdata/test.db") + }() + + if err != nil { + t.Fatal("Expected to be able to set up the database.") + } + + opts := Options{ + DBPath: "./testdata/test.db", + DMName: "First Datamap", + DMPath: "./testdata/datamap.csv", + } + + if err := DatamapToDB(&opts); err != nil { + t.Errorf("Unable to write datamap to database file because %v.", err) + } + + cases := []struct { + index int + key string + }{ + {0, "Project/Programme Name"}, + {1, "Department"}, + {2, "Delivery Body"}, + {3, "Stoogge value"}, + {4, "DRRDD - IPA ID Number"}, + {5, "Controls Project ID number"}, + {6, "Jokey Entry"}, + {7, "Parrots Name"}, + } + + data, _ := DatamapFromDB("First Datamap", db) + + for _, c := range cases { + got := data[c.index].Key + if got != c.key { + t.Errorf("The test expected %s but got %s\n", c.key, data[c.index].Key) + } + } + + if data[0].Key != "Project/Programme Name" { + t.Errorf("expected to see Project/Programme Name and got %q\n", data[0]) + } +} + +func TestExtractUsingDBDM(t *testing.T) { + // setup - we need the datamap in the test database + db, err := setupDB("./testdata/test.db") + defer func() { + db.Close() + os.Remove("./testdata/test.db") + }() + + if err != nil { + t.Fatal("Expected to be able to set up the database.") + } + + opts := Options{ + DBPath: "./testdata/test.db", + DMName: "First Datamap", + DMPath: "./testdata/datamap_matches_test_template.csv", + } + + if err := DatamapToDB(&opts); err != nil { + t.Errorf("Unable to write datamap to database file because %v.", err) + } + + d, _ := ExtractDBDatamap("First Datamap", "testdata/test_template.xlsx", db) + cases := []struct { + sheet, cellref, val string + }{ + {"Introduction", "C9", "Test Department"}, + {"Introduction", "J9", "Greedy Parrots"}, + {"Introduction", "A1", "10"}, + {"Introduction", "C22", "VUNT"}, + } + + for _, c := range cases { + got := d[c.sheet][c.cellref].Value + if got != c.val { + t.Errorf("test_template.xlsx: The test expected %s in %s sheet to be %s "+ + "- instead it is %s.", c.sheet, c.cellref, c.val, + d[c.sheet][c.cellref].Value) + } + } +} + +func TestExtract(t *testing.T) { + d := extract("testdata/datamap.csv", "testdata/test_template.xlsx") + cases := []struct { + sheet, cellref, val string + }{ + {"Introduction", "C9", "Test Department"}, + {"Introduction", "J9", "Greedy Parrots"}, + {"Introduction", "A1", "10"}, + {"Introduction", "C22", "VUNT"}, + } + + for _, c := range cases { + got := d[c.sheet][c.cellref].Value + if got != c.val { + t.Errorf("The test expected %s in %s sheet to be %s "+ + "- instead it is %s.", c.sheet, c.cellref, c.val, + d[c.sheet][c.cellref].Value) + } + } + + if d["Another Sheet"]["E26"].Value != "Integer:" { + t.Errorf("Expected E26 in Another Sheet sheet to be Integer: - instead it is %s", d["Another Sheet"]["E26"].Value) + } +} + +// func TestGetTargetFiles(t *testing.T) { +// // This is not a suitable test for parameterisation, but doing it this way anyway. +// type args struct { +// path string +// } +// tests := []struct { +// name string +// args args +// want []string +// wantErr bool +// }{ +// {"Get files in testdata", +// args{"./testdata/"}, +// []string{ +// "testdata/test_template.xlsm", +// "testdata/test_template.xlsx", +// "testdata/test_template2.xlsx", +// "testdata/test_template3.xlsx", +// }, +// false, +// }, +// } +// for _, tt := range tests { +// t.Log("Running the test") +// t.Run(tt.name, func(t *testing.T) { +// got, err := getTargetFiles(tt.args.path) +// if (err != nil) != tt.wantErr { +// t.Errorf("getTargetFiles() error = %v, wantErr %v", err, tt.wantErr) +// return +// } +// if !reflect.DeepEqual(got, tt.want) { +// t.Errorf("getTargetFiles() = %v, want %v", got, tt.want) +// } +// }) +// } +// } diff --git a/datamaps/testdata/datamap.csv b/datamaps/testdata/datamap.csv new file mode 100644 index 0000000..d13bd27 --- /dev/null +++ b/datamaps/testdata/datamap.csv @@ -0,0 +1,1948 @@ +cell_key,template_sheet,cellreference +Project/Programme Name,Introduction,C11 +Department ,Introduction,C9 +Delivery Body ,Introduction,C10 +Stoogge value,Another Sheet,E26 +DRRDD - IPA ID Number,Introduction,C12 +Controls Project ID number,Introduction,C13 +Jokey Entry,Introduction,A1 +Parrots Name,Introduction,J9 +Project Type (for IPA use),Introduction,C14 +Classification,Introduction,C15 +DRRDD (GMPP - formally joined GMPP),Introduction,C16 +Reporting period (DRRDD - Snapshot Date),Introduction,C17 +Snapshot Date,Introduction,C18 +Senior Responsible Owner (SRO),Introduction,C21 +Senior Responsible Owner (SRO) - Email,Introduction,C22 +Senior Responsible Owner (SRO) - ID number,Introduction,C23 +SRO Sign-Off,Introduction,C24 +Project Director (PD),Introduction,C26 +Project Director (PD) - Email,Introduction,C27 +Project Director (PD) - ID number,Introduction,C28 +Date Report Approved by PD?,Introduction,C29 +Working Contact Name,Introduction,C31 +Working Contact Email,Introduction,C32 +Project Accountant with responsibility for Spend - Email,Introduction,C33 +Project Benefits Mngr with responsibility for Benefits - Email,Introduction,C34 +Project Planner with responsibility for Milestones - Email,Introduction,C35 +IPA's Departmental Single Point of Contact,Introduction,C38 +IPA's Departmental Single Point of Contact - Email,Introduction,C39 +IPA Analysis & Insight Unit (AIU) Lead,Introduction,C40 +IPA Analysis & Insight Unit (AIU) Lead - Email,Introduction,C41 +Date Report Approved by AIU?,Introduction,C42 +IPA Strategic Delivery Advisor (SDA) - Email,Introduction,C43 +Date Report Approved by SDA?,Introduction,C44 +Departmental PPM HoP copied in submission email?,Introduction,C46 +Departmental PPM HoP - Email,Introduction,C47 +Departmental HR HoP copied in submission email?,Introduction,C48 +Departmental HR HoP - Email,Introduction,C49 +Departmental Finance HoP copied in submission email?,Introduction,C50 +Departmental Finance HoP - Email,Introduction,C51 +Departmental Economics HoP copied in submission email?,Introduction,C52 +Departmental Economics HoP - Email,Introduction,C53 +Departmental Legal HoP copied in submission email?,Introduction,C54 +Departmental Legal HoP - Email,Introduction,C55 +Departmental Commercial l HoP copied in submission email?,Introduction,C56 +Departmental Commercial HoP - Email,Introduction,C57 +Departmental IT HoP copied in submission email?,Introduction,C58 +Departmental IT HoP - Email,Introduction,C59 +HMT Spending Team Lead copied in submission email?,Introduction,C60 +HMT Spending Team Lead - Email,Introduction,C61 +Quarter Joined,Introduction,C66 +DFT ID Number,Introduction,C65 +Working Contact Telephone,Introduction,C67 +DfT Group,Introduction,C63 +DfT Division,Introduction,C64 +Brief project description (DRRDD - brief descripton),1 - Project Info,E6 +DRRDD - Dept,1 - Project Info,E7 +Agency or delivery partner (DRRDD - Delivery Organisation primary),1 - Project Info,E8 +Delivery Organisation Secondary,1 - Project Info,E9 +Project status,1 - Project Info,E10 +Is the SRO for this project an MPLA Graduate?,1 - Project Info,E11 +Is the PD for this project an MPLA Graduate?,1 - Project Info,E12 +Does the Project have an issued SRO appointment letter?,1 - Project Info,E13 +Has the SRO issued an appointment letter to the PD?,1 - Project Info,E14 +Delivery Structure,1 - Project Info,E17 +Change Delivery Methodology,1 - Project Info,E18 +Delivery Narrative,1 - Project Info,E19 +DN Type 1,1 - Project Info,D23 +DN Description 1,1 - Project Info,E23 +DN Type 2,1 - Project Info,D24 +DN Description 2,1 - Project Info,E24 +DN Type 3,1 - Project Info,D25 +DN Description 3,1 - Project Info,E25 +DN Type 4,1 - Project Info,D26 +DN Description 4,1 - Project Info,E26 +DN Type 5,1 - Project Info,D27 +DN Description 5,1 - Project Info,E27 +Primary Category,1 - Project Info,E30 +Secondary Category,1 - Project Info,E31 +Tertiary Category,1 - Project Info,E32 +DRRDD Annual Report Category,1 - Project Info,E33 +Significant Steel Requirement,1 - Project Info,E34 +"For all construction, infrastructure or capital investment procurements >£10M, have you adopted the Government's Balanced Scorecard approach",1 - Project Info,E35 +DRRDD - Main reason for joining GMPP,1 - Project Info,E36 +Second reason for joining DRRDD (if applicable),1 - Project Info,E37 +List Strategic Outcomes (DRRDD - Intended Outcome 1),1 - Project Info,D41 +IO1,1 - Project Info,G41 +IO1 - Monetised?,1 - Project Info,H41 +IO1 PESTLE,1 - Project Info,J41 +List Strategic Outcomes (DRRDD - Intended Outcome 2),1 - Project Info,D42 +IO2,1 - Project Info,G42 +IO2 - Monetised?,1 - Project Info,H42 +IO2 PESTLE,1 - Project Info,J42 +List Strategic Outcomes (DRRDD - Intended Outcome 3),1 - Project Info,D43 +IO3,1 - Project Info,G43 +IO3 - Monetised?,1 - Project Info,H43 +IO3 PESTLE,1 - Project Info,J43 +List Strategic Outcomes (DRRDD - Intended Outcome 4),1 - Project Info,D44 +IO4,1 - Project Info,G44 +IO4 - Monetised?,1 - Project Info,H44 +IO4 PESTLE,1 - Project Info,J44 +List Strategic Outcomes (DRRDD - Intended Outcome 5),1 - Project Info,D45 +IO5,1 - Project Info,G45 +IO5 - Monetised?,1 - Project Info,H45 +IO5 PESTLE,1 - Project Info,J45 +List Strategic Outcomes (DRRDD - Intended Outcome 6),1 - Project Info,D46 +IO6,1 - Project Info,G46 +IO6 - Monetised?,1 - Project Info,H46 +IO6 PESTLE,1 - Project Info,J46 +List Strategic Outcomes (DRRDD - Intended Outcome 7),1 - Project Info,D47 +IO7,1 - Project Info,G47 +IO7 - Monetised?,1 - Project Info,H47 +IO7 PESTLE,1 - Project Info,J47 +List Strategic Outcomes (DRRDD - Intended Outcome 8),1 - Project Info,D48 +IO8,1 - Project Info,G48 +IO8 - Monetised?,1 - Project Info,H48 +IO8 PESTLE,1 - Project Info,J48 +List Strategic Outcomes (DRRDD - Intended Outcome 9),1 - Project Info,D49 +IO9,1 - Project Info,G49 +IO9 - Monetised?,1 - Project Info,H49 +IO9 PESTLE,1 - Project Info,J49 +List Strategic Outcomes (DRRDD - Intended Outcome 10),1 - Project Info,D50 +IO10,1 - Project Info,G50 +IO10 - Monetised?,1 - Project Info,H50 +IO10 PESTLE,1 - Project Info,J50 +Primary investment Objective,1 - Project Info,E54 +IO11 Monetised,1 - Project Info,K54 +Secondary Investment Objective,1 - Project Info,E55 +IO12 Monetised,1 - Project Info,K55 +Is successful completion of this project dependent on another DRRDD project? ,1 - Project Info,E58 +Dependency 1 - Department,1 - Project Info,E59 +Dependency 1 - DRRDD Project,1 - Project Info,E60 +Dependency 2 - Department,1 - Project Info,E61 +Dependency 2 - DRRDD Project,1 - Project Info,E62 +Dependency 3 - Department,1 - Project Info,E63 +Dependency 3 - DRRDD Project,1 - Project Info,E64 +Project Bobbins,1 - Project Info,E67 +Departmental DCA,2 - DCA & Risk,E7 +Departmental DCA Narrative,2 - DCA & Risk,E8 +DRRDD - IPA DCA,2 - DCA & Risk,E10 +DRRDD - IPA DCA Commentary,2 - DCA & Risk,E11 +DRRDD - IPA DCA last quarter,2 - DCA & Risk,P10 +Risk Level (RPA),2 - DCA & Risk,E12 +Risk Level (RPA) Date,2 - DCA & Risk,E13 +Brief Risk Decription 1,2 - DCA & Risk,D17 +BRD 1Risk Category,2 - DCA & Risk,E17 +BRD 1 Primary Risk to ,2 - DCA & Risk,G17 +BRD 1 Internal Control,2 - DCA & Risk,I17 +BRD 1 Residual Impact,2 - DCA & Risk,J17 +BRD 1 Residual Likelihood,2 - DCA & Risk,K17 +Brief Risk Decription 2,2 - DCA & Risk,D18 +BRD 2 Risk Category,2 - DCA & Risk,E18 +BRD 2 Primary Risk to ,2 - DCA & Risk,G18 +BRD 2 Internal Control,2 - DCA & Risk,I18 +BRD 2 Residual Impact,2 - DCA & Risk,J18 +BRD 2 Residual Likelihood,2 - DCA & Risk,K18 +Brief Risk Decription 3,2 - DCA & Risk,D19 +BRD 3 Risk Category,2 - DCA & Risk,E19 +BRD 3 Primary Risk to ,2 - DCA & Risk,G19 +BRD 3 Internal Control,2 - DCA & Risk,I19 +BRD 3 Residual Impact,2 - DCA & Risk,J19 +BRD 3 Residual Likelihood,2 - DCA & Risk,K19 +Brief Risk Decription 4,2 - DCA & Risk,D20 +BRD 4 Risk Category,2 - DCA & Risk,E20 +BRD 4 Primary Risk to ,2 - DCA & Risk,G20 +BRD 4 Internal Control,2 - DCA & Risk,I20 +BRD 4 Residual Impact,2 - DCA & Risk,J20 +BRD 4 Residual Likelihood,2 - DCA & Risk,K20 +Brief Risk Decription 5,2 - DCA & Risk,D21 +BRD 5 Risk Category,2 - DCA & Risk,E21 +BRD 5 Primary Risk to ,2 - DCA & Risk,G21 +BRD 5 Internal Control,2 - DCA & Risk,I21 +BRD 5 Residual Impact,2 - DCA & Risk,J21 +BRD 5 Residual Likelihood,2 - DCA & Risk,K21 +1st Bobbins Change - Description / Type,3 - Scope History,E6 +SC1 Date Bobbins Change Implemented,3 - Scope History,E7 +SC1 Date Implemented: Actual or Forecast?,3 - Bobbins History,K7 +SC1 Impact on Project End Date?,3 - Bobbins History,E8 +SC1 Is change in Project End Date solely due to the Bobbins change? ,3 - Scope History,E9 +SC1 Impact on Costs?,3 - Bobbins History,E10 +SC1 Is change in Costs solely due to the Bobbins change? ,3 - Scope History,E11 +SC1 Impact on Intended Outcomes?,3 - Bobbins History,E12 +SC1 Has the Business Case been updated as a result of this Bobbins change?,3 - Scope History,E13 +"SC1 If Yes, new Business Case Type?",3 - Bobbins History,K14 +SC1 New Business Case Version Number,3 - Bobbins History,E14 +SC1 Has HMT approved this new business case?,3 - Bobbins History,E15 +2nd Bobbins Change - Description / Type,3 - Scope History,E18 +SC2 Date Bobbins Change Implemented,3 - Scope History,E19 +SC2 Date Implemented: Actual or Forecast?,3 - Bobbins History,K19 +SC2 Impact on Project End Date?,3 - Bobbins History,E20 +SC2 Is change in Project End Date solely due to the Bobbins change? ,3 - Scope History,E21 +SC2 Impact on Costs?,3 - Bobbins History,E22 +SC2 Is change in Costs solely due to the Bobbins change? ,3 - Scope History,E23 +SC2 Impact on Intended Outcomes?,3 - Bobbins History,E24 +SC2 Has the Business Case been updated as a result of this Bobbins change?,3 - Scope History,E25 +"SC2 If Yes, new Business Case Type?",3 - Bobbins History,E26 +SC2 New Business Case Version Number,3 - Bobbins History,K26 +SC2 Has HMT approved this new business case?,3 - Bobbins History,E27 +3rd Bobbins Change - Description / Type,3 - Scope History,E30 +SC3 Date Bobbins Change Implemented,3 - Scope History,E31 +SC3 Date Implemented: Actual or Forecast?,3 - Bobbins History,K31 +SC3 Impact on Project End Date?,3 - Bobbins History,E32 +SC3 Is change in Project End Date solely due to the Bobbins change? ,3 - Scope History,E33 +SC3 Impact on Costs?,3 - Bobbins History,E34 +SC3 Is change in Costs solely due to the Bobbins change? ,3 - Scope History,E35 +SC3 Impact on Intended Outcomes?,3 - Bobbins History,E36 +SC3 Has the Business Case been updated as a result of this Bobbins change?,3 - Scope History,E37 +"SC3 If Yes, new Business Case Type?",3 - Bobbins History,E38 +SC3 New Business Case Version Number,3 - Bobbins History,K38 +SC3 Has HMT approved this new business case?,3 - Bobbins History,E39 +4th Bobbins Change - Description / Type,3 - Scope History,E42 +SC4 Date Bobbins Change Implemented,3 - Scope History,E43 +SC4 Date Implemented: Actual or Forecast?,3 - Bobbins History,K43 +SC4 Impact on Project End Date?,3 - Bobbins History,E44 +SC4 Is change in Project End Date solely due to the Bobbins change? ,3 - Scope History,E45 +SC4 Impact on Costs?,3 - Bobbins History,E46 +SC4 Is change in Costs solely due to the Bobbins change? ,3 - Scope History,E47 +SC4 Impact on Intended Outcomes?,3 - Bobbins History,E48 +SC4 Has the Business Case been updated as a result of this Bobbins change?,3 - Scope History,E49 +"SC4 If Yes, new Business Case Type?",3 - Bobbins History,E50 +SC4 New Business Case Version Number,3 - Bobbins History,K50 +SC4 Has HMT approved this new business case?,3 - Bobbins History,E51 +SRO Is this position currently filled?,4 - Leaders,E6 +DRRDD - SRO ID,4 - Leaders,E7 +SRO Last Name,4 - Leaders,E8 +SRO First Name,4 - Leaders,E9 +SRO Full Name,4 - Leaders,E10 +SRO Email,4 - Leaders,E11 +SRO Phone No.,4 - Leaders,E12 +SRO Tenure Start Date,4 - Leaders,E13 +SRO Tenure End Date,4 - Leaders,E14 +SRO Length of tenure (years),4 - Leaders,E15 +"If SRO Tenure End Date change, please advise reason",4 - Leaders,E16 +Job Title / Grade,4 - Leaders,E17 +SRO Grade,4 - Leaders,K17 +SRO Career Anchor - Primary,4 - Leaders,E18 +SRO Career Anchor - Secondary,4 - Leaders,E19 +Percentage of time spent on SRO Role,4 - Leaders,E20 +If new SRO reason for change,4 - Leaders,E21 +"If there are further SROs, please name, and explain why?",4 - Leaders,E22 +PD Is this position currently filled?,4 - Leaders,E25 +DRRDD - PD ID,4 - Leaders,E26 +PD Last Name,4 - Leaders,E27 +PD First Name,4 - Leaders,E28 +PD Full Name,4 - Leaders,E29 +PD Email,4 - Leaders,E30 +PD Phone No.,4 - Leaders,E31 +PD Tenure Start Date,4 - Leaders,E32 +PD Tenure End Date,4 - Leaders,E33 +PD Length of tenure (years),4 - Leaders,E34 +"If PD Tenure End Date change, please advise reason, and Type",4 - Leaders,E35 +Job Title,4 - Leaders,E36 +PD Grade,4 - Leaders,K36 +PD Career Anchor - Primary,4 - Leaders,E37 +PD Career Anchor - Secondary,4 - Leaders,E38 +Percentage of time spent on PD Role,4 - Leaders,E39 +If new PD reason for change,4 - Leaders,E40 +Secondary PDs please name?,4 - Leaders,E41 +No public sector employees working on the project,5 - People,E6 +No external contractors working on the project,5 - People,E7 +TOTAL Number working in the project team (FTEs),5 - People,E8 +No employees funded to work on project,5 - People,E9 +Total Number or vacancies on the project,5 - People,E10 +Resource Gap (%),5 - People,E11 +Project Team Turnover since last Quarter - Qualitative Assessment,5 - People,E12 +Resources commentary,5 - People,E13 +Digital - Now,5 - People,E17 +Digital - Future,5 - People,G17 +Digital Short Narrative (Amber or Red),5 - People,I17 +Information Technology - Now,5 - People,E18 +Information Technology - Future,5 - People,G18 +Information Technology Short Narrative (Amber or Red),5 - People,I18 +Legal Commercial Contract Management - Now,5 - People,E19 +Legal Commercial Contract Management - Future,5 - People,G19 +"Legal, Commercial & Contract Management Short Narrative (Amber or Red)",5 - People,I19 +Project Delivery - Now,5 - People,E20 +Project Delivery - Future,5 - People,G20 +Project Delivery Short Narrative (Amber or Red),5 - People,I20 +Change Implementation - Now,5 - People,E21 +Change Implementation - Future,5 - People,G21 +Change Implementation Short Narrative (Amber or Red),5 - People,I21 +Technical - Now,5 - People,E22 +Technical - Future,5 - People,G22 +Technical Short Narrative (Amber or Red),5 - People,I22 +Industry Knowledge - Now,5 - People,E23 +Industry Knowledge - Future,5 - People,G23 +Industry Knowledge Short Narrative (Amber or Red),5 - People,I23 +Finance - Now,5 - People,E24 +Finance - Future,5 - People,G24 +Finance Short Narrative (Amber or Red),5 - People,I24 +Analysis Now,5 - People,E25 +Analysis - future,5 - People,G25 +Analysis Short Narrative (Amber or Red),5 - People,I25 +Communications & Stakeholder Engagement - Now,5 - People,E26 +Communications & Stakeholder Engagement - Future,5 - People,G26 +Communications & Stakeholder Engagement Short Narrative (Amber or Red),5 - People,I26 +Additional Capability 1 Now,5 - People,E27 +Additional Capability 1 Future,5 - People,G27 +Additional Capability 1 Short Narrative (Amber or Red),5 - People,I27 +Additional Capability 2 Now,5 - People,E28 +Additional Capability 2 Future,5 - People,G28 +Additional Capability 2 Short Narrative (Amber or Red),5 - People,I28 +Other Capability 3 - Now,5 - People,E29 +Other Capability 3 - Future,5 - People,G29 +Additional Capability 3 Short Narrative (Amber or Red),5 - People,I29 +Other Capability 4 - Now,5 - People,E30 +Other Capability 4 - Future,5 - People,G30 +Additional Capability 4 Short Narrative (Amber or Red),5 - People,I30 +Additional Capability 5 Now,5 - People,E31 +Additional Capability 5 Future,5 - People,G31 +Additional Capability 5 Short Narrative (Amber or Red),5 - People,I31 +Overall Resource DCA - Now,5 - People,E35 +Overall Resource DCA - Future,5 - People,G35 +Approval MM1,6a - Milestones - Approvals,D7 +Approval MM1 Gov Type,6a - Milestones - Approvals,E7 +Approval MM1 Ver No,6a - Milestones - Approvals,F7 +Approval MM1 Original Bobline,6a - Milestones - Approvals,G7 +Approval MM1 Forecast / Actual,6a - Milestones - Approvals,H7 +Approval MM1 Variance,6a - Milestones - Approvals,I7 +Approval MM1 Status,6a - Milestones - Approvals,J7 +Approval MM1 Notes,6a - Milestones - Approvals,K7 +Approval MM2,6a - Milestones - Approvals,D8 +Approval MM2 Gov Type,6a - Milestones - Approvals,E8 +Approval MM2 Ver No,6a - Milestones - Approvals,F8 +Approval MM2 Original Bobline,6a - Milestones - Approvals,G8 +Approval MM2 Forecast / Actual,6a - Milestones - Approvals,H8 +Approval MM2 Variance,6a - Milestones - Approvals,I8 +Approval MM2 Status,6a - Milestones - Approvals,J8 +Approval MM2 Notes,6a - Milestones - Approvals,K8 +Approval MM3,6a - Milestones - Approvals,D9 +Approval MM3 Gov Type,6a - Milestones - Approvals,E9 +Approval MM3 Ver No,6a - Milestones - Approvals,F9 +Approval MM3 Original Bobline,6a - Milestones - Approvals,G9 +Approval MM3 Forecast / Actual,6a - Milestones - Approvals,H9 +Approval MM3 Variance,6a - Milestones - Approvals,I9 +Approval MM3 Status,6a - Milestones - Approvals,J9 +Approval MM3 Notes,6a - Milestones - Approvals,K9 +Approval MM4,6a - Milestones - Approvals,D10 +Approval MM4 Gov Type,6a - Milestones - Approvals,E10 +Approval MM4 Ver No,6a - Milestones - Approvals,F10 +Approval MM4 Original Bobline,6a - Milestones - Approvals,G10 +Approval MM4 Forecast / Actual,6a - Milestones - Approvals,H10 +Approval MM4 Variance,6a - Milestones - Approvals,I10 +Approval MM4 Status,6a - Milestones - Approvals,J10 +Approval MM4 Notes,6a - Milestones - Approvals,K10 +Approval MM5,6a - Milestones - Approvals,D11 +Approval MM5 Gov Type,6a - Milestones - Approvals,E11 +Approval MM5 Ver No,6a - Milestones - Approvals,F11 +Approval MM5 Original Bobline,6a - Milestones - Approvals,G11 +Approval MM5 Forecast / Actual,6a - Milestones - Approvals,H11 +Approval MM5 Variance,6a - Milestones - Approvals,I11 +Approval MM5 Status,6a - Milestones - Approvals,J11 +Approval MM5 Notes,6a - Milestones - Approvals,K11 +Approval MM6,6a - Milestones - Approvals,D12 +Approval MM6 Gov Type,6a - Milestones - Approvals,E12 +Approval MM6 Ver No,6a - Milestones - Approvals,F12 +Approval MM6 Original Bobline,6a - Milestones - Approvals,G12 +Approval MM6 Forecast / Actual,6a - Milestones - Approvals,H12 +Approval MM6 Variance,6a - Milestones - Approvals,I12 +Approval MM6 Status,6a - Milestones - Approvals,J12 +Approval MM6 Notes,6a - Milestones - Approvals,K12 +Approval MM7,6a - Milestones - Approvals,D13 +Approval MM7 Gov Type,6a - Milestones - Approvals,E13 +Approval MM7 Ver No,6a - Milestones - Approvals,F13 +Approval MM7 Original Bobline,6a - Milestones - Approvals,G13 +Approval MM7 Forecast / Actual,6a - Milestones - Approvals,H13 +Approval MM7 Variance,6a - Milestones - Approvals,I13 +Approval MM7 Status,6a - Milestones - Approvals,J13 +Approval MM7 Notes,6a - Milestones - Approvals,K13 +Approval MM8,6a - Milestones - Approvals,D14 +Approval MM8 Gov Type,6a - Milestones - Approvals,E14 +Approval MM8 Ver No,6a - Milestones - Approvals,F14 +Approval MM8 Original Bobline,6a - Milestones - Approvals,G14 +Approval MM8 Forecast / Actual,6a - Milestones - Approvals,H14 +Approval MM8 Variance,6a - Milestones - Approvals,I14 +Approval MM8 Status,6a - Milestones - Approvals,J14 +Approval MM8 Notes,6a - Milestones - Approvals,K14 +Approval MM9,6a - Milestones - Approvals,D15 +Approval MM9 Gov Type,6a - Milestones - Approvals,E15 +Approval MM9 Ver No,6a - Milestones - Approvals,F15 +Approval MM9 Original Bobline,6a - Milestones - Approvals,G15 +Approval MM9 Forecast / Actual,6a - Milestones - Approvals,H15 +Approval MM9 Variance,6a - Milestones - Approvals,I15 +Approval MM9 Status,6a - Milestones - Approvals,J15 +Approval MM9 Notes,6a - Milestones - Approvals,K15 +Approval MM10,6a - Milestones - Approvals,D16 +Approval MM10 Gov Type,6a - Milestones - Approvals,E16 +Approval MM10 Ver No,6a - Milestones - Approvals,F16 +Approval MM10 Original Bobline,6a - Milestones - Approvals,G16 +Approval MM10 Forecast / Actual,6a - Milestones - Approvals,H16 +Approval MM10 Variance,6a - Milestones - Approvals,I16 +Approval MM10 Status,6a - Milestones - Approvals,J16 +Approval MM10 Notes,6a - Milestones - Approvals,K16 +Approval MM11,6a - Milestones - Approvals,D17 +Approval MM11 Gov Type,6a - Milestones - Approvals,E17 +Approval MM11 Ver No,6a - Milestones - Approvals,F17 +Approval MM11 Original Bobline,6a - Milestones - Approvals,G17 +Approval MM11 Forecast / Actual,6a - Milestones - Approvals,H17 +Approval MM11 Variance,6a - Milestones - Approvals,I17 +Approval MM11 Status,6a - Milestones - Approvals,J17 +Approval MM11 Notes,6a - Milestones - Approvals,K17 +Approval MM12,6a - Milestones - Approvals,D18 +Approval MM12 Gov Type,6a - Milestones - Approvals,E18 +Approval MM12 Ver No,6a - Milestones - Approvals,F18 +Approval MM12 Original Bobline,6a - Milestones - Approvals,G18 +Approval MM12 Forecast / Actual,6a - Milestones - Approvals,H18 +Approval MM12 Variance,6a - Milestones - Approvals,I18 +Approval MM12 Status,6a - Milestones - Approvals,J18 +Approval MM12 Notes,6a - Milestones - Approvals,K18 +Approval MM13,6a - Milestones - Approvals,D19 +Approval MM13 Gov Type,6a - Milestones - Approvals,E19 +Approval MM13 Ver No,6a - Milestones - Approvals,F19 +Approval MM13 Original Bobline,6a - Milestones - Approvals,G19 +Approval MM13 Forecast - Actual,6a - Milestones - Approvals,H19 +Approval MM13 Variance,6a - Milestones - Approvals,I19 +Approval MM13 Status,6a - Milestones - Approvals,J19 +Approval MM13 Notes,6a - Milestones - Approvals,K19 +Approval MM14,6a - Milestones - Approvals,D20 +Approval MM14 Gov Type,6a - Milestones - Approvals,E20 +Approval MM14 Ver No,6a - Milestones - Approvals,F20 +Approval MM14 Original Bobline,6a - Milestones - Approvals,G20 +Approval MM14 Forecast - Actual,6a - Milestones - Approvals,H20 +Approval MM14 Variance,6a - Milestones - Approvals,I20 +Approval MM14 Status,6a - Milestones - Approvals,J20 +Approval MM14 Notes,6a - Milestones - Approvals,K20 +Approval MM15,6a - Milestones - Approvals,D21 +Approval MM15 Gov Type,6a - Milestones - Approvals,E21 +Approval MM15 Ver No,6a - Milestones - Approvals,F21 +Approval MM15 Original Bobline,6a - Milestones - Approvals,G21 +Approval MM15 Forecast - Actual,6a - Milestones - Approvals,H21 +Approval MM15 Variance,6a - Milestones - Approvals,I21 +Approval MM15 Status,6a - Milestones - Approvals,J21 +Approval MM15 Notes,6a - Milestones - Approvals,K21 +Approval MM16,6a - Milestones - Approvals,D22 +Approval MM16 Gov Type,6a - Milestones - Approvals,E22 +Approval MM16 Ver No,6a - Milestones - Approvals,F22 +Approval MM16 Original Bobline,6a - Milestones - Approvals,G22 +Approval MM16 Forecast - Actual,6a - Milestones - Approvals,H22 +Approval MM16 Variance,6a - Milestones - Approvals,I22 +Approval MM16 Status,6a - Milestones - Approvals,J22 +Approval MM16 Notes,6a - Milestones - Approvals,K22 +Approval MM17,6a - Milestones - Approvals,D23 +Approval MM17 Gov Type,6a - Milestones - Approvals,E23 +Approval MM17 Ver No,6a - Milestones - Approvals,F23 +Approval MM17 Original Bobline,6a - Milestones - Approvals,G23 +Approval MM17 Forecast / Actual,6a - Milestones - Approvals,H23 +Approval MM17 Variance,6a - Milestones - Approvals,I23 +Approval MM17 Status,6a - Milestones - Approvals,J23 +Approval MM17 Notes,6a - Milestones - Approvals,K23 +Approval MM18,6a - Milestones - Approvals,D24 +Approval MM18 Gov Type,6a - Milestones - Approvals,E24 +Approval MM18 Ver No,6a - Milestones - Approvals,F24 +Approval MM18 Original Bobline,6a - Milestones - Approvals,G24 +Approval MM18 Forecast / Actual,6a - Milestones - Approvals,H24 +Approval MM18 Variance,6a - Milestones - Approvals,I24 +Approval MM18 Status,6a - Milestones - Approvals,J24 +Approval MM18 Notes,6a - Milestones - Approvals,K24 +Approval MM19,6a - Milestones - Approvals,D25 +Approval MM19 Gov Type,6a - Milestones - Approvals,E25 +Approval MM19 Ver No,6a - Milestones - Approvals,F25 +Approval MM19 Original Bobline,6a - Milestones - Approvals,G25 +Approval MM19 Forecast / Actual,6a - Milestones - Approvals,H25 +Approval MM19 Variance,6a - Milestones - Approvals,I25 +Approval MM19 Status,6a - Milestones - Approvals,J25 +Approval MM19 Notes,6a - Milestones - Approvals,K25 +Approval MM20,6a - Milestones - Approvals,D26 +Approval MM20 Gov Type,6a - Milestones - Approvals,E26 +Approval MM20 Ver No,6a - Milestones - Approvals,F26 +Approval MM20 Original Bobline,6a - Milestones - Approvals,G26 +Approval MM20 Forecast / Actual,6a - Milestones - Approvals,H26 +Approval MM20 Variance,6a - Milestones - Approvals,I26 +Approval MM20 Status,6a - Milestones - Approvals,J26 +Approval MM20 Notes,6a - Milestones - Approvals,K26 +Approval MM21,6a - Milestones - Approvals,D27 +Approval MM21 Gov Type,6a - Milestones - Approvals,E27 +Approval MM21 Ver No,6a - Milestones - Approvals,F27 +Approval MM21 Original Bobline,6a - Milestones - Approvals,G27 +Approval MM21 Forecast / Actual,6a - Milestones - Approvals,H27 +Approval MM21 Variance,6a - Milestones - Approvals,I27 +Approval MM21 Status,6a - Milestones - Approvals,J27 +Approval MM21 Notes,6a - Milestones - Approvals,K27 +Approval MM22,6a - Milestones - Approvals,D28 +Approval MM22 Gov Type,6a - Milestones - Approvals,E28 +Approval MM22 Ver No,6a - Milestones - Approvals,F28 +Approval MM22 Original Bobline,6a - Milestones - Approvals,G28 +Approval MM22 Forecast / Actual,6a - Milestones - Approvals,H28 +Approval MM22 Variance,6a - Milestones - Approvals,I28 +Approval MM22 Status,6a - Milestones - Approvals,J28 +Approval MM22 Notes,6a - Milestones - Approvals,K28 +Approval MM23,6a - Milestones - Approvals,D29 +Approval MM23 Gov Type,6a - Milestones - Approvals,E29 +Approval MM23 Ver No,6a - Milestones - Approvals,F29 +Approval MM23 Original Bobline,6a - Milestones - Approvals,G29 +Approval MM23 Forecast / Actual,6a - Milestones - Approvals,H29 +Approval MM23 Variance,6a - Milestones - Approvals,I29 +Approval MM23 Status,6a - Milestones - Approvals,J29 +Approval MM23 Notes,6a - Milestones - Approvals,K29 +Approval MM24,6a - Milestones - Approvals,D30 +Approval MM24 Gov Type,6a - Milestones - Approvals,E30 +Approval MM24 Ver No,6a - Milestones - Approvals,F30 +Approval MM24 Original Bobline,6a - Milestones - Approvals,G30 +Approval MM24 Forecast / Actual,6a - Milestones - Approvals,H30 +Approval MM24 Variance,6a - Milestones - Approvals,I30 +Approval MM24 Status,6a - Milestones - Approvals,J30 +Approval MM24 Notes,6a - Milestones - Approvals,K30 +Approval MM25,6a - Milestones - Approvals,D31 +Approval MM25 Gov Type,6a - Milestones - Approvals,E31 +Approval MM25 Ver No,6a - Milestones - Approvals,F31 +Approval MM25 Original Bobline,6a - Milestones - Approvals,G31 +Approval MM25 Forecast / Actual,6a - Milestones - Approvals,H31 +Approval MM25 Variance,6a - Milestones - Approvals,I31 +Approval MM25 Status,6a - Milestones - Approvals,J31 +Approval MM25 Notes,6a - Milestones - Approvals,K31 +Approval MM26,6a - Milestones - Approvals,D32 +Approval MM26 Gov Type,6a - Milestones - Approvals,E32 +Approval MM26 Ver No,6a - Milestones - Approvals,F32 +Approval MM26 Original Bobline,6a - Milestones - Approvals,G32 +Approval MM26 Forecast / Actual,6a - Milestones - Approvals,H32 +Approval MM26 Variance,6a - Milestones - Approvals,I32 +Approval MM26 Status,6a - Milestones - Approvals,J32 +Approval MM26 Notes,6a - Milestones - Approvals,K32 +Approval MM27,6a - Milestones - Approvals,D33 +Approval MM27 Gov Type,6a - Milestones - Approvals,E33 +Approval MM27 Ver No,6a - Milestones - Approvals,F33 +Approval MM27 Original Bobline,6a - Milestones - Approvals,G33 +Approval MM27 Forecast / Actual,6a - Milestones - Approvals,H33 +Approval MM27 Variance,6a - Milestones - Approvals,I33 +Approval MM27 Status,6a - Milestones - Approvals,J33 +Approval MM27 Notes,6a - Milestones - Approvals,K33 +Approval MM28,6a - Milestones - Approvals,D34 +Approval MM28 Gov Type,6a - Milestones - Approvals,E34 +Approval MM28 Ver No,6a - Milestones - Approvals,F34 +Approval MM28 Original Bobline,6a - Milestones - Approvals,G34 +Approval MM28 Forecast / Actual,6a - Milestones - Approvals,H34 +Approval MM28 Variance,6a - Milestones - Approvals,I34 +Approval MM28 Status,6a - Milestones - Approvals,J34 +Approval MM28 Notes,6a - Milestones - Approvals,K34 +Approval MM29,6a - Milestones - Approvals,D35 +Approval MM29 Gov Type,6a - Milestones - Approvals,E35 +Approval MM29 Ver No,6a - Milestones - Approvals,F35 +Approval MM29 Original Bobline,6a - Milestones - Approvals,G35 +Approval MM29 Forecast / Actual,6a - Milestones - Approvals,H35 +Approval MM29 Variance,6a - Milestones - Approvals,I35 +Approval MM29 Status,6a - Milestones - Approvals,J35 +Approval MM29 Notes,6a - Milestones - Approvals,K35 +Approval MM30,6a - Milestones - Approvals,D36 +Approval MM30 Gov Type,6a - Milestones - Approvals,E36 +Approval MM30 Ver No,6a - Milestones - Approvals,F36 +Approval MM30 Original Bobline,6a - Milestones - Approvals,G36 +Approval MM30 Forecast / Actual,6a - Milestones - Approvals,H36 +Approval MM30 Variance,6a - Milestones - Approvals,I36 +Approval MM30 Status,6a - Milestones - Approvals,J36 +Approval MM30 Notes,6a - Milestones - Approvals,K36 +Approval MM31,6a - Milestones - Approvals,D37 +Approval MM31 Gov Type,6a - Milestones - Approvals,E37 +Approval MM31 Ver No,6a - Milestones - Approvals,F37 +Approval MM31 Original Bobline,6a - Milestones - Approvals,G37 +Approval MM31 Forecast / Actual,6a - Milestones - Approvals,H37 +Approval MM31 Variance,6a - Milestones - Approvals,I37 +Approval MM31 Status,6a - Milestones - Approvals,J37 +Approval MM31 Notes,6a - Milestones - Approvals,K37 +Approval MM32,6a - Milestones - Approvals,D38 +Approval MM32 Gov Type,6a - Milestones - Approvals,E38 +Approval MM32 Ver No,6a - Milestones - Approvals,F38 +Approval MM32 Original Bobline,6a - Milestones - Approvals,G38 +Approval MM32 Forecast / Actual,6a - Milestones - Approvals,H38 +Approval MM32 Variance,6a - Milestones - Approvals,I38 +Approval MM32 Status,6a - Milestones - Approvals,J38 +Approval MM32 Notes,6a - Milestones - Approvals,K38 +Approval MM33,6a - Milestones - Approvals,D39 +Approval MM33 Gov Type,6a - Milestones - Approvals,E39 +Approval MM33 Ver No,6a - Milestones - Approvals,F39 +Approval MM33 Original Bobline,6a - Milestones - Approvals,G39 +Approval MM33 Forecast / Actual,6a - Milestones - Approvals,H39 +Approval MM33 Variance,6a - Milestones - Approvals,I39 +Approval MM33 Status,6a - Milestones - Approvals,J39 +Approval MM33 Notes,6a - Milestones - Approvals,K39 +Approval MM34,6a - Milestones - Approvals,D40 +Approval MM34 Gov Type,6a - Milestones - Approvals,E40 +Approval MM34 Ver No,6a - Milestones - Approvals,F40 +Approval MM34 Original Bobline,6a - Milestones - Approvals,G40 +Approval MM34 Forecast / Actual,6a - Milestones - Approvals,H40 +Approval MM34 Variance,6a - Milestones - Approvals,I40 +Approval MM34 Status,6a - Milestones - Approvals,J40 +Approval MM34 Notes,6a - Milestones - Approvals,K40 +Approval MM35,6a - Milestones - Approvals,D41 +Approval MM35 Gov Type,6a - Milestones - Approvals,E41 +Approval MM35 Ver No,6a - Milestones - Approvals,F41 +Approval MM35 Original Bobline,6a - Milestones - Approvals,G41 +Approval MM35 Forecast / Actual,6a - Milestones - Approvals,H41 +Approval MM35 Variance,6a - Milestones - Approvals,I41 +Approval MM35 Status,6a - Milestones - Approvals,J41 +Approval MM35 Notes,6a - Milestones - Approvals,K41 +Approval MM36,6a - Milestones - Approvals,D42 +Approval MM36 Gov Type,6a - Milestones - Approvals,E42 +Approval MM36 Ver No,6a - Milestones - Approvals,F42 +Approval MM36 Original Bobline,6a - Milestones - Approvals,G42 +Approval MM36 Forecast / Actual,6a - Milestones - Approvals,H42 +Approval MM36 Variance,6a - Milestones - Approvals,I42 +Approval MM36 Status,6a - Milestones - Approvals,J42 +Approval MM36 Notes,6a - Milestones - Approvals,K42 +Approval MM37,6a - Milestones - Approvals,D43 +Approval MM37 Gov Type,6a - Milestones - Approvals,E43 +Approval MM37 Ver No,6a - Milestones - Approvals,F43 +Approval MM37 Original Bobline,6a - Milestones - Approvals,G43 +Approval MM37 Forecast / Actual,6a - Milestones - Approvals,H43 +Approval MM37 Variance,6a - Milestones - Approvals,I43 +Approval MM37 Status,6a - Milestones - Approvals,J43 +Approval MM37 Notes,6a - Milestones - Approvals,K43 +Approval MM38,6a - Milestones - Approvals,D44 +Approval MM38 Gov Type,6a - Milestones - Approvals,E44 +Approval MM38 Ver No,6a - Milestones - Approvals,F44 +Approval MM38 Original Bobline,6a - Milestones - Approvals,G44 +Approval MM38 Forecast / Actual,6a - Milestones - Approvals,H44 +Approval MM38 Variance,6a - Milestones - Approvals,I44 +Approval MM38 Status,6a - Milestones - Approvals,J44 +Approval MM38 Notes,6a - Milestones - Approvals,K44 +Approval MM39,6a - Milestones - Approvals,D45 +Approval MM39 Gov Type,6a - Milestones - Approvals,E45 +Approval MM39 Ver No,6a - Milestones - Approvals,F45 +Approval MM39 Original Bobline,6a - Milestones - Approvals,G45 +Approval MM39 Forecast / Actual,6a - Milestones - Approvals,H45 +Approval MM39 Variance,6a - Milestones - Approvals,I45 +Approval MM39 Status,6a - Milestones - Approvals,J45 +Approval MM39 Notes,6a - Milestones - Approvals,K45 +Approval MM40,6a - Milestones - Approvals,D46 +Approval MM40 Gov Type,6a - Milestones - Approvals,E46 +Approval MM40 Ver No,6a - Milestones - Approvals,F46 +Approval MM40 Original Bobline,6a - Milestones - Approvals,G46 +Approval MM40 Forecast / Actual,6a - Milestones - Approvals,H46 +Approval MM40 Variance,6a - Milestones - Approvals,I46 +Approval MM40 Status,6a - Milestones - Approvals,J46 +Approval MM40 Notes,6a - Milestones - Approvals,K46 +Approval MM41,6a - Milestones - Approvals,D47 +Approval MM41 Gov Type,6a - Milestones - Approvals,E47 +Approval MM41 Ver No,6a - Milestones - Approvals,F47 +Approval MM41 Original Bobline,6a - Milestones - Approvals,G47 +Approval MM41 Forecast / Actual,6a - Milestones - Approvals,H47 +Approval MM41 Variance,6a - Milestones - Approvals,I47 +Approval MM41 Status,6a - Milestones - Approvals,J47 +Approval MM41 Notes,6a - Milestones - Approvals,K47 +Approval MM42,6a - Milestones - Approvals,D48 +Approval MM42 Gov Type,6a - Milestones - Approvals,E48 +Approval MM42 Ver No,6a - Milestones - Approvals,F48 +Approval MM42 Original Bobline,6a - Milestones - Approvals,G48 +Approval MM42 Forecast / Actual,6a - Milestones - Approvals,H48 +Approval MM42 Variance,6a - Milestones - Approvals,I48 +Approval MM42 Status,6a - Milestones - Approvals,J48 +Approval MM42 Notes,6a - Milestones - Approvals,K48 +Approval MM43,6a - Milestones - Approvals,D49 +Approval MM43 Gov Type,6a - Milestones - Approvals,E49 +Approval MM43 Ver No,6a - Milestones - Approvals,F49 +Approval MM43 Original Bobline,6a - Milestones - Approvals,G49 +Approval MM43 Forecast / Actual,6a - Milestones - Approvals,H49 +Approval MM43 Variance,6a - Milestones - Approvals,I49 +Approval MM43 Status,6a - Milestones - Approvals,J49 +Approval MM43 Notes,6a - Milestones - Approvals,K49 +Approval MM44,6a - Milestones - Approvals,D50 +Approval MM44 Gov Type,6a - Milestones - Approvals,E50 +Approval MM44 Ver No,6a - Milestones - Approvals,F50 +Approval MM44 Original Bobline,6a - Milestones - Approvals,G50 +Approval MM44 Forecast / Actual,6a - Milestones - Approvals,H50 +Approval MM44 Variance,6a - Milestones - Approvals,I50 +Approval MM44 Status,6a - Milestones - Approvals,J50 +Approval MM44 Notes,6a - Milestones - Approvals,K50 +Approval MM45,6a - Milestones - Approvals,D51 +Approval MM45 Gov Type,6a - Milestones - Approvals,E51 +Approval MM45 Ver No,6a - Milestones - Approvals,F51 +Approval MM45 Original Bobline,6a - Milestones - Approvals,G51 +Approval MM45 Forecast / Actual,6a - Milestones - Approvals,H51 +Approval MM45 Variance,6a - Milestones - Approvals,I51 +Approval MM45 Status,6a - Milestones - Approvals,J51 +Approval MM45 Notes,6a - Milestones - Approvals,K51 +Approval MM46,6a - Milestones - Approvals,D52 +Approval MM46 Gov Type,6a - Milestones - Approvals,E52 +Approval MM46 Ver No,6a - Milestones - Approvals,F52 +Approval MM46 Original Bobline,6a - Milestones - Approvals,G52 +Approval MM46 Forecast / Actual,6a - Milestones - Approvals,H52 +Approval MM46 Variance,6a - Milestones - Approvals,I52 +Approval MM46 Status,6a - Milestones - Approvals,J52 +Approval MM46 Notes,6a - Milestones - Approvals,K52 +Approval MM47,6a - Milestones - Approvals,D53 +Approval MM47 Gov Type,6a - Milestones - Approvals,E53 +Approval MM47 Ver No,6a - Milestones - Approvals,F53 +Approval MM47 Original Bobline,6a - Milestones - Approvals,G53 +Approval MM47 Forecast / Actual,6a - Milestones - Approvals,H53 +Approval MM47 Variance,6a - Milestones - Approvals,I53 +Approval MM47 Status,6a - Milestones - Approvals,J53 +Approval MM47 Notes,6a - Milestones - Approvals,K53 +Approval MM48,6a - Milestones - Approvals,D54 +Approval MM48 Gov Type,6a - Milestones - Approvals,E54 +Approval MM48 Ver No,6a - Milestones - Approvals,F54 +Approval MM48 Original Bobline,6a - Milestones - Approvals,G54 +Approval MM48 Forecast / Actual,6a - Milestones - Approvals,H54 +Approval MM48 Variance,6a - Milestones - Approvals,I54 +Approval MM48 Status,6a - Milestones - Approvals,J54 +Approval MM48 Notes,6a - Milestones - Approvals,K54 +Approval MM49,6a - Milestones - Approvals,D55 +Approval MM49 Gov Type,6a - Milestones - Approvals,E55 +Approval MM49 Ver No,6a - Milestones - Approvals,F55 +Approval MM49 Original Bobline,6a - Milestones - Approvals,G55 +Approval MM49 Forecast / Actual,6a - Milestones - Approvals,H55 +Approval MM49 Variance,6a - Milestones - Approvals,I55 +Approval MM49 Status,6a - Milestones - Approvals,J55 +Approval MM49 Notes,6a - Milestones - Approvals,K55 +Approval MM50,6a - Milestones - Approvals,D56 +Approval MM50 Gov Type,6a - Milestones - Approvals,E56 +Approval MM50 Ver No,6a - Milestones - Approvals,F56 +Approval MM50 Original Bobline,6a - Milestones - Approvals,G56 +Approval MM50 Forecast / Actual,6a - Milestones - Approvals,H56 +Approval MM50 Variance,6a - Milestones - Approvals,I56 +Approval MM50 Status,6a - Milestones - Approvals,J56 +Approval MM50 Notes,6a - Milestones - Approvals,K56 +BICC approval point,6a - Milestones - Approvals,F113 +Assurance MM1,6b - Milestones - Assurance,D7 +Assurance MM1 LoD,6b - Milestones - Assurance,E7 +Assurance MM1 Original Bobline,6b - Milestones - Assurance,F7 +Assurance MM1 Forecast - Actual,6b - Milestones - Assurance,G7 +Assurance MM1 Variance,6b - Milestones - Assurance,H7 +Assurance MM1 Status,6b - Milestones - Assurance,I7 +Assurance MM1 Notes,6b - Milestones - Assurance,J7 +Assurance MM2,6b - Milestones - Assurance,D8 +Assurance MM2 LoD,6b - Milestones - Assurance,E8 +Assurance MM2 Original Bobline,6b - Milestones - Assurance,F8 +Assurance MM2 Forecast - Actual,6b - Milestones - Assurance,G8 +Assurance MM2 Variance,6b - Milestones - Assurance,H8 +Assurance MM2 Status,6b - Milestones - Assurance,I8 +Assurance MM2 Notes,6b - Milestones - Assurance,J8 +Assurance MM3,6b - Milestones - Assurance,D9 +Assurance MM3 LoD,6b - Milestones - Assurance,E9 +Assurance MM3 Original Bobline,6b - Milestones - Assurance,F9 +Assurance MM3 Forecast - Actual,6b - Milestones - Assurance,G9 +Assurance MM3 Variance,6b - Milestones - Assurance,H9 +Assurance MM3 Status,6b - Milestones - Assurance,I9 +Assurance MM3 Notes,6b - Milestones - Assurance,J9 +Assurance MM4,6b - Milestones - Assurance,D10 +Assurance MM4 LoD,6b - Milestones - Assurance,E10 +Assurance MM4 Original Bobline,6b - Milestones - Assurance,F10 +Assurance MM4 Forecast - Actual,6b - Milestones - Assurance,G10 +Assurance MM4 Variance,6b - Milestones - Assurance,H10 +Assurance MM4 Status,6b - Milestones - Assurance,I10 +Assurance MM4 Notes,6b - Milestones - Assurance,J10 +Assurance MM5,6b - Milestones - Assurance,D11 +Assurance MM5 LoD,6b - Milestones - Assurance,E11 +Assurance MM5 Original Bobline,6b - Milestones - Assurance,F11 +Assurance MM5 Forecast - Actual,6b - Milestones - Assurance,G11 +Assurance MM5 Variance,6b - Milestones - Assurance,H11 +Assurance MM5 Status,6b - Milestones - Assurance,I11 +Assurance MM5 Notes,6b - Milestones - Assurance,J11 +Assurance MM6,6b - Milestones - Assurance,D12 +Assurance MM6 LoD,6b - Milestones - Assurance,E12 +Assurance MM6 Original Bobline,6b - Milestones - Assurance,F12 +Assurance MM6 Forecast - Actual,6b - Milestones - Assurance,G12 +Assurance MM6 Variance,6b - Milestones - Assurance,H12 +Assurance MM6 Status,6b - Milestones - Assurance,I12 +Assurance MM6 Notes,6b - Milestones - Assurance,J12 +Assurance MM7,6b - Milestones - Assurance,D13 +Assurance MM7 LoD,6b - Milestones - Assurance,E13 +Assurance MM7 Original Bobline,6b - Milestones - Assurance,F13 +Assurance MM7 Forecast - Actual,6b - Milestones - Assurance,G13 +Assurance MM7 Variance,6b - Milestones - Assurance,H13 +Assurance MM7 Status,6b - Milestones - Assurance,I13 +Assurance MM7 Notes,6b - Milestones - Assurance,J13 +Assurance MM8,6b - Milestones - Assurance,D14 +Assurance MM8 LoD,6b - Milestones - Assurance,E14 +Assurance MM8 Original Bobline,6b - Milestones - Assurance,F14 +Assurance MM8 Forecast - Actual,6b - Milestones - Assurance,G14 +Assurance MM8 Variance,6b - Milestones - Assurance,H14 +Assurance MM8 Status,6b - Milestones - Assurance,I14 +Assurance MM8 Notes,6b - Milestones - Assurance,J14 +Assurance MM9,6b - Milestones - Assurance,D15 +Assurance MM9 LoD,6b - Milestones - Assurance,E15 +Assurance MM9 Original Bobline,6b - Milestones - Assurance,F15 +Assurance MM9 Forecast - Actual,6b - Milestones - Assurance,G15 +Assurance MM9 Variance,6b - Milestones - Assurance,H15 +Assurance MM9 Status,6b - Milestones - Assurance,I15 +Assurance MM9 Notes,6b - Milestones - Assurance,J15 +Assurance MM10,6b - Milestones - Assurance,D16 +Assurance MM10 LoD,6b - Milestones - Assurance,E16 +Assurance MM10 Original Bobline,6b - Milestones - Assurance,F16 +Assurance MM10 Forecast - Actual,6b - Milestones - Assurance,G16 +Assurance MM10 Variance,6b - Milestones - Assurance,H16 +Assurance MM10 Status,6b - Milestones - Assurance,I16 +Assurance MM10 Notes,6b - Milestones - Assurance,J16 +Assurance MM11,6b - Milestones - Assurance,D17 +Assurance MM11 LoD,6b - Milestones - Assurance,E17 +Assurance MM11 Original Bobline,6b - Milestones - Assurance,F17 +Assurance MM11 Forecast - Actual,6b - Milestones - Assurance,G17 +Assurance MM11 Variance,6b - Milestones - Assurance,H17 +Assurance MM11 Status,6b - Milestones - Assurance,I17 +Assurance MM11 Notes,6b - Milestones - Assurance,J17 +Assurance MM12,6b - Milestones - Assurance,D18 +Assurance MM12 LoD,6b - Milestones - Assurance,E18 +Assurance MM12 Original Bobline,6b - Milestones - Assurance,F18 +Assurance MM12 Forecast - Actual,6b - Milestones - Assurance,G18 +Assurance MM12 Variance,6b - Milestones - Assurance,H18 +Assurance MM12 Status,6b - Milestones - Assurance,I18 +Assurance MM12 Notes,6b - Milestones - Assurance,J18 +Assurance MM13,6b - Milestones - Assurance,D19 +Assurance MM13 LoD,6b - Milestones - Assurance,E19 +Assurance MM13 Original Bobline,6b - Milestones - Assurance,F19 +Assurance MM13 Forecast - Actual,6b - Milestones - Assurance,G19 +Assurance MM13 Variance,6b - Milestones - Assurance,H19 +Assurance MM13 Status,6b - Milestones - Assurance,I19 +Assurance MM13 Notes,6b - Milestones - Assurance,J19 +Assurance MM14,6b - Milestones - Assurance,D20 +Assurance MM14 LoD,6b - Milestones - Assurance,E20 +Assurance MM14 Original Bobline,6b - Milestones - Assurance,F20 +Assurance MM14 Forecast - Actual,6b - Milestones - Assurance,G20 +Assurance MM14 Variance,6b - Milestones - Assurance,H20 +Assurance MM14 Status,6b - Milestones - Assurance,I20 +Assurance MM14 Notes,6b - Milestones - Assurance,J20 +Assurance MM15,6b - Milestones - Assurance,D21 +Assurance MM15 LoD,6b - Milestones - Assurance,E21 +Assurance MM15 Original Bobline,6b - Milestones - Assurance,F21 +Assurance MM15 Forecast - Actual,6b - Milestones - Assurance,G21 +Assurance MM15 Variance,6b - Milestones - Assurance,H21 +Assurance MM15 Status,6b - Milestones - Assurance,I21 +Assurance MM15 Notes,6b - Milestones - Assurance,J21 +Assurance MM16,6b - Milestones - Assurance,D22 +Assurance MM16 LoD,6b - Milestones - Assurance,E22 +Assurance MM16 Original Bobline,6b - Milestones - Assurance,F22 +Assurance MM16 Forecast - Actual,6b - Milestones - Assurance,G22 +Assurance MM16 Variance,6b - Milestones - Assurance,H22 +Assurance MM16 Status,6b - Milestones - Assurance,I22 +Assurance MM16 Notes,6b - Milestones - Assurance,J22 +Assurance MM17,6b - Milestones - Assurance,D23 +Assurance MM17 LoD,6b - Milestones - Assurance,E23 +Assurance MM17 Original Bobline,6b - Milestones - Assurance,F23 +Assurance MM17 Forecast - Actual,6b - Milestones - Assurance,G23 +Assurance MM17 Variance,6b - Milestones - Assurance,H23 +Assurance MM17 Status,6b - Milestones - Assurance,I23 +Assurance MM17 Notes,6b - Milestones - Assurance,J23 +Assurance MM18,6b - Milestones - Assurance,D24 +Assurance MM18 LoD,6b - Milestones - Assurance,E24 +Assurance MM18 Original Bobline,6b - Milestones - Assurance,F24 +Assurance MM18 Forecast - Actual,6b - Milestones - Assurance,G24 +Assurance MM18 Variance,6b - Milestones - Assurance,H24 +Assurance MM18 Status,6b - Milestones - Assurance,I24 +Assurance MM18 Notes,6b - Milestones - Assurance,J24 +Assurance MM19,6b - Milestones - Assurance,D25 +Assurance MM19 LoD,6b - Milestones - Assurance,E25 +Assurance MM19 Original Bobline,6b - Milestones - Assurance,F25 +Assurance MM19 Forecast - Actual,6b - Milestones - Assurance,G25 +Assurance MM19 Variance,6b - Milestones - Assurance,H25 +Assurance MM19 Status,6b - Milestones - Assurance,I25 +Assurance MM19 Notes,6b - Milestones - Assurance,J25 +Assurance MM20,6b - Milestones - Assurance,D26 +Assurance MM20 LoD,6b - Milestones - Assurance,E26 +Assurance MM20 Original Bobline,6b - Milestones - Assurance,F26 +Assurance MM20 Forecast - Actual,6b - Milestones - Assurance,G26 +Assurance MM20 Variance,6b - Milestones - Assurance,H26 +Assurance MM20 Status,6b - Milestones - Assurance,I26 +Assurance MM20 Notes,6b - Milestones - Assurance,J26 +Assurance MM21,6b - Milestones - Assurance,D27 +Assurance MM21 LoD,6b - Milestones - Assurance,E27 +Assurance MM21 Original Bobline,6b - Milestones - Assurance,F27 +Assurance MM21 Forecast - Actual,6b - Milestones - Assurance,G27 +Assurance MM21 Variance,6b - Milestones - Assurance,H27 +Assurance MM21 Status,6b - Milestones - Assurance,I27 +Assurance MM21 Notes,6b - Milestones - Assurance,J27 +Assurance MM22,6b - Milestones - Assurance,D28 +Assurance MM22 LoD,6b - Milestones - Assurance,E28 +Assurance MM22 Original Bobline,6b - Milestones - Assurance,F28 +Assurance MM22 Forecast - Actual,6b - Milestones - Assurance,G28 +Assurance MM22 Variance,6b - Milestones - Assurance,H28 +Assurance MM22 Status,6b - Milestones - Assurance,I28 +Assurance MM22 Notes,6b - Milestones - Assurance,J28 +Assurance MM23,6b - Milestones - Assurance,D29 +Assurance MM23 LoD,6b - Milestones - Assurance,E29 +Assurance MM23 Original Bobline,6b - Milestones - Assurance,F29 +Assurance MM23 Forecast - Actual,6b - Milestones - Assurance,G29 +Assurance MM23 Variance,6b - Milestones - Assurance,H29 +Assurance MM23 Status,6b - Milestones - Assurance,I29 +Assurance MM23 Notes,6b - Milestones - Assurance,J29 +Assurance MM24,6b - Milestones - Assurance,D30 +Assurance MM24 LoD,6b - Milestones - Assurance,E30 +Assurance MM24 Original Bobline,6b - Milestones - Assurance,F30 +Assurance MM24 Forecast - Actual,6b - Milestones - Assurance,G30 +Assurance MM24 Variance,6b - Milestones - Assurance,H30 +Assurance MM24 Status,6b - Milestones - Assurance,I30 +Assurance MM24 Notes,6b - Milestones - Assurance,J30 +Assurance MM25,6b - Milestones - Assurance,D31 +Assurance MM25 LoD,6b - Milestones - Assurance,E31 +Assurance MM25 Original Bobline,6b - Milestones - Assurance,F31 +Assurance MM25 Forecast - Actual,6b - Milestones - Assurance,G31 +Assurance MM25 Variance,6b - Milestones - Assurance,H31 +Assurance MM25 Status,6b - Milestones - Assurance,I31 +Assurance MM25 Notes,6b - Milestones - Assurance,J31 +Assurance MM26,6b - Milestones - Assurance,D32 +Assurance MM26 LoD,6b - Milestones - Assurance,E32 +Assurance MM26 Original Bobline,6b - Milestones - Assurance,F32 +Assurance MM26 Forecast - Actual,6b - Milestones - Assurance,G32 +Assurance MM26 Variance,6b - Milestones - Assurance,H32 +Assurance MM26 Status,6b - Milestones - Assurance,I32 +Assurance MM26 Notes,6b - Milestones - Assurance,J32 +Assurance MM27,6b - Milestones - Assurance,D33 +Assurance MM27 LoD,6b - Milestones - Assurance,E33 +Assurance MM27 Original Bobline,6b - Milestones - Assurance,F33 +Assurance MM27 Forecast - Actual,6b - Milestones - Assurance,G33 +Assurance MM27 Variance,6b - Milestones - Assurance,H33 +Assurance MM27 Status,6b - Milestones - Assurance,I33 +Assurance MM27 Notes,6b - Milestones - Assurance,J33 +Assurance MM28,6b - Milestones - Assurance,D34 +Assurance MM28 LoD,6b - Milestones - Assurance,E34 +Assurance MM28 Original Bobline,6b - Milestones - Assurance,F34 +Assurance MM28 Forecast - Actual,6b - Milestones - Assurance,G34 +Assurance MM28 Variance,6b - Milestones - Assurance,H34 +Assurance MM28 Status,6b - Milestones - Assurance,I34 +Assurance MM28 Notes,6b - Milestones - Assurance,J34 +Assurance MM29,6b - Milestones - Assurance,D35 +Assurance MM29 LoD,6b - Milestones - Assurance,E35 +Assurance MM29 Original Bobline,6b - Milestones - Assurance,F35 +Assurance MM29 Forecast - Actual,6b - Milestones - Assurance,G35 +Assurance MM29 Variance,6b - Milestones - Assurance,H35 +Assurance MM29 Status,6b - Milestones - Assurance,I35 +Assurance MM29 Notes,6b - Milestones - Assurance,J35 +Assurance MM30,6b - Milestones - Assurance,D36 +Assurance MM30 LoD,6b - Milestones - Assurance,E36 +Assurance MM30 Original Bobline,6b - Milestones - Assurance,F36 +Assurance MM30 Forecast - Actual,6b - Milestones - Assurance,G36 +Assurance MM30 Variance,6b - Milestones - Assurance,H36 +Assurance MM30 Status,6b - Milestones - Assurance,I36 +Assurance MM30 Notes,6b - Milestones - Assurance,J36 +Assurance MM31,6b - Milestones - Assurance,D37 +Assurance MM31 LoD,6b - Milestones - Assurance,E37 +Assurance MM31 Original Bobline,6b - Milestones - Assurance,F37 +Assurance MM31 Forecast - Actual,6b - Milestones - Assurance,G37 +Assurance MM31 Variance,6b - Milestones - Assurance,H37 +Assurance MM31 Status,6b - Milestones - Assurance,I37 +Assurance MM31 Notes,6b - Milestones - Assurance,J37 +Assurance MM32,6b - Milestones - Assurance,D38 +Assurance MM32 LoD,6b - Milestones - Assurance,E38 +Assurance MM32 Original Bobline,6b - Milestones - Assurance,F38 +Assurance MM32 Forecast - Actual,6b - Milestones - Assurance,G38 +Assurance MM32 Variance,6b - Milestones - Assurance,H38 +Assurance MM32 Status,6b - Milestones - Assurance,I38 +Assurance MM32 Notes,6b - Milestones - Assurance,J38 +Assurance MM33,6b - Milestones - Assurance,D39 +Assurance MM33 LoD,6b - Milestones - Assurance,E39 +Assurance MM33 Original Bobline,6b - Milestones - Assurance,F39 +Assurance MM33 Forecast - Actual,6b - Milestones - Assurance,G39 +Assurance MM33 Variance,6b - Milestones - Assurance,H39 +Assurance MM33 Status,6b - Milestones - Assurance,I39 +Assurance MM33 Notes,6b - Milestones - Assurance,J39 +Assurance MM34,6b - Milestones - Assurance,D40 +Assurance MM34 LoD,6b - Milestones - Assurance,E40 +Assurance MM34 Original Bobline,6b - Milestones - Assurance,F40 +Assurance MM34 Forecast - Actual,6b - Milestones - Assurance,G40 +Assurance MM34 Variance,6b - Milestones - Assurance,H40 +Assurance MM34 Status,6b - Milestones - Assurance,I40 +Assurance MM34 Notes,6b - Milestones - Assurance,J40 +Assurance MM35,6b - Milestones - Assurance,D41 +Assurance MM35 LoD,6b - Milestones - Assurance,E41 +Assurance MM35 Original Bobline,6b - Milestones - Assurance,F41 +Assurance MM35 Forecast - Actual,6b - Milestones - Assurance,G41 +Assurance MM35 Variance,6b - Milestones - Assurance,H41 +Assurance MM35 Status,6b - Milestones - Assurance,I41 +Assurance MM35 Notes,6b - Milestones - Assurance,J41 +Assurance MM36,6b - Milestones - Assurance,D42 +Assurance MM36 LoD,6b - Milestones - Assurance,E42 +Assurance MM36 Original Bobline,6b - Milestones - Assurance,F42 +Assurance MM36 Forecast - Actual,6b - Milestones - Assurance,G42 +Assurance MM36 Variance,6b - Milestones - Assurance,H42 +Assurance MM36 Status,6b - Milestones - Assurance,I42 +Assurance MM36 Notes,6b - Milestones - Assurance,J42 +Assurance MM37,6b - Milestones - Assurance,D43 +Assurance MM37 LoD,6b - Milestones - Assurance,E43 +Assurance MM37 Original Bobline,6b - Milestones - Assurance,F43 +Assurance MM37 Forecast - Actual,6b - Milestones - Assurance,G43 +Assurance MM37 Variance,6b - Milestones - Assurance,H43 +Assurance MM37 Status,6b - Milestones - Assurance,I43 +Assurance MM37 Notes,6b - Milestones - Assurance,J43 +Assurance MM38,6b - Milestones - Assurance,D44 +Assurance MM38 LoD,6b - Milestones - Assurance,E44 +Assurance MM38 Original Bobline,6b - Milestones - Assurance,F44 +Assurance MM38 Forecast - Actual,6b - Milestones - Assurance,G44 +Assurance MM38 Variance,6b - Milestones - Assurance,H44 +Assurance MM38 Status,6b - Milestones - Assurance,I44 +Assurance MM38 Notes,6b - Milestones - Assurance,J44 +Assurance MM39,6b - Milestones - Assurance,D45 +Assurance MM39 LoD,6b - Milestones - Assurance,E45 +Assurance MM39 Original Bobline,6b - Milestones - Assurance,F45 +Assurance MM39 Forecast - Actual,6b - Milestones - Assurance,G45 +Assurance MM39 Variance,6b - Milestones - Assurance,H45 +Assurance MM39 Status,6b - Milestones - Assurance,I45 +Assurance MM39 Notes,6b - Milestones - Assurance,J45 +Assurance MM40,6b - Milestones - Assurance,D46 +Assurance MM40 LoD,6b - Milestones - Assurance,E46 +Assurance MM40 Original Bobline,6b - Milestones - Assurance,F46 +Assurance MM40 Forecast - Actual,6b - Milestones - Assurance,G46 +Assurance MM40 Variance,6b - Milestones - Assurance,H46 +Assurance MM40 Status,6b - Milestones - Assurance,I46 +Assurance MM40 Notes,6b - Milestones - Assurance,J46 +Assurance MM41,6b - Milestones - Assurance,D47 +Assurance MM41 LoD,6b - Milestones - Assurance,E47 +Assurance MM41 Original Bobline,6b - Milestones - Assurance,F47 +Assurance MM41 Forecast - Actual,6b - Milestones - Assurance,G47 +Assurance MM41 Variance,6b - Milestones - Assurance,H47 +Assurance MM41 Status,6b - Milestones - Assurance,I47 +Assurance MM41 Notes,6b - Milestones - Assurance,J47 +Assurance MM42,6b - Milestones - Assurance,D48 +Assurance MM42 LoD,6b - Milestones - Assurance,E48 +Assurance MM42 Original Bobline,6b - Milestones - Assurance,F48 +Assurance MM42 Forecast - Actual,6b - Milestones - Assurance,G48 +Assurance MM42 Variance,6b - Milestones - Assurance,H48 +Assurance MM42 Status,6b - Milestones - Assurance,I48 +Assurance MM42 Notes,6b - Milestones - Assurance,J48 +Assurance MM43,6b - Milestones - Assurance,D49 +Assurance MM43 LoD,6b - Milestones - Assurance,E49 +Assurance MM43 Original Bobline,6b - Milestones - Assurance,F49 +Assurance MM43 Forecast - Actual,6b - Milestones - Assurance,G49 +Assurance MM43 Variance,6b - Milestones - Assurance,H49 +Assurance MM43 Status,6b - Milestones - Assurance,I49 +Assurance MM43 Notes,6b - Milestones - Assurance,J49 +Assurance MM44,6b - Milestones - Assurance,D50 +Assurance MM44 LoD,6b - Milestones - Assurance,E50 +Assurance MM44 Original Bobline,6b - Milestones - Assurance,F50 +Assurance MM44 Forecast - Actual,6b - Milestones - Assurance,G50 +Assurance MM44 Variance,6b - Milestones - Assurance,H50 +Assurance MM44 Status,6b - Milestones - Assurance,I50 +Assurance MM44 Notes,6b - Milestones - Assurance,J50 +Assurance MM45,6b - Milestones - Assurance,D51 +Assurance MM45 LoD,6b - Milestones - Assurance,E51 +Assurance MM45 Original Bobline,6b - Milestones - Assurance,F51 +Assurance MM45 Forecast - Actual,6b - Milestones - Assurance,G51 +Assurance MM45 Variance,6b - Milestones - Assurance,H51 +Assurance MM45 Status,6b - Milestones - Assurance,I51 +Assurance MM45 Notes,6b - Milestones - Assurance,J51 +Assurance MM46,6b - Milestones - Assurance,D52 +Assurance MM46 LoD,6b - Milestones - Assurance,E52 +Assurance MM46 Original Bobline,6b - Milestones - Assurance,F52 +Assurance MM46 Forecast - Actual,6b - Milestones - Assurance,G52 +Assurance MM46 Variance,6b - Milestones - Assurance,H52 +Assurance MM46 Status,6b - Milestones - Assurance,I52 +Assurance MM46 Notes,6b - Milestones - Assurance,J52 +Assurance MM47,6b - Milestones - Assurance,D53 +Assurance MM47 LoD,6b - Milestones - Assurance,E53 +Assurance MM47 Original Bobline,6b - Milestones - Assurance,F53 +Assurance MM47 Forecast - Actual,6b - Milestones - Assurance,G53 +Assurance MM47 Variance,6b - Milestones - Assurance,H53 +Assurance MM47 Status,6b - Milestones - Assurance,I53 +Assurance MM47 Notes,6b - Milestones - Assurance,J53 +Assurance MM48,6b - Milestones - Assurance,D54 +Assurance MM48 LoD,6b - Milestones - Assurance,E54 +Assurance MM48 Original Bobline,6b - Milestones - Assurance,F54 +Assurance MM48 Forecast - Actual,6b - Milestones - Assurance,G54 +Assurance MM48 Variance,6b - Milestones - Assurance,H54 +Assurance MM48 Status,6b - Milestones - Assurance,I54 +Assurance MM48 Notes,6b - Milestones - Assurance,J54 +Assurance MM49,6b - Milestones - Assurance,D55 +Assurance MM49 LoD,6b - Milestones - Assurance,E55 +Assurance MM49 Original Bobline,6b - Milestones - Assurance,F55 +Assurance MM49 Forecast - Actual,6b - Milestones - Assurance,G55 +Assurance MM49 Variance,6b - Milestones - Assurance,H55 +Assurance MM49 Status,6b - Milestones - Assurance,I55 +Assurance MM49 Notes,6b - Milestones - Assurance,J55 +Assurance MM50,6b - Milestones - Assurance,D56 +Assurance MM50 LoD,6b - Milestones - Assurance,E56 +Assurance MM50 Original Bobline,6b - Milestones - Assurance,F56 +Assurance MM50 Forecast - Actual,6b - Milestones - Assurance,G56 +Assurance MM50 Variance,6b - Milestones - Assurance,H56 +Assurance MM50 Status,6b - Milestones - Assurance,I56 +Assurance MM50 Notes,6b - Milestones - Assurance,J56 +Project MM18,6c - Milestones - Delivery,D7 +Project MM18 CP,6c - Milestones - Delivery,E7 +Project MM18 Original Bobline,6c - Milestones - Delivery,F7 +Project MM18 Forecast - Actual,6c - Milestones - Delivery,G7 +Project MM18 Variance,6c - Milestones - Delivery,H7 +Project MM18 Status,6c - Milestones - Delivery,I7 +Project MM18 Notes,6c - Milestones - Delivery,J7 +Project MM19,6c - Milestones - Delivery,D8 +Project MM19 CP,6c - Milestones - Delivery,E8 +Project MM19 Original Bobline,6c - Milestones - Delivery,F8 +Project MM19 Forecast - Actual,6c - Milestones - Delivery,G8 +Project MM19 Variance,6c - Milestones - Delivery,H8 +Project MM19 Status,6c - Milestones - Delivery,I8 +Project MM19 Notes,6c - Milestones - Delivery,J8 +Project MM20,6c - Milestones - Delivery,D9 +Project MM20 CP,6c - Milestones - Delivery,E9 +Project MM20 Original Bobline,6c - Milestones - Delivery,F9 +Project MM20 Forecast - Actual,6c - Milestones - Delivery,G9 +Project MM20 Variance,6c - Milestones - Delivery,H9 +Project MM20 Status,6c - Milestones - Delivery,I9 +Project MM20 Notes,6c - Milestones - Delivery,J9 +Project MM21,6c - Milestones - Delivery,D10 +Project MM21 CP,6c - Milestones - Delivery,E10 +Project MM21 Original Bobline,6c - Milestones - Delivery,F10 +Project MM21 Forecast - Actual,6c - Milestones - Delivery,G10 +Project MM21 Variance,6c - Milestones - Delivery,H10 +Project MM21 Status,6c - Milestones - Delivery,I10 +Project MM21 Notes,6c - Milestones - Delivery,J10 +Project MM22,6c - Milestones - Delivery,D11 +Project MM22 CP,6c - Milestones - Delivery,E11 +Project MM22 Original Bobline,6c - Milestones - Delivery,F11 +Project MM22 Forecast - Actual,6c - Milestones - Delivery,G11 +Project MM22 Variance,6c - Milestones - Delivery,H11 +Project MM22 Status,6c - Milestones - Delivery,I11 +Project MM22 Notes,6c - Milestones - Delivery,J11 +Project MM23,6c - Milestones - Delivery,D12 +Project MM23 CP,6c - Milestones - Delivery,E12 +Project MM23 Original Bobline,6c - Milestones - Delivery,F12 +Project MM23 Forecast - Actual,6c - Milestones - Delivery,G12 +Project MM23 Variance,6c - Milestones - Delivery,H12 +Project MM23 Status,6c - Milestones - Delivery,I12 +Project MM23 Notes,6c - Milestones - Delivery,J12 +Project MM24,6c - Milestones - Delivery,D13 +Project MM24 CP,6c - Milestones - Delivery,E13 +Project MM24 Original Bobline,6c - Milestones - Delivery,F13 +Project MM24 Forecast - Actual,6c - Milestones - Delivery,G13 +Project MM24 Variance,6c - Milestones - Delivery,H13 +Project MM24 Status,6c - Milestones - Delivery,I13 +Project MM24 Notes,6c - Milestones - Delivery,J13 +Project MM25,6c - Milestones - Delivery,D14 +Project MM25 CP,6c - Milestones - Delivery,E14 +Project MM25 Original Bobline,6c - Milestones - Delivery,F14 +Project MM25 Forecast - Actual,6c - Milestones - Delivery,G14 +Project MM25 Variance,6c - Milestones - Delivery,H14 +Project MM25 Status,6c - Milestones - Delivery,I14 +Project MM25 Notes,6c - Milestones - Delivery,J14 +Project MM26,6c - Milestones - Delivery,D15 +Project MM26 CP,6c - Milestones - Delivery,E15 +Project MM26 Original Bobline,6c - Milestones - Delivery,F15 +Project MM26 Forecast - Actual,6c - Milestones - Delivery,G15 +Project MM26 Variance,6c - Milestones - Delivery,H15 +Project MM26 Status,6c - Milestones - Delivery,I15 +Project MM26 Notes,6c - Milestones - Delivery,J15 +Project MM27,6c - Milestones - Delivery,D16 +Project MM27 CP,6c - Milestones - Delivery,E16 +Project MM27 Original Bobline,6c - Milestones - Delivery,F16 +Project MM27 Forecast - Actual,6c - Milestones - Delivery,G16 +Project MM27 Variance,6c - Milestones - Delivery,H16 +Project MM27 Status,6c - Milestones - Delivery,I16 +Project MM27 Notes,6c - Milestones - Delivery,J16 +Project MM28,6c - Milestones - Delivery,D17 +Project MM28 CP,6c - Milestones - Delivery,E17 +Project MM28 Original Bobline,6c - Milestones - Delivery,F17 +Project MM28 Forecast - Actual,6c - Milestones - Delivery,G17 +Project MM28 Variance,6c - Milestones - Delivery,H17 +Project MM28 Status,6c - Milestones - Delivery,I17 +Project MM28 Notes,6c - Milestones - Delivery,J17 +Project MM29,6c - Milestones - Delivery,D18 +Project MM29 CP,6c - Milestones - Delivery,E18 +Project MM29 Original Bobline,6c - Milestones - Delivery,F18 +Project MM29 Forecast - Actual,6c - Milestones - Delivery,G18 +Project MM29 Variance,6c - Milestones - Delivery,H18 +Project MM29 Status,6c - Milestones - Delivery,I18 +Project MM29 Notes,6c - Milestones - Delivery,J18 +Project MM30,6c - Milestones - Delivery,D19 +Project MM30 CP,6c - Milestones - Delivery,E19 +Project MM30 Original Bobline,6c - Milestones - Delivery,F19 +Project MM30 Forecast - Actual,6c - Milestones - Delivery,G19 +Project MM30 Variance,6c - Milestones - Delivery,H19 +Project MM30 Status,6c - Milestones - Delivery,I19 +Project MM30 Notes,6c - Milestones - Delivery,J19 +Project MM31,6c - Milestones - Delivery,D20 +Project MM31 CP,6c - Milestones - Delivery,E20 +Project MM31 Original Bobline,6c - Milestones - Delivery,F20 +Project MM31 Forecast - Actual,6c - Milestones - Delivery,G20 +Project MM31 Variance,6c - Milestones - Delivery,H20 +Project MM31 Status,6c - Milestones - Delivery,I20 +Project MM31 Notes,6c - Milestones - Delivery,J20 +Project MM32,6c - Milestones - Delivery,D21 +Project MM32 CP,6c - Milestones - Delivery,E21 +Project MM32 Original Bobline,6c - Milestones - Delivery,F21 +Project MM32 Forecast - Actual,6c - Milestones - Delivery,G21 +Project MM32 Variance,6c - Milestones - Delivery,H21 +Project MM32 Status,6c - Milestones - Delivery,I21 +Project MM32 Notes,6c - Milestones - Delivery,J21 +Project MM33,6c - Milestones - Delivery,D22 +Project MM33 CP,6c - Milestones - Delivery,E22 +Project MM33 Original Bobline,6c - Milestones - Delivery,F22 +Project MM33 Forecast - Actual,6c - Milestones - Delivery,G22 +Project MM33 Variance,6c - Milestones - Delivery,H22 +Project MM33 Status,6c - Milestones - Delivery,I22 +Project MM33 Notes,6c - Milestones - Delivery,J22 +Project MM34,6c - Milestones - Delivery,D23 +Project MM34 CP,6c - Milestones - Delivery,E23 +Project MM34 Original Bobline,6c - Milestones - Delivery,F23 +Project MM34 Forecast - Actual,6c - Milestones - Delivery,G23 +Project MM34 Variance,6c - Milestones - Delivery,H23 +Project MM34 Status,6c - Milestones - Delivery,I23 +Project MM34 Notes,6c - Milestones - Delivery,J23 +Project MM35,6c - Milestones - Delivery,D24 +Project MM35 CP,6c - Milestones - Delivery,E24 +Project MM35 Original Bobline,6c - Milestones - Delivery,F24 +Project MM35 Forecast - Actual,6c - Milestones - Delivery,G24 +Project MM35 Variance,6c - Milestones - Delivery,H24 +Project MM35 Status,6c - Milestones - Delivery,I24 +Project MM35 Notes,6c - Milestones - Delivery,J24 +Project MM36,6c - Milestones - Delivery,D25 +Project MM36 CP,6c - Milestones - Delivery,E25 +Project MM36 Original Bobline,6c - Milestones - Delivery,F25 +Project MM36 Forecast - Actual,6c - Milestones - Delivery,G25 +Project MM36 Variance,6c - Milestones - Delivery,H25 +Project MM36 Status,6c - Milestones - Delivery,I25 +Project MM36 Notes,6c - Milestones - Delivery,J25 +Project MM37,6c - Milestones - Delivery,D26 +Project MM37 CP,6c - Milestones - Delivery,E26 +Project MM37 Original Bobline,6c - Milestones - Delivery,F26 +Project MM37 Forecast - Actual,6c - Milestones - Delivery,G26 +Project MM37 Variance,6c - Milestones - Delivery,H26 +Project MM37 Status,6c - Milestones - Delivery,I26 +Project MM37 Notes,6c - Milestones - Delivery,J26 +Project MM38,6c - Milestones - Delivery,D27 +Project MM38 CP,6c - Milestones - Delivery,E27 +Project MM38 Original Bobline,6c - Milestones - Delivery,F27 +Project MM38 Forecast - Actual,6c - Milestones - Delivery,G27 +Project MM38 Variance,6c - Milestones - Delivery,H27 +Project MM38 Status,6c - Milestones - Delivery,I27 +Project MM38 Notes,6c - Milestones - Delivery,J27 +Project MM39,6c - Milestones - Delivery,D28 +Project MM39 CP,6c - Milestones - Delivery,E28 +Project MM39 Original Bobline,6c - Milestones - Delivery,F28 +Project MM39 Forecast - Actual,6c - Milestones - Delivery,G28 +Project MM39 Variance,6c - Milestones - Delivery,H28 +Project MM39 Status,6c - Milestones - Delivery,I28 +Project MM39 Notes,6c - Milestones - Delivery,J28 +Project MM40,6c - Milestones - Delivery,D29 +Project MM40 CP,6c - Milestones - Delivery,E29 +Project MM40 Original Bobline,6c - Milestones - Delivery,F29 +Project MM40 Forecast - Actual,6c - Milestones - Delivery,G29 +Project MM40 Variance,6c - Milestones - Delivery,H29 +Project MM40 Status,6c - Milestones - Delivery,I29 +Project MM40 Notes,6c - Milestones - Delivery,J29 +Project MM41,6c - Milestones - Delivery,D30 +Project MM41 CP,6c - Milestones - Delivery,E30 +Project MM41 Original Bobline,6c - Milestones - Delivery,F30 +Project MM41 Forecast - Actual,6c - Milestones - Delivery,G30 +Project MM41 Variance,6c - Milestones - Delivery,H30 +Project MM41 Status,6c - Milestones - Delivery,I30 +Project MM41 Notes,6c - Milestones - Delivery,J30 +Project MM42,6c - Milestones - Delivery,D31 +Project MM42 CP,6c - Milestones - Delivery,E31 +Project MM42 Original Bobline,6c - Milestones - Delivery,F31 +Project MM42 Forecast - Actual,6c - Milestones - Delivery,G31 +Project MM42 Variance,6c - Milestones - Delivery,H31 +Project MM42 Status,6c - Milestones - Delivery,I31 +Project MM42 Notes,6c - Milestones - Delivery,J31 +Project MM43,6c - Milestones - Delivery,D32 +Project MM43 CP,6c - Milestones - Delivery,E32 +Project MM43 Original Bobline,6c - Milestones - Delivery,F32 +Project MM43 Forecast - Actual,6c - Milestones - Delivery,G32 +Project MM43 Variance,6c - Milestones - Delivery,H32 +Project MM43 Status,6c - Milestones - Delivery,I32 +Project MM43 Notes,6c - Milestones - Delivery,J32 +Project MM44,6c - Milestones - Delivery,D33 +Project MM44 CP,6c - Milestones - Delivery,E33 +Project MM44 Original Bobline,6c - Milestones - Delivery,F33 +Project MM44 Forecast - Actual,6c - Milestones - Delivery,G33 +Project MM44 Variance,6c - Milestones - Delivery,H33 +Project MM44 Status,6c - Milestones - Delivery,I33 +Project MM44 Notes,6c - Milestones - Delivery,J33 +Project MM45,6c - Milestones - Delivery,D34 +Project MM45 CP,6c - Milestones - Delivery,E34 +Project MM45 Original Bobline,6c - Milestones - Delivery,F34 +Project MM45 Forecast - Actual,6c - Milestones - Delivery,G34 +Project MM45 Variance,6c - Milestones - Delivery,H34 +Project MM45 Status,6c - Milestones - Delivery,I34 +Project MM45 Notes,6c - Milestones - Delivery,J34 +Project MM46,6c - Milestones - Delivery,D35 +Project MM46 CP,6c - Milestones - Delivery,E35 +Project MM46 Original Bobline,6c - Milestones - Delivery,F35 +Project MM46 Forecast - Actual,6c - Milestones - Delivery,G35 +Project MM46 Variance,6c - Milestones - Delivery,H35 +Project MM46 Status,6c - Milestones - Delivery,I35 +Project MM46 Notes,6c - Milestones - Delivery,J35 +Project MM47,6c - Milestones - Delivery,D36 +Project MM47 CP,6c - Milestones - Delivery,E36 +Project MM47 Original Bobline,6c - Milestones - Delivery,F36 +Project MM47 Forecast - Actual,6c - Milestones - Delivery,G36 +Project MM47 Variance,6c - Milestones - Delivery,H36 +Project MM47 Status,6c - Milestones - Delivery,I36 +Project MM47 Notes,6c - Milestones - Delivery,J36 +Project MM48 ,6c - Milestones - Delivery,D37 +Project MM48 CP,6c - Milestones - Delivery,E37 +Project MM48 Original Bobline,6c - Milestones - Delivery,F37 +Project MM48 Forecast - Actual,6c - Milestones - Delivery,G37 +Project MM48 Variance,6c - Milestones - Delivery,H37 +Project MM48 Status,6c - Milestones - Delivery,I37 +Project MM48 Notes,6c - Milestones - Delivery,J37 +Project MM49,6c - Milestones - Delivery,D38 +Project MM49 CP,6c - Milestones - Delivery,E38 +Project MM49 Original Bobline,6c - Milestones - Delivery,F38 +Project MM49 Forecast - Actual,6c - Milestones - Delivery,G38 +Project MM49 Variance,6c - Milestones - Delivery,H38 +Project MM49 Status,6c - Milestones - Delivery,I38 +Project MM49 Notes,6c - Milestones - Delivery,J38 +Project MM50,6c - Milestones - Delivery,D39 +Project MM50 CP,6c - Milestones - Delivery,E39 +Project MM50 Original Bobline,6c - Milestones - Delivery,F39 +Project MM50 Forecast - Actual,6c - Milestones - Delivery,G39 +Project MM50 Variance,6c - Milestones - Delivery,H39 +Project MM50 Status,6c - Milestones - Delivery,I39 +Project MM50 Notes,6c - Milestones - Delivery,J39 +Project MM51,6c - Milestones - Delivery,D40 +Project MM51 CP,6c - Milestones - Delivery,E40 +Project MM51 Original Bobline,6c - Milestones - Delivery,F40 +Project MM51 Forecast - Actual,6c - Milestones - Delivery,G40 +Project MM51 Variance,6c - Milestones - Delivery,H40 +Project MM51 Status,6c - Milestones - Delivery,I40 +Project MM51 Notes,6c - Milestones - Delivery,J40 +Project MM52,6c - Milestones - Delivery,D41 +Project MM52 CP,6c - Milestones - Delivery,E41 +Project MM52 Original Bobline,6c - Milestones - Delivery,F41 +Project MM52 Forecast - Actual,6c - Milestones - Delivery,G41 +Project MM52 Variance,6c - Milestones - Delivery,H41 +Project MM52 Status,6c - Milestones - Delivery,I41 +Project MM52 Notes,6c - Milestones - Delivery,J41 +Project MM53,6c - Milestones - Delivery,D42 +Project MM53 CP,6c - Milestones - Delivery,E42 +Project MM53 Original Bobline,6c - Milestones - Delivery,F42 +Project MM53 Forecast - Actual,6c - Milestones - Delivery,G42 +Project MM53 Variance,6c - Milestones - Delivery,H42 +Project MM53 Status,6c - Milestones - Delivery,I42 +Project MM53 Notes,6c - Milestones - Delivery,J42 +Project MM54,6c - Milestones - Delivery,D43 +Project MM54 CP,6c - Milestones - Delivery,E43 +Project MM54 Original Bobline,6c - Milestones - Delivery,F43 +Project MM54 Forecast - Actual,6c - Milestones - Delivery,G43 +Project MM54 Variance,6c - Milestones - Delivery,H43 +Project MM54 Status,6c - Milestones - Delivery,I43 +Project MM54 Notes,6c - Milestones - Delivery,J43 +Project MM55,6c - Milestones - Delivery,D44 +Project MM55 CP,6c - Milestones - Delivery,E44 +Project MM55 Original Bobline,6c - Milestones - Delivery,F44 +Project MM55 Forecast - Actual,6c - Milestones - Delivery,G44 +Project MM55 Variance,6c - Milestones - Delivery,H44 +Project MM55 Status,6c - Milestones - Delivery,I44 +Project MM55 Notes,6c - Milestones - Delivery,J44 +Project MM56,6c - Milestones - Delivery,D45 +Project MM56 CP,6c - Milestones - Delivery,E45 +Project MM56 Original Bobline,6c - Milestones - Delivery,F45 +Project MM56 Forecast - Actual,6c - Milestones - Delivery,G45 +Project MM56 Variance,6c - Milestones - Delivery,H45 +Project MM56 Status,6c - Milestones - Delivery,I45 +Project MM56 Notes,6c - Milestones - Delivery,J45 +Project MM57,6c - Milestones - Delivery,D46 +Project MM57 CP,6c - Milestones - Delivery,E46 +Project MM57 Original Bobline,6c - Milestones - Delivery,F46 +Project MM57 Forecast - Actual,6c - Milestones - Delivery,G46 +Project MM57 Variance,6c - Milestones - Delivery,H46 +Project MM57 Status,6c - Milestones - Delivery,I46 +Project MM57 Notes,6c - Milestones - Delivery,J46 +Project MM58,6c - Milestones - Delivery,D47 +Project MM58 CP,6c - Milestones - Delivery,E47 +Project MM58 Original Bobline,6c - Milestones - Delivery,F47 +Project MM58 Forecast - Actual,6c - Milestones - Delivery,G47 +Project MM58 Variance,6c - Milestones - Delivery,H47 +Project MM58 Status,6c - Milestones - Delivery,I47 +Project MM58 Notes,6c - Milestones - Delivery,J47 +Project MM59,6c - Milestones - Delivery,D48 +Project MM59 CP,6c - Milestones - Delivery,E48 +Project MM59 Original Bobline,6c - Milestones - Delivery,F48 +Project MM59 Forecast - Actual,6c - Milestones - Delivery,G48 +Project MM59 Variance,6c - Milestones - Delivery,H48 +Project MM59 Status,6c - Milestones - Delivery,I48 +Project MM59 Notes,6c - Milestones - Delivery,J48 +Project MM60,6c - Milestones - Delivery,D49 +Project MM60 CP,6c - Milestones - Delivery,E49 +Project MM60 Original Bobline,6c - Milestones - Delivery,F49 +Project MM60 Forecast - Actual,6c - Milestones - Delivery,G49 +Project MM60 Variance,6c - Milestones - Delivery,H49 +Project MM60 Status,6c - Milestones - Delivery,I49 +Project MM60 Notes,6c - Milestones - Delivery,J49 +Project MM61,6c - Milestones - Delivery,D50 +Project MM61 CP,6c - Milestones - Delivery,E50 +Project MM61 Original Bobline,6c - Milestones - Delivery,F50 +Project MM61 Forecast - Actual,6c - Milestones - Delivery,G50 +Project MM61 Variance,6c - Milestones - Delivery,H50 +Project MM61 Status,6c - Milestones - Delivery,I50 +Project MM61 Notes,6c - Milestones - Delivery,J50 +Project MM62,6c - Milestones - Delivery,D51 +Project MM62 CP,6c - Milestones - Delivery,E51 +Project MM62 Original Bobline,6c - Milestones - Delivery,F51 +Project MM62 Forecast - Actual,6c - Milestones - Delivery,G51 +Project MM62 Variance,6c - Milestones - Delivery,H51 +Project MM62 Status,6c - Milestones - Delivery,I51 +Project MM62 Notes,6c - Milestones - Delivery,J51 +Project MM63,6c - Milestones - Delivery,D52 +Project MM63 CP,6c - Milestones - Delivery,E52 +Project MM63 Original Bobline,6c - Milestones - Delivery,F52 +Project MM63 Forecast - Actual,6c - Milestones - Delivery,G52 +Project MM63 Variance,6c - Milestones - Delivery,H52 +Project MM63 Status,6c - Milestones - Delivery,I52 +Project MM63 Notes,6c - Milestones - Delivery,J52 +Project MM64,6c - Milestones - Delivery,D53 +Project MM64 CP,6c - Milestones - Delivery,E53 +Project MM64 Original Bobline,6c - Milestones - Delivery,F53 +Project MM64 Forecast - Actual,6c - Milestones - Delivery,G53 +Project MM64 Variance,6c - Milestones - Delivery,H53 +Project MM64 Status,6c - Milestones - Delivery,I53 +Project MM64 Notes,6c - Milestones - Delivery,J53 +Project MM65,6c - Milestones - Delivery,D54 +Project MM65 CP,6c - Milestones - Delivery,E54 +Project MM65 Original Bobline,6c - Milestones - Delivery,F54 +Project MM65 Forecast - Actual,6c - Milestones - Delivery,G54 +Project MM65 Variance,6c - Milestones - Delivery,H54 +Project MM65 Status,6c - Milestones - Delivery,I54 +Project MM65 Notes,6c - Milestones - Delivery,J54 +Project MM66,6c - Milestones - Delivery,D55 +Project MM66 CP,6c - Milestones - Delivery,E55 +Project MM66 Original Bobline,6c - Milestones - Delivery,F55 +Project MM66 Forecast - Actual,6c - Milestones - Delivery,G55 +Project MM66 Variance,6c - Milestones - Delivery,H55 +Project MM66 Status,6c - Milestones - Delivery,I55 +Project MM66 Notes,6c - Milestones - Delivery,J55 +Project MM67,6c - Milestones - Delivery,D56 +Project MM67 CP,6c - Milestones - Delivery,E56 +Project MM67 Original Bobline,6c - Milestones - Delivery,F56 +Project MM67 Forecast - Actual,6c - Milestones - Delivery,G56 +Project MM67 Variance,6c - Milestones - Delivery,H56 +Project MM67 Status,6c - Milestones - Delivery,I56 +Project MM67 Notes,6c - Milestones - Delivery,J56 +Milestone Commentary,6c - Milestones - Delivery,F110 +SRO Schedule Confidence,6c - Milestones - Delivery,F109 +Project stage,7 - Business Case,E6 +Project Stage if Other,7 - Business Case,E7 +Latest Treasury Approval Point (TAP) or equivalent,7 - Business Case,E10 +Version Number Of Document used to Source Figures (DRRDD - TAP version Number),7 - Business Case,E11 +Business Case & Version No.,7 - Business Case,E12 +Date of TAP used to source figures,7 - Business Case,E13 +"If no HMT Business Case, please advise why?",7 - Business Case,E14 +"Is your HMT Business case updated / approved annually by HMT, or more frequently?",7 - Business Case,E15 +Does the HMT Businesss Case cover the full life of the project?,7 - Business Case,E16 +"If not, please provide explanation as to why",7 - Business Case,E17 +"If not, please advise how many years are covered",7 - Business Case,E18 +"If not, please advise how much cost is covered, as a percentage",7 - Business Case,E19 +Are the baselines in this return from the most recent HMT Approved Business Case?,7 - Business Case,E20 +"If not, what is the source of baselines in this returns?",7 - Business Case,E21 +"If not, please give a reason why baselines",7 - Business Case,E22 +What is the source of all forecasts in this return?,7 - Business Case,E23 +"Please provide details of any formal arrangement with HMT regarding Business cases, that are outside the classical model",7 - Business Case,E24 +BC One Off new costs,7 - Business Case,E29 +BC Recurring new costs,7 - Business Case,F29 +BC Recurring old costs,7 - Business Case,G29 +BC Non Government costs,7 - Business Case,H29 +BC Income,7 - Business Case,I29 +BC Cashable benefits,7 - Business Case,E31 +BC Non-Cashable benefits,7 - Business Case,F31 +BC UK Economic benefits,7 - Business Case,G31 +BC Disbenefits in the cost section,7 - Business Case,H31 +BC Positive AME benefits in Cashable,7 - Business Case,I31 +BC Non Monetised Benefits,7 - Business Case,J31 +Real or Nominal - Bobline,8 - Finance,E6 +Real or Nominal - Actual/Forecast,8 - Finance,E7 +Index Year,8 - Finance,E8 +Deflator,8 - Finance,E9 +Are you reporting the full costs of the project?,8 - Finance,E10 +"If no, please provide reason why?",8 - Finance,E11 +Does this project create income?,8 - Finance,E14 +Who recieves the income?,8 - Finance,E15 +Do you net the income with your costs in the DRRDD return,8 - Finance,E16 +Income Against which Cost category?,8 - Finance,E17 +Income Bobline - Real or Nominal,8 - Finance,E18 +Income Forecast - Real or Nominal,8 - Finance,E19 +"Income If real, Index Year used?",8 - Finance,E20 +"Income If real, Deflator used?",8 - Finance,E21 +Are you reporting the full income of the project?,8 - Finance,E22 +"Income If no, please provide reason why?",8 - Finance,E23 +Does this project create monetised benefits?,8 - Finance,E26 +Benefits Bobline - Real or Nominal,8 - Finance,E27 +Benefits Forecast - Real or Nominal,8 - Finance,E28 +"Benefits If real, Index Year used?",8 - Finance,E29 +"Benefits If real, Deflator used?",8 - Finance,E30 +Are you reporting the full benefits of the project?,8 - Finance,E31 +"Benefits If no, please provide reason why?",8 - Finance,E32 +Source of Finance,8 - Finance,E35 +Other Finance type Description,8 - Finance,E36 +Optimism Bias Percentage Used in Cost Boblines,8 - Finance,E37 +Overall figure for Optimism Bias (£m),8 - Finance,E38 +Built in contingency (% of Whole Life Cost),8 - Finance,E39 +Overall contingency (£m),8 - Finance,E40 +NPV for all projects and NPV for programmes if available,8 - Finance,E41 +Internal Rate of Return (IRR),8 - Finance,E42 +Adjusted Benefits Cost Ratio (BCR),8 - Finance,E43 +Benefits Map,8 - Finance,E47 +Benefits Analysed,8 - Finance,E48 +Benefits Realisation Plan,8 - Finance,E49 +Initial Benefits Cost Ratio (BCR),8 - Finance,E44 +VfM Category,8 - Finance,E50 +Present Value Cost (PVC),8 - Finance,E45 +Present Value Benefit (PVB),8 - Finance,E46 +Project Costs Narrative,9 - Costs,E6 +Cost comparison with last quarters cost - narrative ,9 - Costs,E7 +Cost comparison within this quarters cost - narrative ,9 - Costs,E8 +Total Budget/BL,9 - Costs,F20 +Total Forecast,9 - Costs,H20 +Pre 19-20 TDEL BL one off new costs,9 - Costs,E27 +Pre 19-20 TDEL BL recurring new costs,9 - Costs,F27 +Pre 19-20 TDEL BL recurring old costs,9 - Costs,G27 +Pre 19-20 TDEL BL Non Gov costs,9 - Costs,H27 +Pre 19-20 TDEL BL Total,9 - Costs,I27 +Pre 19-20 TDEL BL Income,9 - Costs,L27 +Pre 19-20 TDEL Forecast one off new costs,9 - Costs,E28 +Pre 19-20 TDEL Forecast recurring new costs,9 - Costs,F28 +Pre 19-20 TDEL Forecast recurring old costs,9 - Costs,G28 +Pre 19-20 TDEL Forecast Non Gov costs,9 - Costs,H28 +Pre 19-20 TDEL Forecast Total,9 - Costs,I28 +Pre 19-20 TDEL Forecast Income,9 - Costs,L28 +19-20 TDEL BL one off new costs,9 - Costs,E29 +19-20 TDEL BL recurring new costs,9 - Costs,F29 +19-20 TDEL BL recurring old costs,9 - Costs,G29 +19-20 TDEL BL Non Gov costs,9 - Costs,H29 +19-20 TDEL BL Total,9 - Costs,I29 +19-20 TDEL BL Income,9 - Costs,L29 +19-20 TDEL Forecast one off new costs,9 - Costs,E30 +19-20 TDEL Forecast recurring new costs,9 - Costs,F30 +19-20 TDEL Forecast recurring old costs,9 - Costs,G30 +19-20 TDEL Forecast Non Gov costs,9 - Costs,H30 +19-20 TDEL Forecast Total,9 - Costs,I30 +19-20 TDEL Forecast Income,9 - Costs,L30 +20-21 TDEL BL one off new costs,9 - Costs,E31 +20-21 TDEL BL recurring new costs,9 - Costs,F31 +20-21 TDEL BL recurring old costs,9 - Costs,G31 +20-21 TDEL BL Non Gov costs,9 - Costs,H31 +20-21 TDEL BL Total,9 - Costs,I31 +20-21 TDEL BL Income,9 - Costs,L31 +20-21 TDEL Forecast one off new costs,9 - Costs,E32 +20-21 TDEL Forecast recurring new costs,9 - Costs,F32 +20-21 TDEL Forecast recurring old costs,9 - Costs,G32 +20-21 TDEL Forecast Non Gov costs,9 - Costs,H32 +20-21 TDEL Forecast Total,9 - Costs,I32 +20-21 TDEL Forecast Income,9 - Costs,L32 +21-22 TDEL BL one off new costs,9 - Costs,E33 +21-22 TDEL BL recurring new costs,9 - Costs,F33 +21-22 TDEL BL recurring old costs,9 - Costs,G33 +21-22 TDEL BL Non Gov costs,9 - Costs,H33 +21-22 TDEL BL Total,9 - Costs,I33 +21-22 TDEL BL Income,9 - Costs,L33 +21-22 TDEL Forecast one off new costs,9 - Costs,E34 +21-22 TDEL Forecast recurring new costs,9 - Costs,F34 +21-22 TDEL Forecast recurring old costs,9 - Costs,G34 +21-22 TDEL Forecast Non Gov costs,9 - Costs,H34 +21-22 TDEL Forecast Total,9 - Costs,I34 +21-22 TDEL Forecast Income,9 - Costs,L34 +22-23 TDEL BL one off new costs,9 - Costs,E35 +22-23 TDEL BL recurring new costs,9 - Costs,F35 +22-23 TDEL BL recurring old costs,9 - Costs,G35 +22-23 TDEL BL Non Gov costs,9 - Costs,H35 +22-23 TDEL BL Total,9 - Costs,I35 +22-23 TDEL BL Income,9 - Costs,L35 +22-23 TDEL Forecast one off new costs,9 - Costs,E36 +22-23 TDEL Forecast recurring new costs,9 - Costs,F36 +22-23 TDEL Forecast recurring old costs,9 - Costs,G36 +22-23 TDEL Forecast Non Gov costs,9 - Costs,H36 +22-23 TDEL Forecast Total,9 - Costs,I36 +22-23 TDEL Forecast Income,9 - Costs,L36 +23-24 TDEL BL one off new costs,9 - Costs,E37 +23-24 TDEL BL recurring new costs,9 - Costs,F37 +23-24 TDEL BL recurring old costs,9 - Costs,G37 +23-24 TDEL BL Non Gov costs,9 - Costs,H37 +23-24 TDEL BL Total,9 - Costs,I37 +23-24 TDEL BL Income,9 - Costs,L37 +23-24 TDEL Forecast one off new costs,9 - Costs,E38 +23-24 TDEL Forecast recurring new costs,9 - Costs,F38 +23-24 TDEL Forecast recurring old costs,9 - Costs,G38 +23-24 TDEL Forecast Non Gov costs,9 - Costs,H38 +23-24 TDEL Forecast Total,9 - Costs,I38 +23-24 TDEL Forecast Income,9 - Costs,L38 +24-25 TDEL BL one off new costs,9 - Costs,E39 +24-25 TDEL BL recurring new costs,9 - Costs,F39 +24-25 TDEL BL recurring old costs,9 - Costs,G39 +24-25 TDEL BL Non Gov costs,9 - Costs,H39 +24-25 TDEL BL Total,9 - Costs,I39 +24-25 TDEL BL Income,9 - Costs,L39 +24-25 TDEL Forecast one off new costs,9 - Costs,E40 +24-25 TDEL Forecast recurring new costs,9 - Costs,F40 +24-25 TDEL Forecast recurring old costs,9 - Costs,G40 +24-25 TDEL Forecast Non Gov costs,9 - Costs,H40 +24-25 TDEL Forecast Total,9 - Costs,I40 +24-25 TDEL Forecast Income,9 - Costs,L40 +25-26 TDEL BL one off new costs,9 - Costs,E41 +25-26 TDEL BL recurring new costs,9 - Costs,F41 +25-26 TDEL BL recurring old costs,9 - Costs,G41 +25-26 TDEL BL Non Gov costs,9 - Costs,H41 +25-26 TDEL BL Total,9 - Costs,I41 +25-26 TDEL BL Income,9 - Costs,L41 +25-26 TDEL Forecast one off new costs,9 - Costs,E42 +25-26 TDEL Forecast recurring new costs,9 - Costs,F42 +25-26 TDEL Forecast recurring old costs,9 - Costs,G42 +25-26 TDEL Forecast Non Gov costs,9 - Costs,H42 +25-26 TDEL Forecast Total,9 - Costs,I42 +25-26 TDEL Forecast Income,9 - Costs,L42 +26-27 TDEL BL one off new costs,9 - Costs,E43 +26-27 TDEL BL recurring new costs,9 - Costs,F43 +26-27 TDEL BL recurring old costs,9 - Costs,G43 +26-27 TDEL BL Non Gov costs,9 - Costs,H43 +26-27 TDEL BL Total,9 - Costs,I43 +26-27 TDEL BL Income,9 - Costs,L43 +26-27 TDEL Forecast one off new costs,9 - Costs,E44 +26-27 TDEL Forecast recurring new costs,9 - Costs,F44 +26-27 TDEL Forecast recurring old costs,9 - Costs,G44 +26-27 TDEL Forecast Non Gov costs,9 - Costs,H44 +26-27 TDEL Forecast Total,9 - Costs,I44 +26-27 TDEL Forecast Income,9 - Costs,L44 +27-28 TDEL BL one off new costs,9 - Costs,E45 +27-28 TDEL BL recurring new costs,9 - Costs,F45 +27-28 TDEL BL recurring old costs,9 - Costs,G45 +27-28 TDEL BL Non Gov costs,9 - Costs,H45 +27-28 TDEL BL Total,9 - Costs,I45 +27-28 TDEL BL Income,9 - Costs,L45 +27-28 TDEL Forecast one off new costs,9 - Costs,E46 +27-28 TDEL Forecast recurring new costs,9 - Costs,F46 +27-28 TDEL Forecast recurring old costs,9 - Costs,G46 +27-28 TDEL Forecast Non Gov costs,9 - Costs,H46 +27-28 TDEL Forecast Total,9 - Costs,I46 +27-28 TDEL Forecast Income,9 - Costs,L46 +28-29 TDEL BL one off new costs,9 - Costs,E47 +28-29 TDEL BL recurring new costs,9 - Costs,F47 +28-29 TDEL BL recurring old costs,9 - Costs,G47 +28-29 TDEL BL Non Gov costs,9 - Costs,H47 +28-29 TDEL BL Total,9 - Costs,I47 +28-29 TDEL BL Income,9 - Costs,L47 +28-29 TDEL Forecast one off new costs,9 - Costs,E48 +28-29 TDEL Forecast recurring new costs,9 - Costs,F48 +28-29 TDEL Forecast recurring old costs,9 - Costs,G48 +28-29 TDEL Forecast Non Gov costs,9 - Costs,H48 +28-29 TDEL Forecast Total,9 - Costs,I48 +28-29 TDEL Forecast Income,9 - Costs,L48 +Unprofiled TDEL BL one off new costs,9 - Costs,E49 +Unprofiled TDEL BL recurring new costs,9 - Costs,F49 +Unprofiled TDEL BL recurring old costs,9 - Costs,G49 +Unprofiled TDEL BL Non Gov costs,9 - Costs,H49 +Unprofiled TDEL BL Total,9 - Costs,I49 +Unprofiled TDEL BL Income,9 - Costs,L49 +Unprofiled TDEL Forecast one off new costs,9 - Costs,E50 +Unprofiled TDEL Forecast recurring new costs,9 - Costs,F50 +Unprofiled TDEL Forecast recurring old costs,9 - Costs,G50 +Unprofiled TDEL Forecast Non Gov costs,9 - Costs,H50 +Unprofiled TDEL Forecast Total,9 - Costs,I50 +Unprofiled TDEL Forecast Income,9 - Costs,L50 +Total TDEL BL one off new costs,9 - Costs,E51 +Total TDEL BL recurring new costs,9 - Costs,F51 +Total TDEL BL recurring old costs,9 - Costs,G51 +Total TDEL BL Non Gov costs,9 - Costs,H51 +Total TDEL BL Total,9 - Costs,I51 +Total TDEL BL Income,9 - Costs,L51 +Total TDEL Forecast one off new costs,9 - Costs,E52 +Total TDEL Forecast recurring new costs,9 - Costs,F52 +Total TDEL Forecast recurring old costs,9 - Costs,G52 +Total TDEL Forecast Non Gov costs,9 - Costs,H52 +Total TDEL Forecast Total,9 - Costs,I52 +Total TDEL Forecast Income,9 - Costs,L52 +Year TDEL spend stops,9 - Costs,E53 +Pre 19-20 CDEL BL one off new costs,9 - Costs,E56 +Pre 19-20 CDEL BL recurring new costs,9 - Costs,F56 +Pre 19-20 CDEL BL recurring old costs,9 - Costs,G56 +Pre 19-20 BL Non-Gov,9 - Costs,H56 +Pre 19-20 CDEL BL WLC,9 - Costs,I56 +Pre 19-20 BL Income both Revenue and Capital,9 - Costs,L56 +Pre 19-20 CDEL Forecast Total,9 - Costs,E57 +Pre 19-20 CDEL Forecast recurring new costs,9 - Costs,F57 +Pre 19-20 CDEL Forecast recurring old costs,9 - Costs,G57 +Pre 19-20 Forecast Non-Gov,9 - Costs,H57 +Pre 19-20 CDEL Forecast Total WLC,9 - Costs,I57 +Pre 19-20 Actual Income both Revenue and Capital,9 - Costs,L57 +19-20 CDEL BL one off new costs,9 - Costs,E58 +19-20 CDEL BL recurring new costs,9 - Costs,F58 +19-20 CDEL BL recurring old costs,9 - Costs,G58 +19-20 BL Non-Gov,9 - Costs,H58 +19-20 CDEL BL WLC,9 - Costs,I58 +19-20 BL Income both Revenue and Capital,9 - Costs,L58 +19-20 CDEL Forecast Total,9 - Costs,E59 +19-20 CDEL Forecast recurring new costs,9 - Costs,F59 +19-20 CDEL Forecast recurring old costs,9 - Costs,G59 +19-20 Forecast Non-Gov,9 - Costs,H59 +19-20 CDEL Forecast Total WLC,9 - Costs,I59 +19-20 Forecast - Income both Revenue and Capital,9 - Costs,L59 +20-21 CDEL BL one off new costs,9 - Costs,E60 +20-21 CDEL BL recurring new costs,9 - Costs,F60 +20-21 CDEL BL recurring old costs,9 - Costs,G60 +20-21 BL Non-Gov,9 - Costs,H60 +20-21 CDEL BL WLC,9 - Costs,I60 +20-21 BL Income both Revenue and Capital,9 - Costs,L60 +20-21 CDEL Forecast Total,9 - Costs,E61 +20-21 CDEL Forecast recurring new costs,9 - Costs,F61 +20-21 CDEL Forecast recurring old costs,9 - Costs,G61 +20-21 Forecast Non-Gov,9 - Costs,H61 +20-21 CDEL Forecast Total WLC,9 - Costs,I61 +20-21 Forecast - Income both Revenue and Capital,9 - Costs,L61 +21-22 CDEL BL one off new costs,9 - Costs,E62 +21-22 CDEL BL recurring new costs,9 - Costs,F62 +21-22 CDEL BL recurring old costs,9 - Costs,G62 +21-22 BL Non-Gov,9 - Costs,H62 +21-22 CDEL BL WLC,9 - Costs,I62 +21-22 BL - Income both Revenue and Capital,9 - Costs,L62 +21-22 CDEL Forecast Total,9 - Costs,E63 +21-22 CDEL Forecast recurring new costs,9 - Costs,F63 +21-22 CDEL Forecast recurring old costs,9 - Costs,G63 +21-22 Forecast Non-Gov,9 - Costs,H63 +21-22 CDEL Forecast Total WLC,9 - Costs,I63 +21-22 Forecast - Income both Revenue and Capital,9 - Costs,L63 +22-23 CDEL BL one off new costs,9 - Costs,E64 +22-23 CDEL BL recurring new costs,9 - Costs,F64 +22-23 CDEL BL recurring old costs,9 - Costs,G64 +22-23 BL Non-Gov,9 - Costs,H64 +22-23 CDEL BL WLC,9 - Costs,I64 +22-23 BL Income both Revenue and Capital,9 - Costs,L64 +22-23 CDEL Forecast Total,9 - Costs,E65 +22-23 CDEL Forecast recurring new costs,9 - Costs,F65 +22-23 CDEL Forecast recurring old costs,9 - Costs,G65 +22-23 Forecast Non-Gov,9 - Costs,H65 +22-23 CDEL Forecast Total WLC,9 - Costs,I65 +22-23 Forecast - Income both Revenue and Capital,9 - Costs,L65 +23-24 CDEL BL one off new costs,9 - Costs,E66 +23-24 CDEL BL recurring new costs,9 - Costs,F66 +23-24 CDEL BL recurring old costs,9 - Costs,G66 +23-24 BL Non-Gov,9 - Costs,H66 +23-24 CDEL BL WLC,9 - Costs,I66 +23-24 BL Income both Revenue and Capital,9 - Costs,L66 +23-24 CDEL Forecast Total,9 - Costs,E67 +23-24 CDEL Forecast recurring new costs,9 - Costs,F67 +23-24 CDEL Forecast recurring old costs,9 - Costs,G67 +23-24 Forecast Non-Gov,9 - Costs,H67 +23-24 CDEL Forecast Total WLC,9 - Costs,I67 +23-24 Forecast - Income both Revenue and Capital,9 - Costs,L67 +24-25 CDEL BL one off new costs,9 - Costs,E68 +24-25 CDEL BL recurring new costs,9 - Costs,F68 +24-25 CDEL BL recurring old costs,9 - Costs,G68 +24-25 BL Non-Gov,9 - Costs,H68 +24-25 CDEL BL WLC,9 - Costs,I68 +24-25 BL Income both Revenue and Capital,9 - Costs,L68 +24-25 CDEL Forecast Total,9 - Costs,E69 +24-25 CDEL Forecast recurring new costs,9 - Costs,F69 +24-25 CDEL Forecast recurring old costs,9 - Costs,G69 +24-25 Forecast Non-Gov,9 - Costs,H69 +24-25 CDEL Forecast Total WLC,9 - Costs,I69 +24-25 Forecast - Income both Revenue and Capital,9 - Costs,L69 +25-26 CDEL BL one off new costs,9 - Costs,E70 +25-26 CDEL BL recurring new costs,9 - Costs,F70 +25-26 CDEL BL recurring old costs,9 - Costs,G70 +25-26 BL Non-Gov,9 - Costs,H70 +25-26 CDEL BL WLC,9 - Costs,I70 +25-26 BL Income both Revenue and Capital,9 - Costs,L70 +25-26 CDEL Forecast Total,9 - Costs,E71 +25-26 CDEL Forecast recurring new costs,9 - Costs,F71 +25-26 CDEL Forecast recurring old costs,9 - Costs,G71 +25-26 Forecast Non-Gov,9 - Costs,H71 +25-26 CDEL Forecast Total WLC,9 - Costs,I71 +25-26 Forecast - Income both Revenue and Capital,9 - Costs,L71 +26-27 CDEL BL one off new costs,9 - Costs,E72 +26-27 CDEL BL recurring new costs,9 - Costs,F72 +26-27 CDEL BL recurring old costs,9 - Costs,G72 +26-27 BL Non-Gov,9 - Costs,H72 +26-27 CDEL BL WLC,9 - Costs,I72 +26-27 BL Income both Revenue and Capital,9 - Costs,L72 +26-27 CDEL Forecast Total,9 - Costs,E73 +26-27 CDEL Forecast recurring new costs,9 - Costs,F73 +26-27 CDEL Forecast recurring old costs,9 - Costs,G73 +26-27 Forecast Non-Gov,9 - Costs,H73 +26-27 CDEL Forecast Total WLC,9 - Costs,I73 +26-27 Forecast - Income both Revenue and Capital,9 - Costs,L73 +27-28 CDEL BL one off new costs,9 - Costs,E74 +27-28 CDEL BL recurring new costs,9 - Costs,F74 +27-28 CDEL BL recurring old costs,9 - Costs,G74 +27-28 BL Non-Gov,9 - Costs,H74 +27-28 CDEL BL WLC,9 - Costs,I74 +27-28 BL Income both Revenue and Capital,9 - Costs,L74 +27-28 CDEL Forecast Total,9 - Costs,E75 +27-28 CDEL Forecast recurring new costs,9 - Costs,F75 +27-28 CDEL Forecast recurring old costs,9 - Costs,G75 +27-28 Forecast Non-Gov,9 - Costs,H75 +27-28 CDEL Forecast Total WLC,9 - Costs,I75 +27-28 Forecast - Income both Revenue and Capital,9 - Costs,L75 +28-29 CDEL BL one off new costs,9 - Costs,E76 +28-29 CDEL BL recurring new costs,9 - Costs,F76 +28-29 CDEL BL recurring old costs,9 - Costs,G76 +28-29 BL Non-Gov,9 - Costs,H76 +28-29 CDEL BL WLC,9 - Costs,I76 +28-29 BL Income both Revenue and Capital,9 - Costs,L76 +28-29 CDEL Forecast Total,9 - Costs,E77 +28-29 CDEL Forecast recurring new costs,9 - Costs,F77 +28-29 CDEL Forecast recurring old costs,9 - Costs,G77 +28-29 Forecast Non-Gov,9 - Costs,H77 +28-29 CDEL Forecast Total WLC,9 - Costs,I77 +28-29 Forecast - Income both Revenue and Capital,9 - Costs,L77 +Unprofiled CDEL BL one off new costs,9 - Costs,E78 +Unprofiled CDEL BL recurring new costs,9 - Costs,F78 +Unprofiled CDEL BL recurring old costs,9 - Costs,G78 +Unprofiled BL Non-Gov,9 - Costs,H78 +Unprofiled CDEL BL WLC,9 - Costs,I78 +Unprofiled BL Income,9 - Costs,L78 +Unprofiled CDEL Forecast Total,9 - Costs,E79 +Unprofiled CDEL Forecast recurring new costs,9 - Costs,F79 +Unprofiled CDEL Forecast recurring old costs,9 - Costs,G79 +Unprofiled Forecast-Gov,9 - Costs,H79 +Unprofiled CDEL Forecast Total WLC,9 - Costs,I79 +Unprofiled Forecast Income,9 - Costs,L79 +Total CDEL BL one off new costs,9 - Costs,E80 +Total CDEL BL recurring new costs,9 - Costs,F80 +Total CDEL BL recurring old costs,9 - Costs,G80 +Non-Gov Total Budget/BL,9 - Costs,H80 +Total CDEL BL WLC,9 - Costs,I80 +Total Bobline - Income both Revenue and Capital,9 - Costs,L80 +Total CDEL Forecast Total,9 - Costs,E81 +Total CDEL Forecast recurring new costs,9 - Costs,F81 +Total CDEL Forecast recurring old costs,9 - Costs,G81 +Non-Gov Total Forecast,9 - Costs,H81 +Total CDEL Forecast Total WLC,9 - Costs,I81 +Total Forecast - Income both Revenue and Capital,9 - Costs,L81 +Year CDEL spend stops,9 - Costs,E82 +SRO Finance confidence,9 - Costs,E118 +Benefits Narrative,10 - Benefits,E6 +Ben comparison with last quarters cost - narrative ,10 - Benefits,E7 +Ben comparison within this quarters cost - narrative ,10 - Benefits,E8 +Narrative on any project Non-Monetised benefits,10 - Benefits,E9 +"If benefits profile (by years) not provided, please provide reason and date for when they will be",10 - Benefits,E10 +Pre 19-20 BEN Bobline - Gov. Cashable,10 - Benefits,E25 +Pre 19-20 BEN Bobline - Gov. Non-Cashable,10 - Benefits,F25 +Pre 19-20 BEN Bobline - Economic (inc Private Partner),10 - Benefits,G25 +Pre 19-20 BEN Bobline - Disbenefit UK Economic,10 - Benefits,H25 +Pre 19-20 BEN Bobline - Total Monetised Benefits,10 - Benefits,K25 +Pre 19-20 BEN Forecast - Gov. Cashable,10 - Benefits,E26 +Pre 19-20 BEN Forecast - Gov. Non-Cashable,10 - Benefits,F26 +Pre 19-20 BEN Forecast - Economic (inc Private Partner),10 - Benefits,G26 +Pre 19-20 BEN Forecast - Disbenefit UK Economic,10 - Benefits,H26 +Pre 19-20 BEN Forecast - Total Monetised Benefits,10 - Benefits,K26 +19-20 BEN Bobline - Gov. Cashable,10 - Benefits,E27 +19-20 BEN Bobline - Gov. Non-Cashable,10 - Benefits,F27 +19-20 BEN Bobline - Economic (inc Private Partner),10 - Benefits,G27 +19-20 BEN Bobline - Disbenefit UK Economic,10 - Benefits,H27 +19-20 BEN Bobline - Total Monetised Benefits,10 - Benefits,K27 +19-20 BEN Forecast - Gov. Cashable,10 - Benefits,E28 +19-20 BEN Forecast - Gov. Non-Cashable,10 - Benefits,F28 +19-20 BEN Forecast - Economic (inc Private Partner),10 - Benefits,G28 +19-20 BEN Forecast - Disbenefit UK Economic,10 - Benefits,H28 +19-20 BEN Forecast - Total Monetised Benefits,10 - Benefits,K28 +20-21 BEN Bobline - Gov. Cashable,10 - Benefits,E29 +20-21 BEN Bobline - Gov. Non-Cashable,10 - Benefits,F29 +20-21 BEN Bobline - Economic (inc Private Partner),10 - Benefits,G29 +20-21 BEN Bobline - Disbenefit UK Economic,10 - Benefits,H29 +20-21 BEN Bobline - Total Monetised Benefits,10 - Benefits,K29 +20-21 BEN Forecast - Gov. Cashable,10 - Benefits,E30 +20-21 BEN Forecast - Gov. Non-Cashable,10 - Benefits,F30 +20-21 BEN Forecast - Economic (inc Private Partner),10 - Benefits,G30 +20-21 BEN Forecast - Disbenefit UK Economic,10 - Benefits,H30 +20-21 BEN Forecast - Total Monetised Benefits,10 - Benefits,K30 +21-22 BEN Bobline - Gov. Cashable,10 - Benefits,E31 +21-22 BEN Bobline - Gov. Non-Cashable,10 - Benefits,F31 +21-22 BEN Bobline - Economic (inc Private Partner),10 - Benefits,G31 +21-22 BEN Bobline - Disbenefit UK Economic,10 - Benefits,H31 +21-22 BEN Bobline - Total Monetised Benefits,10 - Benefits,K31 +21-22 BEN Forecast - Gov. Cashable,10 - Benefits,E32 +21-22 BEN Forecast - Gov. Non-Cashable,10 - Benefits,F32 +21-22 BEN Forecast - Economic (inc Private Partner),10 - Benefits,G32 +21-22 BEN Forecast - Disbenefit UK Economic,10 - Benefits,H32 +21-22 BEN Forecast - Total Monetised Benefits,10 - Benefits,K32 +22-23 BEN Bobline - Gov. Cashable,10 - Benefits,E33 +22-23 BEN Bobline - Gov. Non-Cashable,10 - Benefits,F33 +22-23 BEN Bobline - Economic (inc Private Partner),10 - Benefits,G33 +22-23 BEN Bobline - Disbenefit UK Economic,10 - Benefits,H33 +22-23 BEN Bobline - Total Monetised Benefits,10 - Benefits,K33 +22-23 BEN Forecast - Gov. Cashable,10 - Benefits,E34 +22-23 BEN Forecast - Gov. Non-Cashable,10 - Benefits,F34 +22-23 BEN Forecast - Economic (inc Private Partner),10 - Benefits,G34 +22-23 BEN Forecast - Disbenefit UK Economic,10 - Benefits,H34 +22-23 BEN Forecast - Total Monetised Benefits,10 - Benefits,K34 +23-24 BEN Bobline - Gov. Cashable,10 - Benefits,E35 +23-24 BEN Bobline - Gov. Non-Cashable,10 - Benefits,F35 +23-24 BEN Bobline - Economic (inc Private Partner),10 - Benefits,G35 +23-24 BEN Bobline - Disbenefit UK Economic,10 - Benefits,H35 +23-24 BEN Bobline - Total Monetised Benefits,10 - Benefits,K35 +23-24 BEN Forecast - Gov. Cashable,10 - Benefits,E36 +23-24 BEN Forecast - Gov. Non-Cashable,10 - Benefits,F36 +23-24 BEN Forecast - Economic (inc Private Partner),10 - Benefits,G36 +23-24 BEN Forecast - Disbenefit UK Economic,10 - Benefits,H36 +23-24 BEN Forecast - Total Monetised Benefits,10 - Benefits,K36 +24-25 BEN Bobline - Gov. Cashable,10 - Benefits,E37 +24-25 BEN Bobline - Gov. Non-Cashable,10 - Benefits,F37 +24-25 BEN Bobline - Economic (inc Private Partner),10 - Benefits,G37 +24-25 BEN Bobline - Disbenefit UK Economic,10 - Benefits,H37 +24-25 BEN Bobline - Total Monetised Benefits,10 - Benefits,K37 +24-25 BEN Forecast - Gov. Cashable,10 - Benefits,E38 +24-25 BEN Forecast - Gov. Non-Cashable,10 - Benefits,F38 +24-25 BEN Forecast - Economic (inc Private Partner),10 - Benefits,G38 +24-25 BEN Forecast - Disbenefit UK Economic,10 - Benefits,H38 +24-25 BEN Forecast - Total Monetised Benefits,10 - Benefits,K38 +25-26 BEN Bobline - Gov. Cashable,10 - Benefits,E39 +25-26 BEN Bobline - Gov. Non-Cashable,10 - Benefits,F39 +25-26 BEN Bobline - Economic (inc Private Partner),10 - Benefits,G39 +25-26 BEN Bobline - Disbenefit UK Economic,10 - Benefits,H39 +25-26 BEN Bobline - Total Monetised Benefits,10 - Benefits,K39 +25-26 BEN Forecast - Gov. Cashable,10 - Benefits,E40 +25-26 BEN Forecast - Gov. Non-Cashable,10 - Benefits,F40 +25-26 BEN Forecast - Economic (inc Private Partner),10 - Benefits,G40 +25-26 BEN Forecast - Disbenefit UK Economic,10 - Benefits,H40 +25-26 BEN Forecast - Total Monetised Benefits,10 - Benefits,K40 +26-27 BEN Bobline - Gov. Cashable,10 - Benefits,E41 +26-27 BEN Bobline - Gov. Non-Cashable,10 - Benefits,F41 +26-27 BEN Bobline - Economic (inc Private Partner),10 - Benefits,G41 +26-27 BEN Bobline - Disbenefit UK Economic,10 - Benefits,H41 +26-27 BEN Bobline - Total Monetised Benefits,10 - Benefits,K41 +26-27 BEN Forecast - Gov. Cashable,10 - Benefits,E42 +26-27 BEN Forecast - Gov. Non-Cashable,10 - Benefits,F42 +26-27 BEN Forecast - Economic (inc Private Partner),10 - Benefits,G42 +26-27 BEN Forecast - Disbenefit UK Economic,10 - Benefits,H42 +26-27 BEN Forecast - Total Monetised Benefits,10 - Benefits,K42 +27-28 BEN Bobline - Gov. Cashable,10 - Benefits,E43 +27-28 BEN Bobline - Gov. Non-Cashable,10 - Benefits,F43 +27-28 BEN Bobline - Economic (inc Private Partner),10 - Benefits,G43 +27-28 BEN Bobline - Disbenefit UK Economic,10 - Benefits,H43 +27-28 BEN Bobline - Total Monetised Benefits,10 - Benefits,K43 +27-28 BEN Forecast - Gov. Cashable,10 - Benefits,E44 +27-28 BEN Forecast - Gov. Non-Cashable,10 - Benefits,F44 +27-28 BEN Forecast - Economic (inc Private Partner),10 - Benefits,G44 +27-28 BEN Forecast - Disbenefit UK Economic,10 - Benefits,H44 +27-28 BEN Forecast - Total Monetised Benefits,10 - Benefits,K44 +28-29 BEN Bobline - Gov. Cashable,10 - Benefits,E45 +28-29 BEN Bobline - Gov. Non-Cashable,10 - Benefits,F45 +28-29 BEN Bobline - Economic (inc Private Partner),10 - Benefits,G45 +28-29 BEN Bobline - Disbenefit UK Economic,10 - Benefits,H45 +28-29 BEN Bobline - Total Monetised Benefits,10 - Benefits,K45 +28-29 BEN Forecast - Gov. Cashable,10 - Benefits,E46 +28-29 BEN Forecast - Gov. Non-Cashable,10 - Benefits,F46 +28-29 BEN Forecast - Economic (inc Private Partner),10 - Benefits,G46 +28-29 BEN Forecast - Disbenefit UK Economic,10 - Benefits,H46 +28-29 BEN Forecast - Total Monetised Benefits,10 - Benefits,K46 +Unprofiled Remainder BEN Bobline - Gov. Cashable,10 - Benefits,E47 +Unprofiled Remainder BEN Bobline - Gov. Non-Cashable,10 - Benefits,F47 +Unprofiled Remainder BEN Bobline - Economic (inc Private Partner),10 - Benefits,G47 +Unprofiled Remainder BEN Bobline - Disbenefit UK Economic,10 - Benefits,H47 +Unprofiled Remainder BEN Bobline - Total Monetised Benefits,10 - Benefits,K47 +Unprofiled Remainder BEN Forecast - Gov. Cashable,10 - Benefits,E48 +Unprofiled Remainder BEN Forecast - Gov. Non-Cashable,10 - Benefits,F48 +Unprofiled Remainder BEN Forecast - Economic (inc Private Partner),10 - Benefits,G48 +Unprofiled Remainder BEN Forecast - Disbenefit UK Economic,10 - Benefits,H48 +Unprofiled Remainder BEN Forecast - Total Monetised Benefits,10 - Benefits,K48 +Total BEN Bobline - Gov. Cashable,10 - Benefits,E49 +Total BEN Bobline - Gov. Non-Cashable,10 - Benefits,F49 +Total BEN Bobline - Economic (inc Private Partner),10 - Benefits,G49 +Total BEN Bobline - Disbenefit UK Economic,10 - Benefits,H49 +Total BEN Bobline - Total Monetised Benefits,10 - Benefits,K49 +Total BEN Forecast - Gov. Cashable,10 - Benefits,E50 +Total BEN Forecast - Gov. Non-Cashable,10 - Benefits,F50 +Total BEN Forecast - Economic (inc Private Partner),10 - Benefits,G50 +Total BEN Forecast - Disbenefit UK Economic,10 - Benefits,H50 +Total BEN Forecast - Total Monetised Benefits,10 - Benefits,K50 +Year BEN spend stops,10 - Benefits,E51 +No Deductions - Net Benefits Provided,10 - Benefits,K54 +Deduct TDEL One Off New Costs?,10 - Benefits,K55 +Deduct CDEL one off New Costs?,10 - Benefits,K56 +Deduct TDEL Recurring New Costs?,10 - Benefits,K57 +Deduct CDEL Recurring New Costs?,10 - Benefits,K58 +Deduct TDEL Recurring Old Costs?,10 - Benefits,K59 +Deduct CDEL Recurring Old Costs?,10 - Benefits,K60 +No Monetised Benefits / Initial Business Case Being Prepared,10 - Benefits,K61 +SRO Benefits RAG,10 - Benefits,E64 diff --git a/datamaps/testdata/datamap_for_master_test.csv b/datamaps/testdata/datamap_for_master_test.csv new file mode 100644 index 0000000..cb6178a --- /dev/null +++ b/datamaps/testdata/datamap_for_master_test.csv @@ -0,0 +1,19 @@ +cell_key,template_sheet,cellreference +A Date,Summary,B2 +A String,Summary,B3 +A String2,Summary,C3 +A String3,Summary,D3 +A Float,Summary,B4 +An Integer,Summary,B5 +A Date 1,Another Sheet,B3 +A String 1,Another Sheet,B4 +A Float 1,Another Sheet,B5 +An Integer 1,Another Sheet,B6 +A Date 2,Another Sheet,D3 +A String 2,Another Sheet,D4 +A Float 3,Another Sheet,D5 +An Integer 3,Another Sheet,D6 +A Ten Integer,Introduction,A1 +A Test String,Introduction,C9 +A Vunt String,Introduction,C22 +A Parrot String,Introduction,J9 diff --git a/datamaps/testdata/datamap_matches_test_template.csv b/datamaps/testdata/datamap_matches_test_template.csv new file mode 100644 index 0000000..9ff8c8c --- /dev/null +++ b/datamaps/testdata/datamap_matches_test_template.csv @@ -0,0 +1,10 @@ +cell_key,template_sheet,cellreference +A Ten,Introduction,A1 +A Test,Introduction,C9 +A Vunt,Introduction,C22 +Floaty,Another Sheet,D5 +A Parrot,Introduction,J9 +A String,Summary,B3 +A Float,Summary,B4 +A Number,Another Sheet,N34 +A Rabbit,Another Sheet,DI15 diff --git a/datamaps/testdata/test_template.xlsm b/datamaps/testdata/test_template.xlsm Binary files differnew file mode 100644 index 0000000..7681c04 --- /dev/null +++ b/datamaps/testdata/test_template.xlsm diff --git a/datamaps/testdata/test_template.xlsx b/datamaps/testdata/test_template.xlsx Binary files differnew file mode 100644 index 0000000..4b46dbb --- /dev/null +++ b/datamaps/testdata/test_template.xlsx diff --git a/datamaps/testdata/test_template2.xlsx b/datamaps/testdata/test_template2.xlsx Binary files differnew file mode 100644 index 0000000..23513bd --- /dev/null +++ b/datamaps/testdata/test_template2.xlsx diff --git a/datamaps/testdata/test_template3.xlsx b/datamaps/testdata/test_template3.xlsx Binary files differnew file mode 100644 index 0000000..8de40da --- /dev/null +++ b/datamaps/testdata/test_template3.xlsx diff --git a/datamaps/writer.go b/datamaps/writer.go new file mode 100644 index 0000000..9e7973f --- /dev/null +++ b/datamaps/writer.go @@ -0,0 +1,153 @@ +package datamaps + +import ( + "database/sql" + "fmt" + "log" + "path/filepath" + + "github.com/tealeg/xlsx/v3" + + // Needed for the sqlite3 driver + _ "github.com/mattn/go-sqlite3" +) + +// CreateMaster creates a master spreadsheet for a specific return given, +// based on a datamap name - both of which already need to be in the database, +// along with the data associated with the return. The datamap and return data +// must already have been imported. +func CreateMaster(opts *Options) error { + wb := xlsx.NewFile() + sh, err := wb.AddSheet("Master Data") + if err != nil { + return fmt.Errorf("cannot add 'Master Data' sheet to new XLSX file: %v", err) + } + + db, err := sql.Open("sqlite3", opts.DBPath) + if err != nil { + return fmt.Errorf("cannot open database %v", err) + } + + // Get number amount of datamap keys in target datamap + keyCountRows := db.QueryRow("SELECT count(key) FROM datamap_line, datamap WHERE datamap.name=?;", opts.DMName) + + var datamapKeysNumber int64 + if err := keyCountRows.Scan(&datamapKeysNumber); err != nil { + return err + } + + datamapKeysRows, err := db.Query("SELECT key FROM datamap_line, datamap WHERE datamap.name=?;", opts.DMName) + if err != nil { + return fmt.Errorf("cannot query for keys in database - %v", err) + } + + var datamapKeys []string + + var i int64 + for i = 0; i < datamapKeysNumber; i++ { + if k := datamapKeysRows.Next(); k { + var key string + if err := datamapKeysRows.Scan(&key); err != nil { + return fmt.Errorf("cannot Scan for key %s - %v", key, err) + } + datamapKeys = append(datamapKeys, key) + } + } + + sqlCount := `SELECT count(return_data.id) + FROM (((return_data + INNER JOIN datamap_line ON return_data.dml_id=datamap_line.id) + INNER JOIN datamap ON datamap_line.dm_id=datamap.id) + INNER JOIN return on return_data.ret_id=return.id) + WHERE datamap.name=? AND return.name=?;` + + var rowCount int64 + rowCountRes := db.QueryRow(sqlCount, opts.DMName, opts.ReturnName) + + if err := rowCountRes.Scan(&rowCount); err != nil { + return err + } + + getDataSQL := `SELECT datamap_line.key, return_data.vFormatted, return_data.filename + FROM (((return_data + INNER JOIN datamap_line ON return_data.dml_id=datamap_line.id) + INNER JOIN datamap ON datamap_line.dm_id=datamap.id) + INNER JOIN return on return_data.ret_id=return.id) + WHERE datamap.name=? AND return.name=? AND datamap_line.key=? + ORDER BY return_data.filename;` + + seen := make(map[string]struct{}) // homemade Set https://emersion.fr/blog/2017/sets-in-go/ + + var values = make(map[string][]string) + headerSlice := make([]string, 0) + for _, k := range datamapKeys { + masterData, err := db.Query(getDataSQL, opts.DMName, opts.ReturnName, k) + if err != nil { + return err + } + for masterData.Next() { + var key, filename, fmttedValue string + if err := masterData.Scan(&key, &fmttedValue, &filename); err != nil { + fmt.Errorf("Problem scanning data from database for master: %v", err) + } + values, err = appendValueMap(key, fmttedValue, values) + if _, ok := seen[filename]; !ok { + headerSlice = append(headerSlice, filename) + seen[filename] = struct{}{} + } + if err != nil { + return err + } + } + } + + for masterRow := 0; masterRow <= len(datamapKeys); masterRow++ { + r, err := sh.AddRowAtIndex(masterRow) + if err != nil { + return fmt.Errorf("cannot create row %d in output spreadsheet: %v", masterRow, err) + } + if masterRow == 0 { + if hdr := r.WriteSlice(append([]string{""}, headerSlice...), -1); hdr == -1 { + return fmt.Errorf("cannot write header values into header row: %v", err) + } + continue + } + dmlKey := datamapKeys[masterRow-1] + + // TODO - we need to format the cells here too, e.g. dates + if sl := r.WriteSlice(append([]string{dmlKey}, values[dmlKey]...), -1); sl == -1 { + log.Printf("not a slice type") + } + } + + log.Printf("saving master at %s", opts.MasterOutPutPath) + if err := wb.Save(filepath.Join(opts.MasterOutPutPath, "master.xlsx")); err != nil { + log.Fatalf("cannot save file to %s", opts.MasterOutPutPath) + } + sh.Close() + return nil +} + +func appendValueMap(k, v string, values map[string][]string) (map[string][]string, error) { + + var keyIn bool + for kv := range values { + if kv == k { + keyIn = true + break + } + } + + if keyIn { + slice, ok := values[k] + if !ok { + return nil, fmt.Errorf("%s is not a key in this map", k) + } + slice = append(slice, v) + values[k] = slice + return values, nil + } else { + values[k] = []string{v} + return values, nil + } +} diff --git a/datamaps/writer_test.go b/datamaps/writer_test.go new file mode 100644 index 0000000..c6cf547 --- /dev/null +++ b/datamaps/writer_test.go @@ -0,0 +1,195 @@ +package datamaps + +import ( + "fmt" + "os" + "os/exec" + "path/filepath" + "strings" + "testing" + + "github.com/tealeg/xlsx/v3" +) + +var ( + // filesInMaster is a map of each filename from the header row of a master, mapped to its + // column number + filesInMaster = make(map[string]int) +) + +func testSetup() (*Options, error) { + // setup - we need the datamap in the test database + _, err := setupDB("./testdata/test.db") + + if err != nil { + fmt.Errorf("expected to be able to set up the database") + } + + opts := Options{ + DBPath: "./testdata/test.db", + DMName: "First Datamap", + DMPath: "./testdata/datamap_for_master_test.csv", + ReturnName: "Unnamed Return", + MasterOutPutPath: "./testdata/", + XLSXPath: "./testdata/", + } + + if err := DatamapToDB(&opts); err != nil { + fmt.Errorf("unable to write datamap to database file because %v", err) + } + + if err := ImportToDB(&opts); err != nil { + fmt.Errorf("cannot read test XLSX files needed before exporting to master - %v", err) + } + return &opts, nil +} + +func TestWriteMaster(t *testing.T) { + + opts, err := testSetup() + if err != nil { + t.Fatal(err) + } + + defer func() { + os.Remove(filepath.Join(opts.MasterOutPutPath, "master.xlsx")) + }() + + defer func() { + os.Remove("./testdata/test.db") + }() + + if err := CreateMaster(opts); err != nil { + t.Fatal(err) + } + + var tests = []struct { + key string + filename string + sheet string + cellref string + value string + }{ + {"A Date", "test_template.xlsx", "Summary", "B2", "20/10/19"}, + {"A String", "test_template.xlsx", "Summary", "B3", "This is a string"}, + {"A String2", "test_template.xlsx", "Summary", "C3", "This is a string"}, + {"A String3", "test_template.xlsx", "Summary", "D3", "This is a string"}, + {"A Float", "test_template.xlsx", "Summary", "B4", "2.2"}, + {"An Integer", "test_template.xlsx", "Summary", "B5", "10"}, + {"A Date 1", "test_template.xlsx", "Another Sheet", "B3", "20/10/19"}, + {"A String 1", "test_template.xlsx", "Another Sheet", "B4", "This is a string"}, + {"A Float 1", "test_template.xlsx", "Another Sheet", "B5", "2.2"}, + {"An Integer 1", "test_template.xlsx", "Another Sheet", "B6", "10"}, + {"A Date 2", "test_template.xlsx", "Another Sheet", "D3", "21/10/19"}, + {"A String 2", "test_template.xlsx", "Another Sheet", "D4", "This is a string"}, + {"A Float 3", "test_template.xlsx", "Another Sheet", "D5", "3.2"}, + {"An Integer 3", "test_template.xlsx", "Another Sheet", "D6", "11"}, + {"A Ten Integer", "test_template.xlsx", "Introduction", "A1", "10"}, + {"A Test String", "test_template.xlsx", "Introduction", "C9", "Test Department"}, + {"A Vunt String", "test_template.xlsx", "Introduction", "C22", "VUNT"}, + {"A Parrot String", "test_template.xlsx", "Introduction", "J9", "Greedy Parrots"}, + + {"A Date", "test_template.xlsm", "Summary", "B2", "20/10/19"}, + {"A String", "test_template.xlsm", "Summary", "B3", "This is a string"}, + {"A String2", "test_template.xlsm", "Summary", "C3", "This is a string"}, + {"A String3", "test_template.xlsm", "Summary", "D3", "This is a string"}, + {"A Float", "test_template.xlsm", "Summary", "B4", "2.2"}, + {"An Integer", "test_template.xlsm", "Summary", "B5", "10"}, + {"A Date 1", "test_template.xlsm", "Another Sheet", "B3", "20/10/19"}, + {"A String 1", "test_template.xlsm", "Another Sheet", "B4", "This is a string"}, + {"A Float 1", "test_template.xlsm", "Another Sheet", "B5", "2.2"}, + {"An Integer 1", "test_template.xlsm", "Another Sheet", "B6", "10"}, + {"A Date 2", "test_template.xlsm", "Another Sheet", "D3", "21/10/19"}, + {"A String 2", "test_template.xlsm", "Another Sheet", "D4", "This is a string"}, + {"A Float 3", "test_template.xlsm", "Another Sheet", "D5", "3.2"}, + {"An Integer 3", "test_template.xlsm", "Another Sheet", "D6", "11"}, + {"A Ten Integer", "test_template.xlsm", "Introduction", "A1", "10"}, + {"A Test String", "test_template.xlsm", "Introduction", "C9", "Test Department"}, + {"A Vunt String", "test_template.xlsm", "Introduction", "C22", "VUNT"}, + {"A Parrot String", "test_template.xlsm", "Introduction", "J9", "Greedy Parrots"}, + } + + // Regular testing of import + // TODO fix date formatting + for _, test := range tests { + sql := fmt.Sprintf(`SELECT return_data.vFormatted FROM return_data, datamap_line + WHERE + (return_data.filename=%q + AND datamap_line.cellref=%q + AND datamap_line.sheet=%q + AND return_data.dml_id=datamap_line.id);`, test.filename, test.cellref, test.sheet) + + got, err := exec.Command("sqlite3", opts.DBPath, sql).Output() + if err != nil { + t.Fatalf("something wrong %v", err) + } + gots := strings.TrimSuffix(string(got), "\n") + if strings.Compare(gots, test.value) != 0 { + t.Errorf("when testing the database, for key %s in file %s we expected %s but got %s", test.key, + test.filename, test.value, gots) + } + } + + // Open the master and the target sheet + master, err := xlsx.OpenFile("./testdata/master.xlsx") + if err != nil { + t.Fatal(err) + } + sheetName := "Master Data" + sh, ok := master.Sheet[sheetName] + if !ok { + t.Errorf("Sheet named %s does not exist", sheetName) + } + defer sh.Close() + + err = sh.ForEachRow(rowVisitorTest) + + for _, tt := range tests { + got, err := masterLookup(sh, tt.key, tt.filename) + if err != nil { + t.Fatal("Problem calling masterLookup()") + } + if got != tt.value { + t.Errorf("when testing the master, for key %s we expected value %s in col %s - got %s", + tt.key, tt.value, tt.filename, got) + } + } +} + +func masterLookup(sheet *xlsx.Sheet, key string, filename string) (string, error) { + var out string + if err := sheet.ForEachRow(func(r *xlsx.Row) error { + if r.GetCell(0).Value == key { + out = r.GetCell(filesInMaster[filename]).Value + return nil + } + return nil + }); err != nil { + return "", err + } + return out, nil +} + +func cellVisitorTest(c *xlsx.Cell) error { + seen := make(map[string]struct{}) + if _, ok := seen[c.Value]; !ok { + if c.Value != "" { + x, _ := c.GetCoordinates() + filesInMaster[c.Value] = x + } + seen[c.Value] = struct{}{} + } + + return nil +} + +func rowVisitorTest(r *xlsx.Row) error { + // TODO here we want to first find the file names from the header row, + // then test that all key (from col 0) matches the value. + + if r.GetCoordinate() == 0 { + r.ForEachCell(cellVisitorTest) + return nil + } + return nil +} |