fix: 采购价格上限按数量计算总价 (#181)
This commit is contained in:
@@ -3,6 +3,7 @@ package service
|
||||
import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"math"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -143,7 +144,8 @@ func TestSybMapping_动态维度保存并复用(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if list.Total != 1 || !list.Rows[0].CanPurchase || list.Rows[0].DefaultMaxPrice != "39.90" {
|
||||
if list.Total != 1 || !list.Rows[0].CanPurchase || list.Rows[0].DefaultUnitPrice != "39.90" ||
|
||||
list.Rows[0].DefaultTotalPrice != "39.90" {
|
||||
t.Fatalf("可采购阶段不对: %+v", list)
|
||||
}
|
||||
row := list.Rows[0]
|
||||
@@ -300,6 +302,9 @@ func stringsReplaceGoodsID(raw string) string {
|
||||
func TestCreatePurchaseTasks_安全字段和重复保护(t *testing.T) {
|
||||
db := newTestDB(t)
|
||||
key := seedPurchasableWorkflow(t, db, "SYB-1")
|
||||
if _, err := db.Exec(`UPDATE syb_orders SET quantity=2 WHERE syb_id='SYB-1'`); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := SaveSybMapping(db, "SYB-1", key, "USR-1"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -309,7 +314,7 @@ func TestCreatePurchaseTasks_安全字段和重复保护(t *testing.T) {
|
||||
}
|
||||
|
||||
result, err := CreatePurchaseTasks(db, admin,
|
||||
[]PurchaseTaskRequest{{SybID: "SYB-1", MaxPriceCent: 4200}}, "CLIENT-1")
|
||||
[]PurchaseTaskRequest{{SybID: "SYB-1", UnitPriceLimitCent: 4200}}, "CLIENT-1")
|
||||
if err != nil || result.Created != 1 || len(result.Failures) != 0 {
|
||||
t.Fatalf("创建结果=%+v err=%v", result, err)
|
||||
}
|
||||
@@ -324,18 +329,18 @@ func TestCreatePurchaseTasks_安全字段和重复保护(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if taskID != "cg1" || status != "assigned" || task.MaxPriceCent != 4200 || task.MaxPriceCent == 999900 ||
|
||||
task.Quantity != 1 || task.PddOptions != key || task.AssignedClient != "CLIENT-1" {
|
||||
if taskID != "cg1" || status != "assigned" || task.MaxPriceCent != 8400 || task.MaxPriceCent == 999900 ||
|
||||
task.Quantity != 2 || task.PddOptions != key || task.AssignedClient != "CLIENT-1" {
|
||||
t.Fatalf("采购任务字段不安全或不完整: status=%s task=%+v", status, task)
|
||||
}
|
||||
claimed, err := repository.ClaimNextTask(db, "CLIENT-1", []string{"purchase"})
|
||||
if err != nil || claimed == nil || claimed.PddOptions != key ||
|
||||
claimed.Quantity != 1 || claimed.MaxPriceCent != 4200 {
|
||||
claimed.Quantity != 2 || claimed.MaxPriceCent != 8400 {
|
||||
t.Fatalf("现有 Client 领取契约读不到完整采购参数: task=%+v err=%v", claimed, err)
|
||||
}
|
||||
|
||||
second, err := CreatePurchaseTasks(db, admin,
|
||||
[]PurchaseTaskRequest{{SybID: "SYB-1", MaxPriceCent: 4300}}, "CLIENT-1")
|
||||
[]PurchaseTaskRequest{{SybID: "SYB-1", UnitPriceLimitCent: 4300}}, "CLIENT-1")
|
||||
if err != nil || second.Created != 0 || len(second.Failures) != 1 {
|
||||
t.Fatalf("重复提交应逐条拒绝: result=%+v err=%v", second, err)
|
||||
}
|
||||
@@ -363,7 +368,7 @@ func TestCreatePurchaseTasks_成功或待核对任务禁止重复采购(t *testi
|
||||
t.Fatal(err)
|
||||
}
|
||||
created, err := CreatePurchaseTasks(db, admin,
|
||||
[]PurchaseTaskRequest{{SybID: "SYB-LOCKED", MaxPriceCent: 4200}}, "CLIENT-1")
|
||||
[]PurchaseTaskRequest{{SybID: "SYB-LOCKED", UnitPriceLimitCent: 4200}}, "CLIENT-1")
|
||||
if err != nil || created.Created != 1 {
|
||||
t.Fatalf("准备采购任务失败: result=%+v err=%v", created, err)
|
||||
}
|
||||
@@ -373,7 +378,7 @@ func TestCreatePurchaseTasks_成功或待核对任务禁止重复采购(t *testi
|
||||
|
||||
before := countPurchaseTasksForSyb(t, db, "SYB-LOCKED")
|
||||
result, err := CreatePurchaseTasks(db, admin,
|
||||
[]PurchaseTaskRequest{{SybID: "SYB-LOCKED", MaxPriceCent: 4300}}, "CLIENT-1")
|
||||
[]PurchaseTaskRequest{{SybID: "SYB-LOCKED", UnitPriceLimitCent: 4300}}, "CLIENT-1")
|
||||
if err != nil || result.Created != 0 || len(result.Failures) != 1 ||
|
||||
!strings.Contains(result.Failures[0].Reason, tc.wantReason) {
|
||||
t.Fatalf("%s 任务必须阻止重复采购: result=%+v err=%v", tc.status, result, err)
|
||||
@@ -408,11 +413,11 @@ func TestCreatePurchaseTasks_客户端权限和逐条失败(t *testing.T) {
|
||||
AssignClient(db, admin, "CLIENT-A", buyerA.UserID, time.Now())
|
||||
|
||||
if _, err := CreatePurchaseTasks(db, buyerB,
|
||||
[]PurchaseTaskRequest{{SybID: "SYB-1", MaxPriceCent: 4200}}, "CLIENT-A"); err == nil {
|
||||
[]PurchaseTaskRequest{{SybID: "SYB-1", UnitPriceLimitCent: 4200}}, "CLIENT-A"); err == nil {
|
||||
t.Fatal("采购员不得使用其他采购员的客户端")
|
||||
}
|
||||
result, err := CreatePurchaseTasks(db, buyerA,
|
||||
[]PurchaseTaskRequest{{SybID: "SYB-1", MaxPriceCent: 0}, {SybID: "NOT-FOUND", MaxPriceCent: 100}}, "CLIENT-A")
|
||||
[]PurchaseTaskRequest{{SybID: "SYB-1", UnitPriceLimitCent: 0}, {SybID: "NOT-FOUND", UnitPriceLimitCent: 100}}, "CLIENT-A")
|
||||
if err != nil || result.Created != 0 || len(result.Failures) != 2 {
|
||||
t.Fatalf("业务失败应逐条返回且不创建: result=%+v err=%v", result, err)
|
||||
}
|
||||
@@ -425,8 +430,8 @@ func TestCreatePurchaseTasks_部分业务失败不影响有效明细(t *testing.
|
||||
admin, _, _ := prepareClientAssignmentUsers(t, db)
|
||||
RegisterClient(db, model.Client{ClientID: "CLIENT-1"}, true)
|
||||
result, err := CreatePurchaseTasks(db, admin, []PurchaseTaskRequest{
|
||||
{SybID: "NOT-FOUND", MaxPriceCent: 100},
|
||||
{SybID: "SYB-1", MaxPriceCent: 4200},
|
||||
{SybID: "NOT-FOUND", UnitPriceLimitCent: 100},
|
||||
{SybID: "SYB-1", UnitPriceLimitCent: 4200},
|
||||
}, "CLIENT-1")
|
||||
if err != nil || result.Created != 1 || len(result.Failures) != 1 || result.Failures[0].SybID != "NOT-FOUND" {
|
||||
t.Fatalf("部分失败边界不对: result=%+v err=%v", result, err)
|
||||
@@ -446,7 +451,7 @@ func TestCreatePurchaseTasksWithOptions_正常采购员可创建真实任务(t *
|
||||
}
|
||||
|
||||
result, err := CreatePurchaseTasksWithOptions(db, buyer,
|
||||
[]PurchaseTaskRequest{{SybID: "SYB-LIVE", MaxPriceCent: 4200}},
|
||||
[]PurchaseTaskRequest{{SybID: "SYB-LIVE", UnitPriceLimitCent: 4200}},
|
||||
PurchaseTaskOptions{ClientID: "CLIENT-LIVE", ExecutionMode: model.TaskExecutionLive})
|
||||
if err != nil || result.Created != 1 {
|
||||
t.Fatalf("正常采购员创建真实任务失败: result=%+v err=%v", result, err)
|
||||
@@ -470,7 +475,7 @@ func TestCreatePurchaseTasksWithOptions_真实模式不要求Client预先声明L
|
||||
SaveSybMapping(db, "SYB-GATE", key, "USR-1")
|
||||
admin, _, _ := prepareClientAssignmentUsers(t, db)
|
||||
RegisterClient(db, model.Client{ClientID: "CLIENT-DRY", Capabilities: `{"purchase_mode":"dry_run"}`}, true)
|
||||
request := []PurchaseTaskRequest{{SybID: "SYB-GATE", MaxPriceCent: 4200}}
|
||||
request := []PurchaseTaskRequest{{SybID: "SYB-GATE", UnitPriceLimitCent: 4200}}
|
||||
|
||||
result, err := CreatePurchaseTasksWithOptions(db, admin, request, PurchaseTaskOptions{
|
||||
ClientID: "CLIENT-DRY", ExecutionMode: model.TaskExecutionLive,
|
||||
@@ -496,7 +501,7 @@ func TestCreatePurchaseTasksWithOptions_离线Live客户端可提前指派(t *te
|
||||
}
|
||||
|
||||
result, err := CreatePurchaseTasksWithOptions(db, admin,
|
||||
[]PurchaseTaskRequest{{SybID: "SYB-OFFLINE", MaxPriceCent: 4200}},
|
||||
[]PurchaseTaskRequest{{SybID: "SYB-OFFLINE", UnitPriceLimitCent: 4200}},
|
||||
PurchaseTaskOptions{ClientID: "CLIENT-OFFLINE", ExecutionMode: model.TaskExecutionLive})
|
||||
if err != nil || result.Created != 1 {
|
||||
t.Fatalf("离线 live 客户端应可提前指派: result=%+v err=%v", result, err)
|
||||
@@ -518,7 +523,7 @@ func TestCreatePurchaseTasksWithOptions_拒绝弹窗打开后变化的规格映
|
||||
RegisterClient(db, model.Client{ClientID: "CLIENT-LIVE", Capabilities: `{"purchase_mode":"live"}`}, true)
|
||||
|
||||
result, err := CreatePurchaseTasksWithOptions(db, admin,
|
||||
[]PurchaseTaskRequest{{SybID: "SYB-STALE", MaxPriceCent: 3990,
|
||||
[]PurchaseTaskRequest{{SybID: "SYB-STALE", UnitPriceLimitCent: 3990,
|
||||
MappingOptionKey: blackKey, ContextVersion: oldVersion}},
|
||||
PurchaseTaskOptions{ClientID: "CLIENT-LIVE", ExecutionMode: model.TaskExecutionLive})
|
||||
if err != nil || result.Created != 0 || len(result.Failures) != 1 ||
|
||||
@@ -540,3 +545,18 @@ func TestParsePriceYuanToCent_精确转换(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCalculateOrderPriceLimitCent_按数量计算且拒绝溢出(t *testing.T) {
|
||||
got, err := CalculateOrderPriceLimitCent(1180, 2)
|
||||
if err != nil || got != 2360 {
|
||||
t.Fatalf("1180 × 2 = %d, %v; want 2360", got, err)
|
||||
}
|
||||
for _, tc := range []struct {
|
||||
unit int64
|
||||
qty int
|
||||
}{{0, 2}, {1180, 0}, {math.MaxInt64, 2}} {
|
||||
if _, err := CalculateOrderPriceLimitCent(tc.unit, tc.qty); err == nil {
|
||||
t.Fatalf("应拒绝 unit=%d qty=%d", tc.unit, tc.qty)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user