-- 物流单绑定包裹/库存: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 SET @col_exists := ( SELECT COUNT(1) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'C_inventory' AND COLUMN_NAME = 'FrozenQty' ); SET @sql := IF( @col_exists = 0, 'ALTER TABLE `C_inventory` ADD COLUMN `FrozenQty` INT NOT NULL DEFAULT 0 COMMENT ''冻结数量'' AFTER `Qty`', 'SELECT ''C_inventory.FrozenQty already exists'' AS info' ); PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt; -- C_inventory.AvailableQty SET @col_exists := ( SELECT COUNT(1) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'C_inventory' AND COLUMN_NAME = 'AvailableQty' ); SET @sql := IF( @col_exists = 0, 'ALTER TABLE `C_inventory` ADD COLUMN `AvailableQty` INT NOT NULL DEFAULT 0 COMMENT ''可用=Qty-FrozenQty'' AFTER `FrozenQty`', 'SELECT ''C_inventory.AvailableQty already exists'' AS info' ); PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt; UPDATE `C_inventory` 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); -- C_parcel_item.FrozenQty SET @col_exists := ( SELECT COUNT(1) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'C_parcel_item' AND COLUMN_NAME = 'FrozenQty' ); SET @sql := IF( @col_exists = 0, 'ALTER TABLE `C_parcel_item` ADD COLUMN `FrozenQty` INT NOT NULL DEFAULT 0 COMMENT ''冻结数量'' AFTER `Quantity`', 'SELECT ''C_parcel_item.FrozenQty already exists'' AS info' ); PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt; -- C_parcel_item.AvailableQty SET @col_exists := ( SELECT COUNT(1) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'C_parcel_item' AND COLUMN_NAME = 'AvailableQty' ); SET @sql := IF( @col_exists = 0, 'ALTER TABLE `C_parcel_item` ADD COLUMN `AvailableQty` INT NOT NULL DEFAULT 0 COMMENT ''可用=Quantity-FrozenQty'' AFTER `FrozenQty`', 'SELECT ''C_parcel_item.AvailableQty already exists'' AS info' ); PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt; UPDATE `C_parcel_item` 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);