1 | <?php |
||
10 | class PurchaseRequest extends AbstractRequest |
||
11 | { |
||
12 | /** @var string */ |
||
13 | protected $liveEndpoint = 'https://secureacceptance.cybersource.com/pay'; |
||
14 | /** @var string */ |
||
15 | protected $testEndpoint = 'https://testsecureacceptance.cybersource.com/pay'; |
||
16 | /** @var string Override this if using inherited class for additional transaction types */ |
||
17 | protected $transactionType = 'sale'; |
||
18 | |||
19 | /** |
||
20 | * Get the profile ID for the merchant account |
||
21 | * |
||
22 | * @return string |
||
23 | */ |
||
24 | 4 | public function getProfileId() |
|
28 | |||
29 | /** |
||
30 | * Set the profile ID for the merchant account |
||
31 | * |
||
32 | * @param string $value ASCII Alphanumeric + punctuation string, maximum 36 characters |
||
33 | * |
||
34 | * @return AbstractRequest |
||
35 | */ |
||
36 | 14 | public function setProfileId($value) |
|
40 | |||
41 | /** |
||
42 | * Get the secret key for the merchant account |
||
43 | * |
||
44 | * @return string |
||
45 | */ |
||
46 | 8 | public function getSecretKey() |
|
50 | |||
51 | /** |
||
52 | * Set the secret key for the merchant account |
||
53 | * |
||
54 | * @param string $value Alphanumeric string, maximum 32 characters |
||
55 | * |
||
56 | * @return AbstractRequest |
||
57 | */ |
||
58 | 14 | public function setSecretKey($value) |
|
62 | |||
63 | /** |
||
64 | * Get the access key for the merchant account |
||
65 | * |
||
66 | * @return string |
||
67 | */ |
||
68 | 4 | public function getAccessKey() |
|
72 | |||
73 | /** |
||
74 | * Set the access key for the merchant account |
||
75 | * |
||
76 | * @param string $value Alphanumeric string, maximum 32 characters |
||
77 | * |
||
78 | * @return AbstractRequest |
||
79 | */ |
||
80 | 14 | public function setAccessKey($value) |
|
84 | |||
85 | /** |
||
86 | * Optional merchant sale reference number, falls back to using the transaction ID if not set |
||
87 | * |
||
88 | * @return string |
||
89 | */ |
||
90 | 3 | public function getReferenceNumber() |
|
95 | |||
96 | /** |
||
97 | * Set the unique merchant-generated order reference or tracking number for each transaction. |
||
98 | * |
||
99 | * @param string $value Reference to use |
||
100 | */ |
||
101 | 1 | public function setReferenceNumber($value) |
|
105 | |||
106 | /** |
||
107 | * Get the locale set for this request, falls back to using 'en' if not set |
||
108 | * |
||
109 | * @return string |
||
110 | */ |
||
111 | 3 | public function getLocale() |
|
116 | |||
117 | /** |
||
118 | * Set the locale for this request |
||
119 | * |
||
120 | * @param string $value ISO formatted string indicating language and country e.g. en-nz |
||
121 | */ |
||
122 | 1 | public function setLocale($value) |
|
126 | |||
127 | /** |
||
128 | * Get the transaction type |
||
129 | * |
||
130 | * Can be one of: |
||
131 | * - authorization |
||
132 | * - authorization,create_payment_token |
||
133 | * - authorization,update_payment_token |
||
134 | * - sale |
||
135 | * - sale,create_payment_token |
||
136 | * - sale,update_payment_token |
||
137 | * - create_payment_token |
||
138 | * - update_payment_token |
||
139 | * |
||
140 | * @return string |
||
141 | */ |
||
142 | 2 | public function getTransactionType() |
|
146 | |||
147 | 2 | public function getData() |
|
148 | { |
||
149 | 2 | $this->validate( |
|
150 | 2 | 'profileId', |
|
151 | 2 | 'accessKey', |
|
152 | // the secret key is not supplied in the data, but is required for generating the signature |
||
153 | 2 | 'secretKey', |
|
154 | 2 | 'amount', |
|
155 | 2 | 'currency' |
|
156 | ); |
||
157 | |||
158 | // mandatory fields |
||
159 | $data = array( |
||
160 | 2 | 'access_key' => $this->getAccessKey(), |
|
161 | 2 | 'amount' => $this->getAmount(), |
|
162 | // uses ISO-4217 codes |
||
163 | 2 | 'currency' => $this->getCurrency(), |
|
164 | 2 | 'locale' => $this->getLocale(), |
|
165 | 2 | 'profile_id' => $this->getProfileId(), |
|
166 | // no duplicate checking on this (falls back to transaction ID if not set) |
||
167 | 2 | 'reference_number' => $this->getReferenceNumber(), |
|
168 | // ISO 8601 date in UTC |
||
169 | 2 | 'signed_date_time' => gmdate("Y-m-d\TH:i:s\Z"), |
|
170 | 2 | 'transaction_type' => $this->getTransactionType(), |
|
171 | // merchant-generated transaction number used for duplicate checking |
||
172 | 2 | 'transaction_uuid' => $this->getTransactionId(), |
|
173 | ); |
||
174 | |||
175 | // optional fields |
||
176 | $optional_data = array( |
||
177 | 2 | 'customer_ip_address' => $this->getClientIp(), |
|
178 | // merchant defined data 1-4 are stored with tokens, so transaction-specific data from 5 onwards |
||
179 | 2 | 'merchant_defined_data5' => $this->getDescription(), |
|
180 | 2 | 'override_backoffice_post_url' => $this->getNotifyUrl(), |
|
181 | 2 | 'override_custom_cancel_page' => $this->getCancelUrl(), |
|
182 | // signing this field is actually required if present, despite what the integration docs say |
||
183 | 2 | 'override_custom_receipt_page' => $this->getReturnUrl(), |
|
184 | ); |
||
185 | |||
186 | // billing details |
||
187 | 2 | $card = $this->getCard(); |
|
188 | 2 | if ($card) { |
|
189 | $optional_data += array( |
||
190 | 1 | 'bill_to_forename' => $card->getFirstName(), |
|
191 | 1 | 'bill_to_surname' => $card->getLastName(), |
|
192 | 1 | 'bill_to_address_line1' => $card->getAddress1(), |
|
193 | 1 | 'bill_to_address_line2' => $card->getAddress2(), |
|
194 | 1 | 'bill_to_address_city' => $card->getCity(), |
|
195 | //alphanumeric,2 [ISO state code; req for US/CA] |
||
196 | // @todo should this kind of reformatting (or error) happen in driver, or at merchant end? |
||
197 | 1 | 'bill_to_address_state' => $card->getState(), |
|
198 | // alphanumeric,10 [strict format check for US/CA addresses] |
||
199 | // @todo should this kind of reformatting (or error) happen in driver, or at merchant end? |
||
200 | 1 | 'bill_to_address_postal_code' => $card->getPostcode(), |
|
201 | 1 | 'bill_to_address_country' => $card->getCountry(), |
|
202 | 1 | 'bill_to_email' => $card->getEmail(), |
|
203 | 1 | 'bill_to_phone' => $card->getPhone(), |
|
204 | ); |
||
205 | } |
||
206 | |||
207 | // item details |
||
208 | 2 | $items = $this->getItems(); |
|
209 | 2 | if ($items) { |
|
210 | // having any item details forces line_item_count to be required |
||
211 | $optional_data += array( |
||
212 | 1 | 'line_item_count' => count($items), |
|
213 | ); |
||
214 | 1 | foreach ($items as $n => $item) { |
|
215 | $optional_data += array( |
||
216 | 1 | "item_{$n}_name" => $item->getName(), |
|
217 | 1 | "item_{$n}_quantity" => $item->getQuantity(), |
|
218 | 1 | "item_{$n}_unit_price" => $this->formatCurrency($item->getPrice()), |
|
219 | ); |
||
220 | // @todo if we want to add additional fields, need to create CyberSourceItem and CyberSourceItemBag |
||
221 | // if ($item instanceof CyberSourceItem) { |
||
|
|||
222 | // "item_{$n}_code" => $item->getCode(), |
||
223 | // "item_{$n}_sku" => $item->getSku(), |
||
224 | // "item_{$n}_tax_amount" => $this->formatCurrency($item->getTax()), |
||
225 | // } |
||
226 | } |
||
227 | } |
||
228 | |||
229 | // omit any optional parameters that aren't set |
||
230 | 2 | $optional_data = array_filter($optional_data); |
|
231 | // merge data |
||
232 | 2 | $data += $optional_data; |
|
233 | |||
234 | // rather than working out peculiar loopholes in the integration documentation, just sign everything |
||
235 | 2 | $data['unsigned_field_names'] = ''; |
|
236 | 2 | $data['signed_field_names'] = implode(',', array_keys($data)).',signed_field_names'; |
|
237 | |||
238 | 2 | return $data; |
|
239 | } |
||
240 | |||
241 | 1 | public function sendData($data) |
|
242 | { |
||
243 | 1 | $security = new Security(); |
|
244 | 1 | $data['signature'] = $security->createSignature( |
|
245 | 1 | $data, |
|
246 | 1 | explode(',', $data['signed_field_names']), |
|
247 | 1 | $this->getSecretKey() |
|
248 | ); |
||
249 | 1 | return $this->response = new PurchaseResponse($this, $data); |
|
250 | } |
||
251 | |||
252 | 2 | public function getEndpoint() |
|
256 | } |
||
257 |
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.
The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.
This check looks for comments that seem to be mostly valid code and reports them.