jenkins-bot has submitted this change and it was merged. ( https://gerrit.wikimedia.org/r/370225 )
Change subject: Orphan Slayer Module ...................................................................... Orphan Slayer Module Change-Id: I1b3d1ac329ff225fdc00bf2fc534114fac617343 --- M composer.lock M phpunit.xml A sites/all/modules/orphan_slayer/OrphanSlayer.php R sites/all/modules/orphan_slayer/globalcollect/orphan_rectify.drush.inc A sites/all/modules/orphan_slayer/orphan_slayer.drush.inc A sites/all/modules/orphan_slayer/orphan_slayer.info A sites/all/modules/orphan_slayer/orphan_slayer.module A sites/all/modules/orphan_slayer/tests/phpunit/OrphanSlayerTest.php M sites/default/bootstrap-phpunit.php M sites/default/enabled_modules 10 files changed, 224 insertions(+), 13 deletions(-) Approvals: jenkins-bot: Verified Ejegg: Looks good to me, approved diff --git a/composer.lock b/composer.lock index 9ed29b5..61952fa 100644 --- a/composer.lock +++ b/composer.lock @@ -2576,16 +2576,16 @@ }, { "name": "phpdocumentor/reflection-common", - "version": "1.0", + "version": "1.0.1", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionCommon.git", - "reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c" + "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/144c307535e82c8fdcaacbcfc1d6d8eeb896687c", - "reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6", + "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6", "shasum": "" }, "require": { @@ -2626,7 +2626,7 @@ "reflection", "static analysis" ], - "time": "2015-12-27T11:43:31+00:00" + "time": "2017-09-11T18:02:19+00:00" }, { "name": "phpdocumentor/reflection-docblock", @@ -2722,22 +2722,22 @@ }, { "name": "phpspec/prophecy", - "version": "v1.7.0", + "version": "v1.7.2", "source": { "type": "git", "url": "https://github.com/phpspec/prophecy.git", - "reference": "93d39f1f7f9326d746203c7c056f300f7f126073" + "reference": "c9b8c6088acd19d769d4cc0ffa60a9fe34344bd6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/93d39f1f7f9326d746203c7c056f300f7f126073", - "reference": "93d39f1f7f9326d746203c7c056f300f7f126073", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/c9b8c6088acd19d769d4cc0ffa60a9fe34344bd6", + "reference": "c9b8c6088acd19d769d4cc0ffa60a9fe34344bd6", "shasum": "" }, "require": { "doctrine/instantiator": "^1.0.2", "php": "^5.3|^7.0", - "phpdocumentor/reflection-docblock": "^2.0|^3.0.2", + "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0", "sebastian/comparator": "^1.1|^2.0", "sebastian/recursion-context": "^1.0|^2.0|^3.0" }, @@ -2748,7 +2748,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.6.x-dev" + "dev-master": "1.7.x-dev" } }, "autoload": { @@ -2781,7 +2781,7 @@ "spy", "stub" ], - "time": "2017-03-02T20:05:34+00:00" + "time": "2017-09-04T11:05:03+00:00" }, { "name": "phpunit/php-code-coverage", diff --git a/phpunit.xml b/phpunit.xml index 06e7423..1a40ebf 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -15,6 +15,9 @@ <testsuite name="exchange_rates tests"> <directory>sites/all/modules/exchange_rates/tests/phpunit</directory> </testsuite> + <testsuite name="orphan_slayer tests"> + <directory>sites/all/modules/orphan_slayer/tests/phpunit</directory> + </testsuite> <testsuite name="queue2civicrm tests"> <directory>sites/all/modules/queue2civicrm/tests/phpunit</directory> </testsuite> diff --git a/sites/all/modules/orphan_slayer/OrphanSlayer.php b/sites/all/modules/orphan_slayer/OrphanSlayer.php new file mode 100644 index 0000000..639eb2b --- /dev/null +++ b/sites/all/modules/orphan_slayer/OrphanSlayer.php @@ -0,0 +1,34 @@ +<?php + +use SmashPig\Core\DataStores\PendingDatabase; + +class OrphanSlayer { + public $gateway; + protected $adapter; + + public function __construct($gateway) { + $this->gateway = $gateway; + } + + public function get_oldest() { + return PendingDatabase::get()->fetchMessageByGatewayOldest($this->gateway); + } + + public function rectify($orphan) { + $orphan['amount'] = $orphan['gross']; + $this->adapter = DonationInterfaceFactory::createAdapter($this->gateway, $orphan); + $result = $this->adapter->rectifyOrphan(); + $this->delete_orphan($orphan); + return $result; + } + + public function cancel($orphan) { + //FIXME: Add cancel when implementing ingenico + $this->delete_orphan($orphan); + } + + protected function delete_orphan($orphan) { + PendingDatabase::get()->deleteMessage($orphan); + } + +} diff --git a/sites/all/modules/wmf_audit/ingenico/orphan_rectify.drush.inc b/sites/all/modules/orphan_slayer/globalcollect/orphan_rectify.drush.inc similarity index 100% rename from sites/all/modules/wmf_audit/ingenico/orphan_rectify.drush.inc rename to sites/all/modules/orphan_slayer/globalcollect/orphan_rectify.drush.inc diff --git a/sites/all/modules/orphan_slayer/orphan_slayer.drush.inc b/sites/all/modules/orphan_slayer/orphan_slayer.drush.inc new file mode 100644 index 0000000..4eb6633 --- /dev/null +++ b/sites/all/modules/orphan_slayer/orphan_slayer.drush.inc @@ -0,0 +1,65 @@ +<?php +/** + * Detect and rectify recently orphaned Gateway transactions + */ + +/** + * Implementation of hook_drush_command() + */ +function orphan_slayer_drush_command() { + $items = array(); + + $items['orphan-slayer'] = array( + 'description' => + 'Check for orphaned Gateway transactions, and resolve.', + 'examples' => array( + 'drush orphan-slay' => '# Run the orphan rectifier.', + ), + 'required-arguments' => 'true', + 'arguments' => array( + 'gateway' => 'gateway', + ), + 'options' => array( + 'time' => 'time' + ) + ); + + return $items; +} + +/** + * Implementation of hook_drush_help() + */ +function orphan_slayer_drush_help($section) { + switch ($section) { + case 'orphan_slayer': + return dt("Check for orphaned transactions, and resolve."); + } +} + +/** + * Note: You'll need to include a bunch of exciting MediaWiki globals in your + * Drupal settings.local.php, including default values that would normally be + * read from extension.json. + * $wgDonationInterfaceGatewayAdapters + * $wgDonationInterfaceForbiddenCountries + * $wgDonationInterface3DSRules + * $wgDonationInterfacePriceFloor + * $wgDonationInterfacePriceCeiling + * $wgDonationInterfaceRetryLoopCount + * For any gateways implemented, set these globals, replacing name with the gateway identifier + * $wg[name]GatewayEnabled + * $wg[name]GatewayAccountInfo + * $wg[name]GatewayURL + + */ +function drush_orphan_slayer() { + // TODO: SmashPig and DI initialization should be reused from a higher + // level and integrated with app config + $args = drush_get_arguments(); + $gateway = $args[1]; + $time = drush_get_option('time', '30'); + + wmf_common_create_smashpig_context("gateway_orphan_slayer", "$gateway"); + orphan_slayer_process_orphans($gateway, $time); +} diff --git a/sites/all/modules/orphan_slayer/orphan_slayer.info b/sites/all/modules/orphan_slayer/orphan_slayer.info new file mode 100644 index 0000000..1b23ca4 --- /dev/null +++ b/sites/all/modules/orphan_slayer/orphan_slayer.info @@ -0,0 +1,5 @@ +name = Orphan Slayer +description = Drush command to find what happened to orphaned transactions +core = 7.x +dependencies[] = wmf_civicrm +files[] = OrphanSlayer.php diff --git a/sites/all/modules/orphan_slayer/orphan_slayer.module b/sites/all/modules/orphan_slayer/orphan_slayer.module new file mode 100644 index 0000000..0a13435 --- /dev/null +++ b/sites/all/modules/orphan_slayer/orphan_slayer.module @@ -0,0 +1,18 @@ +<?php + +use \SmashPig\Core\UtcDate; + +function orphan_slayer_process_orphans($gateway, $time = 30) +{ + $slayer = new OrphanSlayer($gateway); + $orphan = $slayer->get_oldest(); + while ($orphan && ($orphan['date'] < UtcDate::getUtcTimestamp("-$time minutes"))) { + if ($orphan['contribution_tracking_id']) { + $result = $slayer->rectify($orphan); + watchdog('orphan slayer', 'orphan ' .$orphan['contribution_tracking_id'] . ': was rectified and the result is ' . print_r($result, true)); + } else { + $slayer->cancel($orphan); + } + $orphan = $slayer->get_oldest(); + } +} diff --git a/sites/all/modules/orphan_slayer/tests/phpunit/OrphanSlayerTest.php b/sites/all/modules/orphan_slayer/tests/phpunit/OrphanSlayerTest.php new file mode 100644 index 0000000..04efe0b --- /dev/null +++ b/sites/all/modules/orphan_slayer/tests/phpunit/OrphanSlayerTest.php @@ -0,0 +1,84 @@ +<?php + +use SmashPig\Core\Context; +use SmashPig\Tests\TestingContext; +use SmashPig\Tests\TestingGlobalConfiguration; +use SmashPig\Core\DataStores\PendingDatabase; + +/** + * @group OrphanSlayer + */ + +class OrphanSlayerTest extends PHPUnit_Framework_TestCase { + + public function setUp() { + parent::setUp(); + + // Initialize SmashPig with a fake context object + $config = TestingGlobalConfiguration::create(); + TestingContext::init( $config ); + + if ( !defined( 'DRUPAL_ROOT' ) ) { + throw new Exception( "Define DRUPAL_ROOT somewhere before running unit tests." ); + } + + global $user, $_exchange_rate_cache; + $GLOBALS['_PEAR_default_error_mode'] = NULL; + $GLOBALS['_PEAR_default_error_options'] = NULL; + $_exchange_rate_cache = array(); + + $user = new stdClass(); + $user->name = "foo_who"; + $user->uid = "321"; + $user->roles = array( DRUPAL_AUTHENTICATED_RID => 'authenticated user' ); + } + + public function tearDown() { + Context::set( null ); // Nullify any SmashPig context for the next run + parent::tearDown(); + } + + + public function testGetOldest(){ + $slayer = new OrphanSlayer('paypal_ec'); + $orphan = $this->createTestOrphan('paypal_ec'); + $result = $slayer->get_oldest(); + $this->assertEquals($orphan['contribution_tracking_id'], $result['contribution_tracking_id'], "Cannot get orphan"); + PendingDatabase::get()->deleteMessage([$orphan]); + } + + public function testrectify() { + $slayer = new OrphanSlayer('paypal_ec'); + $orphan = $this->createTestOrphan($slayer->gateway); + TestingPaypalExpressAdapter::setDummyGatewayResponseCode('OK'); + $result = $slayer->rectify($orphan); + $this->assertEquals(array(), $result->getErrors(), "rectify_orphan returned errors: " . print_r($result->getErrors(), true)); + $result = PendingDatabase::get()->fetchMessageByGatewayOrderId( 'paypal_ec', $orphan['order_id'] ); + $this->assertEquals($result, null, "Orphan was not deleted"); + } + + protected function createTestOrphan($gateway = 'test'){ + $uniq = mt_rand(); + $message = array( + 'contribution_tracking_id' => $uniq, + 'country' => 'US', + 'first_name' => 'Flighty', + 'last_name' => 'Dono', + 'email' => 'test+...@eff.org', + 'gateway' => $gateway, + 'gateway_txn_id' => "txn-{$uniq}", + 'gateway_session_id' => mt_rand(), + 'order_id' => "order-{$uniq}", + 'gateway_account' => 'default', + 'payment_method' => 'paypal', + 'payment_submethod' => 'mc', + // Defaults to a magic 25 minutes ago, within the process window. + 'date' => time() - 25 * 60, + 'gross' => 123, + 'currency' => 'EUR', + ); + + PendingDatabase::get()->storeMessage($message); + return $message; + } +} diff --git a/sites/default/bootstrap-phpunit.php b/sites/default/bootstrap-phpunit.php index e7f2b26..e7262b4 100644 --- a/sites/default/bootstrap-phpunit.php +++ b/sites/default/bootstrap-phpunit.php @@ -18,6 +18,7 @@ // Load contrib libs so tests can inherit from them. require_once( DRUPAL_ROOT . '/../vendor/autoload.php' ); // And explicitly load some DonationInterface things that it doesn't export via Composer +require_once(DRUPAL_ROOT . '/../vendor/wikimedia/donation-interface/tests/phpunit/TestConfiguration.php'); require_once( DRUPAL_ROOT . '/../vendor/wikimedia/donation-interface/tests/phpunit/includes/test_gateway/test.adapter.php' ); require_once( DRUPAL_ROOT . '/../vendor/wikimedia/donation-interface/tests/phpunit/includes/test_gateway/TestingGlobalCollectAdapter.php' ); require_once( DRUPAL_ROOT . '/../vendor/wikimedia/donation-interface/tests/phpunit/includes/test_gateway/TestingGlobalCollectOrphanAdapter.php' ); @@ -27,5 +28,5 @@ require_once DRUPAL_ROOT . '/sites/default/civicrm/extensions/org.wikimedia.omnimail/tests/phpunit/bootstrap.php'; if ( !defined( 'PRINT_WATCHDOG_ON_TEST_FAIL' ) ) { - define( 'PRINT_WATCHDOG_ON_TEST_FAIL', true ); + define( 'PRINT_WATCHDOG_ON_TEST_FAIL', true ); } diff --git a/sites/default/enabled_modules b/sites/default/enabled_modules index 168aae4..b49e4e0 100644 --- a/sites/default/enabled_modules +++ b/sites/default/enabled_modules @@ -16,6 +16,7 @@ oauth_common oauth_common_providerui offline2civicrm +orphan_slayer queue2civicrm recurring recurring_globalcollect -- To view, visit https://gerrit.wikimedia.org/r/370225 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: merged Gerrit-Change-Id: I1b3d1ac329ff225fdc00bf2fc534114fac617343 Gerrit-PatchSet: 36 Gerrit-Project: wikimedia/fundraising/crm Gerrit-Branch: master Gerrit-Owner: Mepps <me...@wikimedia.org> Gerrit-Reviewer: Ejegg <ej...@ejegg.com> Gerrit-Reviewer: Mepps <me...@wikimedia.org> Gerrit-Reviewer: jenkins-bot <> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits