diff --git a/.drone.yml b/.drone.yml
index 60d227fd9..b9b5a783e 100644
--- a/.drone.yml
+++ b/.drone.yml
@@ -59,6 +59,7 @@ steps:
- cd $DRUPAL_ROOT/sites/all/modules/civicrm/tests/playwright/ && npx playwright test tests/edit_mailing.spec.js
- cd $DRUPAL_ROOT/sites/all/modules/civicrm/tests/playwright/ && npx playwright test tests/contribution_spgateway.spec.js
- cd $DRUPAL_ROOT/sites/all/modules/civicrm/tests/playwright/ && npx playwright test tests/contribution_booster.spec.js
+ - cd $DRUPAL_ROOT/sites/all/modules/civicrm/tests/playwright/ && npx playwright test tests/report_check.spec.js
- name: notify
image: drillster/drone-email
settings:
@@ -143,6 +144,7 @@ steps:
- cd $DRUPAL_ROOT/sites/all/modules/civicrm/tests/playwright/ && npx playwright test tests/edit_mailing.spec.js
- cd $DRUPAL_ROOT/sites/all/modules/civicrm/tests/playwright/ && npx playwright test tests/contribution_spgateway.spec.js
- cd $DRUPAL_ROOT/sites/all/modules/civicrm/tests/playwright/ && npx playwright test tests/contribution_booster.spec.js
+ - cd $DRUPAL_ROOT/sites/all/modules/civicrm/tests/playwright/ && npx playwright test tests/report_check.spec.js
- name: notify
image: drillster/drone-email
settings:
@@ -227,7 +229,9 @@ steps:
- cd $DRUPAL_ROOT/modules/civicrm/tests/playwright/ && npx playwright test tests/event_limit_approval_register.spec.js
- cd $DRUPAL_ROOT/modules/civicrm/tests/playwright/ && npx playwright test tests/event_unlimit_approval_register.spec.js
- cd $DRUPAL_ROOT/modules/civicrm/tests/playwright/ && npx playwright test tests/event_participant.spec.js
+ - cd $DRUPAL_ROOT/modules/civicrm/tests/playwright/ && npx playwright test tests/contribution_spgateway.spec.js
- cd $DRUPAL_ROOT/modules/civicrm/tests/playwright/ && npx playwright test tests/edit_mailing.spec.js
+ - cd $DRUPAL_ROOT/modules/civicrm/tests/playwright/ && npx playwright test tests/report_check.spec.js
- name: notify
image: drillster/drone-email
settings:
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index bd12d3bda..9dc9ea804 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -72,6 +72,8 @@ jobs:
run: docker exec neticrm-ci bash -c "cd \$DRUPAL_ROOT/sites/all/modules/civicrm/tests/playwright/ && npx playwright test tests/contribution_allpay_atm.spec.js"
- name: Payment Test - ALLPAY - Barcode - Playwright
run: docker exec neticrm-ci bash -c "cd \$DRUPAL_ROOT/sites/all/modules/civicrm/tests/playwright/ && npx playwright test tests/contribution_allpay_barcode.spec.js"
+ - name: Payment Test - SPGATEWAY - Playwright
+ run: docker exec neticrm-ci bash -c "cd \$DRUPAL_ROOT/sites/all/modules/civicrm/tests/playwright/ && npx playwright test tests/contribution_spgateway.spec.js"
- name: Frontend - Contribution Editing - Playwright
run: docker exec neticrm-ci bash -c "cd \$DRUPAL_ROOT/sites/all/modules/civicrm/tests/playwright/ && npx playwright test tests/new_contribution.spec.js"
- name: Frontend - Advanced Search - Playwright
@@ -96,10 +98,10 @@ jobs:
run: docker exec neticrm-ci bash -c "cd \$DRUPAL_ROOT/sites/all/modules/civicrm/tests/playwright/ && npx playwright test tests/event_participant.spec.js"
- name: Frontend - Mailing Editing - Playwright
run: docker exec neticrm-ci bash -c "cd \$DRUPAL_ROOT/sites/all/modules/civicrm/tests/playwright/ && npx playwright test tests/edit_mailing.spec.js"
- - name: Payment Test - SPGATEWAY - Playwright
- run: docker exec neticrm-ci bash -c "cd \$DRUPAL_ROOT/sites/all/modules/civicrm/tests/playwright/ && npx playwright test tests/contribution_spgateway.spec.js"
- name: Frontend - Contribution Booster - Playwright
run: docker exec neticrm-ci bash -c "cd \$DRUPAL_ROOT/sites/all/modules/civicrm/tests/playwright/ && npx playwright test tests/contribution_booster.spec.js"
+ - name: Frontend - Report Page Checking - Playwright
+ run: docker exec neticrm-ci bash -c "cd \$DRUPAL_ROOT/sites/all/modules/civicrm/tests/playwright/ && npx playwright test tests/report_check.spec.js"
- uses: actions/upload-artifact@v3
if: always()
@@ -179,6 +181,8 @@ jobs:
run: docker exec neticrm-ci bash -c "cd \$DRUPAL_ROOT/sites/all/modules/civicrm/tests/playwright/ && npx playwright test tests/contribution_allpay_atm.spec.js"
- name: Payment Test - ALLPAY - Barcode - Playwright
run: docker exec neticrm-ci bash -c "cd \$DRUPAL_ROOT/sites/all/modules/civicrm/tests/playwright/ && npx playwright test tests/contribution_allpay_barcode.spec.js"
+ - name: Payment Test - SPGATEWAY - Playwright
+ run: docker exec neticrm-ci bash -c "cd \$DRUPAL_ROOT/sites/all/modules/civicrm/tests/playwright/ && npx playwright test tests/contribution_spgateway.spec.js"
- name: Frontend - Contribution Editing - Playwright
run: docker exec neticrm-ci bash -c "cd \$DRUPAL_ROOT/sites/all/modules/civicrm/tests/playwright/ && npx playwright test tests/new_contribution.spec.js"
- name: Frontend - Advanced Search - Playwright
@@ -203,10 +207,10 @@ jobs:
run: docker exec neticrm-ci bash -c "cd \$DRUPAL_ROOT/sites/all/modules/civicrm/tests/playwright/ && npx playwright test tests/event_participant.spec.js"
- name: Frontend - Mailing Editing - Playwright
run: docker exec neticrm-ci bash -c "cd \$DRUPAL_ROOT/sites/all/modules/civicrm/tests/playwright/ && npx playwright test tests/edit_mailing.spec.js"
- - name: Payment Test - SPGATEWAY - Playwright
- run: docker exec neticrm-ci bash -c "cd \$DRUPAL_ROOT/sites/all/modules/civicrm/tests/playwright/ && npx playwright test tests/contribution_spgateway.spec.js"
- name: Frontend - Contribution Booster - Playwright
run: docker exec neticrm-ci bash -c "cd \$DRUPAL_ROOT/sites/all/modules/civicrm/tests/playwright/ && npx playwright test tests/contribution_booster.spec.js"
+ - name: Frontend - Report Page Checking - Playwright
+ run: docker exec neticrm-ci bash -c "cd \$DRUPAL_ROOT/sites/all/modules/civicrm/tests/playwright/ && npx playwright test tests/report_check.spec.js"
- uses: actions/upload-artifact@v3
if: always()
@@ -248,6 +252,8 @@ jobs:
run: docker exec neticrm-ci bash -c "cd \$DRUPAL_ROOT/modules/civicrm/tests/phpunit && phpunit --filter testLastReceiptId CRM/Contribute/BAO/ContributionTest.php"
- name: Payment Test - ALLPAY
run: docker exec neticrm-ci bash -c "cd \$DRUPAL_ROOT/modules/civicrm/tests/phpunit && phpunit CRM/Core/Payment/ALLPAYTest.php"
+ - name: Payment Test - Neweb(new)
+ run: docker exec neticrm-ci bash -c "cd \$DRUPAL_ROOT/modules/civicrm/tests/phpunit && phpunit CRM/Core/Payment/SPGATEWAYTest.php"
- name: Payment Test - LINE Pay
run: docker exec neticrm-ci bash -c "cd \$DRUPAL_ROOT/modules/civicrm/tests/phpunit && phpunit CRM/Core/Payment/LinePayTest.php"
- name: Payment Test - TapPay
@@ -286,6 +292,8 @@ jobs:
run: docker exec neticrm-ci bash -c "cd \$DRUPAL_ROOT/modules/civicrm/tests/playwright/ && npx playwright test tests/contribution_allpay_atm.spec.js"
- name: Payment Test - ALLPAY - Barcode - Playwright
run: docker exec neticrm-ci bash -c "cd \$DRUPAL_ROOT/modules/civicrm/tests/playwright/ && npx playwright test tests/contribution_allpay_barcode.spec.js"
+ - name: Payment Test - SPGATEWAY - Playwright
+ run: docker exec neticrm-ci bash -c "cd \$DRUPAL_ROOT/modules/civicrm/tests/playwright/ && npx playwright test tests/contribution_spgateway.spec.js"
- name: Frontend - Contribution Editing - Playwright
run: docker exec neticrm-ci bash -c "cd \$DRUPAL_ROOT/modules/civicrm/tests/playwright/ && npx playwright test tests/new_contribution.spec.js"
- name: Frontend - Advanced Search - Playwright
@@ -312,6 +320,8 @@ jobs:
run: docker exec neticrm-ci bash -c "cd \$DRUPAL_ROOT/modules/civicrm/tests/playwright/ && npx playwright test tests/edit_mailing.spec.js"
- name: Frontend - Contribution Booster - Playwright
run: docker exec neticrm-ci bash -c "cd \$DRUPAL_ROOT/modules/civicrm/tests/playwright/ && npx playwright test tests/contribution_booster.spec.js"
+ - name: Frontend - Report Page Checking - Playwright
+ run: docker exec neticrm-ci bash -c "cd \$DRUPAL_ROOT/modules/civicrm/tests/playwright/ && npx playwright test tests/report_check.spec.js"
diff --git a/CRM/Contribute/BAO/Contribution.php b/CRM/Contribute/BAO/Contribution.php
index 7992ad39d..25ae846d9 100644
--- a/CRM/Contribute/BAO/Contribution.php
+++ b/CRM/Contribute/BAO/Contribution.php
@@ -2604,17 +2604,17 @@ static function makeNotifyUrl(&$params, $path, $return_query = FALSE){
$query[] = "contact_id={$params['contactID']}";
$query[] = "cid={$params['contributionID']}";
- if($params['eventID']) {
+ if(!empty($params['eventID'])) {
$query[] = "module=event";
$query[] = "eid={$params['eventID']}";
$query[] = "pid={$params['participantID']}";
}
else {
$query[] = "module=contribute";
- if ( $params['membershipID'] ) {
+ if (!empty($params['membershipID'])) {
$query[] = "mid=".$params['membershipID'];
}
- if ($params['related_contact']) {
+ if (!empty($params['related_contact'])) {
$query[] = "rid=".$params['related_contact'];
if ($params['onbehalf_dupe_alert']) {
$query[] = "onbehalf_dupe_alert=".$params['onbehalf_dupe_alert'];
diff --git a/CRM/Contribute/DAO/SPGATEWAY.php b/CRM/Contribute/DAO/SPGATEWAY.php
new file mode 100644
index 000000000..801b381c1
--- /dev/null
+++ b/CRM/Contribute/DAO/SPGATEWAY.php
@@ -0,0 +1,235 @@
+ 'civicrm_contribution:id',
+ );
+ }
+ return self::$_links;
+ }
+ /**
+ * Returns foreign keys and entity references.
+ *
+ * @return array
+ * [CRM_Core_Reference_Interface]
+ */
+ public static function getReferenceColumns()
+ {
+ if (!isset(Civi::$statics[__CLASS__]['links'])) {
+ Civi::$statics[__CLASS__]['links'] = static ::createReferenceColumns(__CLASS__);
+ Civi::$statics[__CLASS__]['links'][] = new CRM_Core_Reference_Basic(self::getTableName() , 'cid', 'civicrm_contribution', 'id');
+ }
+ return Civi::$statics[__CLASS__]['links'];
+ }
+ /**
+ * returns all the column names of this table
+ *
+ * @access public
+ * @return array
+ */
+ static function &fields()
+ {
+ if (!(self::$_fields)) {
+ self::$_fields = array(
+ 'id' => array(
+ 'name' => 'id',
+ 'type' => CRM_Utils_Type::T_INT,
+ 'required' => true,
+ ) ,
+ 'spgateway_contribution_id' => array(
+ 'name' => 'cid',
+ 'type' => CRM_Utils_Type::T_INT,
+ 'title' => ts('Spgateway Contribution ID') ,
+ 'FKClassName' => 'CRM_Contribute_DAO_Contribution',
+ ) ,
+ 'data' => array(
+ 'name' => 'data',
+ 'type' => CRM_Utils_Type::T_BLOB,
+ 'title' => ts('Data') ,
+ ) ,
+ );
+ }
+ return self::$_fields;
+ }
+ /**
+ * returns the names of this table
+ *
+ * @access public
+ * @return string
+ */
+ static function getTableName()
+ {
+ return self::$_tableName;
+ }
+ /**
+ * returns if this table needs to be logged
+ *
+ * @access public
+ * @return boolean
+ */
+ function getLog()
+ {
+ return self::$_log;
+ }
+ /**
+ * returns the list of fields that can be imported
+ *
+ * @access public
+ * return array
+ */
+ static function &import($prefix = false)
+ {
+ if (!(self::$_import)) {
+ self::$_import = array();
+ $fields = &self::fields();
+ foreach($fields as $name => $field) {
+ if (CRM_Utils_Array::value('import', $field)) {
+ if ($prefix) {
+ self::$_import['contribution_spgateway'] = &$fields[$name];
+ } else {
+ self::$_import[$name] = &$fields[$name];
+ }
+ }
+ }
+ }
+ return self::$_import;
+ }
+ /**
+ * returns the list of fields that can be exported
+ *
+ * @access public
+ * return array
+ */
+ static function &export($prefix = false)
+ {
+ if (!(self::$_export)) {
+ self::$_export = array();
+ $fields = &self::fields();
+ foreach($fields as $name => $field) {
+ if (CRM_Utils_Array::value('export', $field)) {
+ if ($prefix) {
+ self::$_export['contribution_spgateway'] = &$fields[$name];
+ } else {
+ self::$_export[$name] = &$fields[$name];
+ }
+ }
+ }
+ }
+ return self::$_export;
+ }
+}
diff --git a/CRM/Contribute/Form/ContributionPage/Amount.php b/CRM/Contribute/Form/ContributionPage/Amount.php
index 63b1f7745..1dfc287b3 100644
--- a/CRM/Contribute/Form/ContributionPage/Amount.php
+++ b/CRM/Contribute/Form/ContributionPage/Amount.php
@@ -224,7 +224,7 @@ private static function doShowHideFrequencyUnits(&$recurFrequencyUnits, $recurri
foreach ($recurringPaymentProcessor as $ppid) {
$paymentProcessor = CRM_Core_BAO_PaymentProcessor::getPayment($ppid, '');
$paymentClass = 'CRM_Core_'.$paymentProcessor['class_name'];
- if (!empty($paymentClass::$_allowRecurUnit)) {
+ if (class_exists($paymentClass) && property_exists($paymentClass, '_allowRecurUnit')) {
$paymentUnitsCount[$unit] += in_array($unit, $paymentClass::$_allowRecurUnit) ? 1 : 0;
}
else {
diff --git a/CRM/Contribute/Form/ContributionRecur.php b/CRM/Contribute/Form/ContributionRecur.php
index a9f258577..2734e23d4 100644
--- a/CRM/Contribute/Form/ContributionRecur.php
+++ b/CRM/Contribute/Form/ContributionRecur.php
@@ -352,9 +352,9 @@ public function postProcess() {
);
// refs #17486. Date format should be YmdHis.
- foreach ($params as $key => $value) {
- if(preg_match('/\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/',$value)){
- $params[$key] = preg_replace('/-| |:/', '', $value);
+ foreach (array('create_date', 'start_date', 'modified_date', 'cancel_date', 'end_date', 'next_sched_contribution', 'failure_retry_date', 'last_execute_date') as $idx) {
+ if(preg_match('/\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/', $params[$idx])){
+ $params[$idx] = preg_replace('/-| |:/', '', $params[$idx]);
}
}
diff --git a/CRM/Core/BAO/Address.php b/CRM/Core/BAO/Address.php
index 39138dce7..11d46c516 100644
--- a/CRM/Core/BAO/Address.php
+++ b/CRM/Core/BAO/Address.php
@@ -518,7 +518,7 @@ function addDisplay($microformat = FALSE) {
// added this for CRM 1200
'address_id' => $this->id,
// CRM-4003
- 'address_name' => str_replace('', ' ', $this->name),
+ 'address_name' => !empty($this->_name) ? str_replace('', ' ', $this->name) : '',
'street_address' => $this->street_address,
'supplemental_address_1' => $this->supplemental_address_1,
'supplemental_address_2' => $this->supplemental_address_2,
diff --git a/CRM/Core/BAO/PaymentProcessor.php b/CRM/Core/BAO/PaymentProcessor.php
index 4ef914c25..099191f4b 100644
--- a/CRM/Core/BAO/PaymentProcessor.php
+++ b/CRM/Core/BAO/PaymentProcessor.php
@@ -183,7 +183,7 @@ static function getPayments($paymentProcessorIDs, $mode) {
$dao->id = $paymentProcessorID;
$dao->is_active = 1;
if (!$dao->find(TRUE)) {
- return NULL;
+ continue;
}
if ($mode == 'test') {
@@ -211,6 +211,9 @@ static function getPayments($paymentProcessorIDs, $mode) {
}
}
$paymentDAO = $paymentDefault + $paymentDAO;
+ if (empty($paymentDAO)) {
+ return NULL;
+ }
return $paymentDAO;
}
diff --git a/CRM/Core/BAO/UFGroup.php b/CRM/Core/BAO/UFGroup.php
index 6c6f2f77d..6c23e2c60 100644
--- a/CRM/Core/BAO/UFGroup.php
+++ b/CRM/Core/BAO/UFGroup.php
@@ -2401,7 +2401,7 @@ static function commonSendMail($contactID, &$values) {
* @return array
* @access public
*/
- function checkFieldsEmptyValues($gid, $cid, $params) {
+ public static function checkFieldsEmptyValues($gid, $cid, $params) {
if ($gid) {
require_once 'CRM/Core/BAO/UFGroup.php';
if (CRM_Core_BAO_UFGroup::filterUFGroups($gid, $cid)) {
@@ -2438,7 +2438,7 @@ function checkFieldsEmptyValues($gid, $cid, $params) {
* @return void
* @access public
*/
- function profileDisplay($gid, $values, $template) {
+ public static function profileDisplay($gid, $values, $template) {
$groupTitle = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_UFGroup', $gid, 'title');
$template->assign("grouptitle", $groupTitle);
if (count($values)) {
diff --git a/CRM/Core/Config/Variables.php b/CRM/Core/Config/Variables.php
index 4b8b9e3a1..62e08d23d 100644
--- a/CRM/Core/Config/Variables.php
+++ b/CRM/Core/Config/Variables.php
@@ -443,10 +443,17 @@ class CRM_Core_Config_Variables extends CRM_Core_Config_Defaults {
public $cspRules = "";
/**
- * AI Organization profile
+ * AI Organization profile
*/
public $aiOrganizationIntro = '';
+ /**
+ * Webserver Log Dir
+ *
+ * It should only use for web server log processing cron jobs
+ */
+ public $webLogDir = 'log';
+
/**
* Provide addressSequence
*
diff --git a/CRM/Core/DAO/.listAll.php b/CRM/Core/DAO/.listAll.php
index 2242a1306..f12ef2ae5 100644
--- a/CRM/Core/DAO/.listAll.php
+++ b/CRM/Core/DAO/.listAll.php
@@ -143,6 +143,7 @@
$dao['TapPay'] = 'CRM_Contribute_DAO_TapPay';
$dao['TapPayLog'] = 'CRM_Contribute_DAO_TapPayLog';
$dao['AllPay'] = 'CRM_Contribute_DAO_AllPay';
+$dao['SPGATEWAY'] = 'CRM_Contribute_DAO_SPGATEWAY';
$dao['CouponTrack'] = 'CRM_Coupon_DAO_CouponTrack';
$dao['MembershipPayment'] = 'CRM_Member_DAO_MembershipPayment';
$dao['Event'] = 'CRM_Event_DAO_Event';
diff --git a/CRM/Core/DAO/AllCoreTables.data.php b/CRM/Core/DAO/AllCoreTables.data.php
index 5b2a7b9c1..28f23a91f 100644
--- a/CRM/Core/DAO/AllCoreTables.data.php
+++ b/CRM/Core/DAO/AllCoreTables.data.php
@@ -716,6 +716,11 @@
'class' => 'CRM_Contribute_DAO_AllPay',
'table' => 'civicrm_contribution_allpay',
) ,
+ 'CRM_Contribute_DAO_SPGATEWAY' => array(
+ 'name' => 'SPGATEWAY',
+ 'class' => 'CRM_Contribute_DAO_SPGATEWAY',
+ 'table' => 'civicrm_contribution_spgateway',
+ ) ,
'CRM_Coupon_DAO_CouponTrack' => array(
'name' => 'CouponTrack',
'class' => 'CRM_Coupon_DAO_CouponTrack',
diff --git a/CRM/Core/I18n.php b/CRM/Core/I18n.php
index 708b344c9..9e2d771a9 100644
--- a/CRM/Core/I18n.php
+++ b/CRM/Core/I18n.php
@@ -301,7 +301,7 @@ function crm_translate($text, $params = array()) {
}
// replace the numbered %1, %2, etc. params if present
- if (count($params)) {
+ if (is_array($params) && count($params)) {
$text = $this->strarg($text, $params);
}
diff --git a/CRM/Core/Payment/ALLPAY.php b/CRM/Core/Payment/ALLPAY.php
index 5db898b91..42bc7e22d 100644
--- a/CRM/Core/Payment/ALLPAY.php
+++ b/CRM/Core/Payment/ALLPAY.php
@@ -758,7 +758,7 @@ public static function recurCheck($rid, $order = NULL) {
}
// manually trigger ipn
- self::doIPN('Credit', $post, $get, FALSE);
+ self::doIPN(array('allpay', 'ipn', 'Credit'), $post, $get, FALSE);
}
}
}
@@ -844,7 +844,7 @@ public static function tradeCheck($orderId, $order = NULL) {
$ipnPost['do_not_email'] = 1;
}
*/
- $result = self::doIPN('Credit', $ipnPost, $ipnGet, FALSE);
+ $result = self::doIPN(array('allpay', 'ipn', 'Credit'), $ipnPost, $ipnGet, FALSE);
return $result;
}
}
@@ -985,17 +985,25 @@ function cancelRecuringMessage($recurID){
/**
* Execute ipn as called from allpay transaction. Original civicrm_allpay_ipn
*
- * @param string $instrument The code of used instrument like 'Credit' or 'ATM'.
+ * @param array $instrument The code of used instrument like 'Credit' or 'ATM'.
* @param array $post Bring post variables if you need test.
* @param array $get Bring get variables if you need test.
* @param boolean $print Does server echo the result, or just return that. Default is TRUE.
*
* @return string|void If $print is FALSE, function will return the result as Array.
*/
- static function doIPN($instrument = NULL, $post = NULL, $get = NULL, $print = TRUE) {
+ static function doIPN($arguments, $post = NULL, $get = NULL, $print = TRUE) {
// detect variables
$post = !empty($post) ? $post : $_POST;
$get = !empty($get) ? $get : $_GET;
+ if (!empty($arguments)) {
+ if (is_array($arguments)) {
+ $instrument = end($arguments);
+ }
+ else {
+ $instrument = $arguments;
+ }
+ }
if (empty($instrument)) {
$qArray = explode('/', $get['q']);
$instrument = end($qArray);
@@ -1004,13 +1012,11 @@ static function doIPN($instrument = NULL, $post = NULL, $get = NULL, $print = TR
// detect variables
if(empty($post)){
CRM_Core_Error::debug_log_message( "civicrm_allpay: Could not find POST data from payment server", TRUE);
- exit;
+ CRM_Utils_System::civiExit();
}
else{
$component = $get['module'];
if(!empty($component)){
- // include_once(__DIR__.'/ALLPAYIPN.php');
-
$ipn = new CRM_Core_Payment_ALLPAYIPN($post, $get);
$result = $ipn->main($component, $instrument);
if(!empty($result) && $print){
@@ -1024,6 +1030,7 @@ static function doIPN($instrument = NULL, $post = NULL, $get = NULL, $print = TR
CRM_Core_Error::debug_log_message( "civicrm_allpay: Could not get module name from request url", TRUE);
}
}
+ CRM_Utils_System::civiExit();
}
}
diff --git a/CRM/Core/Payment/ALLPAYIPN.php b/CRM/Core/Payment/ALLPAYIPN.php
index b631b7f39..b5b9faad9 100644
--- a/CRM/Core/Payment/ALLPAYIPN.php
+++ b/CRM/Core/Payment/ALLPAYIPN.php
@@ -17,7 +17,12 @@ function main($component, $instrument){
$objects = $ids = $input = array();
$input = $this->_post;
$this->getIds($ids, $component);
- $input['component'] = $component;
+ if (!empty($ids['participant'])) {
+ $input['component'] = 'event';
+ }
+ else {
+ $input['component'] = 'contribute';
+ }
$qfKey = CRM_Utils_Array::value('qfKey', $this->_get);
$civi_base_url = $component == 'event' ? 'civicrm/event/register' : 'civicrm/contribute/transact';
@@ -81,19 +86,22 @@ function main($component, $instrument){
// never for front-end user.
}
- function getIds( &$ids , $component){
- $ids['contact'] = CRM_Utils_Array::value('contact_id', $this->_get);
- $ids['contribution'] = CRM_Utils_Array::value('cid', $this->_get);
- if ( $component == 'event' ) {
- $ids['event'] = CRM_Utils_Array::value('eid', $this->_get);
- $ids['participant'] = CRM_Utils_Array::value('pid', $this->_get);
+ function getIds(&$ids){
+ $contribId = CRM_Utils_Array::value('cid', $this->_get);
+ if (!empty($contribId) && CRM_Utils_Type::escape($contribId, 'Integer')) {
+ $ids = CRM_Contribute_BAO_Contribution::buildIds($contribId, FALSE);
+ if (empty($ids)) {
+ CRM_Core_Error::debug_log_message("Allpay: Could not found contribution id $contribId");
+ CRM_Utils_System::civiExit();
+ }
}
- else {
- $ids['membership'] = CRM_Utils_Array::value('mid', $this->_get);
- $ids['contributionRecur'] = CRM_Utils_Array::value('crid', $this->_get);
- $ids['contributionPage'] = CRM_Utils_Array::value('cpid', $this->_get);
- $ids['related_contact'] = CRM_Utils_Array::value('rid', $this->_get);
- $ids['onbehalf_dupe_alert'] = CRM_Utils_Array::value('onbehalf_dupe_alert', $this->_get);
+ if (!empty($ids['participant'])) {
+ if (!empty($this->_get['rid'])) {
+ $ids['related_contact'] = CRM_Utils_Array::value('rid', $this->_get);
+ }
+ if (!empty($this->_get['onbehalf_dupe_alert'])) {
+ $ids['onbehalf_dupe_alert'] = CRM_Utils_Array::value('onbehalf_dupe_alert', $this->_get);
+ }
}
}
diff --git a/CRM/Core/Payment/Backer.php b/CRM/Core/Payment/Backer.php
index 4d0cfae36..e11984691 100644
--- a/CRM/Core/Payment/Backer.php
+++ b/CRM/Core/Payment/Backer.php
@@ -320,7 +320,8 @@ function processContribution($jsonString, &$contributionResult) {
'email' => $params['additional']['email'][0]['email'],
'last_name' => $params['additional']['last_name'],
'first_name' => $params['additional']['first_name'],
- 'phone' => $params['additional']['phone'][0]['phone']
+ 'phone' => $params['additional']['phone'][0]['phone'],
+ 'street_address' => $params['additional']['address'][0]['street_address'],
);
$dedupeParams = CRM_Dedupe_Finder::formatParams($dedupeParams, 'Individual');
$foundDupes = CRM_Dedupe_Finder::dupesByRules(
@@ -333,6 +334,7 @@ function processContribution($jsonString, &$contributionResult) {
array('table' => 'civicrm_contact', 'field' => 'first_name', 'weight' => 8),
array('table' => 'civicrm_email', 'field' => 'email', 'weight' => 10),
array('table' => 'civicrm_phone', 'field' => 'phone', 'weight' => 7),
+ array('table' => 'civicrm_address', 'field' => 'street_address', 'weight' => 8),
),
20
);
diff --git a/CRM/Core/Payment/Mobile.php b/CRM/Core/Payment/Mobile.php
index 0bef1ee14..685ff907b 100644
--- a/CRM/Core/Payment/Mobile.php
+++ b/CRM/Core/Payment/Mobile.php
@@ -151,22 +151,21 @@ function doTransferCheckout(&$params, $component) {
);
CRM_Core_DAO::executeQuery("UPDATE civicrm_contribution SET payment_instrument_id = %1 WHERE id = %2", $options);
}
+ CRM_Core_Error::debug_var('mobile_payment_params', $params);
if($this->_instrumentType == 'linepay'){
+ CRM_Core_Error::debug_var('mobile_payment_linepay', $cid);
$this->_mobilePayment = new CRM_Core_Payment_LinePay($params['payment_processor']);
$this->_mobilePayment->doRequest($params);
return;
}
+ CRM_Core_Error::debug_var('mobile_payment_others', $cid);
// If not use linepay, We need another payment processor.
$qfKey = $params['qfKey'];
$paymentProcessor = $this->_paymentProcessor;
$provider_name = $paymentProcessor['password'];
- $module_name = 'civicrm_'.strtolower($provider_name);
- if ($this->_instrumentType != 'linepay' && module_load_include('inc', $module_name, $module_name.'.checkout') === FALSE) {
- CRM_Core_Error::fatal('Module '.$module_name.' doesn\'t exists.');
- }
if(!empty($params['eventID'])){
$event = new CRM_Event_DAO_Event();
@@ -213,11 +212,11 @@ function doTransferCheckout(&$params, $component) {
print($page);
CRM_Utils_System::civiExit();
}
- else if ($this->_instrumentType == 'googlepay') {
- $checkoutFunction = $module_name.'_do_transfer_checkout';
+ else if ($this->_instrumentType == 'googlepay' && $provider_name == 'spgateway') {
$mode = $is_test ? 'test':'';
$paymentProcessor = CRM_Core_BAO_PaymentProcessor::getPayment($this->_paymentProcessor['user_name'], $mode);
- $checkoutFunction($params, $component, $paymentProcessor, $is_test);
+ $payment = new CRM_Core_Payment_SPGATEWAY($mode, $paymentProcessor);
+ $payment->doTransferCheckout($params, $component);
}
}
@@ -344,12 +343,11 @@ static function transact(){
$type = 'applepay';
}
// call mobile checkout function
- $module_name = 'civicrm_'.strtolower($ppProvider);
- $checkout_func = $module_name.'_mobile_checkout';
- if(!function_exists($checkout_func)){
- return CRM_Core_Error::fatal('Function '.$checkout_func.' doesn\'t exists.');
+ $paymentProviderClass = 'CRM_Core_Payment_'.strtoupper($ppProvider);
+ if (!is_callable(array($paymentProviderClass, 'mobileCheckout'))) {
+ return CRM_Core_Error::fatal('Function '.$paymentProviderClass.'::mobileCheckout doesn\'t exists.');
}
- $return = call_user_func($checkout_func, $type, $post, $objects);
+ $return = call_user_func(array($paymentProviderClass, 'mobileCheckout'), $type, $post, $objects);
if(!empty($return)){
diff --git a/CRM/Core/Payment/SPGATEWAY.php b/CRM/Core/Payment/SPGATEWAY.php
index 3af812f19..7344af722 100644
--- a/CRM/Core/Payment/SPGATEWAY.php
+++ b/CRM/Core/Payment/SPGATEWAY.php
@@ -2,6 +2,18 @@
date_default_timezone_set('Asia/Taipei');
require_once 'CRM/Core/Payment.php';
class CRM_Core_Payment_SPGATEWAY extends CRM_Core_Payment {
+ const EXPIRE_DAY = 7;
+ const MAX_EXPIRE_DAY = 180;
+ const RESPONSE_TYPE = 'JSON';
+ const MPG_VERSION = '1.2';
+ const RECUR_VERSION = '1.0';
+ const QUERY_VERSION = '1.1';
+ const REAL_DOMAIN = 'https://core.newebpay.com';
+ const TEST_DOMAIN = 'https://ccore.newebpay.com';
+ const URL_SITE = '/MPG/mpg_gateway';
+ const URL_API = '/API/QueryTradeInfo';
+ const URL_RECUR = '/MPG/period';
+ const URL_CREDITBG = "/API/CreditCard";
/**
* mode of operation: live or test
@@ -9,7 +21,7 @@ class CRM_Core_Payment_SPGATEWAY extends CRM_Core_Payment {
* @var object
* @static
*/
- static protected $_mode = NULL;
+ protected static $_mode = NULL;
public static $_hideFields = array('invoice_id');
@@ -37,7 +49,10 @@ class CRM_Core_Payment_SPGATEWAY extends CRM_Core_Payment {
* @var object
* @static
*/
- static private $_singleton = NULL;
+ private static $_singleton = NULL;
+
+ private $_config = NULL;
+ private $_processorName = NULL;
/**
* Constructor
@@ -54,7 +69,7 @@ function __construct($mode, &$paymentProcessor) {
$this->_config = $config;
}
- static function getEditableFields($paymentProcessor = NULL, $form = NULL) {
+ public static function getEditableFields($paymentProcessor = NULL, $form = NULL) {
if (empty($paymentProcessor)) {
$returnArray = array();
}
@@ -89,7 +104,7 @@ static function getEditableFields($paymentProcessor = NULL, $form = NULL) {
return $returnArray;
}
- static function postBuildForm($form) {
+ public static function postBuildForm($form) {
$form->addDate('cycle_day_date', FALSE, FALSE, array('formatType' => 'custom', 'format' => 'mm-dd'));
$cycleDay = &$form->getElement('cycle_day');
unset($cycleDay->_attributes['max']);
@@ -103,7 +118,7 @@ static function postBuildForm($form) {
}
}
- static function validateInstallments($fields, $ignore, $form) {
+ public static function validateInstallments($fields, $ignore, $form) {
$errors = array();
$pass = TRUE;
$contribution_status_id = $fields['contribution_status_id'];
@@ -127,7 +142,7 @@ static function validateInstallments($fields, $ignore, $form) {
* @static
*
*/
- static function &singleton($mode, &$paymentProcessor, &$paymentForm = NULL) {
+ public static function &singleton($mode, &$paymentProcessor, &$paymentForm = NULL) {
$processorName = $paymentProcessor['name'];
if (self::$_singleton[$processorName] === NULL) {
self::$_singleton[$processorName] = new CRM_Core_Payment_SPGATEWAY($mode, $paymentProcessor);
@@ -192,49 +207,417 @@ function doTransferCheckout(&$params, $component) {
if ($component != 'contribute' && $component != 'event') {
CRM_Core_Error::fatal(ts('Component is invalid'));
}
- if (module_load_include('inc', 'civicrm_spgateway', 'civicrm_spgateway.checkout') === FALSE) {
- CRM_Core_Error::fatal('Module civicrm_spgateway doesn\'t exists.');
+ $is_test = $this->_mode == 'test' ? 1 : 0;
+ if (isset($this->_paymentForm) && get_class($this->_paymentForm) == 'CRM_Contribute_Form_Payment_Main') {
+ if (empty($params['email-5'])) {
+ // Retrieve email of billing type or primary.
+ $locationTypes = CRM_Core_PseudoConstant::locationType(FALSE, 'name');
+ $bltID = array_search('Billing', $locationTypes);
+ if (!$bltID) {
+ return CRM_Core_Error::statusBounce(ts('Please set a location type of %1', array(1 => 'Billing')));
+ }
+ $fields = array();
+ $fields['email-'.$bltID] = 1;
+ $fields['email-Primary'] = 1;
+ $default = array();
+
+ CRM_Core_BAO_UFGroup::setProfileDefaults($params['contactID'], $fields, $default);
+ if (!empty($default['email-'.$bltID])) {
+ $params['email-5'] = $default['email-'.$bltID];
+ }
+ elseif (!empty($default['email-Primary'])) {
+ $params['email-5'] = $default['email-Primary'];
+ }
+ }
+ $params['item_name'] = $params['description'];
}
- else {
- $is_test = $this->_mode == 'test' ? 1 : 0;
- if (isset($this->_paymentForm) && get_class($this->_paymentForm) == 'CRM_Contribute_Form_Payment_Main') {
- if (empty($params['email-5'])) {
- // Retrieve email of billing type or primary.
- $locationTypes = CRM_Core_PseudoConstant::locationType(FALSE, 'name');
- $bltID = array_search('Billing', $locationTypes);
- if (!$bltID) {
- return CRM_Core_Error::statusBounce(ts('Please set a location type of %1', array(1 => 'Billing')));
- }
- $fields = array();
- $fields['email-'.$bltID] = 1;
- $fields['email-Primary'] = 1;
- $default = array();
-
- CRM_Core_BAO_UFGroup::setProfileDefaults($params['contactID'], $fields, $default);
- if (!empty($default['email-'.$bltID])) {
- $params['email-5'] = $default['email-'.$bltID];
- }
- elseif (!empty($default['email-Primary'])) {
- $params['email-5'] = $default['email-Primary'];
+
+ $instrumentId = $params['civicrm_instrument_id'];
+ $options = array(1 => array( $instrumentId, 'Integer'));
+ $instrumentName = CRM_Core_DAO::singleValueQuery("SELECT v.name FROM civicrm_option_value v INNER JOIN civicrm_option_group g ON v.option_group_id = g.id WHERE g.name = 'payment_instrument' AND v.is_active = 1 AND v.value = %1;", $options);
+ $spgatewayInstruments = self::instruments('code');
+ $instrumentCode = $spgatewayInstruments[$instrumentName];
+ if (empty($instrumentCode)) {
+ // For google pay
+ $instrumentCode = $instrumentName;
+ }
+ $formKey = $component == 'event' ? 'CRM_Event_Controller_Registration_'.$params['qfKey'] : 'CRM_Contribute_Controller_Contribution_'.$params['qfKey'];
+
+ // The first, we insert every contribution into record. After this, we'll use update for the record.
+ $exists = CRM_Core_DAO::singleValueQuery("SELECT cid FROM civicrm_contribution_spgateway WHERE cid = %1", array(
+ 1 => array($params['contributionID'], 'Integer'),
+ ));
+ if (!$exists) {
+ CRM_Core_DAO::executeQuery("INSERT INTO civicrm_contribution_spgateway (cid) VALUES (%1)", array(
+ 1 => array($params['contributionID'], 'Integer'),
+ ));
+ }
+
+ if($instrumentCode == 'Credit' || $instrumentCode == 'WebATM'){
+ $isPayLater = FALSE;
+ }
+ else{
+ $isPayLater = TRUE;
+
+ // Set participant status to 'Pending from pay later', Accupied the seat.
+ if($params['participantID']){
+ $participantStatus = CRM_Event_PseudoConstant::participantStatus();
+ if($newStatus = array_search('Pending from pay later', $participantStatus)){
+ CRM_Core_DAO::setFieldValue('CRM_Event_DAO_Participant', $params['participantID'], 'status_id', $newStatus, 'id');
+ $cancelledStatus = array_search('Cancelled', $participantStatus);
+ $sql = 'SELECT id FROM civicrm_participant WHERE registered_by_id = %1 AND status_id != %2';
+ $paramsRegisteredBy = array(
+ 1 => array($params['participantID'], 'Integer'),
+ 2 => array($cancelledStatus, 'Integer'),
+ );
+ $dao = CRM_Core_DAO::executeQuery($sql, $paramsRegisteredBy);
+ while($dao->fetch()){
+ CRM_Core_DAO::setFieldValue('CRM_Event_DAO_Participant', $dao->id, 'status_id', $newStatus, 'id');
}
}
- $params['item_name'] = $params['description'];
}
- civicrm_spgateway_do_transfer_checkout($params, $component, $this->_paymentProcessor, $is_test);
}
+
+ // now process contribution to save some default value
+ $contrib_params = array( 'id' => $params['contributionID'] );
+ $contrib_values = $contrib_ids = array();
+ CRM_Contribute_BAO_Contribution::getValues($contrib_params, $contrib_values, $contrib_ids);
+ if($params['civicrm_instrument_id']){
+ $contrib_values['payment_instrument_id'] = $params['civicrm_instrument_id'];
+ }
+ $contrib_values['is_pay_later'] = $isPayLater;
+ $contrib_values['trxn_id'] = self::generateTrxnId($is_test, $params['contributionID']);
+ $contribution =& CRM_Contribute_BAO_Contribution::create($contrib_values, $contrib_ids);
+
+ // Inject in quickform sessions
+ // Special hacking for display trxn_id after thank you page.
+ $_SESSION['CiviCRM'][$formKey]['params']['trxn_id'] = $contribution->trxn_id;
+ $_SESSION['CiviCRM'][$formKey]['params']['is_pay_later'] = $isPayLater;
+ $params['trxn_id'] = $contribution->trxn_id;
+
+ $arguments = $this->prepareOrderParams($contribution, $params, $instrumentCode, $formKey);
+ if(!$contrib_values['is_recur']){
+ CRM_Core_Payment_SPGATEWAYAPI::checkMacValue($arguments, $this->_paymentProcessor);
+ }
+ CRM_Core_Error::debug_var('spgateway_post_data_', $arguments);
+ /* TODO: detect this sh*t
+ // making redirect form
+ $alter = array(
+ 'module' => 'civicrm_spgateway',
+ 'billing_mode' => $this->_paymentProcessor['billing_mode'],
+ 'params' => $arguments,
+ );
+ drupal_alter('civicrm_checkout_params', $alter);
+ */
+ print $this->redirectForm($arguments);
+ CRM_Utils_System::civiExit();
}
+ /**
+ * Migrate from _civicrm_spgateway_order
+ *
+ * Prepare order form element
+ *
+ * @param object $contribution
+ * @param array $vars
+ * @param object $paymentProcessor
+ * @param string $instrumentCode
+ * @param string $formKey
+ * @return void
+ */
+ function prepareOrderParams(&$contribution, &$vars, $instrumentCode, $formKey){
+ global $tsLocale;
+
+ // url
+ $ids = CRM_Contribute_BAO_Contribution::buildIds($contribution->id);
+ $notifyURL= CRM_Contribute_BAO_Contribution::makeNotifyUrl($ids, 'spgateway/ipn/'.$instrumentCode);
+ $baseURL= CRM_Utils_System::currentPath();
+ $urlParams = array( "_qf_ThankYou_display" => "1" , "qfKey" => $vars['qfKey'], );
+ $thankyouURL = CRM_Utils_System::url($baseURL, http_build_query($urlParams), TRUE);
+
+ $component = !empty($ids['eventID']) ? 'event' : 'contribution';
+
+ // parameter
+ if($component == 'event' && !empty($_SESSION['CiviCRM'][$formKey])){
+ $values =& $_SESSION['CiviCRM'][$formKey]['values']['event'];
+ }
+ else{
+ $values =& $_SESSION['CiviCRM'][$formKey]['values'];
+ }
+
+ // max 180 days of expire
+ $baseTime = time() + 86400; // because not include today
+ if (!empty($vars['payment_expired_timestamp'])) {
+ $hours = ($vars['payment_expired_timestamp'] - $baseTime) / 3600;
+ }
+ else {
+ $hours = (CRM_Core_Payment::calcExpirationDate(0) - $baseTime) / 3600;
+ }
+ if ($hours < 24) {
+ $values['expiration_day'] = 1;
+ }
+ elseif ($hours > 24 * self::MAX_EXPIRE_DAY ) {
+ $values['expiration_day'] = self::MAX_EXPIRE_DAY;
+ }
+ elseif(!empty($hours)){
+ $values['expiration_day'] = ceil($hours/24);
+ }
+
+ // building vars
+ $amount = $vars['currencyID'] == 'TWD' && strstr($vars['amount'], '.') ? substr($vars['amount'], 0, strpos($vars['amount'],'.')) : $vars['amount'];
+
+ $itemDescription = $vars['description'];
+ $itemDescription .= ($vars['description'] == $vars['item_name'])?'':':'.$vars['item_name'];
+ $itemDescription .= ':'.floatval($vars['amount']);
+ $itemDescription = preg_replace('/[^[:alnum:][:space:]]/u', ' ', $itemDescription);
+
+ if(!$vars['is_recur']){
+ $args = array(
+ 'MerchantID' => $this->_paymentProcessor['user_name'],
+ 'RespondType' => self::RESPONSE_TYPE,
+ 'TimeStamp' => time(),
+ 'Version' => self::MPG_VERSION,
+ 'Amt' => $amount,
+ 'NotifyURL' => $notifyURL,
+ 'Email' => $vars['email-5'],
+ 'LoginType' => '0',
+ 'ItemDesc' => $itemDescription,
+ 'MerchantOrderNo' => $vars['trxn_id'],
+ );
+ if ($this->_paymentProcessor['is_test']) {
+ $args['#url'] = self::TEST_DOMAIN.self::URL_SITE;
+ }
+ else {
+ $args['#url'] = self::REAL_DOMAIN.self::URL_SITE;
+ }
+
+ switch($instrumentCode){
+ case 'ATM':
+ $args['VACC'] = 1;
+ $day = !empty($values['expiration_day']) ? $values['expiration_day'] : self::EXPIRE_DAY;
+ $args['ExpireDate'] = date('Ymd',strtotime("+$day day"));
+ $args['CustomerURL'] = $thankyouURL;
+ // $args['ReturnURL'] = url('spgateway/record/'.$vars['contributionID'], array('absolute' => true));
+ break;
+ case 'BARCODE':
+ $args['BARCODE'] = 1;
+ $day = !empty($values['expiration_day']) ? $values['expiration_day'] : self::EXPIRE_DAY;
+ $args['ExpireDate'] = date('Ymd',strtotime("+$day day"));
+ $args['CustomerURL'] = $thankyouURL;
+ // $args['ReturnURL'] = url('spgateway/record/'.$vars['contributionID'], array('absolute' => true));
+ break;
+ case 'CVS':
+ $args['CVS'] = 1;
+ if($instrumentCode == 'CVS' && !empty($values['expiration_day'])) {
+ $day = !empty($values['expiration_day']) ? $values['expiration_day'] : self::EXPIRE_DAY;
+ $args['ExpireDate'] = date('Ymd',strtotime("+$day day"));
+ }
+ // $args['ReturnURL'] = url('spgateway/record/'.$vars['contributionID'], array('absolute' => true));
+ // $args['Desc_1'] = '';
+ // $args['Desc_2'] = '';
+ // $args['Desc_3'] = '';
+ // $args['Desc_4'] = '';
+
+ #ATM / CVS / BARCODE
+ $args['CustomerURL'] = $thankyouURL;
+ break;
+ case 'WebATM':
+ $args['WEBATM'] = 1;
+ $args['ReturnURL'] = $thankyouURL;
+ break;
+ case 'Credit':
+ $args['CREDIT'] = 1;
+ $args['ReturnURL'] = $thankyouURL;
+ break;
+ case 'GooglePay':
+ $args['ANDROIDPAY'] = 1;
+ $args['ReturnURL'] = $thankyouURL;
+ break;
+ }
+
+ if($tsLocale == CRM_Core_Config::SYSTEM_LANG){
+ $args['LangType'] = 'en';
+ }
+ // Use hook_civicrm_alterPaymentProcessorParams
+ $mode = $this->_paymentProcessor['is_test'] ? 'test' : 'live';
+ $paymentClass = CRM_Core_Payment::singleton($mode, $this->_paymentProcessor, CRM_Core_DAO::$_nullObject);
+ CRM_Utils_Hook::alterPaymentProcessorParams($paymentClass, $vars, $args);
+ }
+ else{
+ $data = array(
+ 'MerchantID' => $this->_paymentProcessor['user_name'],
+ 'RespondType' => self::RESPONSE_TYPE,
+ 'TimeStamp' => time(),
+ 'Version' => self::RECUR_VERSION,
+ 'Amt' => $amount,
+ 'NotifyURL' => $notifyURL."&qfKey=".$vars['qfKey'],
+ 'PayerEmail' => $vars['email-5'],
+ 'LoginType' => '0',
+ 'MerOrderNo' => $vars['trxn_id'],
+ 'ProdDesc' => $itemDescription,
+ 'PeriodAmt' => $amount,
+ 'PeriodStartType' => 2,
+ 'ReturnURL' => $thankyouURL,
+ 'PaymentInfo' => 'N',
+ 'OrderInfo' => 'N',
+ );
+ $period = strtoupper($vars['frequency_unit'][0]);
+
+ if($vars['frequency_unit'] == 'month'){
+ $frequency_interval = $vars['frequency_interval'] > 12 ? 12 : $vars['frequency_interval'];
+ $data['PeriodType'] = 'M';
+ $data['PeriodPoint'] = date('d');
+ }
+ elseif($vars['frequency_unit'] == 'week'){
+ $frequency_interval = (7 * $vars['frequency_interval']) > 365 ? 365 : ($vars['frequency_interval'] * 7);
+ $data['PeriodType'] = 'W';
+ }
+ elseif($vars['frequency_unit'] == 'year'){
+ $frequency_interval = 1;
+ $data['PeriodType'] = 'Y';
+ $data['PeriodPoint'] = date('md');
+ }
+ if(empty($frequency_interval)){
+ $frequency_interval = 1;
+ }
+ // $data['PeriodTimes'] = $frequency_interval;
+ if($vars['frequency_unit'] == 'year'){
+ $data['PeriodTimes'] = empty($vars['installments']) ? 9 : $vars['installments'];
+ }else{
+ $data['PeriodTimes'] = empty($vars['installments']) ? 99 : $vars['installments']; // support endless
+ }
+ if($tsLocale == CRM_Core_Config::SYSTEM_LANG){
+ $data['LangType'] = 'en';
+ }
+ // Use hook_civicrm_alterPaymentProcessorParams
+ $mode = $this->_paymentProcessor['is_test'] ? 'test' : 'live';
+ $paymentClass = CRM_Core_Payment::singleton($mode, $this->_paymentProcessor, CRM_Core_DAO::$_nullObject);
+ CRM_Utils_Hook::alterPaymentProcessorParams($paymentClass, $vars, $data);
+ // Encrypt Recurring Request.
+ $str = http_build_query($data, '', '&');
+ $strPost = CRM_Core_Payment_SPGATEWAYAPI::recurEncrypt($str, $this->_paymentProcessor);
+ $args['PostData_'] = $strPost;
+ $args['MerchantID_'] = $this->_paymentProcessor['user_name'];
+ if ($this->_paymentProcessor['is_test']) {
+ $args['#url'] = self::TEST_DOMAIN.self::URL_RECUR;
+ }
+ else {
+ $args['#url'] = self::REAL_DOMAIN.self::URL_RECUR;
+ }
+ }
+
+
+ return $args ;
+ }
+
+
+ private function redirectForm($vars){
+ header('Pragma: no-cache');
+ header('Cache-Control: no-store, no-cache, must-revalidate');
+ header('Expires: 0');
+
+ $output = "";
+
+ $js = 'document.forms.redirect.submit();';
+ $output .= '
';
+ return <<
+
+
+
+
+
+ {$output}
+
+
+
+EOT;
+ }
+
+ public static function mobileCheckout($type, $post, $objects) {
+ $contribution = $objects['contribution'];
+ $merchantPaymentProcessor = $objects['payment_processor'];
+
+ if($type = 'applepay') {
+ $email = new CRM_Core_DAO_Email();
+ $email->contact_id = $contribution->contact_id;
+ $email->is_primary = true;
+ $email->find(TRUE);
+
+ $token = urlencode(json_encode($post['token']));
+ $is_test = $contribution->is_test;
+
+ $params = array(
+ 'TimeStamp' => time(),
+ 'Version' => '1.0',
+ 'MerchantOrderNo' => CRM_Core_Payment_SPGATEWAY::generateTrxnId($is_test, $contribution->id),
+ 'Amt' => $contribution->total_amount,
+ 'ProdDesc' => $post['description'],
+ 'PayerEmail' => $email->email,
+ 'CardNo' => '',
+ 'Exp' => '',
+ 'CVC' => '',
+ 'APPLEPAY' => $token,
+ 'APPLEPAYTYPE' => '02',
+ );
+ CRM_Core_Error::debug('applepay_transact_curl_params_before_encrypt', $params);
+
+ $data = CRM_Core_Payment_SPGATEWAYAPI::recurEncrypt(http_build_query($params), get_object_vars($merchantPaymentProcessor));
+
+ $data = array(
+ 'MerchantID_' => $merchantPaymentProcessor->user_name,
+ 'PostData_' => $data,
+ 'Pos_' => 'JSON',
+ );
+ if($contribution->is_test){
+ $url = CRM_Core_Payment_SPGATEWAY::TEST_DOMAIN.CRM_Core_Payment_SPGATEWAY::URL_CREDITBG;
+ }else{
+ $url = CRM_Core_Payment_SPGATEWAY::REAL_DOMAIN.CRM_Core_Payment_SPGATEWAY::URL_CREDITBG;
+ }
+
+ CRM_Core_Error::debug('applepay_transact_curl_data_after_encrypt', $data);
+
+ $ch = curl_init($url);
+ $opt = array();
+ $opt[CURLOPT_RETURNTRANSFER] = TRUE;
+ $opt[CURLOPT_POST] = TRUE;
+ $opt[CURLOPT_POSTFIELDS] = $data;
+ $opt[CURLOPT_SSL_VERIFYPEER] = FALSE;
+ curl_setopt_array($ch, $opt);
+
+ $result = curl_exec($ch);
+ $status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
+ if ($result === FALSE) {
+ $errno = curl_errno($ch);
+ $err = curl_error($ch);
+ $curlError = array($errno => $err);
+ }
+ else{
+ $curlError = array();
+ }
+ curl_close($ch);
+ CRM_Core_Error::debug('applepay_transact_curl_error', $curlError);
+
+ $result = json_decode($result);
+ CRM_Core_Payment_SPGATEWAYAPI::writeRecord($contribution->id, get_object_vars($result));
+ $return = array();
+ if($result->Status == 'SUCCESS'){
+ $return['is_success'] = true;
+ }
+ $return['message'] = $result->Message;
+ }
+ return $return;
+ }
- /*
- * $params = array(
- * 'contribution_recur_id => Positive,
- * 'contribution_status_id' => Positive(7 => suspend, 3 => terminate, 5 => restart),
- * 'amount' => Positive,
- * 'frequency_unit' => String('year', 'month')
- * 'cycle_day' => Positive(1 - 31, 101 - 1231)
- * 'end_date' => Date
- * )
- */
function doUpdateRecur($params, $debug = FALSE) {
if ($debug) {
CRM_Core_Error::debug('SPGATEWAY doUpdateRecur $params', $params);
@@ -243,10 +626,7 @@ function doUpdateRecur($params, $debug = FALSE) {
if ($this->_paymentProcessor['url_recur'] != 1) {
return $params;
}
- if (module_load_include('inc', 'civicrm_spgateway', 'civicrm_spgateway.api') === FALSE) {
- CRM_Core_Error::fatal('Module civicrm_spgateway doesn\'t exists.');
- }
- else if (empty($params['contribution_recur_id'])) {
+ if (empty($params['contribution_recur_id'])) {
CRM_Core_Error::fatal('Missing contribution recur ID in params');
}
else {
@@ -283,9 +663,9 @@ function doUpdateRecur($params, $debug = FALSE) {
if (!empty($params['contribution_status_id'])) {
$apiConstructParams['apiType'] = 'alter-status';
- $spgatewayAPI = new spgateway_spgateway_api($apiConstructParams);
+ $spgatewayAPI = new CRM_Core_Payment_SPGATEWAYAPI($apiConstructParams);
$newStatusId = $params['contribution_status_id'];
-
+
/*
* $requestParams = array(
* 'AlterStatus' => Positive(7 => suspend, 3 => terminate, 5 => restart),
@@ -330,7 +710,7 @@ function doUpdateRecur($params, $debug = FALSE) {
// Send alter other property API.
$apiConstructParams['apiType'] = 'alter-amt';
- $spgatewayAPI = new spgateway_spgateway_api($apiConstructParams);
+ $spgatewayAPI = new CRM_Core_Payment_SPGATEWAYAPI($apiConstructParams);
$isChangeRecur = FALSE;
$requestParams = array(
'Version' => self::$_recurEditAPIVersion,
@@ -430,59 +810,6 @@ function cancelRecuringMessage($recurID){
}
}
- /**
- * return array(
- * // All instrument:
- * 'status' => contribuion_status
- * 'msg' => return message
- *
- * // Not Credit Card:
- * 'payment_instrument' => civicrm_spgateway_notify_display() return value
- * )
- */
- function doGetResultFromIPNNotify($contributionId, $submitValues = array()) {
- // First, check if it is redirect payment.
- $instruments = CRM_Contribute_PseudoConstant::paymentInstrument('Name');
- $cDao = new CRM_Contribute_DAO_Contribution();
- $cDao->id = $contributionId;
- $cDao->fetch(TRUE);
- if (strstr($instruments[$cDao->payment_instrument_id], 'Credit')) {
- // If contribution status id == 2, wait 3 second for IPN trigger
- if ($cDao->contribution_status_id == 2) {
- sleep(3);
- $contribution_status_id = CRM_Core_DAO::getFieldValue('CRM_Contribute_DAO_Contribution', $contributionId, 'contribution_status_id');
- if ($contribution_status_id == 2) {
- $ids = CRM_Contribute_BAO_Contribution::buildIds($contributionId);
- $query = CRM_Contribute_BAO_Contribution::makeNotifyUrl($ids, NULL, TRUE);
- parse_str($query, $get);
- $result = civicrm_spgateway_ipn('Credit', $submitValues, $get, FALSE);
- if(strstr($result, 'OK')){
- $status = 1;
- }
- else{
- $status = 2;
- }
- }
- }
- else {
- $status = $cDao->contribution_status_id;
- if (!empty($submitValues['JSONData'])) {
- $return_params = _civicrm_spgateway_post_decode($submitValues['JSONData']);
- }
- if(!empty($submitValues['Period']) && empty($return_params)){
- $payment_processors = CRM_Core_BAO_PaymentProcessor::getPayment($cDao->payment_processor_id, $cDao->is_test?'test':'live');
- $return_params = _civicrm_spgateway_post_decode(_civicrm_spgateway_recur_decrypt($submitValues['Period'], $payment_processors));
- }
- $msg = _civicrm_spgateway_error_msg($return_params['RtnCode']);
- }
- }
- else {
-
- }
-
- }
-
-
/**
* Function called from contributionRecur page to show tappay detail information
*
@@ -534,7 +861,7 @@ public static function doRecurUpdate($id, $idType = 'contribution', $form = NULL
}
}
- $result = civicrm_spgateway_single_check($trxn_id, TRUE);
+ $result = self::recurSyncTransaction($trxn_id, TRUE);
$session = CRM_Core_Session::singleton();
if (!empty($result)) {
if ($isAddedNewContribution) {
@@ -565,7 +892,7 @@ public static function doRecurUpdate($id, $idType = 'contribution', $form = NULL
}
}
- static function doSingleQueryRecord($contributionId = NULL) {
+ public static function doSingleQueryRecord($contributionId = NULL, $order = NULL) {
$get = $_GET;
unset($get['q']);
if (!is_numeric($contributionId) || empty($contributionId)) {
@@ -582,68 +909,65 @@ static function doSingleQueryRecord($contributionId = NULL) {
$resultMessage = ts("The contribution with transaction ID: %1 can't find from Newebpay API.", array(1 => $cid));
}
else {
- if (module_load_include('inc', 'civicrm_spgateway', 'civicrm_spgateway.checkout') === FALSE) {
- $resultMessage = ts('Module %1 doesn\'t exists.', array(1 => 'civicrm_spgateway'));
+ if (!empty($order)) {
+ // this is for ci testing or something we already had response
+ // should be object or associated array
+ self::syncTransaction($trxnId, $order);
}
else {
- if (!function_exists('civicrm_spgateway_single_contribution_sync')) {
- $resultMessage = ts("Sync single contribution function doesn't exist.");
- }
- else {
- civicrm_spgateway_single_contribution_sync($trxnId);
- $resultMessage = ts("Synchronizing to %1 server success.", array(1 => ts("NewebPay")));
- $updatedDAO = new CRM_Contribute_DAO_Contribution();
- $updatedDAO->id = $cid;
- $updatedDAO->find(TRUE);
- $diffContribution = array();
- if ($updatedDAO->contribution_status_id != $origDAO->contribution_status_id) {
- $status = CRM_Contribute_PseudoConstant::contributionStatus();
- $diffContribution[ts('Contribution Status')] = array($status[$origDAO->contribution_status_id], $status[$updatedDAO->contribution_status_id]);
-
- // Check it will send Email.
- $components = CRM_Contribute_BAO_Contribution::getComponentDetails(array($cid));
- $contributeComponent = $components[$cid];
- $componentName = $contributeComponent['component'];
- $pageId = $contributeComponent['page_id'];
- if ($componentName == 'contribute' && !empty($pageId)) {
- $pageParams = array(1 => array( $pageId, 'Positive'));
- $isEmailReceipt = CRM_Core_DAO::singleValueQuery("SELECT is_email_receipt FROM civicrm_contribution_page WHERE id = %1", $pageParams);
- if ($isEmailReceipt) {
- $diffContribution[] = ts('A notification email has been sent to the supporter.');
- }
- }
+ self::syncTransaction($trxnId);
+ }
+ $resultMessage = ts("Synchronizing to %1 server success.", array(1 => ts("NewebPay")));
+ $updatedDAO = new CRM_Contribute_DAO_Contribution();
+ $updatedDAO->id = $cid;
+ $updatedDAO->find(TRUE);
+ $diffContribution = array();
+ if ($updatedDAO->contribution_status_id != $origDAO->contribution_status_id) {
+ $status = CRM_Contribute_PseudoConstant::contributionStatus();
+ $diffContribution[ts('Contribution Status')] = array($status[$origDAO->contribution_status_id], $status[$updatedDAO->contribution_status_id]);
- // Check if the SMS is sent.
- $activityType = CRM_Core_PseudoConstant::activityType(TRUE, TRUE, FALSE, 'name', TRUE);
- $activitySMSParams = array(
- 'source_record_id' => $cid,
- 'activity_type_id' => CRM_Utils_Array::key('Contribution SMS', $activityType),
- );
- $smsActivity = new CRM_Activity_DAO_Activity();
- $smsActivity->copyValues($activitySMSParams);
- if ($smsActivity->find(TRUE)) {
- $diffContribution[] = ts('SMS Sent');
- }
- }
- if ($updatedDAO->receive_date != $origDAO->receive_date) {
- $diffContribution[ts('Received Date')] = array($origDAO->receive_date, $updatedDAO->receive_date);
- }
- if ($updatedDAO->cancel_date != $origDAO->cancel_date) {
- $diffContribution[ts('Cancel Date')] = array($origDAO->cancel_date, $updatedDAO->cancel_date);
- }
- if ($updatedDAO->cancel_reason != $origDAO->cancel_reason) {
- $diffContribution[ts('Cancel Reason')] = array($origDAO->cancel_reason, $updatedDAO->cancel_reason);
- }
- if ($updatedDAO->receipt_id != $origDAO->receipt_id) {
- $diffContribution[ts('Receipt ID')] = array($origDAO->receipt_id, $updatedDAO->receipt_id);
- }
- if ($updatedDAO->receipt_date != $origDAO->receipt_date) {
- $diffContribution[ts('Receipt Date')] = array($origDAO->receipt_date, $updatedDAO->receipt_date);
- }
- if (empty($diffContribution)) {
- $diffContribution[] = ts("There are no any change.");
+ // Check it will send Email.
+ $components = CRM_Contribute_BAO_Contribution::getComponentDetails(array($cid));
+ $contributeComponent = $components[$cid];
+ $componentName = $contributeComponent['component'];
+ $pageId = $contributeComponent['page_id'];
+ if ($componentName == 'contribute' && !empty($pageId)) {
+ $pageParams = array(1 => array( $pageId, 'Positive'));
+ $isEmailReceipt = CRM_Core_DAO::singleValueQuery("SELECT is_email_receipt FROM civicrm_contribution_page WHERE id = %1", $pageParams);
+ if ($isEmailReceipt) {
+ $diffContribution[] = ts('A notification email has been sent to the supporter.');
}
}
+
+ // Check if the SMS is sent.
+ $activityType = CRM_Core_PseudoConstant::activityType(TRUE, TRUE, FALSE, 'name', TRUE);
+ $activitySMSParams = array(
+ 'source_record_id' => $cid,
+ 'activity_type_id' => CRM_Utils_Array::key('Contribution SMS', $activityType),
+ );
+ $smsActivity = new CRM_Activity_DAO_Activity();
+ $smsActivity->copyValues($activitySMSParams);
+ if ($smsActivity->find(TRUE)) {
+ $diffContribution[] = ts('SMS Sent');
+ }
+ }
+ if ($updatedDAO->receive_date != $origDAO->receive_date) {
+ $diffContribution[ts('Received Date')] = array($origDAO->receive_date, $updatedDAO->receive_date);
+ }
+ if ($updatedDAO->cancel_date != $origDAO->cancel_date) {
+ $diffContribution[ts('Cancel Date')] = array($origDAO->cancel_date, $updatedDAO->cancel_date);
+ }
+ if ($updatedDAO->cancel_reason != $origDAO->cancel_reason) {
+ $diffContribution[ts('Cancel Reason')] = array($origDAO->cancel_reason, $updatedDAO->cancel_reason);
+ }
+ if ($updatedDAO->receipt_id != $origDAO->receipt_id) {
+ $diffContribution[ts('Receipt ID')] = array($origDAO->receipt_id, $updatedDAO->receipt_id);
+ }
+ if ($updatedDAO->receipt_date != $origDAO->receipt_date) {
+ $diffContribution[ts('Receipt Date')] = array($origDAO->receipt_date, $updatedDAO->receipt_date);
+ }
+ if (empty($diffContribution)) {
+ $diffContribution[] = ts("There are no any change.");
}
}
// Redirect to contribution view page.
@@ -661,11 +985,13 @@ static function doSingleQueryRecord($contributionId = NULL) {
}
$resultMessage.="";
}
- CRM_Core_Session::setStatus($resultMessage);
- CRM_Utils_System::redirect($redirect);
+ if (!isset($order)) {
+ CRM_Core_Session::setStatus($resultMessage);
+ CRM_Utils_System::redirect($redirect);
+ }
}
- static function getSyncDataUrl($contributionId, &$form = NULL) {
+ public static function getSyncDataUrl($contributionId, &$form = NULL) {
$get = $_GET;
unset($get['q']);
$query = http_build_query($get);
@@ -698,5 +1024,560 @@ static function getSyncDataUrl($contributionId, &$form = NULL) {
return $sync_url;
}
-}
+ /**
+ * The IPN warpping
+ *
+ * @param array $arguments Router will pass array into this function
+ * @param array $post Simulate POST data
+ * @param array $get Simulate GET data
+ * @param bool $print print result
+ * @return void
+ */
+ public static function doIPN($arguments, $post = NULL, $get = NULL, $print = TRUE) {
+ $post = !empty($post) ? $post : $_POST;
+ $get = !empty($get) ? $get : $_GET;
+ if (!empty($arguments)) {
+ if (is_array($arguments)) {
+ $instrument = end($arguments);
+ }
+ elseif (is_string($arguments)){
+ $instrument = $arguments;
+ }
+ else {
+ CRM_Core_Error::debug_log_message("Spgateway: IPN Missing require argument.");
+ CRM_Utils_System::civiExit();
+ }
+ }
+
+ // detect variables
+ if(empty($post)){
+ CRM_Core_Error::debug_log_message("Spgateway: Could not find POST data from payment server.");
+ CRM_Utils_System::civiExit();
+ }
+ else{
+ // validate some post
+ if (!empty($post['JSONData']) || !empty($post['Period']) || !empty($post['Result'])) {
+ $ipn = new CRM_Core_Payment_SPGATEWAYIPN($post, $get);
+ $result = $ipn->main($instrument);
+ if(is_string($result) && $print){
+ echo $result;
+ }
+ else{
+ return $result;
+ }
+ }
+ else {
+ CRM_Core_Error::debug_log_message("Spgateway: Invlid POST data.");
+ CRM_Core_Error::debug_var("spgateway_ipn_post", $post);
+ }
+ }
+ CRM_Utils_System::civiExit();
+ }
+
+ /**
+ * Migrate from _civicrm_spgateway_instrument
+ *
+ * @param string $type
+ * @return void
+ */
+ public static function instruments($type = 'normal'){
+ $i = array(
+ 'Credit Card' => array('label' => ts('Credit Card'), 'desc' => '', 'code' => 'Credit'),
+ 'ATM' => array('label' => ts('ATM Transfer'), 'desc' => '', 'code' => 'ATM'),
+ 'Web ATM' => array('label' => ts('Web ATM'), 'desc' => '', 'code' => 'WebATM'),
+ 'Convenient Store' => array('label' => ts('Convenient Store Barcode'), 'desc'=>'', 'code' => 'BARCODE'),
+ 'Convenient Store (Code)' => array('label'=> ts('Convenient Store (Code)'),'desc' => '', 'code' => 'CVS'),
+ );
+ if($type == 'form_name'){
+ foreach($i as $name => $data){
+ $form_name = preg_replace('/[^0-9a-z]+/i', '_', strtolower($name));
+ $instrument[$form_name] = $data;
+ }
+ return $instrument;
+ }
+ elseif($type == 'code'){
+ foreach($i as $name => $data){
+ $instrument[$name] = $data['code'];
+ }
+ return $instrument;
+ }
+ else{
+ return $i;
+ }
+ }
+
+ /**
+ * Migrate from _civicrm_spgateway_trxn_id
+ *
+ * @param int $is_test
+ * @param int $id
+ * @return string
+ */
+ public static function generateTrxnId($is_test, $id){
+ if($is_test){
+ $trxnId = 'test' . substr(str_replace(array('.','-'), '', $_SERVER['HTTP_HOST']), 0, 3) . $id. 'T'. mt_rand(100, 999);
+ return $trxnId;
+ }
+ return (string) $id;
+ }
+
+ /**
+ * Migrate from civicrm_spgateway_single_contribution_sync
+ *
+ * Sync non-recurring transaction by specific trxn id
+ *
+ * @param int $inputTrxnId
+ * @return bool|object
+ * @param string $order
+ */
+ public static function syncTransaction($inputTrxnId, $order = NULL) {
+ $paymentProcessorId = 0;
+
+ // Check contribution is exists
+ $contribution = new CRM_Contribute_DAO_Contribution();
+ $contribution->trxn_id = $inputTrxnId;
+ if ($contribution->find(TRUE)) {
+ $paymentProcessorId = $contribution->payment_processor_id;
+ if ($contribution->contribution_status_id == 1) {
+ $message = ts('There are no any change.');
+ return $message;
+ }
+ }
+ // we can't support single contribution check because lake of payment processor id #TODO - logic to get payment processor id
+ if (!empty($paymentProcessorId)) {
+ $paymentProcessor = CRM_Core_BAO_PaymentProcessor::getPayment($paymentProcessorId, $contribution->is_test ? 'test': 'live');
+
+ if (strstr($paymentProcessor['payment_processor_type'], 'SPGATEWAY') && !empty($paymentProcessor['user_name'])) {
+ if ($order) {
+ // this is for ci testing or something we already had response
+ // should be object or associated array
+ $result = $order;
+ }
+ else {
+ $amount = $contribution->total_amount;
+ if ($contribution->contribution_recur_id && !strstr($inputTrxnId, '_')) {
+ $trxnId = $inputTrxnId.'_1';
+ $recurring_first_contribution = TRUE;
+ }
+ else {
+ $trxnId = $inputTrxnId;
+ }
+ $data = array(
+ 'Amt' => floor($amount),
+ 'MerchantID' => $paymentProcessor['user_name'],
+ 'MerchantOrderNo' => $trxnId,
+ 'RespondType' => self::RESPONSE_TYPE,
+ 'TimeStamp' => CRM_REQUEST_TIME,
+ 'Version' => self::QUERY_VERSION,
+ );
+ $args = array('IV','Amt','MerchantID','MerchantOrderNo', 'Key');
+ CRM_Core_Payment_SPGATEWAYAPI::encode($data, $paymentProcessor, $args);
+ $urlApi = $contribution->is_test ? self::TEST_DOMAIN.self::URL_API : self::REAL_DOMAIN.self::URL_API;
+ $result = CRM_Core_Payment_SPGATEWAYAPI::sendRequest($urlApi, $data);
+ }
+
+ // Online contribution
+ // Only trigger if there are pay time in result;
+ if (!empty($result) && $result->Status == 'SUCCESS' && $result->Result->TradeStatus !== '0') {
+ // complex part to simulate spgateway ipn
+ $ipnGet = $ipnPost = array();
+
+ // prepare post, complex logic because recurring have different variable names
+ $ipnResult = clone $result;
+ if ($result->Result->TradeStatus != 1) {
+ $ipnResult->Status =$result->Result->RespondCode;
+ }
+ $ipnResult->Message = $result->Result->RespondMsg;
+ // Pass CheckCode.
+ unset($ipnResult->Result->CheckCode);
+ $ipnPost = (array) $ipnResult;
+
+ if ($contribution->contribution_recur_id) {
+ $ipnResult->Result->AuthAmt = $result->Result->Amt;
+ unset($ipnResult->Result->Amt);
+ $ipnResult->Result->OrderNo = $result->Result->MerchantOrderNo;
+ list($first_id, $period_times) = explode('_', $result->Result->MerchantOrderNo);
+ if(!empty($period_times) && $period_times != 1){
+ $ipnResult->Result->AlreadyTimes = $period_times;
+ }
+ $ipnResult->Result->MerchantOrderNo = $first_id;
+ $ipnResult = json_encode($ipnResult);
+ $ipnPost = array('Period' => CRM_Core_Payment_SPGATEWAYAPI::recurEncrypt($ipnResult, $paymentProcessor));
+ }
+
+ // prepare get
+ $ids = CRM_Contribute_BAO_Contribution::buildIds($contribution->id);
+ $query = CRM_Contribute_BAO_Contribution::makeNotifyUrl($ids, NULL, TRUE);
+ parse_str($query, $ipnGet);
+
+ // create recurring record
+ $result->_post = $ipnPost;
+ $result->_get = $ipnGet;
+ $result->_response = self::doIPN(array('spgateway', 'ipn', 'Credit'), $result->_post, $result->_get, FALSE);
+
+ if ($recurring_first_contribution) {
+ $contribution = new CRM_Contribute_DAO_Contribution();
+ $contribution->trxn_id = $inputTrxnId;
+ if ($contribution->find(TRUE) && strstr($trxnId, '_1')) {
+ // The case first contribution trxn_id not append '_1' in the end.
+ CRM_Core_DAO::setFieldValue('CRM_Contribute_DAO_Contribution', $contribution->id, 'trxn_id', $trxnId);
+ }
+ }
+ return $result;
+ }
+ }
+ }
+ return FALSE;
+ }
+
+ /**
+ * Always trying to fetch next trxn_id which not appear in CRM
+ */
+ /**
+ * Migrate from civicrm_spgateway_recur_check
+ *
+ * Trying to get next transaction by given recurring id
+ *
+ * @param int $recurId
+ * @return void
+ */
+ public static function recurSync($recurId) {
+ $query = "SELECT trxn_id, CAST(REGEXP_REPLACE(trxn_id, '^[0-9_r]+_([0-9]+)$', '\\\\1') as UNSIGNED) as number FROM civicrm_contribution WHERE contribution_recur_id = %1 AND CAST(trxn_id as UNSIGNED) < 900000000 ORDER BY number DESC";
+ $result = CRM_Core_DAO::executeQuery($query, array(1 => array($recurId, 'Integer')));
+ $result->fetch();
+ if(!empty($result->N)){
+ // when recurring trxn_id have underline, eg oooo_1
+ if (strstr($result->trxn_id, '_')) {
+ list($parentTrxnId, $recurringInstallment, $oldRecurInstallment) = explode('_', $result->trxn_id);
+ if ($parentTrxnId == 'r' && is_numeric($oldRecurInstallment)) {
+ // for old recurring. trxn_id like 'r_12_3', $parentTrxnId = 'r', $recurringInstallment = 12, $oldRecurInstallment = 3
+ $oldRecurInstallment++;
+ self::recurSyncTransaction($parentTrxnId.'_'.$recurringInstallment.'_'.$oldRecurInstallment, $createContribution = TRUE);
+ }
+ elseif (is_numeric($recurringInstallment)) {
+ // for current recurring, for trxn_id like 123_4, $parentTrxnId = 123, $recurringInstallment = 4
+ $recurringInstallment++;
+ self::recurSyncTransaction($parentTrxnId.'_'.$recurringInstallment, $createContribution = TRUE);
+ }
+ }
+ // when first recurring trxn_id record without underline
+ else {
+ $parentTrxnId= $result->trxn_id;
+ $installment = 2;
+ self::recurSyncTransaction($parentTrxnId, TRUE);
+ }
+ }
+ }
+
+ /**
+ * Migrate from civicrm_spgateway_single_check
+ *
+ * Create recurring transacation by specific trxn id
+ * Base on spgateway / neweb response
+ *
+ * @param string $trxnId
+ * @param bool $createContribution
+ * @param string $order
+ * @return object|bool
+ */
+ public static function recurSyncTransaction($trxnId, $createContribution = FALSE, $order = NULL) {
+ $parentTrxnId = 0;
+ $paymentProcessorId = 0;
+ if (strstr($trxnId, '_')) {
+ list($recurId, $installment, $oldInstallment) = explode('_', $trxnId);
+ if ($recurId == 'r' && !empty($oldInstallment)) {
+ // Old newebpay recurring, format: r_123_4
+ $parentTrxnId = $recurId.'_'.$installment;
+ }
+ else {
+ // Current spgateway recurring, format: 1234_5
+ $parentTrxnId = $recurId;
+ }
+ }
+ $contribution = new CRM_Contribute_DAO_Contribution();
+ $contribution->trxn_id = $trxnId;
+ if ($contribution->find(TRUE)) {
+ $paymentProcessorId = $contribution->payment_processor_id;
+ if ($contribution->contribution_status_id == 1) {
+ $createContribution = FALSE; // Found, And contribution is already success.
+ }
+ elseif (empty($parentTrxnId) && $createContribution) {
+ // First recurring or single contribution.
+ $contribution = new CRM_Contribute_DAO_Contribution();
+ $contribution->id = $trxnId;
+ if ($contribution->find(TRUE)) {
+ $paymentProcessorId = $contribution->payment_processor_id;
+ if (!empty($contribution->contribution_recur_id)) {
+ // First recurring contribution
+ $trxnId = $trxnId.'_1';
+ }
+ }
+ }
+ }
+ elseif($createContribution) {
+ // recurring contribution
+ if ($parentTrxnId) {
+ $contribution = new CRM_Contribute_DAO_Contribution();
+ $contribution->trxn_id = $parentTrxnId.'_1';
+ if ($contribution->find(TRUE)) {
+ $paymentProcessorId = $contribution->payment_processor_id;
+ }
+ else {
+ $contribution = new CRM_Contribute_DAO_Contribution();
+ $contribution->trxn_id = $parentTrxnId;
+ if ($contribution->find(TRUE)) {
+ $paymentProcessorId = $contribution->payment_processor_id;
+ }
+ }
+ }
+ }
+
+ // we can't support single contribution check because lake of payment processor id #TODO - logic to get payment processor id
+ if (!empty($paymentProcessorId)) {
+ $paymentProcessor = CRM_Core_BAO_PaymentProcessor::getPayment($paymentProcessorId, $contribution->is_test ? 'test': 'live');
+
+ if (!empty($paymentProcessor['user_name'])) {
+ if ($order) {
+ // this is for ci testing or something we already had response
+ // should be object or associated array
+ $result = $order;
+ }
+ else {
+ $amount = CRM_Core_DAO::singleValueQuery('SELECT amount FROM civicrm_contribution_recur WHERE id = %1', array(1 => array($contribution->contribution_recur_id, 'Positive')));
+ $data = array(
+ 'Amt' => floor($amount),
+ 'MerchantID' => $paymentProcessor['user_name'],
+ 'MerchantOrderNo' => $trxnId,
+ 'RespondType' => self::RESPONSE_TYPE,
+ 'TimeStamp' => CRM_REQUEST_TIME,
+ 'Version' => self::QUERY_VERSION,
+ );
+ $args = array('IV','Amt','MerchantID','MerchantOrderNo', 'Key');
+ CRM_Core_Payment_SPGATEWAYAPI::encode($data, $paymentProcessor, $args);
+ $urlApi = $contribution->is_test ? self::TEST_DOMAIN.self::URL_API : self::REAL_DOMAIN.self::URL_API;
+ $result = CRM_Core_Payment_SPGATEWAYAPI::sendRequest($urlApi, $data);
+ }
+
+ // Online contribution
+ if (!empty($result) && $result->Status == 'SUCCESS') {
+ if ($createContribution && $contribution->id) {
+ // complex part to simulate spgateway ipn
+ $ipnGet = $ipnPost = array();
+
+ // prepare post, complex logic because recurring have different variable names
+ $ipnResult = clone $result;
+ if ($result->Result->TradeStatus != 1) {
+ $ipnResult->Status =$result->Result->RespondCode;
+ }
+ $ipnResult->Message = $result->Result->RespondMsg;
+
+ $ipnResult->Result->AuthAmt = $result->Result->Amt;
+ unset($ipnResult->Result->Amt);
+ unset($ipnResult->Result->CheckCode);
+ $ipnResult->Result->OrderNo = $result->Result->MerchantOrderNo;
+ list($first_id, $period_times) = explode('_', $result->Result->MerchantOrderNo);
+ if(!empty($period_times) && $period_times != 1){
+ $ipnResult->Result->AlreadyTimes = $period_times;
+ }
+ $ipnResult->Result->MerchantOrderNo = $first_id;
+ $ipnResult = json_encode($ipnResult);
+ $ipnPost = array('Period' => CRM_Core_Payment_SPGATEWAYAPI::recurEncrypt($ipnResult, $paymentProcessor));
+
+ // prepare get
+ $ids = CRM_Contribute_BAO_Contribution::buildIds($contribution->id);
+ $query = CRM_Contribute_BAO_Contribution::makeNotifyUrl($ids, NULL, $return_query = TRUE);
+ parse_str($query, $ipnGet);
+
+ // create recurring record
+ $result->_post = $ipnPost;
+ $result->_get = $ipnGet;
+ $result->_response = self::doIPN(array('spgateway', 'ipn', 'Credit'), $ipnPost, $ipnGet, FALSE);
+ $contribution = new CRM_Contribute_DAO_Contribution();
+ $contribution->trxn_id = $parentTrxnId;
+ if ($contribution->find(TRUE) && strstr($trxnId, '_1')) {
+ // The case first contribution trxn_id not append '_1' in the end.
+ CRM_Core_DAO::setFieldValue('CRM_Contribute_DAO_Contribution', $contribution->id, 'trxn_id', $trxnId);
+ }
+ return $result;
+ }
+ else {
+ return $result;
+ }
+ }
+ }
+ }
+ return FALSE;
+ }
+
+ /**
+ * Using weblog post data to sync
+ *
+ * @param string $processOnlyDate string that format YYYYmmddHH indicate only process date in that hour
+ * @param array $lines custom provided lines for test o process
+ * @return void
+ */
+ public static function syncTransactionWebLog($filterDatetime = '', $lines = NULL) {
+ $paymentProcessors = array();
+ if (isset($lines) && is_array($lines)) {
+ $logLines = $lines;
+ }
+ else {
+ $logLines = array();
+ $logFile = CRM_Utils_System::cmsRootPath().'/'.CRM_Core_Config::singleton()->webLogDir.'/ipn_post.log';
+ $logContent = '';
+ if (strpos($logFile, '/') === 0 && is_file($logFile)) {
+ $logContent = file_get_contents($logFile);
+ $logLines = explode("\n", $logContent);
+ }
+ }
+
+ if (!empty($logLines)) {
+ $ordersByMerchant = array();
+ foreach ($logLines as $idx => $logLine) {
+ $getParams = $ipnResult = $postParams = array();
+ $logLine = trim($logLine);
+ if (empty($logLine)) {
+ continue;
+ }
+ // separate by space
+ preg_match('/^([^ ]+)\s\[([^\s]+)\]\s([^\s]+)\s(.*)$/', $logLine, $logMatches);
+ if (count($logMatches) >= 4) {
+ $isoDate = $logMatches[2];
+ // skip ipn when filter
+ if ($filterDatetime && strpos(date('YmdH', strtotime($isoDate)), $filterDatetime) === FALSE) {
+ continue;
+ }
+
+ $getString = $logMatches[3];
+ $postString = isset($logMatches[4]) ? $logMatches[4] : '';
+ $postString = preg_replace_callback('/\\\\x([0-9a-fA-F]{2})/', function ($strMatches) {
+ return chr(hexdec($strMatches[1]));
+ }, $postString);
+
+ $parsedUrl = parse_url($getString);
+ parse_str($parsedUrl['query'], $getParams);
+
+ // analysis POST
+ if (!empty($postString)) {
+ if (strpos($postString, 'JSONData=') === 0) {
+ $postString = substr($postString, 9);
+ $postParams = json_decode($postString, true);
+ if (!empty($postParams['Result'])) {
+ $ipnResult = json_decode($postParams['Result'], TRUE);
+ if (!empty($ipnResult['MerchantID'])) {
+ $ordersByMerchant[$ipnResult['MerchantID']][$idx] = array(
+ 'recurring' => FALSE,
+ 'contribution_id' => !empty($getParams['cid']) ? $getParams['cid'] : '',
+ 'contact_id' => !empty($getParams['contact_id']) ? $getParams['contact_id'] : '',
+ 'success' => (isset($postParams['Status']) && $postParams['Status'] === 'SUCCESS') ? TRUE : FALSE,
+ 'total_amount' => isset($ipnResult['Amt']) ? (float)$ipnResult['Amt'] : 0,
+ 'trxn_id' => isset($ipnResult['MerchantOrderNo']) ? $ipnResult['MerchantOrderNo'] : '',
+ 'receive_date' => isset($ipnResult['PayTime']) ? date('c', strtotime($ipnResult['PayTime'])) : '',
+ 'ipn_date' => $isoDate,
+ );
+ }
+ }
+ }
+ elseif (strpos($postString, 'Content-Disposition: form-data') !== false) {
+ $rawPostData = preg_replace('/\r\n--------------------------\w+--\r\n$/', '', $postString);
+ $postParts = preg_split('/\r\n--------------------------\w+\r\n/', $rawPostData);
+ $postParams = array();
+ foreach ($postParts as $part) {
+ if (preg_match('/Content-Disposition: form-data; name="(.+?)"\r\n\r\n(.*)/s', $part, $strMatches)) {
+ $key = $strMatches[1];
+ $value = $strMatches[2];
+ $postParams[$key] = $value;
+ }
+ }
+ if (!empty($postParams['Period'])) {
+ // decode
+ if(is_numeric($getParams['cid'])) {
+ $dao = CRM_Core_DAO::executeQuery("SELECT payment_processor_id, is_test FROM civicrm_contribution WHERE id = %1", array(
+ 1 => array($getParams['cid'], 'Integer'),
+ ));
+ $dao->fetch();
+ if (!empty($paymentProcessors[$dao->payment_processor_id])) {
+ $paymentProcessor = $paymentProcessors[$dao->payment_processor_id];
+ }
+ elseif (!empty($dao->payment_processor_id)) {
+ $paymentProcessor = CRM_Core_BAO_PaymentProcessor::getPayment($dao->payment_processor_id, $dao->is_test ? 'test' : 'live');
+ }
+ $postDecode = CRM_Core_Payment_SPGATEWAYAPI::recurDecrypt($postParams['Period'], $paymentProcessor);
+ if (!empty($postDecode) && json_decode($postDecode)) {
+ $postParams = json_decode($postDecode, TRUE);
+ $ipnResult = $postParams['Result'];
+ if (!empty($ipnResult['OrderNo'])) {
+ $orderNumber = $ipnResult['OrderNo'];
+ $firstRecurring = FALSE;
+ }
+ else {
+ $orderNumber = $ipnResult['MerchantOrderNo'];
+ $firstRecurring = TRUE;
+ }
+ $amount = isset($ipnResult['AuthAmt']) ? $ipnResult['AuthAmt'] : $ipnResult['PeriodAmt'];
+ $ordersByMerchant[$ipnResult['MerchantID']][$idx] = array(
+ 'recurring' => TRUE,
+ 'first_recurring' => $firstRecurring,
+ 'contribution_id' => !empty($getParams['cid']) ? $getParams['cid'] : '',
+ 'contact_id' => !empty($getParams['contact_id']) ? $getParams['contact_id'] : '',
+ 'success' => (isset($postParams['Status']) && $postParams['Status'] === 'SUCCESS') ? TRUE : FALSE,
+ 'total_amount' => $amount,
+ 'trxn_id' => $orderNumber,
+ 'receive_date' => isset($ipnResult['AuthTime']) ? date('c', strtotime($ipnResult['AuthTime'])) : '',
+ 'ipn_date' => $isoDate,
+ );
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ // process complete, start to call sync when necessery
+ // only trigger sync when contribution status is pending
+ if (!empty($ordersByMerchant)) {
+ foreach($ordersByMerchant as $merchantId => $orders) {
+ foreach($orders as $idx => $order) {
+ if (!empty($order['trxn_id'])) {
+ if ($order['first_recurring']) {
+ $current_status_id = CRM_Core_DAO::singleValueQuery("SELECT contribution_status_id FROM civicrm_contribution WHERE trxn_id IN (%1, %2)", array(
+ 1 => array($order['trxn_id'], 'String'),
+ 2 => array($order['trxn_id'].'_1', 'String'),
+ ));
+ }
+ else {
+ $current_status_id = CRM_Core_DAO::singleValueQuery("SELECT contribution_status_id FROM civicrm_contribution WHERE trxn_id = %1", array(
+ 1 => array($order['trxn_id'], 'String'),
+ ));
+ }
+ if ($order['recurring']) {
+ if (empty($current_status_id)) {
+ CRM_Core_Error::debug_log_message("spgateway: weblog sync recur create for trxn_id {$order['trxn_id']}");
+ self::recurSyncTransaction($order['trxn_id'], TRUE);
+ }
+ elseif($current_status_id == 2) {
+ CRM_Core_Error::debug_log_message("spgateway: weblog sync recur status for trxn_id {$order['trxn_id']}");
+ if ($order['first_recurring']) {
+ $ids = explode('_', $order['trxn_id']);
+ self::syncTransaction($ids[0]);
+ }
+ else {
+ self::syncTransaction($order['trxn_id']);
+ }
+ }
+ }
+ else {
+ if ($current_status_id == 2) {
+ // only sync status
+ CRM_Core_Error::debug_log_message("spgateway: weblog sync non-recur status for trxn_id {$order['trxn_id']}");
+ self::syncTransaction($order['trxn_id']);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/CRM/Core/Payment/SPGATEWAYAPI.php b/CRM/Core/Payment/SPGATEWAYAPI.php
new file mode 100644
index 000000000..eb4a8b12e
--- /dev/null
+++ b/CRM/Core/Payment/SPGATEWAYAPI.php
@@ -0,0 +1,678 @@
+ '/MPG/period/AlterStatus',
+ 'alter-amt' => '/MPG/period/AlterAmt',
+ );
+ public static $_alterStatus = array(
+ 'suspend', // Paused
+ 'terminate', // Stop
+ 'restart', // Only used in paused recur.
+ );
+
+ // Used for request result
+ public $_apiURL;
+ public $_request;
+ public $_response;
+ public $_success;
+ public $_curlResult;
+
+ /**
+ * Constructor
+ *
+ * @param array $apiParams
+ * apiType
+ * paymentProcessorId
+ * paymentProcessor
+ * isTest
+ */
+ function __construct($apiParams) {
+ if (!empty($apiParams['paymentProcessor'])) {
+ $this->_paymentProcessor = $apiParams['paymentProcessor'];
+ }
+ else if (!empty($apiParams['paymentProcessorId'])) {
+ $mode = $apiParams['isTest'] ? '' : 'test';
+ $this->_paymentProcessor = CRM_Core_BAO_PaymentProcessor::getPayment($apiParams['paymentProcessorId'], $mode);
+ }
+ else {
+ CRM_Core_Error::fatal('Missing payment processor or payment processor ID');
+ }
+ if ($apiParams['isTest']) {
+ $this->_urlDomain = CRM_Core_Payment_SPGATEWAY::TEST_DOMAIN;
+ }
+ else {
+ $this->_urlDomain = CRM_Core_Payment_SPGATEWAY::REAL_DOMAIN;
+ }
+ $this->_isTest = $apiParams['isTest'];
+ $this->_paymentProcessorId = $this->_paymentProcessor['id'];
+ $this->_apiType = $apiParams['apiType'];
+ }
+
+ /**
+ * Validate and send request to spgateway / neweb
+ *
+ * @param array $params
+ * @return void
+ */
+ public function request($params) {
+ $allowedFields = self::getRequestFields($this->_apiType);
+ $post = array();
+ foreach ($params as $name => $value) {
+ if (!in_array($name, $allowedFields)) {
+ continue;
+ }
+ else {
+ $post[$name] = $value;
+ }
+ }
+ if (empty($post['RespondType'])) {
+ $post['RespondType'] = CRM_Core_Payment_SPGATEWAY::RESPONSE_TYPE;
+ }
+ if (empty($post['Version'])) {
+ $post['Version'] = CRM_Core_Payment_SPGATEWAY::RECUR_VERSION;
+ }
+ if (empty($post['TimeStamp'])) {
+ $post['TimeStamp'] = time();
+ }
+
+ $requiredFields = self::getRequestFields($this->_apiType, TRUE);
+ foreach ($requiredFields as $required) {
+ if(empty($post[$required])){
+ $missingRequired[] = $required;
+ }
+ }
+ if(!empty($missingRequired)) {
+ CRM_Core_Error::fatal('Required parameters missing: '.implode(',', $missingRequired));
+ }
+
+ if (!empty($post['PeriodType']) xor !empty($post['PeriodPoint'])) {
+ CRM_Core_Error::fatal('PeriodType and PeriodPoint must exist at same time.');
+ }
+ if (!empty($post['PeriodType'])) {
+ if ($post['PeriodType'] == 'Y' && !preg_match('/\d{4}/', $post['PeriodPoint'])) {
+ CRM_Core_Error::fatal('PeriodPoint format should be MMDD when PeriodType is "Y".');
+ }
+ if ($post['PeriodType'] == 'M' && !preg_match('/\d{2}/', $post['PeriodPoint'])) {
+ CRM_Core_Error::fatal('PeriodPoint format should be DD when PeriodType is "M".');
+ }
+ }
+
+ $this->_request = $post;
+ $this->_apiURL = $this->_urlDomain.self::$_apiTypes[$this->_apiType];
+ $result = $this->_curlResult = $this->_request();
+ CRM_Core_Error::debug('Spgateway_RecurChangeAPI_request', $this->_request);
+ if ($result['status'] && !empty($this->_response)) {
+
+ CRM_Core_Error::debug('Spgateway_RecurChangeAPI_response', $this->_response);
+ // Curl Correct and have response
+
+ if ($this->_response->Status == 'SUCCESS') {
+ // Format Every thing.
+ // Format of amount
+ $response =& $this->_response;
+ if(!empty($response->amount) && $response->currency != 'TWD') {
+ $response->amount = (float)$response->amount / 100;
+ }
+
+ $apiResult = $this->_response->Result;
+
+ // For AlterType API
+ $resultType = $apiResult->AlterType;
+ if (!empty($resultType)) {
+ $statusReverseMap = array_flip(CRM_Core_Payment_SPGATEWAY::$_statusMap);
+ $recurResult['contribution_status_id'] = $statusReverseMap[$resultType];
+ }
+ if (!empty($result['NewNextTime'])) {
+ $recurResult['next_sched_contribution'] = $result['NewNextTime'];
+ }
+
+ // For AlterOther API
+ if (!empty($apiResult->PeriodType)) {
+ $unitReverseMap = array_flip(CRM_Core_Payment_SPGATEWAY::$_unitMap);
+ $recurResult['frequency_unit'] = $unitReverseMap[$apiResult->PeriodType];
+ }
+ $result['cycle_day'] = $apiResult->PeriodPoint;
+ if (!empty($apiResult->NewNextAmt) && $apiResult->NewNextAmt != '-') {
+ $recurResult['amount'] = $apiResult->NewNextAmt;
+ }
+ if (!empty($apiResult->NewNextTime)) {
+ $recurResult['next_sched_contribution'] = $apiResult->NewNextTime;
+ }
+ if (!empty($apiResult->PeriodTimes)) {
+ $recurResult['installments'] = $apiResult->PeriodTimes;
+ }
+
+ return $recurResult;
+ }
+ else if ( in_array($this->_response->Status, array('PER10061', 'PER10063', 'PER10062', 'PER10064')) ) {
+ // Refs #30842, Status is already changed in NewebPay.
+ $recurResult['response_status'] = $this->_response->Status;
+ $recurResult['msg'] = $recurResult['note_body'] = ts('NewebPay response:') . $this->_response->Message;
+ return $recurResult;
+ }
+ else {
+ $errResult['is_error'] = 1;
+ $errResult['msg'] = $this->_response->Status.': '.$this->_response->Message;
+ CRM_Core_Error::debug('Spgateway_RecurChangeAPI_errResult', $errResult);
+ return $errResult;
+ }
+
+ }
+ else if ($result['success'] == FALSE && $result['status'] == 0){
+ // Curl Error
+ $return = array(
+ 'is_error' => 1,
+ 'msg' => reset($result['curlError']),
+ );
+ return $return;
+ }
+ else if (empty($this->_response)) {
+ // No any response, need to ask Newebpay
+ CRM_Core_Error::debug('NewebPay api request as empty response', $this);
+ $return = array(
+ 'is_error' => 1,
+ 'msg' => ts('The response from payment provider is empty.'),
+ );
+ return $return;
+ }
+ else {
+ CRM_Core_Error::debug('NewebPay api request else', $this);
+ return FALSE;
+ }
+ }
+
+ private function _request() {
+ $this->_success = FALSE;
+ if (!empty(getenv('CIVICRM_TEST_DSN'))) {
+ return array(
+ 'success' => FALSE,
+ 'status' => NULL,
+ 'curlError' => NULL,
+ );
+ }
+ $ch = curl_init($this->_apiURL);
+ $opt = array();
+ $opt[CURLOPT_RETURNTRANSFER] = TRUE;
+ $opt[CURLOPT_SSL_VERIFYPEER] = FALSE;
+ if($this->_apiMethod == 'POST'){
+ $requestString = http_build_query($this->_request, '', '&');
+ $postDataString = self::recurEncrypt($requestString, $this->_paymentProcessor);
+ $postFields = array(
+ 'MerchantID_' => $this->_paymentProcessor['user_name'],
+ 'PostData_' => $postDataString,
+ );
+ $opt[CURLOPT_POST] = TRUE;
+ $opt[CURLOPT_POSTFIELDS] = $postFields;
+ }
+ curl_setopt_array($ch, $opt);
+
+ $result = curl_exec($ch);
+
+ $status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
+ $errno = curl_errno($ch);
+ if (!empty($errno)) {
+ $errno = curl_errno($ch);
+ $err = curl_error($ch);
+ CRM_Core_Error::debug_log_message("CURL: $err :: $errno");
+ }
+
+ if ($result === FALSE) {
+ $errno = curl_errno($ch);
+ $err = curl_error($ch);
+ $curlError = array($errno => $err);
+ }
+ else{
+ $curlError = array();
+ }
+ curl_close($ch);
+ if (!empty($result)) {
+ $response = json_decode($result);
+ $this->_response = json_decode(self::recurDecrypt($response->period, $this->_paymentProcessor));
+ $this->_success = isset($response->status) && $response->status == '0' ? TRUE : FALSE;
+ }
+ else {
+ $this->_response = NULL;
+ }
+ $return = array(
+ 'success' => $this->_success,
+ 'status' => $status,
+ 'curlError' => $curlError,
+ );
+ return $return;
+ }
+
+
+ /**
+ * Migrate from civicrm_spgateway_record
+ *
+ * @param int $cid
+ * @param array $data
+ * @return void
+ */
+ public static function writeRecord($cid, $data = null){
+ if(is_numeric($cid)){
+ if(empty($data) && !empty($_POST)){
+ $data = $_POST;
+ }
+
+ if(!empty($data['JSONData'])){
+ $data = $data['JSONData'];
+ }
+ $exists = CRM_Core_DAO::singleValueQuery("SELECT cid FROM civicrm_contribution_spgateway WHERE cid = %1", array(
+ 1 => array($cid, 'Integer'),
+ ));
+ if ($exists) {
+ CRM_Core_DAO::executeQuery("UPDATE civicrm_contribution_spgateway SET data = %1 WHERE cid = %2", array(
+ 1 => array(json_encode($data), 'String'),
+ 2 => array($cid, 'Integer')
+ ));
+ }
+ else {
+ CRM_Core_DAO::executeQuery("INSERT INTO civicrm_contribution_spgateway (cid, data) VALUES(%2, %1) ", array(
+ 1 => array(json_encode($data), 'String'),
+ 2 => array($cid, 'Integer')
+ ));
+ }
+
+ // Set expire time
+ $dataObj = self::dataDecode($data);
+ if(!empty($dataObj['ExpireDate'])){
+ $expire_date = $dataObj['ExpireDate'];
+ if(!empty($dataObj['ExpireTime'])){
+ $expire_date .= ' '.$dataObj['ExpireTime'];
+ }
+ else{
+ $expire_date .= ' 23:59:59';
+ }
+ }
+ if(!empty($expire_date)){
+ $sql = "UPDATE civicrm_contribution SET expire_date = %1 WHERE id = %2";
+ $params = array(
+ 1 => array( $expire_date, 'String'),
+ 2 => array( $cid, 'Integer'),
+ );
+ CRM_Core_DAO::executeQuery($sql, $params);
+ }
+ }
+ }
+
+ /**
+ * Migrate from _civicrm_spgateway_post_decode
+ *
+ * Decode JSON data before save from Spgateway / neweb response
+ *
+ * @param array|object $post
+ * @return void
+ */
+ public static function dataDecode($post = null){
+ $data = empty($post) ? $_POST : $post;
+ if (is_object($data)) {
+ $data = (array) $data;
+ }
+ if (is_array($data) && !empty($data['JSONData'])){
+ // decode JSONData
+ $data = $data['JSONData'];
+ }
+ if (is_string($data) && json_decode($data)){
+ $data = json_decode($data, TRUE);
+ if (is_string($data) && json_decode($data)) {
+ // Sometimes, neweb will return 2 times encode json.
+ $data = json_decode($data, TRUE);
+ }
+ }
+
+ $return = $data;
+
+ // flatten the jsonData object to 1-dimension array.
+ if(isset($data['Result'])){
+ if(is_string($data['Result']) && json_decode($data['Result'], true)){
+ $return = $dataResult = json_decode($data['Result'], true);
+ }
+ else {
+ $return = $dataResult = (array) $data['Result'];
+ }
+ if (!empty($data['Status'])) {
+ if (empty($return['Status'])) {
+ $return['Status'] = $data['Status'];
+ // status is in origin data, not in 'Result' object.
+ }
+ else {
+ $return['_RequestStatus'] = $data['Status'];
+ // The condition jsonData status is success, but the error status is in 'Result' attribute.
+ }
+ }
+ if (empty($dataResult['Message']) && !empty($data['Message'])) {
+ // 'Result' has no 'Message', use original 'Message'.
+ $return['Message'] = $data['Message'];
+ }
+ }
+ return $return;
+ }
+
+ /**
+ * Prepare available fields for spgateway
+ *
+ * @param string $apiType
+ * @param bool $required
+ * @return array
+ */
+ public static function getRequestFields($apiType, $required = FALSE) {
+ $fields = array();
+ switch($apiType){
+ case 'alter-status':
+ $fields = explode(',', 'RespondType*,Version*,MerOrderNo*,PeriodNo*,AlterType*,TimeStamp*');
+ break;
+ case 'alter-amt':
+ $fields = explode(',', 'RespondType*,Version*,TimeStamp*,MerOrderNo*,PeriodNo*,AlterAmt,PeriodType,PeriodPoint,PeriodTimes,Extday');
+ break;
+ }
+ foreach ($fields as $key => &$value) {
+ if(!strstr($value, '*') && $required) {
+ unset($fields[$key]);
+ }
+ else{
+ $value = str_replace('*', '', $value);
+ }
+ }
+ return $fields;
+ }
+
+ /**
+ * Migrate from _civicrm_spgateway_postdata
+ *
+ * @param string $url
+ * @param array $post_data
+ * @return object
+ */
+ public static function sendRequest($url, $post_data){
+ $ch = curl_init($url);
+ curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
+ curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
+ curl_setopt($ch, CURLOPT_POST, 1);
+ curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
+ curl_setopt($ch, CURLOPT_HEADER, 0); // DO NOT RETURN HTTP HEADERS
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); // RETURN THE CONTENTS OF THE CALL
+ $response = curl_exec($ch);
+ if(curl_errno($ch)){
+ CRM_Core_Error::debug_log_message('civicrm_spgateway: Fetch recuring error: curl_errno: '.curl_errno($ch).' / '. curl_error($ch), 'error');
+ }
+ else{
+ $field_string = http_build_query($post_data, '', '&');
+ CRM_Core_Error::debug_log_message('civicrm_spgateway: Request:'.$url."?".$field_string);
+ CRM_Core_Error::debug_log_message('civicrm_spgateway: Response:'.$response);
+ }
+ curl_close($ch);
+ if(!empty($response)){
+ return json_decode($response);
+ }
+ else{
+ return FALSE;
+ }
+ }
+
+ /**
+ * Migrate from _civicrm_spgateway_encode
+ *
+ * Encode spgateway / neweb API delivery
+ *
+ * @param array $args
+ * @param object $payment_processor
+ * @param array $checkArgs
+ * @return string
+ */
+ public static function encode(&$args, $payment_processor, $checkArgs = array()){
+ // remove empty arg
+ if(is_array($args)){
+ foreach($args as $k => $v){
+ if($k == 'CheckValue'){
+ unset($args[$k]);
+ }
+ }
+ }
+ elseif(is_string($args)){
+ $tmp = explode('&', $args);
+ $args = array();
+ foreach($tmp as $v){
+ list($key, $value) = explode('=', $v);
+ $args[$key] = $value;
+ }
+ }
+ if(count($checkArgs) == 0){
+ $checkArgs = array('HashKey','Amt','MerchantID','MerchantOrderNo','TimeStamp','Version','HashIV');
+ }
+ foreach($checkArgs as $k){
+ switch ($k) {
+ case 'HashIV':
+ case 'IV':
+ $v = $payment_processor['signature'];
+ self::checkKeyIV($v);
+ break;
+ case 'HashKey':
+ case 'Key':
+ $v = $payment_processor['password'];
+ self::checkKeyIV($v);
+ break;
+ default:
+ $v = $args[$k];
+ break;
+ }
+ $a[] = $k.'='.$v;
+ }
+ $keystr = implode('&', $a);
+
+ $checkvalue = strtoupper(hash("sha256", $keystr));
+ $args['CheckValue'] = $checkvalue;
+ return $checkvalue;
+ }
+
+ /**
+ * Migrate from _civicrm_spgateway_checkKeyIV
+ */
+ public static function checkKeyIV($v){
+ if(empty($v)){
+ CRM_Core_Error::fatal(ts('KEY and IV should have value.'));
+ }
+ }
+
+ /**
+ * Migrate from _civicrm_spgateway_checkmacvalue
+ *
+ * @param array $args
+ * @param object $payment_processor
+ * @return string
+ */
+ public static function checkMacValue(&$args, $payment_processor){
+ $used_args = array('HashKey','Amt','MerchantID','MerchantOrderNo','TimeStamp','Version','HashIV');
+ return self::encode($args, $payment_processor, $used_args);
+ }
+
+ /**
+ * Migrate from _civicrm_spgateway_checkcode
+ *
+ * @param array $args
+ * @param object $payment_processor
+ * @return string
+ */
+ public static function checkCode(&$args, $payment_processor){
+ $used_args = array('HashIV','Amt','MerchantID','MerchantOrderNo','TradeNo','HashKey');
+ return self::encode($args, $payment_processor, $used_args);
+ }
+
+ /**
+ * Migrate from _civicrm_spgateway_recur_encrypt
+ *
+ * @param string $str
+ * @param object $payment_processor
+ * @return string
+ */
+ public static function recurEncrypt($str, $payment_processor){
+ $key = $payment_processor['password'];
+ $iv = $payment_processor['signature'];
+ self::checkKeyIV($key);
+ self::checkKeyIV($iv);
+ $str = trim(self::encrypt($key, $iv, $str));
+ return $str;
+ }
+
+ /**
+ * Migrate from _civicrm_spgateway_recur_decrypt
+ *
+ * @param string $str
+ * @param object $payment_processor
+ * @return string
+ */
+ public static function recurDecrypt($str, $payment_processor){
+ $key = $payment_processor['password'];
+ $iv = $payment_processor['signature'];
+ self::checkKeyIV($key);
+ self::checkKeyIV($iv);
+ $str = self::decrypt($key, $iv, $str);
+ return $str;
+ }
+
+ /**
+ * Migrate from _civicrm_spgateway_encrypt
+ *
+ * @param string $key
+ * @param string $iv
+ * @param string $str
+ * @param bool $force
+ *
+ * @return string
+ */
+ public static function encrypt($key, $iv, $str, $force = NULL) {
+ $data = self::addPadding($str);
+ if ($force) {
+ if ($force == 'openssl') {
+ $openssl = TRUE;
+ }
+ elseif($force == 'mcrypt') {
+ $mcrypt = TRUE;
+ }
+ }
+ else {
+ $openssl = extension_loaded('openssl') ? TRUE : FALSE;
+ $mcrypt = extension_loaded('mcrypt') ? TRUE : FALSE;
+ }
+ if (empty($openssl) && empty($mcrypt)) {
+ return FALSE;
+ }
+
+ if ($openssl) {
+ $keyLen = strlen($key);
+ switch($keyLen) {
+ case 16:
+ $encoding = 'AES-128-CBC';
+ break;
+ case 24:
+ $encoding = 'AES-192-CBC';
+ break;
+ case 32:
+ default:
+ $encoding = 'AES-256-CBC';
+ break;
+ }
+ $encrypted = openssl_encrypt($data, $encoding, $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv);
+ }
+ elseif ($mcrypt) {
+ $encrypted = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $data, MCRYPT_MODE_CBC, $iv);
+ }
+ else {
+ return '';
+ }
+ return bin2hex($encrypted);
+ }
+
+ /**
+ * Migrate from _civicrm_spgateway_decrypt
+ *
+ * @param string $key
+ * @param string $iv
+ * @param string $encrypted
+ * @param bool $force
+ * @return void
+ */
+ public static function decrypt($key, $iv, $encrypted, $force = NULL) {
+ if ($force) {
+ if ($force == 'openssl') {
+ $openssl = TRUE;
+ }
+ elseif($force == 'mcrypt') {
+ $mcrypt = TRUE;
+ }
+ }
+ else {
+ $openssl = extension_loaded('openssl') ? TRUE : FALSE;
+ $mcrypt = extension_loaded('mcrypt') ? TRUE : FALSE;
+ }
+ if (empty($openssl) && empty($mcrypt)) {
+ return FALSE;
+ }
+
+ $data = hex2bin($encrypted);
+ if ($openssl) {
+ $keyLen = strlen($key);
+ switch($keyLen) {
+ case 16:
+ $encoding = 'AES-128-CBC';
+ break;
+ case 24:
+ $encoding = 'AES-192-CBC';
+ break;
+ case 32:
+ default:
+ $encoding = 'AES-256-CBC';
+ break;
+ }
+ $decrypted = openssl_decrypt($data, $encoding, $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv);
+ }
+ elseif ($mcrypt) {
+ $decrypted = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $data, MCRYPT_MODE_CBC, $iv);
+ }
+ return self::stripPadding($decrypted);
+ }
+
+ /**
+ * Migrate from _civicrm_spgateway_addpadding
+ *
+ * @param string $string
+ * @param int $blocksize
+ * @return string
+ */
+ public static function addPadding($string, $blocksize = 32) {
+ $len = strlen($string);
+ $pad = $blocksize - ($len % $blocksize);
+ $string .= str_repeat(chr($pad), $pad);
+ return $string;
+ }
+
+ /**
+ * Migrate from _civicrm_spgateway_strippadding
+ *
+ * @param string $string
+ * @return bool|string
+ */
+ public static function stripPadding($string) {
+ $slast = ord(substr($string, -1));
+ $slastc = chr($slast);
+ if (preg_match("/$slastc{" . $slast . "}/", $string)) {
+ $string = substr($string, 0, strlen($string) - $slast);
+ return $string;
+ } else {
+ return false;
+ }
+ }
+}
\ No newline at end of file
diff --git a/CRM/Core/Payment/SPGATEWAYIPN.php b/CRM/Core/Payment/SPGATEWAYIPN.php
new file mode 100644
index 000000000..5ebd161b8
--- /dev/null
+++ b/CRM/Core/Payment/SPGATEWAYIPN.php
@@ -0,0 +1,337 @@
+_post = $post;
+ $this->_get = $get;
+ }
+
+ function main($instrument){
+ $objects = $ids = $input = array();
+ $this->getIds($ids);
+ if(empty($ids['contributionRecur'])){
+ $recur = FALSE;
+ // get the contribution and contact ids from the GET params
+ $input = CRM_Core_Payment_SPGATEWAYAPI::dataDecode($this->_post);
+ CRM_Core_Payment_SPGATEWAYAPI::writeRecord($ids['contribution'], $this->_post);
+ }
+ else{
+ $recur = TRUE;
+ // Refs #35316, recur.proessor_id => contribution.payment_processor_id => $_GET['ppid']
+ $sql = 'SELECT processor_id FROM civicrm_contribution_recur WHERE id = %1';
+ $ppid = CRM_Core_DAO::singleValueQuery($sql, array(1 => array($ids['contributionRecur'], 'Integer')));
+ if (empty($ppid)) {
+ $sql = 'SELECT payment_processor_id FROM civicrm_contribution WHERE id = %1';
+ $ppid = CRM_Core_DAO::singleValueQuery($sql, array(1 => array($ids['contribution'], 'Integer')));
+ }
+ if (empty($ppid)) {
+ CRM_Core_Error::debug_log_message("Spgateway: could not find payment processor id on this contribution {$ids['contribution']}");
+ CRM_Utils_System::civiExit();
+ }
+ $isTest = CRM_Core_DAO::singleValueQuery("SELECT is_test FROM civicrm_payment_processor WHERE id = %1", array(
+ 1 => array($ppid, 'Integer'),
+ ));
+ $paymentProcessor = CRM_Core_BAO_PaymentProcessor::getPayment($ppid, $isTest ? 'test' : 'live');
+ $this->_post = CRM_Core_Payment_SPGATEWAYAPI::recurDecrypt($this->_post['Period'], $paymentProcessor);
+ $input = CRM_Core_Payment_SPGATEWAYAPI::dataDecode($this->_post);
+ // we will save record later if this is recurring after second times.
+ if(empty($input['AlreadyTimes'])){
+ // First time recurring
+ CRM_Core_Payment_SPGATEWAYAPI::writeRecord($ids['contribution'], $this->_post);
+ }
+ }
+ $input['component'] = !empty($ids['participant']) ? 'event' : 'contribute';
+
+ // now, retrieve full object by validateData, or false fallback
+ // when it's recurring, this will load first recurring contrib into object even it's not
+ if (!$this->validateData( $input, $ids, $objects ) ) {
+ return FALSE;
+ }
+
+ // set global variable for paymentProcessor
+ $this->_paymentProcessor = $objects['paymentProcessor'];
+
+ if($objects['contribution']->contribution_status_id == 1 && empty($input['AlreadyTimes'])){
+ // already completed, skip
+ return '1|OK';
+ }
+ else{
+ // skip doing job when contribution already success
+ if(!empty($input['AlreadyTimes']) && $input['Status'] === 'SUCCESS'){
+ $newTrxnId = $input['OrderNo'];
+ if ($newTrxnId == $input['MerchantOrderNo'] . "_1") {
+ if($objects['contribution']->contribution_status_id == 1){
+ CRM_Core_Error::debug_log_message("Spgateway: The transaction {$newTrxnId}, associated with the contribution {$objects['contribution']->trxn_id}, has been successfully processed before. Skipped.");
+ return '1|OK';
+ }
+ }
+ else {
+ $alreadySuccessId = CRM_Core_DAO::singleValueQuery("SELECT id FROM civicrm_contribution WHERE trxn_id = %1 AND contribution_status_id = 1", array(
+ 1 => array($newTrxnId, 'String'),
+ ));
+ if (!empty($alreadySuccessId)) {
+ CRM_Core_Error::debug_log_message("Spgateway: The transaction {$newTrxnId}, associated with the contribution {$alreadySuccessId}, has been successfully processed before. Skipped.");
+ return '1|OK';
+ }
+ }
+ }
+ // start validation
+ $note = '';
+ if( $this->validateOthers($input, $ids, $objects, $note, $instrument) ){
+ $contribution =& $objects['contribution'];
+ if(empty($contribution->receive_date)){
+ if(!empty($input['PayTime'])){
+ $contribution->receive_date = date('YmdHis', strtotime($input['PayTime']));
+ }elseif(!empty($input['AuthTime'])){
+ $contribution->receive_date = date('YmdHis', strtotime($input['AuthTime']));
+ }elseif(!empty($input['AuthDate'])){
+ $contribution->receive_date = date('YmdHis', strtotime($input['AuthDate']));
+ }else{
+ $contribution->receive_date = date('YmdHis');
+ }
+ }
+
+ // assign trxn_id before complete transaction
+ $recurContribCount = NULL;
+ if (!empty($contribution->contribution_recur_id)) {
+ $recurContribCount = CRM_Core_DAO::singleValueQuery("SELECT count(id) FROM civicrm_contribution WHERE contribution_recur_id = %1", array(
+ 1 => array($contribution->contribution_recur_id, 'Integer')
+ ));
+ }
+ if(!empty($input['PeriodAmt']) && $recurContribCount == 1){
+ // first contribution of recurring, update trxn_id.
+ $input['trxn_id'] = $input['MerchantOrderNo'] . "_1";
+ }
+ else {
+ $input['trxn_id'] = $objects['contribution']->trxn_id;
+ }
+ $transaction = new CRM_Core_Transaction();
+ $this->completeTransaction( $input, $ids, $objects, $transaction, $recur );
+ $note .= ts('Completed')."\n";
+ $this->addNote($note, $contribution);
+ return '1|OK';
+ }
+ else{
+ $rtnCode = !empty($input['RtnCode']) ? $input['RtnCode'] : '';
+ $rtnMsg = !empty($input['RtnMsg']) ? $input['RtnMsg'] : '';
+ $note .= ts('Failed')."\n";
+ $note .= ts("Payment Information").": ".ts("Failed").' - '.$rtnMsg."({$rtnCode})";
+ $this->addNote($note, $objects['contribution']);
+ return '';
+ }
+ }
+
+ // error stage: doesn't goto and not the background posturl
+ // never for front-end user.
+ return FALSE;
+ }
+
+ function getIds(&$ids){
+ $contribId = CRM_Utils_Array::value('cid', $this->_get);
+ if (!empty($contribId) && CRM_Utils_Type::escape($contribId, 'Integer')) {
+ $ids = CRM_Contribute_BAO_Contribution::buildIds($contribId, FALSE);
+ if (empty($ids)) {
+ CRM_Core_Error::debug_log_message("Spgateway: Could not found contribution id $contribId");
+ CRM_Utils_System::civiExit();
+ }
+ }
+ // component is contribute
+ if (empty($ids['participant'])) {
+ if (!empty($this->_get['rid'])) {
+ $ids['related_contact'] = CRM_Utils_Array::value('rid', $this->_get);
+ }
+ if (!empty($this->_get['onbehalf_dupe_alert'])) {
+ $ids['onbehalf_dupe_alert'] = CRM_Utils_Array::value('onbehalf_dupe_alert', $this->_get);
+ }
+ }
+ }
+
+ function validateOthers( &$input, &$ids, &$objects, &$note, $instrument = ''){
+ $contribution = &$objects['contribution'];
+ $pass = TRUE;
+ $validValue = array();
+ if(!empty($input['MerchantOrderNo'])){
+ $validValue['MerchantOrderNo'] = $input['MerchantOrderNo'];
+ }else{
+ $validValue['MerchantOrderNo'] = $input['MerOrderNo'];
+ }
+ if(!empty($ids['contributionRecur'])){
+ if(!empty($input['AuthAmt'])){
+ // after the first recurring
+ $validValue['Amt'] = $input['AuthAmt'];
+ if ($contribution->total_amount != $validValue['Amt']) {
+ $note .= ts("Amount values dont match between database and IPN request. Force use IPN instead {$contribution->trxn_id}-{$input['AlreadyTimes']} . Original: {$contribution->total_amount}, IPN:{$validValue['Amt']}")."\n";
+ $contribution->total_amount = $validValue['Amt'];
+ }
+ }
+ else{
+ // first recurring
+ $validValue['Amt'] = !empty($input['PeriodAmt']) ? $input['PeriodAmt'] : '0';
+ }
+ }
+ else{
+ $validValue['Amt'] = !empty($input['Amt']) ? $input['Amt'] : '0';
+ $validValue['CheckCode'] = !empty($input['CheckCode']) ? $input['CheckCode'] : '';
+ }
+
+ // check contribution id matches
+ // If is from old neweb. Skip check.
+ // if it's recurring, the merchant order not should be first recurring no
+ if ( !strstr($contribution->trxn_id, $validValue['MerchantOrderNo']) && !preg_match('/^99[\d]{7}$/', $validValue['MerchantOrderNo'])) {
+ CRM_Core_Error::debug_log_message("Spgateway: OrderNumber values doesn't match between database and IPN request. {$contribution->trxn_id} : {$validValue['MerchantOrderNo']} " );
+ $note .= ts("Failuare: OrderNumber values doesn't match between database and IPN request. {$contribution->trxn_id} : {$validValue['MerchantOrderNo']}")."\n";
+ $pass = FALSE;
+ }
+
+ // check amount
+ if ( round($contribution->total_amount) != $validValue['Amt'] && $input['Status'] == 'SUCCESS' ) {
+ CRM_Core_Error::debug_log_message("Spgateway: Amount values dont match between database and IPN request. {$contribution->trxn_id}-{$input['AlreadyTimes']} : {$validValue['Amt']}" );
+ $note .= ts("Failuare: Amount values dont match between database and IPN request. {$contribution->trxn_id}-{$input['AlreadyTimes']} : {$validValue['Amt']}")."\n";
+ $pass = FALSE;
+ }
+
+ // spgateway validation
+ // only validate this when not test.
+ if (strtolower($instrument) == 'googlepay') {
+ $ppid = $this->_paymentProcessor['user_name'];
+ $test = $contribution->is_test ? 'test':'live';
+ $paymentProcessor = CRM_Core_BAO_PaymentProcessor::getPayment($ppid, $test);
+ }
+ else {
+ $paymentProcessor = $this->_paymentProcessor;
+ }
+ if(!empty($validValue['CheckCode'])){
+ $checkCode = CRM_Core_Payment_SPGATEWAYAPI::checkCode($input, $paymentProcessor);
+ if(strtolower($validValue['CheckCode']) != strtolower($checkCode)) {
+ $note .= ts("Failuare: CheckCode not match. Contact system admin.")."\n";
+ CRM_Core_Error::debug_log_message("Spgateway: Failuare: CheckCode not match. Should be '{$checkCode}', but '{$input['CheckCode']}' provided.");
+ $pass = FALSE;
+ }
+ }
+
+ // recurring validation
+ if(!empty($ids['contributionRecur'])){
+ $recur = &$objects['contributionRecur'];
+ $params = $null = array();
+ // see if we are first time, if not first time, save new contribution
+ // 6 - expired
+ // 5 - processing
+ // 4 - fail
+ // 3 - canceled
+ // 2 - pending
+ // 1 - completed
+
+ // not the first time (PeriodReturnURL)
+ if(!empty($input['AlreadyTimes'])){
+ $trxn_id = $input['OrderNo'];
+ if($input['Status'] != 'SUCCESS'){
+ $contribution->contribution_status_id = 4; // Failed
+ $c = self::copyContribution($contribution, $ids['contributionRecur'], $trxn_id);
+ }
+ else{
+ $contribution->contribution_status_id = 1; // Completed
+ // Check if trxn_id is existed or not.
+ $alreadyExistsId = CRM_Core_DAO::singleValueQuery("SELECT id FROM civicrm_contribution WHERE trxn_id = %1", array(
+ 1 => array($trxn_id, 'String'),
+ ));
+ if (!$alreadyExistsId) {
+ // Trxn_id is not existed, clone contribution.
+ $c = self::copyContribution($contribution, $ids['contributionRecur'], $trxn_id);
+ }
+ else {
+ // Sync contribution from given trxn_id.
+ // Will only process this when contribution status is not success.
+ $c = new CRM_Contribute_DAO_Contribution();
+ $c->id = $alreadyExistsId;
+ $c->find(TRUE);
+ }
+ }
+ if(!empty($c)){
+ unset($objects['contribution']);
+ CRM_Core_Payment_SPGATEWAYAPI::writeRecord($c->id, $this->_post);
+ $objects['contribution'] = $c;
+ if(isset($input['TotalTimes']) && $input['AlreadyTimes'] == $input['TotalTimes']){
+ $recurParam = array(
+ 'id' => $ids['contributionRecur'],
+ 'modified_date' => date('YmdHis'),
+ 'end_date' => date('YmdHis'),
+ 'contribution_status_id' => 1, // completed
+ );
+ CRM_Contribute_BAO_ContributionRecur::add($recurParam, $null);
+ }
+ }
+ }
+ else{
+ // is first time
+ if($input['Status'] == 'SUCCESS'){
+ $params['id'] = $recur->id;
+ $params['start_date'] = date('YmdHis', strtotime($input['AuthTime']));
+ $params['contribution_status_id'] = 5; // from pending to processing
+ $params['modified_date'] = date('YmdHis');
+ $params['trxn_id'] = $input['PeriodNo'];
+ if (!empty($input['AuthTimes']) && $input['AuthTimes'] != $params['installments']) {
+ $params['installments'] = $input['AuthTimes'];
+ $params['message'] = ts('Modify installments by Newebpay data.');
+ CRM_Contribute_BAO_ContributionRecur::addNote($recur->id, $params['message']);
+ }
+ CRM_Contribute_BAO_ContributionRecur::add($params, $null);
+ }
+ else{
+ CRM_Contribute_BAO_ContributionRecur::cancelRecurContribution($recur->id, CRM_Core_DAO::$_nullObject, 4);
+ }
+ }
+ }
+
+ // process fail response
+ if($input['Status'] != 'SUCCESS' && $pass){
+ $responseCode = $input['Status'];
+ $responseMsg = $input['Message']."\n"._civicrm_spgateway_error_msg($responseCode);
+ if ($input['Status'] == 'Error' && !empty($input['RespondCode'])) {
+ $responseCode .= ': ' . $input['RespondCode'];
+ }
+ $failedReason = $responseMsg. ' ('.ts('Error Code:'). $responseCode.')';
+ $note .= $failedReason;
+ if ($input['PayTime']) {
+ $objects['contribution']->cancel_date = $input['PayTime'];
+ }
+ elseif ($input['CreateTime']) {
+ $objects['contribution']->cancel_date = $input['CreateTime'];
+ }
+ elseif ($input['AuthDate']) {
+ $objects['contribution']->cancel_date = $input['AuthDate'];
+ }
+ $transaction = new CRM_Core_Transaction();
+ $this->failed($objects, $transaction, $failedReason);
+ $pass = FALSE;
+ }
+
+ return $pass;
+ }
+
+ function addNote($note, &$contribution){
+ $note = date("Y/m/d H:i:s"). ts("Transaction record").": \n".$note."\n===============================\n";
+ $noteExists = CRM_Core_BAO_Note::getNote( $contribution->id, 'civicrm_contribution' );
+ if(count($noteExists)){
+ $noteId = array( 'id' => reset(array_keys($noteExists)) );
+ $note = $note . reset($noteExists);
+ }
+ else{
+ $noteId = NULL;
+ }
+
+ $noteParams = array(
+ 'entity_table' => 'civicrm_contribution',
+ 'note' => $note,
+ 'entity_id' => $contribution->id,
+ 'contact_id' => $contribution->contact_id,
+ 'modified_date' => date('Ymd')
+ );
+ CRM_Core_BAO_Note::add($noteParams, $noteId);
+ }
+}
\ No newline at end of file
diff --git a/CRM/Core/Payment/SPGATEWAYNeweb.php b/CRM/Core/Payment/SPGATEWAYNeweb.php
new file mode 100644
index 000000000..c84fb356d
--- /dev/null
+++ b/CRM/Core/Payment/SPGATEWAYNeweb.php
@@ -0,0 +1,291 @@
+ array($rid, 'Positive'));
+ $ipn_result['Result']['MerchantOrderNo'] = CRM_Core_DAO::singleValueQuery("SELECT trxn_id FROM civicrm_contribution WHERE contribution_recur_id = %1 ORDER BY id ASC LIMIT 1", $queryParams);
+ $ipn_result['Status'] = $decryptParams['Status'];
+ $ipn_result['Result']['OrderNo'] = 'r_'.$ipn_result['Result']['OrderNo'];
+ $periodNo = $ipn_result['Result']['PeriodNo'];
+ CRM_Core_Error::debug_var('spgateway_neweb_transfer_ipn_result', $ipn_result);
+ $ipn_result = json_encode($ipn_result);
+ $ipn_post = array('Period' => CRM_Core_Payment_SPGATEWAYAPI::recurEncrypt($ipn_result, $paymentProcessor));
+ CRM_Core_Error::debug_var('spgateway_neweb_transfer_ipn_post', $ipn_post);
+
+ // prepare get
+ $firstCid = CRM_Core_DAO::singleValueQuery("SELECT id FROM civicrm_contribution WHERE contribution_recur_id = %1 ORDER BY id ASC LIMIT 1", $queryParams);
+ $ids = CRM_Contribute_BAO_Contribution::buildIds($firstCid);
+ $query = CRM_Contribute_BAO_Contribution::makeNotifyUrl($ids, NULL, TRUE);
+ $query .= '&ppid='.$pid;
+ parse_str($query, $ipn_get);
+ CRM_Core_Error::debug_var('spgateway_neweb_transfer_ipn_get', $ipn_get);
+
+ // create recurring record
+ $result = new stdClass();
+ $result->_ipn_result = $ipn_result;
+ $result->_post = $ipn_post;
+ $result->_get = $ipn_get;
+ $result->_response = CRM_Core_Payment_SPGATEWAY::doIPN(array('spgateway', 'ipn', 'Credit'), $ipn_post, $ipn_get, FALSE);
+ // If correct, it must return '1|OK'.
+ if (!empty($result->_response)) {
+ $query = "UPDATE civicrm_contribution SET payment_processor_id = %1 WHERE contribution_recur_id = %2 ORDER BY id DESC LIMIT 1";
+ $params = array(
+ 1 => array($pid, 'Positive'),
+ 2 => array($ids['contributionRecurID'], 'Positive'),
+ );
+ CRM_Core_DAO::executeQuery($query, $params);
+ // Check processor_id, trxn_id of contribution_recur
+ $sql = "SELECT trxn_id, processor_id FROM civicrm_contribution_recur WHERE id = %1";
+ $sqlParams = array( 1 => array($ids['contributionRecurID'], 'Positive'));
+ $recurDao = CRM_Core_DAO::executeQuery($sql, $sqlParams);
+ while ($recurDao->fetch()) {
+ if ($recurDao->processor_id != $pid) {
+ $recurParams['processor_id'] = $pid;
+ }
+ if ($recurDao->trxn_id != $periodNo) {
+ $recurParams['trxn_id'] = $periodNo;
+ }
+ if (!empty($recurParams)) {
+ $recurParams['id'] = $ids['contributionRecurID'];
+ $recurParams['message'] = ts('Modify parameters of original Newebpay by Newebpay data.');
+ CRM_Core_Error::debug_var('spgateway_neweb_transfer_update_recur_params', $recurParams);
+ CRM_Contribute_BAO_ContributionRecur::addNote($ids['contributionRecurID'], $recurParams['message']);
+ CRM_Contribute_BAO_ContributionRecur::add($recurParams, $null);
+ }
+ }
+ }
+ CRM_Core_Error::debug_var('spgateway_neweb_transfer_ipn_response', $result->_response);
+ echo $result->_response;
+ }
+ else {
+ $msg = 'Error. Decrypt error or Recurring ID is not found.';
+ CRM_Core_Error::debug_log_message('civicrm_spgateway.neweb: '.$msg);
+ echo $msg;
+ }
+ CRM_Utils_System::civiExit();
+ }
+
+
+ /**
+ * Migrate from civicrm_spgateway_neweb_resync
+ *
+ * @param bool $ppid_new
+ * @param string $day
+ * @param array $recurNo
+ * @return void
+ */
+ public static function resync($ppid_new, $day = '', $recurNo = array()) {
+ CRM_Core_Error::debug_log_message("Start doResyncOldNewebRecur, ppid_new = {$ppid_new}, day = {$day}");
+ $payment_processor = CRM_Core_BAO_PaymentProcessor::getPayment($ppid_new, 'live');
+ if (!empty($payment_processor)) {
+
+ if (empty($recurNo)) {
+ $offset = CRM_Core_BAO_Cache::getItem('spgateway_neweb', 'resync_offset_'.$ppid_new);
+ $cycle_day = empty($day) ? date('j') : $day;
+ $sql = "SELECT DISTINCT r.id AS rid from civicrm_contribution_recur r INNER JOIN civicrm_contribution c ON r.id = c.contribution_recur_id WHERE c.trxn_id LIKE 'r_%' AND r.cycle_day = %1 AND c.payment_processor_id = %2 LIMIT 300 OFFSET %3";
+ $params = array(
+ 1 => array($cycle_day, 'Integer'),
+ 2 => array($ppid_new, 'Integer'),
+ 3 => array($offset, 'Integer'),
+ );
+ $bao = CRM_Core_DAO::executeQuery($sql, $params);
+ if ($bao->N == 0) {
+ // offset variable roll back to zero.
+ CRM_Core_BAO_Cache::setItem(0, 'spgateway_neweb', 'resync_offset_'.$ppid_new);
+
+ // There are no recur need execute. return finished.
+ $message = "No more old neweb recurring need to sync {$ppid_new}";
+ CRM_Core_Error::debug_log_message($message);
+ return TRUE;
+ }
+ while($bao->fetch()) {
+ $recurNo[] = $bao->rid;
+ }
+ }
+ $total = count($recurNo);
+ $skip = $count = $alreadyExist = $transactFailed = $success = $queryFailed = 0;
+
+ foreach ($recurNo as $recurId) {
+ $sql = "SELECT id, last_receive_date , last_failed_date, ltid.last_trxn_id FROM civicrm_contribution_recur AS r
+ LEFT JOIN (SELECT contribution_recur_id AS rid, MAX(receive_date) AS last_receive_date FROM civicrm_contribution WHERE contribution_status_id = 1 AND contribution_recur_id = %1 GROUP BY contribution_recur_id) lrd ON lrd.rid = r.id
+ LEFT JOIN (SELECT contribution_recur_id AS rid, MAX(cancel_date) AS last_failed_date FROM civicrm_contribution WHERE contribution_status_id = 4 AND contribution_recur_id = %1 GROUP BY contribution_recur_id) lfd ON lfd.rid = r.id
+ LEFT JOIN (SELECT contribution_recur_id AS rid, CONCAT('r_', contribution_recur_id, '_', MAX(CAST(REGEXP_SUBSTR(trxn_id, '[0-9]+$') as INT))) AS last_trxn_id FROM civicrm_contribution WHERE contribution_recur_id = %1 AND trxn_id LIKE CONCAT('r_', contribution_recur_id, '_%') GROUP BY contribution_recur_id) ltid ON ltid.rid = r.id
+ WHERE r.id = %1";
+ $dao = CRM_Core_DAO::executeQuery($sql, array(1 => array($recurId, 'Integer')));
+ $dao->fetch();
+
+ // Only execute the contributions last month have successed.
+ $lastReceiveMonth = date('Ym', strtotime($dao->last_receive_date));
+ $lastCancelMonth = date('Ym', strtotime($dao->last_failed_date));
+ $lastExecuteMonth = max($lastReceiveMonth, $lastCancelMonth);
+ $thisMonth = date('Ym');
+ $subtractMonth = $thisMonth - $lastExecuteMonth;
+ if (!in_array($subtractMonth, array(1, 89))) {
+ $skip++;
+ continue;
+ }
+ $output = 'Recur ID: '.$recurId;
+ CRM_Core_Error::debug_log_message("Find not complete contribution in this month, recur_id = {$recurId}, trxn_id = {$dao->last_trxn_id}, receive_date = {$dao->last_receive_date}, cancel_date = {$dao->last_failed_date}, last_execute_month = {$lastExecuteMonth}");
+ $lastTrxnId = $dao->last_trxn_id;
+ $explodeTrxnId = explode('_', $lastTrxnId);
+ $no = $explodeTrxnId[2]+1;
+ $trxn_id = $recurId.'_'.$no;
+ $count++;
+
+ $sql = "SELECT amount FROM civicrm_contribution_recur WHERE id = %1";
+ $params = array( 1 => array($recurId, 'Positive'));
+ $amount = CRM_Core_DAO::singleValueQuery($sql, $params);
+ $amount = (int)$amount;
+ $request_data = array(
+ 'Amt' => $amount,
+ 'MerchantID' => $payment_processor['user_name'],
+ 'MerchantOrderNo' => $trxn_id,
+ 'RespondType' => CRM_Core_Payment_SPGATEWAY::RESPONSE_TYPE,
+ 'TimeStamp' => CRM_REQUEST_TIME,
+ 'Version' => CRM_Core_Payment_SPGATEWAY::QUERY_VERSION,
+ );
+ CRM_Core_Error::debug_var("doResyncOldNewebRecur:request_data", $request_data);
+ $used_args = array('IV','Amt','MerchantID','MerchantOrderNo', 'Key');
+ CRM_Core_Payment_SPGATEWAYAPI::encode($request_data, $payment_processor, $used_args);
+ $urlApi = CRM_Core_Payment_SPGATEWAY::REAL_DOMAIN.CRM_Core_Payment_SPGATEWAY::URL_API;
+ sleep(0.5);
+ CRM_Core_Error::debug_var("doResyncOldNewebRecur:encoded_request_data", $request_data);
+ $result = CRM_Core_Payment_SPGATEWAYAPI::sendRequest($urlApi, $request_data);
+ CRM_Core_Error::debug_var("doResyncOldNewebRecur:result", $result);
+
+ if (!empty($result) && $result->Status == 'SUCCESS') {
+ $output .= ":QuerySuccess";
+ echo ":QuerySuccess";
+ // prepare contribution
+ $contribution = new CRM_Contribute_DAO_Contribution();
+ $contribution->contribution_recur_id = $recurId;
+ $contribution->orderBy("id ASC");
+ $contribution->find(TRUE);
+ if ($contribution->id && $contribution->contribution_recur_id == $recurId) {
+ $exists = CRM_Core_DAO::singleValueQuery("SELECT COUNT(*) FROM civicrm_contribution WHERE trxn_id LIKE 'r_{$trxn_id}'");
+ if ($exists) {
+ $alreadyExist++;
+ $output .= ":DataExists:";
+ $output .= $result->Result->TradeStatus."\n";
+ echo ":DataExists:";
+ echo $result->Result->TradeStatus."\n";
+ continue;
+ }
+ // complex part to simulate spgateway ipn
+ $ipn_get = $ipn_post = array();
+
+ // prepare post, complex logic because recurring have different variable names
+ $ipn_result = clone $result;
+ if ($result->Result->TradeStatus != 1) {
+ $output .= ":TransactionFailed:".$result->Result->RespondMsg;
+ echo ":TransactionFailed:".$result->Result->RespondMsg;
+ $ipn_result->Status = 'Error';
+ $transactFailed++;
+ }
+ else {
+ $output .= ":TransactionCompleted";
+ echo ":TransactionCompleted";
+ $success++;
+ }
+ $ipn_result->Message = $result->Result->RespondMsg;
+ $ipn_result->Result->AuthAmt = $result->Result->Amt;
+ unset($ipn_result->Result->Amt);
+ unset($ipn_result->Result->CheckCode);
+ $ipn_result->Result->OrderNo = $result->Result->MerchantOrderNo;
+ $ipn_result->Result->MerchantOrderNo = $recurId;
+ $ipn_result->Result->do_not_email = TRUE;
+ $ipn_result->Result->AlreadyTimes = 1;
+ CRM_Core_Error::debug_var('doResyncOldNewebRecur:ipn_result', $ipn_result);
+ $ipn_result = json_encode($ipn_result);
+ $ipn_post = array('Period' => CRM_Core_Payment_SPGATEWAYAPI::recurEncrypt($ipn_result, $payment_processor));
+ CRM_Core_Error::debug_var('doResyncOldNewebRecur:ipn_post', $ipn_post);
+ self::transfer($ipn_post);
+ }
+ }
+ else {
+ var_dump($result);
+ $output .= ":QueryFailed";
+ echo ":QueryFailed";
+ $queryFailed++;
+ }
+ echo "\n";
+ CRM_Core_Error::debug_log_message($output);
+
+ }
+ $message = "cron result:";
+ $start = $offset+1;
+ $message .= "From date {$start}. ";
+ if ($skip > 0) {
+ $message .= "Skip {$skip} records which already completed this month. ";
+ }
+ $message .= "Updated {$count} records. {$alreadyExist} records exists, {$transactFailed} records failed, {$success} records success, {$queryFailed} records query failed.";
+ if ($total > ($count+$skip)) {
+ $unexecuted = $total - $count - $skip;
+ $message .= ",{$unexecuted} records scheduled to next cron.";
+ }
+ CRM_Core_Error::debug_log_message($message);
+ CRM_Core_BAO_Cache::setItem($offset+300, 'spgateway_neweb', 'resync_offset_'.$ppid_new);
+ }
+ }
+}
diff --git a/CRM/Core/xml/Menu/Misc.xml b/CRM/Core/xml/Menu/Misc.xml
index 8f62d576a..a9ca9c392 100644
--- a/CRM/Core/xml/Menu/Misc.xml
+++ b/CRM/Core/xml/Menu/Misc.xml
@@ -186,4 +186,18 @@
CRM_Core_Payment_SPGATEWAY::doSingleQueryRecord
access CiviContribute
+ -
+ spgateway/ipn
+ CRM_Core_Payment_SPGATEWAY::doIPN
+ 1
+ true
+ true
+
+ -
+ spgateway/neweb-transfer
+ CRM_Core_Payment_SPGATEWAYNeweb::transfer
+ 1
+ true
+ true
+
diff --git a/CRM/Import/Parser/Contact.php b/CRM/Import/Parser/Contact.php
index d7975115e..483db5d31 100644
--- a/CRM/Import/Parser/Contact.php
+++ b/CRM/Import/Parser/Contact.php
@@ -1912,7 +1912,7 @@ function formatParams(&$params, $onDuplicate, $cid) {
* @param string $dateParam index of params
* @static
*/
- function formatCustomDate(&$params, &$formatted, $dateType, $dateParam) {
+ public static function formatCustomDate(&$params, &$formatted, $dateType, $dateParam) {
//fix for CRM-2687
CRM_Utils_Date::convertToDefaultDate($params, $dateType, $dateParam);
diff --git a/CRM/Mailing/BAO/Mailing.php b/CRM/Mailing/BAO/Mailing.php
index 9332491af..7b1b0fc0f 100644
--- a/CRM/Mailing/BAO/Mailing.php
+++ b/CRM/Mailing/BAO/Mailing.php
@@ -2022,7 +2022,7 @@ public static function &report($id, $skipDetails = FALSE) {
$row[$field] = $mailing->$field;
}
- if ($mailing->queue) {
+ if (!empty($mailing->queue) && !empty($mailing->delivered)) {
$row['delivered_rate'] = (100.0 * $mailing->delivered) / $mailing->queue;
$row['opened_rate'] = (100.0 * $row['opened']) / $mailing->delivered;
$row['clicked_rate'] = (100.0 * $row['url']) / $mailing->delivered;
diff --git a/CRM/Utils/Mail.php b/CRM/Utils/Mail.php
index 6d9de3351..9e4c224d2 100644
--- a/CRM/Utils/Mail.php
+++ b/CRM/Utils/Mail.php
@@ -442,7 +442,7 @@ public static function checkRFC822Email($address) {
$name = '';
$email = trim($address);
}
- if (!empty($name) && preg_match('/[' . preg_quote(self::RFC_2822_SPECIAL_CHARS) . ']/u', $name)) {
+ if (!empty($name) && preg_match('/[ ' . preg_quote(self::RFC_2822_SPECIAL_CHARS) . ']/u', $name)) {
// check the name already quoted
if (!preg_match('/^"[^"]+"\s*<[^>]+@[^>]+>/i', $address)) {
return FALSE;
diff --git a/CRM/Utils/Recent.php b/CRM/Utils/Recent.php
index 31ea96d2b..63af8c3e5 100644
--- a/CRM/Utils/Recent.php
+++ b/CRM/Utils/Recent.php
@@ -64,7 +64,7 @@ static function initialize() {
if (!self::$_recent) {
$session = CRM_Core_Session::singleton();
self::$_recent = $session->get(self::STORE_NAME);
- if (!self::$_recent) {
+ if (empty(self::$_recent) || (!empty(self::$_recent) && !is_array(self::$_recent))) {
self::$_recent = array();
}
}
diff --git a/CRM/Utils/Rule.php b/CRM/Utils/Rule.php
index c613e4da2..22e8d3355 100644
--- a/CRM/Utils/Rule.php
+++ b/CRM/Utils/Rule.php
@@ -172,6 +172,12 @@ static function url($url, $checkDomain = '', $checkHTTPS = NULL) {
$url = $scheme.'://' . $_SERVER['HTTP_HOST'] . $url;
}
$valid = (bool) filter_var($url, FILTER_VALIDATE_URL);
+ if (!$valid) {
+ $parts = parse_url($url);
+ if (!empty($parts['scheme']) && !empty($parts['host'])) {
+ $valid = TRUE;
+ }
+ }
if (!in_array(substr($url, 0, 5), array('http:', 'https'))) {
$valid = FALSE;
diff --git a/CRM/Utils/System.php b/CRM/Utils/System.php
index cbf0af714..ef0e59896 100644
--- a/CRM/Utils/System.php
+++ b/CRM/Utils/System.php
@@ -1583,7 +1583,7 @@ public static function cmsDir($type) {
/**
* Get CMS public or private or temp dir
*
- * @return boolean.
+ * @return string
*/
public static function cmsRootPath() {
return CRM_Core_Config::$_userSystem->cmsRootPath();
@@ -1697,22 +1697,24 @@ public static function sameSiteCheck() {
$isUcBrowser = preg_match('/UCBrowser\//i', $useragent);
if ($isUcBrowser) {
- preg_match('/UCBrowser\/(\d+)\.(\d+)\.(\d+)[\.\d]* /i', $useragent, $ucVersion);
- if ($ucVersion[1] < 12) { // major
- return FALSE;
- }
- if ($ucVersion[2] < 13) { // minor
- return FALSE;
- }
- if ($ucVersion[3] < 2) { // buil
- return FALSE;
+ if(preg_match('/UCBrowser\/(\d+)\.(\d+)\.(\d+)[\.\d]* /i', $useragent, $ucVersion)) {
+ if ($ucVersion[1] < 12) { // major
+ return FALSE;
+ }
+ if ($ucVersion[2] < 13) { // minor
+ return FALSE;
+ }
+ if ($ucVersion[3] < 2) { // buil
+ return FALSE;
+ }
}
}
if ($isChromiumBased) {
- preg_match('/Chrome\/(\d+)\.(\d+)\.(\d+)[\.\d]* /i', $useragent, $chVersion);
- if ($chVersion[1] >= 51 && $chVersion[1] <= 66) {
- return FALSE;
+ if (preg_match('/Chrome\/(\d+)\.(\d+)\.(\d+)[\.\d]* /i', $useragent, $chVersion)) {
+ if ($chVersion[1] >= 51 && $chVersion[1] <= 66) {
+ return FALSE;
+ }
}
}
return TRUE;
diff --git a/CRM/Utils/System/Drupal.php b/CRM/Utils/System/Drupal.php
index 30e6f2353..35faa4c2e 100644
--- a/CRM/Utils/System/Drupal.php
+++ b/CRM/Utils/System/Drupal.php
@@ -614,7 +614,8 @@ static function variable_get($name, $default) {
if ($version < 8 ) {
return variable_get($name, $default);
}
- else {
+ else{
+ // no drupal 8+ equivilent func
// exception
}
}
diff --git a/api/v2/utils.v2.php b/api/v2/utils.v2.php
index 3b238766b..b885a7435 100644
--- a/api/v2/utils.v2.php
+++ b/api/v2/utils.v2.php
@@ -103,8 +103,7 @@ function civicrm_create_success($result = 1) {
*/
function civicrm_duplicate($error) {
if (is_array($error) && civicrm_error($error)) {
- $code = $error['error_message']['code'];
- if ($code == CRM_Core_Error::DUPLICATE_CONTACT) {
+ if (!empty($error['error_message']['code']) && $error['error_message']['code'] == CRM_Core_Error::DUPLICATE_CONTACT) {
return TRUE;
}
}
diff --git a/api/v3/Contact.php b/api/v3/Contact.php
index 86c9f0ace..de621b3a2 100644
--- a/api/v3/Contact.php
+++ b/api/v3/Contact.php
@@ -917,4 +917,79 @@ function civicrm_api3_contact_checksum($params) {
array($params['contact_id'] => $checksum),
);
return civicrm_api3_create_success($values, $params, 'contact', 'checksum');
+}
+
+function civicrm_api3_contact_duplicatecheck($params) {
+ if (empty($params['contact_type'])) {
+ return civicrm_api3_create_error('Missing required field in params: contact_type.');
+ }
+ if (empty($params['match'])) {
+ return civicrm_api3_create_error('Missing required fields in params: match.');
+ }
+
+ $dedupeParams = CRM_Dedupe_Finder::formatParams($params['match'], $params['contact_type']);
+ if (empty($dedupeParams['civicrm_contact'])) {
+ return civicrm_api3_create_error('Parameter check error. You need to specify at least 1 field to dedupe.');
+ }
+ if (isset($params['check_permission'])) {
+ $dedupeParams['check_permission'] = $params['check_permission'];
+ }
+
+ if (!empty($params['dedupe_rule_id'])) {
+ if (!is_numeric($params['dedupe_rule_id'])) {
+ return civicrm_api3_create_error('Please specify numeric rule id.');
+ }
+ $rgBao = new CRM_Dedupe_BAO_RuleGroup();
+ $rgBao->id = $params['dedupe_rule_id'];
+ $rgBao->contact_type = $params['contact_type'];
+ if (!$rgBao->find(TRUE)) {
+ return civicrm_api3_create_error('Please specify the correct rule ID corresponding to contact type.');
+ }
+ $foundDupes = CRM_Dedupe_Finder::dupesByParams($dedupeParams,
+ $params['contact_type'],
+ 'Strict',
+ array(),
+ $params['dedupe_rule_id']
+ );
+ }
+ elseif(!empty($params['dedupe_rules']) && is_array($params['dedupe_rules'])) {
+ if (empty($params['threshold']) || !is_numeric($params['threshold']) || $params['threshold'] <= 0) {
+ return civicrm_api3_create_error('Please specify numeric threshold and greater than zero of this dedupe.');
+ }
+ $supportedFields = CRM_Dedupe_BAO_RuleGroup::supportedFields($params['contact_type']);
+ foreach($params['dedupe_rules'] as $rule) {
+ if (!empty($rule['table']) && !empty($rule['field']) && !empty($rule['weight'])) {
+ if (!isset($supportedFields[$rule['table']])) {
+ return civicrm_api3_create_error('Rule table should be in supported table. Your rule table: '.$rule['table']." doesn't be supported.");
+ }
+ else {
+ if (!isset($supportedFields[$rule['table']][$rule['field']])) {
+ return civicrm_api3_create_error('Your rule table: '.$rule['table'].', field:'.$rule['field']." doesn't be supported.");
+ }
+ }
+ }
+ else {
+ return civicrm_api3_create_error('Each rule should have three required data: table,field,weight.');
+ }
+ }
+ $foundDupes = CRM_Dedupe_Finder::dupesByRules(
+ $dedupeParams,
+ $params['contact_type'],
+ 'Strict',
+ array(),
+ $params['dedupe_rules'],
+ $params['threshold']
+ );
+ }
+ else {
+ $foundDupes = CRM_Dedupe_Finder::dupesByParams($dedupeParams, $params['contact_type'], 'Strict', array());
+ }
+
+ if (empty($foundDupes)) {
+ $foundDupes = [];
+ }
+ if (count($foundDupes)) {
+ sort($foundDupes);
+ }
+ return civicrm_api3_create_success($foundDupes, $params, 'contact', 'duplicatecheck');
}
\ No newline at end of file
diff --git a/api/v3/utils.php b/api/v3/utils.php
index 4ad9ceaf3..ee91ada70 100644
--- a/api/v3/utils.php
+++ b/api/v3/utils.php
@@ -715,7 +715,9 @@ function _civicrm_api3_get_options_from_params(&$params, $queryObject = false, $
function _civicrm_api3_apply_options_to_dao(&$params, &$dao, $entity) {
$options = _civicrm_api3_get_options_from_params($params,false,$entity);
- $dao->limit((int)$options['offset'], (int)$options['limit']);
+ if (!empty($options['limit'])) {
+ $dao->limit((int)$options['offset'], (int)$options['limit']);
+ }
if (!empty($options['sort'])) {
$dao->orderBy($options['sort']);
}
diff --git a/civicrm-version.txt b/civicrm-version.txt
index ee2b15f99..6cb41c9e1 100644
--- a/civicrm-version.txt
+++ b/civicrm-version.txt
@@ -1 +1 @@
-6.0.9+8 (3957f57)
+6.0.9+9 (e7cc3c4)
diff --git a/drupal b/drupal
index 966d85030..3cb5b18f3 160000
--- a/drupal
+++ b/drupal
@@ -1 +1 @@
-Subproject commit 966d850309fe39deea302b0f03805556c1e61b2e
+Subproject commit 3cb5b18f384d1646042028e04abe7dba827c9b28
diff --git a/extern/url.php b/extern/url.php
index ed644d770..02715a0bb 100644
--- a/extern/url.php
+++ b/extern/url.php
@@ -1,6 +1,6 @@
-{js src=packages/Magnific-Popup/dist/jquery.magnific-popup.min.js group=999 weight=997}{/js}
+{js src=packages/Magnific-Popup/dist/jquery.magnific-popup.min.js group=999 weight=997 library=civicrm/civicrm-js-magnific-popup}{/js}
+
diff --git a/templates/CRM/Event/Form/Registration/ThankYou.tpl b/templates/CRM/Event/Form/Registration/ThankYou.tpl
index 385d8a66f..939a95b11 100644
--- a/templates/CRM/Event/Form/Registration/ThankYou.tpl
+++ b/templates/CRM/Event/Form/Registration/ThankYou.tpl
@@ -245,7 +245,7 @@
{ts 1=$customName+1}Participant Information - Participant %1{/ts}
{foreach from=$value item=val key=field}
- {if $field eq additionalCustomPre or $field eq additionalCustomPost }
+ {if $field eq 'additionalCustomPre' or $field eq 'additionalCustomPost' }
{if $field eq 'additionalCustomPre' }