jenkins-bot has submitted this change and it was merged. Change subject: Adyen audit processor ......................................................................
Adyen audit processor A lot like AstroPay's. Handles donations, refunds, and chargebacks. Bug: T121129 Change-Id: Icbdbe3fa2c0537c622a4621095527b3d4a7c1769 --- M Core/UtcDate.php A PaymentProviders/Adyen/Audit/AdyenAudit.php M PaymentProviders/Adyen/ExpatriatedMessages/ReportAvailable.php A PaymentProviders/Adyen/Jobs/DownloadReportJob.php D PaymentProviders/Adyen/Jobs/ProcessAccountingReportJob.php A PaymentProviders/Adyen/ReferenceData.php A PaymentProviders/Adyen/Tests/Data/chargeback.csv A PaymentProviders/Adyen/Tests/Data/donation.csv A PaymentProviders/Adyen/Tests/Data/refund.csv A PaymentProviders/Adyen/Tests/phpunit/AuditTest.php M config_defaults.php M phpunit.xml 12 files changed, 461 insertions(+), 158 deletions(-) Approvals: XenoRyet: Looks good to me, approved jenkins-bot: Verified diff --git a/Core/UtcDate.php b/Core/UtcDate.php index 11c1701..b2ef976 100644 --- a/Core/UtcDate.php +++ b/Core/UtcDate.php @@ -6,9 +6,9 @@ use SmashPig\Core\Logging\Logger; class UtcDate { - public static function getUtcTimestamp( $dateString ) { + public static function getUtcTimestamp( $dateString, $timeZone = 'UTC' ) { try { - $obj = new DateTime( $dateString, new DateTimeZone( 'UTC' ) ); + $obj = new DateTime( $dateString, new DateTimeZone( $timeZone ) ); return $obj->getTimestamp(); } catch ( Exception $ex ) { Logger::warning ( 'Caught date exception: ' . $ex->getMessage(), $dateString ); diff --git a/PaymentProviders/Adyen/Audit/AdyenAudit.php b/PaymentProviders/Adyen/Audit/AdyenAudit.php new file mode 100644 index 0000000..42f9dda --- /dev/null +++ b/PaymentProviders/Adyen/Audit/AdyenAudit.php @@ -0,0 +1,175 @@ +<?php namespace SmashPig\PaymentProviders\Adyen\Audit; + +use OutOfBoundsException; +use SmashPig\Core\UtcDate; +use SmashPig\PaymentProviders\Adyen\ReferenceData; + +/** + * Class AdyenAudit + * @package SmashPig\PaymentProviders\Adyen\Audit + * Processes Adyen's Settlement Detail Reports. + * Sends donations, chargebacks, and refunds to queue. + * https://docs.adyen.com/manuals/reporting-manual/settlement-detail-report-structure/settlement-detail-report-journal-types + */ +class AdyenAudit { + + protected $columnHeaders; + protected $ignoredStatuses; + protected $fileData = array(); + protected static $ignoredTypes = array( + 'Fee', + 'MiscCosts', + 'MerchantPayout', + 'ChargebackReversed', // oh hey, we could try to handle these + 'RefundedReversed', + 'DepositCorrection', + 'InvoiceDeduction', + 'MatchedStatement', + 'ManualCorrected', + 'AuthorisationSchemeFee', + 'BankInstructionReturned', + 'InternalCompanyPayout', + 'EpaPaid', + 'BalanceTransfer', + 'PaymentCost', + 'SettleCost', + 'PaidOut', + 'PaidOutReversed', + ); + + public function __construct() { + $this->columnHeaders = array( + 'Company Account', + 'Merchant Account', + 'Psp Reference', + 'Merchant Reference', + 'Payment Method', + 'Creation Date', + 'TimeZone', + 'Type', + 'Modification Reference', + 'Gross Currency', + 'Gross Debit (GC)', + 'Gross Credit (GC)', + 'Exchange Rate', + 'Net Currency', + 'Net Debit (NC)', + 'Net Credit (NC)', + 'Commission (NC)', + 'Markup (NC)', + 'Scheme Fees (NC)', + 'Interchange (NC)', + 'Payment Method Variant', + 'Modification Merchant Reference', + 'Batch Number', + 'Reserved4', + 'Reserved5', + 'Reserved6', + 'Reserved7', + 'Reserved8', + 'Reserved9', + 'Reserved10', + ); + } + + // TODO base class this? + public function parseFile( $path ) { + $this->path = $path; + $this->file = fopen( $path, 'r' ); + + $ignoreLines = 1; + for ( $i = 0; $i < $ignoreLines; $i++ ) { + fgets( $this->file ); + } + + while ( $line = fgetcsv( $this->file, 0, ',', '"', '\\' ) ) { + try { + $this->parseLine( $line ); + } catch ( NormalizationException $ex ) { + // TODO: actually throw these below + Logger::error( $ex->getMessage() ); + } + } + fclose( $this->file ); + + return $this->fileData; + } + + protected function parseLine( $line ) { + $row = array_combine( $this->columnHeaders, $line ); + $type = $row['Type']; + if ( in_array( $type, self::$ignoredTypes ) ) { + return; + } + + $msg = array( + 'gateway' => 'adyen', + 'log_id' => $row['Merchant Reference'], + 'date' => $this->getDate( $row ), + ); + $parts = explode( '.', $row['Merchant Reference'] ); + $msg['contribution_tracking_id'] = $parts[0]; + + switch( $type ) { + case 'Settled': + $this->parseDonation( $row, $msg ); + break; + case 'Chargeback': + case 'Refunded': + $this->parseRefund( $row, $msg ); + break; + default: + throw new OutOfBoundsException( "Unknown audit line type {$row['Type']}." ); + } + + $this->fileData[] = $msg; + } + + protected function parseRefund( array $row, array &$msg ) { + $msg['gross'] = $row['Gross Debit (GC)']; // Actually paid to donor + $msg['gross_currency'] = $row['Gross Currency']; + // 'Net Debit (NC)' is the amount we paid including fees + // 'Net Currency' is the currency we paid in + // Deal with these when queue consumer can understand them + + $msg['gateway_parent_id'] = $row['Psp Reference']; + $msg['gateway_refund_id'] = $row['Modification Reference']; + if ( $row['Type'] === 'Chargeback' ) { + $msg['type'] = 'chargeback'; + } else { + $msg['type'] = 'refund'; + } + } + + protected function parseDonation( array $row, array &$msg ) { + $msg['gateway_txn_id'] = $row['Psp Reference']; + + $msg['currency'] = $row['Gross Currency']; + $msg['gross'] = $row['Gross Credit (GC)']; + // fee is given in settlement currency + // but queue consumer expects it in original + $exchange = $row['Exchange Rate']; + $fee = $row['Commission (NC)'] + + $row['Markup (NC)'] + + $row['Scheme Fees (NC)'] + + $row['Interchange (NC)']; + $msg['fee'] = round( $fee / $exchange, 2 ); + + // shouldn't this be settled_net or settled_amount? + $msg['settled_gross'] = $row['Net Credit (NC)']; + $msg['settled_currency'] = $row['Net Currency']; + $msg['settled_fee'] = $fee; + + list( $method, $submethod ) = ReferenceData::decodePaymentMethod( + $row['Payment Method'], $row['Payment Method Variant'] + ); + $msg['payment_method'] = $method; + $msg['payment_submethod'] = $submethod; + } + + protected function getDate( $row ) { + $local = $row['Creation Date']; + $zone = $row['TimeZone']; + return UtcDate::getUtcTimestamp( $local, $zone ); + } +} diff --git a/PaymentProviders/Adyen/ExpatriatedMessages/ReportAvailable.php b/PaymentProviders/Adyen/ExpatriatedMessages/ReportAvailable.php index 06189c7..d9996e4 100644 --- a/PaymentProviders/Adyen/ExpatriatedMessages/ReportAvailable.php +++ b/PaymentProviders/Adyen/ExpatriatedMessages/ReportAvailable.php @@ -2,7 +2,7 @@ use SmashPig\Core\Context; use SmashPig\Core\Logging\Logger; -use SmashPig\PaymentProviders\Adyen\Jobs\ProcessAccountingReportJob; +use SmashPig\PaymentProviders\Adyen\Jobs\DownloadReportJob; class ReportAvailable extends AdyenMessage { /** @@ -21,9 +21,9 @@ ); $jobQueueObj = Context::get()->getConfiguration()->obj( 'data-store/jobs' ); - if ( strpos( $this->pspReference, 'payments_accounting_report' ) === 0 ) { + if ( strpos( $this->pspReference, 'settlement_detail_report' ) === 0 ) { $jobQueueObj->addObject( - ProcessAccountingReportJob::factory( + DownloadReportJob::factory( $this->merchantAccountCode, $this->reason ) diff --git a/PaymentProviders/Adyen/Jobs/DownloadReportJob.php b/PaymentProviders/Adyen/Jobs/DownloadReportJob.php new file mode 100644 index 0000000..2f566c1 --- /dev/null +++ b/PaymentProviders/Adyen/Jobs/DownloadReportJob.php @@ -0,0 +1,84 @@ +<?php namespace SmashPig\PaymentProviders\Adyen\Jobs; + +use SmashPig\Core\Context; +use SmashPig\Core\DataFiles\HeadedCsvReader; +use SmashPig\Core\Logging\TaggedLogger; +use SmashPig\Core\SmashPigException; +use SmashPig\Core\Jobs\RunnableJob; + +/** + * Download Adyen settlement detail reports. These reports are named + * settlement_detail_report_batch_[n].csv + * + * @package SmashPig\PaymentProviders\Adyen\Jobs + */ +class DownloadReportJob extends RunnableJob { + + /** @var TaggedLogger */ + protected $logger; + + protected $account; + protected $reportUrl; + + protected $downloadLoc; + + public static function factory( $account, $url ) { + $obj = new DownloadReportJob(); + + $obj->account = $account; + $obj->reportUrl = $url; + + return $obj; + } + + public function execute() { + $this->logger = new TaggedLogger( __CLASS__ ); + $c = Context::get()->getConfiguration(); + + // Construct the temporary file path + $fileName = basename( $this->reportUrl ); + $this->downloadLoc = + $c->val( "payment-provider/adyen/accounts/{$this->account}/report-location" ) . '/' . + $fileName; + + $user = $c->val( "payment-provider/adyen/accounts/{$this->account}/report-username" ); + $pass = $c->val( "payment-provider/adyen/accounts/{$this->account}/report-password" ); + + $this->logger->info( + "Beginning report download from {$this->reportUrl} using username {$user} into {$this->downloadLoc}" + ); + + $fp = fopen( $this->downloadLoc, 'w' ); + if ( !$fp ) { + $str = "Could not open {$this->downloadLoc} for writing! Will not download report."; + $this->logger->error( $str ); + throw new SmashPigException( $str ); + } + + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, $this->reportUrl); + + curl_setopt($ch, CURLOPT_RETURNTRANSFER, false); + curl_setopt($ch, CURLOPT_FILE, $fp ); + + curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); + + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true); + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); + curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_ANY ); + curl_setopt($ch, CURLOPT_USERPWD, "{$user}:{$pass}" ); + + $result = curl_exec($ch); + $httpCode = curl_getinfo( $ch, CURLINFO_HTTP_CODE ); + $error = curl_error( $ch ); + curl_close( $ch ); + + if ( $result === false ) { + $this->logger->error( "Could not download report due to cURL error {$error}" ); + throw new SmashPigException( "Could not download report." ); + } elseif ( $httpCode !== 200 ) { + $this->logger->error( "Report downloaded(?), but with incorrect HTTP code: {$httpCode}" ); + throw new SmashPigException( "Could not download report." ); + } + } +} diff --git a/PaymentProviders/Adyen/Jobs/ProcessAccountingReportJob.php b/PaymentProviders/Adyen/Jobs/ProcessAccountingReportJob.php deleted file mode 100644 index 4366ed9..0000000 --- a/PaymentProviders/Adyen/Jobs/ProcessAccountingReportJob.php +++ /dev/null @@ -1,150 +0,0 @@ -<?php namespace SmashPig\PaymentProviders\Adyen\Jobs; - -use SmashPig\Core\Context; -use SmashPig\Core\DataFiles\HeadedCsvReader; -use SmashPig\Core\Logging\TaggedLogger; -use SmashPig\Core\SmashPigException; -use SmashPig\Core\Jobs\RunnableJob; - -/** - * Process Adyen end of day payment reports. These reports are named - * payments_accounting_report_[yyyy]_[mm]_[dd].csv - * - * @package SmashPig\PaymentProviders\Adyen\Jobs - */ -class ProcessAccountingReportJob extends RunnableJob { - - /** @var TaggedLogger */ - protected $logger; - - protected $account; - protected $reportUrl; - - protected $downloadLoc; - - public static function factory( $account, $url ) { - $obj = new ProcessAccountingReportJob(); - - $obj->account = $account; - $obj->reportUrl = $url; - - return $obj; - } - - public function execute() { - $this->logger = new TaggedLogger( __CLASS__ ); - $c = Context::get()->getConfiguration(); - - // Construct the temporary file path - $fileName = basename( $this->reportUrl ); - $this->downloadLoc = - $c->val( "payment-provider/adyen/accounts/{$this->account}/report-location" ) . '/' . - $fileName; - - // Actually get the file - $this->downloadLog(); - - // Now iterate through; finding all the ones marked Authorised and SentForSettle - // The Authorised entries at the end that do not have a SentForSettle need to be - // reviewed in the payment console. - // TODO: we should confirm settled transactions like the rest of the - // audit parsers. - $this->logger->debug( "Finding uncaptured authorizations" ); - $f = new HeadedCsvReader( $this->downloadLoc ); - $tempQueue = array(); - - foreach ( $f as $row ) { - switch ( $f->extractCol( 'Record Type', $row ) ) { - case 'Authorised': - $tempQueue[$f->extractCol( 'Psp Reference', $row )] = $row; - break; - - case 'SentForSettle': - unset( $tempQueue[$f->extractCol( 'Psp Reference', $row )] ); - // TODO: Audit this row; probably send it to an audit queue - break; - - default: - // Don't care :) - break; - } - } - - $tqc = count( $tempQueue ); - $this->logger->debug( - "Of {$f->key()} rows, {$tqc} need to be reprocessed.", - array( 'headers' => $f->headers(), 'values' => $tempQueue ) - ); - - foreach ( $tempQueue as $pspRef => $row ) { - $correlationId = 'adyen-' . $f->extractCol( 'Merchant Reference', $row ); - $this->logger->enterContext( "$correlationId" ); - - $currency = $f->extractCol( 'Payment Currency', $row ); - $amount = floatval( $f->extractCol( 'Authorised (PC)', $row ) ); - $account = $f->extractCol( 'Merchant Account', $row ); - - $this->logger->info( - "Please review authorization for {$currency} {$amount} with id {$correlationId} and " . - "psp reference {$pspRef}." - ); - - $this->logger->leaveContext(); // Must be the last line in this loop - } - - // OK; we're done here, move the file to the archive folder - try { - $archiveLocation = - $c->val( "payment-provider/adyen/accounts/{$this->account}/report-archive-location" ); - rename( $this->downloadLoc, $archiveLocation . '/' . $fileName ); - } catch ( ConfigurationKeyException $ex ) { - $this->logger->warning( 'Report archive location not configured!' ); - } - - return true; - } - - protected function downloadLog() { - $c = Context::get()->getConfiguration(); - - $user = $c->val( "payment-provider/adyen/accounts/{$this->account}/report-username" ); - $pass = $c->val( "payment-provider/adyen/accounts/{$this->account}/report-password" ); - - $this->logger->info( - "Beginning log download from {$this->reportUrl} using username {$user} into {$this->downloadLoc}" - ); - - $fp = fopen( $this->downloadLoc, 'w' ); - if ( !$fp ) { - $str = "Could not open {$this->downloadLoc} for writing! Will not download/process report."; - $this->logger->error( $str ); - throw new SmashPigException( $str ); - } - - $ch = curl_init(); - curl_setopt($ch, CURLOPT_URL, $this->reportUrl); - - curl_setopt($ch, CURLOPT_RETURNTRANSFER, false); - curl_setopt($ch, CURLOPT_FILE, $fp ); - - curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); - - curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true); - curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); - curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_ANY ); - curl_setopt($ch, CURLOPT_USERPWD, "{$user}:{$pass}" ); - - $result = curl_exec($ch); - $httpCode = curl_getinfo( $ch, CURLINFO_HTTP_CODE ); - $error = curl_error( $ch ); - curl_close( $ch ); - - if ( $result === false ) { - $this->logger->error( "Could not download report due to cURL error {$error}" ); - throw new SmashPigException( "Could not download report." ); - } elseif ( $httpCode !== 200 ) { - $this->logger->error( "Report downloaded(?), but with incorrect HTTP code: {$httpCode}" ); - throw new SmashPigException( "Could not download report." ); - } - } -} diff --git a/PaymentProviders/Adyen/ReferenceData.php b/PaymentProviders/Adyen/ReferenceData.php new file mode 100644 index 0000000..872dea7 --- /dev/null +++ b/PaymentProviders/Adyen/ReferenceData.php @@ -0,0 +1,104 @@ +<?php namespace SmashPig\PaymentProviders\Adyen; + +use OutOfBoundsException; + +class ReferenceData { + + static $methods = array( + 'alipay' => array( + 'method' => 'ew', + 'submethod' => 'ew_alipay', + ), + 'amex' => array( + 'method' => 'cc', + 'submethod' => 'amex', + ), + // International Bank Transfer (IBAN) + 'banktransfer_IBAN' => array( + 'method' => 'bt', + 'submethod' => 'iban', + ), + // China Union Pay + 'cup' => array( + 'method' => 'cc', + 'submethod' => 'cup', + ), + 'diners' => array( + 'method' => 'cc', + 'submethod' => 'dc', + ), + // Sofortüberweisung + 'directEbanking' => array( + 'method' => 'rtbt', + 'submethod' => 'rtbt_sofortuberweisung', + ), + 'discover' => array( + 'method' => 'cc', + 'submethod' => 'discover', + ), + 'dotpay' => array( + 'method' => 'ew', + 'submethod' => 'ew_dotpay', + ), + 'ideal' => array( + 'method' => 'rtbt', + 'submethod' => 'rtbt_ideal', + ), + 'mc' => array( + 'method' => 'cc', + 'submethod' => 'mc', + 'variants' => array( + 'mcdebit' => 'mc-debit', + ), + ), + 'multibanco' => array( + 'method' => 'rtbt', + 'submethod' => 'rtbt_multibanco', + ), + 'safetypay' => array( + 'method' => 'rtbt', + 'submethod' => 'rtbt_safetypay', + ), + 'sepadirectdebit' => array( + 'method' => 'dd', + 'submethod' => 'dd_sepa', + ), + 'tenpay' => array( + 'method' => 'ew', + 'submethod' => 'ew_tenpay', + ), + 'trustly' => array( + 'method' => 'obt', + 'submethod' => 'trustly', + ), + 'visa' => array( + 'method' => 'cc', + 'submethod' => 'visa', + 'variants' => array( + 'visabeneficial' => 'visa-beneficial', // guessing at Adyen code + 'visadebit' => 'visa-debit', + 'visaelectron' => 'visa-electron', // guessing at Adyen code + ) + ), + ); + + /** + * @param string $method Adyen's 'Payment Method' + * @param string $variant Adyen's 'Payment Method Variant' + * @returns array first entry is our payment_method, second is our payment_submethod + */ + public static function decodePaymentMethod( $method, $variant ) { + if ( !array_key_exists( $method, self::$methods ) ) { + throw new OutOfBoundsException( "Unknown Payment Method $method " ); + } + $entry = self::$methods[$method]; + $ourMethod = $entry['method']; + if ( $variant && array_key_exists( 'variants', $entry ) && + array_key_exists( $variant, $entry['variants'] ) ) { + $ourSubmethod = $entry['variants'][$variant]; + } else { + $ourSubmethod = $entry['submethod']; + } + return array( $ourMethod, $ourSubmethod ); + } +} \ No newline at end of file diff --git a/PaymentProviders/Adyen/Tests/Data/chargeback.csv b/PaymentProviders/Adyen/Tests/Data/chargeback.csv new file mode 100644 index 0000000..66dfe8f --- /dev/null +++ b/PaymentProviders/Adyen/Tests/Data/chargeback.csv @@ -0,0 +1,4 @@ +Company Account,Merchant Account,Psp Reference,Merchant Reference,Payment Method,Creation Date,TimeZone,Type,Modification Reference,Gross Currency,Gross Debit (GC),Gross Credit (GC),Exchange Rate,Net Currency,Net Debit (NC),Net Credit (NC),Commission (NC),Markup (NC),Scheme Fees (NC),Interchange (NC),Payment Method Variant,Modification Merchant Reference,Batch Number,Reserved4,Reserved5,Reserved6,Reserved7,Reserved8,Reserved9,Reserved10 +Wikimedia,WikimediaCOM,4555568860022701,92598318.0,visa,2016-02-10 10:25:36,PST,Chargeback,4555568869855336,USD,1.00,,1,USD,3.00,,2.00,,,,visaclassic,,3,,,,,,, +Wikimedia,WikimediaCOM,,,,2016-02-15 21:29:37,PST,Fee,Transaction Fees February 2016,EUR,,,,USD,1.80,,,,,,,,3,,,,,,, +Wikimedia,WikimediaCOM,,,,2016-02-15 21:29:37,PST,MerchantPayout,"TX3488899933XT batch 3, WikimediaCOM batch 3, WikimediaCOM",EUR,,,,USD,4.03,,,,,,,,3,,,,,,, diff --git a/PaymentProviders/Adyen/Tests/Data/donation.csv b/PaymentProviders/Adyen/Tests/Data/donation.csv new file mode 100644 index 0000000..e21deef --- /dev/null +++ b/PaymentProviders/Adyen/Tests/Data/donation.csv @@ -0,0 +1,3 @@ +Company Account,Merchant Account,Psp Reference,Merchant Reference,Payment Method,Creation Date,TimeZone,Type,Modification Reference,Gross Currency,Gross Debit (GC),Gross Credit (GC),Exchange Rate,Net Currency,Net Debit (NC),Net Credit (NC),Commission (NC),Markup (NC),Scheme Fees (NC),Interchange (NC),Payment Method Variant,Modification Merchant Reference,Batch Number,Reserved4,Reserved5,Reserved6,Reserved7,Reserved8,Reserved9,Reserved10 +Wikimedia,WikimediaCOM,5364893193133131,33992337.0,visa,2016-02-18 16:10:51,PST,Settled,5364893193133131,USD,,1.00,1,USD,,0.76,,,0.02,0.22,visadebit,,2,,,,,,, +Wikimedia,WikimediaCOM,,,,2016-02-18 19:53:26,PST,MerchantPayout,"TX2342222277XT batch 2, WikimediaCOM batch 2, WikimediaCOM",EUR,,,,USD,0.76,,,,,,,,2,,,,,,, diff --git a/PaymentProviders/Adyen/Tests/Data/refund.csv b/PaymentProviders/Adyen/Tests/Data/refund.csv new file mode 100644 index 0000000..ba36903 --- /dev/null +++ b/PaymentProviders/Adyen/Tests/Data/refund.csv @@ -0,0 +1,4 @@ +Company Account,Merchant Account,Psp Reference,Merchant Reference,Payment Method,Creation Date,TimeZone,Type,Modification Reference,Gross Currency,Gross Debit (GC),Gross Credit (GC),Exchange Rate,Net Currency,Net Debit (NC),Net Credit (NC),Commission (NC),Markup (NC),Scheme Fees (NC),Interchange (NC),Payment Method Variant,Modification Merchant Reference,Batch Number,Reserved4,Reserved5,Reserved6,Reserved7,Reserved8,Reserved9,Reserved10 +Wikimedia,WikimediaCOM,4522268860022701,92598312.0,visa,2016-02-10 10:25:36,PST,Refunded,4522268869855336,USD,1.00,,1,USD,1.00,,,,,,visaclassic,92598312.0,3,,,,,,, +Wikimedia,WikimediaCOM,,,,2016-02-15 21:29:37,PST,Fee,Transaction Fees February 2016,EUR,,,,USD,1.80,,,,,,,,3,,,,,,, +Wikimedia,WikimediaCOM,,,,2016-02-15 21:29:37,PST,MerchantPayout,"TX3488899933XT batch 3, WikimediaCOM batch 3, WikimediaCOM",EUR,,,,USD,4.03,,,,,,,,3,,,,,,, diff --git a/PaymentProviders/Adyen/Tests/phpunit/AuditTest.php b/PaymentProviders/Adyen/Tests/phpunit/AuditTest.php new file mode 100644 index 0000000..f94d4d5 --- /dev/null +++ b/PaymentProviders/Adyen/Tests/phpunit/AuditTest.php @@ -0,0 +1,78 @@ +<?php namespace SmashPig\PaymentProviders\Adyen\Test; + +use SmashPig\PaymentProviders\Adyen\Audit\AdyenAudit; + +/** + * Verify Adyen audit file processor functions + */ +class AuditTest extends \BaseSmashPigUnitTestCase { + /** + * Normal donation + */ + public function testProcessDonation() { + $processor = new AdyenAudit(); + $output = $processor->parseFile( __DIR__ . '/../Data/donation.csv' ); + $this->assertEquals( 1, count( $output ), 'Should have found one donation' ); + $actual = $output[0]; + $expected = array( + 'gateway' => 'adyen', + 'gross' => '1.00', + 'contribution_tracking_id' => '33992337', + 'currency' => 'USD', + 'gateway_txn_id' => '5364893193133131', + 'log_id' => '33992337.0', + 'payment_method' => 'cc', + 'payment_submethod' => 'visa-debit', + 'date' => 1455840651, + 'settled_currency' => 'USD', + 'fee' => '0.24', + 'settled_gross' => '0.76', + 'settled_fee' => '0.24', + ); + $this->assertEquals( $expected, $actual, 'Did not parse donation correctly' ); + } + + /** + * Now try a refund + */ + public function testProcessRefund() { + $processor = new AdyenAudit(); + $output = $processor->parseFile( __DIR__ . '/../Data/refund.csv' ); + $this->assertEquals( 1, count( $output ), 'Should have found one refund' ); + $actual = $output[0]; + $expected = array( + 'gateway' => 'adyen', + 'contribution_tracking_id' => '92598312', + 'date' => 1455128736, + 'gross' => '1.00', + 'gateway_parent_id' => '4522268860022701', + 'gateway_refund_id' => '4522268869855336', + 'gross_currency' => 'USD', + 'log_id' => '92598312.0', + 'type' => 'refund', + ); + $this->assertEquals( $expected, $actual, 'Did not parse refund correctly' ); + } + + /** + * And a chargeback + */ + public function testProcessChargeback() { + $processor = new AdyenAudit(); + $output = $processor->parseFile( __DIR__ . '/../Data/chargeback.csv' ); + $this->assertEquals( 1, count( $output ), 'Should have found one chargeback' ); + $actual = $output[0]; + $expected = array( + 'gateway' => 'adyen', + 'contribution_tracking_id' => '92598318', + 'date' => 1455128736, + 'gross' => '1.00', + 'gateway_parent_id' => '4555568860022701', + 'gateway_refund_id' => '4555568869855336', + 'gross_currency' => 'USD', + 'log_id' => '92598318.0', + 'type' => 'chargeback', + ); + $this->assertEquals( $expected, $actual, 'Did not parse chargeback correctly' ); + } +} diff --git a/config_defaults.php b/config_defaults.php index 5abbb66..841294a 100644 --- a/config_defaults.php +++ b/config_defaults.php @@ -126,8 +126,7 @@ * The ws- credentials should be a user authorized to make * API calls, and the report- credentials should be a user * authorized to download reports. Reports will be - * downloaded to the location specified in report-location - * and moved to report-archive-location after processing. + * downloaded to the location specified in report-location. * * At least one account and all subkeys are required. * @@ -137,7 +136,6 @@ * 'report-username' => '', * 'report-password' => '', * 'report-location' => '/tmp', - * 'report-archive-location' => '/var/spool/audit/adyen/completed', * ) **/ ), diff --git a/phpunit.xml b/phpunit.xml index 6a7c8e0..01a15ec 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -4,6 +4,9 @@ bootstrap="Tests/bootstrap-phpunit.php"> <testsuites> + <testsuite name="Adyen tests"> + <directory>PaymentProviders/Adyen/Tests/phpunit</directory> + </testsuite> <testsuite name="Amazon tests"> <directory>PaymentProviders/Amazon/Tests/phpunit</directory> </testsuite> -- To view, visit https://gerrit.wikimedia.org/r/270457 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: merged Gerrit-Change-Id: Icbdbe3fa2c0537c622a4621095527b3d4a7c1769 Gerrit-PatchSet: 7 Gerrit-Project: wikimedia/fundraising/SmashPig Gerrit-Branch: master Gerrit-Owner: Cdentinger <cdentin...@wikimedia.org> Gerrit-Reviewer: Awight <awi...@wikimedia.org> Gerrit-Reviewer: Cdentinger <cdentin...@wikimedia.org> Gerrit-Reviewer: Ejegg <eeggles...@wikimedia.org> Gerrit-Reviewer: XenoRyet <dkozlow...@wikimedia.org> Gerrit-Reviewer: jenkins-bot <> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits