20#include "kptappointment.h"
22#include "kptproject.h"
24#include "kptdatetime.h"
25#include "kptcalendar.h"
26#include "kpteffortcostmap.h"
27#include "kptschedule.h"
36AppointmentInterval::AppointmentInterval() {
39AppointmentInterval::AppointmentInterval(
const AppointmentInterval &interval) {
41 m_start = interval.startTime();
42 m_end = interval.endTime();
43 m_load = interval.load();
45AppointmentInterval::AppointmentInterval(
const DateTime &start,
const DateTime end,
double load) {
51AppointmentInterval::~AppointmentInterval() {
56 if (start >= m_end || end <= m_start) {
59 DateTime s = (start > m_start ? start : m_start);
60 DateTime e = (end < m_end ? end : m_end);
61 return (e - s) * m_load / 100;
66 if (time <= m_start) {
69 DateTime e = (time < m_end ? time : m_end);
70 return (e - m_start) * m_load / 100;
76 DateTime s = (time > m_start ? time : m_start);
77 return (m_end - s) * m_load / 100;
80bool AppointmentInterval::loadXML(TQDomElement &element) {
83 TQString s = element.attribute(
"start");
85 m_start = DateTime::fromString(s);
86 s = element.attribute(
"end");
88 m_end = DateTime::fromString(s);
89 m_load = element.attribute(
"load",
"100").toDouble(&ok);
90 if (!ok) m_load = 100;
91 return m_start.isValid() && m_end.isValid();
94void AppointmentInterval::saveXML(TQDomElement &element)
const {
95 TQDomElement me = element.ownerDocument().createElement(
"interval");
96 element.appendChild(me);
98 me.setAttribute(
"start", m_start.toString(TQt::ISODate));
99 me.setAttribute(
"end", m_end.toString(TQt::ISODate));
100 me.setAttribute(
"load", m_load);
103bool AppointmentInterval::isValid()
const {
104 return m_start.isValid() && m_end.isValid();
107AppointmentInterval AppointmentInterval::firstInterval(
const AppointmentInterval &interval,
const DateTime &from)
const {
110 DateTime s1 = m_start;
112 DateTime s2 = interval.startTime();
113 DateTime e2 = interval.endTime();
114 AppointmentInterval a;
115 if (f.isValid() && f >= e1 && f >= e2) {
119 if (s1 < f && f < e1) {
122 if (s2 < f && f < e2) {
126 f = s1 < s2 ? s1 : s2;
136 }
else if (s1 > s2) {
143 a.setLoad(interval.load());
150 a.setLoad(m_load + interval.load());
158Appointment::UsedEffortItem::UsedEffortItem(TQDate date,
Duration effort,
bool overtime) {
161 m_overtime = overtime;
163TQDate Appointment::UsedEffortItem::date() {
166Duration Appointment::UsedEffortItem::effort() {
169bool Appointment::UsedEffortItem::isOvertime() {
173Appointment::UsedEffort::UsedEffort() {
177void Appointment::UsedEffort::inSort(TQDate date, Duration
effort,
bool overtime) {
178 UsedEffortItem *item =
new UsedEffortItem(date,
effort, overtime);
179 TQPtrList<UsedEffortItem>::inSort(item);
182Duration Appointment::UsedEffort::usedEffort(
bool includeOvertime)
const {
184 TQPtrListIterator<UsedEffortItem> it(*
this);
185 for (; it.current(); ++it) {
186 if (includeOvertime || !it.current()->isOvertime()) {
187 eff += it.current()->effort();
193Duration Appointment::UsedEffort::usedEffort(
const TQDate &date,
bool includeOvertime)
const {
195 TQPtrListIterator<UsedEffortItem> it(*
this);
196 for (; it.current(); ++it) {
197 if ((includeOvertime || !it.current()->isOvertime()) &&
198 it.current()->date() == date) {
199 eff += it.current()->effort();
205Duration Appointment::UsedEffort::usedEffortTo(
const TQDate &date,
bool includeOvertime)
const {
207 TQPtrListIterator<UsedEffortItem> it(*
this);
208 for (; it.current(); ++it) {
209 if ((includeOvertime || !it.current()->isOvertime()) &&
210 it.current()->date() <= date) {
211 eff += it.current()->effort();
217Duration Appointment::UsedEffort::usedOvertime()
const {
218 UsedEffortItem *item = getFirst();
222Duration Appointment::UsedEffort::usedOvertime(
const TQDate &date)
const {
224 TQPtrListIterator<UsedEffortItem> it(*
this);
225 for (; it.current(); ++it) {
226 if (it.current()->isOvertime() && it.current()->date() == date) {
227 eff += it.current()->effort();
233Duration Appointment::UsedEffort::usedOvertimeTo(
const TQDate &date)
const {
235 TQPtrListIterator<UsedEffortItem> it(*
this);
236 for (; it.current(); ++it) {
237 if (it.current()->isOvertime() && it.current()->date() <= date) {
238 eff += it.current()->effort();
244bool Appointment::UsedEffort::load(TQDomElement &element) {
246 TQDomNodeList list = element.childNodes();
247 for (
unsigned int i=0; i<list.count(); ++i) {
248 if (list.item(i).isElement()) {
249 TQDomElement e = list.item(i).toElement();
250 if (e.tagName() ==
"actual-effort") {
252 s = e.attribute(
"date");
254 date = TQDate::fromString(s, TQt::ISODate);
255 Duration eff = Duration::fromString(e.attribute(
"effort"));
256 bool ot = e.attribute(
"overtime",
"0").toInt();
257 if (date.isValid()) {
258 inSort(date, eff, ot);
260 kdError()<<k_funcinfo<<
"Load failed, illegal date: "<<e.attribute(
"date")<<endl;
268void Appointment::UsedEffort::save(TQDomElement &element)
const {
269 if (isEmpty())
return;
270 TQPtrListIterator<UsedEffortItem> it = *
this;
271 for (; it.current(); ++it) {
272 TQDomElement me = element.ownerDocument().createElement(
"actual-effort");
273 element.appendChild(me);
274 me.setAttribute(
"date",it.current()->date().toString(TQt::ISODate));
275 me.setAttribute(
"effort",it.current()->effort().toString());
276 me.setAttribute(
"overtime",it.current()->isOvertime());
280int Appointment::UsedEffort::compareItems(TQPtrCollection::Item item1, TQPtrCollection::Item item2) {
281 TQDate d1 =
static_cast<UsedEffortItem*
>(item1)->date();
282 TQDate d2 =
static_cast<UsedEffortItem*
>(item2)->date();
283 if (d1 > d2)
return 1;
284 if (d1 < d2)
return -1;
289Appointment::Appointment()
290 : m_extraRepeats(), m_skipRepeats() {
294 m_repeatInterval=Duration();
297 m_intervals.setAutoDelete(
true);
300Appointment::Appointment(Schedule *resource, Schedule *node, DateTime start, DateTime end,
double load)
305 m_resource = resource;
306 m_repeatInterval = Duration();
309 addInterval(start, end, load);
311 m_intervals.setAutoDelete(
true);
314Appointment::Appointment(Schedule *resource, Schedule *node, DateTime start, Duration duration,
double load)
319 m_resource = resource;
320 m_repeatInterval = Duration();
323 addInterval(start, duration, load);
325 m_intervals.setAutoDelete(
true);
328Appointment::~Appointment() {
333void Appointment::addInterval(AppointmentInterval *a) {
335 m_intervals.inSort(a);
337void Appointment::addInterval(
const DateTime &start,
const DateTime &end,
double load) {
338 addInterval(
new AppointmentInterval(start, end, load));
340void Appointment::addInterval(
const DateTime &start,
const Duration &duration,
double load) {
341 DateTime e = start+duration;
342 addInterval(start, e, load);
345double Appointment::maxLoad()
const {
347 TQPtrListIterator<AppointmentInterval> it = m_intervals;
348 for (; it.current(); ++it) {
349 if (v < it.current()->load())
350 v = it.current()->load();
355DateTime Appointment::startTime()
const {
357 TQPtrListIterator<AppointmentInterval> it = m_intervals;
358 for (; it.current(); ++it) {
359 if (!t.isValid() || t > it.current()->startTime())
360 t = it.current()->startTime();
365DateTime Appointment::endTime()
const {
367 TQPtrListIterator<AppointmentInterval> it = m_intervals;
368 for (; it.current(); ++it) {
369 if (!t.isValid() || t < it.current()->endTime())
370 t = it.current()->endTime();
375void Appointment::deleteAppointmentFromRepeatList(DateTime) {
378void Appointment::addAppointmentToRepeatList(DateTime) {
381bool Appointment::isBusy(
const DateTime &,
const DateTime &) {
385bool Appointment::loadXML(TQDomElement &element, Project &project, Schedule &sch) {
387 TQDictIterator<Node> it = project.nodeDict();
391 Node *node = project.findNode(element.attribute(
"task-id"));
393 kdError()<<k_funcinfo<<
"The referenced task does not exists: "<<element.attribute(
"task-id")<<endl;
396 Resource *res = project.resource(element.attribute(
"resource-id"));
398 kdError()<<k_funcinfo<<
"The referenced resource does not exists: resource id="<<element.attribute(
"resource-id")<<endl;
401 if (!res->addAppointment(
this, sch)) {
402 kdError()<<k_funcinfo<<
"Failed to add appointment to resource: "<<res->name()<<endl;
405 if (!node->addAppointment(
this, sch)) {
406 kdError()<<k_funcinfo<<
"Failed to add appointment to node: "<<node->name()<<endl;
407 m_resource->takeAppointment(
this);
411 TQDomNodeList list = element.childNodes();
412 for (
unsigned int i=0; i<list.count(); ++i) {
413 if (list.item(i).isElement()) {
414 TQDomElement e = list.item(i).toElement();
415 if (e.tagName() ==
"interval") {
416 AppointmentInterval *a =
new AppointmentInterval();
420 kdError()<<k_funcinfo<<
"Could not load interval"<<endl;
426 if (m_intervals.isEmpty()) {
429 m_actualEffort.load(element);
433void Appointment::saveXML(TQDomElement &element)
const {
434 if (m_intervals.isEmpty()) {
435 kdError()<<k_funcinfo<<
"Incomplete appointment data: No intervals"<<endl;
437 if (m_resource == 0 || m_resource->resource() == 0) {
438 kdError()<<k_funcinfo<<
"Incomplete appointment data: No resource"<<endl;
441 if (m_node == 0 || m_node->node() == 0) {
442 kdError()<<k_funcinfo<<
"Incomplete appointment data: No node"<<endl;
446 TQDomElement me = element.ownerDocument().createElement(
"appointment");
447 element.appendChild(me);
449 me.setAttribute(
"resource-id", m_resource->resource()->id());
450 me.setAttribute(
"task-id", m_node->node()->id());
451 TQPtrListIterator<AppointmentInterval> it = m_intervals;
452 for (; it.current(); ++it) {
453 it.current()->saveXML(me);
455 m_actualEffort.save(me);
461 TQPtrListIterator<AppointmentInterval> it = m_intervals;
462 for (; it.current(); ++it) {
463 d += it.current()->effort();
473 TQPtrListIterator<AppointmentInterval> it = m_intervals;
474 for (; it.current(); ++it) {
475 d += it.current()->effort(s, e);
484 TQPtrListIterator<AppointmentInterval> it = m_intervals;
485 for (; it.current(); ++it) {
486 d += it.current()->effort(e,
true);
499 double rate = m_resource->normalRatePrHour();
500 AppointmentIntervalListIterator it = m_intervals;
501 for (; it.current(); ++it) {
502 DateTime st = it.current()->startTime();
503 DateTime e = it.current()->endTime();
506 if (dt.date() < st.date()) {
507 dt.setDate(st.date());
509 ndt = TQDateTime(dt.addDays(1));
510 while (dt.date() <= e.date()) {
511 eff = it.current()->effort(dt, ndt);
512 ec.add(dt.date(), eff, eff.toDouble(Duration::Unit_h) * rate);
513 if (dt.date() < e.date() ) {
516 ndt = TQDateTime(ndt.addDays(1));
528 return m_actualEffort.usedEffort();
533 return m_actualEffort.usedEffort(date);
538 return m_actualEffort.usedEffortTo(date);
542 if (m_resource && m_resource->resource()) {
543 return plannedEffort().toDouble(Duration::Unit_h) * m_resource->resource()->normalRate();
550 if (m_resource && m_resource->resource()) {
551 return plannedEffort(date).toDouble(Duration::Unit_h) * m_resource->resource()->normalRate();
558 if (m_resource && m_resource->resource()) {
559 return plannedEffortTo(date).toDouble(Duration::Unit_h) * m_resource->resource()->normalRate();
567 if (m_resource && m_resource->resource()) {
568 return (m_actualEffort.usedEffort(
false ).toDouble(Duration::Unit_h)*m_resource->resource()->normalRate()) + (m_actualEffort.usedOvertime().toDouble(Duration::Unit_h)*m_resource->resource()->overtimeRate());
575 if (m_resource && m_resource->resource()) {
576 return (m_actualEffort.usedEffort(date,
false ).toDouble(Duration::Unit_h)*m_resource->resource()->normalRate()) + (m_actualEffort.usedOvertime(date).toDouble(Duration::Unit_h)*m_resource->resource()->overtimeRate());
583 if (m_resource && m_resource->resource()) {
584 return (m_actualEffort.usedEffortTo(date,
false ).toDouble(Duration::Unit_h)*m_resource->resource()->normalRate()) + (m_actualEffort.usedOvertimeTo(date).toDouble(Duration::Unit_h)*m_resource->resource()->overtimeRate());
589void Appointment::addActualEffort(TQDate date,
Duration effort,
bool overtime) {
590 m_actualEffort.inSort(date, effort, overtime);
595 if (m_resource && m_node) {
596 m_resource->add(
this);
600 kdWarning()<<k_funcinfo<<
"Failed: "<<(m_resource ?
"" :
"resource=0 ")
601 <<(m_node ?
"" :
"node=0")<<endl;
608 m_resource->takeAppointment(
this);
611 m_node->takeAppointment(
this);
618 TQPtrListIterator<AppointmentInterval> it = m_intervals;
619 for (; it.current(); ++it) {
620 d += it.current()->effort(start, end);
627 TQPtrListIterator<AppointmentInterval> it = m_intervals;
628 for (; it.current(); ++it) {
629 d += it.current()->effort(start, start+duration);
636 TQPtrListIterator<AppointmentInterval> it = m_intervals;
637 for (; it.current(); ++it) {
638 d += it.current()->effort(time,
false);
644 m_resource = app.resource();
646 m_repeatInterval = app.repeatInterval();
647 m_repeatCount = app.repeatCount();
650 TQPtrListIterator<AppointmentInterval> it = app.intervals();
651 for (; it.current(); ++it) {
652 addInterval(
new AppointmentInterval(*(it.current())));
657Appointment &Appointment::operator+=(
const Appointment &app) {
662Appointment Appointment::operator+(
const Appointment &app) {
664 AppointmentIntervalList ai = app.intervals();
665 AppointmentInterval i;
666 AppointmentInterval *i1 = m_intervals.first();
667 AppointmentInterval *i2 = ai.first();
671 if (!from.isValid() || from < i2->startTime())
672 from = i2->startTime();
673 a.addInterval(from, i2->endTime(), i2->load());
675 from = i2->endTime();
680 if (!from.isValid() || from < i1->startTime())
681 from = i1->startTime();
682 a.addInterval(from, i1->endTime(), i1->load());
684 from = i1->endTime();
685 i1 = m_intervals.next();
688 i = i1->firstInterval(*i2, from);
695 if (i1 && a.endTime() >= i1->endTime()) {
696 i1 = m_intervals.next();
698 if (i2 && a.endTime() >= i2->endTime()) {
706void Appointment::printDebug(TQString indent)
710 kdDebug()<<indent<<
" No node schedule"<<endl;
712 }
else if (m_node->node() == 0) {
713 kdDebug()<<indent<<
" No node"<<endl;
716 if (m_resource == 0) {
717 kdDebug()<<indent<<
" No resource schedule"<<endl;
719 }
else if (m_resource->resource() == 0) {
720 kdDebug()<<indent<<
" No resource"<<endl;
725 kdDebug()<<indent<<
" + Appointment to schedule: "<<m_node->name()<<
" ("<<m_node->type()<<
")"<<
" resource: "<<m_resource->resource()->name()<<endl;
727 TQPtrListIterator<AppointmentInterval> it = intervals();
728 for (; it.current(); ++it) {
729 kdDebug()<<indent<<it.current()->startTime().toString()<<
" - "<<it.current()->endTime().toString()<<
" load="<<it.current()->load()<<endl;
A resource (Resource) can be scheduled to be used at any time, this is represented internally with Ap...
Duration effortFrom(const DateTime &time) const
Returns the planned effort from time onwards.
void detach()
detach appointment from resource and node
EffortCostMap plannedPrDay(const TQDate &start, const TQDate &end) const
Returns the planned effort and cost for the interval start to end (inclusive).
double plannedCost()
Calculates the total planned cost for this appointment.
double actualCost()
Calculates the total actual cost for this appointment.
double actualCostTo(const TQDate &date)
Calculates the actual cost upto and including date.
Duration plannedEffort() const
Returns the total planned effort for this appointment.
bool attach()
attach appointment to resource and node
Duration actualEffortTo(const TQDate &date) const
Returns the actual effort on the date.
Duration effort(const DateTime &start, const DateTime &end) const
Returns the planned effort from start to end.
Duration plannedEffortTo(const TQDate &date) const
Returns the planned effort upto and including date.
Duration actualEffort() const
Returns the total actual effort for this appointment.
double plannedCostTo(const TQDate &date)
Calculates the planned cost upto and including date.
DateTime is a TQDateTime which knows about Duration.
The duration class can be used to store a timespan in a convenient format.
static const Duration zeroDuration
This is useful for occasions where we need a zero duration.
Any resource that is used by a task.