/**
  * See if the is_test flag is properly passed on through batching
  * 
  * @see https://github.com/Project60/sepa_dd/issues/114
  * @author endres -at- systopia.de
  */
 public function testTestMandates()
 {
     $frst_notice = CRM_Core_BAO_Setting::getItem('SEPA Direct Debit Preferences', 'batching_FRST_notice');
     $this->assertNotEmpty($frst_notice, "No FRST notice period specified!");
     CRM_Core_BAO_Setting::setItem('SEPA Direct Debit Preferences', 'batching_RCUR_notice', $frst_notice);
     $rcur_notice = CRM_Core_BAO_Setting::getItem('SEPA Direct Debit Preferences', 'batching_RCUR_notice');
     $this->assertNotEmpty($rcur_notice, "No RCUR notice period specified!");
     $this->assertEquals($frst_notice, $rcur_notice, "Notice periods should be the same.");
     $cycle_day = date("d", strtotime("+{$frst_notice} days"));
     // 2) create a RCUR mandate, due for collection right now
     $mandate = $this->createMandate(array('type' => 'RCUR', 'status' => 'FRST'), array('cycle_day' => $cycle_day));
     CRM_Sepa_Logic_Batching::updateRCUR($mandate['creditor_id'], 'FRST');
     $rcontrib = $this->callAPISuccess("ContributionRecur", "getsingle", array("id" => $mandate['entity_id']));
     $this->assertEquals('0', $rcontrib['is_test'], "Test flag should not be set!");
     $contrib = $this->callAPISuccess("Contribution", "getsingle", array("contribution_recur_id" => $rcontrib['id']));
     $this->assertEquals('0', $contrib['is_test'], "Test flag should not be set!");
     // 3) create a RCUR TEST mandate, due for collection right now
     $ccount = CRM_Core_DAO::singleValueQuery("SELECT count(id) FROM civicrm_contribution;");
     $tccount = CRM_Core_DAO::singleValueQuery("SELECT count(id) FROM civicrm_contribution WHERE is_test=1;");
     $mandate = $this->createMandate(array('type' => 'RCUR', 'status' => 'FRST'), array('is_test' => 1, 'cycle_day' => $cycle_day));
     CRM_Sepa_Logic_Batching::updateRCUR($mandate['creditor_id'], 'FRST');
     $this->assertDBQuery($ccount + 1, "SELECT count(id) FROM civicrm_contribution;");
     $rcontrib = $this->callAPISuccess("ContributionRecur", "getsingle", array("id" => $mandate['entity_id']));
     $this->assertEquals('1', $rcontrib['is_test'], "Test flag should be set!");
     // cannot use API for Contribution, wouldn't load test contributions
     $this->assertDBQuery($tccount + 1, "SELECT count(id) FROM civicrm_contribution WHERE is_test=1;");
     // 4) create a OOFF TEST mandate
     $mandate = $this->createMandate(array('type' => 'OOFF', 'status' => 'INIT'), array('is_test' => 1));
     CRM_Sepa_Logic_Batching::updateRCUR($mandate['creditor_id'], 'FRST');
     $contrib = $this->callAPISuccess("Contribution", "getsingle", array("id" => $mandate['entity_id']));
     $this->assertEquals('1', $contrib['is_test'], "Test flag should be set!");
 }
/**
 * API CALL TO UPDATE TXGROUPs ("Batching")
 *
 * @package CiviCRM_SEPA
 *
 */
function civicrm_api3_sepa_alternative_batching_update($params)
{
    // get creditor list
    $creditor_query = civicrm_api('SepaCreditor', 'get', array('version' => 3, 'option.limit' => 99999));
    if (!empty($creditor_query['is_error'])) {
        return civicrm_api3_create_error("Cannot get creditor list: " . $creditor_query['error_message']);
    } else {
        $creditors = array();
        foreach ($creditor_query['values'] as $creditor) {
            $creditors[] = $creditor['id'];
        }
    }
    if ($params['type'] == 'OOFF') {
        foreach ($creditors as $creditor_id) {
            CRM_Sepa_Logic_Batching::updateOOFF($creditor_id);
        }
    } elseif ($params['type'] == 'RCUR' || $params['type'] == 'FRST') {
        // first: make sure, that there are no outdated mandates:
        CRM_Sepa_Logic_Batching::closeEnded();
        // then, run the update for recurring mandates
        foreach ($creditors as $creditor_id) {
            CRM_Sepa_Logic_Batching::updateRCUR($creditor_id, $params['type']);
        }
    } else {
        return civicrm_api3_create_error(sprintf("Unknown batching mode '%s'.", $params['type']));
    }
    return civicrm_api3_create_success();
}
function civicrm_api3_sepa_transaction_group_createnext($params)
{
    $errors = $counter = 0;
    $values = array();
    $group = (int) $params["id"];
    if (!$group) {
        throw new API_Exception("Incorrect or missing value for group id");
    }
    $contribs = civicrm_api("sepa_contribution_group", "getdetail", $params);
    foreach ($contribs["values"] as $old) {
        if (!$old['recur_id']) {
            throw new API_Exception("Trying to create next payment for non-recurrent contribution?");
        }
        $date = strtotime(substr($old["receive_date"], 0, 10));
        $next_collectionDate = strtotime("+" . $old["frequency_interval"] . " " . $old["frequency_unit"], $date);
        $next_collectionDate = date('YmdHis', $next_collectionDate);
        $new = $old;
        $new["hash"] = md5(uniqid(rand(), true));
        $new["source"] = "SEPA recurring contribution";
        unset($new["id"]);
        unset($new["contribution_id"]);
        $new["receive_date"] = $next_collectionDate;
        $new["contribution_status_id"] = 2;
        $new["contribution_recur_id"] = $new["recur_id"];
        unset($new["recur_id"]);
        /*
          CRM_Core_DAO::executeQuery("
          UPDATE civicrm_contribution_recur 
          SET next_sched_contribution = %1 
          WHERE id = %2
          ", array(
          1 => array($next_collectionDate, 'String'),
          2 => array($new["contribution_recur_id"], 'Integer')
          )
          );
        */
        $new["version"] = 3;
        $new["sequential"] = 1;
        /*
        $total += $new["total_amount"];
        ++$counter;
        continue;
        */
        $result = civicrm_api('contribution', 'create', $new);
        if ($result['is_error']) {
            $output[] = $result['error_message'];
            ++$errors;
            continue;
        } else {
            ++$counter;
            $total += $result["total_amount"];
            $mandate = new CRM_Sepa_BAO_SEPAMandate();
            $contrib = new CRM_Contribute_BAO_Contribution();
            $contrib->get('id', $result["id"]);
            //it sucks to have to fetch again, just to get the BAO
            //      $mandate->get('id', $old["mandate_id"]);
            //      $values[] = $result["values"];
            $group = CRM_Sepa_Logic_Batching::batchContributionByCreditor($contrib, $old["creditor_id"], $old["payment_instrument_id"]);
            $values = $group->toArray();
        }
    }
    if (!$errors) {
        $values["nb_contrib"] = $counter;
        $values["total"] = $total;
        return civicrm_api3_create_success(array($values), $params, 'address', $contrib);
    } else {
        civicrm_api3_create_error("Could not create " . $errors . " new contributions", $output);
    }
}
예제 #4
0
 /**
  * This is the counterpart to the doDirectPayment method. This method creates
  * partial mandates, where the subsequent payment processess produces a payment.
  *
  * This function here should be called after the payment process was completed.
  * It will process all the PARTIAL mandates and connect them with created contributions.
  */
 public static function processPartialMandates()
 {
     // load all the PARTIAL mandates
     $partial_mandates = civicrm_api3('SepaMandate', 'get', array('version' => 3, 'status' => 'PARTIAL', 'option.limit' => 9999));
     foreach ($partial_mandates['values'] as $mandate_id => $mandate) {
         if ($mandate['type'] == 'OOFF') {
             // in the OOFF case, we need to find the contribution, and connect it
             $contribution = civicrm_api('Contribution', 'getsingle', array('version' => 3, 'trxn_id' => $mandate['reference']));
             if (empty($contribution['is_error'])) {
                 // check collection date
                 $ooff_notice = (int) CRM_Sepa_Logic_Settings::getSetting("batching.OOFF.notice", $mandate['creditor_id']);
                 $first_collection_date = strtotime("+{$ooff_notice} days");
                 $collection_date = strtotime($contribution['receive_date']);
                 if ($collection_date < $first_collection_date) {
                     // adjust collection date to the earliest possible one
                     $collection_date = $first_collection_date;
                 }
                 // FOUND! Update the contribution...
                 $contribution_bao = new CRM_Contribute_BAO_Contribution();
                 $contribution_bao->get('id', $contribution['id']);
                 $contribution_bao->is_pay_later = 0;
                 $contribution_bao->receive_date = date('YmdHis', $collection_date);
                 $contribution_bao->contribution_status_id = (int) CRM_Core_OptionGroup::getValue('contribution_status', 'Pending', 'name');
                 $contribution_bao->payment_instrument_id = (int) CRM_Core_OptionGroup::getValue('payment_instrument', 'OOFF', 'name');
                 $contribution_bao->save();
                 // ...and connect it to the mandate
                 $mandate_update = array();
                 $mandate_update['id'] = $mandate['id'];
                 $mandate_update['entity_id'] = $contribution['id'];
                 $mandate_update['type'] = $mandate['type'];
                 if (empty($mandate['contact_id'])) {
                     // this happens when the payment gets created AFTER the doDirectPayment method
                     $mandate_update['contact_id'] = $contribution_bao->contact_id;
                 }
                 // initialize according to the creditor settings
                 CRM_Sepa_BAO_SEPACreditor::initialiseMandateData($mandate['creditor_id'], $mandate_update);
                 // finally, write the changes to the mandate
                 civicrm_api3('SepaMandate', 'create', $mandate_update);
             } else {
                 // if NOT FOUND or error, delete the partial mandate
                 civicrm_api3('SepaMandate', 'delete', array('id' => $mandate_id));
             }
         } elseif ($mandate['type'] == 'RCUR') {
             // in the RCUR case, we also need to find the contribution, and connect it
             // load the contribution AND the associated recurring contribution
             $contribution = civicrm_api('Contribution', 'getsingle', array('version' => 3, 'trxn_id' => $mandate['reference']));
             $rcontribution = civicrm_api('ContributionRecur', 'getsingle', array('version' => 3, 'trxn_id' => $mandate['reference']));
             if (empty($contribution['is_error']) && empty($rcontribution['is_error'])) {
                 // we need to set the receive date to the correct collection date, otherwise it will be created again (w/o)
                 $rcur_notice = (int) CRM_Sepa_Logic_Settings::getSetting("batching.RCUR.notice", $mandate['creditor_id']);
                 $now = strtotime(date('Y-m-d', strtotime("now +{$rcur_notice} days")));
                 // round to full day
                 $collection_date = CRM_Sepa_Logic_Batching::getNextExecutionDate($rcontribution, $now);
                 // fix contribution
                 $contribution_bao = new CRM_Contribute_BAO_Contribution();
                 $contribution_bao->get('id', $contribution['id']);
                 $contribution_bao->is_pay_later = 0;
                 $contribution_bao->contribution_status_id = (int) CRM_Core_OptionGroup::getValue('contribution_status', 'Pending', 'name');
                 $contribution_bao->payment_instrument_id = (int) CRM_Core_OptionGroup::getValue('payment_instrument', 'FRST', 'name');
                 $contribution_bao->receive_date = date('YmdHis', strtotime($collection_date));
                 $contribution_bao->save();
                 // fix recurring contribution
                 $rcontribution_bao = new CRM_Contribute_BAO_ContributionRecur();
                 $rcontribution_bao->get('id', $rcontribution['id']);
                 $rcontribution_bao->start_date = date('YmdHis', strtotime($rcontribution_bao->start_date));
                 $rcontribution_bao->create_date = date('YmdHis', strtotime($rcontribution_bao->create_date));
                 $rcontribution_bao->modified_date = date('YmdHis', strtotime($rcontribution_bao->modified_date));
                 $rcontribution_bao->contribution_status_id = (int) CRM_Core_OptionGroup::getValue('contribution_status', 'Pending', 'name');
                 $rcontribution_bao->payment_instrument_id = (int) CRM_Core_OptionGroup::getValue('payment_instrument', 'FRST', 'name');
                 $rcontribution_bao->save();
                 // ...and connect it to the mandate
                 $mandate_update = array();
                 $mandate_update['id'] = $mandate['id'];
                 $mandate_update['entity_id'] = $rcontribution['id'];
                 $mandate_update['type'] = $mandate['type'];
                 if (empty($mandate['contact_id'])) {
                     $mandate_update['contact_id'] = $contribution['contact_id'];
                     $mandate['contact_id'] = $contribution['contact_id'];
                 }
                 //NO: $mandate_update['first_contribution_id'] = $contribution['id'];
                 // initialize according to the creditor settings
                 CRM_Sepa_BAO_SEPACreditor::initialiseMandateData($mandate['creditor_id'], $mandate_update);
                 // finally, write the changes to the mandate
                 civicrm_api3('SepaMandate', 'create', $mandate_update);
                 // ...and trigger notification
                 // FIXME: WORKAROUND, see https://github.com/Project60/org.project60.sepa/issues/296)
                 CRM_Contribute_BAO_ContributionPage::recurringNotify(CRM_Core_Payment::RECURRING_PAYMENT_START, $mandate['contact_id'], $contribution_bao->contribution_page_id, $rcontribution_bao);
             } else {
                 // something went wrong, delete partial
                 error_log("org.project60.sepa: deleting partial mandate " . $mandate['reference']);
                 civicrm_api3('SepaMandate', 'delete', array('id' => $mandate_id));
             }
         }
     }
 }