Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update testsuite; normalizing/parsing fixes #1

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 0 additions & 6 deletions .idea/codeception.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions .idea/ofx-php-parser.iml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions .idea/phpspec.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

26 changes: 14 additions & 12 deletions src/OFX.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public static function parse(string $ofxData): null|OFXData
}
}
} elseif (isset($xml->CREDITCARDMSGSRSV1)) {
$bankAccounts[] = self::parseCreditAccount($xml->TRNUID, $xml);
$bankAccounts[] = self::parseCreditAccount($xml->TRNUID, $xml->CREDITCARDMSGSRSV1->CCSTMTTRNRS);
}
return new OFXData($signOn, $accountInfo, $bankAccounts);
}
Expand Down Expand Up @@ -91,11 +91,13 @@ protected static function parseDate(string $dateString): DateTime
{
$dateString = explode('.', $dateString)[0];
// Extract the numeric part of the offset (e.g., -5 from [-5:EST])
preg_match('/([-+]\d+):(\w+)/', $dateString, $matches);
// Also deal with some OFX data where the date string contains the offset, but not the
// timezone abbreviation, ie. 20240501094851[-8]
preg_match('/([-+]\d+)(:)?(\w+)?/', $dateString, $matches);

if (count($matches) === 3) {
if (count($matches) >= 2) {
$offset = $matches[1];
$timezoneAbbreviation = $matches[2];
$timezoneAbbreviation = $matches[3] ?? null;

// Remove the offset with brackets and timezone abbreviation from the date string
$dateStringWithoutOffset = preg_replace('/[-+]\d+:\w+/', '', $dateString);
Expand All @@ -105,7 +107,7 @@ protected static function parseDate(string $dateString): DateTime

// Create a DateTime object with the appropriate timezone offset
$dateTime = new DateTime($dateStringWithoutOffset, new DateTimeZone("GMT$offset"));
$dateTime->setTimezone(new DateTimeZone($timezoneAbbreviation));
(null === $timezoneAbbreviation) ?: $dateTime->setTimezone(new DateTimeZone($timezoneAbbreviation));

} else {
// Handle cases where the date format doesn't match expectations
Expand All @@ -120,12 +122,12 @@ protected static function parseDate(string $dateString): DateTime
*/
private static function parseBankAccount(string $uuid, SimpleXMLElement $xml): BankAccount
{
$accountNumber = $xml->BANKACCTFROM->ACCTID;
$accountType = $xml->BANKACCTFROM->ACCTTYPE;
$agencyNumber = $xml->BANKACCTFROM->BRANCHID;
$routingNumber = $xml->BANKACCTFROM->BANKID;
$balance = $xml->LEDGERBAL->BALAMT;
$balanceDate = self::parseDate($xml->LEDGERBAL->DTASOF);
$accountNumber = $xml->BANKACCTFROM->ACCTID ?? 'N/A';
$accountType = $xml->BANKACCTFROM->ACCTTYPE ?? 'N/A';
$agencyNumber = $xml->BANKACCTFROM->BRANCHID ?? 'N/A';
$routingNumber = $xml->BANKACCTFROM->BANKID ?? 'N/A';
$balance = $xml->LEDGERBAL->BALAMT ?? 'N/A';
$balanceDate = (null !== $xml->LEDGERBAL->DTASOF) ? self::parseDate($xml->LEDGERBAL->DTASOF) : new DateTime();
$statement = self::parseStatement($xml);
return new BankAccount(
$accountNumber,
Expand Down Expand Up @@ -155,7 +157,7 @@ private static function parseCreditAccount(string $uuid, SimpleXMLElement $xml):
$routingNumber = $xml->CCSTMTRS->$nodeName->BANKID;
$balance = $xml->CCSTMTRS->LEDGERBAL->BALAMT;
$balanceDate = self::parseDate($xml->CCSTMTRS->LEDGERBAL->DTASOF);
$statement = self::parseStatement($xml);
$statement = self::parseStatement($xml->CCSTMTRS);
return new BankAccount(
$accountNumber,
$accountType,
Expand Down
2 changes: 1 addition & 1 deletion src/OFXUtils.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public static function normalizeOfx(string $ofxContent): string|false|SimpleXMLE
$ofxXml = $ofxSgml;
} else {
if (preg_match('/<OFX>.*<\/OFX>/', $ofxSgml) === 1) {
return str_replace('<', "\n<", $ofxSgml); // add line breaks to allow XML to parse
$ofxSgml = str_replace('<', "\n<", $ofxSgml); // add line breaks to allow XML to parse
}
$ofxXml = self::convertSgmlToXml($ofxSgml);
}
Expand Down
275 changes: 273 additions & 2 deletions tests/OFXTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public function testMultipleAccountsXML()

$parsedData = OFX::parse($ofxContent);

var_dump($parsedData);
//var_dump($parsedData);

$this->assertNotEmpty($parsedData);
}
Expand All @@ -32,8 +32,279 @@ public function testOfxData()

$parsedData = OFX::parse($ofxContent);

var_dump($parsedData);
//var_dump($parsedData);

$this->assertNotEmpty($parsedData);
}

/**
* @throws Exception
*/
public function testOfxDataBankingXml200()
{
$filePath = $this->ofxTestFilesDir . '/ofxdata-banking-xml200.ofx';
$ofxContent = file_get_contents($filePath);

$parsedData = OFX::parse($ofxContent);

//var_dump($parsedData);

$this->assertNotEmpty($parsedData);
}

/**
* @throws Exception
*/
public function testOfxDataBB()
{
$filePath = $this->ofxTestFilesDir . '/ofxdata-bb.ofx';
$ofxContent = file_get_contents($filePath);

$parsedData = OFX::parse($ofxContent);

//var_dump($parsedData);

$this->assertNotEmpty($parsedData);
}

/**
* @throws Exception
*/
public function testOfxDataBBTwoStmtrs()
{
$filePath = $this->ofxTestFilesDir . '/ofxdata-bb-two-stmtrs.ofx';
$ofxContent = file_get_contents($filePath);

$parsedData = OFX::parse($ofxContent);

//var_dump($parsedData);

$this->assertNotEmpty($parsedData);
}

/**
* @throws Exception
*/
public function testOfxDataBpbfc()
{
$filePath = $this->ofxTestFilesDir . '/ofxdata-bpbfc.ofx';
$ofxContent = file_get_contents($filePath);

$parsedData = OFX::parse($ofxContent);

//var_dump($parsedData);

$this->assertNotEmpty($parsedData);
}

/**
* @throws Exception
*/
public function testOfxDataCmfr()
{
$filePath = $this->ofxTestFilesDir . '/ofxdata-cmfr.ofx';
$ofxContent = file_get_contents($filePath);

$parsedData = OFX::parse($ofxContent);

//var_dump($parsedData);

$this->assertNotEmpty($parsedData);
}

/**
* @throws Exception
*/
public function testOfxDataCreditCard()
{
$filePath = $this->ofxTestFilesDir . '/ofxdata-credit-card.ofx';
$ofxContent = file_get_contents($filePath);

$parsedData = OFX::parse($ofxContent);

//var_dump($parsedData);

$this->assertNotEmpty($parsedData);
}

/**
* @throws Exception
*/
public function testOfxDataEmptyDateTime()
{
$filePath = $this->ofxTestFilesDir . '/ofxdata-emptyDateTime.ofx';
$ofxContent = file_get_contents($filePath);

$parsedData = OFX::parse($ofxContent);

//var_dump($parsedData);

$this->assertNotEmpty($parsedData);
}

/**
* @throws Exception
*/
public function testOfxDataFullExample()
{
$filePath = $this->ofxTestFilesDir . '/ofxdata-full-example.ofx';
$ofxContent = file_get_contents($filePath);

$parsedData = OFX::parse($ofxContent);

//var_dump($parsedData);

$this->assertNotEmpty($parsedData);
}

/**
* @throws Exception
*/
public function testOfxDataGoogle()
{
$filePath = $this->ofxTestFilesDir . '/ofxdata-google.ofx';
$ofxContent = file_get_contents($filePath);

$parsedData = OFX::parse($ofxContent);

//var_dump($parsedData);

$this->assertNotEmpty($parsedData);
}

/**
* @throws Exception
*/
public function testOfxDataInvestmentsMultipleAccountsXml()
{
$filePath = $this->ofxTestFilesDir . '/ofxdata-investments-multiple-accounts-xml.ofx';
$ofxContent = file_get_contents($filePath);

$parsedData = OFX::parse($ofxContent);

//var_dump($parsedData);

$this->assertNotEmpty($parsedData);
}

/**
* @throws Exception
*/
public function testOfxDataInvestmentsOnelineXml()
{
$filePath = $this->ofxTestFilesDir . '/ofxdata-investments-oneline-xml.ofx';
$ofxContent = file_get_contents($filePath);

$parsedData = OFX::parse($ofxContent);

//var_dump($parsedData);

$this->assertNotEmpty($parsedData);
}

/**
* @throws Exception
*/
public function testOfxDataInvestmentsXml()
{
$filePath = $this->ofxTestFilesDir . '/ofxdata-investments-xml.ofx';
$ofxContent = file_get_contents($filePath);

$parsedData = OFX::parse($ofxContent);

//var_dump($parsedData);

$this->assertNotEmpty($parsedData);
}

/**
* @throws Exception
*/
public function testOfxDataMemoWithAmpersand()
{
$filePath = $this->ofxTestFilesDir . '/ofxdata-memoWithAmpersand.ofx';
$ofxContent = file_get_contents($filePath);

$parsedData = OFX::parse($ofxContent);

//var_dump($parsedData);

$this->assertNotEmpty($parsedData);
}

/**
* @throws Exception
*/
public function testOfxDataMemoWithQuotes()
{
$filePath = $this->ofxTestFilesDir . '/ofxdata-memoWithQuotes.ofx';
$ofxContent = file_get_contents($filePath);

$parsedData = OFX::parse($ofxContent);

//var_dump($parsedData);

$this->assertNotEmpty($parsedData);
}

/**
* @throws Exception
*/
public function testOfxDataOneline()
{
$filePath = $this->ofxTestFilesDir . '/ofxdata-oneline.ofx';
$ofxContent = file_get_contents($filePath);

$parsedData = OFX::parse($ofxContent);

//var_dump($parsedData);

$this->assertNotEmpty($parsedData);
}

/**
* @throws Exception
*/
public function testOfxDataRbcCreditCard()
{
$filePath = $this->ofxTestFilesDir . '/ofxdata-rbc-credit-card.ofx';
$ofxContent = file_get_contents($filePath);

$parsedData = OFX::parse($ofxContent);

//var_dump($parsedData);

$this->assertNotEmpty($parsedData);
}

/**
* @throws Exception
*/
public function testOfxDataSelfClose()
{
$filePath = $this->ofxTestFilesDir . '/ofxdata-selfclose.ofx';
$ofxContent = file_get_contents($filePath);

$parsedData = OFX::parse($ofxContent);

//var_dump($parsedData);

$this->assertNotEmpty($parsedData);
}

/**
* @throws Exception
*/
public function testOfxDataXml()
{
$filePath = $this->ofxTestFilesDir . '/ofxdata-xml.ofx';
$ofxContent = file_get_contents($filePath);

$parsedData = OFX::parse($ofxContent);

//var_dump($parsedData);

$this->assertNotEmpty($parsedData);
}

}
Loading