# Install Measurement Tracking # Copyright 2004, 2007 by Brian C. Christensen # This file is part of GanttPV. # # GanttPV is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # GanttPV is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with GanttPV; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # 040724 - first draft of program based on Add Document Tracking # 040725 - revisions to data design # 040820 - updated several times since last date logged here (when I stop finding changes # that need to be made to the design, I'll start implementing it) # 040902 - changed table name to MeasurementDependency # 040905 - added daily and weekly flags to ProjectMeasurement # 040907 - added effort adjustment to project; convert "Also" name to ID; moved measurement data storage # to ProjectWeek and ProjectDay # 040914 - changed EffortAdjustment to float # 041009 - fixed some data types # 041011 - included TaskWeek in table adds; fixed logic to change existing column types; added AddRow # 041012 - moved AddTable, AddRow, and AddReportType to Data.py # 041121 - added ProjectResource report # 041218 - combined Install Expense Tracking and Install Expense Measurement # into Install Earned Value Tracking and renamed as Install Measurement Tracking # 050606 - Brian - remove "(Hours)" from effort label # 051022 - Alex - compensate for a bug in AddRow (GanttPV 0.5) # 070411 - Brian - added default report layouts # These design notes are intended to explore the problem. They include more than will be # implemented in the initial version. # To calculate earned value; # Project # - EffortAdjustment (multiply all task estimates by this amount while doing earned value calculations. # for example, if pm thinks that only half of effort for project has been identified # either double individual task estimates or enter 2 here. defaults to 1.) # - ActualEndDate # Task # - EffortHours # - Cost (dollars?? - depends on currency used) (not required) # - CostCurrency (defaults to ??) (use only if multiple currencies) # - PercentComplete (recommended to use ActualEndDate, but could use PercentComplete instead) # - ActualStartDate (not used for earned value) # - ActualStartHour (not used for earned value) # - ActualEndDate # - ActualEndHour (defaults to 0) # - BaseStartDate (not used for earned value) # - BaseStartHour (not used for earned value) # - BaseEndDate # - BaseEndHour (defaults to 0) # TaskWeek # - ID # - TaskID # - Period # - CalculatedEffort (Plan Hours) (sum of Resource/Task/Week hours) # - PercentComplete (not recommended, but okay if EV based on partial completions) # TaskDay # - ID # - TaskID # - Period # - CalculatedEffort (Plan Hours) (sum of Resource/Task/Day hours) # - PercentComplete (not recommended, but okay if EV based on partial completions) # ProjectResource # - ID # - ProjectID # - ResourceID # - TaskDerived (True if this record was created because of Task/Resource assignments) # ProjectResourceWeek # - ID # - ProjectResourceID # - Period (Beginning of Week Date - Monday) # - ActualEffortHours # - ActualCost (not required) # - Currency (defaults to ??) (use only if multiple currencies) # ProjectResourceDay # - ID # - ProjectResourceID # - Period (Day) # - ActualEffortHours # - ActualCost (not required) # - Currency (defaults to ??) (use only if multiple currencies) # To display earned value: # Measurement (also PriorMeasurement) # - ID # - Name (don't change this, also serves as the data column name -- assigned by Pure Violet; use xxNames when adding your own) # - Label (Okay to change this -- especially for translations) # - Description ## - TableName (default "Project" -- may allow measurement idea to apply to other things) ## - ColumnName (name of column in Project/Week or Project/Day that stores this measurement -- use # xxNames when adding your own) (Can't be Table, ID, ProjectID, Week, or Day) # - DataType (controls how measurement "Value" can be manually entered) # - Script (that can be run to collect data for measurement, default is manual entry of data) # MeasurementDependency # - ID # - PriorMeasurementID ("PriorMeasurement" = synonym for Measurement -- constrains sequence of # measurement calculations) # - MeasurementID # ProjectMeasurement (which measurements will be used for each project) # Project measurements turn Columns into rows. # - ID # - ProjectID # - MeasurementID # - Daily (include in daily calculation, default is False) # - LastDaily (Date of last daily update, default is day prior to project begin) # - Weekly (include in weekly calculation, default is False) # - LastWeekly (Date of last weekly update, default is week prior to project begin) # ---- start omit ---- # - Name (?defaults to measurement label?) # (It is okay to use the same measurement more than once in a project. This name # allows the user to distinguish among them. Because the same measuremnt can appear # more than once, it may # be necessary to provide additional data so the measurement script will know how # to compute this particular occurrence. The columns needed may vary for each # measurement.) # ---- end omit ---- # ProjectWeek (cantains the measurement data for each week) # - ID # - ProjectID # - Period # - (Values) (default: "data is not yet available") # (I added the day measurement because I find that I am tracking measurements for this project on a daily basis.) # ProjectDay (cantains the measurement data for each day) # - ID # - ProjectID # - Period # - (Values) (default: "data is not yet available") # This script must be run against each file to include the new report options. # If you want to make sure the report types and column types you add don't conflict # with new releases of GanttPV, prefix the Name with "xx". For # example: "xxDocument", "xxOwner", "xxURL", etc. def DoAdd(): # global AddReportType, AddTable, AddRow # Specified all required Report Types and Column Types # It will either add them or update them if they already exist. rt = { 'Name': 'Project', 'TableA': 'Project', 'TableB': None, 'Also': None, 'AllOrEach': 'all' } ct = [ # { 'Name': 'EffortAdjustment', 'Label': 'Effort\nAdjustment', 'DataType': 'i', 'AccessType': 'd', 'T': 'A', 'Edit': True, 'Width': 80 }, { 'Name': 'ActualEndDate', 'Label': 'Actual\nEnd Date', 'DataType': 'd', 'AccessType': 'd', 'T': 'A', 'Edit': True, 'Width': 80 }, ] Data.AddReportType(rt, ct) rt = { 'Name': 'Task', 'TableA': 'Task', 'TableB': None, 'Also': None, 'AllOrEach': 'both' } ct = [ # { 'Name': 'EndDate', 'Label': 'End Date', 'DataType': 'd', 'AccessType': 'd', 'T': 'A', 'Edit': True, 'Width': 80 }, { 'Name': 'EffortHours', 'Label': 'Effort', 'DataType': 'i', 'AccessType': 'd', 'T': 'A', 'Edit': True, 'Width': 80 }, { 'Name': 'Cost', 'Label': None, 'DataType': 'i', 'AccessType': 'd', 'T': 'A', 'Edit': True, 'Width': 80 }, { 'Name': 'PercentComplete', 'Label': 'Percent\nComplete', 'DataType': 'i', 'AccessType': 'd', 'T': 'A', 'Edit': True, 'Width': 80 }, { 'Name': 'ActualEndDate', 'Label': 'Actual\nEnd Date', 'DataType': 'd', 'AccessType': 'd', 'T': 'A', 'Edit': True, 'Width': 80 }, # { 'Name': 'ActualEndHour', 'Label': 'Actual\nEnd Hour', 'DataType': 'i', 'AccessType': 'd', 'T': 'A', 'Edit': True, 'Width': 80 }, { 'Name': 'BaseEndDate', 'Label': 'Base\nEnd Date', 'DataType': 'd', 'AccessType': 'd', 'T': 'A', 'Edit': True, 'Width': 80 }, # { 'Name': 'BaseEndHour', 'Label': 'Base\nEnd Hour', 'DataType': 'i', 'AccessType': 'd', 'T': 'A', 'Edit': True, 'Width': 80 }, { 'Name': 'Week/Effort', 'Label': None, 'DataType': 'i', 'AccessType': 's', 'T': 'X', 'Edit': True, 'Width': 40 }, # { 'Name': 'Week/PercentComplete','Label': None, 'DataType': 'i', 'AccessType': 's', 'T': 'X', 'Edit': True, 'Width': 40 }, ] Data.AddReportType(rt, ct) rt = { 'Name': 'Measurement', 'TableA': 'Measurement', 'TableB': None, 'Also': None, 'AllOrEach': 'all' } ct = [ { 'Name': 'ID', 'Label': None, 'DataType': 'i', 'AccessType': 'd', 'T': 'A', 'Edit': False, 'Width': 40 }, { 'Name': 'Name', 'Label': None, 'DataType': 't', 'AccessType': 'd', 'T': 'A', 'Edit': False, 'Width': 140 }, { 'Name': 'Label', 'Label': None, 'DataType': 't', 'AccessType': 'd', 'T': 'A', 'Edit': True, 'Width': 160 }, # { 'Name': 'TableName', 'Label': 'Table\nName', 'DataType': 't', 'AccessType': 'd', 'T': 'A', 'Edit': True, 'Width': 140 }, # { 'Name': 'ColumnName', 'Label': 'Column\nName', 'DataType': 't', 'AccessType': 'd', 'T': 'A', 'Edit': True, 'Width': 140 }, { 'Name': 'Script', 'Label': None, 'DataType': 't', 'AccessType': 'd', 'T': 'A', 'Edit': False, 'Width': 140 }, { 'Name': 'DataType', 'Label': 'Data\nType', 'DataType': 't', 'AccessType': 'd', 'T': 'A', 'Edit': False, 'Width': 60 }, ] Data.AddReportType(rt, ct) rt = { 'Name': 'Measurement/MeasurementDependency', 'Label': 'Measurement Dependency', 'TableA': 'Measurement', 'TableB': 'MeasurementDependency', 'Also': 'Measurement', 'AllOrEach': 'all' } ct = [ { 'Name': 'ID', 'Label': None, 'DataType': 'i', 'AccessType': 'd', 'T': 'B', 'Edit': False, 'Width': 40 }, { 'Name': 'Measurement/Name', 'Label': 'Measurement\nName', 'DataType': 't', 'AccessType': 'i', 'T': 'B', 'Edit': False, 'Width': 160 }, { 'Name': 'Measurement/Label', 'Label': 'Measurement\nLabel', 'DataType': 't', 'AccessType': 'i', 'T': 'B', 'Edit': True, 'Width': 160 }, { 'Name': 'PriorMeasurement/Name', 'Label': 'Prior Measurement\nName', 'DataType': 't', 'AccessType': 'i', 'T': 'B', 'Edit': False, 'Width': 160 }, { 'Name': 'PriorMeasurement/Label', 'Label': 'Prior Measurement\nLabel', 'DataType': 't', 'AccessType': 'i', 'T': 'B', 'Edit': True, 'Width': 160 }, ] Data.AddReportType(rt, ct) rt = { 'Name': 'ProjectMeasurement', 'Label': 'Project Measurement', 'TableA': 'ProjectMeasurement', 'TableB': None, 'Also': None, 'AllOrEach': 'each', 'SuggestedColumns': ',MeasurementID,,;,Measurement/Label,,;,Week/Measurement,,10' } ct = [ { 'Name': 'ID', 'Label': None, 'DataType': 'i', 'AccessType': 'd', 'T': 'A', 'Edit': False, 'Width': 40 }, # { 'Name': 'Name', 'Label': None, 'DataType': 't', 'AccessType': 'd', 'T': 'A', 'Edit': True, 'Width': 140 }, { 'Name': 'ProjectID', 'Label': 'Project\nID', 'DataType': 'i', 'AccessType': 'd', 'T': 'A', 'Edit': False, 'Width': 80 }, { 'Name': 'MeasurementID', 'Label': 'Measurement\nID', 'DataType': 'i', 'AccessType': 'd', 'T': 'A', 'Edit': True, 'Width': 100 }, { 'Name': 'Measurement/Name', 'Label': None, 'DataType': 't', 'AccessType': 'i', 'T': 'A', 'Edit': False, 'Width': 140 }, { 'Name': 'Measurement/Label','Label': None, 'DataType': 't', 'AccessType': 'i', 'T': 'A', 'Edit': True, 'Width': 140 }, # { 'Name': 'Daily', 'Label': None, 'DataType': 'tf', 'AccessType': 'd', 'T': 'A', 'Edit': True, 'Width': 60 }, # { 'Name': 'LastDaily', 'Label': 'Last Daily', 'DataType': 'd', 'AccessType': 'd', 'T': 'A', 'Edit': True, 'Width': 80 }, # { 'Name': 'Weekly', 'Label': None, 'DataType': 'tf', 'AccessType': 'd', 'T': 'A', 'Edit': True, 'Width': 60 }, { 'Name': 'LastUpdate', 'Label': 'Last Update', 'DataType': 'd', 'AccessType': 'd', 'T': 'A', 'Edit': True, 'Width': 80 }, { 'Name': 'Week/Measurement', 'Label': None, 'DataType': 't', 'AccessType': 's', 'T': 'A', 'Edit': True, 'Width': 60 }, # { 'Name': 'Day/Measurement', 'Label': None, 'DataType': 't', 'AccessType': 's', 'T': 'A', 'Edit': True, 'Width': 60 }, ] Data.AddReportType(rt, ct) rt = { 'Name': 'ProjectResource', 'Label': 'Project Resource', 'TableA': 'ProjectResource', 'TableB': None, 'Also': None, 'AllOrEach': 'both', 'SuggestedColumns': ',ResourceID;,Resource/Name,,;,Week/ActualEffortHours,,10' } ct = [ { 'Name': 'ID', 'Label': None, 'DataType': 'i', 'AccessType': 'd', 'T': 'A', 'Edit': False, 'Width': 40 }, { 'Name': 'ProjectID', 'Label': 'Project\nID', 'DataType': 'i', 'AccessType': 'd', 'T': 'A', 'Edit': False, 'Width': 80 }, { 'Name': 'Project/Name', 'Label': None, 'DataType': 't', 'AccessType': 'i', 'T': 'A', 'Edit': False, 'Width': 140 }, { 'Name': 'ResourceID', 'Label': 'Resource\nID', 'DataType': 'i', 'AccessType': 'd', 'T': 'A', 'Edit': True, 'Width': 80 }, { 'Name': 'Resource/Name', 'Label': None, 'DataType': 't', 'AccessType': 'i', 'T': 'A', 'Edit': False, 'Width': 140 }, { 'Name': 'HourlyRate', 'Label': 'Hourly Rate', 'DataType': 'f', 'AccessType': 'd', 'T': 'A', 'Edit': True, 'Width': 80 }, { 'Name': 'Week/ActualEffortHours', 'Label': None, 'DataType': 'i', 'AccessType': 's', 'T': 'A', 'Edit': True, 'Width': 80 }, { 'Name': 'Day/ActualEffortHours', 'Label': None, 'DataType': 'i', 'AccessType': 's', 'T': 'A', 'Edit': True, 'Width': 80 }, ] Data.AddReportType(rt, ct) rt = { 'Name': 'Expense', 'TableA': 'Expense', 'TableB': None, 'Also': None, 'AllOrEach': 'each', 'SuggestedColumns': ',Category;,Description;,PlannedDate;,PlannedAmount;,ActualDate;,ActualAmount;,Note;,Reference' } ct = [ { 'Name': 'Category', 'Label': None, 'DataType': 't', 'AccessType': 'd', 'T': 'A', 'Edit': True, 'Width': 60 }, { 'Name': 'Description', 'Label': None, 'DataType': 't', 'AccessType': 'd', 'T': 'A', 'Edit': True, 'Width': 180 }, { 'Name': 'PlannedDate', 'Label': 'Planned\nDate', 'DataType': 'd', 'AccessType': 'd', 'T': 'A', 'Edit': True, 'Width': 80 }, { 'Name': 'PlannedAmount', 'Label': 'Planned\nAmount', 'DataType': 'f', 'AccessType': 'd', 'T': 'A', 'Edit': True, 'Width': 80 }, { 'Name': 'ActualDate', 'Label': 'Actual\nDate', 'DataType': 'd', 'AccessType': 'd', 'T': 'A', 'Edit': True, 'Width': 80 }, { 'Name': 'ActualAmount', 'Label': 'Actual\nAmount', 'DataType': 'f', 'AccessType': 'd', 'T': 'A', 'Edit': True, 'Width': 80 }, { 'Name': 'Note', 'Label': None, 'DataType': 't', 'AccessType': 'd', 'T': 'A', 'Edit': True, 'Width': 140 }, { 'Name': 'Reference', 'Label': None, 'DataType': 't', 'AccessType': 'd', 'T': 'A', 'Edit': True, 'Width': 140 }, ] Data.AddReportType(rt, ct) # add required data tables Data.AddTable('ProjectWeek') Data.AddTable('ProjectDay') # Data.AddTable('ProjectResource') Data.AddTable('ProjectResourceWeek') Data.AddTable('ProjectResourceDay') if not Data.Database.has_key('PriorMeasurement'): Data.Database['PriorMeasurement'] = Data.Database['Measurement'] Data.AddTable('TaskWeek') # should change this to update if record already exists # change = { 'Table': "Measurement", 'Name': 'ActualCost', 'Label': 'Actual Cost', # 'Script': 'Earned Value Hours.py', 'DataType': 'i' } # Data.AddRow(change) change = { 'Table': "Measurement", 'Name': 'ActualEffortHours', 'Label': 'Actual Effort Hours', 'Script': 'Earned Value Hours.py', 'DataType': 'i' } Data.AddRow(change) if not Data.Database['Measurement']: Data.Update(change) change = { 'Table': "Measurement", 'Name': 'ActualEffortHoursToDate', 'Label': 'Actual Effort Hours To Date', 'Script': 'Earned Value Hours.py', 'DataType': 'i' } Data.AddRow(change) change = { 'Table': "Measurement", 'Name': 'EarnedValueHours', 'Label': 'Earned Value Hours', 'Script': 'Earned Value Hours.py', 'DataType': 'i' } Data.AddRow(change) change = { 'Table': "Measurement", 'Name': 'EarnedValueHoursToDate', 'Label': 'Earned Value Hours To Date', 'Script': 'Earned Value Hours.py', 'DataType': 'i' } Data.AddRow(change) # change = { 'Table': "Measurement", 'Name': 'EarnedValueCost', 'Label': 'Earned Value Cost', # 'Script': 'Earned Value Hours.py', 'DataType': 'i' } # Data.AddRow(change) change = { 'Table': "Measurement", 'Name': 'PlannedValueHours', 'Label': 'Planned Value Hours', 'Script': 'Earned Value Hours.py', 'DataType': 'i' } Data.AddRow(change) change = { 'Table': "Measurement", 'Name': 'PlannedValueHoursToDate', 'Label': 'Planned Value Hours To Date', 'Script': 'Earned Value Hours.py', 'DataType': 'i' } Data.AddRow(change) # change = { 'Table': "Measurement", 'Name': 'PlannedValueCost', 'Label': 'Planned Value Cost', # 'Script': 'Earned Value Hours.py', 'DataType': 'i' } # Data.AddRow(change) change = { 'Table': "Measurement", 'Name': 'ActualExpense', 'Label': 'Actual Expense', 'Script': 'Expense.py', 'DataType': 'i' } Data.AddRow(change) change = { 'Table': "Measurement", 'Name': 'ActualExpenseToDate', 'Label': 'Actual Expense To Date', 'Script': 'Expense.py', 'DataType': 'i' } Data.AddRow(change) change = { 'Table': "Measurement", 'Name': 'PlannedExpense', 'Label': 'Planned Expense', 'Script': 'Expense.py', 'DataType': 'i' } Data.AddRow(change) change = { 'Table': "Measurement", 'Name': 'PlannedExpenseToDate', 'Label': 'Planned Expense To Date', 'Script': 'Expense.py', 'DataType': 'i' } Data.AddRow(change) change = { 'Table': "Measurement", 'Name': 'OutlookExpense', 'Label': 'Outlook Expense', 'Script': 'Expense.py', 'DataType': 'i' } Data.AddRow(change) change = { 'Table': "Measurement", 'Name': 'OutlookExpenseToDate', 'Label': 'Outlook Expense To Date', 'Script': 'Expense.py', 'DataType': 'i' } Data.AddRow(change) Data.SetUndo("Add Measurement Tracking") # do only if GanttPV version 0.2 or greater DoAdd()