'Update the status fields of the different Project levels
Fired onaccept of:
project_activity_criteria (if status_from_activities)
project_indicator_criteria (if status_from_activities: weightings may have changed)
project_indicator_data
project_indicator (weightings may have changed)
project_output (weightings may have changed)
project_outcome (weightings may have changed)
project_goal (weightings may have changed)
@param project_id: the ID of the project record to update
@ToDo: Handle deployment_settings for which levels are exposed'

@staticmethod
def project_planning_status_update(project_id):

    db = current.db
    s3db = current.s3db
    if current.deployment_settings.get_project_status_from_activities():
        now = current.request.utcnow
        atable = s3db.project_activity
        table = s3db.project_criteria_activity
        ltable = s3db.project_criteria_activity_activity
        query = (((((((table.project_id == project_id) & (table.deleted == False)) & (table.id == ltable.criteria_activity_id)) & (atable.id == ltable.activity_id)) & (atable.end_date < now)) & (table.actual_progress != None)) & (table.planned_progress != None))
        activity_data = db(query).select(table.criteria_id, table.actual_progress, table.planned_progress, table.weighting, atable.end_date)
        if activity_data:
            year_start = datetime.datetime(now.year, 1, 1)
            project = None
            goals = {}
            outcomes = {}
            outputs = {}
            indicators = {}
            criteria = {}
            for a in activity_data:
                end_date = a['project_activity.end_date']
                end_date = datetime.datetime(end_date.year, end_date.month, end_date.day)
                a = a['project_criteria_activity']
                criteria_id = a.criteria_id
                weighting = a.weighting
                actual_progress = (a.actual_progress * weighting)
                planned_progress = (a.planned_progress * weighting)
                if (end_date > year_start):
                    years_actual_progress = actual_progress
                    years_planned_progress = planned_progress
                else:
                    years_actual_progress = 0
                    years_planned_progress = 0
                if (criteria_id not in criteria):
                    criteria[criteria_id] = {'actual_progress': actual_progress, 'planned_progress': planned_progress, 'years_actual_progress': years_actual_progress, 'years_planned_progress': years_planned_progress}
                else:
                    c = criteria[criteria_id]
                    c['actual_progress'] += actual_progress
                    c['planned_progress'] += planned_progress
                    c['years_actual_progress'] += years_actual_progress
                    c['years_planned_progress'] += years_planned_progress
            table = s3db.project_indicator_criteria
            query = ((table.project_id == project_id) & (table.deleted == False))
            rows = db(query).select(table.id, table.indicator_id, table.weighting)
            for r in rows:
                criteria_id = r.id
                if (criteria_id not in criteria):
                    actual_progress = planned_progress = years_actual_progress = years_planned_progress = 0
                else:
                    c = criteria[criteria_id]
                    actual_progress = c['actual_progress']
                    planned_progress = c['planned_progress']
                    years_actual_progress = c['years_actual_progress']
                    years_planned_progress = c['years_planned_progress']
                r.update_record(actual_progress_by_activities=actual_progress, planned_progress_by_activities=planned_progress, years_actual_progress_by_activities=years_actual_progress, years_planned_progress_by_activities=years_planned_progress)
                indicator_id = r.indicator_id
                weighting = r.weighting
                actual_progress = (actual_progress * weighting)
                planned_progress = (planned_progress * weighting)
                years_actual_progress = (years_actual_progress * weighting)
                years_planned_progress = (years_planned_progress * weighting)
                if (indicator_id not in indicators):
                    indicators[indicator_id] = {'actual_progress': actual_progress, 'planned_progress': planned_progress, 'years_actual_progress': years_actual_progress, 'years_planned_progress': years_planned_progress}
                else:
                    i = indicators[indicator_id]
                    i['actual_progress'] += actual_progress
                    i['planned_progress'] += planned_progress
                    i['years_actual_progress'] += years_actual_progress
                    i['years_planned_progress'] += years_planned_progress
            table = s3db.project_indicator
            query = ((table.project_id == project_id) & (table.deleted == False))
            rows = db(query).select(table.id, table.output_id, table.weighting)
            for r in rows:
                indicator_id = r.id
                if (indicator_id not in indicators):
                    actual_progress = planned_progress = years_actual_progress = years_planned_progress = None
                else:
                    i = indicators[indicator_id]
                    actual_progress = i['actual_progress']
                    planned_progress = i['planned_progress']
                    years_actual_progress = i['years_actual_progress']
                    years_planned_progress = i['years_planned_progress']
                r.update_record(actual_progress_by_activities=actual_progress, planned_progress_by_activities=planned_progress, years_actual_progress_by_activities=years_actual_progress, years_planned_progress_by_activities=years_planned_progress)
                if (actual_progress is not None):
                    output_id = r.output_id
                    weighting = r.weighting
                    actual_progress = (actual_progress * weighting)
                    planned_progress = (planned_progress * weighting)
                    years_actual_progress = (years_actual_progress * weighting)
                    years_planned_progress = (years_planned_progress * weighting)
                    if (output_id not in outputs):
                        outputs[output_id] = {'actual_progress': actual_progress, 'planned_progress': planned_progress, 'years_actual_progress': years_actual_progress, 'years_planned_progress': years_planned_progress}
                    else:
                        o = outputs[output_id]
                        o['actual_progress'] += actual_progress
                        o['planned_progress'] += planned_progress
                        o['years_actual_progress'] += years_actual_progress
                        o['years_planned_progress'] += years_planned_progress
            table = s3db.project_output
            query = ((table.project_id == project_id) & (table.deleted == False))
            rows = db(query).select(table.id, table.outcome_id, table.weighting)
            for r in rows:
                output_id = r.id
                if (output_id not in outputs):
                    actual_progress = planned_progress = years_actual_progress = years_planned_progress = None
                else:
                    o = outputs[output_id]
                    actual_progress = o['actual_progress']
                    planned_progress = o['planned_progress']
                    years_actual_progress = o['years_actual_progress']
                    years_planned_progress = o['years_planned_progress']
                r.update_record(actual_progress_by_activities=actual_progress, planned_progress_by_activities=planned_progress, years_actual_progress_by_activities=years_actual_progress, years_planned_progress_by_activities=years_planned_progress)
                if (actual_progress is not None):
                    outcome_id = r.outcome_id
                    weighting = r.weighting
                    actual_progress = (actual_progress * weighting)
                    planned_progress = (planned_progress * weighting)
                    years_actual_progress = (years_actual_progress * weighting)
                    years_planned_progress = (years_planned_progress * weighting)
                    if (outcome_id not in outcomes):
                        outcomes[outcome_id] = {'actual_progress': actual_progress, 'planned_progress': planned_progress, 'years_actual_progress': years_actual_progress, 'years_planned_progress': years_planned_progress}
                    else:
                        o = outcomes[outcome_id]
                        o['actual_progress'] += actual_progress
                        o['planned_progress'] += planned_progress
                        o['years_actual_progress'] += years_actual_progress
                        o['years_planned_progress'] += years_planned_progress
            table = s3db.project_outcome
            query = ((table.project_id == project_id) & (table.deleted == False))
            rows = db(query).select(table.id, table.goal_id, table.weighting)
            for r in rows:
                outcome_id = r.id
                if (outcome_id not in outcomes):
                    actual_progress = planned_progress = years_actual_progress = years_planned_progress = None
                else:
                    o = outcomes[outcome_id]
                    actual_progress = o['actual_progress']
                    planned_progress = o['planned_progress']
                    years_actual_progress = o['years_actual_progress']
                    years_planned_progress = o['years_planned_progress']
                r.update_record(actual_progress_by_activities=actual_progress, planned_progress_by_activities=planned_progress, years_actual_progress_by_activities=years_actual_progress, years_planned_progress_by_activities=years_planned_progress)
                if (actual_progress is not None):
                    goal_id = r.goal_id
                    weighting = r.weighting
                    actual_progress = (actual_progress * weighting)
                    planned_progress = (planned_progress * weighting)
                    years_actual_progress = (years_actual_progress * weighting)
                    years_planned_progress = (years_planned_progress * weighting)
                    if (goal_id not in goals):
                        goals[goal_id] = {'actual_progress': actual_progress, 'planned_progress': planned_progress, 'years_actual_progress': years_actual_progress, 'years_planned_progress': years_planned_progress}
                    else:
                        g = goals[goal_id]
                        g['actual_progress'] += actual_progress
                        g['planned_progress'] += planned_progress
                        g['years_actual_progress'] += years_actual_progress
                        g['years_planned_progress'] += years_planned_progress
            table = s3db.project_goal
            query = ((table.project_id == project_id) & (table.deleted == False))
            rows = db(query).select(table.id, table.weighting)
            for r in rows:
                goal_id = r.id
                if (goal_id not in goals):
                    actual_progress = planned_progress = years_actual_progress = years_planned_progress = None
                else:
                    g = goals[goal_id]
                    actual_progress = g['actual_progress']
                    planned_progress = g['planned_progress']
                    years_actual_progress = g['years_actual_progress']
                    years_planned_progress = g['years_planned_progress']
                r.update_record(actual_progress_by_activities=actual_progress, planned_progress_by_activities=planned_progress, years_actual_progress_by_activities=years_actual_progress, years_planned_progress_by_activities=years_planned_progress)
                if (actual_progress is not None):
                    weighting = r.weighting
                    actual_progress = (actual_progress * weighting)
                    planned_progress = (planned_progress * weighting)
                    years_actual_progress = (years_actual_progress * weighting)
                    years_planned_progress = (years_planned_progress * weighting)
                    if (project is None):
                        project = {'actual_progress': actual_progress, 'planned_progress': planned_progress, 'years_actual_progress': years_actual_progress, 'years_planned_progress': years_planned_progress}
                    else:
                        project['actual_progress'] += actual_progress
                        project['planned_progress'] += planned_progress
                        project['years_actual_progress'] += years_actual_progress
                        project['years_planned_progress'] += years_planned_progress
            table = s3db.project_project
            pset = db((table.id == project_id))
            if (project is None):
                pset.update(actual_progress_by_activities=None, planned_progress_by_activities=None, years_actual_progress_by_activities=None, years_planned_progress_by_activities=None)
            else:
                pset.update(actual_progress_by_activities=project['actual_progress'], planned_progress_by_activities=project['planned_progress'], years_actual_progress_by_activities=project['years_actual_progress'], years_planned_progress_by_activities=project['years_planned_progress'])
    table = s3db.project_indicator_data
    query = (((((table.project_id == project_id) & (table.deleted == False)) & (table.end_date < current.request.utcnow)) & (table.target_value != None)) & (table.value != None))
    indicator_data = db(query).select(table.indicator_id, table.target_value, table.value, table.end_date, orderby=(~ table.end_date))
    if (not indicator_data):
        return
    project = None
    goals = {}
    outcomes = {}
    outputs = {}
    indicators = {}
    latest_date = None
    for d in indicator_data:
        target_value = d.target_value
        value = d.value
        if ((target_value == 0.0) and (value == 0.0)):
            continue
        else:
            end_date = d.end_date
            if (not latest_date):
                latest_date = end_date
            indicator_id = d.indicator_id
            if (indicator_id not in indicators):
                indicators[indicator_id] = {'total_target': target_value, 'total_value': value, 'current_target': target_value, 'current_value': value, 'current_date': end_date}
            else:
                i = indicators[indicator_id]
                i['total_target'] += target_value
                i['total_value'] += value
    latest_month = latest_date.month
    latest_year = latest_date.year
    for indicator_id in indicators:
        i = indicators[indicator_id]
        current_date = i['current_date']
        if ((current_date.month != latest_month) or (current_date.year != latest_year)):
            i.update(current_target=None, current_value=None)
    table = s3db.project_indicator
    query = ((table.project_id == project_id) & (table.deleted == False))
    rows = db(query).select(table.id, table.output_id, table.weighting)
    for r in rows:
        indicator_id = r.id
        if (indicator_id not in indicators):
            current_status = overall_status = None
        else:
            i = indicators[indicator_id]
            total_target = i['total_target']
            total_value = i['total_value']
            current_target = i['current_target']
            current_value = i['current_value']
            if (total_target is None):
                overall_status = None
            elif (total_target == 0.0):
                if (total_value == 0.0):
                    overall_status = None
                else:
                    overall_status = 100.0
            elif (total_value == 0.0):
                overall_status = 0.0
            else:
                overall_status = ((total_value / total_target) * 100)
            if (current_target is None):
                current_status = None
            elif (current_target == 0.0):
                if (current_value == 0.0):
                    current_status = None
                else:
                    current_status = 100.0
            elif (current_value == 0.0):
                current_status = 0.0
            else:
                current_status = ((current_value / current_target) * 100)
        r.update_record(current_status_by_indicators=current_status, overall_status_by_indicators=overall_status)
        output_id = r.output_id
        weighting = r.weighting
        if (current_status is None):
            current_status = current_weighting = 0
        else:
            if (current_status > 100):
                current_status = 100
            current_status = (current_status * weighting)
            current_weighting = weighting
        if (overall_status is None):
            overall_status = overall_weighting = 0
        else:
            if (overall_status > 100):
                overall_status = 100
            overall_status = (overall_status * weighting)
            overall_weighting = weighting
        if (output_id not in outputs):
            outputs[output_id] = {'current_status': current_status, 'overall_status': overall_status, 'total_current_weighting': current_weighting, 'total_overall_weighting': overall_weighting}
        else:
            o = outputs[output_id]
            o.update(current_status=(o['current_status'] + current_status), overall_status=(o['overall_status'] + overall_status), total_current_weighting=(o['total_current_weighting'] + current_weighting), total_overall_weighting=(o['total_overall_weighting'] + overall_weighting))
    table = s3db.project_output
    query = ((table.project_id == project_id) & (table.deleted == False))
    rows = db(query).select(table.id, table.outcome_id, table.weighting)
    for r in rows:
        output_id = r.id
        if (output_id not in outputs):
            current_status = overall_status = None
        else:
            o = outputs[output_id]
            total_current_weighting = o['total_current_weighting']
            if total_current_weighting:
                current_status = (o['current_status'] / total_current_weighting)
            else:
                current_status = None
            total_overall_weighting = o['total_overall_weighting']
            if total_overall_weighting:
                overall_status = (o['overall_status'] / total_overall_weighting)
            else:
                overall_status = None
        r.update_record(current_status_by_indicators=current_status, overall_status_by_indicators=overall_status)
        outcome_id = r.outcome_id
        weighting = r.weighting
        if (current_status is None):
            current_status = current_weighting = 0
        else:
            current_status = (current_status * weighting)
            current_weighting = weighting
        if (overall_status is None):
            overall_status = overall_weighting = 0
        else:
            overall_status = (overall_status * weighting)
            overall_weighting = weighting
        if (outcome_id not in outcomes):
            outcomes[outcome_id] = {'current_status': current_status, 'overall_status': overall_status, 'total_current_weighting': current_weighting, 'total_overall_weighting': overall_weighting}
        else:
            o = outcomes[outcome_id]
            o.update(current_status=(o['current_status'] + current_status), overall_status=(o['overall_status'] + overall_status), total_current_weighting=(o['total_current_weighting'] + current_weighting), total_overall_weighting=(o['total_overall_weighting'] + overall_weighting))
    table = s3db.project_outcome
    query = ((table.project_id == project_id) & (table.deleted == False))
    rows = db(query).select(table.id, table.goal_id, table.weighting)
    for r in rows:
        outcome_id = r.id
        if (outcome_id not in outcomes):
            current_status = overall_status = None
        else:
            o = outcomes[outcome_id]
            total_current_weighting = o['total_current_weighting']
            if total_current_weighting:
                current_status = (o['current_status'] / total_current_weighting)
            else:
                current_status = None
            total_overall_weighting = o['total_overall_weighting']
            if total_overall_weighting:
                overall_status = (o['overall_status'] / total_overall_weighting)
            else:
                overall_status = None
        r.update_record(current_status_by_indicators=current_status, overall_status_by_indicators=overall_status)
        goal_id = r.goal_id
        weighting = r.weighting
        if (current_status is None):
            current_status = current_weighting = 0
        else:
            current_status = (current_status * weighting)
            current_weighting = weighting
        if (overall_status is None):
            overall_status = overall_weighting = 0
        else:
            overall_status = (overall_status * weighting)
            overall_weighting = weighting
        if (goal_id not in goals):
            goals[goal_id] = {'current_status': current_status, 'overall_status': overall_status, 'total_current_weighting': current_weighting, 'total_overall_weighting': overall_weighting}
        else:
            g = goals[goal_id]
            g.update(current_status=(g['current_status'] + current_status), overall_status=(g['overall_status'] + overall_status), total_current_weighting=(g['total_current_weighting'] + current_weighting), total_overall_weighting=(g['total_overall_weighting'] + overall_weighting))
    table = s3db.project_goal
    query = ((table.project_id == project_id) & (table.deleted == False))
    rows = db(query).select(table.id, table.weighting)
    for r in rows:
        goal_id = r.id
        if (goal_id not in goals):
            current_status = overall_status = None
        else:
            g = goals[goal_id]
            total_current_weighting = g['total_current_weighting']
            if total_current_weighting:
                current_status = (g['current_status'] / total_current_weighting)
            else:
                current_status = None
            total_overall_weighting = g['total_overall_weighting']
            if total_overall_weighting:
                overall_status = (g['overall_status'] / total_overall_weighting)
            else:
                overall_status = None
        r.update_record(current_status_by_indicators=current_status, overall_status_by_indicators=overall_status)
        weighting = r.weighting
        if (current_status is None):
            current_status = current_weighting = 0
        else:
            current_status = (current_status * weighting)
            current_weighting = weighting
        if (overall_status is None):
            overall_status = overall_weighting = 0
        else:
            overall_status = (overall_status * weighting)
            overall_weighting = weighting
        if (project is None):
            project = {'current_status': current_status, 'overall_status': overall_status, 'total_current_weighting': current_weighting, 'total_overall_weighting': overall_weighting}
        else:
            project['current_status'] += current_status
            project['overall_status'] += overall_status
            project['total_current_weighting'] += current_weighting
            project['total_overall_weighting'] += overall_weighting
    total_current_weighting = project['total_current_weighting']
    if total_current_weighting:
        current_status = (project['current_status'] / total_current_weighting)
    else:
        current_status = None
    total_overall_weighting = project['total_overall_weighting']
    if total_overall_weighting:
        overall_status = (project['overall_status'] / total_overall_weighting)
    else:
        overall_status = None
    table = s3db.project_project
    db((table.id == project_id)).update(current_status_by_indicators=current_status, overall_status_by_indicators=overall_status)
