diff --git a/kmymoney/dialogs/keditscheduledlgdecl.ui b/kmymoney/dialogs/keditscheduledlgdecl.ui
index ef4385367..25d1b97eb 100644
--- a/kmymoney/dialogs/keditscheduledlgdecl.ui
+++ b/kmymoney/dialogs/keditscheduledlgdecl.ui
@@ -1,504 +1,504 @@
KEditScheduleDlgDecl
0
0
798
640
Edit Scheduled transaction
true
-
-
-
Schedule name:
false
-
Qt::StrongFocus
-
-
Frequency:
false
-
999
1
Number of selected periods between entries
Qt::StrongFocus
-
-
Payment information
-
-
Payment method
false
-
3
0
0
0
-
61
21
QSizePolicy::Expanding
Qt::Horizontal
-
QFrame::HLine
QFrame::Sunken
-
0
12
Security
Details
C
Payment
Deposit
Quantity
Price
Value
Balance
-
5
1
-
Options
-
-
-
- Do nothing
+ Do not change the date
-
Change the date to the previous processing day
-
Change the date to the next processing day
-
If this schedule occurs on a non-processing day:
false
-
-
The amount is an estimate because it varies for each payment
-
false
10
-
21
20
QSizePolicy::Expanding
Qt::Horizontal
-
Always process this schedule the last day of a month
-
Enter this schedule into the register automatically when it is due
-
This schedule will end at some time
-
QFrame::NoFrame
QFrame::Raised
0
-
20
20
QSizePolicy::Fixed
Qt::Horizontal
-
Number of transactions remaining:
false
-
0
9999
-
Date of final transaction:
false
-
Qt::StrongFocus
-
20
16
QSizePolicy::Expanding
Qt::Vertical
-
0
6
-
Help
-
280
0
QSizePolicy::Expanding
Qt::Horizontal
-
OK
true
true
-
Cancel
KComboBox
QComboBox
KIntNumInput
QWidget
1
KIntSpinBox
QSpinBox
KMyMoneyGeneralCombo
QWidget
1
KMyMoneyOccurrencePeriodCombo
QWidget
1
buttonOk
clicked()
KEditScheduleDlgDecl
accept()
m_endSeriesEdit
toggled(bool)
m_endOptionsFrame
setEnabled(bool)
buttonCancel
clicked()
KEditScheduleDlgDecl
reject()
m_estimateEdit
toggled(bool)
m_variation
setEnabled(bool)
diff --git a/kmymoney/mymoney/mymoneyschedule.cpp b/kmymoney/mymoney/mymoneyschedule.cpp
index 8dee2a8a5..1ac85fd22 100644
--- a/kmymoney/mymoney/mymoneyschedule.cpp
+++ b/kmymoney/mymoney/mymoneyschedule.cpp
@@ -1,1391 +1,1391 @@
/***************************************************************************
mymoneyschedule.cpp
-------------------
copyright : (C) 2000-2002 by Michael Edwardes
(C) 2007 by Thomas Baumgart
***************************************************************************/
/***************************************************************************
* *
* This program 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. *
* *
***************************************************************************/
#include "mymoneyschedule.h"
// ----------------------------------------------------------------------------
// QT Includes
#include
// ----------------------------------------------------------------------------
// KDE Includes
#include
// ----------------------------------------------------------------------------
// Project Includes
#include "mymoneyexception.h"
#include "mymoneyfile.h"
#include "imymoneyprocessingcalendar.h"
static IMyMoneyProcessingCalendar* processingCalendarPtr = 0;
MyMoneySchedule::MyMoneySchedule() :
MyMoneyObject()
{
// Set up the default values
m_occurrence = OCCUR_ANY;
m_occurrenceMultiplier = 1;
m_type = TYPE_ANY;
m_paymentType = STYPE_ANY;
m_fixed = false;
m_lastDayInMonth = false;
m_autoEnter = false;
m_startDate = QDate();
m_endDate = QDate();
m_lastPayment = QDate();
m_weekendOption = MoveNothing;
}
MyMoneySchedule::MyMoneySchedule(const QString& name, typeE type,
occurrenceE occurrence, int occurrenceMultiplier,
paymentTypeE paymentType,
const QDate& /* startDate */,
const QDate& endDate,
bool fixed, bool autoEnter) :
MyMoneyObject()
{
// Set up the default values
m_name = name;
m_occurrence = occurrence;
m_occurrenceMultiplier = occurrenceMultiplier;
simpleToCompoundOccurrence(m_occurrenceMultiplier, m_occurrence);
m_type = type;
m_paymentType = paymentType;
m_fixed = fixed;
m_lastDayInMonth = false;
m_autoEnter = autoEnter;
m_startDate = QDate();
m_endDate = endDate;
m_lastPayment = QDate();
m_weekendOption = MoveNothing;
}
MyMoneySchedule::MyMoneySchedule(const QDomElement& node) :
MyMoneyObject(node)
{
if ("SCHEDULED_TX" != node.tagName())
throw MYMONEYEXCEPTION("Node was not SCHEDULED_TX");
m_name = node.attribute("name");
m_startDate = stringToDate(node.attribute("startDate"));
m_endDate = stringToDate(node.attribute("endDate"));
m_lastPayment = stringToDate(node.attribute("lastPayment"));
m_type = static_cast(node.attribute("type").toInt());
m_paymentType = static_cast(node.attribute("paymentType").toInt());
m_occurrence = static_cast(node.attribute("occurence").toInt()); // krazy:exclude=spelling
m_occurrenceMultiplier = node.attribute("occurenceMultiplier", "1").toInt(); // krazy:exclude=spelling
// Convert to compound occurrence
simpleToCompoundOccurrence(m_occurrenceMultiplier, m_occurrence);
m_lastDayInMonth = static_cast(node.attribute("lastDayInMonth").toInt());
m_autoEnter = static_cast(node.attribute("autoEnter").toInt());
m_fixed = static_cast(node.attribute("fixed").toInt());
m_weekendOption = static_cast(node.attribute("weekendOption").toInt());
// read in the associated transaction
QDomNodeList nodeList = node.elementsByTagName("TRANSACTION");
if (nodeList.count() == 0)
throw MYMONEYEXCEPTION("SCHEDULED_TX has no TRANSACTION node");
setTransaction(MyMoneyTransaction(nodeList.item(0).toElement(), false), true);
// some old versions did not remove the entry date and post date fields
// in the schedule. So if this is the case, we deal with a very old transaction
// and can't use the post date field as next due date. Hence, we wipe it out here
if (m_transaction.entryDate().isValid()) {
m_transaction.setPostDate(QDate());
m_transaction.setEntryDate(QDate());
}
// readin the recorded payments
nodeList = node.elementsByTagName("PAYMENTS");
if (nodeList.count() > 0) {
nodeList = nodeList.item(0).toElement().elementsByTagName("PAYMENT");
for (int i = 0; i < nodeList.count(); ++i) {
m_recordedPayments << stringToDate(nodeList.item(i).toElement().attribute("date"));
}
}
// if the next due date is not set (comes from old version)
// then set it up the old way
if (!nextDueDate().isValid() && !m_lastPayment.isValid()) {
m_transaction.setPostDate(m_startDate);
// clear it, because the schedule has never been used
m_startDate = QDate();
}
// There are reports that lastPayment and nextDueDate are identical or
// that nextDueDate is older than lastPayment. This could
// be caused by older versions of the application. In this case, we just
// clear out the nextDueDate and let it calculate from the lastPayment.
if (nextDueDate().isValid() && nextDueDate() <= m_lastPayment) {
m_transaction.setPostDate(QDate());
}
if (!nextDueDate().isValid()) {
m_transaction.setPostDate(m_startDate);
m_transaction.setPostDate(nextPayment(m_lastPayment.addDays(1)));
}
}
MyMoneySchedule::MyMoneySchedule(const QString& id, const MyMoneySchedule& right) :
MyMoneyObject(id)
{
*this = right;
setId(id);
}
MyMoneySchedule::occurrenceE MyMoneySchedule::occurrence() const
{
MyMoneySchedule::occurrenceE occ = m_occurrence;
int mult = m_occurrenceMultiplier;
compoundToSimpleOccurrence(mult, occ);
return occ;
}
void MyMoneySchedule::setStartDate(const QDate& date)
{
m_startDate = date;
}
void MyMoneySchedule::setPaymentType(paymentTypeE type)
{
m_paymentType = type;
}
void MyMoneySchedule::setFixed(bool fixed)
{
m_fixed = fixed;
}
void MyMoneySchedule::setTransaction(const MyMoneyTransaction& transaction)
{
setTransaction(transaction, false);
}
void MyMoneySchedule::setTransaction(const MyMoneyTransaction& transaction, bool noDateCheck)
{
MyMoneyTransaction t = transaction;
if (!noDateCheck) {
// don't allow a transaction that has no due date
// if we get something like that, then we use the
// the current next due date. If that is also invalid
// we can't help it.
if (!t.postDate().isValid()) {
t.setPostDate(m_transaction.postDate());
}
if (!t.postDate().isValid())
return;
}
// make sure to clear out some unused information in scheduled transactions
// we need to do this for the case that the transaction passed as argument
// is a matched or imported transaction.
QList splits = t.splits();
if (splits.count() > 0) {
QList::const_iterator it_s;
for (it_s = splits.constBegin(); it_s != splits.constEnd(); ++it_s) {
MyMoneySplit s = *it_s;
// clear out the bankID
if (!(*it_s).bankID().isEmpty()) {
s.setBankID(QString());
t.modifySplit(s);
}
// only clear payees from second split onwards
if (it_s == splits.constBegin())
continue;
if (!(*it_s).payeeId().isEmpty()) {
// but only if the split references an income/expense category
MyMoneyFile* file = MyMoneyFile::instance();
// some unit tests don't have a storage attached, so we
// simply skip the test
// Don't check for accounts with an id of 'Phony-ID' which is used
// internally for non-existing accounts (during creation of accounts)
if (file->storageAttached() && s.accountId() != QString("Phony-ID")) {
MyMoneyAccount acc = file->account(s.accountId());
if (acc.isIncomeExpense()) {
s.setPayeeId(QString());
t.modifySplit(s);
}
}
}
}
}
m_transaction = t;
// make sure that the transaction does not have an id so that we can enter
// it into the engine
m_transaction.clearId();
}
void MyMoneySchedule::setEndDate(const QDate& date)
{
m_endDate = date;
}
void MyMoneySchedule::setLastDayInMonth(bool state)
{
m_lastDayInMonth = state;
}
void MyMoneySchedule::setAutoEnter(bool autoenter)
{
m_autoEnter = autoenter;
}
const QDate& MyMoneySchedule::startDate() const
{
if (m_startDate.isValid())
return m_startDate;
return nextDueDate();
}
const QDate& MyMoneySchedule::nextDueDate() const
{
return m_transaction.postDate();
}
QDate MyMoneySchedule::adjustedNextDueDate() const
{
if (isFinished())
return QDate();
if (lastDayInMonth()) {
QDate date = nextDueDate();
return adjustedDate(QDate(date.year(), date.month(), date.daysInMonth()), weekendOption());
}
return adjustedDate(nextDueDate(), weekendOption());
}
QDate MyMoneySchedule::adjustedDate(QDate date, weekendOptionE option) const
{
if (!date.isValid() || option == MyMoneySchedule::MoveNothing || isProcessingDate(date))
return date;
int step = 1;
if (option == MyMoneySchedule::MoveBefore)
step = -1;
while (!isProcessingDate(date))
date = date.addDays(step);
return date;
}
void MyMoneySchedule::setNextDueDate(const QDate& date)
{
if (date.isValid()) {
m_transaction.setPostDate(date);
// m_startDate = date;
}
}
void MyMoneySchedule::setLastPayment(const QDate& date)
{
// Delete all payments older than date
QList::Iterator it;
QList delList;
for (it = m_recordedPayments.begin(); it != m_recordedPayments.end(); ++it) {
if (*it < date || !date.isValid())
delList.append(*it);
}
for (it = delList.begin(); it != delList.end(); ++it) {
m_recordedPayments.removeAll(*it);
}
m_lastPayment = date;
if (!m_startDate.isValid())
m_startDate = date;
}
void MyMoneySchedule::setName(const QString& nm)
{
m_name = nm;
}
void MyMoneySchedule::setOccurrence(occurrenceE occ)
{
MyMoneySchedule::occurrenceE occ2 = occ;
int mult = 1;
simpleToCompoundOccurrence(mult, occ2);
setOccurrencePeriod(occ2);
setOccurrenceMultiplier(mult);
}
void MyMoneySchedule::setOccurrencePeriod(occurrenceE occ)
{
m_occurrence = occ;
}
void MyMoneySchedule::setOccurrenceMultiplier(int occmultiplier)
{
m_occurrenceMultiplier = occmultiplier < 1 ? 1 : occmultiplier;
}
void MyMoneySchedule::setType(typeE type)
{
m_type = type;
}
void MyMoneySchedule::validate(bool id_check) const
{
/* Check the supplied instance is valid...
*
* To be valid it must not have the id set and have the following fields set:
*
* m_occurrence
* m_type
* m_startDate
* m_paymentType
* m_transaction
* the transaction must contain at least one split (two is better ;-) )
*/
if (id_check && !m_id.isEmpty())
throw MYMONEYEXCEPTION("ID for schedule not empty when required");
if (m_occurrence == OCCUR_ANY)
throw MYMONEYEXCEPTION("Invalid occurrence type for schedule");
if (m_type == TYPE_ANY)
throw MYMONEYEXCEPTION("Invalid type for schedule");
if (!nextDueDate().isValid())
throw MYMONEYEXCEPTION("Invalid next due date for schedule");
if (m_paymentType == STYPE_ANY)
throw MYMONEYEXCEPTION("Invalid payment type for schedule");
if (m_transaction.splitCount() == 0)
throw MYMONEYEXCEPTION("Scheduled transaction does not contain splits");
// Check the payment types
switch (m_type) {
case TYPE_BILL:
if (m_paymentType == STYPE_DIRECTDEPOSIT || m_paymentType == STYPE_MANUALDEPOSIT)
throw MYMONEYEXCEPTION("Invalid payment type for bills");
break;
case TYPE_DEPOSIT:
if (m_paymentType == STYPE_DIRECTDEBIT || m_paymentType == STYPE_WRITECHEQUE)
throw MYMONEYEXCEPTION("Invalid payment type for deposits");
break;
case TYPE_ANY:
throw MYMONEYEXCEPTION("Invalid type ANY");
break;
case TYPE_TRANSFER:
// if (m_paymentType == STYPE_DIRECTDEPOSIT || m_paymentType == STYPE_MANUALDEPOSIT)
// return false;
break;
case TYPE_LOANPAYMENT:
break;
}
}
QDate MyMoneySchedule::adjustedNextPayment(const QDate& refDate) const
{
return nextPaymentDate(true, refDate);
}
QDate MyMoneySchedule::nextPayment(const QDate& refDate) const
{
return nextPaymentDate(false, refDate);
}
QDate MyMoneySchedule::nextPaymentDate(const bool& adjust, const QDate& refDate) const
{
weekendOptionE option(adjust ? weekendOption() :
MyMoneySchedule::MoveNothing);
QDate adjEndDate(adjustedDate(m_endDate, option));
// if the enddate is valid and it is before the reference date,
// then there will be no more payments.
if (adjEndDate.isValid() && adjEndDate < refDate) {
return QDate();
}
QDate dueDate(nextDueDate());
QDate paymentDate(adjustedDate(dueDate, option));
if (paymentDate.isValid() &&
(paymentDate <= refDate || m_recordedPayments.contains(dueDate))) {
switch (m_occurrence) {
case OCCUR_ONCE:
// If the lastPayment is already set or the payment should have been
// prior to the reference date then invalidate the payment date.
if (m_lastPayment.isValid() || paymentDate <= refDate)
paymentDate = QDate();
break;
case OCCUR_DAILY: {
int step = m_occurrenceMultiplier;
do {
dueDate = dueDate.addDays(step);
paymentDate = adjustedDate(dueDate, option);
} while (paymentDate.isValid() &&
(paymentDate <= refDate ||
m_recordedPayments.contains(dueDate)));
}
break;
case OCCUR_WEEKLY: {
int step = 7 * m_occurrenceMultiplier;
do {
dueDate = dueDate.addDays(step);
paymentDate = adjustedDate(dueDate, option);
} while (paymentDate.isValid() &&
(paymentDate <= refDate ||
m_recordedPayments.contains(dueDate)));
}
break;
case OCCUR_EVERYHALFMONTH:
do {
dueDate = addHalfMonths(dueDate, m_occurrenceMultiplier);
paymentDate = adjustedDate(dueDate, option);
} while (paymentDate.isValid() &&
(paymentDate <= refDate ||
m_recordedPayments.contains(dueDate)));
break;
case OCCUR_MONTHLY:
do {
dueDate = dueDate.addMonths(m_occurrenceMultiplier);
fixDate(dueDate);
paymentDate = adjustedDate(dueDate, option);
} while (paymentDate.isValid() &&
(paymentDate <= refDate ||
m_recordedPayments.contains(dueDate)));
break;
case OCCUR_YEARLY:
do {
dueDate = dueDate.addYears(m_occurrenceMultiplier);
fixDate(dueDate);
paymentDate = adjustedDate(dueDate, option);
} while (paymentDate.isValid() &&
(paymentDate <= refDate ||
m_recordedPayments.contains(dueDate)));
break;
case OCCUR_ANY:
default:
paymentDate = QDate();
break;
}
}
if (paymentDate.isValid() && adjEndDate.isValid() && paymentDate > adjEndDate)
paymentDate = QDate();
return paymentDate;
}
QList MyMoneySchedule::paymentDates(const QDate& _startDate, const QDate& _endDate) const
{
QDate paymentDate(nextDueDate());
QList theDates;
weekendOptionE option(weekendOption());
QDate endDate(_endDate);
if (willEnd() && m_endDate < endDate) {
// consider the adjusted end date instead of the plain end date
endDate = adjustedDate(m_endDate, option);
}
QDate start_date(adjustedDate(startDate(), option));
// if the period specified by the parameters and the adjusted period
// defined for this schedule don't overlap, then the list remains empty
if ((willEnd() && adjustedDate(m_endDate, option) < _startDate)
|| start_date > endDate)
return theDates;
QDate date(adjustedDate(paymentDate, option));
switch (m_occurrence) {
case OCCUR_ONCE:
if (start_date >= _startDate && start_date <= endDate)
theDates.append(start_date);
break;
case OCCUR_DAILY:
while (date.isValid() && (date <= endDate)) {
if (date >= _startDate)
theDates.append(date);
paymentDate = paymentDate.addDays(m_occurrenceMultiplier);
date = adjustedDate(paymentDate, option);
}
break;
case OCCUR_WEEKLY: {
int step = 7 * m_occurrenceMultiplier;
while (date.isValid() && (date <= endDate)) {
if (date >= _startDate)
theDates.append(date);
paymentDate = paymentDate.addDays(step);
date = adjustedDate(paymentDate, option);
}
}
break;
case OCCUR_EVERYHALFMONTH:
while (date.isValid() && (date <= endDate)) {
if (date >= _startDate)
theDates.append(date);
paymentDate = addHalfMonths(paymentDate, m_occurrenceMultiplier);
date = adjustedDate(paymentDate, option);
}
break;
case OCCUR_MONTHLY:
while (date.isValid() && (date <= endDate)) {
if (date >= _startDate)
theDates.append(date);
paymentDate = paymentDate.addMonths(m_occurrenceMultiplier);
fixDate(paymentDate);
date = adjustedDate(paymentDate, option);
}
break;
case OCCUR_YEARLY:
while (date.isValid() && (date <= endDate)) {
if (date >= _startDate)
theDates.append(date);
paymentDate = paymentDate.addYears(m_occurrenceMultiplier);
fixDate(paymentDate);
date = adjustedDate(paymentDate, option);
}
break;
case OCCUR_ANY:
default:
break;
}
return theDates;
}
bool MyMoneySchedule::operator <(const MyMoneySchedule& right) const
{
return adjustedNextDueDate() < right.adjustedNextDueDate();
}
bool MyMoneySchedule::operator ==(const MyMoneySchedule& right) const
{
if (MyMoneyObject::operator==(right) &&
m_occurrence == right.m_occurrence &&
m_occurrenceMultiplier == right.m_occurrenceMultiplier &&
m_type == right.m_type &&
m_startDate == right.m_startDate &&
m_paymentType == right.m_paymentType &&
m_fixed == right.m_fixed &&
m_transaction == right.m_transaction &&
m_endDate == right.m_endDate &&
m_lastDayInMonth == right.m_lastDayInMonth &&
m_autoEnter == right.m_autoEnter &&
m_lastPayment == right.m_lastPayment &&
((m_name.length() == 0 && right.m_name.length() == 0) || (m_name == right.m_name)))
return true;
return false;
}
int MyMoneySchedule::transactionsRemaining() const
{
return transactionsRemainingUntil(adjustedDate(m_endDate, weekendOption()));
}
int MyMoneySchedule::transactionsRemainingUntil(const QDate& endDate) const
{
int counter = 0;
QDate startDate = m_lastPayment.isValid() ? m_lastPayment : m_startDate;
if (startDate.isValid() && endDate.isValid()) {
QList dates = paymentDates(startDate, endDate);
counter = dates.count();
}
return counter;
}
MyMoneyAccount MyMoneySchedule::account(int cnt) const
{
QList splits = m_transaction.splits();
QList::ConstIterator it;
MyMoneyFile* file = MyMoneyFile::instance();
MyMoneyAccount acc;
// search the first asset or liability account
for (it = splits.constBegin(); it != splits.constEnd() && (acc.id().isEmpty() || cnt); ++it) {
try {
acc = file->account((*it).accountId());
if (acc.isAssetLiability())
--cnt;
if (!cnt)
return acc;
} catch (const MyMoneyException &) {
qWarning("Schedule '%s' references unknown account '%s'", qPrintable(id()), qPrintable((*it).accountId()));
return MyMoneyAccount();
}
}
return MyMoneyAccount();
}
QDate MyMoneySchedule::dateAfter(int transactions) const
{
int counter = 1;
QDate paymentDate(startDate());
if (transactions <= 0)
return paymentDate;
switch (m_occurrence) {
case OCCUR_ONCE:
break;
case OCCUR_DAILY:
while (counter++ < transactions)
paymentDate = paymentDate.addDays(m_occurrenceMultiplier);
break;
case OCCUR_WEEKLY: {
int step = 7 * m_occurrenceMultiplier;
while (counter++ < transactions)
paymentDate = paymentDate.addDays(step);
}
break;
case OCCUR_EVERYHALFMONTH:
paymentDate = addHalfMonths(paymentDate, m_occurrenceMultiplier * (transactions - 1));
break;
case OCCUR_MONTHLY:
while (counter++ < transactions)
paymentDate = paymentDate.addMonths(m_occurrenceMultiplier);
break;
case OCCUR_YEARLY:
while (counter++ < transactions)
paymentDate = paymentDate.addYears(m_occurrenceMultiplier);
break;
case OCCUR_ANY:
default:
break;
}
return paymentDate;
}
bool MyMoneySchedule::isOverdue() const
{
if (isFinished())
return false;
if (adjustedNextDueDate() >= QDate::currentDate())
return false;
return true;
}
bool MyMoneySchedule::isFinished() const
{
if (!m_lastPayment.isValid())
return false;
if (m_endDate.isValid()) {
if (m_lastPayment >= m_endDate
|| !nextDueDate().isValid()
|| nextDueDate() > m_endDate)
return true;
}
// Check to see if its a once off payment
if (m_occurrence == MyMoneySchedule::OCCUR_ONCE)
return true;
return false;
}
bool MyMoneySchedule::hasRecordedPayment(const QDate& date) const
{
// m_lastPayment should always be > recordedPayments()
if (m_lastPayment.isValid() && m_lastPayment >= date)
return true;
if (m_recordedPayments.contains(date))
return true;
return false;
}
void MyMoneySchedule::recordPayment(const QDate& date)
{
m_recordedPayments.append(date);
}
void MyMoneySchedule::setWeekendOption(const weekendOptionE option)
{
// make sure only valid values are used. Invalid defaults to MoveNothing.
switch (option) {
case MoveBefore:
case MoveAfter:
m_weekendOption = option;
break;
default:
m_weekendOption = MoveNothing;
break;
}
}
void MyMoneySchedule::fixDate(QDate& date) const
{
QDate fixDate(m_startDate);
if (fixDate.isValid()
&& date.day() != fixDate.day()
&& QDate::isValid(date.year(), date.month(), fixDate.day())) {
date = QDate(date.year(), date.month(), fixDate.day());
}
}
void MyMoneySchedule::writeXML(QDomDocument& document, QDomElement& parent) const
{
QDomElement el = document.createElement("SCHEDULED_TX");
writeBaseXML(document, el);
el.setAttribute("name", m_name);
el.setAttribute("type", m_type);
el.setAttribute("occurence", m_occurrence); // krazy:exclude=spelling
el.setAttribute("occurenceMultiplier", m_occurrenceMultiplier);
el.setAttribute("paymentType", m_paymentType);
el.setAttribute("startDate", dateToString(m_startDate));
el.setAttribute("endDate", dateToString(m_endDate));
el.setAttribute("fixed", m_fixed);
el.setAttribute("lastDayInMonth", m_lastDayInMonth);
el.setAttribute("autoEnter", m_autoEnter);
el.setAttribute("lastPayment", dateToString(m_lastPayment));
el.setAttribute("weekendOption", m_weekendOption);
//store the payment history for this scheduled task.
QList payments = recordedPayments();
QList::ConstIterator it;
QDomElement paymentsElement = document.createElement("PAYMENTS");
for (it = payments.constBegin(); it != payments.constEnd(); ++it) {
QDomElement paymentEntry = document.createElement("PAYMENT");
paymentEntry.setAttribute("date", dateToString(*it));
paymentsElement.appendChild(paymentEntry);
}
el.appendChild(paymentsElement);
//store the transaction data for this task.
m_transaction.writeXML(document, el);
parent.appendChild(el);
}
bool MyMoneySchedule::hasReferenceTo(const QString& id) const
{
return m_transaction.hasReferenceTo(id);
}
QString MyMoneySchedule::occurrenceToString() const
{
return occurrenceToString(occurrenceMultiplier(), occurrencePeriod());
}
QString MyMoneySchedule::occurrenceToString(occurrenceE occurrence)
{
QString occurrenceString = I18N_NOOP2("Frequency of schedule", "Any");
if (occurrence == MyMoneySchedule::OCCUR_ONCE)
occurrenceString = I18N_NOOP2("Frequency of schedule", "Once");
else if (occurrence == MyMoneySchedule::OCCUR_DAILY)
occurrenceString = I18N_NOOP2("Frequency of schedule", "Daily");
else if (occurrence == MyMoneySchedule::OCCUR_WEEKLY)
occurrenceString = I18N_NOOP2("Frequency of schedule", "Weekly");
else if (occurrence == MyMoneySchedule::OCCUR_FORTNIGHTLY)
occurrenceString = I18N_NOOP2("Frequency of schedule", "Fortnightly");
else if (occurrence == MyMoneySchedule::OCCUR_EVERYOTHERWEEK)
occurrenceString = I18N_NOOP2("Frequency of schedule", "Every other week");
else if (occurrence == MyMoneySchedule::OCCUR_EVERYHALFMONTH)
occurrenceString = I18N_NOOP2("Frequency of schedule", "Every half month");
else if (occurrence == MyMoneySchedule::OCCUR_EVERYTHREEWEEKS)
occurrenceString = I18N_NOOP2("Frequency of schedule", "Every three weeks");
else if (occurrence == MyMoneySchedule::OCCUR_EVERYFOURWEEKS)
occurrenceString = I18N_NOOP2("Frequency of schedule", "Every four weeks");
else if (occurrence == MyMoneySchedule::OCCUR_EVERYTHIRTYDAYS)
occurrenceString = I18N_NOOP2("Frequency of schedule", "Every thirty days");
else if (occurrence == MyMoneySchedule::OCCUR_MONTHLY)
occurrenceString = I18N_NOOP2("Frequency of schedule", "Monthly");
else if (occurrence == MyMoneySchedule::OCCUR_EVERYEIGHTWEEKS)
occurrenceString = I18N_NOOP2("Frequency of schedule", "Every eight weeks");
else if (occurrence == MyMoneySchedule::OCCUR_EVERYOTHERMONTH)
occurrenceString = I18N_NOOP2("Frequency of schedule", "Every two months");
else if (occurrence == MyMoneySchedule::OCCUR_EVERYTHREEMONTHS)
occurrenceString = I18N_NOOP2("Frequency of schedule", "Every three months");
else if (occurrence == MyMoneySchedule::OCCUR_QUARTERLY)
occurrenceString = I18N_NOOP2("Frequency of schedule", "Quarterly");
else if (occurrence == MyMoneySchedule::OCCUR_EVERYFOURMONTHS)
occurrenceString = I18N_NOOP2("Frequency of schedule", "Every four months");
else if (occurrence == MyMoneySchedule::OCCUR_TWICEYEARLY)
occurrenceString = I18N_NOOP2("Frequency of schedule", "Twice yearly");
else if (occurrence == MyMoneySchedule::OCCUR_YEARLY)
occurrenceString = I18N_NOOP2("Frequency of schedule", "Yearly");
else if (occurrence == MyMoneySchedule::OCCUR_EVERYOTHERYEAR)
occurrenceString = I18N_NOOP2("Frequency of schedule", "Every other year");
return occurrenceString;
}
QString MyMoneySchedule::occurrenceToString(int mult, occurrenceE type)
{
QString occurrenceString = I18N_NOOP2("Frequency of schedule", "Any");
if (type == MyMoneySchedule::OCCUR_ONCE)
switch (mult) {
case 1:
occurrenceString = I18N_NOOP2("Frequency of schedule", "Once");
break;
default:
occurrenceString = I18N_NOOP2("Frequency of schedule", QString("%1 times").arg(mult));
}
else if (type == MyMoneySchedule::OCCUR_DAILY)
switch (mult) {
case 1:
occurrenceString = I18N_NOOP2("Frequency of schedule", "Daily");
break;
case 30:
occurrenceString = I18N_NOOP2("Frequency of schedule", "Every thirty days");
break;
default:
occurrenceString = I18N_NOOP2("Frequency of schedule", QString("Every %1 days").arg(mult));
}
else if (type == MyMoneySchedule::OCCUR_WEEKLY)
switch (mult) {
case 1:
occurrenceString = I18N_NOOP2("Frequency of schedule", "Weekly");
break;
case 2:
occurrenceString = I18N_NOOP2("Frequency of schedule", "Every other week");
break;
case 3:
occurrenceString = I18N_NOOP2("Frequency of schedule", "Every three weeks");
break;
case 4:
occurrenceString = I18N_NOOP2("Frequency of schedule", "Every four weeks");
break;
case 8:
occurrenceString = I18N_NOOP2("Frequency of schedule", "Every eight weeks");
break;
default:
occurrenceString = I18N_NOOP2("Frequency of schedule", QString("Every %1 weeks").arg(mult));
}
else if (type == MyMoneySchedule::OCCUR_EVERYHALFMONTH)
switch (mult) {
case 1:
occurrenceString = I18N_NOOP2("Frequency of schedule", "Every half month");
break;
default:
occurrenceString = I18N_NOOP2("Frequency of schedule", QString("Every %1 half months").arg(mult));
}
else if (type == MyMoneySchedule::OCCUR_MONTHLY)
switch (mult) {
case 1:
occurrenceString = I18N_NOOP2("Frequency of schedule", "Monthly");
break;
case 2:
occurrenceString = I18N_NOOP2("Frequency of schedule", "Every two months");
break;
case 3:
occurrenceString = I18N_NOOP2("Frequency of schedule", "Every three months");
break;
case 4:
occurrenceString = I18N_NOOP2("Frequency of schedule", "Every four months");
break;
case 6:
occurrenceString = I18N_NOOP2("Frequency of schedule", "Twice yearly");
break;
default:
occurrenceString = I18N_NOOP2("Frequency of schedule", QString("Every %1 months").arg(mult));
}
else if (type == MyMoneySchedule::OCCUR_YEARLY)
switch (mult) {
case 1:
occurrenceString = I18N_NOOP2("Frequency of schedule", "Yearly");
break;
case 2:
occurrenceString = I18N_NOOP2("Frequency of schedule", "Every other year");
break;
default:
occurrenceString = I18N_NOOP2("Frequency of schedule", QString("Every %1 years").arg(mult));
}
return occurrenceString;
}
QString MyMoneySchedule::occurrencePeriodToString(MyMoneySchedule::occurrenceE type)
{
QString occurrenceString = I18N_NOOP2("Schedule occurrence period", "Any");
if (type == MyMoneySchedule::OCCUR_ONCE)
occurrenceString = I18N_NOOP2("Schedule occurrence period", "Once");
else if (type == MyMoneySchedule::OCCUR_DAILY)
occurrenceString = I18N_NOOP2("Schedule occurrence period", "Day");
else if (type == MyMoneySchedule::OCCUR_WEEKLY)
occurrenceString = I18N_NOOP2("Schedule occurrence period", "Week");
else if (type == MyMoneySchedule::OCCUR_EVERYHALFMONTH)
occurrenceString = I18N_NOOP2("Schedule occurrence period", "Half-month");
else if (type == MyMoneySchedule::OCCUR_MONTHLY)
occurrenceString = I18N_NOOP2("Schedule occurrence period", "Month");
else if (type == MyMoneySchedule::OCCUR_YEARLY)
occurrenceString = I18N_NOOP2("Schedule occurrence period", "Year");
return occurrenceString;
}
QString MyMoneySchedule::scheduleTypeToString(MyMoneySchedule::typeE type)
{
QString text;
switch (type) {
case MyMoneySchedule::TYPE_BILL:
text = I18N_NOOP2("Scheduled transaction type", "Bill");
break;
case MyMoneySchedule::TYPE_DEPOSIT:
text = I18N_NOOP2("Scheduled transaction type", "Deposit");
break;
case MyMoneySchedule::TYPE_TRANSFER:
text = I18N_NOOP2("Scheduled transaction type", "Transfer");
break;
case MyMoneySchedule::TYPE_LOANPAYMENT:
text = I18N_NOOP2("Scheduled transaction type", "Loan payment");
break;
case MyMoneySchedule::TYPE_ANY:
default:
text = I18N_NOOP2("Scheduled transaction type", "Unknown");
}
return text;
}
QString MyMoneySchedule::paymentMethodToString(MyMoneySchedule::paymentTypeE paymentType)
{
QString text;
switch (paymentType) {
case MyMoneySchedule::STYPE_DIRECTDEBIT:
text = I18N_NOOP2("Scheduled Transaction payment type", "Direct debit");
break;
case MyMoneySchedule::STYPE_DIRECTDEPOSIT:
text = I18N_NOOP2("Scheduled Transaction payment type", "Direct deposit");
break;
case MyMoneySchedule::STYPE_MANUALDEPOSIT:
text = I18N_NOOP2("Scheduled Transaction payment type", "Manual deposit");
break;
case MyMoneySchedule::STYPE_OTHER:
text = I18N_NOOP2("Scheduled Transaction payment type", "Other");
break;
case MyMoneySchedule::STYPE_WRITECHEQUE:
text = I18N_NOOP2("Scheduled Transaction payment type", "Write check");
break;
case MyMoneySchedule::STYPE_STANDINGORDER:
text = I18N_NOOP2("Scheduled Transaction payment type", "Standing order");
break;
case MyMoneySchedule::STYPE_BANKTRANSFER:
text = I18N_NOOP2("Scheduled Transaction payment type", "Bank transfer");
break;
case MyMoneySchedule::STYPE_ANY:
text = I18N_NOOP2("Scheduled Transaction payment type", "Any (Error)");
break;
}
return text;
}
QString MyMoneySchedule::weekendOptionToString(MyMoneySchedule::weekendOptionE weekendOption)
{
QString text;
switch (weekendOption) {
case MyMoneySchedule::MoveBefore:
text = I18N_NOOP("Change the date to the previous processing day");
break;
case MyMoneySchedule::MoveAfter:
text = I18N_NOOP("Change the date to the next processing day");
break;
case MyMoneySchedule::MoveNothing:
- text = I18N_NOOP("Do Nothing");
+ text = I18N_NOOP("Do not change the date");
break;
}
return text;
}
// until we don't have the means to store the value
// of the variation, we default to 10% in case this
// scheduled transaction is marked 'not fixed'.
//
// ipwizard 2009-04-18
int MyMoneySchedule::variation() const
{
int rc = 0;
if (!isFixed()) {
rc = 10;
#if 0
QString var = value("kmm-variation");
if (!var.isEmpty())
rc = var.toInt();
#endif
}
return rc;
}
void MyMoneySchedule::setVariation(int var)
{
Q_UNUSED(var)
#if 0
deletePair("kmm-variation");
if (var != 0)
setValue("kmm-variation", QString("%1").arg(var));
#endif
}
int MyMoneySchedule::eventsPerYear(MyMoneySchedule::occurrenceE occurrence)
{
int rc = 0;
switch (occurrence) {
case MyMoneySchedule::OCCUR_DAILY:
rc = 365;
break;
case MyMoneySchedule::OCCUR_WEEKLY:
rc = 52;
break;
case MyMoneySchedule::OCCUR_FORTNIGHTLY:
rc = 26;
break;
case MyMoneySchedule::OCCUR_EVERYOTHERWEEK:
rc = 26;
break;
case MyMoneySchedule::OCCUR_EVERYHALFMONTH:
rc = 24;
break;
case MyMoneySchedule::OCCUR_EVERYTHREEWEEKS:
rc = 17;
break;
case MyMoneySchedule::OCCUR_EVERYFOURWEEKS:
rc = 13;
break;
case MyMoneySchedule::OCCUR_MONTHLY:
case MyMoneySchedule::OCCUR_EVERYTHIRTYDAYS:
rc = 12;
break;
case MyMoneySchedule::OCCUR_EVERYEIGHTWEEKS:
rc = 6;
break;
case MyMoneySchedule::OCCUR_EVERYOTHERMONTH:
rc = 6;
break;
case MyMoneySchedule::OCCUR_EVERYTHREEMONTHS:
case MyMoneySchedule::OCCUR_QUARTERLY:
rc = 4;
break;
case MyMoneySchedule::OCCUR_EVERYFOURMONTHS:
rc = 3;
break;
case MyMoneySchedule::OCCUR_TWICEYEARLY:
rc = 2;
break;
case MyMoneySchedule::OCCUR_YEARLY:
rc = 1;
break;
default:
qWarning("Occurrence not supported by financial calculator");
}
return rc;
}
int MyMoneySchedule::daysBetweenEvents(MyMoneySchedule::occurrenceE occurrence)
{
int rc = 0;
switch (occurrence) {
case MyMoneySchedule::OCCUR_DAILY:
rc = 1;
break;
case MyMoneySchedule::OCCUR_WEEKLY:
rc = 7;
break;
case MyMoneySchedule::OCCUR_FORTNIGHTLY:
rc = 14;
break;
case MyMoneySchedule::OCCUR_EVERYOTHERWEEK:
rc = 14;
break;
case MyMoneySchedule::OCCUR_EVERYHALFMONTH:
rc = 15;
break;
case MyMoneySchedule::OCCUR_EVERYTHREEWEEKS:
rc = 21;
break;
case MyMoneySchedule::OCCUR_EVERYFOURWEEKS:
rc = 28;
break;
case MyMoneySchedule::OCCUR_EVERYTHIRTYDAYS:
rc = 30;
break;
case MyMoneySchedule::OCCUR_MONTHLY:
rc = 30;
break;
case MyMoneySchedule::OCCUR_EVERYEIGHTWEEKS:
rc = 56;
break;
case MyMoneySchedule::OCCUR_EVERYOTHERMONTH:
rc = 60;
break;
case MyMoneySchedule::OCCUR_EVERYTHREEMONTHS:
case MyMoneySchedule::OCCUR_QUARTERLY:
rc = 90;
break;
case MyMoneySchedule::OCCUR_EVERYFOURMONTHS:
rc = 120;
break;
case MyMoneySchedule::OCCUR_TWICEYEARLY:
rc = 180;
break;
case MyMoneySchedule::OCCUR_YEARLY:
rc = 360;
break;
default:
qWarning("Occurrence not supported by financial calculator");
}
return rc;
}
QDate MyMoneySchedule::addHalfMonths(QDate date, int mult) const
{
QDate newdate = date;
int d, dm;
if (mult > 0) {
d = newdate.day();
if (d <= 12) {
if (mult % 2 == 0)
newdate = newdate.addMonths(mult >> 1);
else
newdate = newdate.addMonths(mult >> 1).addDays(15);
} else
for (int i = 0; i < mult; i++) {
if (d <= 13)
newdate = newdate.addDays(15);
else {
dm = newdate.daysInMonth();
if (d == 14)
newdate = newdate.addDays((dm < 30) ? dm - d : 15);
else if (d == 15)
newdate = newdate.addDays(dm - d);
else if (d == dm)
newdate = newdate.addDays(15 - d).addMonths(1);
else
newdate = newdate.addDays(-15).addMonths(1);
}
d = newdate.day();
}
} else if (mult < 0) // Go backwards
for (int i = 0; i > mult; i--) {
d = newdate.day();
dm = newdate.daysInMonth();
if (d > 15) {
dm = newdate.daysInMonth();
newdate = newdate.addDays((d == dm) ? 15 - dm : -15);
} else if (d <= 13)
newdate = newdate.addMonths(-1).addDays(15);
else if (d == 15)
newdate = newdate.addDays(-15);
else { // 14
newdate = newdate.addMonths(-1);
dm = newdate.daysInMonth();
newdate = newdate.addDays((dm < 30) ? dm - d : 15);
}
}
return newdate;
}
/**
* Helper method to convert simple occurrence to compound occurrence + multiplier
*
* @param multiplier Returned by reference. Adjusted multiplier
* @param occurrence Returned by reference. Occurrence type
*/
void MyMoneySchedule::simpleToCompoundOccurrence(int& multiplier, occurrenceE& occurrence)
{
occurrenceE newOcc = occurrence;
int newMulti = 1;
if (occurrence == MyMoneySchedule::OCCUR_ONCE ||
occurrence == MyMoneySchedule::OCCUR_DAILY ||
occurrence == MyMoneySchedule::OCCUR_WEEKLY ||
occurrence == MyMoneySchedule::OCCUR_EVERYHALFMONTH ||
occurrence == MyMoneySchedule::OCCUR_MONTHLY ||
occurrence == MyMoneySchedule::OCCUR_YEARLY) { // Already a base occurrence and multiplier
} else if (occurrence == MyMoneySchedule::OCCUR_FORTNIGHTLY ||
occurrence == MyMoneySchedule::OCCUR_EVERYOTHERWEEK) {
newOcc = MyMoneySchedule::OCCUR_WEEKLY;
newMulti = 2;
} else if (occurrence == MyMoneySchedule::OCCUR_EVERYTHREEWEEKS) {
newOcc = MyMoneySchedule::OCCUR_WEEKLY;
newMulti = 3;
} else if (occurrence == MyMoneySchedule::OCCUR_EVERYFOURWEEKS) {
newOcc = MyMoneySchedule::OCCUR_WEEKLY;
newMulti = 4;
} else if (occurrence == MyMoneySchedule::OCCUR_EVERYTHIRTYDAYS) {
newOcc = MyMoneySchedule::OCCUR_DAILY;
newMulti = 30;
} else if (occurrence == MyMoneySchedule::OCCUR_EVERYEIGHTWEEKS) {
newOcc = MyMoneySchedule::OCCUR_WEEKLY;
newMulti = 8;
} else if (occurrence == MyMoneySchedule::OCCUR_EVERYOTHERMONTH) {
newOcc = MyMoneySchedule::OCCUR_MONTHLY;
newMulti = 2;
} else if (occurrence == MyMoneySchedule::OCCUR_EVERYTHREEMONTHS ||
occurrence == MyMoneySchedule::OCCUR_QUARTERLY) {
newOcc = MyMoneySchedule::OCCUR_MONTHLY;
newMulti = 3;
} else if (occurrence == MyMoneySchedule::OCCUR_EVERYFOURMONTHS) {
newOcc = MyMoneySchedule::OCCUR_MONTHLY;
newMulti = 4;
} else if (occurrence == MyMoneySchedule::OCCUR_TWICEYEARLY) {
newOcc = MyMoneySchedule::OCCUR_MONTHLY;
newMulti = 6;
} else if (occurrence == MyMoneySchedule::OCCUR_EVERYOTHERYEAR) {
newOcc = MyMoneySchedule::OCCUR_YEARLY;
newMulti = 2;
} else { // Unknown
newOcc = MyMoneySchedule::OCCUR_ANY;
newMulti = 1;
}
if (newOcc != occurrence) {
occurrence = newOcc;
multiplier = newMulti == 1 ? multiplier : newMulti * multiplier;
}
}
/**
* Helper method to convert compound occurrence + multiplier to simple occurrence
*
* @param multiplier Returned by reference. Adjusted multiplier
* @param occurrence Returned by reference. Occurrence type
*/
void MyMoneySchedule::compoundToSimpleOccurrence(int& multiplier, occurrenceE& occurrence)
{
occurrenceE newOcc = occurrence;
if (occurrence == MyMoneySchedule::OCCUR_ONCE) { // Nothing to do
} else if (occurrence == MyMoneySchedule::OCCUR_DAILY) {
switch (multiplier) {
case 1:
break;
case 30:
newOcc = MyMoneySchedule::OCCUR_EVERYTHIRTYDAYS;
break;
}
} else if (newOcc == MyMoneySchedule::OCCUR_WEEKLY) {
switch (multiplier) {
case 1:
break;
case 2:
newOcc = MyMoneySchedule::OCCUR_EVERYOTHERWEEK;
break;
case 3:
newOcc = MyMoneySchedule::OCCUR_EVERYTHREEWEEKS;
break;
case 4:
newOcc = MyMoneySchedule::OCCUR_EVERYFOURWEEKS;
break;
case 8:
newOcc = MyMoneySchedule::OCCUR_EVERYEIGHTWEEKS;
break;
}
} else if (occurrence == MyMoneySchedule::OCCUR_MONTHLY)
switch (multiplier) {
case 1:
break;
case 2:
newOcc = MyMoneySchedule::OCCUR_EVERYOTHERMONTH;
break;
case 3:
newOcc = MyMoneySchedule::OCCUR_EVERYTHREEMONTHS;
break;
case 4:
newOcc = MyMoneySchedule::OCCUR_EVERYFOURMONTHS;
break;
case 6:
newOcc = MyMoneySchedule::OCCUR_TWICEYEARLY;
break;
}
else if (occurrence == MyMoneySchedule::OCCUR_EVERYHALFMONTH)
switch (multiplier) {
case 1:
break;
}
else if (occurrence == MyMoneySchedule::OCCUR_YEARLY) {
switch (multiplier) {
case 1:
break;
case 2:
newOcc = MyMoneySchedule::OCCUR_EVERYOTHERYEAR;
break;
}
}
if (occurrence != newOcc) { // Changed to derived type
occurrence = newOcc;
multiplier = 1;
}
}
void MyMoneySchedule::setProcessingCalendar(IMyMoneyProcessingCalendar* pc)
{
processingCalendarPtr = pc;
}
bool MyMoneySchedule::isProcessingDate(const QDate& date) const
{
if (processingCalendarPtr)
return processingCalendarPtr->isProcessingDate(date);
return date.dayOfWeek() < Qt::Saturday;
}
IMyMoneyProcessingCalendar* MyMoneySchedule::processingCalendar() const
{
return processingCalendarPtr;
}
bool MyMoneySchedule::replaceId(const QString& newId, const QString& oldId)
{
return m_transaction.replaceId(newId, oldId);
}