TMDO_Quotation::register() 舊版偵測 TMQUO_Main / TMQUO_Plugin 兩個類別, 在 partner 外掛中並不存在(或載入太晚),偵測實際完全靠 file_exists() 後備 撐著——程式碼讀起來像在驗證「partner 已載入」,實際只驗證了「目錄存在」。 改用 TMQUO_VERSION / TMQUO_PLUGIN_DIR,兩者在 partner 主檔的檔案解析當下即 define,早於 plugins_loaded,故本 AddOn bootstrap 的 :6 時點確實可用。 file_exists() 後備保留不動,行為不變;但偵測不再是死碼,即使將來移除後備也 不會重演 infocards-addon 那種「整個 AddOn 靜默失效」的事故。 同一版本另含先前未提交的 schema 工作:補齊 expected_columns / indexes, 並將 registry 索引 config key 由 expected_indexes 更正為 indexes (wp_parse_args() 會靜默丟棄未知 key,索引期望值先前等同從未送達)。 實測驗證(mu-plugin 於 plugins_loaded:6 量測真實請求): 新常數 AVAILABLE;wp wpdo doctor 89 OK / 0 FAIL;表註冊欄位與索引 100% 完整。
This commit is contained in:
@@ -3,7 +3,7 @@
|
|||||||
* Plugin Name: 2meet Data Optimizer — Quotation AddOn
|
* Plugin Name: 2meet Data Optimizer — Quotation AddOn
|
||||||
* Plugin URI: https://2meet.io/2meet-data-optimizer/quotation
|
* Plugin URI: https://2meet.io/2meet-data-optimizer/quotation
|
||||||
* Description: 2meet-quotation 8 張自訂表 (2mq_*) 註冊(含 hp_vendor post_type_link)
|
* Description: 2meet-quotation 8 張自訂表 (2mq_*) 註冊(含 hp_vendor post_type_link)
|
||||||
* Version: 0.1.0
|
* Version: 0.1.1
|
||||||
* Requires at least: 6.0
|
* Requires at least: 6.0
|
||||||
* Tested up to: 6.9.4
|
* Tested up to: 6.9.4
|
||||||
* Requires PHP: 8.1
|
* Requires PHP: 8.1
|
||||||
@@ -24,7 +24,7 @@ if ( ! defined( 'ABSPATH' ) ) {
|
|||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
define( 'TMDO_QUOTATION_VERSION', '0.1.0' );
|
define( 'TMDO_QUOTATION_VERSION', '0.1.1' );
|
||||||
define( 'TMDO_QUOTATION_PATH', plugin_dir_path( __FILE__ ) );
|
define( 'TMDO_QUOTATION_PATH', plugin_dir_path( __FILE__ ) );
|
||||||
define( 'TMDO_QUOTATION_URL', plugin_dir_url( __FILE__ ) );
|
define( 'TMDO_QUOTATION_URL', plugin_dir_url( __FILE__ ) );
|
||||||
define( 'TMDO_QUOTATION_FILE', __FILE__ );
|
define( 'TMDO_QUOTATION_FILE', __FILE__ );
|
||||||
|
|||||||
@@ -13,6 +13,33 @@ Versioning follows [Semantic Versioning](https://semver.org/).
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## [0.1.1] — 2026-08-08 — 8 張 `2mq_*` 表補齊 schema 期望值
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- 為全部 8 張 `2mq_*` 表補上 `expected_columns` 與 `indexes`:`2mq_quotations`、
|
||||||
|
`2mq_quotation_items`、`2mq_quotation_history`、`2mq_vendor_presets`、
|
||||||
|
`2mq_catalog_categories`、`2mq_catalog_items`、`2mq_quotation_templates`、
|
||||||
|
`2mq_vendor_catalog_prices`。欄位與索引逐項轉錄自 2meet-quotation activator 的
|
||||||
|
`CREATE TABLE`。先前只註冊表名,`wp wpdo doctor` 只知道表存在,無從判斷欄位或
|
||||||
|
索引是否漂移。
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- `TMDO_Custom_Table_Registry::register()` 的索引期望值 config key 由
|
||||||
|
`expected_indexes` 更正為 `indexes`。該 API 以 `wp_parse_args()` 併入預設值,
|
||||||
|
未知 key 會被**靜默丟棄**——先前索引期望值等同從未送達 registry,
|
||||||
|
`wp wpdo doctor` 的 schema drift 只驗欄位、不驗索引。此問題橫跨全部 8 個 AddOn,
|
||||||
|
已一併更正。
|
||||||
|
- `TMDO_Quotation::register()` 的 partner 偵測符號對齊實際存在的常數。舊版偵測
|
||||||
|
`TMQUO_Main` / `TMQUO_Plugin` 兩個類別,但這兩者在 2meet-quotation 中**根本不存在**,
|
||||||
|
偵測實際完全靠 `file_exists()` 後備撐著。改用 `TMQUO_VERSION` / `TMQUO_PLUGIN_DIR`,
|
||||||
|
兩者在主檔檔案解析當下即 define,早於 `plugins_loaded`。
|
||||||
|
實測(mu-plugin 於 `plugins_loaded:6` 量測):`TMQUO_VERSION` = AVAILABLE。
|
||||||
|
`file_exists()` 後備保留不動,行為不變;但偵測不再是死碼。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## [0.1.0] — TBD
|
## [0.1.0] — TBD
|
||||||
|
|
||||||
### Added (initial release, scaffold)
|
### Added (initial release, scaffold)
|
||||||
|
|||||||
@@ -21,9 +21,18 @@ if ( ! defined( 'ABSPATH' ) ) {
|
|||||||
*/
|
*/
|
||||||
final class TMDO_Quotation {
|
final class TMDO_Quotation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 偵測以常數優先:`TMQUO_VERSION` / `TMQUO_PLUGIN_DIR` 在 2meet-quotation 主檔的
|
||||||
|
* **檔案解析當下**(第 22/25 行)即 define,早於 `plugins_loaded`;本 AddOn
|
||||||
|
* bootstrap 掛在 `plugins_loaded:6`,故此時常數已可用。
|
||||||
|
*
|
||||||
|
* 舊版偵測的 `TMQUO_Main` / `TMQUO_Plugin` 兩個類別在 2meet-quotation 中**並不存在**,
|
||||||
|
* 偵測實際完全靠 `file_exists()` 撐著。保留 file_exists 作最終後備,但常數檢查
|
||||||
|
* 現在真的有效——即使將來移除後備也不會像 infocards 那樣整個 AddOn 靜默失效。
|
||||||
|
*/
|
||||||
public static function register(): void {
|
public static function register(): void {
|
||||||
$detected = class_exists( 'TMQUO_Main' )
|
$detected = defined( 'TMQUO_VERSION' )
|
||||||
|| class_exists( 'TMQUO_Plugin' )
|
|| defined( 'TMQUO_PLUGIN_DIR' )
|
||||||
|| file_exists( WP_PLUGIN_DIR . '/2meet-quotation/2meet-quotation.php' );
|
|| file_exists( WP_PLUGIN_DIR . '/2meet-quotation/2meet-quotation.php' );
|
||||||
if ( ! $detected ) {
|
if ( ! $detected ) {
|
||||||
return;
|
return;
|
||||||
@@ -33,23 +42,201 @@ final class TMDO_Quotation {
|
|||||||
|
|
||||||
public static function register_custom_tables( TMDO_Custom_Table_Registry $registry ): void {
|
public static function register_custom_tables( TMDO_Custom_Table_Registry $registry ): void {
|
||||||
$tables = array(
|
$tables = array(
|
||||||
'2mq_quotations' => array( 'id', 'hp_vendor' ), // vendor_id 關聯 hp_vendor
|
// vendor_id 關聯 hp_vendor.
|
||||||
'2mq_quotation_items' => array( 'id', null ),
|
'2mq_quotations' => array(
|
||||||
'2mq_quotation_history' => array( 'id', null ),
|
'primary_key' => 'id',
|
||||||
'2mq_vendor_presets' => array( 'id', 'hp_vendor' ),
|
'post_type_link' => 'hp_vendor',
|
||||||
'2mq_catalog_categories' => array( 'id', null ),
|
'expected_columns' => array(
|
||||||
'2mq_catalog_items' => array( 'id', null ),
|
'id' => 'BIGINT',
|
||||||
'2mq_quotation_templates' => array( 'id', null ),
|
'vendor_id' => 'BIGINT',
|
||||||
'2mq_vendor_catalog_prices' => array( 'id', 'hp_vendor' ),
|
'template_id' => 'BIGINT',
|
||||||
|
'quote_number' => 'VARCHAR',
|
||||||
|
'status' => 'VARCHAR',
|
||||||
|
'client_name' => 'VARCHAR',
|
||||||
|
'client_email' => 'VARCHAR',
|
||||||
|
'client_phone' => 'VARCHAR',
|
||||||
|
'event_type' => 'VARCHAR',
|
||||||
|
'event_date' => 'DATE',
|
||||||
|
'event_time' => 'VARCHAR',
|
||||||
|
'event_duration_hours' => 'DECIMAL',
|
||||||
|
'event_location' => 'VARCHAR',
|
||||||
|
'venue_name' => 'VARCHAR',
|
||||||
|
'guest_count' => 'INT',
|
||||||
|
'performer_count' => 'INT',
|
||||||
|
'subtotal' => 'DECIMAL',
|
||||||
|
'discount_amount' => 'DECIMAL',
|
||||||
|
'discount_reason' => 'VARCHAR',
|
||||||
|
'tax_amount' => 'DECIMAL',
|
||||||
|
'total' => 'DECIMAL',
|
||||||
|
'currency' => 'VARCHAR',
|
||||||
|
'deposit_percent' => 'INT',
|
||||||
|
'deposit_amount' => 'DECIMAL',
|
||||||
|
'balance_amount' => 'DECIMAL',
|
||||||
|
'deposit_status' => 'VARCHAR',
|
||||||
|
'deposit_order_id' => 'BIGINT',
|
||||||
|
'client_signature' => 'TEXT',
|
||||||
|
'contract_html' => 'TEXT',
|
||||||
|
'deposit_due_days' => 'INT',
|
||||||
|
'balance_due_days' => 'INT',
|
||||||
|
'cancel_policy' => 'VARCHAR',
|
||||||
|
'included_services' => 'TEXT',
|
||||||
|
'notes' => 'TEXT',
|
||||||
|
'internal_notes' => 'TEXT',
|
||||||
|
'valid_days' => 'INT',
|
||||||
|
'valid_until' => 'DATE',
|
||||||
|
'sent_at' => 'DATETIME',
|
||||||
|
'viewed_at' => 'DATETIME',
|
||||||
|
'accepted_at' => 'DATETIME',
|
||||||
|
'declined_at' => 'DATETIME',
|
||||||
|
'access_token' => 'VARCHAR',
|
||||||
|
'created_at' => 'DATETIME',
|
||||||
|
'updated_at' => 'DATETIME',
|
||||||
|
),
|
||||||
|
'indexes' => array(
|
||||||
|
'quote_number' => array( 'quote_number' ),
|
||||||
|
'vendor_id' => array( 'vendor_id' ),
|
||||||
|
'status' => array( 'status' ),
|
||||||
|
'access_token' => array( 'access_token' ),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'2mq_quotation_items' => array(
|
||||||
|
'primary_key' => 'id',
|
||||||
|
'post_type_link' => null,
|
||||||
|
'expected_columns' => array(
|
||||||
|
'id' => 'BIGINT',
|
||||||
|
'quotation_id' => 'BIGINT',
|
||||||
|
'catalog_item_id' => 'BIGINT',
|
||||||
|
'module_code' => 'VARCHAR',
|
||||||
|
'label' => 'VARCHAR',
|
||||||
|
'description' => 'TEXT',
|
||||||
|
'quantity' => 'DECIMAL',
|
||||||
|
'unit' => 'VARCHAR',
|
||||||
|
'unit_price' => 'DECIMAL',
|
||||||
|
'subtotal' => 'DECIMAL',
|
||||||
|
'is_optional' => 'TINYINT',
|
||||||
|
'config' => 'TEXT',
|
||||||
|
'sort_order' => 'INT',
|
||||||
|
),
|
||||||
|
'indexes' => array(
|
||||||
|
'quotation_id' => array( 'quotation_id' ),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'2mq_quotation_history' => array(
|
||||||
|
'primary_key' => 'id',
|
||||||
|
'post_type_link' => null,
|
||||||
|
'expected_columns' => array(
|
||||||
|
'id' => 'BIGINT',
|
||||||
|
'quotation_id' => 'BIGINT',
|
||||||
|
'action' => 'VARCHAR',
|
||||||
|
'actor' => 'VARCHAR',
|
||||||
|
'snapshot' => 'TEXT',
|
||||||
|
'note' => 'TEXT',
|
||||||
|
'created_at' => 'DATETIME',
|
||||||
|
),
|
||||||
|
'indexes' => array(
|
||||||
|
'quotation_id' => array( 'quotation_id' ),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'2mq_vendor_presets' => array(
|
||||||
|
'primary_key' => 'id',
|
||||||
|
'post_type_link' => 'hp_vendor',
|
||||||
|
'expected_columns' => array(
|
||||||
|
'id' => 'BIGINT',
|
||||||
|
'vendor_id' => 'BIGINT',
|
||||||
|
'module_code' => 'VARCHAR',
|
||||||
|
'label' => 'VARCHAR',
|
||||||
|
'config' => 'TEXT',
|
||||||
|
'is_active' => 'TINYINT',
|
||||||
|
'sort_order' => 'INT',
|
||||||
|
'created_at' => 'DATETIME',
|
||||||
|
'updated_at' => 'DATETIME',
|
||||||
|
),
|
||||||
|
'indexes' => array(
|
||||||
|
'vendor_module' => array( 'vendor_id', 'module_code' ),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'2mq_catalog_categories' => array(
|
||||||
|
'primary_key' => 'id',
|
||||||
|
'post_type_link' => null,
|
||||||
|
'expected_columns' => array(
|
||||||
|
'id' => 'BIGINT',
|
||||||
|
'code' => 'VARCHAR',
|
||||||
|
'name' => 'VARCHAR',
|
||||||
|
'icon' => 'VARCHAR',
|
||||||
|
'sort_order' => 'INT',
|
||||||
|
'is_active' => 'TINYINT',
|
||||||
|
),
|
||||||
|
'indexes' => array(
|
||||||
|
'code' => array( 'code' ),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'2mq_catalog_items' => array(
|
||||||
|
'primary_key' => 'id',
|
||||||
|
'post_type_link' => null,
|
||||||
|
'expected_columns' => array(
|
||||||
|
'id' => 'BIGINT',
|
||||||
|
'category_code' => 'VARCHAR',
|
||||||
|
'module_code' => 'VARCHAR',
|
||||||
|
'name' => 'VARCHAR',
|
||||||
|
'description' => 'TEXT',
|
||||||
|
'unit' => 'VARCHAR',
|
||||||
|
'default_price' => 'DECIMAL',
|
||||||
|
'default_quantity' => 'DECIMAL',
|
||||||
|
'pricing_type' => 'VARCHAR',
|
||||||
|
'config' => 'TEXT',
|
||||||
|
'is_optional' => 'TINYINT',
|
||||||
|
'sort_order' => 'INT',
|
||||||
|
'is_active' => 'TINYINT',
|
||||||
|
'created_at' => 'DATETIME',
|
||||||
|
'updated_at' => 'DATETIME',
|
||||||
|
),
|
||||||
|
'indexes' => array(
|
||||||
|
'category_code' => array( 'category_code' ),
|
||||||
|
'module_code' => array( 'module_code' ),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'2mq_quotation_templates' => array(
|
||||||
|
'primary_key' => 'id',
|
||||||
|
'post_type_link' => null,
|
||||||
|
'expected_columns' => array(
|
||||||
|
'id' => 'BIGINT',
|
||||||
|
'name' => 'VARCHAR',
|
||||||
|
'description' => 'TEXT',
|
||||||
|
'event_type' => 'VARCHAR',
|
||||||
|
'items' => 'TEXT',
|
||||||
|
'config' => 'TEXT',
|
||||||
|
'sort_order' => 'INT',
|
||||||
|
'is_active' => 'TINYINT',
|
||||||
|
'created_at' => 'DATETIME',
|
||||||
|
'updated_at' => 'DATETIME',
|
||||||
|
),
|
||||||
|
'indexes' => array(
|
||||||
|
'event_type' => array( 'event_type' ),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'2mq_vendor_catalog_prices' => array(
|
||||||
|
'primary_key' => 'id',
|
||||||
|
'post_type_link' => 'hp_vendor',
|
||||||
|
'expected_columns' => array(
|
||||||
|
'id' => 'BIGINT',
|
||||||
|
'vendor_id' => 'BIGINT',
|
||||||
|
'catalog_item_id' => 'BIGINT',
|
||||||
|
'custom_price' => 'DECIMAL',
|
||||||
|
'custom_label' => 'VARCHAR',
|
||||||
|
'is_active' => 'TINYINT',
|
||||||
|
'created_at' => 'DATETIME',
|
||||||
|
'updated_at' => 'DATETIME',
|
||||||
|
),
|
||||||
|
'indexes' => array(
|
||||||
|
'vendor_item' => array( 'vendor_id', 'catalog_item_id' ),
|
||||||
|
'vendor_id' => array( 'vendor_id' ),
|
||||||
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
foreach ( $tables as $table_name => $meta ) {
|
foreach ( $tables as $table_name => $meta ) {
|
||||||
$registry->register(
|
$registry->register(
|
||||||
'2meet-quotation',
|
'2meet-quotation',
|
||||||
array(
|
array_merge( array( 'table_name' => $table_name ), $meta )
|
||||||
'table_name' => $table_name,
|
|
||||||
'primary_key' => $meta[0],
|
|
||||||
'post_type_link' => $meta[1],
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user