1 /*
2 * Copyright (c) 2003-2018, John Wiegley. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 * - Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * - Neither the name of New Artisans LLC nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <system.hh>
33
34 #include "convert.h"
35 #include "csv.h"
36 #include "scope.h"
37 #include "iterators.h"
38 #include "report.h"
39 #include "xact.h"
40 #include "print.h"
41 #include "lookup.h"
42
43 namespace ledger {
44
convert_command(call_scope_t & args)45 value_t convert_command(call_scope_t& args)
46 {
47 report_t& report(args.context<report_t>());
48 journal_t& journal(*report.session.journal.get());
49
50 string bucket_name;
51 if (report.HANDLED(account_))
52 bucket_name = report.HANDLER(account_).str();
53 else
54 bucket_name = _("Equity:Unknown");
55
56 account_t * bucket = journal.master->find_account(bucket_name);
57 account_t * unknown = journal.master->find_account(_("Expenses:Unknown"));
58
59 // Create a flat list
60 xacts_list current_xacts(journal.xacts_begin(), journal.xacts_end());
61
62 // Read in the series of transactions from the CSV file
63
64 print_xacts formatter(report);
65 path csv_file_path(args.get<string>(0));
66
67 report.session.parsing_context.push(csv_file_path);
68 parse_context_t& context(report.session.parsing_context.get_current());
69 context.journal = &journal;
70 context.master = bucket;
71
72 csv_reader reader(context);
73
74 try {
75 while (xact_t * xact = reader.read_xact(report.HANDLED(rich_data))) {
76 if (report.HANDLED(invert)) {
77 foreach (post_t * post, xact->posts)
78 post->amount.in_place_negate();
79 }
80
81 string ref = (xact->has_tag(_("UUID")) ?
82 xact->get_tag(_("UUID"))->to_string() :
83 sha1sum(reader.get_last_line()));
84
85 checksum_map_t::const_iterator entry = journal.checksum_map.find(ref);
86 if (entry != journal.checksum_map.end()) {
87 INFO(file_context(reader.get_pathname(),
88 reader.get_linenum())
89 << " " << "Ignoring known UUID " << ref);
90 checked_delete(xact); // ignore it
91 continue;
92 }
93
94 if (report.HANDLED(rich_data) && ! xact->has_tag(_("UUID")))
95 xact->set_tag(_("UUID"), string_value(ref));
96
97 if (xact->posts.front()->account == NULL) {
98 if (account_t * acct =
99 (report.HANDLED(auto_match) ?
100 lookup_probable_account(xact->payee, current_xacts.rbegin(),
101 current_xacts.rend(), bucket).second :
102 NULL))
103 xact->posts.front()->account = acct;
104 else
105 xact->posts.front()->account = unknown;
106 }
107
108 if (! journal.add_xact(xact)) {
109 checked_delete(xact);
110 throw_(std::runtime_error,
111 _("Failed to finalize derived transaction (check commodities)"));
112 }
113 else {
114 xact_posts_iterator xact_iter(*xact);
115 while (post_t * post = *xact_iter++)
116 formatter(*post);
117 }
118 }
119 formatter.flush();
120 }
121 catch (const std::exception&) {
122 add_error_context(_f("While parsing file %1%")
123 % file_context(reader.get_pathname(),
124 reader.get_linenum()));
125 add_error_context(_("While parsing CSV line:"));
126 add_error_context(line_context(reader.get_last_line()));
127 throw;
128 }
129
130 // If not, transform the payee according to regexps
131
132 // Set the account to a default vaule, then transform the account according
133 // to the payee
134
135 // Print out the final form of the transaction
136
137 return true;
138 }
139
140 } // namespace ledger
141