1
|
|
|
<?php declare(strict_types=1); |
2
|
|
|
|
3
|
|
|
namespace OfxParser; |
4
|
|
|
|
5
|
|
|
use SimpleXMLElement; |
6
|
|
|
use OfxParser\Utils; |
7
|
|
|
use OfxParser\Entities\AccountInfo; |
8
|
|
|
use OfxParser\Entities\BankAccount; |
9
|
|
|
use OfxParser\Entities\Institute; |
10
|
|
|
use OfxParser\Entities\SignOn; |
11
|
|
|
use OfxParser\Entities\Statement; |
12
|
|
|
use OfxParser\Entities\Status; |
13
|
|
|
use OfxParser\Entities\Transaction; |
14
|
|
|
|
15
|
|
|
/** |
16
|
|
|
* The OFX object |
17
|
|
|
* |
18
|
|
|
* Heavily refactored from Guillaume Bailleul's grimfor/ofxparser |
19
|
|
|
* |
20
|
|
|
* Second refactor by Oliver Lowe to unify the API across all |
21
|
|
|
* OFX data-types. |
22
|
|
|
* |
23
|
|
|
* Based on Andrew A Smith's Ruby ofx-parser |
24
|
|
|
* |
25
|
|
|
* @author Guillaume BAILLEUL <[email protected]> |
26
|
|
|
* @author James Titcumb <[email protected]> |
27
|
|
|
* @author Oliver Lowe <[email protected]> |
28
|
|
|
*/ |
29
|
|
|
class Ofx |
30
|
|
|
{ |
31
|
|
|
/** |
32
|
|
|
* @var Header[] |
33
|
|
|
*/ |
34
|
|
|
public $header = []; |
35
|
|
|
|
36
|
|
|
/** |
37
|
|
|
* @var SignOn |
38
|
|
|
*/ |
39
|
|
|
public $signOn; |
40
|
|
|
|
41
|
|
|
/** |
42
|
|
|
* @var AccountInfo[] |
43
|
|
|
*/ |
44
|
|
|
public $signupAccountInfo; |
45
|
|
|
|
46
|
|
|
/** |
47
|
|
|
* @var BankAccount[] |
48
|
|
|
*/ |
49
|
|
|
public $bankAccounts = []; |
50
|
|
|
|
51
|
|
|
/** |
52
|
|
|
* Only populated if there is only one bank account |
53
|
|
|
* @var BankAccount|null |
54
|
|
|
* @deprecated This will be removed in future versions |
55
|
|
|
*/ |
56
|
|
|
public $bankAccount; |
57
|
|
|
|
58
|
|
|
/** |
59
|
|
|
* @param SimpleXMLElement $xml |
60
|
|
|
* @throws \Exception |
61
|
|
|
*/ |
62
|
3 |
|
public function __construct(SimpleXMLElement $xml) |
63
|
|
|
{ |
64
|
3 |
|
$this->signOn = $this->buildSignOn($xml->SIGNONMSGSRSV1->SONRS); |
65
|
3 |
|
$this->signupAccountInfo = $this->buildAccountInfo($xml->SIGNUPMSGSRSV1->ACCTINFOTRNRS); |
66
|
|
|
|
67
|
3 |
|
if (property_exists($xml, 'BANKMSGSRSV1') && $xml->BANKMSGSRSV1 !== null) { |
68
|
3 |
|
$this->bankAccounts = $this->buildBankAccounts($xml); |
69
|
|
|
} elseif (property_exists($xml, 'CREDITCARDMSGSRSV1') && $xml->CREDITCARDMSGSRSV1 !== null) { |
70
|
|
|
$this->bankAccounts = $this->buildCreditAccounts($xml); |
71
|
|
|
} |
72
|
|
|
|
73
|
|
|
// Set a helper if only one bank account |
74
|
3 |
|
if (count($this->bankAccounts) === 1) { |
75
|
2 |
|
$this->bankAccount = $this->bankAccounts[0]; |
|
|
|
|
76
|
|
|
} |
77
|
3 |
|
} |
78
|
|
|
|
79
|
|
|
/** |
80
|
|
|
* Get the transactions that have been processed |
81
|
|
|
* |
82
|
|
|
* @return \OfxParser\Entities\Transaction[] |
83
|
|
|
* @deprecated This will be removed in future versions |
84
|
|
|
*/ |
85
|
|
|
public function getTransactions(): array |
86
|
|
|
{ |
87
|
|
|
return $this->bankAccount->statement->transactions; |
|
|
|
|
88
|
|
|
} |
89
|
|
|
|
90
|
|
|
/** |
91
|
|
|
* @param array $header |
92
|
|
|
* @return Ofx |
93
|
|
|
*/ |
94
|
|
|
public function buildHeader(array $header): self |
95
|
|
|
{ |
96
|
|
|
$this->header = $header; |
97
|
|
|
|
98
|
|
|
return $this; |
99
|
|
|
} |
100
|
|
|
|
101
|
|
|
/** |
102
|
|
|
* @param SimpleXMLElement $xml |
103
|
|
|
* @return \OfxParser\Entities\SignOn |
104
|
|
|
* @throws \Exception |
105
|
|
|
*/ |
106
|
3 |
|
protected function buildSignOn(SimpleXMLElement $xml): \OfxParser\Entities\SignOn |
107
|
|
|
{ |
108
|
3 |
|
$signOn = new SignOn(); |
109
|
3 |
|
$signOn->status = $this->buildStatus($xml->STATUS); |
110
|
3 |
|
$signOn->date = Utils::createDateTimeFromStr($xml->DTSERVER, true); |
111
|
3 |
|
$signOn->language = $xml->LANGUAGE; |
112
|
|
|
|
113
|
3 |
|
$signOn->institute = new Institute(); |
114
|
3 |
|
$signOn->institute->name = $xml->FI->ORG; |
115
|
3 |
|
$signOn->institute->id = $xml->FI->FID; |
116
|
|
|
|
117
|
3 |
|
return $signOn; |
118
|
|
|
} |
119
|
|
|
|
120
|
|
|
/** |
121
|
|
|
* @param SimpleXMLElement|null $xml |
122
|
|
|
* @return array AccountInfo |
123
|
|
|
*/ |
124
|
3 |
|
private function buildAccountInfo(SimpleXMLElement $xml = null): array |
125
|
|
|
{ |
126
|
3 |
|
if (null === $xml) { |
127
|
3 |
|
return []; |
128
|
|
|
} |
129
|
|
|
|
130
|
|
|
if (!(property_exists($xml, 'ACCTINFO') && $xml->ACCTINFO !== null)) { |
131
|
|
|
return []; |
132
|
|
|
} |
133
|
|
|
|
134
|
|
|
$accounts = []; |
135
|
|
|
foreach ($xml->ACCTINFO as $account) { |
136
|
|
|
$accountInfo = new AccountInfo(); |
137
|
|
|
$accountInfo->desc = $account->DESC; |
138
|
|
|
$accountInfo->number = $account->ACCTID; |
139
|
|
|
$accounts[] = $accountInfo; |
140
|
|
|
} |
141
|
|
|
|
142
|
|
|
return $accounts; |
143
|
|
|
} |
144
|
|
|
|
145
|
|
|
/** |
146
|
|
|
* @param SimpleXMLElement $xml |
147
|
|
|
* @throws \Exception |
148
|
|
|
* @return \OfxParser\Entities\BankAccount[] |
149
|
|
|
*/ |
150
|
|
|
private function buildCreditAccounts(SimpleXMLElement $xml): array |
151
|
|
|
{ |
152
|
|
|
// Loop through the bank accounts |
153
|
|
|
$bankAccounts = []; |
154
|
|
|
|
155
|
|
|
foreach ($xml->CREDITCARDMSGSRSV1->CCSTMTTRNRS as $accountStatement) { |
156
|
|
|
$bankAccounts[] = $this->buildCreditAccount($accountStatement); |
|
|
|
|
157
|
|
|
} |
158
|
|
|
return $bankAccounts; |
159
|
|
|
} |
160
|
|
|
|
161
|
|
|
/** |
162
|
3 |
|
* @param SimpleXMLElement $xml |
163
|
|
|
* @throws \Exception |
164
|
|
|
* @return \OfxParser\Entities\BankAccount[] |
165
|
3 |
|
*/ |
166
|
3 |
|
private function buildBankAccounts(SimpleXMLElement $xml): array |
167
|
3 |
|
{ |
168
|
3 |
|
// Loop through the bank accounts |
169
|
|
|
$bankAccounts = []; |
170
|
|
|
foreach ($xml->BANKMSGSRSV1->STMTTRNRS as $accountStatement) { |
171
|
3 |
|
foreach ($accountStatement->STMTRS as $statementResponse) { |
172
|
|
|
$bankAccounts[] = $this->buildBankAccount($accountStatement->TRNUID, $statementResponse); |
|
|
|
|
173
|
|
|
} |
174
|
|
|
} |
175
|
|
|
return $bankAccounts; |
176
|
|
|
} |
177
|
|
|
|
178
|
|
|
/** |
179
|
|
|
* @param string $transactionUid |
180
|
3 |
|
* @param SimpleXMLElement $statementResponse |
181
|
|
|
* @throws \Exception |
182
|
3 |
|
* @return \OfxParser\Entities\BankAccount |
183
|
3 |
|
*/ |
184
|
3 |
|
private function buildBankAccount(?\SimpleXMLElement $transactionUid, SimpleXMLElement $statementResponse): \OfxParser\Entities\BankAccount |
185
|
3 |
|
{ |
186
|
3 |
|
$bankAccount = new BankAccount(); |
187
|
3 |
|
$bankAccount->transactionUid = $transactionUid; |
188
|
3 |
|
$bankAccount->agencyNumber = $statementResponse->BANKACCTFROM->BRANCHID; |
189
|
3 |
|
$bankAccount->accountNumber = $statementResponse->BANKACCTFROM->ACCTID; |
190
|
3 |
|
$bankAccount->routingNumber = $statementResponse->BANKACCTFROM->BANKID; |
191
|
3 |
|
$bankAccount->accountType = $statementResponse->BANKACCTFROM->ACCTTYPE; |
192
|
|
|
$bankAccount->balance = $statementResponse->LEDGERBAL->BALAMT; |
193
|
|
|
$bankAccount->balanceDate = Utils::createDateTimeFromStr( |
194
|
3 |
|
$statementResponse->LEDGERBAL->DTASOF, |
195
|
3 |
|
true |
196
|
|
|
); |
197
|
3 |
|
|
198
|
3 |
|
$bankAccount->statement = new Statement(); |
199
|
|
|
$bankAccount->statement->currency = $statementResponse->CURDEF; |
200
|
|
|
|
201
|
3 |
|
$bankAccount->statement->startDate = Utils::createDateTimeFromStr( |
202
|
3 |
|
$statementResponse->BANKTRANLIST->DTSTART |
203
|
|
|
); |
204
|
|
|
|
205
|
3 |
|
$bankAccount->statement->endDate = Utils::createDateTimeFromStr( |
206
|
3 |
|
$statementResponse->BANKTRANLIST->DTEND |
207
|
|
|
); |
208
|
|
|
|
209
|
3 |
|
$bankAccount->statement->transactions = $this->buildTransactions( |
210
|
|
|
$statementResponse->BANKTRANLIST->STMTTRN |
211
|
|
|
); |
212
|
|
|
|
213
|
|
|
return $bankAccount; |
214
|
|
|
} |
215
|
|
|
|
216
|
|
|
/** |
217
|
|
|
* @param SimpleXMLElement $xml |
218
|
|
|
* @throws \Exception |
219
|
|
|
* @return \OfxParser\Entities\BankAccount |
220
|
|
|
*/ |
221
|
|
|
private function buildCreditAccount(SimpleXMLElement $xml): \OfxParser\Entities\BankAccount |
222
|
|
|
{ |
223
|
|
|
$nodeName = 'CCACCTFROM'; |
224
|
|
|
if (!isset($xml->CCSTMTRS->$nodeName)) { |
225
|
|
|
$nodeName = 'BANKACCTFROM'; |
226
|
|
|
} |
227
|
|
|
|
228
|
|
|
$creditAccount = new BankAccount(); |
229
|
|
|
$creditAccount->transactionUid = $xml->TRNUID; |
230
|
|
|
$creditAccount->agencyNumber = $xml->CCSTMTRS->$nodeName->BRANCHID; |
231
|
|
|
$creditAccount->accountNumber = $xml->CCSTMTRS->$nodeName->ACCTID; |
232
|
|
|
$creditAccount->routingNumber = $xml->CCSTMTRS->$nodeName->BANKID; |
233
|
|
|
$creditAccount->accountType = $xml->CCSTMTRS->$nodeName->ACCTTYPE; |
234
|
|
|
$creditAccount->balance = $xml->CCSTMTRS->LEDGERBAL->BALAMT; |
235
|
|
|
$creditAccount->balanceDate = Utils::createDateTimeFromStr($xml->CCSTMTRS->LEDGERBAL->DTASOF, true); |
236
|
|
|
|
237
|
|
|
$creditAccount->statement = new Statement(); |
238
|
|
|
$creditAccount->statement->currency = $xml->CCSTMTRS->CURDEF; |
239
|
|
|
$creditAccount->statement->startDate = Utils::createDateTimeFromStr($xml->CCSTMTRS->BANKTRANLIST->DTSTART); |
240
|
|
|
$creditAccount->statement->endDate = Utils::createDateTimeFromStr($xml->CCSTMTRS->BANKTRANLIST->DTEND); |
241
|
|
|
$creditAccount->statement->transactions = $this->buildTransactions($xml->CCSTMTRS->BANKTRANLIST->STMTTRN); |
242
|
|
|
|
243
|
|
|
return $creditAccount; |
244
|
|
|
} |
245
|
|
|
|
246
|
|
|
/** |
247
|
3 |
|
* @param SimpleXMLElement $transactions |
248
|
|
|
* @throws \Exception |
249
|
3 |
|
* @return \OfxParser\Entities\Transaction[] |
250
|
3 |
|
*/ |
251
|
3 |
|
private function buildTransactions(SimpleXMLElement $transactions): array |
252
|
3 |
|
{ |
253
|
3 |
|
$return = []; |
254
|
3 |
|
foreach ($transactions as $t) { |
255
|
2 |
|
$transaction = new Transaction(); |
256
|
|
|
$transaction->type = (string)$t->TRNTYPE; |
257
|
3 |
|
$transaction->date = Utils::createDateTimeFromStr($t->DTPOSTED); |
258
|
3 |
|
if ('' !== (string)$t->DTUSER) { |
259
|
3 |
|
$transaction->userInitiatedDate = Utils::createDateTimeFromStr($t->DTUSER); |
260
|
3 |
|
} |
261
|
3 |
|
$transaction->amount = Utils::createAmountFromStr($t->TRNAMT); |
262
|
3 |
|
$transaction->uniqueId = (string)$t->FITID; |
263
|
3 |
|
$transaction->name = (string)$t->NAME; |
264
|
|
|
$transaction->memo = (string)$t->MEMO; |
265
|
|
|
$transaction->sic = $t->SIC; |
266
|
3 |
|
$transaction->checkNumber = $t->CHECKNUM; |
267
|
|
|
$return[] = $transaction; |
268
|
|
|
} |
269
|
|
|
|
270
|
|
|
return $return; |
271
|
|
|
} |
272
|
|
|
|
273
|
3 |
|
/** |
274
|
|
|
* @param SimpleXMLElement $xml |
275
|
3 |
|
* @return \OfxParser\Entities\Status |
276
|
3 |
|
*/ |
277
|
3 |
|
private function buildStatus(SimpleXMLElement $xml): \OfxParser\Entities\Status |
278
|
3 |
|
{ |
279
|
|
|
$status = new Status(); |
280
|
3 |
|
$status->code = $xml->CODE; |
281
|
|
|
$status->severity = $xml->SEVERITY; |
282
|
|
|
$status->message = $xml->MESSAGE; |
283
|
|
|
|
284
|
|
|
return $status; |
285
|
|
|
} |
286
|
|
|
} |
287
|
|
|
|
This property has been deprecated. The supplier of the class has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.