WordPress как на ладони
Очень Удобный и Быстрый Хостинг для сайтов на WordPress. Пользуюсь сам и вам рекомендую!

Дубликат метода оплаты Cash on delivery (COD)

Создал плагин с копией метода оплаты COD, но в выполненных ордерах приходит как товар оплаченный онлайн. Как сделать ордер без оплаты (точно как COD). Мне надо сделать оплата картой при доставке товара, что бы курьер мог взять с собой терминал для оплаты картой.

Вот таким макаром создал копию метода оплаты. https://stackoverflow.com/questions/63787049/extending-woocommerce-cod-payment-gateway-in-a-plugin

Здесь cкопировал код COD и сделал COD2 https://github.com/woocommerce/woocommerce/blob/4.4.1/includes/gateways/cod/class-wc-gateway-cod.php

Плагины для создания дополнительных методов оплаты пробовал, так же выводят что продукт был оплачен онлайн.

Разницав в заказах

Вот мой код.

<?php
/*
Plugin Name: Woo card payment on delivery
Plugin URI: https://woocommerce.com/
Description: Your shipping method plugin
Version: 1.0.0
Author: Aleksei
Author URI: https://woocommerce.com/
*/

defined( 'ABSPATH' ) or exit;
// Make sure WooCommerce is active
if ( ! in_array( 'woocommerce/woocommerce.php', apply_filters( 'active_plugins', get_option( 'active_plugins' ) ) ) ) {
	return;
}

add_filter( 'woocommerce_payment_gateways', 'wc_custom_add_to_gateways' );
function wc_custom_add_to_gateways( $gateways ) {
	$gateways[] = 'WC_Gateway_COD2';
	return $gateways;
}

add_filter( 'plugin_action_links_' . plugin_basename( __FILE__ ), 'wc_gateway_custom_plugin_links' );
function wc_gateway_custom_plugin_links( $links ) {
	$plugin_links = array(
		'<a href="' . admin_url( 'admin.php?page=wc-settings&tab=checkout&section=cod2' ) . '">' . __( 'Configure', 'payment_cod2' ) . '</a>'
	);
	return array_merge( $plugin_links, $links );
}

add_action( 'plugins_loaded', 'wc_gateway_cod2_init', 11 );
function wc_gateway_cod2_init() {
	class WC_Gateway_COD2 extends WC_Payment_Gateway {

		public $domain; // The text domain (optional)

		/**
		 * Constructor for the gateway.
		 */
		public function __construct() {
			$this->domain = 'payment_cod2'; // text domain name (for translations)

			// Setup general properties.
			$this->setup_properties();

			// Load the settings.
			$this->init_form_fields();
			$this->init_settings();

			// Get settings.
			$this->title              = $this->get_option( 'title' );
			$this->description        = $this->get_option( 'description' );
			$this->instructions       = $this->get_option( 'instructions' );
			$this->enable_for_methods = $this->get_option( 'enable_for_methods', array() );
			$this->enable_for_virtual = $this->get_option( 'enable_for_virtual', 'yes' ) === 'yes';

			add_action( 'woocommerce_update_options_payment_gateways_' . $this->id, array( $this, 'process_admin_options' ) );
			add_action( 'woocommerce_thankyou_' . $this->id, array( $this, 'thankyou_page' ) );
			add_filter( 'woocommerce_payment_complete_order_status', array( $this, 'change_payment_complete_order_status' ), 10, 3 );

			// Customer Emails.
			add_action( 'woocommerce_email_before_order_table', array( $this, 'email_instructions' ), 10, 3 );
		}

		/**
		 * Setup general properties for the gateway.
		 */
		protected function setup_properties() {
			$this->id                 = 'cod2';
			$this->icon               = apply_filters( 'woocommerce_cod2_icon', '' );
			$this->method_title       = __( 'Card Payment on Delivery', 'woocommerce' );
			$this->method_description = __( 'Have your customers pay with card upon delivery.', 'woocommerce' );
			$this->has_fields         = false;
		}

		/**
	 * Initialise Gateway Settings Form Fields.
	 */
	public function init_form_fields() {
		$this->form_fields = array(
			'enabled'            => array(
				'title'       => __( 'Enable/Disable', 'woocommerce' ),
				'label'       => __( 'Enable Card Payment on Delivery', 'woocommerce' ),
				'type'        => 'checkbox',
				'description' => '',
				'default'     => 'no',
			),
			'title'              => array(
				'title'       => __( 'Title', 'woocommerce' ),
				'type'        => 'text',
				'description' => __( 'Payment method description that the customer will see on your checkout.', 'woocommerce' ),
				'default'     => __( 'Card Payment on Delivery', 'woocommerce' ),
				'desc_tip'    => true,
			),
			'description'        => array(
				'title'       => __( 'Description', 'woocommerce' ),
				'type'        => 'textarea',
				'description' => __( 'Payment method description that the customer will see on your website.', 'woocommerce' ),
				'default'     => __( 'Pay with card upon delivery.', 'woocommerce' ),
				'desc_tip'    => true,
			),
			'instructions'       => array(
				'title'       => __( 'Instructions', 'woocommerce' ),
				'type'        => 'textarea',
				'description' => __( 'Instructions that will be added to the thank you page.', 'woocommerce' ),
				'default'     => __( 'Pay with card upon delivery.', 'woocommerce' ),
				'desc_tip'    => true,
			),

		);
	}

		/**
	   * Check If The Gateway Is Available For Use.
		 *
		 * @return bool
		 */
	  public function is_available() {
		 $order          = null;
		 $needs_shipping = false;

		 // Test if shipping is needed first.
		 if ( WC()->cart && WC()->cart->needs_shipping() ) {
			$needs_shipping = true;
		 } elseif ( is_page( wc_get_page_id( 'checkout' ) ) && 0 < get_query_var( 'order-pay' ) ) {
			$order_id = absint( get_query_var( 'order-pay' ) );
			$order    = wc_get_order( $order_id );

			// Test if order needs shipping.
			if ( 0 < count( $order->get_items() ) ) {
			   foreach ( $order->get_items() as $item ) {
				  $_product = $item->get_product();
				  if ( $_product && $_product->needs_shipping() ) {
					 $needs_shipping = true;
					 break;
				  }
			   }
			}
		 }

		 $needs_shipping = apply_filters( 'woocommerce_cart_needs_shipping', $needs_shipping );

		 // Virtual order, with virtual disabled.
		 if ( ! $this->enable_for_virtual && ! $needs_shipping ) {
			return false;
		 }

		 // Only apply if all packages are being shipped via chosen method, or order is virtual.
		 if ( ! empty( $this->enable_for_methods ) && $needs_shipping ) {
			$order_shipping_items            = is_object( $order ) ? $order->get_shipping_methods() : false;
			$chosen_shipping_methods_session = WC()->session->get( 'chosen_shipping_methods' );

			if ( $order_shipping_items ) {
			   $canonical_rate_ids = $this->get_canonical_order_shipping_item_rate_ids( $order_shipping_items );
			} else {
			   $canonical_rate_ids = $this->get_canonical_package_rate_ids( $chosen_shipping_methods_session );
			}

			if ( ! count( $this->get_matching_rates( $canonical_rate_ids ) ) ) {
			   return false;
			}
		 }

		 return parent::is_available();
	  }
	  /**
	   * Checks to see whether or not the admin settings are being accessed by the current request.
		 *
		 * @return bool
		 */
	  private function is_accessing_settings() {
		 if ( is_admin() ) {
			// phpcs:disable WordPress.Security.NonceVerification
			if ( ! isset( $_REQUEST['page'] ) || 'wc-settings' !== $_REQUEST['page'] ) {
			   return false;
			}
			if ( ! isset( $_REQUEST['tab'] ) || 'checkout' !== $_REQUEST['tab'] ) {
			   return false;
			}
			if ( ! isset( $_REQUEST['section'] ) || 'cod' !== $_REQUEST['section'] ) {
			   return false;
			}
			// phpcs:enable WordPress.Security.NonceVerification

			return true;
		 }

		 if ( Constants::is_true( 'REST_REQUEST' ) ) {
			global $wp;
			if ( isset( $wp->query_vars['rest_route'] ) && false !== strpos( $wp->query_vars['rest_route'], '/payment_gateways' ) ) {
			   return true;
			}
		 }

		 return false;
	  }
	  /**
	   * Loads all of the shipping method options for the enable_for_methods field.
		 *
		 * @return array
		 */
	  private function load_shipping_method_options() {
		 // Since this is expensive, we only want to do it if we're actually on the settings page.
		 if ( ! $this->is_accessing_settings() ) {
			return array();
		 }

		 $data_store = WC_Data_Store::load( 'shipping-zone' );
		 $raw_zones  = $data_store->get_zones();

		 foreach ( $raw_zones as $raw_zone ) {
			$zones[] = new WC_Shipping_Zone( $raw_zone );
		 }

		 $zones[] = new WC_Shipping_Zone( 0 );

		 $options = array();
		 foreach ( WC()->shipping()->load_shipping_methods() as $method ) {

			$options[ $method->get_method_title() ] = array();

			// Translators: %1$s shipping method name.
			$options[ $method->get_method_title() ][ $method->id ] = sprintf( __( 'Any "%1$s" method', 'woocommerce' ), $method->get_method_title() );

			foreach ( $zones as $zone ) {

			   $shipping_method_instances = $zone->get_shipping_methods();

			   foreach ( $shipping_method_instances as $shipping_method_instance_id => $shipping_method_instance ) {

				  if ( $shipping_method_instance->id !== $method->id ) {
					 continue;
				  }

				  $option_id = $shipping_method_instance->get_rate_id();

				  // Translators: %1$s shipping method title, %2$s shipping method id.
				  $option_instance_title = sprintf( __( '%1$s (#%2$s)', 'woocommerce' ), $shipping_method_instance->get_title(), $shipping_method_instance_id );

				  // Translators: %1$s zone name, %2$s shipping method instance name.
				  $option_title = sprintf( __( '%1$s – %2$s', 'woocommerce' ), $zone->get_id() ? $zone->get_zone_name() : __( 'Other locations', 'woocommerce' ), $option_instance_title );

				  $options[ $method->get_method_title() ][ $option_id ] = $option_title;
			   }
			}
		 }

		 return $options;
	  }
	  /**
	   * Converts the chosen rate IDs generated by Shipping Methods to a canonical 'method_id:instance_id' format.
		 *
		 * @since  3.4.0
		 *
		 * @param  array $order_shipping_items  Array of WC_Order_Item_Shipping objects.
		 * @return array $canonical_rate_ids    Rate IDs in a canonical format.
		 */
	  private function get_canonical_order_shipping_item_rate_ids( $order_shipping_items ) {

		 $canonical_rate_ids = array();

		 foreach ( $order_shipping_items as $order_shipping_item ) {
			$canonical_rate_ids[] = $order_shipping_item->get_method_id() . ':' . $order_shipping_item->get_instance_id();
		 }

		 return $canonical_rate_ids;
	  }

	  /**
	   * Converts the chosen rate IDs generated by Shipping Methods to a canonical 'method_id:instance_id' format.
		 *
		 * @since  3.4.0
		 *
		 * @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.
		 * @return array $canonical_rate_ids  Rate IDs in a canonical format.
		 */
	  private function get_canonical_package_rate_ids( $chosen_package_rate_ids ) {

		 $shipping_packages  = WC()->shipping()->get_packages();
		 $canonical_rate_ids = array();

		 if ( ! empty( $chosen_package_rate_ids ) && is_array( $chosen_package_rate_ids ) ) {
			foreach ( $chosen_package_rate_ids as $package_key => $chosen_package_rate_id ) {
			   if ( ! empty( $shipping_packages[ $package_key ]['rates'][ $chosen_package_rate_id ] ) ) {
				  $chosen_rate          = $shipping_packages[ $package_key ]['rates'][ $chosen_package_rate_id ];
				  $canonical_rate_ids[] = $chosen_rate->get_method_id() . ':' . $chosen_rate->get_instance_id();
			   }
			}
		 }

		 return $canonical_rate_ids;
	  }
	  /**
	   * Indicates whether a rate exists in an array of canonically-formatted rate IDs that activates this gateway.
		 *
		 * @since  3.4.0
		 *
		 * @param array $rate_ids Rate ids to check.
		 * @return boolean
		 */
	  private function get_matching_rates( $rate_ids ) {
		 // 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.
		 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 ) ) ) ) );
	  }

	  /**
	   * Process the payment and return the result.
		 *
		 * @param int $order_id Order ID.
		 * @return array
		 */
	  public function process_payment( $order_id ) {
		 $order = wc_get_order( $order_id );

		 if ( $order->get_total() > 0 ) {
			// Mark as processing or on-hold (payment won't be taken until delivery).
			$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' ) );
		 } else {
			$order->payment_complete();
		 }

		 // Remove cart.
		 WC()->cart->empty_cart();

		 // Return thankyou redirect.
		 return array(
			'result'   => 'success',
			'redirect' => $this->get_return_url( $order ),
		 );
	  }

	  /**
	   * Output for the order received page.
		 */
	  public function thankyou_page() {
		 if ( $this->instructions ) {
			echo wp_kses_post( wpautop( wptexturize( $this->instructions ) ) );
		 }
	  }

	  /**
	   * Change payment complete order status to completed for COD orders.
		 *
		 * @since  3.1.0
		 * @param  string         $status Current order status.
		 * @param  int            $order_id Order ID.
		 * @param  WC_Order|false $order Order object.
		 * @return string
		 */
	  public function change_payment_complete_order_status( $status, $order_id = 0, $order = false ) {
		 if ( $order && 'cod' === $order->get_payment_method() ) {
			$status = 'completed';
		 }
		 return $status;
	  }

	  /**
	   * Add content to the WC emails.
		 *
		 * @param WC_Order $order Order object.
		 * @param bool     $sent_to_admin  Sent to admin.
		 * @param bool     $plain_text Email format: plain text or HTML.
		 */
	  public function email_instructions( $order, $sent_to_admin, $plain_text = false ) {
		 if ( $this->instructions && ! $sent_to_admin && $this->id === $order->get_payment_method() ) {
			echo wp_kses_post( wpautop( wptexturize( $this->instructions ) ) . PHP_EOL );
		 }
	  }
	}
}
0
zukovski
1.7 года назад
  • 1
    stepan2278 www.weblancer.net/users/stepanko/?affili...

    Я не совсем понимаю вашу задачу, НО если вам нужно выводить СВОЙ статус для заказа, который оплатили вашим методом, что выше
    то вот здесь

    $status = 'completed';

    вы ставите статус заказу.
    Предлагаю добавить кастомный order status
    cod2_completed
    И ставить его, когда оплата прошла способом cod2

    if ( $order && 'cod2' === $order->get_payment_method() ) {
    	$status = 'cod2_completed';
     }

    Там пример, как добавить кастомный статус в order

    zukovski 1.7 года назад

    Мне надо что бы метод оплаты был такой же как и наличными при доставке. Он не должен быть оплачен онлайн, а оплачивается картой при доставке.

    Сейчас ордер приходит в админку как и COD, но он почему то со статусом оплачен онлайн приходит в POS систему (кассу)

    stepan 1.7 года назад

    Решение выше.
    Еще раз - в Woo НЕТ понятия статус "Оплачен онлайн"
    есть статус "Выполнен" или в "Обработка"
    Замените у себя этот участок кода, и какой статус будет приходить тогда:

     if ( $order && 'cod2' === $order->get_payment_method() ) {
    			$status = 'processing';
    		 }
    stepan 1.7 года назад

    Вот такой статус должен быть в админке.
    И тогда он никак не может передаваться, как "оплачен онлайн" - ХОТЯ еще раз - WOO нет понятия статус как "оплачен онлайн".

    zukovski 1.7 года назад

    Статус сейчас возвращает в процессе. Спасибо вам!

    Комментировать
На вопросы могут отвечать только зарегистрированные пользователи. Вход . Регистрация