-- 物流单绑定包裹/库存:t_order_stock_bind + c_inventory/c_parcel_item 冻结与可用字段 -- 见 oms系统设计-050801.md §4.2.11 / §4.4.6 / §3.1.2 -- ConcurrencyStamp 默认用固定 GUID,避免 DEFAULT (UUID()) 触发复制 1674 -- 可重复执行 CREATE TABLE IF NOT EXISTS `t_order_stock_bind` ( `Id` INT NOT NULL AUTO_INCREMENT, `OrderId` INT NOT NULL COMMENT '物流单 t_order.Id', `CustomerId` INT NOT NULL COMMENT '客户隔离键', `WarehouseId` INT NOT NULL COMMENT '仓库', `BindType` VARCHAR(20) NOT NULL COMMENT 'inventory / parcelItem', `SkuId` INT NULL COMMENT 'SKU', `InventoryId` INT NULL COMMENT 'c_inventory.Id,可空=按SKU分摊', `BinLocationId` INT NULL COMMENT '库位快照', `ParcelId` INT NULL COMMENT 'c_parcel.Id', `ParcelItemId` INT NULL COMMENT 'c_parcel_item.Id', `BindQty` INT NOT NULL COMMENT '绑定数量', `Status` VARCHAR(20) NOT NULL DEFAULT 'bound' COMMENT 'bound/deducted/released', `SkuCode` VARCHAR(64) NULL, `SkuName` VARCHAR(128) NULL, `TrackingNo` VARCHAR(64) NULL, `ProductName` VARCHAR(256) NULL, `ImageUrl` VARCHAR(512) NULL, `AttributeText` VARCHAR(256) NULL, `Remark` VARCHAR(512) NULL, `IsDeleted` TINYINT NOT NULL DEFAULT 0, `ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000' COMMENT '并发戳', `CreateUserId` INT NOT NULL, `CreateTime` DATETIME NOT NULL, `UpdateUserId` INT NULL, `UpdateTime` DATETIME NULL, PRIMARY KEY (`Id`), KEY `idx_osb_order` (`OrderId`, `IsDeleted`, `Status`), KEY `idx_osb_parcel_item` (`ParcelItemId`, `Status`, `IsDeleted`), KEY `idx_osb_sku` (`CustomerId`, `WarehouseId`, `SkuId`, `Status`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='物流单仓储绑定明细'; -- 已建表但缺 ConcurrencyStamp 时补列(可重复执行) SET @col_exists := ( SELECT COUNT(1) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 't_order_stock_bind' AND COLUMN_NAME = 'ConcurrencyStamp' ); SET @sql := IF( @col_exists = 0, 'ALTER TABLE `t_order_stock_bind` ADD COLUMN `ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT ''00000000-0000-0000-0000-000000000000'' COMMENT ''并发戳'' AFTER `IsDeleted`', 'SELECT ''t_order_stock_bind.ConcurrencyStamp already exists'' AS info' ); PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt; -- c_inventory.FrozenQty(兼容尚未 rename 的旧表名 C_inventory) SET @inv_table := IF( EXISTS (SELECT 1 FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'c_inventory'), 'c_inventory', IF( EXISTS (SELECT 1 FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'C_inventory'), 'C_inventory', NULL ) ); SET @col_exists := IF(@inv_table IS NULL, 1, (SELECT COUNT(1) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = @inv_table AND COLUMN_NAME = 'FrozenQty') ); SET @sql := IF(@inv_table IS NULL OR @col_exists > 0, 'SELECT ''c_inventory.FrozenQty already exists or table missing'' AS info', CONCAT('ALTER TABLE `', @inv_table, '` ADD COLUMN `FrozenQty` INT NOT NULL DEFAULT 0 COMMENT ''冻结数量'' AFTER `Qty`') ); PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @col_exists := IF(@inv_table IS NULL, 1, (SELECT COUNT(1) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = @inv_table AND COLUMN_NAME = 'AvailableQty') ); SET @sql := IF(@inv_table IS NULL OR @col_exists > 0, 'SELECT ''c_inventory.AvailableQty already exists or table missing'' AS info', CONCAT('ALTER TABLE `', @inv_table, '` ADD COLUMN `AvailableQty` INT NOT NULL DEFAULT 0 COMMENT ''可用=Qty-FrozenQty'' AFTER `FrozenQty`') ); PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @sql := IF(@inv_table IS NULL, 'SELECT ''c_inventory table missing'' AS info', CONCAT('UPDATE `', @inv_table, '` SET `AvailableQty` = GREATEST(0, `Qty` - IFNULL(`FrozenQty`, 0)) WHERE `AvailableQty` <> GREATEST(0, `Qty` - IFNULL(`FrozenQty`, 0)) OR (`AvailableQty` = 0 AND `Qty` > 0 AND IFNULL(`FrozenQty`, 0) = 0)') ); PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt; -- c_parcel_item.FrozenQty SET @pi_table := IF( EXISTS (SELECT 1 FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'c_parcel_item'), 'c_parcel_item', IF( EXISTS (SELECT 1 FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'C_parcel_item'), 'C_parcel_item', NULL ) ); SET @col_exists := IF(@pi_table IS NULL, 1, (SELECT COUNT(1) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = @pi_table AND COLUMN_NAME = 'FrozenQty') ); SET @sql := IF(@pi_table IS NULL OR @col_exists > 0, 'SELECT ''c_parcel_item.FrozenQty already exists or table missing'' AS info', CONCAT('ALTER TABLE `', @pi_table, '` ADD COLUMN `FrozenQty` INT NOT NULL DEFAULT 0 COMMENT ''冻结数量'' AFTER `Quantity`') ); PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @col_exists := IF(@pi_table IS NULL, 1, (SELECT COUNT(1) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = @pi_table AND COLUMN_NAME = 'AvailableQty') ); SET @sql := IF(@pi_table IS NULL OR @col_exists > 0, 'SELECT ''c_parcel_item.AvailableQty already exists or table missing'' AS info', CONCAT('ALTER TABLE `', @pi_table, '` ADD COLUMN `AvailableQty` INT NOT NULL DEFAULT 0 COMMENT ''可用=Quantity-FrozenQty'' AFTER `FrozenQty`') ); PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @sql := IF(@pi_table IS NULL, 'SELECT ''c_parcel_item table missing'' AS info', CONCAT('UPDATE `', @pi_table, '` SET `AvailableQty` = GREATEST(0, `Quantity` - IFNULL(`FrozenQty`, 0)) WHERE `AvailableQty` <> GREATEST(0, `Quantity` - IFNULL(`FrozenQty`, 0)) OR (`AvailableQty` = 0 AND `Quantity` > 0 AND IFNULL(`FrozenQty`, 0) = 0)') ); PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;