Files
jiu/backend/internal/service/migrate.go
T
wangjia 4fd0bb8b83 feat(backend): 出入库定价字段消歧 + 总利润落库 + 成本仅管理员可见
- 字段重命名(旧列弃用保留,启动幂等回填 BackfillPricingColumns):
  入库 unit_price/total_price/total_amount → cost_price/cost_amount/cost_total;
  出库同前缀 + 新增 sale_amount(售价小计)/ sale_total(应收)/ profit_total(总利润)
- 建单落三值;确认售价联动重算 sale_amount/sale_total/profit_total;
  确认进价回填成本后联动重算受影响出库单利润(recalcStockOutProfit)
- 出库 List/Get 对 operator/readonly 抹零成本与利润(stripStockOutCost 服务端兜底)
- 兼容一版:Create/Update 接受旧 key unit_price 回落(v1.0.87 及之前客户端)
- SUM 聚合/价格趋势/导入/种子工具同步切新列;测试全量改名 + 6 个新回归

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JJ1g8XV1YhhmHRzhwWEW7o
2026-07-03 12:44:22 +08:00

52 lines
2.5 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package service
import (
"log"
"gorm.io/gorm"
"github.com/wangjia/jiu/backend/internal/model"
)
// BackfillPricingColumns 2026-07 定价字段消歧的一次性数据迁移(幂等,可反复执行):
// - stock_in_items / stock_out_itemsunit_price→cost_price、total_price→cost_amount
// - stock_in_orderstotal_amount→cost_totalstock_out_orderstotal_amount→sale_total
// - stock_out_items.sale_amount = sale_price×quantity(待定价行保持 0
// - stock_out_orders.profit_total = Σ(sale_price>0 ? (sale_price-cost_price)×qty : 0)
//
// 只在新列为 0 且旧列非 0 时拷贝,不修改旧列(旧列观察一版后手动 DROP)。
// profit_total 以「为 0 且存在已定价明细」为待回填判据——利润恰为 0 的单重算一次
// 结果不变,幂等。全新安装(schema.sql 已无旧列)时整体跳过。
func BackfillPricingColumns(db *gorm.DB) {
// 旧列存在性守卫:四张表的旧列是同批产生的,抽查一张即可
// model 已无 UnitPrice 字段,HasColumn 会按原始列名探测)
if !db.Migrator().HasColumn(&model.StockOutItem{}, "unit_price") {
return
}
stmts := []string{
`UPDATE stock_in_items SET cost_price = unit_price WHERE cost_price = 0 AND unit_price <> 0`,
`UPDATE stock_in_items SET cost_amount = total_price WHERE cost_amount = 0 AND total_price <> 0`,
`UPDATE stock_in_orders SET cost_total = total_amount WHERE cost_total = 0 AND total_amount <> 0`,
`UPDATE stock_out_items SET cost_price = unit_price WHERE cost_price = 0 AND unit_price <> 0`,
`UPDATE stock_out_items SET cost_amount = total_price WHERE cost_amount = 0 AND total_price <> 0`,
`UPDATE stock_out_items SET sale_amount = sale_price * quantity WHERE sale_amount = 0 AND sale_price > 0`,
`UPDATE stock_out_orders SET sale_total = total_amount WHERE sale_total = 0 AND total_amount <> 0`,
`UPDATE stock_out_orders SET profit_total = (
SELECT COALESCE(SUM(CASE WHEN i.sale_price > 0
THEN (i.sale_price - i.cost_price) * i.quantity ELSE 0 END), 0)
FROM stock_out_items i WHERE i.order_id = stock_out_orders.id
) WHERE profit_total = 0 AND EXISTS (
SELECT 1 FROM stock_out_items i2
WHERE i2.order_id = stock_out_orders.id AND i2.sale_price > 0
)`,
}
for _, q := range stmts {
res := db.Exec(q)
if res.Error != nil {
log.Printf("backfill pricing columns failed (%.60s...): %v", q, res.Error)
} else if res.RowsAffected > 0 {
log.Printf("backfill pricing: %d rows (%.60s...)", res.RowsAffected, q)
}
}
}