| @@ -10,9 +10,9 @@ | ||
| 10 | 10 | public static function getSqlSchema(): string |
| 11 | 11 | { |
| 12 | 12 | return "`id` BIGINT(20) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, |
| 13 | 13 | `order_id` BIGINT(20) UNSIGNED NOT NULL, |
| 14 | - `tax_rate_id` BIGINT(20) UNSIGNED NOT NULL, | |
| 14 | + `tax_rate_id` BIGINT(20) NOT NULL, | |
| 15 | 15 | `shipping_tax` BIGINT NULL, |
| 16 | 16 | `order_tax` BIGINT NULL, |
| 17 | 17 | `total_tax` BIGINT NULL, |
| 18 | 18 | `meta` json DEFAULT NULL, |
| @@ -24,8 +24,44 @@ | ||
| 24 | 24 | public static function migrated() |
| 25 | 25 | { |
| 26 | 26 | static::addMetaColumn(); |
| 27 | 27 | static::addFiledAtColumn(); |
| 28 | + static::allowVirtualTaxRateIds(); | |
| 29 | + static::deduplicateOrderTaxRates(); | |
| 30 | + static::addOrderTaxRateUniqueIndex(); | |
| 31 | + } | |
| 32 | + | |
| 33 | + public static function allowVirtualTaxRateIds() | |
| 34 | + { | |
| 35 | + // EU VAT registration rates are virtual and use negative IDs. Keep zero | |
| 36 | + // reserved for the no-tax sentinel while allowing those rows to persist. | |
| 37 | + static::modifyColumnIfExists('tax_rate_id', 'BIGINT(20) NOT NULL'); | |
| 38 | + } | |
| 39 | + | |
| 40 | + public static function deduplicateOrderTaxRates() | |
| 41 | + { | |
| 42 | + // Keep only the latest row per (order_id, tax_rate_id) before adding the unique | |
| 43 | + // index — duplicate keys from the old write path would cause ALTER TABLE to fail. | |
| 44 | + // | |
| 45 | + // "Latest" = highest id. Duplicates existed because the original prepareOtherData() | |
| 46 | + // path did INSERT without a uniqueness guard; the last write was always authoritative | |
| 47 | + // (it overwrote the in-memory tax_data), so keeping the highest id is correct. | |
| 48 | + // Any rows deleted here were already superseded by a later write in the same order. | |
| 49 | + global $wpdb; | |
| 50 | + $table = $wpdb->prefix . static::$tableName; | |
| 51 | + // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared | |
| 52 | + $wpdb->query(" | |
| 53 | + DELETE t1 FROM `{$table}` t1 | |
| 54 | + INNER JOIN `{$table}` t2 | |
| 55 | + ON t1.order_id = t2.order_id | |
| 56 | + AND t1.tax_rate_id = t2.tax_rate_id | |
| 57 | + AND t1.id < t2.id | |
| 58 | + "); | |
| 59 | + } | |
| 60 | + | |
| 61 | + public static function addOrderTaxRateUniqueIndex() | |
| 62 | + { | |
| 63 | + static::addIndexIfNotExists('uniq_order_tax_rate', ['order_id', 'tax_rate_id'], true); | |
| 28 | 64 | } |
| 29 | 65 | |
| 30 | 66 | public static function addMetaColumn() |
| 31 | 67 | { |