1 /********************************************************************\
2  * gnc-import-price.hpp - import prices from csv files              *
3  *                                                                  *
4  * This program is free software; you can redistribute it and/or    *
5  * modify it under the terms of the GNU General Public License as   *
6  * published by the Free Software Foundation; either version 2 of   *
7  * the License, or (at your option) any later version.              *
8  *                                                                  *
9  * This program is distributed in the hope that it will be useful,  *
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of   *
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    *
12  * GNU General Public License for more details.                     *
13  *                                                                  *
14  * You should have received a copy of the GNU General Public License*
15  * along with this program; if not, contact:                        *
16  *                                                                  *
17  * Free Software Foundation           Voice:  +1-617-542-5942       *
18  * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652       *
19  * Boston, MA  02110-1301,  USA       gnu@gnu.org                   *
20 \********************************************************************/
21 
22 /** @file
23      @brief Class to import prices from CSV or fixed width files
24      *
25      gnc-import-price.hpp
26      @author Copyright (c) 2015 Geert Janssens <geert@kobaltwit.be>
27      @author Copyright (c) 2017 Robert Fewell
28  */
29 
30 #ifndef GNC_PRICE_IMPORT_HPP
31 #define GNC_PRICE_IMPORT_HPP
32 
33 extern "C" {
34 #include "config.h"
35 #include "gnc-commodity.h"
36 }
37 
38 #include <vector>
39 #include <set>
40 #include <map>
41 #include <memory>
42 
43 #include "gnc-tokenizer.hpp"
44 #include "gnc-imp-props-price.hpp"
45 #include "gnc-imp-settings-csv-price.hpp"
46 #include <boost/optional.hpp>
47 
48 /* A set of currency formats that the user sees. */
49 extern const int num_currency_formats_price;
50 extern const gchar* currency_format_user_price[];
51 
52 /** An enum describing the columns found in a parse_line_t. Currently these are:
53  *  - a tokenized line of input
54  *  - an optional error string
55  *  - a struct to hold user selected properties for a price
56  *  - a boolean to mark the line as skipped by error and/or user or not */
57 enum parse_line_cols {
58     PL_INPUT,
59     PL_ERROR,
60     PL_PREPRICE,
61     PL_SKIP
62 };
63 
64 /** Tuple to hold
65  *  - a tokenized line of input
66  *  - an optional error string
67  *  - a struct to hold user selected properties for a price */
68 using parse_line_t = std::tuple<StrVec,
69                                 std::string,
70                                 std::shared_ptr<GncImportPrice>,
71                                 bool>;
72 struct ErrorListPrice;
73 
74 /** The actual PriceImport class
75  * It's intended to use in the following sequence of actions:
76  * - set a file format
77  * - load a file
78  * - optionally convert it's encoding
79  * - parse the file into lines, which in turn are split up in to columns
80  *   the result of this step can be queried from tokenizer
81  * - the user should now map the columns to types, which is stored in column_types
82  * - last step is convert the mapped columns into a list of prices to add */
83 class GncPriceImport
84 {
85 public:
86     // Constructor - Destructor
87     GncPriceImport(GncImpFileFormat format = GncImpFileFormat::UNKNOWN);
88     ~GncPriceImport();
89 
90     void file_format(GncImpFileFormat format);
91     GncImpFileFormat file_format();
92 
93     void over_write (bool over);
94     bool over_write ();
95 
96     void from_commodity (gnc_commodity *from_commodity);
97     gnc_commodity *from_commodity ();
98 
99     void to_currency (gnc_commodity *to_currency);
100     gnc_commodity *to_currency ();
101 
102     void currency_format (int currency_format);
103     int currency_format ();
104 
105     void date_format (int date_format);
106     int date_format ();
107 
108     void encoding (const std::string& encoding);
109     std::string encoding ();
110 
111     void update_skipped_lines (boost::optional<uint32_t> start, boost::optional<uint32_t> end,
112                                boost::optional<bool> alt, boost::optional<bool> errors);
113     uint32_t skip_start_lines ();
114     uint32_t skip_end_lines ();
115     bool skip_alt_lines ();
116     bool skip_err_lines ();
117 
118     void separators (std::string separators);
119     std::string separators ();
120 
121     void settings (const CsvPriceImpSettings& settings);
122     bool save_settings ();
123 
124     void settings_name (std::string name);
125     std::string settings_name ();
126 
127 
128     void load_file (const std::string& filename);
129 
130     void tokenize (bool guessColTypes);
131 
132     std::string verify();
133 
134     /** This function will attempt to convert all tokenized lines into
135      *  prices using the column types the user has set.
136      */
137     void create_prices ();
138     bool check_for_column_type (GncPricePropType type);
139     void set_column_type_price (uint32_t position, GncPricePropType type, bool force = false);
140     std::vector<GncPricePropType> column_types_price ();
141 
142     std::unique_ptr<GncTokenizer> m_tokenizer;    /**< Will handle file loading/encoding conversion/splitting into fields */
143     std::vector<parse_line_t> m_parsed_lines;     /**< source file parsed into a two-dimensional array of strings.
144                                                      Per line also holds possible error messages and objects with extracted
145                                                      price properties. */
146     int  m_prices_added;
147     int  m_prices_duplicated;
148     int  m_prices_replaced;
149 
150 private:
151     /** A helper function used by create_prices. It will attempt
152      *  to convert a single tokenized line into a price using
153      *  the column types the user has set.
154      */
155     void create_price (std::vector<parse_line_t>::iterator& parsed_line);
156 
157     void verify_column_selections (ErrorListPrice& error_msg);
158 
159     /* Internal helper function to force reparsing of columns subject to format changes */
160     void reset_formatted_column (std::vector<GncPricePropType>& col_types);
161 
162     /* Two internal helper functions that should only be called from within
163      * set_column_type_price for consistency (otherwise error messages may not be (re)set)
164      */
165     void update_price_props (uint32_t row, uint32_t col, GncPricePropType prop_type);
166 
167     CsvPriceImpSettings m_settings;
168     bool m_skip_errors;
169     bool m_over_write;
170 };
171 
172 
173 #endif
174