purchase-orders-for-woocommerce.php


<?php

/*

Plugin Name: Purchase Orders for WooCommerce

Plugin URI: https://www.stationeryvenue.com

Description: Adds a Purchase Order payment method to WooCommerce with corporate user restrictions.

Author: Abhinav Rohatgi

Version: 1.12.7

Stable tag: 1.12.7

Text Domain: pofwc

Requires at least: 4.8

Requires PHP: 7.4

Requires plugins: woocommerce

WC requires at least: 3.0

WC tested up to: 9.3

License: GNU General Public License v2.0

License URI: http://www.gnu.org/licenses/gpl-2.0.html

*/

if ( ! defined( 'ABSPATH' ) ) {

exit; // Came directly here? Vamoose. Go on, scram.

}


use Automattic\WooCommerce\Utilities\OrderUtil;


/**

* Declare HPOS compatibility

*

* @since 1.9.0 Added compatibility

*/

add_action( 'before_woocommerce_init', function() {

if ( class_exists( \Automattic\WooCommerce\Utilities\FeaturesUtil::class ) ) {

\Automattic\WooCommerce\Utilities\FeaturesUtil::declare_compatibility( 'custom_order_tables',

__FILE__, true );

}

} );


/**

* Loads translation files

*

* @since 1.2.0 Added function

*/

function pofwc_load_textdomain() {

load_plugin_textdomain( 'pofwc', false, basename( dirname( __FILE__ ) ) . '/languages' );

}

add_action( 'plugins_loaded', 'pofwc_load_textdomain' );


/**

* Get list of Indian states and union territories

*

* @since 1.12.0 Added Indian states list

* @return array List of states and union territories

*/

function pofwc_get_indian_states() {

return array(

// States

'andhra-pradesh' => __( 'Andhra Pradesh', 'pofwc' ),

'arunachal-pradesh' => __( 'Arunachal Pradesh', 'pofwc' ),

'assam' => __( 'Assam', 'pofwc' ),

'bihar' => __( 'Bihar', 'pofwc' ),

'chhattisgarh' => __( 'Chhattisgarh', 'pofwc' ),

'goa' => __( 'Goa', 'pofwc' ),

'gujarat' => __( 'Gujarat', 'pofwc' ),

'haryana' => __( 'Haryana', 'pofwc' ),

'himachal-pradesh' => __( 'Himachal Pradesh', 'pofwc' ),

'jharkhand' => __( 'Jharkhand', 'pofwc' ),

'karnataka' => __( 'Karnataka', 'pofwc' ),

'kerala' => __( 'Kerala', 'pofwc' ),

'madhya-pradesh' => __( 'Madhya Pradesh', 'pofwc' ),

'maharashtra' => __( 'Maharashtra', 'pofwc' ),

'manipur' => __( 'Manipur', 'pofwc' ),

'meghalaya' => __( 'Meghalaya', 'pofwc' ),

'mizoram' => __( 'Mizoram', 'pofwc' ),

'nagaland' => __( 'Nagaland', 'pofwc' ),

'odisha' => __( 'Odisha', 'pofwc' ),

'punjab' => __( 'Punjab', 'pofwc' ),

'rajasthan' => __( 'Rajasthan', 'pofwc' ),

'sikkim' => __( 'Sikkim', 'pofwc' ),

'tamil-nadu' => __( 'Tamil Nadu', 'pofwc' ),

'telangana' => __( 'Telangana', 'pofwc' ),

'tripura' => __( 'Tripura', 'pofwc' ),

'uttar-pradesh' => __( 'Uttar Pradesh', 'pofwc' ),

'uttarakhand' => __( 'Uttarakhand', 'pofwc' ),

'west-bengal' => __( 'West Bengal', 'pofwc' ),

// Union Territories

'andaman-nicobar' => __( 'Andaman and Nicobar Islands', 'pofwc' ),

'chandigarh' => __( 'Chandigarh', 'pofwc' ),

'dadra-nagar-haveli-daman-diu' => __( 'Dadra and Nagar Haveli and Daman and Diu', 'pofwc' ),

'delhi' => __( 'Delhi', 'pofwc' ),

'jammu-kashmir' => __( 'Jammu and Kashmir', 'pofwc' ),

'ladakh' => __( 'Ladakh', 'pofwc' ),

'lakshadweep' => __( 'Lakshadweep', 'pofwc' ),

'puducherry' => __( 'Puducherry', 'pofwc' ),

);

}


/**

* Get GST code to state mapping

*

* @since 1.12.5 Added GST code mapping

* @return array GST code to state mapping

*/

function pofwc_get_gst_state_mapping() {

return array(

'01' => 'jammu-kashmir',

'02' => 'himachal-pradesh',

'03' => 'punjab',

'04' => 'chandigarh',

'05' => 'uttarakhand',

'06' => 'haryana',

'07' => 'delhi',

'08' => 'rajasthan',

'09' => 'uttar-pradesh',

'10' => 'bihar',

'11' => 'sikkim',

'12' => 'arunachal-pradesh',

'13' => 'nagaland',

'14' => 'manipur',

'15' => 'mizoram',

'16' => 'tripura',

'17' => 'meghalaya',

'18' => 'assam',

'19' => 'west-bengal',

'20' => 'jharkhand',

'21' => 'odisha',

'22' => 'chhattisgarh',

'23' => 'madhya-pradesh',

'24' => 'gujarat',

'25' => 'dadra-nagar-haveli-daman-diu',

'26' => 'dadra-nagar-haveli-daman-diu',

'27' => 'maharashtra',

'29' => 'karnataka',

'30' => 'goa',

'31' => 'lakshadweep',

'32' => 'kerala',

'33' => 'tamil-nadu',

'34' => 'puducherry',

'35' => 'andaman-nicobar',

'36' => 'telangana',

'37' => 'andhra-pradesh',

'38' => 'ladakh'

);

}


/**

* Create corporate user role

*

* @since 1.12.0 Added corporate user role

*/

function pofwc_create_corporate_user_role() {

add_role(

'corporate_user',

__( 'Corporate User', 'pofwc' ),

array(

'read' => true,

'edit_posts' => false,

'delete_posts' => false,

)

);

}

register_activation_hook( __FILE__, 'pofwc_create_corporate_user_role' );


/**

* Adds option on activation to check if newly activated. If true, runs WooCommerce check after

* register_activation_hook redirection

*

* @since 1.2.0 Added function

*/

function pofwc_activate(){

add_option( 'pofwc_activated', 'pofwc' );

pofwc_create_corporate_user_role();

}

register_activation_hook( __FILE__, 'pofwc_activate' );


/**

* Set default role to corporate_user for new user creation

*

* @since 1.12.5 Added default role setting

*/

add_filter( 'pre_option_default_role', 'pofwc_set_default_role_corporate_user' );


function pofwc_set_default_role_corporate_user( $default_role ) {

// Only change default role on user creation page in admin

if ( is_admin() && isset( $_GET['action'] ) && $_GET['action'] === 'add-new-user' ) {

return 'corporate_user';

}

return $default_role;

}


/**

* Set corporate_user as selected in dropdown

*

* @since 1.12.5 Added JavaScript role selection

*/

add_action( 'admin_footer-user-new.php', 'pofwc_set_corporate_user_selected' );


function pofwc_set_corporate_user_selected() {

?>

<script type="text/javascript">

jQuery(document).ready(function($) {

// Set Corporate User as selected in role dropdown

$('#role').val('corporate_user');

});

</script>

<?php

}


/**

* Ensure corporate_user role exists in dropdown

*

* @since 1.12.5 Added role to editable roles

*/

add_filter( 'editable_roles', 'pofwc_add_corporate_user_to_roles' );


function pofwc_add_corporate_user_to_roles( $roles ) {

// Make sure corporate_user role appears in admin dropdowns

if ( ! isset( $roles['corporate_user'] ) ) {

$roles['corporate_user'] = array(

'name' => 'Corporate User',

'capabilities' => array(

'read' => true,

),

);

}

return $roles;

}


/**

* Add custom fields to user profile for existing users

*

* @since 1.12.0 Added custom user fields

* @since 1.12.5 Added payment gateway settings integration, PAN, email, mobile, auth validity

*/

function pofwc_add_custom_user_fields( $user ) {

pofwc_render_corporate_fields( $user );

}


/**

* Add custom fields after role selection in user creation

*

* @since 1.12.5 Added for proper user creation order

*/

function pofwc_add_custom_user_fields_after_role() {

?>

<script type="text/javascript">

jQuery(document).ready(function($) {

// Move Corporate Information section after Role field

var corporateSection = $('.corporate-info-section');

if (corporateSection.length) {

corporateSection.insertAfter($('tr:has(#role)').closest('tr'));

}

});

</script>

<?php

// Create a user object for new user creation

$user = new stdClass();

$user->ID = 0;

pofwc_render_corporate_fields( $user );

}


/**

* Render corporate fields (shared between edit and new user)

*

* @since 1.12.5 Extracted common rendering logic

*/

function pofwc_render_corporate_fields( $user ) {

$user_roles = isset( $user->roles ) ? $user->roles : array();

?>

<div class="corporate-info-section">

<h3><?php _e( 'Corporate Information', 'pofwc' ); ?></h3>

<table class="form-table">

<tr>

<th><label for="pofwc_company_name"><?php _e( 'Company Name', 'pofwc' ); ?> <span class="required">*</span></label></th>

<td>

<input type="text" name="pofwc_company_name" id="pofwc_company_name"

value="<?php echo esc_attr( get_user_meta( $user->ID, 'pofwc_company_name', true ) ); ?>"

class="regular-text" required />

</td>

</tr>

<tr>

<th><label for="pofwc_gst_number"><?php _e( 'GSTIN', 'pofwc' ); ?> <span class="required">*</span></label></th>

<td>

<input type="text" name="pofwc_gst_number" id="pofwc_gst_number"

value="<?php echo esc_attr( get_user_meta( $user->ID, 'pofwc_gst_number', true ) ); ?>"

class="regular-text" required maxlength="15" style="text-transform: uppercase;" />

<p class="description"><?php _e( 'Enter 15-digit GSTIN. State and PAN will be auto-filled.', 'pofwc' ); ?></p>

</td>

</tr>

<tr>

<th><label for="pofwc_pan_number"><?php _e( 'PAN Number', 'pofwc' ); ?></label></th>

<td>

<input type="text" name="pofwc_pan_number" id="pofwc_pan_number"

value="<?php echo esc_attr( get_user_meta( $user->ID, 'pofwc_pan_number', true ) ); ?>"

class="regular-text" readonly style="background-color: #f1f1f1; text-transform: uppercase;" />

<p class="description"><?php _e( 'Auto-extracted from GSTIN.', 'pofwc' ); ?></p>

</td>

</tr>

<tr>

<th><label for="pofwc_billing_address_1"><?php _e( 'Billing Address 1', 'pofwc' ); ?> <span class="required">*</span></label></th>

<td>

<input type="text" name="pofwc_billing_address_1" id="pofwc_billing_address_1"

value="<?php echo esc_attr( get_user_meta( $user->ID, 'pofwc_billing_address_1', true ) ); ?>"

class="regular-text" required />

</td>

</tr>

<tr>

<th><label for="pofwc_billing_address_2"><?php _e( 'Billing Address 2', 'pofwc' ); ?> <span class="required">*</span></label></th>

<td>

<input type="text" name="pofwc_billing_address_2" id="pofwc_billing_address_2"

value="<?php echo esc_attr( get_user_meta( $user->ID, 'pofwc_billing_address_2', true ) ); ?>"

class="regular-text" required />

</td>

</tr>

<tr>

<th><label for="pofwc_landmark"><?php _e( 'Landmark', 'pofwc' ); ?> <span class="required">*</span></label></th>

<td>

<input type="text" name="pofwc_landmark" id="pofwc_landmark"

value="<?php echo esc_attr( get_user_meta( $user->ID, 'pofwc_landmark', true ) ); ?>"

class="regular-text" required />

</td>

</tr>

<tr>

<th><label for="pofwc_pincode"><?php _e( 'Pin Code', 'pofwc' ); ?> <span class="required">*</span></label></th>

<td>

<input type="text" name="pofwc_pincode" id="pofwc_pincode"

value="<?php echo esc_attr( get_user_meta( $user->ID, 'pofwc_pincode', true ) ); ?>"

class="regular-text" required pattern="[0-9]{6}" />

</td>

</tr>

<tr>

<th><label for="pofwc_city"><?php _e( 'City', 'pofwc' ); ?> <span class="required">*</span></label></th>

<td>

<input type="text" name="pofwc_city" id="pofwc_city"

value="<?php echo esc_attr( get_user_meta( $user->ID, 'pofwc_city', true ) ); ?>"

class="regular-text" required />

</td>

</tr>

<tr>

<th><label for="pofwc_state"><?php _e( 'State', 'pofwc' ); ?> <span class="required">*</span></label></th>

<td>

<?php

$current_state = get_user_meta( $user->ID, 'pofwc_state', true );

$states = pofwc_get_indian_states();

?>

<select name="pofwc_state" id="pofwc_state" class="regular-text" required>

<option value=""><?php _e( 'Select State', 'pofwc' ); ?></option>

<?php foreach( $states as $state_value => $state_name ) : ?>

<option value="<?php echo esc_attr( $state_value ); ?>" <?php selected( $current_state, $state_value ); ?>>

<?php echo esc_html( $state_name ); ?>

</option>

<?php endforeach; ?>

</select>

</td>

</tr>

<tr>

<th><label for="pofwc_contact_number"><?php _e( 'Contact Number', 'pofwc' ); ?> <span class="required">*</span></label></th>

<td>

<input type="tel" name="pofwc_contact_number" id="pofwc_contact_number"

value="<?php echo esc_attr( get_user_meta( $user->ID, 'pofwc_contact_number', true ) ); ?>"

class="regular-text" required pattern="[0-9]{10}" />

</td>

</tr>

<tr>

<th><label for="pofwc_mobile_number"><?php _e( 'Mobile Number', 'pofwc' ); ?> <span class="required">*</span></label></th>

<td>

<input type="tel" name="pofwc_mobile_number" id="pofwc_mobile_number"

value="<?php echo esc_attr( get_user_meta( $user->ID, 'pofwc_mobile_number', true ) ); ?>"

class="regular-text" pattern="[0-9]{10}" required />

</td>

</tr>

<tr>

<th><label for="pofwc_email_id"><?php _e( 'Email ID', 'pofwc' ); ?> <span class="required">*</span></label></th>

<td>

<input type="email" name="pofwc_email_id" id="pofwc_email_id"

value="<?php echo esc_attr( get_user_meta( $user->ID, 'pofwc_email_id', true ) ); ?>"

class="regular-text" required />

</td>

</tr>

<tr>

<th><label for="pofwc_contact_person"><?php _e( 'Authorized Person', 'pofwc' ); ?> <span class="required">*</span></label></th>

<td>

<input type="text" name="pofwc_contact_person" id="pofwc_contact_person"

value="<?php echo esc_attr( get_user_meta( $user->ID, 'pofwc_contact_person', true ) ); ?>"

class="regular-text" required />

</td>

</tr>

<tr>

<th><label for="pofwc_designation"><?php _e( 'Designation', 'pofwc' ); ?> <span class="required">*</span></label></th>

<td>

<input type="text" name="pofwc_designation" id="pofwc_designation"

value="<?php echo esc_attr( get_user_meta( $user->ID, 'pofwc_designation', true ) ); ?>"

class="regular-text" required />

</td>

</tr>

<?php

$auth_validity_enabled = get_user_meta( $user->ID, 'pofwc_authorization_validity_enabled', true );

$auth_start_date = get_user_meta( $user->ID, 'pofwc_auth_start_date', true );

$auth_end_date = get_user_meta( $user->ID, 'pofwc_auth_end_date', true );

?>

<tr>

<th><label for="pofwc_authorization_validity_enabled"><?php _e( 'Authorization Validity', 'pofwc' ); ?></label></th>

<td>

<input type="checkbox" name="pofwc_authorization_validity_enabled" id="pofwc_authorization_validity_enabled"

value="1" <?php checked( $auth_validity_enabled, '1' ); ?> />

<label for="pofwc_authorization_validity_enabled"><?php _e( 'Enable authorization validity dates', 'pofwc' ); ?></label>

</td>

</tr>

<tr id="auth_dates_row" style="<?php echo $auth_validity_enabled ? '' : 'display:none;'; ?>">

<th><label><?php _e( 'Validity Period', 'pofwc' ); ?></label></th>

<td>

<label for="pofwc_auth_start_date"><?php _e( 'Start Date:', 'pofwc' ); ?></label>

<input type="date" name="pofwc_auth_start_date" id="pofwc_auth_start_date"

value="<?php echo esc_attr( $auth_start_date ); ?>" />

<br><br>

<label for="pofwc_auth_end_date"><?php _e( 'End Date:', 'pofwc' ); ?></label>

<input type="date" name="pofwc_auth_end_date" id="pofwc_auth_end_date"

value="<?php echo esc_attr( $auth_end_date ); ?>" />

</td>

</tr>

</table>

</div>

<style>

.required { color: red; }

.form-table th { width: 200px; }

</style>

<script type="text/javascript">

jQuery(document).ready(function($) {

// GST state mapping

var gstStateMapping = <?php echo json_encode( pofwc_get_gst_state_mapping() ); ?>;

// GST number processing

$('#pofwc_gst_number').on('input', function() {

var gstNumber = $(this).val().toUpperCase();

$(this).val(gstNumber);

if (gstNumber.length >= 2) {

var stateCode = gstNumber.substring(0, 2);

// Don't auto-select for codes 97 and 99

if (stateCode !== '97' && stateCode !== '99' && gstStateMapping[stateCode]) {

$('#pofwc_state').val(gstStateMapping[stateCode]);

}

}

if (gstNumber.length >= 12) {

// Extract PAN (characters 3-12, making it 10 characters)

var panNumber = gstNumber.substring(2, 12);

$('#pofwc_pan_number').val(panNumber);

}

});

// Authorization validity checkbox toggle

$('#pofwc_authorization_validity_enabled').change(function() {

if ($(this).is(':checked')) {

$('#auth_dates_row').show();

} else {

$('#auth_dates_row').hide();

$('#pofwc_auth_start_date, #pofwc_auth_end_date').val('');

}

});

});

</script>

<?php

// Payment gateway settings section (existing code)

if ( current_user_can( 'manage_options' ) ) {

$enabled_gateways = get_user_meta( $user->ID, 'enabled_payment_gateways', true );

if ( ! is_array( $enabled_gateways ) ) {

$enabled_gateways = array();

}

// Get all payment gateways (not just available ones for admin settings)

if ( class_exists( 'WC_Payment_Gateways' ) ) {

$payment_gateways = WC_Payment_Gateways::instance();

$all_gateways = $payment_gateways->payment_gateways();

$available_gateways = array();

// Filter to only enabled gateways

foreach ( $all_gateways as $gateway_id => $gateway ) {

if ( $gateway->enabled === 'yes' ) {

$available_gateways[$gateway_id] = $gateway;

}

}

} else {

$available_gateways = array();

}

?>

<h3><?php _e( 'Payment Gateway Settings', 'pofwc' ); ?></h3>

<p class="description"><?php _e( 'Select which payment gateways this corporate user can access. Payment gateways will only be shown if corporate information is provided above.', 'pofwc' ); ?></p>

<table class="form-table">

<tr id="payment_gateways_row">

<th><label><?php _e( 'Available Payment Gateways', 'pofwc' ); ?></label></th>

<td>

<fieldset>

<?php if ( ! empty( $available_gateways ) ) : ?>

<?php foreach ( $available_gateways as $gateway_id => $gateway ) : ?>

<label for="gateway_<?php echo esc_attr( $gateway_id ); ?>">

<input type="checkbox"

name="enabled_payment_gateways[]"

id="gateway_<?php echo esc_attr( $gateway_id ); ?>"

value="<?php echo esc_attr( $gateway_id ); ?>"

<?php checked( in_array( $gateway_id, $enabled_gateways ) ); ?> />

<?php echo esc_html( $gateway->get_method_title() ); ?>

</label><br>

<?php endforeach; ?>

<?php else : ?>

<p><?php _e( 'No payment gateways available.', 'pofwc' ); ?></p>

<?php endif; ?>

<span class="description"><?php _e( 'Corporate users will only see the selected payment gateways during checkout.', 'pofwc' ); ?></span>

</fieldset>

</td>

</tr>

</table>

<script type="text/javascript">

jQuery(document).ready(function($) {

// Function to check if user has corporate information

function checkCorporateInfo() {

var hasCompanyName = $('#pofwc_company_name').val() && $('#pofwc_company_name').val().trim() !== '';

var hasGstNumber = $('#pofwc_gst_number').val() && $('#pofwc_gst_number').val().trim() !== '';

if (hasCompanyName || hasGstNumber) {

$('#payment_gateways_row').show();

} else {

$('#payment_gateways_row').hide();

// Uncheck all payment gateways if no corporate info

$('input[name="enabled_payment_gateways[]"]').prop('checked', false);

}

}

// Check on page load

checkCorporateInfo();

// Monitor corporate information fields

$('#pofwc_company_name, #pofwc_gst_number').on('input', function() {

checkCorporateInfo();

});

});

</script>

<?php

}

}

add_action( 'show_user_profile', 'pofwc_add_custom_user_fields' );

add_action( 'edit_user_profile', 'pofwc_add_custom_user_fields' );


// Use different approach for user creation - insert after role field

add_action( 'user_new_form', 'pofwc_add_custom_user_fields_after_role' );


/**

* Save custom user fields

*

* @since 1.12.0 Added save function for custom fields

* @since 1.12.5 Added payment gateway settings, corporate user auto-detection, and billing sync

*/

function pofwc_save_custom_user_fields( $user_id ) {

if ( ! current_user_can( 'edit_user', $user_id ) ) {

return false;

}


$fields = array(

'pofwc_company_name',

'pofwc_gst_number',

'pofwc_pan_number',

'pofwc_billing_address_1',

'pofwc_billing_address_2',

'pofwc_landmark',

'pofwc_pincode',

'pofwc_city',

'pofwc_state',

'pofwc_contact_number',

'pofwc_mobile_number',

'pofwc_email_id',

'pofwc_contact_person',

'pofwc_designation'

);


// Validate required fields

$required_fields = array(

'pofwc_company_name' => __( 'Company Name', 'pofwc' ),

'pofwc_gst_number' => __( 'GSTIN', 'pofwc' ),

'pofwc_billing_address_1' => __( 'Billing Address 1', 'pofwc' ),

'pofwc_billing_address_2' => __( 'Billing Address 2', 'pofwc' ),

'pofwc_landmark' => __( 'Landmark', 'pofwc' ),

'pofwc_pincode' => __( 'Pin Code', 'pofwc' ),

'pofwc_city' => __( 'City', 'pofwc' ),

'pofwc_state' => __( 'State', 'pofwc' ),

'pofwc_contact_number' => __( 'Contact Number', 'pofwc' ),

'pofwc_mobile_number' => __( 'Mobile Number', 'pofwc' ),

'pofwc_email_id' => __( 'Email ID', 'pofwc' ),

'pofwc_contact_person' => __( 'Authorized Person', 'pofwc' ),

'pofwc_designation' => __( 'Designation', 'pofwc' )

);


$errors = array();

foreach ( $required_fields as $field => $label ) {

if ( empty( $_POST[ $field ] ) ) {

$errors[] = $label;

}

}


if ( ! empty( $errors ) ) {

wp_die( sprintf( __( 'Required fields missing: %s', 'pofwc' ), implode( ', ', $errors ) ) );

}


// Save all fields

foreach ( $fields as $field ) {

if ( isset( $_POST[ $field ] ) ) {

update_user_meta( $user_id, $field, sanitize_text_field( $_POST[ $field ] ) );

}

}

// Save authorization validity fields

$auth_validity_enabled = isset( $_POST['pofwc_authorization_validity_enabled'] ) ? '1' : '';

update_user_meta( $user_id, 'pofwc_authorization_validity_enabled', $auth_validity_enabled );

if ( $auth_validity_enabled ) {

$auth_start_date = isset( $_POST['pofwc_auth_start_date'] ) ? sanitize_text_field( $_POST['pofwc_auth_start_date'] ) : '';

$auth_end_date = isset( $_POST['pofwc_auth_end_date'] ) ? sanitize_text_field( $_POST['pofwc_auth_end_date'] ) : '';

update_user_meta( $user_id, 'pofwc_auth_start_date', $auth_start_date );

update_user_meta( $user_id, 'pofwc_auth_end_date', $auth_end_date );

} else {

delete_user_meta( $user_id, 'pofwc_auth_start_date' );

delete_user_meta( $user_id, 'pofwc_auth_end_date' );

}

// Auto-populate WooCommerce billing fields

$company_name = sanitize_text_field( $_POST['pofwc_company_name'] );

$address_1 = sanitize_text_field( $_POST['pofwc_billing_address_1'] );

$address_2 = sanitize_text_field( $_POST['pofwc_billing_address_2'] );

$city = sanitize_text_field( $_POST['pofwc_city'] );

$state = sanitize_text_field( $_POST['pofwc_state'] );

$postcode = sanitize_text_field( $_POST['pofwc_pincode'] );

$phone = sanitize_text_field( $_POST['pofwc_contact_number'] );

$contact_person = sanitize_text_field( $_POST['pofwc_contact_person'] );

// Map corporate fields to WooCommerce billing fields

update_user_meta( $user_id, 'billing_company', $company_name );

update_user_meta( $user_id, 'billing_address_1', $address_1 );

update_user_meta( $user_id, 'billing_address_2', $address_2 );

update_user_meta( $user_id, 'billing_city', $city );

update_user_meta( $user_id, 'billing_state', $state );

update_user_meta( $user_id, 'billing_postcode', $postcode );

update_user_meta( $user_id, 'billing_country', 'IN' );

update_user_meta( $user_id, 'billing_phone', $phone );

// Split contact person name for first/last name

$name_parts = explode( ' ', $contact_person, 2 );

update_user_meta( $user_id, 'billing_first_name', $name_parts[0] );

update_user_meta( $user_id, 'billing_last_name', isset( $name_parts[1] ) ? $name_parts[1] : '' );

// Also update shipping fields to match billing

update_user_meta( $user_id, 'shipping_company', $company_name );

update_user_meta( $user_id, 'shipping_address_1', $address_1 );

update_user_meta( $user_id, 'shipping_address_2', $address_2 );

update_user_meta( $user_id, 'shipping_city', $city );

update_user_meta( $user_id, 'shipping_state', $state );

update_user_meta( $user_id, 'shipping_postcode', $postcode );

update_user_meta( $user_id, 'shipping_country', 'IN' );

update_user_meta( $user_id, 'shipping_first_name', $name_parts[0] );

update_user_meta( $user_id, 'shipping_last_name', isset( $name_parts[1] ) ? $name_parts[1] : '' );

// Payment gateway settings and corporate user auto-detection (existing code)

if ( current_user_can( 'manage_options' ) ) {

// Save enabled payment gateways

$enabled_gateways = isset( $_POST['enabled_payment_gateways'] ) ? $_POST['enabled_payment_gateways'] : array();

update_user_meta( $user_id, 'enabled_payment_gateways', $enabled_gateways );

// Auto-detect if user is corporate based on corporate information

$gst_number = isset( $_POST['pofwc_gst_number'] ) ? sanitize_text_field( $_POST['pofwc_gst_number'] ) : '';

// Also check existing meta values if not in POST

if ( empty( $company_name ) ) {

$company_name = get_user_meta( $user_id, 'pofwc_company_name', true );

}

if ( empty( $gst_number ) ) {

$gst_number = get_user_meta( $user_id, 'pofwc_gst_number', true );

}

// Mark as corporate user if they have company information

$is_corporate = ( ! empty( $company_name ) || ! empty( $gst_number ) ) ? '1' : '';

update_user_meta( $user_id, 'is_corporate_user', $is_corporate );

}

}

add_action( 'personal_options_update', 'pofwc_save_custom_user_fields' );

add_action( 'edit_user_profile_update', 'pofwc_save_custom_user_fields' );

add_action( 'user_register', 'pofwc_save_custom_user_fields' );


/**

* Display corporate company information at checkout

*

* @since 1.12.2 Added company info display

* @since 1.12.5 Added PAN, mobile, email, authorized person with enhanced design

* @since 1.12.6 Updated alignment and styling

*/

function pofwc_display_corporate_info_at_checkout() {

if ( ! is_user_logged_in() ) {

return;

}


$current_user = wp_get_current_user();

if ( ! in_array( 'corporate_user', $current_user->roles ) ) {

return;

}


$company_name = get_user_meta( $current_user->ID, 'pofwc_company_name', true );

$gst_number = get_user_meta( $current_user->ID, 'pofwc_gst_number', true );

$pan_number = get_user_meta( $current_user->ID, 'pofwc_pan_number', true );

$contact_person = get_user_meta( $current_user->ID, 'pofwc_contact_person', true );

$mobile_number = get_user_meta( $current_user->ID, 'pofwc_mobile_number', true );

$email_id = get_user_meta( $current_user->ID, 'pofwc_email_id', true );

if ( empty( $company_name ) && empty( $gst_number ) ) {

return; // Don't show if no company info

}

// Extract PAN from GSTIN if PAN is empty but GSTIN exists

if ( empty( $pan_number ) && ! empty( $gst_number ) && strlen( $gst_number ) >= 12 ) {

$pan_number = substr( $gst_number, 2, 10 );

}

?>

<div class="pofwc-company-info-checkout">

<div class="pofwc-company-header">

<h3><?php _e( 'CORPORATE INFORMATION', 'pofwc' ); ?></h3>

</div>

<div class="pofwc-company-details-checkout">

<div class="pofwc-info-left">

<?php if ( $company_name ) : ?>

<div class="pofwc-info-row">

<span class="pofwc-label">COMPANY NAME :</span>

<span class="pofwc-value"><?php echo esc_html( strtoupper( $company_name ) ); ?></span>

</div>

<?php endif; ?>

<?php if ( $gst_number ) : ?>

<div class="pofwc-info-row">

<span class="pofwc-label">GSTIN :</span>

<span class="pofwc-value"><?php echo esc_html( strtoupper( $gst_number ) ); ?></span>

</div>

<?php endif; ?>

<?php if ( $pan_number ) : ?>

<div class="pofwc-info-row">

<span class="pofwc-label">PAN :</span>

<span class="pofwc-value"><?php echo esc_html( strtoupper( $pan_number ) ); ?></span>

</div>

<?php endif; ?>

</div>

<div class="pofwc-info-right">

<?php if ( $contact_person ) : ?>

<div class="pofwc-info-row">

<span class="pofwc-label">AUTHORIZED PERSON :</span>

<span class="pofwc-value"><?php echo esc_html( strtoupper( $contact_person ) ); ?></span>

</div>

<?php endif; ?>

<?php if ( $email_id ) : ?>

<div class="pofwc-info-row">

<span class="pofwc-label">EMAIL ID :</span>

<span class="pofwc-value"><?php echo esc_html( strtoupper( $email_id ) ); ?></span>

</div>

<?php endif; ?>

<?php if ( $mobile_number ) : ?>

<div class="pofwc-info-row">

<span class="pofwc-label">MOBILE NO. :</span>

<span class="pofwc-value"><?php echo esc_html( $mobile_number ); ?></span>

</div>

<?php endif; ?>

</div>

</div>

</div>

<style>

.pofwc-company-info-checkout {

border: 2px solid #e74c3c;

border-radius: 8px;

margin: 20px 0;

background: white;

overflow: hidden;

}


.pofwc-company-header {

background: #e74c3c;

padding: 12px 20px;

text-align: center;

}


.pofwc-company-header h3 {

margin: 0 !important;

font-size: 16px !important;

font-weight: 700 !important;

color: white !important;

letter-spacing: 1px;

}


.pofwc-company-details-checkout {

display: grid;

grid-template-columns: 1fr 1fr;

padding: 20px;

gap: 30px;

background: white;

}


.pofwc-info-left {

display: flex;

flex-direction: column;

gap: 8px;

}


.pofwc-info-right {

display: flex;

flex-direction: column;

gap: 8px;

}


.pofwc-info-row {

display: flex;

align-items: center;

line-height: 1.4;

}


.pofwc-label {

font-weight: 700;

color: #333;

font-size: 14px;

min-width: 150px;

display: inline-block;

}


.pofwc-value {

font-weight: 400;

color: #333;

font-size: 14px;

margin-left: 5px;

}

@media (max-width: 768px) {

.pofwc-company-details-checkout {

grid-template-columns: 1fr;

gap: 20px;

}

}

</style>

<?php

}

add_action( 'woocommerce_checkout_before_customer_details', 'pofwc_display_corporate_info_at_checkout' );


/**

* Modify checkout fields for corporate users - Pre-filled fields only

*

* @since 1.12.0 Added checkout field modification

* @since 1.12.3 Simplified to pre-filled fields only

*/

function pofwc_modify_checkout_fields_for_corporate_users( $fields ) {

if ( ! is_user_logged_in() ) {

return $fields;

}


$current_user = wp_get_current_user();

if ( ! in_array( 'corporate_user', $current_user->roles ) ) {

return $fields;

}


// Get user meta data

$company_name = get_user_meta( $current_user->ID, 'pofwc_company_name', true );

$address_1 = get_user_meta( $current_user->ID, 'pofwc_billing_address_1', true );

$address_2 = get_user_meta( $current_user->ID, 'pofwc_billing_address_2', true );

$city = get_user_meta( $current_user->ID, 'pofwc_city', true );

$state = get_user_meta( $current_user->ID, 'pofwc_state', true );

$postcode = get_user_meta( $current_user->ID, 'pofwc_pincode', true );

$contact_person = get_user_meta( $current_user->ID, 'pofwc_contact_person', true );


if ( isset( $fields['shipping'] ) ) {

// Pre-fill shipping fields

$fields['shipping']['shipping_company']['default'] = $company_name;

$fields['shipping']['shipping_address_1']['default'] = $address_1;

$fields['shipping']['shipping_address_2']['default'] = $address_2;

$fields['shipping']['shipping_city']['default'] = $city;

$fields['shipping']['shipping_postcode']['default'] = $postcode;

// Add first name and last name if contact person is available

if ( $contact_person ) {

$name_parts = explode(' ', $contact_person, 2);

$fields['shipping']['shipping_first_name']['default'] = isset($name_parts[0]) ? $name_parts[0] : '';

$fields['shipping']['shipping_last_name']['default'] = isset($name_parts[1]) ? $name_parts[1] : '';

}

// Handle state field with dropdown options

$fields['shipping']['shipping_state']['type'] = 'select';

$fields['shipping']['shipping_state']['options'] = array( '' => __( 'Select State', 'pofwc' ) ) + pofwc_get_indian_states();

$fields['shipping']['shipping_state']['default'] = $state;

// Set country to India by default for corporate users

$fields['shipping']['shipping_country']['default'] = 'IN';

}


return $fields;

}

add_filter( 'woocommerce_checkout_fields', 'pofwc_modify_checkout_fields_for_corporate_users' );


/**

* Add "Add New Address" functionality for corporate users

*

* @since 1.12.0 Added new address functionality

* @since 1.12.3 Simplified version

*/

function pofwc_add_new_address_button() {

if ( ! is_user_logged_in() ) {

return;

}


$current_user = wp_get_current_user();

if ( ! in_array( 'corporate_user', $current_user->roles ) ) {

return;

}

?>

<div class="pofwc-address-controls-section">

<div class="pofwc-address-status">

<h4><?php _e( 'Shipping Address', 'pofwc' ); ?></h4>

<p><span id="pofwc-current-status"><?php _e( 'Using company address', 'pofwc' ); ?></span></p>

</div>

<div class="pofwc-toggle-buttons">

<button type="button" id="pofwc-enable-custom" class="button button-primary">

<?php _e( 'Add New Address', 'pofwc' ); ?>

</button>

</div>

</div>


<style>

.pofwc-address-controls-section {

background: #f8f9fa;

border: 1px solid #ddd;

border-radius: 6px;

padding: 20px;

margin: 20px 0;

}


.pofwc-address-status h4 {

margin: 0 0 5px 0;

font-size: 16px;

color: #333;

}


.pofwc-address-status p {

margin: 0 0 15px 0;

}


.pofwc-toggle-buttons {

display: flex;

gap: 10px;

}


.pofwc-toggle-buttons .button {

padding: 10px 20px;

font-size: 14px;

border-radius: 4px;

transition: all 0.3s ease;

}


#pofwc-current-status {

font-weight: 600;

color: #28a745;

}

</style>

<?php

}

add_action( 'woocommerce_after_checkout_shipping_form', 'pofwc_add_new_address_button' );


/**

* CORRECTED: Register custom order status - Pending PO Verification

* Fixed typo and simplified to prevent issues

*

* @since 1.12.4 Added custom order status

* @since 1.12.7 Fixed typo and simplified

*/

function pofwc_register_pending_po_verification_order_status() {

register_post_status( 'wc-pending-po-verification', array(

'label' => 'Pending PO Verification',

'public' => true,

'exclude_from_search' => false,

'show_in_admin_all_list' => true,

'show_in_admin_status_list' => true,

'label_count' => _n_noop( 'Pending PO Verification (%s)', 'Pending PO Verification (%s)' )

));

}

add_action( 'init', 'pofwc_register_pending_po_verification_order_status' );


/**

* CORRECTED: Add custom status to WooCommerce order status list

* Simplified version to prevent conflicts

*

* @since 1.12.4 Added to order statuses

* @since 1.12.7 Simplified to prevent issues

*/

function pofwc_add_pending_po_verification_to_order_statuses( $order_statuses ) {

$new_order_statuses = array();

foreach ( $order_statuses as $key => $status ) {

$new_order_statuses[ $key ] = $status;

if ( 'wc-pending' === $key ) {

$new_order_statuses['wc-pending-po-verification'] = 'Pending PO Verification';

}

}

return $new_order_statuses;

}

add_filter( 'wc_order_statuses', 'pofwc_add_pending_po_verification_to_order_statuses' );


/**

* CORRECTED: Anti-cancellation protection (simplified, no infinite loops)

* This prevents WooCommerce from cancelling PO orders automatically

*

* @since 1.12.7 Simplified anti-cancellation system

*/

function pofwc_exclude_po_orders_from_cancellation( $order_ids ) {

if ( empty( $order_ids ) || ! is_array( $order_ids ) ) {

return $order_ids;

}

foreach( $order_ids as $key => $order_id ) {

$order = wc_get_order( $order_id );

if( $order && $order->get_payment_method() === 'purchase_order_gateway' ) {

unset( $order_ids[$key] );

}

}

return $order_ids;

}

add_filter( 'woocommerce_cancel_unpaid_orders', 'pofwc_exclude_po_orders_from_cancellation' );


/**

* CORRECTED: Extend stock hold time for PO orders

* Prevents stock-based cancellation without causing issues

*

* @since 1.12.7 Simplified stock hold extension

*/

function pofwc_extend_po_order_stock_hold( $hold_stock_minutes, $order = null ) {

// Check if we have an order and it's a PO order

if ( $order && is_object( $order ) && method_exists( $order, 'get_payment_method' ) ) {

if ( $order->get_payment_method() === 'purchase_order_gateway' ) {

return 60 * 24 * 90; // 90 days for PO orders

}

}

// Fallback: check current order if in checkout context

if ( ! $order && isset( WC()->session ) ) {

$order_id = WC()->session->get( 'order_awaiting_payment' );

if ( $order_id ) {

$current_order = wc_get_order( $order_id );

if ( $current_order && $current_order->get_payment_method() === 'purchase_order_gateway' ) {

return 60 * 24 * 90;

}

}

}

return $hold_stock_minutes;

}

add_filter( 'woocommerce_hold_stock_minutes', 'pofwc_extend_po_order_stock_hold', 10, 2 );


/**

* CORRECTED: Fix existing orders function (prevents HTTP 500)

* Enhanced error handling and batch processing

*

* @since 1.12.7 Enhanced with better error handling

*/

function pofwc_fix_existing_po_orders() {

// Security check

if ( ! is_admin() || ! current_user_can( 'manage_woocommerce' ) ) {

wp_die( __( 'You do not have sufficient permissions to access this page.', 'pofwc' ) );

}

// Add time limit and memory limit to prevent timeouts

set_time_limit( 300 ); // 5 minutes

ini_set( 'memory_limit', '512M' );

try {

// Get orders in smaller batches to prevent memory issues

$fixed_count = 0;

$offset = 0;

$batch_size = 50;

do {

$orders = wc_get_orders( array(

'limit' => $batch_size,

'offset' => $offset,

'status' => array( 'pending', 'on-hold' ),

'payment_method' => 'purchase_order_gateway',

'return' => 'objects'

) );

foreach( $orders as $order ) {

$current_status = $order->get_status();

if( in_array( $current_status, array( 'pending', 'on-hold' ) ) ) {

$order->update_status(

'pending-po-verification',

sprintf( __( 'Status corrected from %s to pending-po-verification by admin tool.', 'pofwc' ), $current_status )

);

$fixed_count++;

}

}

$offset += $batch_size;

} while ( count( $orders ) === $batch_size );

if( $fixed_count > 0 ) {

echo '<div class="notice notice-success"><p>' .

sprintf( __( 'Successfully fixed %d purchase order statuses.', 'pofwc' ), $fixed_count ) .

'</p></div>';

} else {

echo '<div class="notice notice-info"><p>' .

__( 'No purchase orders found that need status correction.', 'pofwc' ) .

'</p></div>';

}

} catch ( Exception $e ) {

echo '<div class="notice notice-error"><p>' .

sprintf( __( 'Error occurred: %s', 'pofwc' ), esc_html( $e->getMessage() ) ) .

'</p></div>';

}

}


/**

* CORRECTED: Restore cancelled orders function (prevents HTTP 500)

* Enhanced error handling and extended search period

*

* @since 1.12.7 Enhanced with better error handling

*/

function pofwc_restore_cancelled_po_orders() {

// Security check

if ( ! is_admin() || ! current_user_can( 'manage_woocommerce' ) ) {

wp_die( __( 'You do not have sufficient permissions to access this page.', 'pofwc' ) );

}

// Add time limit and memory limit

set_time_limit( 300 );

ini_set( 'memory_limit', '512M' );

try {

// Look for cancelled PO orders from the last 7 days (extended period)

$orders = wc_get_orders( array(

'limit' => 100, // Limit to prevent memory issues

'status' => 'cancelled',

'payment_method' => 'purchase_order_gateway',

'date_created' => '>' . ( time() - ( 7 * DAY_IN_SECONDS ) ), // Last 7 days

'return' => 'objects'

) );

$restored_count = 0;

foreach( $orders as $order ) {

// Always restore cancelled PO orders (they shouldn't be cancelled automatically)

$order->update_status(

'pending-po-verification',

__( 'Order restored from cancelled status - Purchase Orders should not be auto-cancelled.', 'pofwc' )

);

$restored_count++;

}

if( $restored_count > 0 ) {

echo '<div class="notice notice-success"><p>' .

sprintf( __( 'Successfully restored %d purchase orders from cancelled status.', 'pofwc' ), $restored_count ) .

'</p></div>';

} else {

echo '<div class="notice notice-info"><p>' .

__( 'No cancelled purchase orders found to restore from the last 7 days.', 'pofwc' ) .

'</p></div>';

}

} catch ( Exception $e ) {

echo '<div class="notice notice-error"><p>' .

sprintf( __( 'Error occurred: %s', 'pofwc' ), esc_html( $e->getMessage() ) ) .

'</p></div>';

}

}


/**

* CORRECTED: Admin tools registration

* Simplified and safer tool registration

*

* @since 1.12.7 Simplified admin tools

*/

function pofwc_add_status_fix_tools( $tools ) {

$tools['fix_po_order_status'] = array(

'name' => __( 'Fix Purchase Order Statuses', 'pofwc' ),

'button' => __( 'Fix PO Statuses', 'pofwc' ),

'desc' => __( 'Updates purchase orders from "pending" to "pending-po-verification" status.', 'pofwc' ),

'callback' => 'pofwc_fix_existing_po_orders'

);

$tools['restore_cancelled_po_orders'] = array(

'name' => __( 'Restore Cancelled Purchase Orders', 'pofwc' ),

'button' => __( 'Restore PO Orders', 'pofwc' ),

'desc' => __( 'Restores cancelled purchase orders from the last 7 days.', 'pofwc' ),

'callback' => 'pofwc_restore_cancelled_po_orders'

);

return $tools;

}

add_filter( 'woocommerce_debug_tools', 'pofwc_add_status_fix_tools' );


/**

* Register the custom email class with WooCommerce

*

* @since 1.12.4 Added email system

*/

function pofwc_add_po_verification_email_class( $email_classes ) {

require_once dirname( __FILE__ ) . '/class-po-verification-email.php';

$email_classes['WC_PO_Verification_Email'] = new WC_PO_Verification_Email();

return $email_classes;

}

add_filter( 'woocommerce_email_classes', 'pofwc_add_po_verification_email_class' );


/**

* Trigger email when order status changes to pending-po-verification

*

* @since 1.12.4 Added email trigger

*/

function pofwc_trigger_po_verification_email( $order_id, $order = false ) {

if ( ! $order ) {

$order = wc_get_order( $order_id );

}

// Only send if payment method is purchase order

if ( $order && $order->get_payment_method() === 'purchase_order_gateway' ) {

$emails = WC()->mailer()->get_emails();

if ( isset( $emails['WC_PO_Verification_Email'] ) ) {

$emails['WC_PO_Verification_Email']->trigger( $order_id, $order );

}

}

}

add_action( 'woocommerce_order_status_pending-po-verification', 'pofwc_trigger_po_verification_email', 10, 2 );


/**

* CORRECTED: Simplified status display CSS

* Clean styling without conflicts

*

* @since 1.12.7 Simplified styling

*/

function pofwc_add_status_styles() {

echo '<style>

.order-status.status-pending-po-verification,

mark.order-status.status-pending-po-verification {

background: #ffba00 !important;

color: #fff !important;

border-radius: 3px;

padding: 2px 8px;

font-weight: bold;

font-size: 11px;

}

.widefat .column-order_status mark.order-status.status-pending-po-verification {

background: #ffba00 !important;

color: #fff !important;

}

.woocommerce-orders-table .order-status.status-pending-po-verification {

background: #ffba00 !important;

color: #fff !important;

padding: 3px 8px;

border-radius: 3px;

font-weight: bold;

font-size: 12px;

}

</style>';

}

add_action( 'admin_head', 'pofwc_add_status_styles' );

add_action( 'wp_head', 'pofwc_add_status_styles' );


/**

* CORRECTED: Simplified cancelled orders notice (no performance issues)

* Only shows when there are actually cancelled orders

*

* @since 1.12.7 Simplified notice system

*/

function pofwc_add_cancelled_po_orders_notice() {

if ( ! current_user_can( 'manage_woocommerce' ) ) {

return;

}

$screen = get_current_screen();

if ( $screen->id !== 'dashboard' ) {

return;

}

// Only check once per hour to avoid performance issues

$last_check = get_transient( 'pofwc_cancelled_orders_check' );

if ( $last_check ) {

return;

}

// Set transient for 1 hour

set_transient( 'pofwc_cancelled_orders_check', time(), HOUR_IN_SECONDS );

// Quick check for cancelled PO orders

$cancelled_count = wc_get_orders( array(

'limit' => 1,

'status' => 'cancelled',

'payment_method' => 'purchase_order_gateway',

'date_created' => '>' . ( time() - ( 7 * DAY_IN_SECONDS ) ),

'return' => 'ids',

'count' => true

) );

if ( $cancelled_count > 0 ) {

?>

<div class="notice notice-error">

<p>

<strong><?php _e( 'Purchase Orders Alert:', 'pofwc' ); ?></strong>

<?php _e( 'Cancelled purchase orders detected.', 'pofwc' ); ?>

<a href="<?php echo admin_url( 'admin.php?page=wc-status&tab=tools' ); ?>" class="button button-primary" style="margin-left: 10px;">

<?php _e( 'Check Tools', 'pofwc' ); ?>

</a>

</p>

</div>

<?php

}

}

add_action( 'admin_notices', 'pofwc_add_cancelled_po_orders_notice' );


/**

* Add validation to ensure corporate users have required address data

*

* @since 1.12.1 Added validation for corporate user address

*/

function pofwc_validate_corporate_user_address() {

if ( ! is_user_logged_in() ) {

return;

}


$current_user = wp_get_current_user();

if ( ! in_array( 'corporate_user', $current_user->roles ) ) {

return;

}


// Check if essential address fields are missing

$required_fields = array(

'pofwc_company_name' => __( 'Company Name', 'pofwc' ),

'pofwc_billing_address_1' => __( 'Address', 'pofwc' ),

'pofwc_city' => __( 'City', 'pofwc' ),

'pofwc_state' => __( 'State', 'pofwc' ),

'pofwc_pincode' => __( 'Pin Code', 'pofwc' )

);


$missing_fields = array();

foreach ( $required_fields as $field => $label ) {

if ( empty( get_user_meta( $current_user->ID, $field, true ) ) ) {

$missing_fields[] = $label;

}

}


if ( ! empty( $missing_fields ) ) {

wc_add_notice(

sprintf(

__( 'Your corporate profile is incomplete. Please contact administrator to update: %s', 'pofwc' ),

implode( ', ', $missing_fields )

),

'error'

);

}

}

add_action( 'woocommerce_checkout_process', 'pofwc_validate_corporate_user_address' );


/**

* Add admin notice for incomplete corporate user profiles

*

* @since 1.12.1 Added admin notifications

*/

function pofwc_admin_notice_incomplete_profiles() {

if ( ! current_user_can( 'manage_options' ) ) {

return;

}


// Get corporate users with incomplete profiles

$corporate_users = get_users( array( 'role' => 'corporate_user' ) );

$incomplete_users = array();


foreach ( $corporate_users as $user ) {

$required_fields = array( 'pofwc_company_name', 'pofwc_billing_address_1', 'pofwc_city', 'pofwc_state', 'pofwc_pincode' );

foreach ( $required_fields as $field ) {

if ( empty( get_user_meta( $user->ID, $field, true ) ) ) {

$incomplete_users[] = $user;

break;

}

}

}


if ( ! empty( $incomplete_users ) && get_current_screen()->id === 'dashboard' ) {

?>

<div class="notice notice-warning">

<p>

<strong><?php _e( 'Purchase Orders Plugin:', 'pofwc' ); ?></strong>

<?php

printf(

_n(

'There is %d corporate user with incomplete address information.',

'There are %d corporate users with incomplete address information.',

count( $incomplete_users ),

'pofwc'

),

count( $incomplete_users )

);

?>

<a href="<?php echo admin_url( 'users.php?role=corporate_user' ); ?>"><?php _e( 'Review users', 'pofwc' ); ?></a>

</p>

</div>

<?php

}

}

add_action( 'admin_notices', 'pofwc_admin_notice_incomplete_profiles' );


/**

* Adds the gateway to WC Available Gateways

*

* @param array $gateways all available WC gateways

* @return array $gateways all WC gateways + offline gateway

*

* @since 1.0.0

*/

function pofwc_add_to_gateways( $gateways ) {

$gateways[] = 'WC_Gateway_Purchase_Order';

return $gateways;

}

add_filter( 'woocommerce_payment_gateways', 'pofwc_add_to_gateways' );


/**

* Adds plugin page links

*

* @param array $links all plugin links

* @return array $links all plugin links + our custom links

*

* @since 1.0.0

*/

function pofwc_purchase_order_gateway_plugin_links( $links ) {

$plugin_links = array(

'<a href="' . admin_url( 'admin.php?page=wc-settings&tab=checkout&section=purchase_order_gateway' ) . '">' .

__( 'Settings', 'pofwc' ) . '</a>'

);

return array_merge( $plugin_links, $links );

}

add_filter( 'plugin_action_links_' . plugin_basename( __FILE__ ),

'pofwc_purchase_order_gateway_plugin_links' );


/**

* Displays the purchase order information

*

* @param int $order_id The order ID

* @return string The formatted html

*

* @since 1.10.0

* @since 1.11.0 Added action hooks

* @since 1.12.0 Simplified to show only PO number and date

*/

function pofwc_show_invoice_address( $order_id ){

$order = wc_get_order( $order_id );

echo '<h2>' . __( 'Purchase order information', 'pofwc' ) . '</h2>';

echo '<p>';

echo '<strong>' . __( 'Purchase order number', 'pofwc' ) . ':</strong> ' .

$order->get_meta( '_purchase_order_number', true ) . '<br>';

$po_date = $order->get_meta( '_purchase_order_date', true );

if ( $po_date ) {

echo '<strong>' . __( 'Purchase order date', 'pofwc' ) . ':</strong> ' .

esc_html( $po_date ) . '<br>';

}

do_action( 'pofwc_account_display_after_po_form', $order );

echo '</p>';

}

add_action( 'woocommerce_view_order', 'pofwc_show_invoice_address', 20, 1 );


/**

* CRITICAL: Fix for PO Data Not Saving

* This hook ensures PO data is saved properly during checkout

*

* @since 1.12.7 Added to ensure PO data saving

*/

function pofwc_save_po_data_on_checkout( $order_id ) {

// Only process if this is a purchase order payment

$order = wc_get_order( $order_id );

if ( ! $order || $order->get_payment_method() !== 'purchase_order_gateway' ) {

return;

}

// Check if PO data is already saved (to avoid duplicating)

$existing_po_number = $order->get_meta( '_purchase_order_number', true );

if ( ! empty( $existing_po_number ) ) {

return; // Data already saved

}

// Save PO data from POST if it exists

if ( isset( $_POST['purchase-order-number'] ) && ! empty( trim( $_POST['purchase-order-number'] ) ) ) {

$order->update_meta_data( '_purchase_order_number', sanitize_text_field( $_POST['purchase-order-number'] ) );

}

if ( isset( $_POST['purchase-order-date'] ) && ! empty( trim( $_POST['purchase-order-date'] ) ) ) {

$order->update_meta_data( '_purchase_order_date', sanitize_text_field( $_POST['purchase-order-date'] ) );

}

// Save the order to ensure meta data is persisted

$order->save();

}

add_action( 'woocommerce_checkout_order_processed', 'pofwc_save_po_data_on_checkout', 10, 1 );


/**

* Debug function for troubleshooting (only in debug mode)

* Enable this if you need to troubleshoot issues

*

* @since 1.12.7 Enhanced debugging

*/

function pofwc_debug_order_processing( $order_id ) {

if ( ! WP_DEBUG ) {

return; // Only run in debug mode

}

$order = wc_get_order( $order_id );

if ( $order ) {

error_log( sprintf(

'PO Debug - Order ID: %d, Payment Method: %s, Status: %s, PO Number: %s, PO Date: %s, Time: %s',

$order_id,

$order->get_payment_method(),

$order->get_status(),

$order->get_meta( '_purchase_order_number', true ),

$order->get_meta( '_purchase_order_date', true ),

current_time( 'Y-m-d H:i:s' )

) );

}

}

// Uncomment the lines below if you need debugging

// add_action( 'woocommerce_checkout_order_processed', 'pofwc_debug_order_processing', 30, 1 );

// add_action( 'woocommerce_order_status_changed', 'pofwc_debug_order_processing', 30, 1 );


// Load corporate user management functions

require_once dirname( __FILE__ ) . '/includes/corporate-user-functions.php';


// Require files

require dirname( __FILE__ ) . '/class-purchase-order-gateway.php';



class-purchase-order-gateway.php


<?php

if ( ! defined( 'ABSPATH' ) ) {

exit; // Came directly here? Vamoose.

}


use Automattic\WooCommerce\Utilities\OrderUtil;


add_action( 'plugins_loaded', 'pofwc_purchase_order_gateway_init', 11 );


function pofwc_purchase_order_gateway_init() {

if ( class_exists( 'WC_Payment_Gateway' ) ) {

class WC_Gateway_Purchase_Order extends WC_Payment_Gateway {


/**

* @since 1.10.1 Declared properties

* @since 1.12.0 Simplified properties

* @since 1.12.5 Added corporate user restriction

* @since 1.12.7 Enhanced for better PO data handling

*/

public $title;

public $status;

public $description;

public $instructions;

public $po_number_label;

public $po_number_required;

public $po_date_label;

public $po_date_required;

public $po_show_in_email;


/**

* Constructor for the gateway

*

* @access public

*

* @since 1.0.0

* @since 1.4.0 Added field settings

* @since 1.12.0 Simplified for PO number and date only

* @since 1.12.5 Added corporate user support

* @since 1.12.7 Enhanced for better reliability

*/

public function __construct() {

$this->id = 'purchase_order_gateway';

$this->icon = apply_filters( 'woocommerce_offline_icon', '' );

$this->has_fields = true;

$this->method_title = __( 'Purchase Order', 'pofwc' );

$this->method_description = __( 'Allows purchase order payments for corporate users only.', 'pofwc' );


// Load the settings.

$this->init_form_fields();

$this->init_settings();


// Define user set variables

$this->title = $this->get_option( 'title' );

$this->status = $this->get_option( 'status' );

$this->description = $this->get_option( 'description' );

$this->instructions = $this->get_option( 'instructions', $this->description );

$this->po_number_label = $this->get_option( 'po_number_label' );

$this->po_number_required = $this->get_option( 'po_number_required' );

$this->po_date_label = $this->get_option( 'po_date_label' );

$this->po_date_required = $this->get_option( 'po_date_required' );

$this->po_show_in_email = $this->get_option( 'po_show_in_email' );


// Actions

add_action( 'woocommerce_update_options_payment_gateways_' . $this->id,

array( $this, 'process_admin_options' ) );

add_action( 'woocommerce_thankyou_' . $this->id, array( $this, 'pofwc_thankyou' ) );


// Emails

add_action( 'woocommerce_email_after_order_table',

array( $this, 'pofwc_email_instructions' ), 10, 3 );

add_filter( 'woocommerce_email_order_meta_fields',

array( $this, 'pofwc_email_order_meta_fields' ), 10, 3 );


// Display meta data

add_action( 'woocommerce_admin_order_data_after_billing_address',

array( $this, 'pofwc_display_purchase_order_meta' ), 10, 1 );

add_action( 'woocommerce_thankyou',

array( $this, 'pofwc_add_po_number_to_order_received_page' ), 1 );


// Other

add_filter( 'wc_stripe_validate_checkout_required_fields',

array( $this, 'pofwc_stripe_validate_checkout_unset_gateways_required_fields' ) );

}


/**

* Check if the gateway is available for use

* Corporate user restriction added

*

* @return bool

* @since 1.12.5 Added corporate user restriction

*/

public function is_available() {

$available = parent::is_available();

// Check if user is logged in

if ( ! is_user_logged_in() ) {

return false;

}

$user_id = get_current_user_id();

// Check if user is corporate user (auto-detected based on corporate info)

$is_corporate = get_user_meta( $user_id, 'is_corporate_user', true );

if ( ! $is_corporate ) {

return false;

}

// Check if purchase order gateway is enabled for this corporate user

$enabled_gateways = get_user_meta( $user_id, 'enabled_payment_gateways', true );

if ( ! is_array( $enabled_gateways ) || ! in_array( $this->id, $enabled_gateways ) ) {

return false;

}

return $available;

}


/**

* Gets WooCommerce order statuses

*

* @since 1.8.5 Added ability to select from all order statuses, including custom statuses

*/

private function get_order_statuses(){

$statuses = wc_get_order_statuses();

return $statuses;

}


/**

* Initialises Gateway Settings Form Fields

*

* @access public

*

* @return string The formatted HTML

*

* @since 1.0.0

* @since 1.12.0 Simplified form fields to PO number and date only

* @since 1.12.5 Updated description for corporate user restriction

* @since 1.12.7 Enhanced default status setting

*/

public function init_form_fields() {

$statuses = $this->get_order_statuses();

$this->form_fields = apply_filters( 'wc_offline_form_fields', array(

'enabled' => array(

'title' => __( 'Enable/Disable', 'pofwc' ),

'type' => 'checkbox',

'label' => __( 'Enable purchase order payment', 'pofwc' ),

'default' => 'no',

'description' => __( 'This payment method will only be available to corporate users who have been granted access by administrators.', 'pofwc' ),

'desc_tip' => true,

),

'status' => array(

'title' => __( 'Checkout order status', 'pofwc' ),

'type' => 'select',

'options' => $statuses,

'description' => __( 'This controls the order status after checkout.', 'pofwc' ),

'desc_tip' => true,

'default' => 'wc-pending-po-verification',

),

'title' => array(

'title' => __( 'Title', 'pofwc' ),

'type' => 'text',

'description' => __( 'This controls the title for the payment method the customer sees during checkout.', 'pofwc' ),

'default' => __( 'Purchase order', 'pofwc' ),

'desc_tip' => true,

),

'description' => array(

'title' => __( 'Description', 'pofwc' ),

'type' => 'textarea',

'description' => __( 'Payment method description that the customer will see on your checkout.', 'pofwc' ),

'default' => __( 'Please provide your purchase order details.', 'pofwc' ),

'desc_tip' => true,

),

'instructions' => array(

'title' => __( 'Instructions', 'pofwc' ),

'type' => 'textarea',

'description' => __( 'Instructions that will be added to the thank you page and emails.', 'pofwc' ),

'default' => 'Thank you for your purchase order. We will process your order shortly.',

'desc_tip' => true,

),

'po_number_label' => array(

'title' => __( 'Purchase order number label', 'pofwc' ),

'type' => 'text',

'description' => __( 'This controls the label of the purchase order number field the customer sees during checkout.', 'pofwc' ),

'default' => __( 'Purchase order number', 'pofwc' ),

'desc_tip' => true,

),

'po_number_required' => array(

'title' => __( 'Purchase order number', 'pofwc' ),

'type' => 'checkbox',

'label' => __( 'Is purchase order number a required field?', 'pofwc' ),

'default' => 'yes'

),

'po_date_label' => array(

'title' => __( 'Purchase order date label', 'pofwc' ),

'type' => 'text',

'description' => __( 'This controls the label of the purchase order date field the customer sees during checkout.', 'pofwc' ),

'default' => __( 'Purchase order date', 'pofwc' ),

'desc_tip' => true,

),

'po_date_required' => array(

'title' => __( 'Purchase order date', 'pofwc' ),

'type' => 'checkbox',

'label' => __( 'Is purchase order date a required field?', 'pofwc' ),

'default' => 'yes'

),

'po_show_in_email' => array(

'title' => __( 'Show purchase order details in order emails', 'pofwc' ),

'type' => 'checkbox',

'label' => __( 'Show details', 'pofwc' ),

'default' => 'yes',

'description' => __( 'Choose to display the purchase order details in order emails. Default is checked.', 'pofwc' ),

'desc_tip' => true,

),

) );

}


/**

* Defines output for the order received page

*

* @access public

*

* @return string The formatted HTML

*

* @since 1.0.0

*/

public function pofwc_thankyou() {

if ( $this->instructions ) {

echo wp_kses_post( wpautop( wptexturize( $this->instructions ) ) );

}

}


/**

* Adds content to the WC emails

*

* @access public

*

* @param WC_Order $order

* @param bool $sent_to_admin

* @param bool $plain_text

*

* @since 1.0.0

* @since 1.8.1 Added wp_kses_post() to output

*/

public function pofwc_email_instructions( $order, $sent_to_admin, $plain_text = false ) {

if ( $this->instructions && ! $sent_to_admin && $this->id === $order->get_payment_method() && $order->has_status( $this->status ) ) {

echo wp_kses_post( wpautop( wptexturize( $this->instructions ) ) . PHP_EOL );

}

}


/**

* CRITICAL FIX: Processes the payment and returns the result

* Enhanced to ensure PO data is properly saved and status is correctly set

*

* @access public

*

* @param int $order_id The order ID

* @return array Redirects to thankyou page with relevant data

*

* @since 1.0.0

* @since 1.12.0 Simplified to handle only PO number and date, removed zero-total auto-complete

* @since 1.12.4 Updated to use pending-po-verification status for all PO orders

* @since 1.12.7 CRITICAL FIX - Added proper order saving to ensure PO data persists

*/

public function process_payment( $order_id ) {

$order = wc_get_order( $order_id );


// CRITICAL: Add order meta data FIRST and validate

$po_number = '';

$po_date = '';

if( isset( $_POST['purchase-order-number'] ) && trim( $_POST['purchase-order-number'] ) != '' ){

$po_number = sanitize_text_field( $_POST['purchase-order-number'] );

$order->update_meta_data( '_purchase_order_number', $po_number );

}

if( isset( $_POST['purchase-order-date'] ) && trim( $_POST['purchase-order-date'] ) != '' ){

$po_date = sanitize_text_field( $_POST['purchase-order-date'] );

$order->update_meta_data( '_purchase_order_date', $po_date );

}


// CRITICAL FIX: Save the order IMMEDIATELY after updating meta data

// This ensures the PO data is persisted before any status changes

$order->save();


// Verify the data was saved (for debugging purposes)

if ( WP_DEBUG ) {

error_log( sprintf(

'PO Gateway Debug - Order ID: %d, PO Number: %s, PO Date: %s',

$order_id,

$order->get_meta( '_purchase_order_number', true ),

$order->get_meta( '_purchase_order_date', true )

) );

}


// Set status to pending PO verification for ALL purchase order payments

$order->update_status( 'pending-po-verification', 'Purchase order received - awaiting verification.' );


// Reduce stock levels.

wc_reduce_stock_levels( $order_id );


// Remove cart.

WC()->cart->empty_cart();


// Return thankyou redirect.

return array(

'result' => 'success',

'redirect' => $this->get_return_url( $order )

);

}


/**

* Adds form fields to checkout gateway

*

* @access public

*

* @return string The formatted HTML

*

* @since 1.0.0

* @since 1.12.0 Simplified to show only PO number and date fields

* @since 1.12.7 Enhanced field validation

*/

public function payment_fields(){

?>

<p class="form-row form-row-wide">

<?php echo $this->description; ?>

</p>

<?php

// Purchase Order Number Field

$po_number_label = ( $this->po_number_label != '' ) ? $this->po_number_label : __( 'Purchase order number', 'pofwc' );

$po_number_required_text = ( $this->po_number_required == 'yes' ) ? '<span class="required">*</span>' : '';

$po_number_required_class = ( $this->po_number_required == 'yes' ) ? 'validate-required' : '';

?>

<p class="form-row form-row-wide <?php echo $po_number_required_class; ?>">

<label for="purchase-order-number"><?php echo esc_html( $po_number_label ); ?><?php echo $po_number_required_text; ?></label>

<input type="text" id="purchase-order-number" name="purchase-order-number" class="input-text" placeholder="<?php echo esc_attr( $po_number_label ); ?>">

</p>


<?php

// Purchase Order Date Field

$po_date_label = ( $this->po_date_label != '' ) ? $this->po_date_label : __( 'Purchase order date', 'pofwc' );

$po_date_required_text = ( $this->po_date_required == 'yes' ) ? '<span class="required">*</span>' : '';

$po_date_required_class = ( $this->po_date_required == 'yes' ) ? 'validate-required' : '';

?>

<p class="form-row form-row-wide <?php echo $po_date_required_class; ?>">

<label for="purchase-order-date"><?php echo esc_html( $po_date_label ); ?><?php echo $po_date_required_text; ?></label>

<input type="date" id="purchase-order-date" name="purchase-order-date" class="input-text" placeholder="<?php echo esc_attr( $po_date_label ); ?>">

</p>


<?php do_action( 'pofwc_form_after_po_form' ); ?>

<script type="text/javascript">

jQuery(document).ready(function($) {

// Enhanced validation for PO fields

$('body').on('checkout_error', function() {

// Highlight any empty required PO fields

if ($('#purchase-order-number').hasClass('validate-required') && !$('#purchase-order-number').val()) {

$('#purchase-order-number').addClass('woocommerce-invalid');

}

if ($('#purchase-order-date').hasClass('validate-required') && !$('#purchase-order-date').val()) {

$('#purchase-order-date').addClass('woocommerce-invalid');

}

});

// Clear validation styling on input

$('#purchase-order-number, #purchase-order-date').on('input change', function() {

$(this).removeClass('woocommerce-invalid');

});

});

</script>

<?php

}


/**

* ENHANCED: Validates gateway checkout form fields

* Better validation with specific error messages

*

* @access public

*

* @return mixed Boolean or formatted HTML string

*

* @since 1.0.0

* @since 1.12.0 Simplified validation for PO number and date only

* @since 1.12.7 Enhanced validation with better error messages

*/

public function validate_fields() {

$valid = true;

// Check if required fields are set, if not add an error

if ( $this->po_number_required == 'yes' && ( ! isset( $_POST['purchase-order-number'] ) || empty( trim( $_POST['purchase-order-number'] ) ) ) ){

wc_add_notice( __( 'Purchase Order Number is required. Please enter a valid purchase order number.', 'pofwc' ), 'error' );

$valid = false;

}

if ( $this->po_date_required == 'yes' && ( ! isset( $_POST['purchase-order-date'] ) || empty( trim( $_POST['purchase-order-date'] ) ) ) ){

wc_add_notice( __( 'Purchase Order Date is required. Please select a valid date.', 'pofwc' ), 'error' );

$valid = false;

}

// Additional validation for PO date format if provided

if ( isset( $_POST['purchase-order-date'] ) && ! empty( trim( $_POST['purchase-order-date'] ) ) ) {

$date = trim( $_POST['purchase-order-date'] );

if ( ! $this->validate_date_format( $date ) ) {

wc_add_notice( __( 'Purchase Order Date format is invalid. Please use a valid date format.', 'pofwc' ), 'error' );

$valid = false;

}

}

return $valid;

}

/**

* NEW: Validate date format

*

* @since 1.12.7 Added date format validation

*/

private function validate_date_format( $date ) {

$d = DateTime::createFromFormat( 'Y-m-d', $date );

return $d && $d->format( 'Y-m-d' ) === $date;

}


/**

* Bypasses the Stripe plugin's validation of fields

*

* @access public

*

* @param array $required_fields The required fields

*

* @since 1.2.0

* @since 1.12.0 Simplified for PO number and date only

*/

public function pofwc_stripe_validate_checkout_unset_gateways_required_fields( $required_fields ){

if( isset( $required_fields['purchase-order-number'] ) ){

unset( $required_fields['purchase-order-number'] );

}

if( isset( $required_fields['purchase-order-date'] ) ){

unset( $required_fields['purchase-order-date'] );

}

return $required_fields;

}


/**

* ENHANCED: Displays meta data in order screen

* Better formatting and error handling

*

* @access public

*

* @return string The formatted HTML

*

* @since 1.0.0

* @since 1.12.0 Simplified to show only PO number and date

* @since 1.12.7 Enhanced with better formatting

*/

public function pofwc_display_purchase_order_meta(){

$order = wc_get_order( get_the_ID() );

// Ensure we have a valid order and it's a PO order

if ( ! $order || $order->get_payment_method() !== 'purchase_order_gateway' ) {

return;

}

$po_number = $order->get_meta('_purchase_order_number', true );

$po_date = $order->get_meta('_purchase_order_date', true );

// Only display if we have PO data

if ( $po_number || $po_date ) {

echo '<div class="pofwc-admin-order-meta">';

echo '<h3>' . __( 'Purchase Order Information', 'pofwc' ) . '</h3>';

echo '<div class="pofwc-po-details">';

if ( $po_number ) {

echo '<p><strong>' . __( 'Purchase Order Number:', 'pofwc' ) . '</strong> ' . esc_html( $po_number ) . '</p>';

}

if ( $po_date ) {

// Format the date nicely

$formatted_date = date_i18n( get_option( 'date_format' ), strtotime( $po_date ) );

echo '<p><strong>' . __( 'Purchase Order Date:', 'pofwc' ) . '</strong> ' . esc_html( $formatted_date ) . '</p>';

}

do_action( 'pofwc_admin_display_after_po_form', $order );

echo '</div>';

echo '</div>';

// Add some styling

echo '<style>

.pofwc-admin-order-meta {

background: #f9f9f9;

border: 1px solid #ddd;

border-radius: 4px;

padding: 15px;

margin-top: 20px;

}

.pofwc-admin-order-meta h3 {

margin-top: 0;

color: #0073aa;

}

.pofwc-po-details p {

margin: 5px 0;

}

</style>';

}

}


/**

* ENHANCED: Displays the purchase order number on the order-received page

* Better formatting and data handling

*

* @access public

*

* @return string The formatted HTML

*

* @since 1.7.4

* @since 1.12.0 Simplified to show only PO number and date

* @since 1.12.7 Enhanced formatting

*/

public function pofwc_add_po_number_to_order_received_page() {

global $wp;

$order_id = absint( $wp->query_vars['order-received'] );

$order = wc_get_order( $order_id );

// Ensure we have a valid order and it's a PO order

if ( ! $order || $order->get_payment_method() !== 'purchase_order_gateway' ) {

return;

}

$purchase_order_number = $order->get_meta('_purchase_order_number', true );

$po_date = $order->get_meta('_purchase_order_date', true );

if ( $purchase_order_number || $po_date ) {

echo '<div class="pofwc-thankyou-po-info">';

if ( $purchase_order_number ) {

echo '<p><strong>' . __( 'Purchase Order Number', 'pofwc' ) . ':</strong> ' . esc_html( $purchase_order_number ) . '</p>';

}

if ( $po_date ) {

$formatted_date = date_i18n( get_option( 'date_format' ), strtotime( $po_date ) );

echo '<p><strong>' . __( 'Purchase Order Date', 'pofwc' ) . ':</strong> ' . esc_html( $formatted_date ) . '</p>';

}

do_action( 'pofwc_thankyou_display_after_po_form', $order );

echo '</div>';

// Add styling

echo '<style>

.pofwc-thankyou-po-info {

background: #e8f4f8;

border: 1px solid #0073aa;

border-radius: 4px;

padding: 15px;

margin: 20px 0;

}

.pofwc-thankyou-po-info p {

margin: 5px 0;

}

</style>';

}

}


/**

* ENHANCED: Adds the purchase order number to the order emails

* Better data handling and formatting

*

* @access public

*

* @param array $fields The order meta fields

* @param bool $sent_to_admin Send email to admin as well as customer?

* @param object $order The order object

*

* @return array $fields The updated order meta fields

*

* @since 1.7.4

* @since 1.12.0 Simplified to show only PO number and date

* @since 1.12.7 Enhanced with better data handling

*/

public function pofwc_email_order_meta_fields( $fields, $sent_to_admin, $order ) {

// Only show if admin setting is enabled and it's a PO order

if( $this->po_show_in_email == 'yes' && $order->get_payment_method() === 'purchase_order_gateway' ){

$purchase_order_number = $order->get_meta( '_purchase_order_number', true );

$purchase_order_date = $order->get_meta( '_purchase_order_date', true );

if ( $purchase_order_number ) {

$fields['purchase_order_number'] = array(

'label' => __( 'Purchase Order Number', 'pofwc' ),

'value' => esc_html( $purchase_order_number )

);

}

if ( $purchase_order_date ) {

$formatted_date = date_i18n( get_option( 'date_format' ), strtotime( $purchase_order_date ) );

$fields['purchase_order_date'] = array(

'label' => __( 'Purchase Order Date', 'pofwc' ),

'value' => esc_html( $formatted_date )

);

}

}

return $fields;

}

}

}

}


class-po-verification-email.php


<?php

/**

* Purchase Order Verification Email Class

*

* This file should be placed in your plugin folder alongside purchase-orders-for-woocommerce.php

*

* @package PurchaseOrdersForWooCommerce

* @version 1.12.4

* @since 1.12.4

*/


if ( ! defined( 'ABSPATH' ) ) {

exit; // Exit if accessed directly

}


if ( ! class_exists( 'WC_PO_Verification_Email' ) ) :


/**

* Purchase Order Verification Email

*

* Sends email to customer when order status changes to "pending-po-verification"

*

* @class WC_PO_Verification_Email

* @extends WC_Email

*/

class WC_PO_Verification_Email extends WC_Email {


/**

* Constructor.

*/

public function __construct() {

$this->id = 'po_verification';

$this->title = __( 'Purchase Order Verification', 'pofwc' );

$this->description = __( 'Purchase order verification emails are sent to customers when their order is received and awaiting PO verification.', 'pofwc' );

$this->template_html = 'emails/po-verification.php';

$this->template_plain = 'emails/plain/po-verification.php';

// Set template base to look in theme first

$this->template_base = trailingslashit( get_template_directory() ) . 'woocommerce/';

// Set placeholders

$this->placeholders = array(

'{order_date}' => '',

'{order_number}' => '',

'{site_title}' => $this->get_blogname(),

);


// Call parent constructor.

parent::__construct();


// This is a customer email

$this->customer_email = true;

}


/**

* Get email subject.

*

* @return string

*/

public function get_default_subject() {

return __( 'Your order #{order_number} is awaiting purchase order verification', 'pofwc' );

}


/**

* Get email heading.

*

* @return string

*/

public function get_default_heading() {

return __( 'Purchase Order Received - Verification Required', 'pofwc' );

}


/**

* Trigger the sending of this email.

*

* @param int $order_id The order ID.

* @param WC_Order|false $order Order object.

*/

public function trigger( $order_id, $order = false ) {

$this->setup_locale();


if ( $order_id && ! is_a( $order, 'WC_Order' ) ) {

$order = wc_get_order( $order_id );

}


if ( is_a( $order, 'WC_Order' ) ) {

$this->object = $order;

$this->recipient = $this->object->get_billing_email();

$this->placeholders['{order_date}'] = wc_format_datetime( $this->object->get_date_created() );

$this->placeholders['{order_number}'] = $this->object->get_order_number();

}


if ( $this->is_enabled() && $this->get_recipient() ) {

$this->send( $this->get_recipient(), $this->get_subject(), $this->get_content(), $this->get_headers(), $this->get_attachments() );

}


$this->restore_locale();

}


/**

* Get content html.

*

* @return string

*/

public function get_content_html() {

return wc_get_template_html(

$this->template_html,

array(

'order' => $this->object,

'email_heading' => $this->get_heading(),

'additional_content' => $this->get_additional_content(),

'sent_to_admin' => false,

'plain_text' => false,

'email' => $this,

),

'woocommerce/',

$this->template_base

);

}


/**

* Get content plain.

*

* @return string

*/

public function get_content_plain() {

return wc_get_template_html(

$this->template_plain,

array(

'order' => $this->object,

'email_heading' => $this->get_heading(),

'additional_content' => $this->get_additional_content(),

'sent_to_admin' => false,

'plain_text' => true,

'email' => $this,

),

'woocommerce/',

$this->template_base

);

}


/**

* Initialize settings form fields.

*/

public function init_form_fields() {

$this->form_fields = array(

'enabled' => array(

'title' => __( 'Enable/Disable', 'woocommerce' ),

'type' => 'checkbox',

'label' => __( 'Enable this email notification', 'woocommerce' ),

'default' => 'yes',

),

'subject' => array(

'title' => __( 'Subject', 'woocommerce' ),

'type' => 'text',

'desc_tip' => true,

'description' => sprintf( __( 'Available placeholders: %s', 'woocommerce' ), '<code>{site_title}, {order_date}, {order_number}</code>' ),

'placeholder' => $this->get_default_subject(),

'default' => '',

),

'heading' => array(

'title' => __( 'Email heading', 'woocommerce' ),

'type' => 'text',

'desc_tip' => true,

'description' => sprintf( __( 'Available placeholders: %s', 'woocommerce' ), '<code>{site_title}, {order_date}, {order_number}</code>' ),

'placeholder' => $this->get_default_heading(),

'default' => '',

),

'additional_content' => array(

'title' => __( 'Additional content', 'woocommerce' ),

'description' => __( 'Text to appear below the main email content.', 'woocommerce' ) . ' ' . sprintf( __( 'Available placeholders: %s', 'woocommerce' ), '<code>{site_title}, {order_date}, {order_number}</code>' ),

'css' => 'width:400px; height: 75px;',

'placeholder' => __( 'N/A', 'woocommerce' ),

'type' => 'textarea',

'default' => $this->get_default_additional_content(),

'desc_tip' => true,

),

'email_type' => array(

'title' => __( 'Email type', 'woocommerce' ),

'type' => 'select',

'description' => __( 'Choose which format of email to send.', 'woocommerce' ),

'default' => 'html',

'class' => 'email_type wc-enhanced-select',

'options' => $this->get_email_type_options(),

'desc_tip' => true,

),

);

}


/**

* Get default additional content.

*

* @return string

*/

public function get_default_additional_content() {

return __( 'We have received your purchase order and it is currently being verified. You will receive another email once your order is confirmed.', 'pofwc' );

}

}


endif;


includes/corporate-user-functions.php


<?php

/**

* Corporate User Functions

*

* @package Purchase_Orders_WooCommerce

* @since 1.12.5

*/


// Prevent direct access

if ( ! defined( 'ABSPATH' ) ) {

exit;

}


/**

* Add PO information after order number in My Account Orders

* NEW: Shows PO details in customer order history

*/

add_action( 'woocommerce_my_account_my_orders_column_order-number', 'pofwc_add_po_info_to_my_orders', 20 );


function pofwc_add_po_info_to_my_orders( $order ) {

// Check if this order used purchase order gateway

if ( $order->get_payment_method() === 'purchase_order_gateway' ) {

$po_number = $order->get_meta( '_purchase_order_number', true );

$po_date = $order->get_meta( '_purchase_order_date', true );

if ( $po_number ) {

echo '<br><small style="color: #666;"><strong>' . __( 'Purchase Order:', 'pofwc' ) . '</strong></small>';

echo '<br><small style="color: #666;">' . __( 'Number:', 'pofwc' ) . ' ' . esc_html( $po_number ) . '</small>';

if ( $po_date ) {

echo '<br><small style="color: #666;">' . __( 'Date:', 'pofwc' ) . ' ' . esc_html( $po_date ) . '</small>';

}

}

}

}


/**

* Restrict payment gateways for corporate users

* NEW: Filters available payment methods based on user permissions

*/

add_filter( 'woocommerce_available_payment_gateways', 'pofwc_restrict_payment_gateways_for_corporate_users' );


function pofwc_restrict_payment_gateways_for_corporate_users( $available_gateways ) {

// Only on frontend checkout/cart and for logged in users

// Don't filter in admin or when getting all gateways for settings

if ( is_admin() || ! is_user_logged_in() || ! ( is_checkout() || is_cart() || wp_doing_ajax() ) ) {

return $available_gateways;

}

$user_id = get_current_user_id();

$is_corporate = get_user_meta( $user_id, 'is_corporate_user', true );

if ( $is_corporate ) {

$enabled_gateways = get_user_meta( $user_id, 'enabled_payment_gateways', true );

if ( ! is_array( $enabled_gateways ) ) {

$enabled_gateways = array();

}

// Filter available gateways to only show enabled ones for this corporate user

foreach ( $available_gateways as $gateway_id => $gateway ) {

if ( ! in_array( $gateway_id, $enabled_gateways ) ) {

unset( $available_gateways[$gateway_id] );

}

}

}

return $available_gateways;

}


/**

* Auto-detect corporate users based on checkout data

* NEW: Automatically mark users as corporate during checkout

*/

add_action( 'woocommerce_checkout_update_user_meta', 'pofwc_auto_detect_corporate_user' );


function pofwc_auto_detect_corporate_user( $user_id ) {

// Check if user has corporate information in checkout

$company = WC()->checkout->get_value( 'billing_company' );

if ( ! empty( $company ) ) {

// Auto-mark as corporate user if they provided company information

update_user_meta( $user_id, 'is_corporate_user', '1' );

}

}


/**

* Add admin notice for corporate users without payment gateway access

* NEW: Warning for admins about corporate users without gateways

*/

add_action( 'admin_notices', 'pofwc_corporate_user_gateway_notice' );


function pofwc_corporate_user_gateway_notice() {

$screen = get_current_screen();

if ( $screen->id !== 'user-edit' && $screen->id !== 'profile' ) {

return;

}

// Check if we're editing a user

$user_id = isset( $_GET['user_id'] ) ? intval( $_GET['user_id'] ) : get_current_user_id();

$is_corporate = get_user_meta( $user_id, 'is_corporate_user', true );

$enabled_gateways = get_user_meta( $user_id, 'enabled_payment_gateways', true );

if ( $is_corporate && ( empty( $enabled_gateways ) || ! is_array( $enabled_gateways ) ) ) {

echo '<div class="notice notice-warning"><p><strong>' . __( 'Corporate User Notice:', 'pofwc' ) . '</strong> ' . __( 'This corporate user has no payment gateways enabled. Please select payment gateways in the Payment Gateway Settings section below.', 'pofwc' ) . '</p></div>';

}

}


/**

* Add corporate status indicator to users list

* NEW: Shows corporate status in admin users list

*/

add_filter( 'manage_users_columns', 'pofwc_add_corporate_column' );


function pofwc_add_corporate_column( $columns ) {

$columns['corporate_user'] = __( 'Corporate User', 'pofwc' );

return $columns;

}


/**

* Display corporate status in users list

*/

add_action( 'manage_users_custom_column', 'pofwc_show_corporate_column_content', 10, 3 );


function pofwc_show_corporate_column_content( $value, $column_name, $user_id ) {

if ( $column_name == 'corporate_user' ) {

$is_corporate = get_user_meta( $user_id, 'is_corporate_user', true );

if ( $is_corporate ) {

return '<span style="color: green;">✓ ' . __( 'Yes', 'pofwc' ) . '</span>';

} else {

return '<span style="color: #ccc;">– ' . __( 'No', 'pofwc' ) . '</span>';

}

}

return $value;

}


/**

* Add bulk action to mark users as corporate

* NEW: Bulk operations for corporate users

*/

add_filter( 'bulk_actions-users', 'pofwc_add_corporate_bulk_actions' );


function pofwc_add_corporate_bulk_actions( $bulk_actions ) {

$bulk_actions['mark_corporate'] = __( 'Mark as Corporate User', 'pofwc' );

$bulk_actions['unmark_corporate'] = __( 'Remove Corporate Status', 'pofwc' );

return $bulk_actions;

}


/**

* Handle bulk actions for corporate users

*/

add_filter( 'handle_bulk_actions-users', 'pofwc_handle_corporate_bulk_actions', 10, 3 );


function pofwc_handle_corporate_bulk_actions( $redirect_to, $doaction, $user_ids ) {

if ( $doaction !== 'mark_corporate' && $doaction !== 'unmark_corporate' ) {

return $redirect_to;

}

foreach ( $user_ids as $user_id ) {

if ( $doaction == 'mark_corporate' ) {

update_user_meta( $user_id, 'is_corporate_user', '1' );

} else {

delete_user_meta( $user_id, 'is_corporate_user' );

delete_user_meta( $user_id, 'enabled_payment_gateways' );

}

}

$redirect_to = add_query_arg( 'bulk_' . $doaction, count( $user_ids ), $redirect_to );

return $redirect_to;

}


/**

* Display bulk action notices

*/

add_action( 'admin_notices', 'pofwc_corporate_bulk_action_notices' );


function pofwc_corporate_bulk_action_notices() {

if ( ! empty( $_REQUEST['bulk_mark_corporate'] ) ) {

$count = intval( $_REQUEST['bulk_mark_corporate'] );

printf( '<div class="notice notice-success is-dismissible"><p>' .

_n( 'Marked %s user as corporate user.',

'Marked %s users as corporate users.',

$count, 'pofwc' ) . '</p></div>', $count );

}

if ( ! empty( $_REQUEST['bulk_unmark_corporate'] ) ) {

$count = intval( $_REQUEST['bulk_unmark_corporate'] );

printf( '<div class="notice notice-success is-dismissible"><p>' .

_n( 'Removed corporate status from %s user.',

'Removed corporate status from %s users.',

$count, 'pofwc' ) . '</p></div>', $count );

}

}


/**

* Add shortcode to display corporate user info

* NEW: Shortcode for displaying corporate information

*/

add_shortcode( 'corporate_user_info', 'pofwc_corporate_user_info_shortcode' );


function pofwc_corporate_user_info_shortcode( $atts ) {

if ( ! is_user_logged_in() ) {

return __( 'Please log in to view corporate information.', 'pofwc' );

}

$user_id = get_current_user_id();

$is_corporate = get_user_meta( $user_id, 'is_corporate_user', true );

if ( ! $is_corporate ) {

return __( 'You are not registered as a corporate user.', 'pofwc' );

}

$enabled_gateways = get_user_meta( $user_id, 'enabled_payment_gateways', true );

if ( ! is_array( $enabled_gateways ) ) {

$enabled_gateways = array();

}

$output = '<div class="corporate-user-info">';

$output .= '<h4>' . __( 'Corporate User Information', 'pofwc' ) . '</h4>';

$output .= '<p>' . __( 'Status: Corporate User', 'pofwc' ) . '</p>';

if ( ! empty( $enabled_gateways ) ) {

$output .= '<p>' . __( 'Available Payment Methods:', 'pofwc' ) . '</p>';

$output .= '<ul>';

if ( class_exists( 'WC_Payment_Gateways' ) ) {

$payment_gateways = WC_Payment_Gateways::instance();

$available_gateways = $payment_gateways->get_available_payment_gateways();

foreach ( $enabled_gateways as $gateway_id ) {

if ( isset( $available_gateways[$gateway_id] ) ) {

$output .= '<li>' . esc_html( $available_gateways[$gateway_id]->get_method_title() ) . '</li>';

}

}

}

$output .= '</ul>';

} else {

$output .= '<p>' . __( 'No payment methods currently available. Please contact administrator.', 'pofwc' ) . '</p>';

}

$output .= '</div>';

return $output;

}


/**

* Add CSS for corporate user elements

*/

add_action( 'wp_head', 'pofwc_corporate_user_styles' );


function pofwc_corporate_user_styles() {

echo '<style>

.corporate-user-info {

background: #f9f9f9;

border: 1px solid #ddd;

padding: 15px;

border-radius: 5px;

margin: 10px 0;

}

.corporate-user-info h4 {

margin-top: 0;

color: #0073aa;

}

.corporate-user-info ul {

margin: 10px 0;

padding-left: 20px;

}

</style>';

}


/**

* Enhanced corporate user detection based on existing fields

* NEW: Better integration with existing corporate fields

*/

add_action( 'profile_update', 'pofwc_enhanced_corporate_detection', 10, 1 );


function pofwc_enhanced_corporate_detection( $user_id ) {

// Check existing corporate fields

$company_name = get_user_meta( $user_id, 'pofwc_company_name', true );

$gst_number = get_user_meta( $user_id, 'pofwc_gst_number', true );

// Auto-detect corporate status based on existing fields

if ( ! empty( $company_name ) || ! empty( $gst_number ) ) {

update_user_meta( $user_id, 'is_corporate_user', '1' );

} else {

// Remove corporate status if no corporate info

delete_user_meta( $user_id, 'is_corporate_user' );

delete_user_meta( $user_id, 'enabled_payment_gateways' );

}

}