| 1 | <?php |
|---|
| 2 | |
|---|
| 3 | |
|---|
| 4 | |
|---|
| 5 | /** |
|---|
| 6 | * @package ecommerce |
|---|
| 7 | */ |
|---|
| 8 | |
|---|
| 9 | /** |
|---|
| 10 | * Sub-class of Payment that supports PayPal Website Payment Standard |
|---|
| 11 | * (https://www.paypal.com/IntegrationCenter/ic_standard_home.html) as its payment processor |
|---|
| 12 | Configure using |
|---|
| 13 | PayPalPayment::setMyVariable(value); |
|---|
| 14 | in www.mysite.com/ecommerce/_config.php file |
|---|
| 15 | |
|---|
| 16 | Must configure: |
|---|
| 17 | $setPayPalRealAccount; |
|---|
| 18 | $setPayPalTestAccount; |
|---|
| 19 | $setPayPalUseTestAccount; |
|---|
| 20 | |
|---|
| 21 | May configure |
|---|
| 22 | $setPayPalImageLocation; |
|---|
| 23 | $setPayPalContinueNextButton; |
|---|
| 24 | $setPayPalPurchaseName; |
|---|
| 25 | $setPayPalCppHeaderImage; |
|---|
| 26 | $setPayPalCppHeaderBackcolor; |
|---|
| 27 | $setPayPalCppHeaderBordercolor; |
|---|
| 28 | $setPayPalCppPayflowColor; |
|---|
| 29 | $setPayPalCs; |
|---|
| 30 | |
|---|
| 31 | REQUIREMENTS: |
|---|
| 32 | need to add: "PayPalInstructions" field to CheckoutPage.php |
|---|
| 33 | static $db = array( |
|---|
| 34 | "PayPalInstructions" => "HTMLText" |
|---|
| 35 | ); |
|---|
| 36 | |
|---|
| 37 | have a paypalPaymentPage.ss template or replace some code below (search for renderwith) |
|---|
| 38 | on the paypalPaymentPage you can use $PayPalInstructions (see above) |
|---|
| 39 | **/ |
|---|
| 40 | |
|---|
| 41 | |
|---|
| 42 | class PayPalPayment extends Payment { |
|---|
| 43 | |
|---|
| 44 | protected static $payPalRealAccount; static function setPayPalRealAccount($payPalRealAccount) { self::$payPalRealAccount = $payPalRealAccount; } |
|---|
| 45 | protected static $payPalTestAccount; static function setPayPalTestAccount($payPalTestAccount) { self::$payPalTestAccount = $payPalTestAccount; } |
|---|
| 46 | protected static $payPalUseTestAccount; static function setPayPalUseTestAccount($payPalUseTestAccount) { self::$payPalUseTestAccount = $payPalUseTestAccount; } |
|---|
| 47 | protected static $payPalImageLocation; static function setPayPalImageLocation($payPalImageLocation) { self::$payPalImageLocation = $payPalImageLocation; } |
|---|
| 48 | protected static $payPalContinueNextButton; static function setPayPalContinueNextButton($payPalContinueNextButton) { self::$payPalContinueNextButton = $payPalContinueNextButton; } |
|---|
| 49 | protected static $payPalPurchaseName; static function setPayPalPurchaseName($payPalPurchaseName) { self::$payPalPurchaseName = $payPalPurchaseName; } |
|---|
| 50 | protected static $payPalCppHeaderImage; static function setPayPalCppHeaderImage($payPalCppHeaderImage) { self::$payPalCppHeaderImage = $payPalCppHeaderImage; } |
|---|
| 51 | protected static $payPalCppHeaderBackcolor; static function setPayPalCppHeaderBackcolor($payPalCppHeaderBackcolor) { self::$payPalCppHeaderBackcolor = $payPalCppHeaderBackcolor; } |
|---|
| 52 | protected static $payPalCppHeaderBordercolor; static function setPayPalCppHeaderBordercolor($payPalCppHeaderBordercolor) { self::$payPalCppHeaderBordercolor = $payPalCppHeaderBordercolor; } |
|---|
| 53 | protected static $payPalCppPayflowColor; static function setPayPalCppPayflowColor($payPalCppPayflowColor) { self::$payPalCppPayflowColor = $payPalCppPayflowColor; } |
|---|
| 54 | protected static $payPalCs; static function setPayPalCs($payPalCs) { self::$payPalCs = $payPalCs; } |
|---|
| 55 | |
|---|
| 56 | |
|---|
| 57 | // extra fields to be added to the checkout form |
|---|
| 58 | // at present we do not do anything with this selection |
|---|
| 59 | // however, on the paypal select payment type the user is pushed toward paypal while they can also pay with credit card |
|---|
| 60 | // in the future, it is envisaged that their choice will be forwarded to paypal so that they can skip this section |
|---|
| 61 | function getPaymentFormFields() { |
|---|
| 62 | $field = new OptionsetField("PayPalPaymentMethod", "preferred payment method", array("VISA" => "VISA", "MASTERCARD" => "MASTERCARD", "AMEX" => "AMEX", "PAYPAL ACCOUNT" => "PAYPAL ACCOUNT"), "" ); |
|---|
| 63 | $field->addExtraClass("optionSet"); |
|---|
| 64 | $fieldSet = new FieldSet( |
|---|
| 65 | $field |
|---|
| 66 | ); |
|---|
| 67 | return $fieldSet; |
|---|
| 68 | } |
|---|
| 69 | |
|---|
| 70 | function getPaymentFormRequirements() { |
|---|
| 71 | null; |
|---|
| 72 | } |
|---|
| 73 | |
|---|
| 74 | function getPaymentFormRequiredFields() { |
|---|
| 75 | return array(); |
|---|
| 76 | } |
|---|
| 77 | |
|---|
| 78 | function processPayment($data, $form) { |
|---|
| 79 | $tmpPage = new Page(); |
|---|
| 80 | $tmpPage->Title = "Make payment at Paypal"; |
|---|
| 81 | /* |
|---|
| 82 | echo $this->StartPayPalForm(); |
|---|
| 83 | return array('Processing' => true, 'ReturnValue' => $form); |
|---|
| 84 | */ |
|---|
| 85 | $CheckoutPageObject = DataObject::get_one("CheckoutPage", ""); |
|---|
| 86 | $message = $CheckoutPageObject->PayPalInstructions; |
|---|
| 87 | $tmpPage->PayPalInstructions = $message; |
|---|
| 88 | $tmpPage->Content = $this->buildPayPalSubmission(); |
|---|
| 89 | $tmpPage->URLSegment = "paypalpayment"; |
|---|
| 90 | $controller = new Page_Controller($tmpPage); |
|---|
| 91 | //$controller->pushCurrent();/* does not work! */ |
|---|
| 92 | $form = $controller->renderWith("paypalPaymentPage"); |
|---|
| 93 | Requirements::clear(); /* does not work! */ |
|---|
| 94 | return array('Processing' => true, 'ReturnValue' => $form); |
|---|
| 95 | } |
|---|
| 96 | |
|---|
| 97 | function buildPayPalSubmission() { |
|---|
| 98 | $member = $this->Member(); |
|---|
| 99 | $o = DataObject::get_by_id("Order", $this->OrderID); |
|---|
| 100 | if(self::$payPalUseTestAccount) { |
|---|
| 101 | $accountEmail = self::$payPalTestAccount; |
|---|
| 102 | $URL = "https://www.sandbox.paypal.com/cgi-bin/webscr"; |
|---|
| 103 | } |
|---|
| 104 | else { |
|---|
| 105 | $accountEmail = self::$payPalRealAccount; |
|---|
| 106 | $URL = "https://www.paypal.com/cgi-bin/webscr"; |
|---|
| 107 | } |
|---|
| 108 | |
|---|
| 109 | $returnUrl = Director::absoluteBaseURL(). 'PayPalPayment_Handler/?flush=1'; |
|---|
| 110 | $cancelUrl = Director::absoluteBaseURL(). CheckoutPage::find_link() . "ConfirmPayPal/$order->ID"; |
|---|
| 111 | $notifyUrl = $returnUrl; |
|---|
| 112 | |
|---|
| 113 | $info = array( |
|---|
| 114 | //<!-- PayPal Configuration --> |
|---|
| 115 | "business" => $accountEmail, |
|---|
| 116 | //rather than uploading the cart, the decision was made to just upload the total cost of the purchase |
|---|
| 117 | "cmd" => "_xclick", //The button that the person clicked was a Buy Now button |
|---|
| 118 | "return" => $returnUrl, |
|---|
| 119 | "cancel_return" => $cancelUrl, |
|---|
| 120 | "notify_url" => $notifyUrl, |
|---|
| 121 | "rm" => 0, // 0 = GET with all variables, 1 GET without transaction variables, 2 = POST with transaction variables |
|---|
| 122 | "currency_code" => Order::site_currency(), |
|---|
| 123 | "bn" => "Silverstripe", //name of cart I think .... |
|---|
| 124 | |
|---|
| 125 | //<!-- Payment Page Information --> |
|---|
| 126 | "no_shipping" => 1,// silverstripe collects this 0: (default) buyer is prompted to include a shipping address. 1: buyer is not asked for a shipping address? 2: buyer must provide a shipping address |
|---|
| 127 | "noShipping" => 1,// check! |
|---|
| 128 | "no_note" => 1, //buyer does not have to leave a note |
|---|
| 129 | "cn" => "",//Label above the note field. |
|---|
| 130 | |
|---|
| 131 | //payment page look and paypal customisation |
|---|
| 132 | "image_url" => self::$payPalImageLocation, |
|---|
| 133 | "cbt" => self::$payPalContinueNextButton, |
|---|
| 134 | "lc" => "NZ", //language of login page on Paypal |
|---|
| 135 | "cpp_header_image" => self::$payPalCppHeaderImage, //Sets the image at the top left of the payment page. The images maximum size is 750 pixels wide by 90 pixels high. PayPal recommends that you provide an image that is stored only on a secure (https) server. |
|---|
| 136 | "cpp_headerback_color" => self::$payPalCppHeaderBackcolor, |
|---|
| 137 | "cpp_headerborder_color" => self::$payPalCppHeaderBordercolor, |
|---|
| 138 | "cpp_payflow_color" => self::$payPalCppPayflowColor, |
|---|
| 139 | "cs" => self::$payPalCs, //background color - this can be set using your paypal account |
|---|
| 140 | "page_style" => "primary", //you can set different styles or choose paypal |
|---|
| 141 | |
|---|
| 142 | //<!-- Product Information --> |
|---|
| 143 | "item_name" => self::$payPalPurchaseName, |
|---|
| 144 | "amount" => $this->Amount, |
|---|
| 145 | "quantity" => 1, |
|---|
| 146 | "item_number" => $this->OrderID, |
|---|
| 147 | "undefined_quantity" => 0, |
|---|
| 148 | /* set options - colours - etc... |
|---|
| 149 | "on0" => $paypal[on0], |
|---|
| 150 | "os0" => $paypal[os0], |
|---|
| 151 | "on1" => $paypal[on1], |
|---|
| 152 | "os1" => $paypal[os1], |
|---|
| 153 | */ |
|---|
| 154 | //<!-- Shipping and Misc Information --> |
|---|
| 155 | "shipping" => $this->Shipping, |
|---|
| 156 | "shipping2" => 0, |
|---|
| 157 | "handling" => 0, |
|---|
| 158 | "tax" => $this->AddedTax, |
|---|
| 159 | "custom" => $this->OrderID,//add anything extra here |
|---|
| 160 | "invoice" => "", // |
|---|
| 161 | |
|---|
| 162 | //<!-- Customer Information --> |
|---|
| 163 | "address_override" => 1, |
|---|
| 164 | "first_name" => $member->FirstName, |
|---|
| 165 | "last_name" => $member->Surname, |
|---|
| 166 | "address1" => $member->Address, |
|---|
| 167 | "address2" => $member->AddressLine2, |
|---|
| 168 | "city" => $member->City, |
|---|
| 169 | "country" => $member->Country, |
|---|
| 170 | "state" => $member->State, |
|---|
| 171 | "zip" => $member->Postcode, |
|---|
| 172 | //it is hard to change the SS phone number (basically one number / string) to the PayPal one (broken down into parts) |
|---|
| 173 | "night_phone_a" => "", // country code or area code |
|---|
| 174 | "night_phone_b" => "", //phone without country code or next three digits |
|---|
| 175 | "night_phone_c" => "", // last four digits |
|---|
| 176 | ); |
|---|
| 177 | |
|---|
| 178 | foreach($info as $k => $v) { |
|---|
| 179 | $fields .= "<input type=\"hidden\" name=\"" . Convert::raw2att($k) . "\" value=\"" . Convert::raw2att($v) . "\" />\n"; |
|---|
| 180 | } |
|---|
| 181 | return <<<HTML |
|---|
| 182 | <form id="PaymentForm" method="post" action="$URL"> |
|---|
| 183 | <p> |
|---|
| 184 | $fields |
|---|
| 185 | </p> |
|---|
| 186 | <p class="Actions" id="Submit"> |
|---|
| 187 | <input type="submit" value="Start Payment Process" /> |
|---|
| 188 | </p> |
|---|
| 189 | </form> |
|---|
| 190 | HTML; |
|---|
| 191 | } |
|---|
| 192 | } |
|---|
| 193 | |
|---|
| 194 | /** |
|---|
| 195 | * Handler for responses from the PayPal site |
|---|
| 196 | */ |
|---|
| 197 | class PayPalPayment_Handler extends Controller { |
|---|
| 198 | |
|---|
| 199 | function init() { |
|---|
| 200 | parent::init(); |
|---|
| 201 | ManifestBuilder::compileManifest(); |
|---|
| 202 | $this->paid(); |
|---|
| 203 | } |
|---|
| 204 | function paid(){ |
|---|
| 205 | $order = DataObject::get_by_id("Order", $_REQUEST["item_number"]); |
|---|
| 206 | if($_REQUEST['payment_status']=='Completed' && $order->Status == "Unpaid"){ |
|---|
| 207 | $payment = Object::create("Payment"); |
|---|
| 208 | $payment->Amount = $_REQUEST["payment_gross"]; |
|---|
| 209 | $payment->OrderID = $_REQUEST["item_number"]; |
|---|
| 210 | $payment->Status = 'Success'; |
|---|
| 211 | $payment->Currency = $_REQUEST["mc_currency"]; |
|---|
| 212 | $payment->TxnRef = 'PayPal technical details: '. |
|---|
| 213 | $_REQUEST["txn_id"]." | ".$_REQUEST["verify_sign"]." | ".$_REQUEST["payer_id"]." | ". |
|---|
| 214 | $_REQUEST["receiver_id"]." | ".$_REQUEST["payer_email"]." | ".$_REQUEST["mc_gross"]." | ". |
|---|
| 215 | $_REQUEST["item_number"]; |
|---|
| 216 | $paymentID = $payment->write(); |
|---|
| 217 | Session::set('Order.OrderID', $order->ID); |
|---|
| 218 | Session::set('Order.PurchaseComplete',true); |
|---|
| 219 | $order->Status = 'paid'; |
|---|
| 220 | $order->sendReceipt(); |
|---|
| 221 | $order->isComplete(); |
|---|
| 222 | $order->write(); |
|---|
| 223 | Director::redirect(CheckoutPage::find_link() . "OrderSuccessful/$order->ID"); |
|---|
| 224 | } |
|---|
| 225 | elseif($_REQUEST['payment_status']=='Completed' && $order->Status == "Paid") { |
|---|
| 226 | Director::redirect(CheckoutPage::find_link() . "OrderSuccessful/$order->ID"); |
|---|
| 227 | } |
|---|
| 228 | elseif($_REQUEST['payment_status']=='Pending'){ |
|---|
| 229 | /* CHECK THIS */ |
|---|
| 230 | Director::redirect(CheckoutPage::find_link() . "ConfirmPayPal/$order->ID"); |
|---|
| 231 | } |
|---|
| 232 | else{ |
|---|
| 233 | Director::redirect(CheckoutPage::find_link() . "ConfirmPayPal/$order->ID"); |
|---|
| 234 | } |
|---|
| 235 | } |
|---|
| 236 | |
|---|
| 237 | function PayPalInstructions() { |
|---|
| 238 | return DataObject::get_one('CheckoutPage')->PayPalInstructions; |
|---|
| 239 | } |
|---|
| 240 | } |
|---|
| 241 | |
|---|
| 242 | |
|---|
| 243 | |
|---|
| 244 | /* what comes back from Paypal as get variables (see https://www.paypal.com/IntegrationCenter/ic_ipn-pdt-variable-reference.html) |
|---|
| 245 | txn_type=web_accept |
|---|
| 246 | payment_date=19%3A09%3A25+Apr+15%2C+2008+PDT |
|---|
| 247 | last_name=Tester |
|---|
| 248 | residence_country=US |
|---|
| 249 | item_name=templates |
|---|
| 250 | payment_gross=70.00 |
|---|
| 251 | mc_currency=USD |
|---|
| 252 | business=abc%40def.ghi (email of business owner) |
|---|
| 253 | payment_type=instant |
|---|
| 254 | payer_status=verified |
|---|
| 255 | verify_sign=AFhW6IfTc.P96fDJUr48Gahf6BlHAhxUUkTH59p-rGnYUe2n5es5ZeLn |
|---|
| 256 | test_ipn=1 |
|---|
| 257 | payer_email=testpayer%40abc.def.ghi (person paying) |
|---|
| 258 | tax=0.00 |
|---|
| 259 | txn_id=40863971JS8149811 |
|---|
| 260 | first_name=Chester |
|---|
| 261 | receiver_email=aaa%40bbb.com |
|---|
| 262 | quantity=1 |
|---|
| 263 | payer_id=QW5PPSM3TFGPA |
|---|
| 264 | receiver_id=LZZDEWP3XWLUG |
|---|
| 265 | item_number=39 |
|---|
| 266 | payment_status=Completed |
|---|
| 267 | mc_fee=3.03 |
|---|
| 268 | payment_fee=3.03 |
|---|
| 269 | shipping=0.00 |
|---|
| 270 | mc_gross=70.00 |
|---|
| 271 | custom=39 |
|---|
| 272 | */ |
|---|