These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | /** |
||
3 | * Class WC_Gateway_COD file. |
||
4 | * |
||
5 | * @package WooCommerce\Gateways |
||
6 | */ |
||
7 | |||
8 | 1 | if ( ! defined( 'ABSPATH' ) ) { |
|
9 | exit; // Exit if accessed directly. |
||
10 | } |
||
11 | |||
12 | /** |
||
13 | * Cash on Delivery Gateway. |
||
14 | * |
||
15 | * Provides a Cash on Delivery Payment Gateway. |
||
16 | * |
||
17 | * @class WC_Gateway_COD |
||
18 | * @extends WC_Payment_Gateway |
||
19 | * @version 2.1.0 |
||
20 | * @package WooCommerce/Classes/Payment |
||
21 | */ |
||
22 | class WC_Gateway_COD extends WC_Payment_Gateway { |
||
23 | |||
24 | /** |
||
25 | * Constructor for the gateway. |
||
26 | */ |
||
27 | 427 | public function __construct() { |
|
28 | // Setup general properties. |
||
29 | 427 | $this->setup_properties(); |
|
30 | |||
31 | // Load the settings. |
||
32 | 427 | $this->init_form_fields(); |
|
33 | 427 | $this->init_settings(); |
|
34 | |||
35 | // Get settings. |
||
36 | 427 | $this->title = $this->get_option( 'title' ); |
|
37 | 427 | $this->description = $this->get_option( 'description' ); |
|
38 | 427 | $this->instructions = $this->get_option( 'instructions' ); |
|
39 | 427 | $this->enable_for_methods = $this->get_option( 'enable_for_methods', array() ); |
|
40 | 427 | $this->enable_for_virtual = $this->get_option( 'enable_for_virtual', 'yes' ) === 'yes'; |
|
41 | |||
42 | 427 | add_action( 'woocommerce_update_options_payment_gateways_' . $this->id, array( $this, 'process_admin_options' ) ); |
|
43 | 427 | add_action( 'woocommerce_thankyou_' . $this->id, array( $this, 'thankyou_page' ) ); |
|
44 | 427 | add_filter( 'woocommerce_payment_complete_order_status', array( $this, 'change_payment_complete_order_status' ), 10, 3 ); |
|
45 | |||
46 | // Customer Emails. |
||
47 | 427 | add_action( 'woocommerce_email_before_order_table', array( $this, 'email_instructions' ), 10, 3 ); |
|
48 | } |
||
49 | |||
50 | /** |
||
51 | * Setup general properties for the gateway. |
||
52 | */ |
||
53 | 427 | protected function setup_properties() { |
|
54 | 427 | $this->id = 'cod'; |
|
55 | 427 | $this->icon = apply_filters( 'woocommerce_cod_icon', '' ); |
|
56 | 427 | $this->method_title = __( 'Cash on delivery', 'woocommerce' ); |
|
57 | 427 | $this->method_description = __( 'Have your customers pay with cash (or by other means) upon delivery.', 'woocommerce' ); |
|
58 | 427 | $this->has_fields = false; |
|
59 | } |
||
60 | |||
61 | /** |
||
62 | * Initialise Gateway Settings Form Fields. |
||
63 | */ |
||
64 | 427 | public function init_form_fields() { |
|
65 | |||
66 | 427 | $options = array(); |
|
67 | 427 | $data_store = WC_Data_Store::load( 'shipping-zone' ); |
|
68 | 427 | $raw_zones = $data_store->get_zones(); |
|
69 | |||
70 | 427 | foreach ( $raw_zones as $raw_zone ) { |
|
71 | $zones[] = new WC_Shipping_Zone( $raw_zone ); |
||
72 | } |
||
73 | |||
74 | 427 | $zones[] = new WC_Shipping_Zone( 0 ); |
|
75 | |||
76 | 427 | foreach ( WC()->shipping()->load_shipping_methods() as $method ) { |
|
77 | |||
78 | 427 | $options[ $method->get_method_title() ] = array(); |
|
79 | |||
80 | // Translators: %1$s shipping method name. |
||
81 | 427 | $options[ $method->get_method_title() ][ $method->id ] = sprintf( __( 'Any "%1$s" method', 'woocommerce' ), $method->get_method_title() ); |
|
82 | |||
83 | 427 | foreach ( $zones as $zone ) { |
|
84 | |||
85 | 427 | $shipping_method_instances = $zone->get_shipping_methods(); |
|
86 | |||
87 | 427 | foreach ( $shipping_method_instances as $shipping_method_instance_id => $shipping_method_instance ) { |
|
88 | |||
89 | if ( $shipping_method_instance->id !== $method->id ) { |
||
90 | continue; |
||
91 | } |
||
92 | |||
93 | $option_id = $shipping_method_instance->get_rate_id(); |
||
94 | |||
95 | // Translators: %1$s shipping method title, %2$s shipping method id. |
||
96 | $option_instance_title = sprintf( __( '%1$s (#%2$s)', 'woocommerce' ), $shipping_method_instance->get_title(), $shipping_method_instance_id ); |
||
97 | |||
98 | // Translators: %1$s zone name, %2$s shipping method instance name. |
||
99 | $option_title = sprintf( __( '%1$s – %2$s', 'woocommerce' ), $zone->get_id() ? $zone->get_zone_name() : __( 'Other locations', 'woocommerce' ), $option_instance_title ); |
||
100 | |||
101 | $options[ $method->get_method_title() ][ $option_id ] = $option_title; |
||
102 | } |
||
103 | } |
||
104 | } |
||
105 | |||
106 | 427 | $this->form_fields = array( |
|
107 | 'enabled' => array( |
||
108 | 427 | 'title' => __( 'Enable/Disable', 'woocommerce' ), |
|
109 | 427 | 'label' => __( 'Enable cash on delivery', 'woocommerce' ), |
|
110 | 427 | 'type' => 'checkbox', |
|
111 | 427 | 'description' => '', |
|
112 | 427 | 'default' => 'no', |
|
113 | ), |
||
114 | 'title' => array( |
||
115 | 427 | 'title' => __( 'Title', 'woocommerce' ), |
|
116 | 427 | 'type' => 'text', |
|
117 | 427 | 'description' => __( 'Payment method description that the customer will see on your checkout.', 'woocommerce' ), |
|
118 | 427 | 'default' => __( 'Cash on delivery', 'woocommerce' ), |
|
119 | 'desc_tip' => true, |
||
120 | ), |
||
121 | 'description' => array( |
||
122 | 427 | 'title' => __( 'Description', 'woocommerce' ), |
|
123 | 427 | 'type' => 'textarea', |
|
124 | 427 | 'description' => __( 'Payment method description that the customer will see on your website.', 'woocommerce' ), |
|
125 | 427 | 'default' => __( 'Pay with cash upon delivery.', 'woocommerce' ), |
|
126 | 'desc_tip' => true, |
||
127 | ), |
||
128 | 'instructions' => array( |
||
129 | 427 | 'title' => __( 'Instructions', 'woocommerce' ), |
|
130 | 427 | 'type' => 'textarea', |
|
131 | 427 | 'description' => __( 'Instructions that will be added to the thank you page.', 'woocommerce' ), |
|
132 | 427 | 'default' => __( 'Pay with cash upon delivery.', 'woocommerce' ), |
|
133 | 'desc_tip' => true, |
||
134 | ), |
||
135 | 'enable_for_methods' => array( |
||
136 | 427 | 'title' => __( 'Enable for shipping methods', 'woocommerce' ), |
|
137 | 427 | 'type' => 'multiselect', |
|
138 | 427 | 'class' => 'wc-enhanced-select', |
|
139 | 427 | 'css' => 'width: 400px;', |
|
140 | 427 | 'default' => '', |
|
141 | 427 | 'description' => __( 'If COD is only available for certain methods, set it up here. Leave blank to enable for all methods.', 'woocommerce' ), |
|
142 | 427 | 'options' => $options, |
|
143 | 'desc_tip' => true, |
||
144 | 'custom_attributes' => array( |
||
145 | 427 | 'data-placeholder' => __( 'Select shipping methods', 'woocommerce' ), |
|
146 | ), |
||
147 | ), |
||
148 | 'enable_for_virtual' => array( |
||
149 | 427 | 'title' => __( 'Accept for virtual orders', 'woocommerce' ), |
|
150 | 427 | 'label' => __( 'Accept COD if the order is virtual', 'woocommerce' ), |
|
151 | 427 | 'type' => 'checkbox', |
|
152 | 427 | 'default' => 'yes', |
|
153 | ), |
||
154 | ); |
||
155 | } |
||
156 | |||
157 | /** |
||
158 | * Check If The Gateway Is Available For Use. |
||
159 | * |
||
160 | * @return bool |
||
161 | */ |
||
162 | 1 | public function is_available() { |
|
163 | 1 | $order = null; |
|
164 | 1 | $needs_shipping = false; |
|
165 | |||
166 | // Test if shipping is needed first. |
||
167 | 1 | if ( WC()->cart && WC()->cart->needs_shipping() ) { |
|
168 | $needs_shipping = true; |
||
169 | 1 | } elseif ( is_page( wc_get_page_id( 'checkout' ) ) && 0 < get_query_var( 'order-pay' ) ) { |
|
170 | $order_id = absint( get_query_var( 'order-pay' ) ); |
||
171 | $order = wc_get_order( $order_id ); |
||
172 | |||
173 | // Test if order needs shipping. |
||
174 | if ( 0 < count( $order->get_items() ) ) { |
||
175 | foreach ( $order->get_items() as $item ) { |
||
176 | $_product = $item->get_product(); |
||
177 | if ( $_product && $_product->needs_shipping() ) { |
||
178 | $needs_shipping = true; |
||
179 | break; |
||
180 | } |
||
181 | } |
||
182 | } |
||
183 | } |
||
184 | |||
185 | 1 | $needs_shipping = apply_filters( 'woocommerce_cart_needs_shipping', $needs_shipping ); |
|
186 | |||
187 | // Virtual order, with virtual disabled. |
||
188 | 1 | if ( ! $this->enable_for_virtual && ! $needs_shipping ) { |
|
189 | return false; |
||
190 | } |
||
191 | |||
192 | // Only apply if all packages are being shipped via chosen method, or order is virtual. |
||
193 | 1 | if ( ! empty( $this->enable_for_methods ) && $needs_shipping ) { |
|
194 | $order_shipping_items = is_object( $order ) ? $order->get_shipping_methods() : false; |
||
195 | $chosen_shipping_methods_session = WC()->session->get( 'chosen_shipping_methods' ); |
||
196 | |||
197 | if ( $order_shipping_items ) { |
||
198 | $canonical_rate_ids = $this->get_canonical_order_shipping_item_rate_ids( $order_shipping_items ); |
||
199 | } else { |
||
200 | $canonical_rate_ids = $this->get_canonical_package_rate_ids( $chosen_shipping_methods_session ); |
||
201 | } |
||
202 | |||
203 | if ( ! count( $this->get_matching_rates( $canonical_rate_ids ) ) ) { |
||
204 | return false; |
||
205 | } |
||
206 | } |
||
207 | |||
208 | 1 | return parent::is_available(); |
|
209 | } |
||
210 | |||
211 | /** |
||
212 | * Converts the chosen rate IDs generated by Shipping Methods to a canonical 'method_id:instance_id' format. |
||
213 | * |
||
214 | * @since 3.4.0 |
||
215 | * |
||
216 | * @param array $order_shipping_items Array of WC_Order_Item_Shipping objects. |
||
217 | * @return array $canonical_rate_ids Rate IDs in a canonical format. |
||
218 | */ |
||
219 | private function get_canonical_order_shipping_item_rate_ids( $order_shipping_items ) { |
||
220 | |||
221 | $canonical_rate_ids = array(); |
||
222 | |||
223 | foreach ( $order_shipping_items as $order_shipping_item ) { |
||
224 | $canonical_rate_ids[] = $order_shipping_item->get_method_id() . ':' . $order_shipping_item->get_instance_id(); |
||
225 | } |
||
226 | |||
227 | return $canonical_rate_ids; |
||
228 | } |
||
229 | |||
230 | /** |
||
231 | * Converts the chosen rate IDs generated by Shipping Methods to a canonical 'method_id:instance_id' format. |
||
232 | * |
||
233 | * @since 3.4.0 |
||
234 | * |
||
235 | * @param array $chosen_package_rate_ids Rate IDs as generated by shipping methods. Can be anything if a shipping method doesn't honor WC conventions. |
||
236 | * @return array $canonical_rate_ids Rate IDs in a canonical format. |
||
237 | */ |
||
238 | private function get_canonical_package_rate_ids( $chosen_package_rate_ids ) { |
||
239 | |||
240 | $shipping_packages = WC()->shipping()->get_packages(); |
||
241 | $canonical_rate_ids = array(); |
||
242 | |||
243 | if ( ! empty( $chosen_package_rate_ids ) && is_array( $chosen_package_rate_ids ) ) { |
||
244 | foreach ( $chosen_package_rate_ids as $package_key => $chosen_package_rate_id ) { |
||
245 | if ( ! empty( $shipping_packages[ $package_key ]['rates'][ $chosen_package_rate_id ] ) ) { |
||
246 | $chosen_rate = $shipping_packages[ $package_key ]['rates'][ $chosen_package_rate_id ]; |
||
247 | $canonical_rate_ids[] = $chosen_rate->get_method_id() . ':' . $chosen_rate->get_instance_id(); |
||
248 | } |
||
249 | } |
||
250 | } |
||
251 | |||
252 | return $canonical_rate_ids; |
||
253 | } |
||
254 | |||
255 | /** |
||
256 | * Indicates whether a rate exists in an array of canonically-formatted rate IDs that activates this gateway. |
||
257 | * |
||
258 | * @since 3.4.0 |
||
259 | * |
||
260 | * @param array $rate_ids Rate ids to check. |
||
261 | * @return boolean |
||
262 | */ |
||
263 | private function get_matching_rates( $rate_ids ) { |
||
264 | // First, match entries in 'method_id:instance_id' format. Then, match entries in 'method_id' format by stripping off the instance ID from the candidates. |
||
265 | return array_unique( array_merge( array_intersect( $this->enable_for_methods, $rate_ids ), array_intersect( $this->enable_for_methods, array_unique( array_map( 'wc_get_string_before_colon', $rate_ids ) ) ) ) ); |
||
266 | } |
||
267 | |||
268 | /** |
||
269 | * Process the payment and return the result. |
||
270 | * |
||
271 | * @param int $order_id Order ID. |
||
272 | * @return array |
||
273 | */ |
||
274 | View Code Duplication | public function process_payment( $order_id ) { |
|
275 | $order = wc_get_order( $order_id ); |
||
276 | |||
277 | if ( $order->get_total() > 0 ) { |
||
278 | // Mark as processing or on-hold (payment won't be taken until delivery). |
||
279 | $order->update_status( apply_filters( 'woocommerce_cod_process_payment_order_status', $order->has_downloadable_item() ? 'on-hold' : 'processing', $order ), __( 'Payment to be made upon delivery.', 'woocommerce' ) ); |
||
280 | } else { |
||
281 | $order->payment_complete(); |
||
282 | } |
||
283 | |||
284 | // Remove cart. |
||
285 | WC()->cart->empty_cart(); |
||
286 | |||
287 | // Return thankyou redirect. |
||
288 | return array( |
||
289 | 'result' => 'success', |
||
290 | 'redirect' => $this->get_return_url( $order ), |
||
291 | ); |
||
292 | } |
||
293 | |||
294 | /** |
||
295 | * Output for the order received page. |
||
296 | */ |
||
297 | public function thankyou_page() { |
||
298 | if ( $this->instructions ) { |
||
299 | echo wp_kses_post( wpautop( wptexturize( $this->instructions ) ) ); |
||
300 | } |
||
301 | } |
||
302 | |||
303 | /** |
||
304 | * Change payment complete order status to completed for COD orders. |
||
305 | * |
||
306 | * @since 3.1.0 |
||
307 | * @param string $status Current order status. |
||
308 | * @param int $order_id Order ID. |
||
309 | * @param WC_Order|false $order Order object. |
||
310 | * @return string |
||
311 | */ |
||
312 | 4 | public function change_payment_complete_order_status( $status, $order_id = 0, $order = false ) { |
|
313 | 4 | if ( $order && 'cod' === $order->get_payment_method() ) { |
|
314 | $status = 'completed'; |
||
315 | } |
||
316 | 4 | return $status; |
|
317 | } |
||
318 | |||
319 | /** |
||
320 | * Add content to the WC emails. |
||
321 | * |
||
322 | * @access public |
||
323 | * @param WC_Order $order Order object. |
||
324 | * @param bool $sent_to_admin Sent to admin. |
||
325 | * @param bool $plain_text Email format: plain text or HTML. |
||
326 | */ |
||
327 | public function email_instructions( $order, $sent_to_admin, $plain_text = false ) { |
||
0 ignored issues
–
show
|
|||
328 | View Code Duplication | if ( $this->instructions && ! $sent_to_admin && $this->id === $order->get_payment_method() ) { |
|
329 | echo wp_kses_post( wpautop( wptexturize( $this->instructions ) ) . PHP_EOL ); |
||
330 | } |
||
331 | } |
||
332 | } |
||
333 |
This check looks from parameters that have been defined for a function or method, but which are not used in the method body.