From d966b778602784c8cc0070f7a3143615ca4ddd2e Mon Sep 17 00:00:00 2001 From: Rich Lott / Artful Robot Date: Fri, 22 Oct 2021 12:36:53 +0100 Subject: [PATCH] Add tests to Order create re memberships --- tests/phpunit/api/v3/OrderTest.php | 128 +++++++++++++++++++++++++++-- 1 file changed, 119 insertions(+), 9 deletions(-) diff --git a/tests/phpunit/api/v3/OrderTest.php b/tests/phpunit/api/v3/OrderTest.php index 4fff5e9c51..3556439553 100644 --- a/tests/phpunit/api/v3/OrderTest.php +++ b/tests/phpunit/api/v3/OrderTest.php @@ -39,6 +39,9 @@ class api_v3_OrderTest extends CiviUnitTestCase { public $debug = 0; + protected static $phpunitStartedDate; + protected static $skipStatusCalStillExists; + /** * Setup function. * @@ -323,12 +326,38 @@ class api_v3_OrderTest extends CiviUnitTestCase { * @throws \CRM_Core_Exception * * @param array $membershipExtraParams Optional additional params for the membership, - * e.g. skipStatusCal or start_date + * e.g. skipStatusCal or start_date. This can also have a 'renewalOf' key, in which + * case we'll create an existing membership based on the values therein and try to renew it. * @param ?string $paymentDate - if set, a payment will be made on that date, completing the order. (Not implemented yet) * @param array $expectations */ public function testAddOrderForMembershipWithDates(array $membershipExtraParams, ?string $paymentDate, array $expectations): void { + if (date('Y-m-d') > static::$phpunitStartedDate) { + $this->markTestSkipped("Test run spanned 2 days so skipping test as results would be affected"); + } + if (date('Hi') > '2357') { + $this->markTestSkipped("It‘s less than 2 mins to midnight, test skipped as 'today' may change during test."); + } + if (isset($membershipExtraParams['skipStatusCal']) && !$this->skipStatusCalStillExists()) { + $this->markTestSkipped("The test was skipped as skipStatusCal seems to have been removed, so this test is useless and should be removed."); + } + $membershipType = $this->membershipTypeCreate(); + + if (isset($membershipExtraParams['renewalOf'])) { + // Create a pre-existing membership + $originalMembershipID = $this->callAPISuccess('Membership', 'create', + $membershipExtraParams['renewalOf'] + + [ + 'contact_id' => $this->_individualId, + 'membership_type_id' => $membershipType, + 'source' => 'Old', + ])['id']; + unset($membershipExtraParams['renewalOf']); + // To make this Order a renewal, we provide the ID of the membership. + $membershipExtraParams['id'] = $originalMembershipID; + } + // Use the 2nd and last price field value defined in the fixture, which has value 200 $priceFieldValue = end($this->createPriceSet()['values']); $orderCreateParams = [ @@ -372,28 +401,109 @@ class api_v3_OrderTest extends CiviUnitTestCase { ]; $this->checkPaymentResult($order, $expectedResult); + // If we are to make a payment to complete this order, do that now. + if ($paymentDate) { + $paymentCreateResult = $this->callAPISuccess('Payment', 'create', [ + 'contribution_id' => $order['id'], + 'total_amount' => 200, + 'trxn_date' => $paymentDate, + 'is_send_contribution_notification' => FALSE, + ]); + // Reload the order, check it's now completed. + $order = $this->callAPISuccess('Order', 'get', ['id' => $order['id']]); + $expectedResult[$order['id']]['contribution_status'] = 'Completed'; + $this->checkPaymentResult($order, $expectedResult); + } + + // Check membership details $membershipPayment = $this->callAPISuccessGetSingle('MembershipPayment', ['contribution_id' => $order['id']]); $membership = $this->callAPISuccessGetSingle('Membership', ['id' => $membershipPayment['id']]); - // Check membership dates automatically added + if (isset($expectations['status_id'])) { + $membership['status_id'] = \CRM_Member_PseudoConstant::membershipstatus()[$membership['status_id']]; + } + $actuals = []; foreach ($expectations as $field => $expectedValue) { - $this->assertEquals($expectedValue, $membership[$field] ?? NULL, "Expected $field of membership to be $expectedValue"); + $actuals[$field] = $membership[$field] ?? NULL; } + $this->assertEquals($expectations, $actuals, "Membership expectations are not met"); // Clean up $this->callAPISuccess('Contribution', 'Delete', ['id' => $order['id']]); } /** - * Provides data. + * Provides data for testAddOrderForMembershipWithDates. + * + * As well as checking various things work as expected, this set of tests is + * here to set out what IS expected behaviour. */ public function dataForTestAddOrderForMembershipWithDates() { - return [ - // Without skipStatusCal or dates, we should get a pending membership starting today.' - [[], NULL, ['start_date' => date('Y-m-d'), 'join_date' => date('Y-m-d'), 'end_date' => date('Y-m-d', strtotime('+1 year - 1 day'))]], - // With skipStatusCal, and without dates we should get the same. - [['skipStatusCal' => 1], NULL, ['start_date' => date('Y-m-d'), 'join_date' => date('Y-m-d'), 'end_date' => date('Y-m-d', strtotime('+1 year - 1 day'))]], + // Prevent test mis-fires because of running over midnight. + static::$phpunitStartedDate = date('Y-m-d'); + + $today = date('Y-m-d'); + $aYearLater = date('Y-m-d', strtotime('+1 year')); + $fromTodayForAYear = ['start_date' => $today, 'join_date' => $today, 'end_date' => date('Y-m-d', strtotime('+1 year - 1 day'))]; + $historical = ['start_date' => '2020-01-01', 'join_date' => '2020-01-01', 'end_date' => '2020-12-31']; + $currentMembership = [ + 'join_date' => date('Y-m-d', strtotime('-9 months')), + 'start_date' => date('Y-m-d', strtotime('-9 months')), + 'end_date' => date('Y-m-d', strtotime('-9 months + 1 year - 1 day')), + ]; + + $tests = [ + // #0 Without dates, we should get a pending membership starting today.' + [[], NULL, $fromTodayForAYear + ['status_id' => 'Pending']], + // #1 With our own dates. + [$historical + ['skipStatusCal' => 1], NULL, $historical + ['status_id' => 'Pending']], + // #2 Auto dates (from today), payment today. + [[], $today , $fromTodayForAYear + ['status_id' => 'New']], + // #3 With our own dates, payment today: i.e. payment date should not affect membership date. + [$historical, $today, $historical + ['status_id' => 'Expired']], + // #4 Renewal that is not yet paid: we would expect Order.create NOT to change + // dates or status on the current membership (...until it gets paid, see next tests). + [['renewalOf' => []], NULL, $fromTodayForAYear + ['status_id' => 'New']], + // #5 Existing expired membership gets renewed today. + [$historical + ['renewalOf' => $historical], $today, [ + 'join_date' => $historical['join_date'], /* unchanged */ + 'start_date' => $today, + 'end_date' => $fromTodayForAYear['end_date'], + 'status_id' => 'Current', /* Hmmm. */ + ], + ], + // #6 Existing current membership gets renewed today. + // We expect that it adds a concurrent membership year, rather than overlapping. + [['renewalOf' => $currentMembership], $today, [ + 'join_date' => $currentMembership['join_date'], /* unchanged */ + 'start_date' => $currentMembership['start_date'], /* also unchanged */ + 'end_date' => date('Y-m-d', strtotime("$currentMembership[end_date] +1 year")), + 'status_id' => 'Current', + ], + ], ]; + + // Duplicate the tests with skipStatusCal: i.e. should return the same + // results for all these tests which use the Order API. + // (This deprecated parameter should only affect a direct api3 Membership.create call.) + // Remove this code (and skipStatusCalStillExists etc) if/when that is finally deprecated. + foreach ($tests as $test) { + $test[0] += ['skipStatusCal' => 1]; + $tests[] = $test; + } + + return $tests; + } + + /** + * We can lose a bunch of tests when skipStatusCal is finally gone. + */ + public function skipStatusCalStillExists() { + if (!isset(static::$skipStatusCalStillExists)) { + $path = Civi::paths()->getPath('[civicrm.root]/api/v3/Membership.php'); + static::$skipStatusCalStillExists = stripos(file_get_contents($path), 'skipStatusCal') !== FALSE; + } + return static::$skipStatusCalStillExists; } /** -- 2.25.1