Project

General

Profile

Statistics
| Branch: | Tag: | Revision:

aqbanking / src / libs / plugins / imexporters / q43 / q43.c @ 5bc3f3e7

History | View | Annotate | Download (10.4 KB)

1
/***************************************************************************
2
    begin       : Mon May 03 2010
3
    copyright   : (C) 2018 by Martin Preuss
4
    email       : martin@libchipcard.de
5

6
 ***************************************************************************
7
 *          Please see toplevel file COPYING for license details           *
8
 ***************************************************************************/
9

    
10
#ifdef HAVE_CONFIG_H
11
# include <config.h>
12
#endif
13

    
14

    
15
#include "q43_p.h"
16

    
17

    
18
#include "i18n_l.h"
19
#include <aqbanking/banking.h>
20
#include <gwenhywfar/debug.h>
21
#include <gwenhywfar/misc.h>
22
#include <gwenhywfar/gui.h>
23
#include <gwenhywfar/inherit.h>
24
#include <gwenhywfar/gwendate.h>
25
#include <gwenhywfar/gwentime.h>
26
#include <gwenhywfar/text.h>
27

    
28
#include <ctype.h>
29

    
30
#define YEAR_2000_CUTOFF 80
31

    
32

    
33

    
34
GWEN_INHERIT(AB_IMEXPORTER, AH_IMEXPORTER_Q43);
35

    
36

    
37

    
38
AB_IMEXPORTER *AB_ImExporterQ43_new(AB_BANKING *ab){
39
  AB_IMEXPORTER *ie;
40
  AH_IMEXPORTER_Q43 *ieh;
41

    
42
  ie=AB_ImExporter_new(ab, "q43");
43
  GWEN_NEW_OBJECT(AH_IMEXPORTER_Q43, ieh);
44
  GWEN_INHERIT_SETDATA(AB_IMEXPORTER, AH_IMEXPORTER_Q43, ie, ieh,
45
                       AH_ImExporterQ43_FreeData);
46

    
47
  AB_ImExporter_SetImportFn(ie, AH_ImExporterQ43_Import);
48
  AB_ImExporter_SetExportFn(ie, AH_ImExporterQ43_Export);
49
  AB_ImExporter_SetCheckFileFn(ie, AH_ImExporterQ43_CheckFile);
50
  return ie;
51
}
52

    
53

    
54

    
55
void GWENHYWFAR_CB AH_ImExporterQ43_FreeData(void *bp, void *p){
56
  AH_IMEXPORTER_Q43 *ieh;
57

    
58
  ieh=(AH_IMEXPORTER_Q43*)p;
59
  GWEN_FREE_OBJECT(ieh);
60
}
61

    
62

    
63

    
64
/* this needs to be replaced later by a more generic approach */
65
const char *AH_ImExporterQ43_GetCurrencyCode(int code) {
66
  switch(code) {
67
  case 978: return "EUR"; break;
68
  default:
69
    break;
70
  }
71

    
72
  return NULL;
73
}
74

    
75

    
76

    
77
int AH_ImExporterQ43_ReadInt(const char *p, int len) {
78
  int res=0;
79
  int i;
80

    
81
  for (i=0; i<len; i++) {
82
    char c;
83

    
84
    c=*(p++);
85
    if (!isdigit(c))
86
      return res;
87
    res*=10;
88
    res+=c-'0';
89
  }
90

    
91
  return res;
92
}
93

    
94

    
95

    
96
int AH_ImExporterQ43_ReadDocument(AB_IMEXPORTER *ie,
97
                                  AB_IMEXPORTER_CONTEXT *ctx,
98
                                  GWEN_FAST_BUFFER *fb,
99
                                  GWEN_DB_NODE *params){
100
  AB_IMEXPORTER_ACCOUNTINFO *iea=NULL;
101
  AB_IMEXPORTER_ACCOUNTINFO_LIST *ieaList;
102
  AB_TRANSACTION *t=NULL;
103
  GWEN_DATE *date=NULL;
104
  GWEN_BUFFER *lbuf;
105
  const char *currency=NULL;
106
  int rv;
107
  int hadSome=0;
108
  int records=0;
109

    
110
  ieaList=AB_ImExporterContext_GetAccountInfoList(ctx);
111
  assert(ieaList);
112

    
113
  lbuf=GWEN_Buffer_new(0, 256, 0, 1);
114

    
115
  do {
116
    rv=GWEN_FastBuffer_ReadLineToBuffer(fb, lbuf);
117
    if (rv==0) {
118
      int code;
119
      char *p;
120
      int size;
121

    
122
      size=GWEN_Buffer_GetUsedBytes(lbuf);
123
      if (size<2) {
124
        DBG_ERROR(AQBANKING_LOGDOMAIN,
125
                  "Line too short (%d bytes)",
126
                  GWEN_Buffer_GetUsedBytes(lbuf));
127
        AB_Transaction_free(t);
128
        GWEN_Date_free(date);
129
        GWEN_Buffer_free(lbuf);
130
        return GWEN_ERROR_BAD_DATA;
131
      }
132
      p=GWEN_Buffer_GetStart(lbuf);
133
      code=((p[0]-'0')*10)+(p[1]-'0');
134
      DBG_INFO(AQBANKING_LOGDOMAIN, "Got record %02d", code);
135

    
136
      switch(code) {
137
      case 0: { /* file header */
138
        int y, m, d;
139

    
140
        if (size<12) {
141
          DBG_ERROR(AQBANKING_LOGDOMAIN,
142
                    "Record %02d too short (%d bytes)",
143
                    code, GWEN_Buffer_GetUsedBytes(lbuf));
144
          AB_Transaction_free(t);
145
          GWEN_Date_free(date);
146
          GWEN_Buffer_free(lbuf);
147
          return GWEN_ERROR_BAD_DATA;
148
        }
149

    
150
        /* extract date */
151
        y=((p[6] -'0')*10)+(p[7] -'0');
152
        m=((p[8] -'0')*10)+(p[9] -'0');
153
        d=((p[10]-'0')*10)+(p[11]-'0');
154
        if (y>YEAR_2000_CUTOFF)
155
          y+=1900;
156
        else
157
          y+=2000;
158
        GWEN_Date_free(date);
159
        date=GWEN_Date_fromGregorian(y, m, d);
160
        if (date==NULL) {
161
          DBG_ERROR(AQBANKING_LOGDOMAIN, "Invalid date in record %02d", code);
162
          AB_Transaction_free(t);
163
          GWEN_Date_free(date);
164
          GWEN_Buffer_free(lbuf);
165
          return GWEN_ERROR_BAD_DATA;
166
        }
167
        break;
168
      }
169

    
170
      case 11: { /* account header */
171
        char bankCode[9];
172
        char accountNumber[11];
173
        int cy;
174

    
175
        if (size<80) {
176
          DBG_ERROR(AQBANKING_LOGDOMAIN,
177
                    "Record %02d too short (%d bytes)",
178
                    code, GWEN_Buffer_GetUsedBytes(lbuf));
179
          AB_Transaction_free(t);
180
          GWEN_Date_free(date);
181
          GWEN_Buffer_free(lbuf);
182
          return GWEN_ERROR_BAD_DATA;
183
        }
184

    
185
        /* get bankcode (combine bank code key and office branch code */
186
        strncpy(bankCode, p+2, 8);
187
        bankCode[8]=0;
188

    
189
        /* get account number */
190
        strncpy(accountNumber, p+10, 10);
191
        accountNumber[10]=0;
192

    
193
        /* get account info (or create it if necessary) */
194
        iea=AB_ImExporterAccountInfo_List_GetByBankCodeAndAccountNumber(ieaList, bankCode, accountNumber, AB_AccountType_Unknown);
195
        if (iea==NULL) {
196
          iea=AB_ImExporterAccountInfo_new();
197
          AB_ImExporterAccountInfo_SetBankCode(iea, bankCode);
198
          AB_ImExporterAccountInfo_SetAccountNumber(iea, accountNumber);
199
          AB_ImExporterContext_AddAccountInfo(ctx, iea);
200
        }
201

    
202
        cy=((p[47]-'0')*100)+((p[48]-'0')*10)+(p[49]-'0');
203
        currency=AH_ImExporterQ43_GetCurrencyCode(cy);
204
        if (!currency) {
205
          DBG_WARN(AQBANKING_LOGDOMAIN, "Unknown currency code %d, ignoring", cy);
206
        }
207

    
208
        /* TODO: read initial balance */
209
        hadSome++;
210
        break;
211
      }
212

    
213
      case 22: {
214
        GWEN_DATE *da;
215
        AB_VALUE *v;
216
        int y, m, d;
217
        char amount[32];
218
        const char *s;
219

    
220
        if (size<80) {
221
          DBG_ERROR(AQBANKING_LOGDOMAIN,
222
                    "Record %02d too short (%d bytes)",
223
                    code, GWEN_Buffer_GetUsedBytes(lbuf));
224
          AB_Transaction_free(t);
225
          GWEN_Date_free(date);
226
          GWEN_Buffer_free(lbuf);
227
          return GWEN_ERROR_BAD_DATA;
228
        }
229

    
230
        if (iea==NULL) {
231
          DBG_ERROR(AQBANKING_LOGDOMAIN, "Bad order of records (22 before 11)");
232
          AB_Transaction_free(t);
233
          GWEN_Date_free(date);
234
          GWEN_Buffer_free(lbuf);
235
          return GWEN_ERROR_BAD_DATA;
236
        }
237

    
238
        if (t)
239
          AB_ImExporterAccountInfo_AddTransaction(iea, t);
240
        t=AB_Transaction_new();
241

    
242
        /* extract booking date */
243
        y=((p[10]-'0')*10)+(p[11]-'0');
244
        m=((p[12]-'0')*10)+(p[13]-'0');
245
        d=((p[14]-'0')*10)+(p[15]-'0');
246
        if (y>YEAR_2000_CUTOFF)
247
          y+=1900;
248
        else
249
          y+=2000;
250
        da=GWEN_Date_fromGregorian(y, m, d);
251
        if (da==NULL) {
252
          DBG_WARN(AQBANKING_LOGDOMAIN, "Invalid booking date in record %02d, ignoring", code);
253
        }
254
        else {
255
          AB_Transaction_SetDate(t, da);
256
          GWEN_Date_free(da);
257
        }
258

    
259
        /* extract valuta date */
260
        y=((p[16]-'0')*10)+(p[17]-'0');
261
        m=((p[18]-'0')*10)+(p[18]-'0');
262
        d=((p[19]-'0')*10)+(p[20]-'0');
263
        if (y>YEAR_2000_CUTOFF)
264
          y+=1900;
265
        else
266
          y+=2000;
267
        da=GWEN_Date_fromGregorian(y, m, d);
268
        if (da==NULL) {
269
          DBG_WARN(AQBANKING_LOGDOMAIN, "Invalid valuta date in record %02d, ignoring", code);
270
        }
271
        else {
272
          AB_Transaction_SetValutaDate(t, da);
273
          GWEN_Date_free(da);
274
        }
275

    
276
        /* get amount */
277
        strncpy(amount, p+28, 14);
278
        amount[14]=0;
279
        strncat(amount, "/100:", sizeof(amount)-strlen(amount)-1);
280
        if (currency)
281
          strncat(amount, currency, sizeof(amount)-strlen(amount)-1);
282
        amount[sizeof(amount)-1]=0;
283
        v=AB_Value_fromString(amount);
284
        if (v==NULL) {
285
          DBG_ERROR(AQBANKING_LOGDOMAIN, "Invalid amount in transaction");
286
          AB_Transaction_free(t);
287
          GWEN_Date_free(date);
288
          GWEN_Buffer_free(lbuf);
289
          return GWEN_ERROR_BAD_DATA;
290
        }
291
        else {
292
          if (p[27]=='1')
293
            /* FIXME: Do we have to negate on "1" or "2"? */
294
            AB_Value_Negate(v);
295
          AB_Transaction_SetValue(t, v);
296
          AB_Value_free(v);
297
        }
298

    
299
        /* copy local account info */
300
        s=AB_ImExporterAccountInfo_GetAccountNumber(iea);
301
        AB_Transaction_SetLocalAccountNumber(t, s);
302
        s=AB_ImExporterAccountInfo_GetBankCode(iea);
303
        AB_Transaction_SetLocalBankCode(t, s);
304
        break;
305
      }
306

    
307
      case 23: { /* transaction comments */
308
        GWEN_BUFFER *tbuf;
309

    
310
        if (size<80) {
311
          DBG_ERROR(AQBANKING_LOGDOMAIN,
312
                    "Record %02d too short (%d bytes)",
313
                    code, GWEN_Buffer_GetUsedBytes(lbuf));
314
          AB_Transaction_free(t);
315
          GWEN_Date_free(date);
316
          GWEN_Buffer_free(lbuf);
317
          return GWEN_ERROR_BAD_DATA;
318
        }
319

    
320
        if (t==NULL) {
321
          DBG_ERROR(AQBANKING_LOGDOMAIN, "Bad order of records (23 before 22)");
322
          AB_Transaction_free(t);
323
          GWEN_Date_free(date);
324
          GWEN_Buffer_free(lbuf);
325
          return GWEN_ERROR_BAD_DATA;
326
        }
327

    
328
        tbuf=GWEN_Buffer_new(0, 256, 0, 1);
329
        /* comment 1 */
330
        GWEN_Buffer_AppendBytes(tbuf, p+4, 38);
331
        GWEN_Text_CondenseBuffer(tbuf);
332
        if (GWEN_Buffer_GetUsedBytes(tbuf))
333
          AB_Transaction_AddPurposeLine(t, GWEN_Buffer_GetStart(tbuf));
334
        GWEN_Buffer_Reset(tbuf);
335

    
336
        /* comment 2 */
337
        GWEN_Buffer_AppendBytes(tbuf, p+42, 38);
338
        GWEN_Text_CondenseBuffer(tbuf);
339
        if (GWEN_Buffer_GetUsedBytes(tbuf))
340
          AB_Transaction_AddPurposeLine(t, GWEN_Buffer_GetStart(tbuf));
341
        GWEN_Buffer_free(tbuf);
342
        break;
343
      }
344

    
345
      case 33: { /* end of accunt record */
346
        /* store current transaction if any */
347
        if (t) {
348
          AB_ImExporterAccountInfo_AddTransaction(iea, t);
349
          t=NULL;
350
        }
351

    
352
        // TODO: check the control fields here, read final account balance
353
        break;
354
      }
355

    
356
      case 88: {
357
        int numrecs;
358

    
359
        numrecs=AH_ImExporterQ43_ReadInt(p+20, 6);
360
        if (numrecs!=records) {
361
          DBG_ERROR(AQBANKING_LOGDOMAIN,
362
                    "Number of records doesn't match (%d != %d)",
363
                    numrecs, records);
364
          AB_Transaction_free(t);
365
          GWEN_Date_free(date);
366
          GWEN_Buffer_free(lbuf);
367
          return GWEN_ERROR_BAD_DATA;
368
        }
369
        break;
370
      }
371

    
372
      default:
373
        DBG_WARN(AQBANKING_LOGDOMAIN, "Ignoring line with code %02d", code);
374
      }
375

    
376
      GWEN_Buffer_Reset(lbuf);
377
      if (code!=0)
378
        records++;
379
    }
380
  } while (rv>=0);
381

    
382
  if (rv==GWEN_ERROR_EOF && hadSome)
383
    /* ignore EOF when we received some data */
384
    rv=0;
385

    
386
  if (t) {
387
    DBG_WARN(AQBANKING_LOGDOMAIN, "There is still a transaction open...");
388
    AB_Transaction_free(t);
389
  }
390

    
391
  /* done */
392
  GWEN_Date_free(date);
393
  GWEN_Buffer_free(lbuf);
394

    
395
  return rv;
396
}
397

    
398

    
399

    
400
int AH_ImExporterQ43_Import(AB_IMEXPORTER *ie,
401
                            AB_IMEXPORTER_CONTEXT *ctx,
402
                            GWEN_SYNCIO *sio,
403
                            GWEN_DB_NODE *params){
404
  AH_IMEXPORTER_Q43 *ieh;
405
  GWEN_FAST_BUFFER *fb;
406
  int rv;
407

    
408
  assert(ie);
409
  ieh=GWEN_INHERIT_GETDATA(AB_IMEXPORTER, AH_IMEXPORTER_Q43, ie);
410
  assert(ieh);
411

    
412
  fb=GWEN_FastBuffer_new(1024, sio);
413
  rv=AH_ImExporterQ43_ReadDocument(ie, ctx, fb, params);
414
  GWEN_FastBuffer_free(fb);
415

    
416
  return rv;
417
}
418

    
419

    
420

    
421
int AH_ImExporterQ43_CheckFile(AB_IMEXPORTER *ie, const char *fname){
422
  AH_IMEXPORTER_Q43 *ieh;
423

    
424
  assert(ie);
425
  ieh=GWEN_INHERIT_GETDATA(AB_IMEXPORTER, AH_IMEXPORTER_Q43, ie);
426
  assert(ieh);
427

    
428
  /* always return indifferent (for now) */
429
  return AB_ERROR_INDIFFERENT;
430
}
431

    
432

    
433

    
434
int AH_ImExporterQ43_Export(AB_IMEXPORTER *ie,
435
                            AB_IMEXPORTER_CONTEXT *ctx,
436
                            GWEN_SYNCIO *sio,
437
                            GWEN_DB_NODE *params){
438
  AH_IMEXPORTER_Q43 *ieh;
439

    
440
  assert(ie);
441
  ieh=GWEN_INHERIT_GETDATA(AB_IMEXPORTER, AH_IMEXPORTER_Q43, ie);
442
  assert(ieh);
443

    
444

    
445
  // TODO
446

    
447
  return GWEN_ERROR_NOT_IMPLEMENTED;
448
}
449

    
450