Project

General

Profile

Statistics
| Branch: | Tag: | Revision:

aqbanking / src / libs / plugins / imexporters / camt / camt52_001_02.c @ f4a16f5b

History | View | Annotate | Download (13 KB)

1
/***************************************************************************
2
    begin       : Sat Dec 15 2018
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

    
11

    
12

    
13
static void _import_052_001_02_read_account_spec(AB_IMEXPORTER *ie,
14
                                                 GWEN_XMLNODE *xmlNode,
15
                                                 AB_ACCOUNT_SPEC *accountSpec) {
16
  const char *s;
17

    
18
  s=GWEN_XMLNode_GetCharValueByPath(xmlNode, "Id/IBAN", NULL);
19
  if (s && *s)
20
    AB_AccountSpec_SetIban(accountSpec, s);
21

    
22
  s=GWEN_XMLNode_GetCharValueByPath(xmlNode, "Ccy", NULL);
23
  if (s && *s)
24
    AB_AccountSpec_SetCurrency(accountSpec, s);
25

    
26
  s=GWEN_XMLNode_GetCharValueByPath(xmlNode, "Ownr/Nm", NULL);
27
  if (s && *s)
28
    AB_AccountSpec_SetOwnerName(accountSpec, s);
29

    
30
  s=GWEN_XMLNode_GetCharValueByPath(xmlNode, "Svcr/FinInstnId/BIC", NULL);
31
  if (s && *s)
32
    AB_AccountSpec_SetBic(accountSpec, s);
33

    
34
}
35

    
36

    
37

    
38
static int _import_052_001_02_read_balance(AB_IMEXPORTER *ie,
39
                                           GWEN_XMLNODE *xmlNode,
40
                                           AB_IMEXPORTER_ACCOUNTINFO *accountInfo) {
41
  const char *s;
42
  GWEN_XMLNODE *n;
43
  AB_BALANCE *balance=NULL;
44

    
45
  balance=AB_Balance_new();
46

    
47
  /* read amount */
48
  n=GWEN_XMLNode_GetNodeByXPath(xmlNode, "Amt", GWEN_PATH_FLAGS_NAMEMUSTEXIST);
49
  if (n) {
50
    const char *currency;
51
    AB_VALUE *val=NULL;
52

    
53
    currency=GWEN_XMLNode_GetProperty(n, "Ccy", "EUR");
54

    
55
    s=GWEN_XMLNode_GetCharValue(xmlNode, "Amt", NULL);
56
    if (!(s && *s)) {
57
      DBG_ERROR(AQBANKING_LOGDOMAIN, "No data in <BAL/Amt>: [%s]", s);
58
      AB_Balance_free(balance);
59
      return GWEN_ERROR_BAD_DATA;
60
    }
61

    
62
    val=AB_Value_fromString(s);
63
    if (val==NULL) {
64
      DBG_ERROR(AQBANKING_LOGDOMAIN, "Invalid amount in <BAL>: [%s]", s);
65
      AB_Balance_free(balance);
66
      return GWEN_ERROR_BAD_DATA;
67
    }
68
    AB_Value_SetCurrency(val, currency);
69

    
70
    s=GWEN_XMLNode_GetCharValue(xmlNode, "CdtDbtInd", NULL);
71
    if (!(s && *s)) {
72
      DBG_ERROR(AQBANKING_LOGDOMAIN, "Missing <CdtDbtInd> in <BAL>");
73
      AB_Value_free(val);
74
      AB_Balance_free(balance);
75
      return GWEN_ERROR_BAD_DATA;
76
    }
77
    if (strcasecmp(s, "CRDT")==0)
78
      AB_Value_Negate(val);
79

    
80
    AB_Balance_SetValue(balance, val);
81
    AB_Value_free(val);
82
  }
83

    
84
  /* read date */
85
  s=GWEN_XMLNode_GetCharValueByPath(xmlNode, "Dt/Dt", NULL);
86
  if (!(s && *s))
87
    s=GWEN_XMLNode_GetCharValueByPath(xmlNode, "Dt/DtTm", NULL);
88
  if (s && *s) {
89
    GWEN_DATE *dt;
90

    
91
    dt=GWEN_Date_fromStringWithTemplate(s, "YYYY-MM-DD");
92
    if (dt==NULL) {
93
      DBG_ERROR(AQBANKING_LOGDOMAIN, "Invalid date in <BAL>: [%s]", s);
94
      AB_Balance_free(balance);
95
      return GWEN_ERROR_BAD_DATA;
96
    }
97
    AB_Balance_SetDate(balance, dt);
98
    GWEN_Date_free(dt);
99
  }
100

    
101
  /* determine the type of balance, add if acceptable */
102
  s=GWEN_XMLNode_GetCharValueByPath(xmlNode, "Tp/CdOrPrtry/Cd", NULL);
103
  if (s && *s) {
104
    if (strcasecmp(s, "CLBD")==0 ||  /* CLBD: Closing Booked Balance */
105
        strcasecmp(s, "PRCD")==0) {  /* PRCD: Previously Closed Booked Balance */
106
      AB_Balance_SetType(balance, AB_Balance_TypeBooked);
107
      AB_ImExporterAccountInfo_AddBalance(accountInfo, balance);
108
    }
109

    
110
    else if (strcasecmp(s, "CLAV")==0) {
111
      /* CLAV: Closing Available Balance */
112
      AB_Balance_SetType(balance, AB_Balance_TypeDisposable);
113
      AB_ImExporterAccountInfo_AddBalance(accountInfo, balance);
114
    }
115
    else {
116
      DBG_ERROR(AQBANKING_LOGDOMAIN, "Unknown balance type [%s] in <BAL>, ignoring", s);
117
      AB_Balance_free(balance);
118
    }
119
  }
120

    
121
  return 0;
122
}
123

    
124

    
125

    
126
static int _import_052_001_02_read_balances(AB_IMEXPORTER *ie,
127
                                            GWEN_XMLNODE *xmlNode,
128
                                            AB_IMEXPORTER_ACCOUNTINFO *accountInfo) {
129
  GWEN_XMLNODE *n;
130

    
131
  n=GWEN_XMLNode_FindFirstTag(xmlNode, "Bal", NULL, NULL);
132
  while(n) {
133
    int rv;
134

    
135
    rv=_import_052_001_02_read_balance(ie, n, accountInfo);
136
    if (rv<0) {
137
      DBG_INFO(AQBANKING_LOGDOMAIN, "here (%d)", rv);
138
      return rv;
139
    }
140
    n=GWEN_XMLNode_FindNextTag(n, "Bal", NULL, NULL);
141
  } /* while n */
142

    
143
  return 0;
144
}
145

    
146

    
147

    
148
static int _import_052_001_02_read_transaction_details(AB_IMEXPORTER *ie,
149
                                                       GWEN_XMLNODE *xmlNode,
150
                                                       AB_TRANSACTION *t,
151
                                                       int isCredit) {
152
  const char *s;
153
  GWEN_XMLNODE *n;
154

    
155
  s=GWEN_XMLNode_GetCharValueByPath(xmlNode, "Refs/EndToEndId", NULL);
156
  if (s && *s)
157
    AB_Transaction_SetEndToEndReference(t, s);
158

    
159
  /* read names and accounts */
160
  s=GWEN_XMLNode_GetCharValueByPath(xmlNode, "Refs/MndtId", NULL);
161
  if (s && *s)
162
    AB_Transaction_SetMandateId(t, s);
163

    
164
  if (isCredit) {
165
    s=GWEN_XMLNode_GetCharValueByPath(xmlNode, "RltdPties/Dbtr/Nm", NULL);
166
    if (s && *s)
167
      AB_Transaction_SetRemoteName(t, s);
168
    s=GWEN_XMLNode_GetCharValueByPath(xmlNode, "RltdPties/DbtrAcct/Id/IBAN", NULL);
169
    if (s && *s)
170
      AB_Transaction_SetRemoteIban(t, s);
171

    
172
    s=GWEN_XMLNode_GetCharValueByPath(xmlNode, "RltdPties/Cdtr/Nm", NULL);
173
    if (s && *s)
174
      AB_Transaction_SetLocalName(t, s);
175
    s=GWEN_XMLNode_GetCharValueByPath(xmlNode, "RltdPties/CdtrAcct/Id/IBAN", NULL);
176
    if (s && *s)
177
      AB_Transaction_SetLocalIban(t, s);
178
  }
179
  else {
180
    s=GWEN_XMLNode_GetCharValueByPath(xmlNode, "RltdPties/Dbtr/Nm", NULL);
181
    if (s && *s)
182
      AB_Transaction_SetLocalName(t, s);
183
    s=GWEN_XMLNode_GetCharValueByPath(xmlNode, "RltdPties/DbtrAcct/Id/IBAN", NULL);
184
    if (s && *s)
185
      AB_Transaction_SetLocalIban(t, s);
186

    
187
    s=GWEN_XMLNode_GetCharValueByPath(xmlNode, "RltdPties/Cdtr/Nm", NULL);
188
    if (s && *s)
189
      AB_Transaction_SetRemoteName(t, s);
190

    
191
    s=GWEN_XMLNode_GetCharValueByPath(xmlNode, "RltdPties/CdtrAcct/Id/IBAN", NULL);
192
    if (s && *s)
193
      AB_Transaction_SetRemoteIban(t, s);
194

    
195
    s=GWEN_XMLNode_GetCharValueByPath(xmlNode, "RltdPties/Cdtr/Id/PrvtId/Othr/Id", NULL);
196
    if (s && *s)
197
      AB_Transaction_SetOriginatorId(t, s);
198
  }
199

    
200
  /* read transaction codes */
201
  s=GWEN_XMLNode_GetCharValueByPath(xmlNode, "BkTxCd/Domn/Cd", NULL);
202
  if (s && *s) {
203
    GWEN_BUFFER *tbuf;
204

    
205
    tbuf=GWEN_Buffer_new(0, 256, 0, 1);
206
    GWEN_Buffer_AppendString(tbuf, s);
207
    GWEN_Buffer_AppendByte(tbuf, '-');
208

    
209
    s=GWEN_XMLNode_GetCharValueByPath(xmlNode, "BkTxCd/Domn/Fmly/Cd", NULL);
210
    if (s && *s)
211
      GWEN_Buffer_AppendString(tbuf, s);
212
    GWEN_Buffer_AppendByte(tbuf, '-');
213

    
214
    s=GWEN_XMLNode_GetCharValueByPath(xmlNode, "BkTxCd/Domn/Fmly/SubFmlyCd", NULL);
215
    if (s && *s)
216
      GWEN_Buffer_AppendString(tbuf, s);
217

    
218
    AB_Transaction_SetTransactionKey(t, GWEN_Buffer_GetStart(tbuf));
219
    GWEN_Buffer_free(tbuf);
220
  }
221

    
222

    
223
  /* read purpose */
224
  n=GWEN_XMLNode_FindFirstTag(xmlNode, "RmtInf", NULL, NULL);
225
  if(n)
226
    n=GWEN_XMLNode_FindFirstTag(n, "Ustrd", NULL, NULL);
227
  while(n) {
228
    GWEN_XMLNODE *nn;
229

    
230
    nn=GWEN_XMLNode_GetFirstData(n);
231
    if (nn) {
232
      s=GWEN_XMLNode_GetData(nn);
233
      if (s && *s)
234
        AB_Transaction_AddPurposeLine(t, s);
235
    }
236
    n=GWEN_XMLNode_FindNextTag(n, "Ustrd", NULL, NULL);
237
  } /* while n */
238

    
239
  return 0;
240
}
241

    
242

    
243

    
244
static int _import_052_001_02_read_transaction(AB_IMEXPORTER *ie,
245
                                               GWEN_XMLNODE *xmlNode,
246
                                               AB_IMEXPORTER_ACCOUNTINFO *accountInfo) {
247
  const char *s;
248
  GWEN_XMLNODE *n;
249
  AB_TRANSACTION *t;
250
  int isCredit=0;
251

    
252
  t=AB_Transaction_new();
253
  AB_Transaction_SetType(t, AB_Transaction_TypeStatement);
254

    
255
  /* read credit/debit mark */
256
  s=GWEN_XMLNode_GetCharValueByPath(xmlNode, "CdtDbtInd", NULL);
257
  if (s && *s) {
258
    if (strcasecmp(s, "DBIT")==0) {
259
      isCredit=0;
260
    }
261
    else if (strcasecmp(s, "CRDT")==0) {
262
      isCredit=1;
263
    }
264
    else {
265
      DBG_ERROR(AQBANKING_LOGDOMAIN, "Invalid CdtDbtInd in <Ntry>: [%s]", s);
266
      AB_Transaction_free(t);
267
      return GWEN_ERROR_BAD_DATA;
268
    }
269
  }
270

    
271
  /* read amount */
272
  n=GWEN_XMLNode_GetNodeByXPath(xmlNode, "Amt", GWEN_PATH_FLAGS_NAMEMUSTEXIST);
273
  if (n) {
274
    const char *currency;
275
    AB_VALUE *val=NULL;
276

    
277
    currency=GWEN_XMLNode_GetProperty(n, "Ccy", "EUR");
278

    
279
    s=GWEN_XMLNode_GetCharValue(xmlNode, "Amt", NULL);
280
    if (!(s && *s)) {
281
      DBG_ERROR(AQBANKING_LOGDOMAIN, "No currency in <Ntry/Amt>: [%s]", s);
282
      AB_Transaction_free(t);
283
      return GWEN_ERROR_BAD_DATA;
284
    }
285

    
286
    val=AB_Value_fromString(s);
287
    if (val==NULL) {
288
      DBG_ERROR(AQBANKING_LOGDOMAIN, "Invalid amount in <Ntry>: [%s]", s);
289
      AB_Transaction_free(t);
290
      return GWEN_ERROR_BAD_DATA;
291
    }
292

    
293
    AB_Value_SetCurrency(val, currency);
294
    if (!isCredit)
295
      AB_Value_Negate(val);
296

    
297
    AB_Transaction_SetValue(t, val);
298
    AB_Value_free(val);
299
  }
300

    
301
  /* read booked date */
302
  s=GWEN_XMLNode_GetCharValueByPath(xmlNode, "BookgDt/Dt", NULL);
303
  if (s && *s) {
304
    GWEN_DATE *dt;
305

    
306
    dt=GWEN_Date_fromStringWithTemplate(s, "YYYY-MM-DD");
307
    if (dt==NULL) {
308
      DBG_ERROR(AQBANKING_LOGDOMAIN, "Invalid booking date in <Ntry>: [%s]", s);
309
      AB_Transaction_free(t);
310
      return GWEN_ERROR_BAD_DATA;
311
    }
312
    AB_Transaction_SetDate(t, dt);
313
    GWEN_Date_free(dt);
314
  }
315

    
316
  /* read valuta date */
317
  s=GWEN_XMLNode_GetCharValueByPath(xmlNode, "ValDt/Dt", NULL);
318
  if (s && *s) {
319
    GWEN_DATE *dt;
320

    
321
    dt=GWEN_Date_fromStringWithTemplate(s, "YYYY-MM-DD");
322
    if (dt==NULL) {
323
      DBG_ERROR(AQBANKING_LOGDOMAIN, "Invalid valuta date in <Ntry>: [%s]", s);
324
      AB_Transaction_free(t);
325
      return GWEN_ERROR_BAD_DATA;
326
    }
327
    AB_Transaction_SetValutaDate(t, dt);
328
    GWEN_Date_free(dt);
329
  }
330

    
331
  /* read bank reference */
332
  s=GWEN_XMLNode_GetCharValueByPath(xmlNode, "NtryRef", NULL);
333
  if (s && *s)
334
    AB_Transaction_SetBankReference(t, s);
335

    
336
  /* read transaction details */
337
  n=GWEN_XMLNode_GetNodeByXPath(xmlNode, "NtryDtls/TxDtls", GWEN_PATH_FLAGS_NAMEMUSTEXIST);
338
  if (n) {
339
    int rv;
340

    
341
    rv=_import_052_001_02_read_transaction_details(ie, n, t, isCredit);
342
    if (rv<0) {
343
      DBG_INFO(AQBANKING_LOGDOMAIN, "here (%d)", rv);
344
      return rv;
345
    }
346
  }
347

    
348
  /* check transaction */
349
  if (!(AB_Transaction_GetValue(t) && (AB_Transaction_GetDate(t) || AB_Transaction_GetValutaDate(t)))) {
350
    DBG_ERROR(AQBANKING_LOGDOMAIN, "Incomplete transaction received");
351
    AB_Transaction_free(t);
352
    return GWEN_ERROR_BAD_DATA;
353
  }
354
  AB_ImExporterAccountInfo_AddTransaction(accountInfo, t);
355

    
356
  return 0;
357
}
358

    
359

    
360

    
361
static int _import_052_001_02_read_transactions(AB_IMEXPORTER *ie,
362
                                                GWEN_XMLNODE *xmlNode,
363
                                                AB_IMEXPORTER_ACCOUNTINFO *accountInfo) {
364
  GWEN_XMLNODE *n;
365

    
366
  n=GWEN_XMLNode_FindFirstTag(xmlNode, "Ntry", NULL, NULL);
367
  while(n) {
368
    int rv;
369

    
370
    rv=_import_052_001_02_read_transaction(ie, n, accountInfo);
371
    if (rv<0) {
372
      DBG_INFO(AQBANKING_LOGDOMAIN, "here (%d)", rv);
373
      return rv;
374
    }
375
    n=GWEN_XMLNode_FindNextTag(n, "Ntry", NULL, NULL);
376
  } /* while n */
377

    
378
  return 0;
379
}
380

    
381

    
382

    
383
static int _import_052_001_02_report(AB_IMEXPORTER *ie,
384
                                     AB_IMEXPORTER_CONTEXT *ctx,
385
                                     GWEN_DB_NODE *params,
386
                                     GWEN_XMLNODE *xmlNode) {
387
  GWEN_XMLNODE *n;
388
  AB_IMEXPORTER_ACCOUNTINFO *accountInfo=NULL;
389
  int rv;
390

    
391
  /* read account, set accountInfo */
392
  n=GWEN_XMLNode_FindFirstTag(xmlNode, "Acct", NULL, NULL);
393
  if (n) {
394
    AB_ACCOUNT_SPEC *accountSpec;
395

    
396
    accountSpec=AB_AccountSpec_new();
397
    _import_052_001_02_read_account_spec(ie, n, accountSpec);
398
    accountInfo=AB_ImExporterContext_GetOrAddAccountInfo(ctx,
399
                                                         0,
400
                                                         AB_AccountSpec_GetIban(accountSpec),
401
                                                         AB_AccountSpec_GetBankCode(accountSpec),
402
                                                         AB_AccountSpec_GetAccountNumber(accountSpec),
403
                                                         AB_AccountType_Unknown);
404
    assert(accountInfo);
405
    AB_AccountSpec_free(accountSpec);
406
  }
407

    
408
  /* read balances */
409
  rv=_import_052_001_02_read_balances(ie, xmlNode, accountInfo);
410
  if (rv<0) {
411
    DBG_INFO(AQBANKING_LOGDOMAIN, "here (%d)", rv);
412
    return rv;
413
  }
414

    
415
  /* read transactions */
416
  rv=_import_052_001_02_read_transactions(ie, xmlNode, accountInfo);
417
  if (rv<0) {
418
    DBG_INFO(AQBANKING_LOGDOMAIN, "here (%d)", rv);
419
    return rv;
420
  }
421

    
422
  return 0;
423
}
424

    
425

    
426

    
427

    
428

    
429
int AH_ImExporterCAMT_Import_052_001_02(AB_IMEXPORTER *ie,
430
                                        AB_IMEXPORTER_CONTEXT *ctx,
431
                                        GWEN_DB_NODE *params,
432
                                        GWEN_XMLNODE *xmlNode) {
433
  GWEN_XMLNODE *n;
434

    
435
  n=GWEN_XMLNode_FindFirstTag(xmlNode, "BkToCstmrAcctRpt", NULL, NULL);
436
  if (n==NULL) {
437
    DBG_ERROR(AQBANKING_LOGDOMAIN, "<BkToCstmrAcctRpt> element not found");
438
    return GWEN_ERROR_BAD_DATA;
439
  }
440

    
441
  n=GWEN_XMLNode_FindFirstTag(n, "Rpt", NULL, NULL);
442
  if (n==NULL) {
443
    DBG_ERROR(AQBANKING_LOGDOMAIN, "<Rpt> element not found");
444
    return GWEN_ERROR_BAD_DATA;
445
  }
446

    
447
  /* now read every report */
448
  while(n) {
449
    int rv;
450

    
451
    rv=_import_052_001_02_report(ie, ctx, params, n);
452
    if (rv<0) {
453
      DBG_INFO(AQBANKING_LOGDOMAIN, "here (%d)", rv);
454
      return rv;
455
    }
456
    n=GWEN_XMLNode_FindNextTag(n, "Rpt", NULL, NULL);
457
  }
458
  return 0;
459
}
460

    
461

    
462

    
463