1 #ident "Kalopa: $Id: acctview.c,v 1.16 2008/10/15 15:11:13 dtynan Exp $"
2
3 /*
4 * $Id: acctview.c,v 1.16 2008/10/15 15:11:13 dtynan Exp $
5 *
6 * Copyright (c) 2004, Kalopa Media Limited. All rights reserved.
7 * Copyright (c) 2005, Kalopa Research Limited. All rights reserved.
8 * This is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published
10 * by the Free Software Foundation; either version 2, or (at your
11 * option) any later version.
12 *
13 * It is distributed in the hope that it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
16 * License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this product; see the file COPYING. If not, write to
20 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139,
21 * USA.
22 *
23 * THIS SOFTWARE IS PROVIDED BY KALOPA RESEARCH LIMITED "AS IS" AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
25 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
26 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KALOPA
27 * RESEARCH LIMITED BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
30 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
32 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
34 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 *
36 * ABSTRACT
37 *
38 * $Log: acctview.c,v $
39 * Revision 1.16 2008/10/15 15:11:13 dtynan
40 * Mammoth change to convert from old-style database configuration to new
41 * schema where an RC file defines the database access.
42 *
43 * Revision 1.15 2008/10/13 20:59:38 dtynan
44 * Extensive changes (part 1) for change to database configuration.
45 *
46 * Revision 1.14 2008/01/15 18:10:43 dtynan
47 * Changed to use new company name and copyright, also fixed a few old
48 * files with the wrong license.
49 *
50 * Revision 1.13 2008/01/15 15:33:01 dtynan
51 * Extensive changes for new DBOW version (due out soon...)
52 *
53 * Revision 1.12 2007/10/29 17:24:34 dtynan
54 * Various tweaks and fixes.
55 *
56 * Revision 1.11 2006/07/31 10:17:51 dtynan
57 * Massive changeover to a more Ruby/Rails primary key naming convention.
58 *
59 * Revision 1.10 2005/03/22 09:41:23 dtynan
60 * Extensive upgrade to make sure the copyright block was
61 * consistent and GPL'ed.
62 *
63 * Revision 1.9 2005/03/08 16:38:59 dtynan
64 * Added the journal ID number to the report outputs.
65 *
66 * Revision 1.8 2005/02/17 17:25:27 dtynan
67 * Fixed some compiler warnings.
68 *
69 * Revision 1.7 2005/01/13 21:57:09 dtynan
70 * Use nominal account table from main database.
71 *
72 * Revision 1.6 2004/12/09 20:23:39 dtynan
73 * Cleaned up include mechanisms.
74 *
75 * Revision 1.5 2004/12/09 19:19:57 dtynan
76 * Added a folio field to the output data.
77 *
78 * Revision 1.4 2004/09/08 10:43:12 dtynan
79 * Fix a bug where 0.0 was shown as a negative balance and add a
80 * "Closing Balance" line to all accounts.
81 *
82 * Revision 1.3 2004/09/03 13:46:43 dtynan
83 * Created a text format for use without groff and made it the default.
84 *
85 * Revision 1.2 2004/08/26 17:15:35 dtynan
86 * New version will display the transactions for any account.
87 *
88 * Revision 1.1 2004/08/07 15:31:24 dtynan
89 * New program to produce a pro-forma bank statement.
90 */
91 #include <stdio.h>
92 #include <stdlib.h>
93 #include <unistd.h>
94 #include <string.h>
95 #include <time.h>
96 #include <math.h>
97
98 #include "beanie.h"
99
100 int verbose;
101 int troff;
102 int lineno;
103 char *title;
104 double bals[10000];
105 struct db_company *comp;
106
107 extern int optind, opterr;
108 extern char *optarg;
109
110 void acctview(struct db_nomacct *, int);
111 void heading(int, int);
112 void usage();
113
114 struct db_journal *findjournalentries(dbow_conn *);
115 struct db_journal_item *findjournalitems(dbow_conn *, int);
116 struct db_nomacct *findnomaccts(dbow_conn *);
117
118 char *month[12] = {
119 "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"
120 };
121
122 /*
123 *
124 */
125 int
main(int argc,char * argv[])126 main(int argc, char *argv[])
127 {
128 int i, aflag, year, acctno;
129 char *cname;
130 struct tm *tmp;
131 struct db_nomacct *np;
132 dbow_conn *dbp;
133 time_t now;
134
135 /*
136 * Process command-line options.
137 */
138 cname = NULL;
139 time(&now);
140 if ((tmp = localtime(&now)) != NULL)
141 year = tmp->tm_year;
142 else
143 year = 104;
144 opterr = verbose = aflag = troff = 0;
145 while ((i = getopt(argc, argv, "ac:y:vt")) != EOF) {
146 switch (i) {
147 case 'a':
148 /*
149 * Do all the accounts...
150 */
151 aflag = 1;
152 break;
153
154 case 'c':
155 cname = optarg;
156 break;
157
158 case 'y':
159 if ((i = atoi(optarg)) < 1990 || i > 2099) {
160 fprintf(stderr, "?Error - invalid year.\n");
161 exit(2);
162 }
163 year = i - 1900;
164 break;
165
166 case 't':
167 troff = 1;
168 break;
169
170 case 'v':
171 verbose = 1;
172 break;
173
174 default:
175 usage();
176 break;
177 }
178 }
179 if (!aflag && (argc - optind) != 1)
180 usage();
181 loadconfig(cname);
182 dbp = getdbase();
183 if ((comp = db_findcompanyfirst(dbp)) == NULL) {
184 fprintf(stderr, "?Error - cannot find specified company.\n");
185 exit(1);
186 }
187 if (!aflag) {
188 acctno = atoi(argv[optind]);
189 if ((np = db_findnomacctbyid(dbp, acctno)) == NULL) {
190 fprintf(stderr, "?Invalid nominal account number.\n");
191 exit(1);
192 }
193 acctview(np, year);
194 } else {
195 for (np = findnomaccts(dbp); np != NULL;
196 np = db_findnomacctnext(dbp, np)) {
197 heading(-1, -1);
198 acctview(np, year);
199 }
200 }
201 exit(0);
202 }
203
204 /*
205 *
206 */
207 void
acctview(struct db_nomacct * np,int year)208 acctview(struct db_nomacct *np, int year)
209 {
210 int sawflag = 0;
211 struct db_journal *jp;
212 struct db_journal_item *jip;
213 struct tm *tmp;
214 char tmpbal[20];
215 double tot;
216 dbow_conn *dbp = getdbase();
217
218 title = strdup(np->aname);
219 lineno = 0;
220 tot = 0.0;
221 for (jp = findjournalentries(dbp); jp != NULL;
222 jp = db_findjournalnext(dbp, jp)) {
223 if ((tmp = localtime((time_t *)&jp->jdate)) == NULL)
224 continue;
225 if (tmp->tm_year != year)
226 continue;
227 for (jip = findjournalitems(dbp, jp->id);
228 jip != NULL;
229 jip = db_findjournal_itemnext(dbp, jip)) {
230 if (jip->nomacct_id != np->id)
231 continue;
232 heading(0, year);
233 sawflag = 1;
234 if (troff) {
235 printf("%d-%s:", tmp->tm_mday,
236 month[tmp->tm_mon]);
237 if (jp->folio != NULL)
238 printf("%s", jp->folio);
239 printf(":%s:", jp->descr);
240 if (jip->drcrf) {
241 printf(":%.2f:", jip->amount);
242 tot += jip->amount;
243 } else {
244 printf("%.2f::", jip->amount);
245 tot -= jip->amount;
246 }
247 if (tot < 0.0)
248 printf("(%.2f)\n", -tot);
249 else
250 printf("%.2f\n", tot);
251 lineno++;
252 } else {
253 printf("|%2d-%s|%4d|", tmp->tm_mday,
254 month[tmp->tm_mon],
255 jp->id);
256 if (jp->folio != NULL)
257 printf("%4.4s|", jp->folio);
258 else
259 printf(" |");
260 printf("%-28.28s|", jp->descr);
261 if (jip->drcrf) {
262 printf(" |%9.2f|", jip->amount);
263 tot += jip->amount;
264 } else {
265 printf("%9.2f| |", jip->amount);
266 tot -= jip->amount;
267 }
268 if (tot < 0.0)
269 sprintf(tmpbal, "(%.2f)", -tot);
270 else
271 sprintf(tmpbal, "%.2f ", tot);
272 printf("%12s|\n", tmpbal);
273 }
274 }
275 }
276 if (!sawflag && tot == 0.0)
277 return;
278 heading(0, year);
279 if (troff) {
280 printf("::Balance Brought Forward:::");
281 if (tot < 0.0)
282 printf("(%.2f)\n", -tot);
283 else
284 printf("%.2f\n", tot);
285 lineno++;
286 } else {
287 printf("| | | |Balance Brought Forward | | |");
288 if (tot < 0.0)
289 sprintf(tmpbal, "(%.2f)", -tot);
290 else
291 sprintf(tmpbal, "%.2f ", tot);
292 printf("%12s|\n", tmpbal);
293 }
294 heading(-1, year);
295 putchar('\n');
296 }
297
298 /*
299 *
300 */
301 void
heading(int type,int year)302 heading(int type, int year)
303 {
304 static int htype = -1, pageno = 0;
305
306 if (year == -1) {
307 htype = -1;
308 return;
309 }
310 if (!troff) {
311 if (htype == -1) {
312 printf("%s for %s", title, comp->cname);
313 if (year != 0)
314 printf(" -- %d", year + 1900);
315 putchar('\n');
316 }
317 if (type == -1 || htype == -1) {
318 printf("+------+-------------------------------------");
319 printf("-+---------+---------+------------+\n");
320 }
321 htype = 0;
322 return;
323 }
324 if (type >= 0 && htype == -1) {
325 printf(".nr PS 12\n.nr VS 14\n.sp 2c\n");
326 htype = 0;
327 }
328 if (htype == type && lineno > 0 && lineno < 50) {
329 lineno++;
330 return;
331 }
332 if (lineno > 0)
333 printf(".TE\n");
334 if (type < 0)
335 return;
336 if (lineno > 0)
337 printf(".bp\n.sp 2.5c\n");
338 if (htype != type) {
339 lineno = pageno = 0;
340 htype = type;
341 }
342 printf("%s for %s", title, comp->cname);
343 printf(" (Page %d)\n.sp\n.TS\n", ++pageno);
344 switch (type) {
345 case 0:
346 printf("center box tab(:);\nc | c | c | c | c\n");
347 printf("ri | lw4ib | r | r | r.\n");
348 printf("Date:Details:Debit:Credit:Balance\n_\n");
349 break;
350 }
351 lineno = 1;
352 }
353
354 /*
355 *
356 */
357 void
usage()358 usage()
359 {
360 fprintf(stderr, "Usage: acctview [-a][-v][-c <comp>] [-y year] [acctno]\n");
361 exit(2);
362 }
363