1 /***************************************************************************
2                           mymoneyqifreader.h  -  description
3                              -------------------
4     begin                : Mon Jan 27 2003
5     copyright            : (C) 2000-2003 by Michael Edwardes
6     email                : mte@users.sourceforge.net
7                            Javier Campos Morales <javi_c@users.sourceforge.net>
8                            Felix Rodriguez <frodriguez@users.sourceforge.net>
9                            John C <thetacoturtle@users.sourceforge.net>
10                            Thomas Baumgart <ipwizard@users.sourceforge.net>
11                            Kevin Tambascio <ktambascio@users.sourceforge.net>
12  ***************************************************************************/
13 
14 /***************************************************************************
15  *                                                                         *
16  *   This program is free software; you can redistribute it and/or modify  *
17  *   it under the terms of the GNU General Public License as published by  *
18  *   the Free Software Foundation; either version 2 of the License, or     *
19  *   (at your option) any later version.                                   *
20  *                                                                         *
21  ***************************************************************************/
22 
23 #ifndef MYMONEYQIFREADER_H
24 #define MYMONEYQIFREADER_H
25 
26 // ----------------------------------------------------------------------------
27 // QT Headers
28 
29 #include <QList>
30 #include <QObject>
31 #include <QString>
32 #include <QStringList>
33 #include <QByteArray>
34 #include <QUrl>
35 #include <QFile>
36 #include <QProcess>
37 
38 // ----------------------------------------------------------------------------
39 // KDE Headers
40 
41 // ----------------------------------------------------------------------------
42 // Project Headers
43 
44 #include "mymoneyaccount.h"
45 #include "mymoneytransaction.h"
46 #include "mymoneyenums.h"
47 #include "../config/mymoneyqifprofile.h"
48 
49 class MyMoneyFileTransaction;
50 class MyMoneyStatement;
51 class MyMoneyQifProfile;
52 
53 /**
54   * @author Thomas Baumgart
55   */
56 class MyMoneyQifReader : public QObject
57 {
58   Q_OBJECT
59   friend class Private;
60 
61 private:
62   typedef enum {
63     EntryUnknown = 0,
64     EntryAccount,
65     EntryTransaction,
66     EntryCategory,
67     EntryMemorizedTransaction,
68     EntryInvestmentTransaction,
69     EntrySecurity,
70     EntryPrice,
71     EntryPayee,
72     EntryClass,
73     EntrySkip
74   } QifEntryTypeE;
75 
76   struct qSplit {
77     QString      m_strCategoryName;
78     QString      m_strMemo;
79     QString      m_amount;
80   };
81 
82 public:
83   MyMoneyQifReader();
84   ~MyMoneyQifReader();
85 
86   /**
87     * This method is used to store the filename into the object.
88     * The file should exist. If it does and an external filter
89     * program is specified with the current selected profile,
90     * the file is send through this filter and the result
91     * is stored in the m_tempFile file.
92     *
93     * @param url URL of the file to be imported
94     */
95   void setURL(const QUrl &url);
96 
97   /**
98     * This method is used to store the name of the profile into the object.
99     * The selected profile will be loaded if it exists. If an external
100     * filter program is specified with the current selected profile,
101     * the file is send through this filter and the result
102     * is stored in the m_tempFile file.
103     *
104     * @param name QString reference to the name of the profile
105     */
106   void setProfile(const QString& name);
107 
108   /**
109     * This method actually starts the import of data from the selected file
110     * into the MyMoney engine.
111     *
112     * This method also starts the user defined import filter program
113     * defined in the QIF profile. If none is defined, the file is read
114     * as is (actually the UNIX command 'cat -' is used as the filter).
115     *
116     * If data from the filter program is available, the slot
117     * slotReceivedDataFromFilter() will be called.
118     *
119     * Make sure to connect the signal importFinished() to detect when
120     * the import actually ended. Call the method finishImport() to clean
121     * things up and get the overall result of the import.
122     *
123     * @retval true the import was started successfully
124     * @retval false the import could not be started.
125     */
126   bool startImport();
127 
128   void setCategoryMapping(bool map);
129 
account()130   inline const MyMoneyAccount& account() const {
131     return m_account;
132   };
133 
134   int statementCount() const;
135 
136   void setProgressCallback(void(*callback)(qint64, qint64, const QString&));
137 
138 private:
139   /**
140     * This method is used to update the progress information. It
141     * checks if an appropriate function is known and calls it.
142     *
143     * For a parameter description see KMyMoneyView::progressCallback().
144     */
145   void signalProgress(qint64 current, qint64 total, const QString& = "");
146 
147   /**
148     * This method scans a transaction contained in
149     * a QIF file formatted as an account record. This
150     * format is used by MS-Money. If the specific data
151     * is not found, then the data in the entry is treated
152     * as a transaction. In this case, the user will be asked to
153     * specify the account to which the transactions should be imported.
154     * The entry data is found in m_qifEntry.
155     *
156     * @param accountType see MyMoneyAccount() for details. Defaults to eMyMoney::Account::Type::Checkings
157     */
158   void processMSAccountEntry(const eMyMoney::Account::Type accountType = eMyMoney::Account::Type::Checkings);
159 
160   /**
161    * This method scans the m_qifEntry object as a payee record specified by Quicken
162    */
163   void processPayeeEntry();
164 
165   /**
166     * This method scans the m_qifEntry object as an account record specified
167     * by Quicken. In case @p resetAccountId is @p true (the default), the
168     * global account id will be reset.
169     *
170     * The id of the account will be returned.
171     */
172   const QString processAccountEntry(bool resetAccountId = true);
173 
174   /**
175     * This method scans the m_qifEntry object as a category record specified
176     * by Quicken.
177     */
178   void processCategoryEntry();
179 
180   /**
181     * This method scans the m_qifEntry object as a transaction record specified
182     * by Quicken.
183     */
184   void processTransactionEntry();
185 
186   /**
187     * This method scans the m_qifEntry object as an investment transaction
188     * record specified by Quicken.
189     */
190   void processInvestmentTransactionEntry();
191 
192   /**
193     * This method scans the m_qifEntry object as a price record specified
194     * by Quicken.
195     */
196   void processPriceEntry();
197 
198   /**
199     * This method scans the m_qifEntry object as a security record specified
200     * by Quicken.
201     */
202   void processSecurityEntry();
203 
204   /**
205     * This method processes the lines previously collected in
206     * the member variable m_qifEntry. If further information
207     * by the user is required to process the entry it will
208     * be collected.
209     */
210   void processQifEntry();
211 
212   /**
213    * This method process a line starting with an exclamation mark
214    */
215   void processQifSpecial(const QString& _line);
216 
217   /**
218     * This method extracts the line beginning with the letter @p id
219     * from the lines contained in the QStringList object @p m_qifEntry.
220     * An empty QString is returned, if the line is not found.
221     *
222     * @param id QChar containing the letter to be found
223     * @param cnt return cnt'th of occurrence of id in lines. cnt defaults to 1.
224     *
225     * @return QString with the remainder of the line or empty if
226     *         @p id is not found in @p lines
227     */
228   const QString extractLine(const QChar& id, int cnt = 1);
229 
230   /**
231     * This method examines each line in the QStringList object @p m_qifEntry,
232     * searching for split entries, which it extracts into a struct qSplit and
233     * stores all splits found in @p listqSplits .
234     */
235   bool extractSplits(QList<qSplit>& listqSplits) const;
236 
237   enum SelectCreateMode {
238     Create = 0,
239     Select
240   };
241 
242   /**
243     * This method looks up the @p searchname account by name and returns its id
244     * if it was found.  If it was not found, it creates a new income account using
245     * @p searchname as a name, and returns the id if the newly created account
246     *
247     * @param searchname The name of the account to find or create
248     * @return QString id of the found or created account
249     */
250   static const QString findOrCreateIncomeAccount(const QString& searchname);
251 
252   /**
253     * This method looks up the @p searchname account by name and returns its id
254     * if it was found.  If it was not found, it creates a new expense account using
255     * @p searchname as a name, and returns the id if the newly created account
256     *
257     * @param searchname The name of the account to find or create
258     * @return QString id of the found or created account
259     */
260   static const QString findOrCreateExpenseAccount(const QString& searchname);
261 
262   /**
263    * This methods returns the account from the list of accounts identified by
264    * an account id or account name including an account hierarchy.
265    *
266    * The parent account specifies from which account the search should be started.
267    * In case the parent account does not have an id, the method scans all top-level accounts.
268    *
269    * If the account is not found in the list of accounts, MyMoneyAccount() is returned.
270    *
271    * @param acc account to find
272    * @param parent parent account to search from
273    * @retval found MyMoneyAccount account instance
274    * @retval MyMoneyAccount() if not found
275    */
276   MyMoneyAccount findAccount(const MyMoneyAccount& acc, const MyMoneyAccount& parent) const;
277 
278   /**
279    * This method returns the account id for a given account @a name. In
280    * case @a name references an investment account and @a useBrokerage is @a true
281    * (the default), the id of the corresponding brokerage account will be
282    * returned. In case an account does not exist, it will be created.
283    */
284   const QString transferAccount(const QString& name, bool useBrokerage = true);
285 
286   // void processQifLine();
287   void createOpeningBalance(eMyMoney::Account::Type accType = eMyMoney::Account::Type::Checkings);
288 
289 Q_SIGNALS:
290   void statementsReady(const QList<MyMoneyStatement> &);
291 
292 private Q_SLOTS:
293   void slotSendDataToFilter();
294   void slotReceivedDataFromFilter();
295   void slotReceivedErrorFromFilter();
296   void slotProcessData();
297 
298   /**
299     * This slot is used to be informed about the end of the filtering process.
300     * It emits the signal importFinished()
301     */
302   void slotImportFinished();
303 
304 
305 private:
306 
307   void parseReceivedData(const QByteArray& data);
308 
309 
310   /// \internal d-pointer class.
311   class Private;
312   /// \internal d-pointer instance.
313   Private* const d;
314 
315   QProcess                m_filter;
316   QString                 m_filename;
317   QUrl                    m_url;
318   MyMoneyQifProfile       m_qifProfile;
319   MyMoneyAccount          m_account;
320   unsigned long           m_transactionsSkipped;
321   unsigned long           m_transactionsProcessed;
322   QStringList             m_dontAskAgain;
323   QMap<QString, QString>  m_accountTranslation;
324   QMap<QString, QString>  m_investmentMap;
325   QFile                   *m_file;
326   char                    m_buffer[1024];
327   QByteArray              m_lineBuffer;
328   QStringList             m_qifEntry;
329   int                     m_extractedLine;
330   QString                 m_qifLine;
331   QStringList             m_qifLines;
332   QifEntryTypeE           m_entryType;
333   bool                    m_skipAccount;
334   bool                    m_processingData;
335   bool                    m_userAbort;
336   bool                    m_autoCreatePayee;
337   unsigned long           m_pos;
338   unsigned                m_linenumber;
339   bool                    m_warnedInvestment;
340   bool                    m_warnedSecurity;
341   bool                    m_warnedPrice;
342   QList<MyMoneyTransaction> m_transactionCache;
343 
344   QList<QByteArray>  m_data;
345 
346   void (*m_progressCallback)(qint64, qint64, const QString&);
347 
348   MyMoneyFileTransaction* m_ft;
349 };
350 
351 #endif
352