首页 / 教程文章 / WordPress文创商品柔性预售与产能匹配插件教程

WordPress文创商品柔性预售与产能匹配插件教程

WordPress文创商品柔性预售与产能匹配插件教程

引言:文创电商的产能挑战与解决方案

在文创商品电商领域,生产者常常面临一个两难困境:一方面,预售可以准确掌握市场需求,避免库存积压;另一方面,产能有限可能导致订单延迟,影响客户体验。柔性预售与产能匹配系统正是解决这一问题的创新方案。

本教程将指导您如何为WordPress文创电商网站开发一个智能的柔性预售与产能匹配插件。该系统将根据实时产能数据动态调整预售库存,实现供需平衡,优化生产计划。

插件架构设计

1.1 系统核心功能模块

我们的插件将包含以下核心模块:

  • 产能管理模块:设置和管理生产能力
  • 预售商品管理:特殊商品类型定义
  • 订单产能匹配:实时匹配订单与产能
  • 生产计划生成:自动生成生产排期
  • 客户通知系统:自动更新订单状态

1.2 数据库表结构设计

<?php
/**
 * 创建插件所需数据库表
 * 这段代码应该放在插件激活钩子中执行
 */
function fpp_create_database_tables() {
    global $wpdb;
    
    $charset_collate = $wpdb->get_charset_collate();
    
    // 产能计划表
    $capacity_table = $wpdb->prefix . 'fpp_capacity';
    $capacity_sql = "CREATE TABLE IF NOT EXISTS $capacity_table (
        id mediumint(9) NOT NULL AUTO_INCREMENT,
        date date NOT NULL,
        max_capacity int NOT NULL DEFAULT 0,
        booked_capacity int NOT NULL DEFAULT 0,
        product_id bigint(20) DEFAULT 0,
        created_at datetime DEFAULT CURRENT_TIMESTAMP,
        PRIMARY KEY (id),
        KEY date_index (date),
        KEY product_index (product_id)
    ) $charset_collate;";
    
    // 预售商品扩展表
    $presale_table = $wpdb->prefix . 'fpp_presale_products';
    $presale_sql = "CREATE TABLE IF NOT EXISTS $presale_table (
        id mediumint(9) NOT NULL AUTO_INCREMENT,
        product_id bigint(20) NOT NULL,
        is_presale tinyint(1) DEFAULT 0,
        estimated_days int DEFAULT 7,
        capacity_per_unit int DEFAULT 1,
        max_presale_quantity int DEFAULT 100,
        start_date date DEFAULT NULL,
        end_date date DEFAULT NULL,
        PRIMARY KEY (id),
        UNIQUE KEY product_id (product_id)
    ) $charset_collate;";
    
    // 订单产能分配表
    $order_allocation_table = $wpdb->prefix . 'fpp_order_allocation';
    $order_allocation_sql = "CREATE TABLE IF NOT EXISTS $order_allocation_table (
        id mediumint(9) NOT NULL AUTO_INCREMENT,
        order_id bigint(20) NOT NULL,
        order_item_id bigint(20) NOT NULL,
        product_id bigint(20) NOT NULL,
        quantity int NOT NULL,
        allocated_date date NOT NULL,
        production_date date DEFAULT NULL,
        status varchar(20) DEFAULT 'pending',
        created_at datetime DEFAULT CURRENT_TIMESTAMP,
        PRIMARY KEY (id),
        KEY order_index (order_id),
        KEY date_index (allocated_date),
        KEY status_index (status)
    ) $charset_collate;";
    
    require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
    dbDelta($capacity_sql);
    dbDelta($presale_sql);
    dbDelta($order_allocation_sql);
}
?>

产能管理模块开发

2.1 产能设置界面

<?php
/**
 * 产能管理后台界面
 * 添加产能管理菜单和页面
 */
class FPP_Capacity_Manager {
    
    public function __construct() {
        add_action('admin_menu', array($this, 'add_admin_menu'));
        add_action('admin_enqueue_scripts', array($this, 'enqueue_admin_scripts'));
    }
    
    public function add_admin_menu() {
        add_menu_page(
            '柔性预售产能管理',
            '产能管理',
            'manage_options',
            'fpp-capacity',
            array($this, 'render_capacity_page'),
            'dashicons-calendar-alt',
            56
        );
        
        add_submenu_page(
            'fpp-capacity',
            '产能日历',
            '产能日历',
            'manage_options',
            'fpp-capacity-calendar',
            array($this, 'render_calendar_page')
        );
    }
    
    public function render_capacity_page() {
        ?>
        <div class="wrap">
            <h1>柔性预售产能管理</h1>
            
            <div class="fpp-admin-container">
                <div class="fpp-admin-card">
                    <h2>每日产能设置</h2>
                    <form method="post" action="<?php echo admin_url('admin-post.php'); ?>">
                        <input type="hidden" name="action" value="fpp_save_capacity">
                        <?php wp_nonce_field('fpp_save_capacity_nonce'); ?>
                        
                        <table class="form-table">
                            <tr>
                                <th scope="row">
                                    <label for="capacity_date">日期</label>
                                </th>
                                <td>
                                    <input type="date" 
                                           id="capacity_date" 
                                           name="capacity_date" 
                                           value="<?php echo date('Y-m-d'); ?>" 
                                           required>
                                </td>
                            </tr>
                            <tr>
                                <th scope="row">
                                    <label for="max_capacity">最大产能</label>
                                </th>
                                <td>
                                    <input type="number" 
                                           id="max_capacity" 
                                           name="max_capacity" 
                                           min="0" 
                                           step="1" 
                                           value="100" 
                                           required>
                                    <p class="description">该日期可处理的最大订单数量</p>
                                </td>
                            </tr>
                            <tr>
                                <th scope="row">
                                    <label for="product_id">关联商品 (可选)</label>
                                </th>
                                <td>
                                    <select id="product_id" name="product_id">
                                        <option value="0">所有商品</option>
                                        <?php
                                        $products = wc_get_products(array(
                                            'limit' => -1,
                                            'type' => 'presale'
                                        ));
                                        
                                        foreach ($products as $product) {
                                            echo '<option value="' . $product->get_id() . '">' 
                                                 . $product->get_name() . '</option>';
                                        }
                                        ?>
                                    </select>
                                </td>
                            </tr>
                        </table>
                        
                        <?php submit_button('保存产能设置'); ?>
                    </form>
                </div>
                
                <div class="fpp-admin-card">
                    <h2>近期产能概览</h2>
                    <?php $this->render_capacity_overview(); ?>
                </div>
            </div>
        </div>
        
        <style>
            .fpp-admin-container {
                display: grid;
                grid-template-columns: 1fr 1fr;
                gap: 20px;
                margin-top: 20px;
            }
            
            .fpp-admin-card {
                background: #fff;
                padding: 20px;
                border-radius: 8px;
                box-shadow: 0 2px 4px rgba(0,0,0,0.1);
            }
            
            @media (max-width: 1200px) {
                .fpp-admin-container {
                    grid-template-columns: 1fr;
                }
            }
        </style>
        <?php
    }
    
    private function render_capacity_overview() {
        global $wpdb;
        $table_name = $wpdb->prefix . 'fpp_capacity';
        
        $capacities = $wpdb->get_results(
            "SELECT * FROM $table_name 
             WHERE date >= CURDATE() 
             ORDER BY date ASC 
             LIMIT 7"
        );
        
        if (empty($capacities)) {
            echo '<p>暂无产能数据</p>';
            return;
        }
        
        echo '<table class="wp-list-table widefat fixed striped">';
        echo '<thead>
                <tr>
                    <th>日期</th>
                    <th>最大产能</th>
                    <th>已预订</th>
                    <th>剩余</th>
                    <th>利用率</th>
                </tr>
              </thead>';
        echo '<tbody>';
        
        foreach ($capacities as $capacity) {
            $remaining = $capacity->max_capacity - $capacity->booked_capacity;
            $utilization = $capacity->max_capacity > 0 
                ? round(($capacity->booked_capacity / $capacity->max_capacity) * 100, 1) 
                : 0;
            
            echo '<tr>';
            echo '<td>' . $capacity->date . '</td>';
            echo '<td>' . $capacity->max_capacity . '</td>';
            echo '<td>' . $capacity->booked_capacity . '</td>';
            echo '<td>' . $remaining . '</td>';
            echo '<td>' . $utilization . '%</td>';
            echo '</tr>';
        }
        
        echo '</tbody></table>';
    }
}
?>

预售商品功能集成

3.1 自定义商品类型与字段

<?php
/**
 * 扩展WooCommerce商品类型
 * 添加预售商品类型和自定义字段
 */
class FPP_Product_Type_Extension {
    
    public function __construct() {
        // 注册预售商品类型
        add_filter('product_type_selector', array($this, 'add_presale_product_type'));
        
        // 添加商品数据选项卡
        add_filter('woocommerce_product_data_tabs', array($this, 'add_product_data_tab'));
        
        // 显示预售设置面板
        add_action('woocommerce_product_data_panels', array($this, 'show_presale_settings_panel'));
        
        // 保存预售设置
        add_action('woocommerce_process_product_meta', array($this, 'save_presale_settings'));
        
        // 在前端显示预售信息
        add_action('woocommerce_single_product_summary', array($this, 'show_frontend_presale_info'), 25);
    }
    
    public function add_presale_product_type($types) {
        $types['presale'] = __('预售商品', 'fpp');
        return $types;
    }
    
    public function add_product_data_tab($tabs) {
        $tabs['presale'] = array(
            'label'    => __('预售设置', 'fpp'),
            'target'   => 'presale_product_data',
            'class'    => array('show_if_presale'),
            'priority' => 80,
        );
        return $tabs;
    }
    
    public function show_presale_settings_panel() {
        global $post;
        
        $product = wc_get_product($post->ID);
        $is_presale = $product->get_meta('_is_presale', true);
        $estimated_days = $product->get_meta('_estimated_days', true) ?: 7;
        $capacity_per_unit = $product->get_meta('_capacity_per_unit', true) ?: 1;
        $max_presale_quantity = $product->get_meta('_max_presale_quantity', true) ?: 100;
        ?>
        
        <div id="presale_product_data" class="panel woocommerce_options_panel hidden">
            <div class="options_group">
                <?php
                // 是否启用预售
                woocommerce_wp_checkbox(array(
                    'id'          => '_is_presale',
                    'label'       => __('启用预售', 'fpp'),
                    'description' => __('启用后此商品将作为预售商品销售', 'fpp'),
                    'value'       => $is_presale,
                ));
                
                // 预计发货天数
                woocommerce_wp_text_input(array(
                    'id'          => '_estimated_days',
                    'label'       => __('预计发货天数', 'fpp'),
                    'description' => __('下单后预计发货所需天数', 'fpp'),
                    'type'        => 'number',
                    'custom_attributes' => array(
                        'min'  => '1',
                        'step' => '1',
                    ),
                    'value'       => $estimated_days,
                ));
                
                // 单位产能消耗
                woocommerce_wp_text_input(array(
                    'id'          => '_capacity_per_unit',
                    'label'       => __('单位产能消耗', 'fpp'),
                    'description' => __('每件商品消耗的产能单位数', 'fpp'),
                    'type'        => 'number',
                    'custom_attributes' => array(
                        'min'  => '1',
                        'step' => '1',
                    ),
                    'value'       => $capacity_per_unit,
                ));
                
                // 最大预售数量
                woocommerce_wp_text_input(array(
                    'id'          => '_max_presale_quantity',
                    'label'       => __('最大预售数量', 'fpp'),
                    'description' => __('该商品最大可预售数量', 'fpp'),
                    'type'        => 'number',
                    'custom_attributes' => array(
                        'min'  => '1',
                        'step' => '1',
                    ),
                    'value'       => $max_presale_quantity,
                ));
                
                // 预售开始时间
                woocommerce_wp_text_input(array(
                    'id'          => '_presale_start_date',
                    'label'       => __('预售开始时间', 'fpp'),
                    'description' => __('预售开始日期和时间', 'fpp'),
                    'type'        => 'datetime-local',
                    'value'       => $product->get_meta('_presale_start_date', true),
                ));
                
                // 预售结束时间
                woocommerce_wp_text_input(array(
                    'id'          => '_presale_end_date',
                    'label'       => __('预售结束时间', 'fpp'),
                    'description' => __('预售结束日期和时间', 'fpp'),
                    'type'        => 'datetime-local',
                    'value'       => $product->get_meta('_presale_end_date', true),
                ));
                ?>
            </div>
        </div>
        
        <script>
            jQuery(document).ready(function($) {
                // 显示/隐藏预售设置面板
                $('.product_type').change(function() {
                    var isPresale = $('#product-type').val() === 'presale';
                    $('.show_if_presale').toggle(isPresale);
                }).change();
            });
        </script>
        <?php
    }
    
    public function save_presale_settings($product_id) {
        $product = wc_get_product($product_id);
        
        // 保存预售设置
        $is_presale = isset($_POST['_is_presale']) ? 'yes' : 'no';
        $product->update_meta_data('_is_presale', $is_presale);
        
        if (isset($_POST['_estimated_days'])) {
            $product->update_meta_data('_estimated_days', absint($_POST['_estimated_days']));
        }
        
        if (isset($_POST['_capacity_per_unit'])) {
            $product->update_meta_data('_capacity_per_unit', absint($_POST['_capacity_per_unit']));
        }
        
        if (isset($_POST['_max_presale_quantity'])) {
            $product->update_meta_data('_max_presale_quantity', absint($_POST['_max_presale_quantity']));
        }
        
        if (isset($_POST['_presale_start_date'])) {
            $product->update_meta_data('_presale_start_date', sanitize_text_field($_POST['_presale_start_date']));
        }
        
        if (isset($_POST['_presale_end_date'])) {
            $product->update_meta_data('_presale_end_date', sanitize_text_field($_POST['_presale_end_date']));
        }
        
        $product->save();
    }
    
    public function show_frontend_presale_info() {
        global $product;
        
        if ($product->get_meta('_is_presale', true) !== 'yes') {
            return;
        }
        
        $estimated_days = $product->get_meta('_estimated_days', true);
        $start_date = $product->get_meta('_presale_start_date', true);
        $end_date = $product->get_meta('_presale_end_date', true);
        
        echo '<div class="presale-notice" style="background: #f0f8ff; padding: 15px; border-radius: 5px; margin: 20px 0;">';
        echo '<h3>' . __('预售商品说明', 'fpp') . '</h3>';
        
        if ($estimated_days) {
            echo '<p>' . sprintf(__('预计下单后 %d 天内发货', 'fpp'), $estimated_days) . '</p>';
        }
        
        if ($start_date && strtotime($start_date) > time()) {
            echo '<p>' . sprintf(__('预售开始时间: %s', 'fpp'), date('Y-m-d H:i', strtotime($start_date))) . '</p>';
        }
        
        if ($end_date && strtotime($end_date) > time()) {
            echo '<p>' . sprintf(__('预售结束时间: %s', 'fpp'), date('Y-m-d H:i', strtotime($end_date))) . '</p>';
        }
        
        echo '<p><strong>' . __('注意:预售商品将根据产能安排生产,具体发货时间可能根据订单量有所调整', 'fpp') . '</strong></p>';
        echo '</div>';
    }
}
?>

订单处理与产能匹配引擎

4.1 智能产能分配算法

<?php
/**
 * 订单产能匹配引擎
 * 处理新订单并分配到合适的产能日期
 */
class FPP_Order_Allocation_Engine {
    
    private $db;
    
    public function __construct() {
        global $wpdb;
        $this->db = $wpdb;
        
        // 订单创建时触发产能分配
        add_action('woocommerce_checkout_order_processed', array($this, 'allocate_order_capacity'), 10, 3);
        

// 订单状态变化时更新产能

    add_action('woocommerce_order_status_changed', array($this, 'update_capacity_on_status_change'), 10, 4);
}

/**
 * 为新订单分配产能
 * @param int $order_id 订单ID
 * @param array $posted_data 提交的数据
 * @param WC_Order $order 订单对象
 */
public function allocate_order_capacity($order_id, $posted_data, $order) {
    // 获取订单中的所有商品
    $items = $order->get_items();
    
    foreach ($items as $item_id => $item) {
        $product = $item->get_product();
        
        // 检查是否为预售商品
        if ($product->get_meta('_is_presale', true) !== 'yes') {
            continue; // 非预售商品跳过
        }
        
        $product_id = $product->get_id();
        $quantity = $item->get_quantity();
        $capacity_per_unit = $product->get_meta('_capacity_per_unit', true) ?: 1;
        $total_capacity_needed = $quantity * $capacity_per_unit;
        
        // 查找可用的产能日期
        $allocated_date = $this->find_available_capacity_date($product_id, $total_capacity_needed);
        
        if ($allocated_date) {
            // 分配产能并记录
            $this->allocate_capacity_for_item(
                $order_id,
                $item_id,
                $product_id,
                $quantity,
                $allocated_date
            );
            
            // 更新产能表的已预订数量
            $this->update_booked_capacity($allocated_date, $product_id, $total_capacity_needed);
            
            // 计算预计发货日期
            $estimated_days = $product->get_meta('_estimated_days', true) ?: 7;
            $production_date = date('Y-m-d', strtotime($allocated_date));
            $shipping_date = date('Y-m-d', strtotime($allocated_date . " + $estimated_days days"));
            
            // 添加订单备注
            $order->add_order_note(
                sprintf(
                    __('预售商品 "%s" 已分配产能,生产日期: %s,预计发货日期: %s', 'fpp'),
                    $product->get_name(),
                    $production_date,
                    $shipping_date
                )
            );
            
            // 更新订单项meta
            wc_add_order_item_meta($item_id, '_production_date', $production_date);
            wc_add_order_item_meta($item_id, '_estimated_shipping_date', $shipping_date);
        } else {
            // 没有可用产能,标记为等待分配
            $this->allocate_capacity_for_item(
                $order_id,
                $item_id,
                $product_id,
                $quantity,
                null,
                'waiting'
            );
            
            $order->add_order_note(
                sprintf(
                    __('预售商品 "%s" 暂时无法分配产能,已加入等待队列', 'fpp'),
                    $product->get_name()
                )
            );
        }
    }
}

/**
 * 查找可用的产能日期
 * @param int $product_id 商品ID
 * @param int $needed_capacity 所需产能
 * @return string|null 可用日期或null
 */
private function find_available_capacity_date($product_id, $needed_capacity) {
    $capacity_table = $this->db->prefix . 'fpp_capacity';
    
    // 查询未来30天内的产能情况
    $query = $this->db->prepare(
        "SELECT date, max_capacity, booked_capacity 
         FROM $capacity_table 
         WHERE (product_id = %d OR product_id = 0) 
         AND date >= CURDATE() 
         AND date <= DATE_ADD(CURDATE(), INTERVAL 30 DAY)
         AND max_capacity - booked_capacity >= %d
         ORDER BY date ASC
         LIMIT 1",
        $product_id,
        $needed_capacity
    );
    
    $result = $this->db->get_row($query);
    
    return $result ? $result->date : null;
}

/**
 * 为订单项分配产能
 */
private function allocate_capacity_for_item($order_id, $item_id, $product_id, $quantity, $allocated_date, $status = 'allocated') {
    $table_name = $this->db->prefix . 'fpp_order_allocation';
    
    $this->db->insert(
        $table_name,
        array(
            'order_id' => $order_id,
            'order_item_id' => $item_id,
            'product_id' => $product_id,
            'quantity' => $quantity,
            'allocated_date' => $allocated_date ?: date('Y-m-d'),
            'production_date' => $allocated_date,
            'status' => $status,
            'created_at' => current_time('mysql')
        ),
        array('%d', '%d', '%d', '%d', '%s', '%s', '%s', '%s')
    );
}

/**
 * 更新已预订产能
 */
private function update_booked_capacity($date, $product_id, $capacity) {
    $table_name = $this->db->prefix . 'fpp_capacity';
    
    // 先检查是否存在该日期的记录
    $existing = $this->db->get_var(
        $this->db->prepare(
            "SELECT id FROM $table_name WHERE date = %s AND product_id = %d",
            $date,
            $product_id
        )
    );
    
    if ($existing) {
        // 更新现有记录
        $this->db->query(
            $this->db->prepare(
                "UPDATE $table_name 
                 SET booked_capacity = booked_capacity + %d 
                 WHERE date = %s AND product_id = %d",
                $capacity,
                $date,
                $product_id
            )
        );
    } else {
        // 创建新记录(使用通用产能设置)
        $this->db->insert(
            $table_name,
            array(
                'date' => $date,
                'product_id' => $product_id,
                'max_capacity' => 100, // 默认值
                'booked_capacity' => $capacity
            ),
            array('%s', '%d', '%d', '%d')
        );
    }
}

/**
 * 订单状态变化时更新产能
 */
public function update_capacity_on_status_change($order_id, $old_status, $new_status, $order) {
    // 如果订单取消或退款,释放产能
    if (in_array($new_status, array('cancelled', 'refunded'))) {
        $this->release_capacity_for_order($order_id);
    }
    
    // 如果订单完成,标记生产完成
    if ($new_status === 'completed') {
        $this->mark_production_completed($order_id);
    }
}

/**
 * 释放订单占用的产能
 */
private function release_capacity_for_order($order_id) {
    $allocation_table = $this->db->prefix . 'fpp_order_allocation';
    $capacity_table = $this->db->prefix . 'fpp_capacity';
    
    // 获取订单的所有产能分配记录
    $allocations = $this->db->get_results(
        $this->db->prepare(
            "SELECT * FROM $allocation_table WHERE order_id = %d AND status = 'allocated'",
            $order_id
        )
    );
    
    foreach ($allocations as $allocation) {
        // 获取商品信息计算产能
        $product = wc_get_product($allocation->product_id);
        $capacity_per_unit = $product->get_meta('_capacity_per_unit', true) ?: 1;
        $total_capacity = $allocation->quantity * $capacity_per_unit;
        
        // 释放产能
        $this->db->query(
            $this->db->prepare(
                "UPDATE $capacity_table 
                 SET booked_capacity = GREATEST(0, booked_capacity - %d) 
                 WHERE date = %s AND product_id = %d",
                $total_capacity,
                $allocation->allocated_date,
                $allocation->product_id
            )
        );
        
        // 更新分配状态
        $this->db->update(
            $allocation_table,
            array('status' => 'cancelled'),
            array('id' => $allocation->id),
            array('%s'),
            array('%d')
        );
    }
}

}
?>


## 生产计划与报表系统

### 5.1 生产计划生成器

<?php
/**

  • 生产计划生成与管理系统
    */

class FPP_Production_Planner {


public function __construct() {
    add_action('admin_menu', array($this, 'add_production_menu'));
    add_action('wp_ajax_generate_production_plan', array($this, 'ajax_generate_plan'));
    add_action('wp_ajax_export_production_csv', array($this, 'ajax_export_csv'));
}

public function add_production_menu() {
    add_submenu_page(
        'fpp-capacity',
        '生产计划',
        '生产计划',
        'manage_options',
        'fpp-production',
        array($this, 'render_production_page')
    );
}

public function render_production_page() {
    ?>
    <div class="wrap">
        <h1>生产计划管理</h1>
        
        <div class="fpp-production-controls">
            <form method="get" action="<?php echo admin_url('admin.php'); ?>">
                <input type="hidden" name="page" value="fpp-production">
                
                <label for="start_date">开始日期:</label>
                <input type="date" id="start_date" name="start_date" 
                       value="<?php echo isset($_GET['start_date']) ? $_GET['start_date'] : date('Y-m-d'); ?>">
                
                <label for="end_date">结束日期:</label>
                <input type="date" id="end_date" name="end_date" 
                       value="<?php echo isset($_GET['end_date']) ? $_GET['end_date'] : date('Y-m-d', strtotime('+7 days')); ?>">
                
                <label for="product_id">商品筛选:</label>
                <select id="product_id" name="product_id">
                    <option value="0">所有商品</option>
                    <?php
                    $products = wc_get_products(array(
                        'limit' => -1,
                        'meta_key' => '_is_presale',
                        'meta_value' => 'yes'
                    ));
                    
                    foreach ($products as $product) {
                        $selected = isset($_GET['product_id']) && $_GET['product_id'] == $product->get_id() ? 'selected' : '';
                        echo '<option value="' . $product->get_id() . '" ' . $selected . '>' 
                             . $product->get_name() . '</option>';
                    }
                    ?>
                </select>
                
                <?php submit_button('筛选', 'secondary', 'filter', false); ?>
                
                <button type="button" class="button button-primary" 
                        onclick="generateProductionPlan()">
                    生成生产计划
                </button>
                
                <button type="button" class="button" 
                        onclick="exportProductionCSV()">
                    导出CSV
                </button>
            </form>
        </div>
        
        <div id="production-plan-result" style="margin-top: 20px;"></div>
        
        <?php $this->render_production_table(); ?>
    </div>
    
    <script>
    function generateProductionPlan() {
        const startDate = document.getElementById('start_date').value;
        const endDate = document.getElementById('end_date').value;
        const productId = document.getElementById('product_id').value;
        
        jQuery('#production-plan-result').html('<p>正在生成计划...</p>');
        
        jQuery.ajax({
            url: ajaxurl,
            type: 'POST',
            data: {
                action: 'generate_production_plan',
                start_date: startDate,
                end_date: endDate,
                product_id: productId,
                nonce: '<?php echo wp_create_nonce('fpp_generate_plan'); ?>'
            },
            success: function(response) {
                jQuery('#production-plan-result').html(response.data);
            }
        });
    }
    
    function exportProductionCSV() {
        const startDate = document.getElementById('start_date').value;
        const endDate = document.getElementById('end_date').value;
        const productId = document.getElementById('product_id').value;
        
        const url = ajaxurl + '?action=export_production_csv&start_date=' + startDate + 
                   '&end_date=' + endDate + '&product_id=' + productId + 
                   '&nonce=<?php echo wp_create_nonce('fpp_export_csv'); ?>';
        
        window.location.href = url;
    }
    </script>
    
    <style>
    .fpp-production-controls {
        background: #fff;
        padding: 20px;
        border-radius: 8px;
        margin-bottom: 20px;
    }
    
    .fpp-production-controls label {
        margin-right: 5px;
        margin-left: 15px;
    }
    
    .fpp-production-controls input,
    .fpp-production-controls select {
        margin-right: 15px;
    }
    
    .production-summary {
        display: grid;
        grid-template-columns: repeat(4, 1fr);
        gap: 15px;
        margin: 20px 0;
    }
    
    .summary-card {
        background: #fff;
        padding: 15px;
        border-radius: 8px;
        text-align: center;
        box-shadow: 0 2px 4px rgba(0,0,0,0.1);
    }
    
    .summary-card h3 {
        margin-top: 0;
        color: #333;
    }
    
    .summary-card .number {
        font-size: 24px;
        font-weight: bold;
        color: #0073aa;
    }
    </style>
    <?php
}

public function render_production_table() {
    global $wpdb;
    
    $start_date = isset($_GET['start_date']) ? $_GET['start_date'] : date('Y-m-d');
    $end_date = isset($_GET['end_date']) ? $_GET['end_date'] : date('Y-m-d', strtotime('+7 days'));
    $product_id = isset($_GET['product_id']) ? intval($_GET['product_id']) : 0;
    
    $allocation_table = $wpdb->prefix . 'fpp_order_allocation';
    $capacity_table = $wpdb->prefix . 'fpp_capacity';
    
    // 构建查询
    $query = "SELECT 
                a.allocated_date as production_date,
                a.product_id,
                p.post_title as product_name,
                SUM(a.quantity) as total_quantity,
                COUNT(DISTINCT a.order_id) as order_count,
                c.max_capacity,
                c.booked_capacity
              FROM $allocation_table a
              LEFT JOIN {$wpdb->posts} p ON a.product_id = p.ID
              LEFT JOIN $capacity_table c ON a.allocated_date = c.date AND a.product_id = c.product_id
              WHERE a.status = 'allocated' 
              AND a.allocated_date BETWEEN %s AND %s";
    
    $params = array($start_date, $end_date);
    
    if ($product_id > 0) {
        $query .= " AND a.product_id = %d";
        $params[] = $product_id;
    }
    
    $query .= " GROUP BY a.allocated_date, a.product_id
                ORDER BY a.allocated_date ASC, a.product_id ASC";
    
    $results = $wpdb->get_results($wpdb->prepare($query, $params));
    
    if (empty($results)) {
        echo '<p>没有找到生产计划数据</p>';
        return;
    }
    
    // 显示统计摘要
    $total_quantity = array_sum(array_column($results, 'total_quantity'));
    $total_orders = array_sum(array_column($results, 'order_count'));
    $unique_products = count(array_unique(array_column($results, 'product_id')));
    $utilization_rate = 0;
    
    if (!empty($results)) {
        $total_capacity = array_sum(array_column($results, 'max_capacity'));
        $total_booked = array_sum(array_column($results, 'booked_capacity'));
        $utilization_rate = $total_capacity > 0 ? round(($total_booked / $total_capacity) * 100, 1) : 0;
    }
    ?>
    
    <div class="production-summary">
        <div class="summary-card">
            <h3>总生产数量</h3>
            <div class="number"><?php echo $total_quantity; ?></div>
        </div>
        <div class="summary-card">
            <h3>订单数量</h3>
            <div class="number"><?php echo $total_orders; ?></div>
        </div>
        <div class="summary-card">
            <h3>商品种类</h3>
            <div class="number"><?php echo $unique_products; ?></div>
        </div>
        <div class="summary-card">
            <h3>产能利用率</h3>
            <div class="number"><?php echo $utilization_rate; ?>%</div>
        </div>
    </div>
    
    <table class="wp-list-table widefat fixed striped">
        <thead>
            <tr>
                <th>生产日期</th>
                <th>商品名称</th>
                <th>生产数量</th>
                <th>订单数</th>
                <th>最大产能</th>
                <th>已分配</th>
                <th>剩余产能</th>
                <th>操作</th>
            </tr>
        </thead>
        <tbody>
            <?php foreach ($results as $row): 
                $remaining = $row->max_capacity - $row->booked_capacity;
                $utilization = $row->max_capacity > 0 ? round(($row
本文来自网络,不代表柔性供应链服务中心立场,转载请注明出处:https://mall.org.cn/6255.html

EXCHANGES®作者

上一篇
下一篇

为您推荐

发表回复

联系我们

联系我们

18559313275

在线咨询: QQ交谈

邮箱: vip@exchanges.center

工作时间:周一至周五,9:00-17:30,节假日休息
返回顶部