Save contribution, prevents insertion failure
[tc-ipn-receiver.git] / trustcommerceIPN.php
CommitLineData
33422de3
LMM
1<?php
2/*
3 * This file is part of CiviCRM.
4 *
5 * CiviCRM is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * CiviCRM is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with CiviCRM. If not, see <http://www.gnu.org/licenses/>.
17 *
38aae692
RR
18 * Copyright (C) 2012
19 * Licensed to CiviCRM under the GPL v3 or higher
20 *
21 * Modified by Lisa Marie Maginnis <lisa@fsf.org> (http://www.fsf.org)
33422de3
LMM
22 *
23 */
24
25class CRM_Core_Payment_trustcommerce_IPN extends CRM_Core_Payment_BaseIPN {
26 function __construct() {
27 parent::__construct();
28 }
29
30
31 function main($component = 'contribute') {
32 static $no = NULL;
33 $billingid = CRM_Utils_Request::retrieve('billingid', 'String', $no, FALSE, 'GET');
34 $input['status'] = CRM_Utils_Request::retrieve('status', 'String', $no, FALSE, 'GET');
35 $input['amount'] = CRM_Utils_Request::retrieve('amount', 'String', $no, FALSE, 'GET');
36 $input['date'] = CRM_Utils_Request::retrieve('date', 'String', $no, FALSE, 'GET');
37 $input['trxn_id'] = CRM_Utils_Request::retrieve('trxn_id', 'String', $no, FALSE, 'GET');
38 $checksum = CRM_Utils_Request::retrieve('checksum', 'String', $no, FALSE, 'GET');
39
40 if ($billingid) {
41 if( $input['status'] == '' || $input['amount'] == '' || $input['date'] == '' || $input['trxn_id'] == '' || md5($billingid.$input['trxn_id'].$input['amount'].$input['date']) != $checksum) {
42 CRM_Core_Error::debug_log_message("Error: IPN called with out proper fields");
43 echo "Error: invalid paramaters<p>\n";
44 exit;
45 }
46
47
48 $ids = $objects = array();
49 $input['component'] = $component;
50
51 // load post ids in $ids
52 $ids = NULL;
53 $ids = $this->getIDs($billingid, $input, $input['component']);
54
55 $ids['trxn_id'] = $input['trxn_id'];
56
57 if($this->checkDuplicate($input, $ids) != NULL) {
38aae692 58 $msg = 'TrustCommerceIPN: Skipping duplicate contribution: '.$ids['contribution'].' for contact: '.$ids['contact'].' amount: $'.$input['amount'].' trxn_id: '.$input['trxn_id']."\n";
de12f901
LMM
59 echo $msg;
60 CRM_Core_Error::debug_log_message($msg);
33422de3
LMM
61 exit;
62 }
33422de3
LMM
63
64 if(array_key_exists('membership', $ids)) {
65 $membership = array();
66 $params = array('id' => $ids['membership']);
67 $obj = CRM_Member_BAO_Membership::retrieve($params, $membership);
68 $objects['membership'] = array(&$obj);
69 }
33422de3
LMM
70
71 $paymentProcessorID = CRM_Core_DAO::getFieldValue('CRM_Financial_DAO_PaymentProcessorType',
72 'TrustCommerce', 'id', 'name'
73 );
74
75 if (!$this->validateData($input, $ids, $objects, TRUE, $paymentProcessorID)) {
76 return FALSE;
77 }
78 // var_dump($objects);
79
80 if ($component == 'contribute' && $ids['contributionRecur']) {
81 // check if first contribution is completed, else complete first contribution
82 $first = TRUE;
83 if ($objects['contribution']->contribution_status_id == 1) {
84 $first = FALSE;
85 }
86
87
88 return $this->processRecur($input, $ids, $objects, $first);
89
90 }
91
92 }
38aae692 93}
33422de3
LMM
94
95 protected function checkDuplicate($input, $ids) {
96// $sql='select id from civicrm_contribution where receive_date like \''.$input['date'].'%\' and total_amount='.$input['amount'].' and contact_id='.$ids['contact'].' and contribution_status_id = 1 limit 1';
1c234935 97 $sql="select id from civicrm_contribution where trxn_id = '".$ids['trxn_id']."' and contribution_status_id != 2";
33422de3
LMM
98
99
100 $result = CRM_Core_DAO::executeQuery($sql);
de12f901
LMM
101 if($result->fetch()) {
102 $id = $result->id;
103 } else {
104 $id = NULL;
105 }
106
33422de3
LMM
107 return $id;
108 }
109 protected function processRecur($input, $ids, $objects, $first) {
110 $recur = &$objects['contributionRecur'];
111 $contributionStatus = CRM_Contribute_PseudoConstant::contributionStatus(NULL, 'name');
112
113 $transaction = new CRM_Core_Transaction();
114
115 $now = date('YmdHis');
116
117 // fix dates that already exist
118 $dates = array('create_date', 'start_date', 'end_date', 'cancel_date', 'modified_date');
119 foreach ($dates as $name) {
120 if ($recur->$name) {
121 $recur->$name = CRM_Utils_Date::isoToMysql($recur->$name);
122 }
123 }
124
125 if (!$first) {
126 // create a contribution and then get it processed
127 $contribution = new CRM_Contribute_BAO_Contribution();
128 $contribution->contact_id = $ids['contact'];
129 $contribution->financial_type_id = $objects['contributionType']->id;
130 $contribution->contribution_page_id = $ids['contributionPage'];
131 $contribution->contribution_recur_id = $ids['contributionRecur'];
132 $contribution->receive_date = $input['date'];
133 $contribution->currency = $objects['contribution']->currency;
134 $contribution->payment_instrument_id = 1;
135 $contribution->amount_level = $objects['contribution']->amount_level;
136 $contribution->address_id = $objects['contribution']->address_id;
33422de3
LMM
137 $contribution->campaign_id = $objects['contribution']->campaign_id;
138 $contribution->total_amount = $input['amount'];
139
140 $objects['contribution'] = &$contribution;
141 }
de12f901 142
33422de3
LMM
143 $objects['contribution']->invoice_id = md5(uniqid(rand(), TRUE));
144 // $objects['contribution']->total_amount = $objects['contribution']->total_amount;
145 $objects['contribution']->trxn_id = $input['trxn_id'];
146
3e3d3df5
LMM
147 // check if contribution is already completed, if so we ignore this ipn
148 if ($objects['contribution']->contribution_status_id == 1) {
149 $transaction->commit();
150 CRM_Core_Error::debug_log_message("returning since contribution has already been handled");
151 echo 'Success: Contribution has already been handled<p>';
152 echo '';
153 return TRUE;
154 }
33422de3
LMM
155
156 $sendNotification = FALSE;
de12f901
LMM
157
158 $recur->trxn_id = $input['trxn_id'];
159 $recur->total_amount = $input['amount'];
160 $recur->payment_instrument_id = 1;
161 $recur->fee = 0;
162 $recur->net_amount = $input['amount'];
163
7bd867b8 164 $objects['contribution']->save();
802589c9 165
33422de3
LMM
166 if ($input['status'] == 1) {
167
168 // Approved
169 if ($first) {
170 $recur->start_date = $now;
171 $sendNotification = TRUE;
172 $subscriptionPaymentStatus = CRM_Core_Payment::RECURRING_PAYMENT_START;
173 }
174 $statusName = 'In Progress';
175 if (($recur->installments > 0) &&
176 ($input['subscription_paynum'] >= $recur->installments)
177 ) {
178 // this is the last payment
179 $statusName = 'Completed';
180 $recur->end_date = $now;
181
182 $sendNotification = TRUE;
183 $subscriptionPaymentStatus = CRM_Core_Payment::RECURRING_PAYMENT_END;
184 }
33422de3
LMM
185
186 $recur->modified_date = $now;
187 $recur->contribution_status_id = array_search($statusName, $contributionStatus);
188 $recur->save();
de12f901 189 $input['is_test'] = 0;
38aae692 190 $msg = 'TrustCommerceIPN: Created contribution: '.$ids['contribution'].' for contact: '.$ids['contact'].' amount: $'.$input['amount'].' trxn_id: '.$input['trxn_id'].' status: Completed'."\n";
de12f901
LMM
191 echo $msg;
192 CRM_Core_Error::debug_log_message($msg);
193
194 $this->completeTransaction($input, $ids, $objects, $transaction, $recur);
33422de3 195 }
de12f901 196 else if( $input['status'] == 4 ) {
33422de3
LMM
197 // Declined
198 // failed status
de12f901 199
33422de3
LMM
200 $recur->contribution_status_id = array_search('Failed', $contributionStatus);
201 $recur->cancel_date = $now;
202 $recur->save();
de12f901 203
38aae692 204 $msg = 'TrustCommerceIPN: Created contribution: '.$ids['contribution'].' for contact: '.$ids['contact'].' amount: $'.$input['amount'].' trxn_id: '.$input['trxn_id'].' status: Failed'."\n";
de12f901
LMM
205 echo $msg;
206 CRM_Core_Error::debug_log_message($msg);
571c1830
LMM
207
208 /* Disable cancelling transactions */
209 $input['skipComponentSync'] = 1;
38aae692 210 return $this->failed($objects, $transaction, $input);
33422de3
LMM
211 }
212
33422de3
LMM
213 if ($sendNotification) {
214 $autoRenewMembership = FALSE;
de12f901 215 if ($recur->id && isset($ids['membership']) && $ids['membership'] ) {
33422de3
LMM
216 $autoRenewMembership = TRUE;
217 }
218
33422de3
LMM
219 //send recurring Notification email for user
220 CRM_Contribute_BAO_ContributionPage::recurringNotify($subscriptionPaymentStatus,
221 $ids['contact'],
222 $ids['contributionPage'],
223 $recur,
224 $autoRenewMembership
225 );
33422de3 226 }
33422de3
LMM
227 }
228
229 protected function getIDs($billingid, $input, $module) {
230 $sql = "SELECT cr.id, cr.contact_id, co.id as coid
231 FROM civicrm_contribution_recur cr
232 INNER JOIN civicrm_contribution co ON co.contribution_recur_id = cr.id
233 WHERE cr.processor_id = '$billingid' LIMIT 1";
234
235
236 $result = CRM_Core_DAO::executeQuery($sql);
237 $result->fetch();
238 $ids['contribution'] = $result->coid;
239 $ids['contributionRecur'] = $result->id;
240 $ids['contact'] = $result->contact_id;
241
242 if (!$ids['contributionRecur']) {
243 CRM_Core_Error::debug_log_message("Could not find billingid: ".$billingid);
1c234935 244 echo "Failure: Could not find contributionRecur: $billingid <p>\n";
33422de3
LMM
245 exit();
246 }
247
248 // get page id based on contribution id
249 $ids['contributionPage'] = CRM_Core_DAO::getFieldValue('CRM_Contribute_DAO_Contribution',
250 $ids['contribution'],
251 'contribution_page_id'
252 );
253
254 if ($module == 'event') {
255 // FIXME: figure out fields for event
256 }
257 else {
258 // get the optional ids
259
260 // Get membershipId. Join with membership payment table for additional checks
261 $sql = "
262 SELECT m.id
263 FROM civicrm_membership as m
264 WHERE m.contribution_recur_id = '{$ids['contributionRecur']}'
265 LIMIT 1";
266 if ($membershipId = CRM_Core_DAO::singleValueQuery($sql)) {
267
268 $ids['membership'] = $membershipId;
269 }
270
271 }
272
273 return $ids;
274}
275
276
277
278}