class-cmbird-purchase-admin.php
1 year ago
class-cmbird-purchase-automation.php
1 year ago
class-cmbird-purchase-order-email.php
1 year ago
class-cmbird-purchase-order.php
1 year ago
class-cmbird-rest-shop-purchase-controller.php
1 year ago
index.php
1 year ago
class-cmbird-purchase-order.php
460 lines
| 1 | <?php |
| 2 | |
| 3 | if ( ! defined( 'ABSPATH' ) ) { |
| 4 | exit; |
| 5 | } |
| 6 | |
| 7 | // Ensure WooCommerce is active |
| 8 | if ( ! class_exists( 'WC_Order' ) ) { |
| 9 | return; |
| 10 | } |
| 11 | |
| 12 | /** |
| 13 | * Purchase Order Class |
| 14 | * |
| 15 | * This class extends the WC_Order class to add custom functionality for purchase orders. |
| 16 | */ |
| 17 | |
| 18 | class CMBIRD_Purchase_Order extends WC_Order { |
| 19 | |
| 20 | public $order_type = 'shop_purchase'; |
| 21 | |
| 22 | public function __construct( $order_id = 0 ) { |
| 23 | parent::__construct( $order_id ); |
| 24 | $this->order_type = 'shop_purchase'; |
| 25 | // Custom initialization code for purchase orders can go here |
| 26 | } |
| 27 | |
| 28 | public function get_type() { |
| 29 | return 'shop_purchase'; |
| 30 | } |
| 31 | |
| 32 | // You can override or add methods for handling purchase orders |
| 33 | public function is_purchase() { |
| 34 | return true; |
| 35 | } |
| 36 | |
| 37 | public function remove_item( $item_id ) { |
| 38 | parent::remove_item( $item_id ); |
| 39 | parent::calculate_totals(); |
| 40 | } |
| 41 | |
| 42 | // update meta data |
| 43 | public function update_meta_data( $key, $value, $meta_id = 0 ) { |
| 44 | parent::update_meta_data( $key, $value, $meta_id ); |
| 45 | // Custom logic for updating meta data for purchase orders |
| 46 | } |
| 47 | } |
| 48 | |
| 49 | // Register the custom order type |
| 50 | function cmbird_register_shop_purchase_order_type() { |
| 51 | wc_register_order_type( |
| 52 | 'shop_purchase', |
| 53 | array( |
| 54 | 'labels' => array( |
| 55 | 'name' => __( 'Purchase Orders', 'commercebird' ), |
| 56 | 'singular_name' => __( 'Purchase Order', 'commercebird' ), |
| 57 | 'add_new' => _x( 'Add Purchase', 'custom post type setting', 'commercebird' ), |
| 58 | 'add_new_item' => _x( 'Add New Purchase', 'custom post type setting', 'commercebird' ), |
| 59 | 'edit' => _x( 'Edit', 'custom post type setting', 'commercebird' ), |
| 60 | 'edit_item' => _x( 'Edit Purchase', 'custom post type setting', 'commercebird' ), |
| 61 | 'new_item' => _x( 'New Purchase', 'custom post type setting', 'commercebird' ), |
| 62 | 'view' => _x( 'View Purchase', 'custom post type setting', 'commercebird' ), |
| 63 | 'view_item' => _x( 'View Purchase', 'custom post type setting', 'commercebird' ), |
| 64 | 'search_items' => __( 'Search Purchases', 'commercebird' ), |
| 65 | 'not_found_in_trash' => _x( 'No Purchases found in trash', 'custom post type setting', 'commercebird' ), |
| 66 | 'parent' => _x( 'Parent Purchases', 'custom post type setting', 'commercebird' ), |
| 67 | 'menu_name' => __( 'Purchases', 'commercebird' ), |
| 68 | ), |
| 69 | 'description' => __( 'This is where purchase orders are stored.', 'commercebird' ), |
| 70 | 'public' => false, |
| 71 | 'show_ui' => true, |
| 72 | 'capability_type' => 'shop_order', |
| 73 | 'map_meta_cap' => true, |
| 74 | 'publicly_queryable' => false, |
| 75 | 'exclude_from_search' => true, |
| 76 | 'show_in_menu' => current_user_can( 'manage_woocommerce' ) ? 'woocommerce' : true, |
| 77 | 'hierarchical' => false, |
| 78 | 'show_in_nav_menus' => false, |
| 79 | 'rewrite' => false, |
| 80 | 'query_var' => false, |
| 81 | 'supports' => array( 'title', 'comments', 'custom-fields' ), |
| 82 | 'has_archive' => false, |
| 83 | // wc_register_order_type() params |
| 84 | 'exclude_from_orders_screen' => true, |
| 85 | 'exclude_from_order_webhooks' => true, |
| 86 | 'exclude_from_order_count' => true, |
| 87 | 'exclude_from_order_views' => true, |
| 88 | 'exclude_from_order_reports' => true, |
| 89 | 'exclude_from_order_sales_reports' => true, |
| 90 | 'add_order_meta_boxes' => true, |
| 91 | 'class_name' => 'CMBIRD_Purchase_Order', |
| 92 | ) |
| 93 | ); |
| 94 | |
| 95 | // register custom statuses |
| 96 | global $wc_order_statuses; |
| 97 | $statuses = cmbird_get_purchase_order_statuses(); |
| 98 | foreach ( $statuses as $status => $label ) { |
| 99 | register_post_status( |
| 100 | $status, |
| 101 | array( |
| 102 | 'label' => $label, |
| 103 | 'public' => true, |
| 104 | 'exclude_from_search' => false, |
| 105 | 'show_in_admin_all_list' => true, |
| 106 | 'show_in_admin_status_list' => true, |
| 107 | 'label_count' => _n_noop( $label . ' <span class="count">(%s)</span>', $label . ' <span class="count">(%s)</span>', 'commercebird' ), |
| 108 | 'post_type' => array( 'shop_order', 'shop_purchase' ), |
| 109 | ) |
| 110 | ); |
| 111 | } |
| 112 | // Create the "vendor" role |
| 113 | add_role( |
| 114 | 'vendor', |
| 115 | __( 'Vendor', 'commercebird' ), |
| 116 | array( |
| 117 | 'read' => true, |
| 118 | ) |
| 119 | ); |
| 120 | } |
| 121 | // Register our custom purchase order type after WC_Post_types::register_post_types() |
| 122 | add_action( 'init', 'cmbird_register_shop_purchase_order_type', 5 ); |
| 123 | |
| 124 | // Create array of Purchase Order Statuses |
| 125 | function cmbird_get_purchase_order_statuses() { |
| 126 | return array( |
| 127 | 'wc-awaiting-approval' => _x( 'Awaiting Approval', 'Order status', 'commercebird' ), |
| 128 | 'wc-approved' => _x( 'Approved', 'Order status', 'commercebird' ), |
| 129 | 'wc-part-received' => _x( 'Partially Received', 'Order status', 'commercebird' ), |
| 130 | 'wc-received' => _x( 'Received', 'Order status', 'commercebird' ), |
| 131 | ); |
| 132 | } |
| 133 | |
| 134 | // Load custom class for Purchase Orders |
| 135 | function cmbird_load_purchase_order_class( $order_classname, $order_type, $order_id ) { |
| 136 | if ( 'shop_purchase' === $order_type ) { |
| 137 | $order_classname = 'CMBIRD_Purchase_Order'; |
| 138 | } |
| 139 | return $order_classname; |
| 140 | } |
| 141 | add_filter( 'woocommerce_order_class', 'cmbird_load_purchase_order_class', 10, 3 ); |
| 142 | |
| 143 | /** |
| 144 | * Custom order statuses for Purchase Orders |
| 145 | * @param mixed $order_statuses |
| 146 | * @return array |
| 147 | * @since 1.0.0 |
| 148 | */ |
| 149 | // Add custom order statuses for 'shop_purchase' |
| 150 | function cmbird_custom_order_statuses( $order_statuses ) { |
| 151 | // Add custom statuses once, outside the loop |
| 152 | $custom_statuses = array( |
| 153 | 'wc-awaiting-approval' => 'Awaiting Approval', |
| 154 | 'wc-approved' => 'Approved', |
| 155 | 'wc-part-received' => 'Partially Received', |
| 156 | 'wc-received' => 'Received', |
| 157 | ); |
| 158 | |
| 159 | return array_merge( $order_statuses, $custom_statuses ); |
| 160 | } |
| 161 | add_filter( 'wc_order_statuses', 'cmbird_custom_order_statuses' ); |
| 162 | |
| 163 | function cmbird_add_valid_custom_statuses_for_shop_purchase( $statuses ) { |
| 164 | $statuses[] = 'wc-awaiting-approval'; |
| 165 | $statuses[] = 'wc-approved'; |
| 166 | $statuses[] = 'wc-part-received'; |
| 167 | $statuses[] = 'wc-received'; |
| 168 | return $statuses; |
| 169 | } |
| 170 | add_filter( 'woocommerce_register_shop_order_post_statuses', 'cmbird_add_valid_custom_statuses_for_shop_purchase' ); |
| 171 | |
| 172 | function cmbird_custom_shop_purchase_bulk_actions( $bulk_actions ) { |
| 173 | $bulk_actions['mark_awaiting-approval'] = __( 'Change status to awaiting approval', 'commercebird' ); |
| 174 | $bulk_actions['mark_approved'] = __( 'Change status to approved', 'commercebird' ); |
| 175 | $bulk_actions['mark_part-received'] = __( 'Change status to partially received', 'commercebird' ); |
| 176 | $bulk_actions['mark_received'] = __( 'Change status to received', 'commercebird' ); |
| 177 | |
| 178 | // unset the statuses that are not needed - e.g. 'mark_processing' |
| 179 | unset( $bulk_actions['mark_processing'] ); |
| 180 | unset( $bulk_actions['mark_on-hold'] ); |
| 181 | unset( $bulk_actions['mark_completed'] ); |
| 182 | |
| 183 | return $bulk_actions; |
| 184 | } |
| 185 | add_filter( 'bulk_actions-edit-shop_purchase', 'cmbird_custom_shop_purchase_bulk_actions' ); |
| 186 | // HPOS Screens |
| 187 | add_filter( 'bulk_actions-woocommerce_page_wc-orders--shop_purchase', 'cmbird_custom_shop_purchase_bulk_actions' ); |
| 188 | |
| 189 | |
| 190 | function cmbird_handle_custom_status_transitions( $order_id, $old_status, $new_status ) { |
| 191 | |
| 192 | if ( 'awaiting-approval' === $new_status ) { |
| 193 | // Logic for when the order is awaiting approval |
| 194 | } |
| 195 | |
| 196 | if ( 'approved' === $new_status ) { |
| 197 | // Logic for when the order is approved |
| 198 | } |
| 199 | |
| 200 | if ( 'part-received' === $new_status ) { |
| 201 | // logic for when the order is partially received |
| 202 | } |
| 203 | |
| 204 | if ( 'received' === $new_status ) { |
| 205 | $order = wc_get_order( $order_id ); |
| 206 | |
| 207 | foreach ( $order->get_items() as $item_id => $item ) { |
| 208 | $product = $item->get_product(); |
| 209 | |
| 210 | if ( $product && $product->managing_stock() ) { |
| 211 | $quantity_ordered = $item->get_quantity(); |
| 212 | $already_received = (int) wc_get_order_item_meta( $item_id, 'received', true ); |
| 213 | $quantity_to_add = $quantity_ordered; |
| 214 | |
| 215 | if ( 'part-received' === $old_status ) { |
| 216 | // Only add the remaining quantity not yet received |
| 217 | $quantity_to_add = max( 0, $quantity_ordered - $already_received ); |
| 218 | } |
| 219 | |
| 220 | if ( $quantity_to_add > 0 ) { |
| 221 | $current_stock = $product->get_stock_quantity(); |
| 222 | $new_stock = $current_stock + $quantity_to_add; |
| 223 | |
| 224 | // Update stock |
| 225 | $product->set_stock_quantity( $new_stock ); |
| 226 | $product->save(); |
| 227 | } |
| 228 | |
| 229 | // Optionally, update the "received" meta to reflect full receipt |
| 230 | wc_update_order_item_meta( $item_id, 'received', $quantity_ordered ); |
| 231 | } |
| 232 | } |
| 233 | } |
| 234 | } |
| 235 | add_action( 'woocommerce_order_status_changed', 'cmbird_handle_custom_status_transitions', 10, 3 ); |
| 236 | |
| 237 | // Set cost price in purchase orders when created or edited via Admin |
| 238 | function cmbird_set_cost_price_for_admin_purchase_order( $post_id, $post, $update ) { |
| 239 | if ( 'shop_purchase' === wc_get_order_type( $post_id ) ) { |
| 240 | |
| 241 | $order = wc_get_order( $post_id ); |
| 242 | |
| 243 | if ( $order && 'shop_purchase' === $order->get_type() ) { |
| 244 | |
| 245 | foreach ( $order->get_items() as $item_id => $item ) { |
| 246 | $product = $item->get_product(); |
| 247 | |
| 248 | if ( $product ) { |
| 249 | // Get the cost price from product meta |
| 250 | $cost_price = get_post_meta( $product->get_id(), '_cost_price', true ); |
| 251 | |
| 252 | // If cost price is set, update the item price in the order |
| 253 | if ( $cost_price && is_numeric( $cost_price ) ) { |
| 254 | $item->set_subtotal( $cost_price * $item->get_quantity() ); |
| 255 | $item->set_total( $cost_price * $item->get_quantity() ); |
| 256 | $item->save(); |
| 257 | } |
| 258 | } |
| 259 | } |
| 260 | |
| 261 | // Recalculate totals for the order after setting cost price |
| 262 | $order->calculate_totals(); |
| 263 | |
| 264 | // Set the store's address as the shipping address for purchase orders |
| 265 | $location_address = get_option( 'woocommerce_wh_address', '' ); |
| 266 | $location_address_2 = get_option( 'woocommerce_wh_address_2', '' ); |
| 267 | $location_city = get_option( 'woocommerce_wh_city', '' ); |
| 268 | $location_state = get_option( 'woocommerce_wh_state', '' ); |
| 269 | $location_country = get_option( 'woocommerce_wh_country', '' ); |
| 270 | $location_zip = get_option( 'woocommerce_wh_postcode', '' ); |
| 271 | |
| 272 | // Update the shipping address with store details |
| 273 | $shipping_address = array( |
| 274 | 'first_name' => 'Store', |
| 275 | 'last_name' => 'Address', |
| 276 | 'company' => get_option( 'blogname' ), |
| 277 | 'address_1' => $location_address, |
| 278 | 'address_2' => $location_address_2, |
| 279 | 'city' => $location_city, |
| 280 | 'state' => $location_state, |
| 281 | 'postcode' => $location_zip, |
| 282 | 'country' => $location_country, |
| 283 | ); |
| 284 | |
| 285 | // Set the new shipping address for the order |
| 286 | $order->set_address( $shipping_address, 'shipping' ); |
| 287 | |
| 288 | // save shipping address as customer shipping address. |
| 289 | $customer = $order->get_customer(); |
| 290 | $customer->set_shipping_address( $shipping_address ); |
| 291 | $customer->save(); |
| 292 | } |
| 293 | } |
| 294 | } |
| 295 | add_action( 'save_post_shop_purchase', 'cmbird_set_cost_price_for_admin_purchase_order', 10, 3 ); |
| 296 | |
| 297 | // Add location address in woocommerce settings |
| 298 | add_filter( 'woocommerce_general_settings', 'cmbird_additional_store_addresses_admin', 9999 ); |
| 299 | |
| 300 | function cmbird_additional_store_addresses_admin( $settings ) { |
| 301 | |
| 302 | $new_settings = array( |
| 303 | |
| 304 | array( |
| 305 | 'title' => 'location Address', |
| 306 | 'type' => 'title', |
| 307 | 'id' => 'wh_address', |
| 308 | ), |
| 309 | |
| 310 | array( |
| 311 | 'title' => __( 'Address line 1', 'commercebird' ), |
| 312 | 'id' => 'woocommerce_wh_address', |
| 313 | 'type' => 'text', |
| 314 | ), |
| 315 | |
| 316 | array( |
| 317 | 'title' => __( 'Address line 2', 'commercebird' ), |
| 318 | 'id' => 'woocommerce_wh_address_2', |
| 319 | 'type' => 'text', |
| 320 | ), |
| 321 | |
| 322 | array( |
| 323 | 'title' => __( 'City', 'commercebird' ), |
| 324 | 'id' => 'woocommerce_wh_city', |
| 325 | 'type' => 'text', |
| 326 | ), |
| 327 | |
| 328 | array( |
| 329 | 'title' => __( 'State', 'commercebird' ), |
| 330 | 'id' => 'woocommerce_wh_state', |
| 331 | 'type' => 'text', |
| 332 | ), |
| 333 | |
| 334 | array( |
| 335 | 'title' => __( 'Country', 'commercebird' ), |
| 336 | 'id' => 'woocommerce_wh_country', |
| 337 | 'type' => 'single_select_country', |
| 338 | ), |
| 339 | |
| 340 | array( |
| 341 | 'title' => __( 'Postcode / ZIP', 'commercebird' ), |
| 342 | 'id' => 'woocommerce_wh_postcode', |
| 343 | 'type' => 'text', |
| 344 | ), |
| 345 | |
| 346 | array( |
| 347 | 'type' => 'sectionend', |
| 348 | 'id' => 'wh_address', |
| 349 | ), |
| 350 | |
| 351 | ); |
| 352 | |
| 353 | return array_merge( array_slice( $settings, 0, 7 ), $new_settings, array_slice( $settings, 7 ) ); |
| 354 | } |
| 355 | |
| 356 | /** |
| 357 | * Use 'woocommerce_rest_insert_customer' action hook to change the user role to vendor when creating customer. |
| 358 | * |
| 359 | * @param WP_User $user_data Data used to create the customer. |
| 360 | * @param WP_REST_Request $request Request object. |
| 361 | * @param boolean $creating True when creating customer, false when updating customer. |
| 362 | */ |
| 363 | function cmbird_change_user_role_to_vendor( $user_data, $request, $creating ) { |
| 364 | // Get the property 'role' from the request object |
| 365 | $role = $request->get_param( 'role' ); |
| 366 | |
| 367 | // Change the user role to 'vendor' |
| 368 | if ( ! empty( $role ) && 'vendor' === $role ) { |
| 369 | $user_data->set_role( 'vendor' ); |
| 370 | } |
| 371 | |
| 372 | // Return the user data |
| 373 | return $user_data; |
| 374 | } |
| 375 | add_action( 'woocommerce_rest_insert_customer', 'cmbird_change_user_role_to_vendor', 10, 3 ); |
| 376 | |
| 377 | /** |
| 378 | * Register the custom email class for Purchase Orders |
| 379 | * @param array $email_classes |
| 380 | * @return array |
| 381 | */ |
| 382 | function cmbird_register_purchase_order_email( $email_classes ) { |
| 383 | require_once 'class-cmbird-purchase-order-email.php'; |
| 384 | $email_classes['CMBIRD_Email_Purchase_Order'] = new CMBIRD_Email_Purchase_Order(); |
| 385 | return $email_classes; |
| 386 | } |
| 387 | add_action( 'woocommerce_email_classes', 'cmbird_register_purchase_order_email' ); |
| 388 | |
| 389 | function cmbird_format_purchase_order_number( $order_number, $order ) { |
| 390 | if ( 'shop_purchase' === $order->get_type() ) { |
| 391 | return 'PO-' . $order_number; |
| 392 | } |
| 393 | return $order_number; |
| 394 | } |
| 395 | add_filter( 'woocommerce_order_number', 'cmbird_format_purchase_order_number', 10, 2 ); |
| 396 | |
| 397 | function cmbird_set_vendor_email_recipient( $recipient, $order ) { |
| 398 | if ( ! $order || ! is_a( $order, 'WC_Order' ) ) { |
| 399 | return $recipient; |
| 400 | } |
| 401 | |
| 402 | if ( 'shop_purchase' === $order->get_type() ) { |
| 403 | $vendor_id = $order->get_customer_id(); |
| 404 | $vendor = get_userdata( $vendor_id ); |
| 405 | |
| 406 | if ( $vendor && in_array( 'vendor', (array) $vendor->roles ) ) { |
| 407 | $recipient = $vendor->user_email; |
| 408 | } |
| 409 | } |
| 410 | return $recipient; |
| 411 | } |
| 412 | add_filter( 'woocommerce_email_recipient_new_order', 'cmbird_set_vendor_email_recipient', 10, 2 ); |
| 413 | |
| 414 | function cmbird_customize_purchase_order_email_subject( $subject, $order ) { |
| 415 | if ( ! $order || ! is_a( $order, 'WC_Order' ) ) { |
| 416 | return $subject; |
| 417 | } |
| 418 | |
| 419 | if ( 'shop_purchase' === $order->get_type() ) { |
| 420 | $subject = sprintf( __( 'New Purchase Order: PO-%s', 'commercebird' ), $order->get_id() ); |
| 421 | } |
| 422 | return $subject; |
| 423 | } |
| 424 | add_filter( 'woocommerce_email_subject_new_order', 'cmbird_customize_purchase_order_email_subject', 10, 2 ); |
| 425 | |
| 426 | function cmbird_customize_purchase_order_email_heading( $heading, $email ) { |
| 427 | if ( isset( $email->object ) && is_a( $email->object, 'WC_Order' ) && 'shop_purchase' === $email->object->get_type() ) { |
| 428 | $heading = __( 'You Have a New Purchase Order', 'commercebird' ); |
| 429 | } |
| 430 | return $heading; |
| 431 | } |
| 432 | add_filter( 'woocommerce_email_heading_new_order', 'cmbird_customize_purchase_order_email_heading', 10, 2 ); |
| 433 | |
| 434 | function cmbird_remove_order_totals_for_shop_purchase( $totals, $order ) { |
| 435 | if ( $order->get_type() === 'shop_purchase' ) { |
| 436 | // Remove pricing-related rows |
| 437 | unset( $totals['cart_subtotal'] ); |
| 438 | unset( $totals['discount'] ); |
| 439 | unset( $totals['shipping'] ); |
| 440 | unset( $totals['payment_method'] ); |
| 441 | unset( $totals['order_total'] ); |
| 442 | } |
| 443 | return $totals; |
| 444 | } |
| 445 | add_filter( 'woocommerce_get_order_item_totals', 'cmbird_remove_order_totals_for_shop_purchase', 10, 2 ); |
| 446 | |
| 447 | // function cmbird_remove_item_prices_for_shop_purchase( $items, $order ) { |
| 448 | // if ( $order instanceof WC_Order && $order->get_type() === 'shop_purchase' ) { |
| 449 | // foreach ( $items as $item_id => $item ) { |
| 450 | // // Ensure that only product items are modified |
| 451 | // if ( $item instanceof WC_Order_Item_Product ) { |
| 452 | // $item->set_subtotal( value: 0 ); |
| 453 | // $item->set_total( 0 ); |
| 454 | // } |
| 455 | // } |
| 456 | // } |
| 457 | // return $items; |
| 458 | // } |
| 459 | // add_filter( 'woocommerce_order_get_items', 'cmbird_remove_item_prices_for_shop_purchase', 10, 2 ); |
| 460 |