def _resolve_actual(self, project, task): today = strpdate(project["today"]) actual = task.get("actual") if actual is None or actual.get("start") is None: return if "period" in actual: end_date = calc_date_in_business_days(strpdate(actual["start"]), actual["period"], project["closed_dates"]) actual["end"] = end_date.strftime("%Y/%m/%d") if "progress" in actual: start = strpdate(actual["start"]) progress = actual["progress"] dates = set( [start + timedelta(i) for i in range((today - start).days)]) dates = dates - set(project["closed_dates"]) days = math.ceil(len(dates) / progress) actual["completed"] = today.strftime("%Y/%m/%d") end_date = calc_date_in_business_days(start, days, project["closed_dates"]) actual["end"] = end_date.strftime("%Y/%m/%d")
def _create_calendar(self, project, closed_dates): start = strpdate(project["start"]) end = strpdate(project["end"]) calendar = Calendar(start, end, strpdate(project["today"]), closed_dates, project["scale"]) return calendar
def _get_closed_dates(self, project): closed_dates = [] opened_dates = [] start = strpdate(project["start"]) end = strpdate(project["end"]) if "SCHEDAUS_DEFAULT_HOLIDAYS" in os.environ: for c in os.environ["SCHEDAUS_DEFAULT_HOLIDAYS"].split(","): try: d = strpdate(c, fmt="%m/%d") closed_dates.extend( month_day_pair_to_dates(d.month, d.day, start, end)) except ValueError: closed_dates.extend(weekday_to_dates(c, start, end)) for c in project["closed"]: try: d = strpdate(c) closed_dates.append(d) except ValueError: closed_dates.extend(weekday_to_dates(c, start, end)) for c in project.get("opened", []): try: d = strpdate(c) opened_dates.append(d) except ValueError: opened_dates.extend(weekday_to_dates(c, start, end)) return list(set(closed_dates) - set(opened_dates))
def project_period(self, line, m): try: strpdate(m.group(2)) strpdate(m.group(3)) self.output["project"]["start"] = m.group(2) self.output["project"]["end"] = m.group(3) except ValueError: pass
def _ranged_day(self, line, m): ret = [] try: d = strpdate(m.group(1)) end = strpdate(m.group(2)) + timedelta(days=1) if d > end: return while d != end: ret.append(d.strftime("%Y/%m/%d")) d += timedelta(days=1) except ValueError: pass return ret
def _(k): if plan[k + "_org"].endswith("'s end"): dep = plan[k + "_org"].replace("'s end", "") dep_end = strpdate( schedules.get(dep, {}).get("plan", {}).get("end")) return DependencyPath(dep, dep_end, name, strpdate(plan[k]), self.path_color) if plan[k + "_org"].endswith("'s start"): dep = plan[k + "_org"].replace("'s start", "") dep_start = strpdate( schedules.get(dep, {}).get("plan", {}).get("start")) return DependencyPath(dep, dep_start, name, strpdate(plan[k]), self.path_color)
def _resolve_date(self, project, schedules, name): t = schedules[name] plan = t.get("plan") if plan is None: return def _date_delta(d, delta): return calc_date_in_business_days( strpdate(d), delta, project["closed_dates"]).strftime("%Y/%m/%d") def _(k): if plan[k] == "project's start": plan[k] = project["start"] if plan[k] == "project's end": plan[k] = project["end"] if plan[k].endswith("'s end"): dep = plan[k].replace("'s end", "") plan[k + "_org"] = plan[k] plan[k] = _date_delta( schedules.get(dep, {}).get("plan", {}).get("end"), 2) if plan[k].endswith("'s start"): dep = plan[k].replace("'s start", "") plan[k + "_org"] = plan[k] plan[k] = _date_delta( schedules.get(dep, {}).get("plan", {}).get("start"), -2) if "start" in plan: _("start") if "end" in plan: _("end") if "period" in plan: end_date = calc_date_in_business_days(strpdate(plan["start"]), plan["period"], project["closed_dates"]) plan["end"] = end_date.strftime("%Y/%m/%d")
def today(self, line, m): try: strpdate(m.group(1)) self.output["project"]["today"] = m.group(1) except ValueError: pass
def _date_delta(d, delta): return calc_date_in_business_days( strpdate(d), delta, project["closed_dates"]).strftime("%Y/%m/%d")
def resolve(self, data_dict): ret = { "calendar": None, "schedules": [], "dependency_paths": [], "groups": [], } project = data_dict["project"] project["scale"] = project.get("scale", "daily") project["closed_dates"] = self._get_closed_dates(project) ret["calendar"] = self._create_calendar(project, project["closed_dates"]) self.colors = self._get_colors(data_dict.get("style")) tasks = data_dict.get("task", []) milestones = data_dict.get("milestone", []) self._check_name_duplication(tasks, milestones) for m in milestones: if "plan" in m: m["plan"] = {"start": m["plan"], "end": m["plan"]} schedules = tasks + milestones schedules = {s["name"]: s for s in schedules} dr = DependResolver(self.colors["path"]) dpaths = dr.resolve(project, schedules) ret["dependency_paths"] = dpaths for task in data_dict.get("task", []): self._resolve_actual(project, task) t = Task( task["name"], task.get("text", task["name"]), strpdate(task["plan"]["start"]), strpdate(task["plan"]["end"]), self.colors["task"]["plan_fill"], self.colors["task"]["plan_outline"], self.colors["task"]["actual_fill"], self.colors["task"]["actual_outline"], self.colors["task"]["text"], strpdate(task.get("actual", {}).get("start")), strpdate(task.get("actual", {}).get("completed")), task.get("actual", {}).get("progress"), strpdate(task.get("actual", {}).get("end")), task.get("assignee"), ) ret["schedules"].append(t) for ms in data_dict.get("milestone", []): m = Milestone( ms["name"], ms.get("text", ms["name"]), strpdate(ms["plan"]["start"]), self.colors["milestone"]["plan_fill"], self.colors["milestone"]["plan_outline"], self.colors["milestone"]["actual_fill"], self.colors["milestone"]["actual_outline"], self.colors["milestone"]["text"], strpdate(ms.get("actual", None)), ) ret["schedules"].append(m) belongs = set() for group in data_dict.get("group", []): ret["groups"].append(Group(group["text"], group["member"])) belongs.update(group["member"]) notbelongs_unordered = set([sc.name for sc in ret["schedules"]]) - belongs notbelongs = [] for sc in ret["schedules"]: if sc.name in notbelongs_unordered: notbelongs.append(sc.name) ret["groups"].insert(0, Group("", notbelongs)) logger.debug(pformat(ret)) return ret