完善配送订单创建联动

This commit is contained in:
czl231
2026-08-23 11:30:52 +08:00
parent c07c9ea6f2
commit 59a01192c0
15 changed files with 935 additions and 163 deletions

View File

@@ -1,5 +1,5 @@
// 功能描述:实现配送点范围内的合同、合同气瓶和配送订单接口。
// 版本v1.1.0。
// 版本v1.2.0。
package delivery
import (
@@ -49,23 +49,33 @@ func scopedContract(ctx *gin.Context, identity string, pointID uint64) (models.G
return contract, true
}
// deliveryContractListQuery 构造当前配送点合同列表;订单候选模式额外限定可履约状态。
func deliveryContractListQuery(database *gorm.DB, gasID, pointID uint64, candidate string, now time.Time) *gorm.DB {
query := platformgasorder.ContractPartyDisplayQuery(database).
Where("gasorder_contract.gas_basic_id = ? AND gasorder_contract.delivery_basic_id = ?", gasID, pointID)
if candidate == "order" {
return platformgasorder.FilterGasorderContractCandidates(query, "order", now)
}
return query
}
func ListContract(ctx *gin.Context) {
point, _, ok := currentScope(ctx)
if !ok {
return
}
page, size := common.PageSize(ctx)
query := common.ApplyKeywordFilter(ctx,
common.ActiveRecords(db().Model(&models.GasorderContract{})).
Where("gas_basic_id = ? AND delivery_basic_id = ?", point.GasBasicID, point.ID),
&models.GasorderContract{})
query := deliveryContractListQuery(
db(), point.GasBasicID, point.ID, strings.TrimSpace(ctx.Query("candidate")), time.Now(),
)
query = common.ApplyKeywordFilter(ctx, query, &models.GasorderContract{})
var total int64
if err := query.Count(&total).Error; err != nil {
infra.Response.Error(ctx, err)
return
}
var list []models.GasorderContract
if err := query.Order("gasorder_contract.created_at desc").Offset((page - 1) * size).Limit(size).Find(&list).Error; err != nil {
var list []platformgasorder.ContractPartyDisplay
if err := query.Order("gasorder_contract.created_at desc").Offset((page - 1) * size).Limit(size).Scan(&list).Error; err != nil {
infra.Response.Error(ctx, err)
return
}
@@ -74,7 +84,11 @@ func ListContract(ctx *gin.Context) {
infra.Response.Error(ctx, err)
return
}
protected, err := protectDeliveryContractListResponse(ctx, response, list)
contracts := make([]models.GasorderContract, 0, len(list))
for _, item := range list {
contracts = append(contracts, item.GasorderContract)
}
protected, err := protectDeliveryContractListResponse(ctx, response, contracts)
if err != nil {
infra.Response.Error(ctx, err)
return
@@ -186,15 +200,63 @@ func TerminateContract(ctx *gin.Context) {
withContract(ctx, platformgasorder.TerminateGasorderContract)
}
// deliveryContractProductQuery 构造当前配送点合同气瓶查询;指定合同时仅保留未解绑候选。
func deliveryContractProductQuery(database *gorm.DB, pointID, contractID uint64, keyword string) *gorm.DB {
query := common.ActiveRecords(database.Model(&models.GasorderContractProduct{})).
Select("gasorder_contract_product.*, COALESCE(display_product.name, '') AS product_name").
Joins("JOIN gasorder_contract ON gasorder_contract.id = gasorder_contract_product.gasorder_contract_id").
Joins("LEFT JOIN product_info AS display_product ON display_product.id = gasorder_contract_product.product_info_id AND display_product.deleted_at IS NULL AND display_product.status <> ?", common.StatusArchived).
Where("gasorder_contract.delivery_basic_id = ?", pointID)
if contractID > 0 {
query = query.Where("gasorder_contract_product.gasorder_contract_id = ? AND gasorder_contract_product.unbound_at IS NULL", contractID)
}
keyword = strings.ToLower(strings.TrimSpace(keyword))
if keyword == "" {
return query
}
pattern := "%" + keyword + "%"
return query.Where("(LOWER(COALESCE(display_product.name, '')) LIKE ? OR LOWER(gasorder_contract_product.product_code) LIKE ? OR LOWER(gasorder_contract_product.product_type_name) LIKE ?)", pattern, pattern, pattern)
}
func ListContractProduct(ctx *gin.Context) {
point, _, ok := currentScope(ctx)
if !ok {
return
}
query := common.ActiveRecords(db().Model(&models.GasorderContractProduct{})).
Joins("JOIN gasorder_contract ON gasorder_contract.id = gasorder_contract_product.gasorder_contract_id").
Where("gasorder_contract.delivery_basic_id = ?", point.ID)
listScoped(ctx, &models.GasorderContractProduct{}, query, "gasorder_contract_product.created_at desc")
contractIdentity := strings.TrimSpace(ctx.Query("contract_identity"))
var contractID uint64
if contractIdentity != "" {
contract, valid := scopedContract(ctx, contractIdentity, point.ID)
if !valid {
return
}
contractID = contract.ID
}
query := deliveryContractProductQuery(db(), point.ID, contractID, ctx.Query("keyword"))
page, size := common.PageSize(ctx)
var total int64
if err := query.Count(&total).Error; err != nil {
infra.Response.Error(ctx, err)
return
}
type contractProductDisplay struct {
models.GasorderContractProduct
ProductName string `gorm:"column:product_name" json:"product_name"`
}
var list []contractProductDisplay
if err := query.Order("gasorder_contract_product.created_at desc").Offset((page - 1) * size).Limit(size).Scan(&list).Error; err != nil {
infra.Response.Error(ctx, err)
return
}
response, err := common.PublicResourceResponse(list)
if err != nil {
infra.Response.Error(ctx, err)
return
}
infra.Response.Success(ctx, gin.H{
"total": total,
"list": common.ProtectPreciseLocation(ctx, &models.GasorderContractProduct{}, response),
})
}
func GetContractProduct(ctx *gin.Context) {

View File

@@ -0,0 +1,78 @@
// 功能描述:验证配送点创建订单的合同、地址和合同气瓶候选查询范围。
// 版本v1.0.0。
package delivery
import (
"strings"
"testing"
"time"
"github.com/DATA-DOG/go-sqlmock"
"gorm.io/driver/postgres"
"gorm.io/gorm"
)
// candidateTestDatabase 创建只用于生成 SQL 的模拟数据库。
func candidateTestDatabase(t *testing.T) *gorm.DB {
t.Helper()
sqlDatabase, _, err := sqlmock.New()
if err != nil {
t.Fatalf("创建模拟数据库失败:%v", err)
}
t.Cleanup(func() { _ = sqlDatabase.Close() })
database, err := gorm.Open(postgres.New(postgres.Config{Conn: sqlDatabase}), &gorm.Config{})
if err != nil {
t.Fatalf("创建 GORM 数据库失败:%v", err)
}
return database
}
// assertSQLFragments 验证候选查询包含全部范围约束。
func assertSQLFragments(t *testing.T, statement string, fragments ...string) {
t.Helper()
for _, fragment := range fragments {
if !strings.Contains(statement, fragment) {
t.Fatalf("候选 SQL 缺少 %q%s", fragment, statement)
}
}
}
func TestDeliveryOrderContractCandidates(t *testing.T) {
database := candidateTestDatabase(t)
statement := database.ToSQL(func(tx *gorm.DB) *gorm.DB {
return deliveryContractListQuery(tx, 7, 9, "order", time.Now()).Find(&[]map[string]any{})
})
assertSQLFragments(t, statement,
"gasorder_contract.gas_basic_id = 7",
"gasorder_contract.delivery_basic_id = 9",
"candidate_relation.user_account_id = gasorder_contract.user_account_id",
"contract_status = 11",
)
}
func TestDeliveryOrderAddressCandidates(t *testing.T) {
database := candidateTestDatabase(t)
statement := database.ToSQL(func(tx *gorm.DB) *gorm.DB {
return addressQueryForContract(
addressQueryWithDatabase(tx, 9), 31,
).Find(&[]map[string]any{})
})
assertSQLFragments(t, statement,
"user_service_relation.delivery_basic_id = 9",
"user_address.user_account_id = 31",
)
}
func TestDeliveryOrderContractProductCandidates(t *testing.T) {
database := candidateTestDatabase(t)
statement := database.ToSQL(func(tx *gorm.DB) *gorm.DB {
return deliveryContractProductQuery(tx, 9, 27, "阀门").Find(&[]map[string]any{})
})
assertSQLFragments(t, statement,
"gasorder_contract.delivery_basic_id = 9",
"gasorder_contract_product.gasorder_contract_id = 27",
"gasorder_contract_product.unbound_at IS NULL",
"display_product.name",
"gasorder_contract_product.product_code",
)
}

View File

@@ -1,7 +1,10 @@
// 功能描述:实现配送点范围内的用户、服务关系和收货地址管理。
// 版本v1.1.0。
package delivery
import (
"errors"
"strings"
"git.apinb.com/bsm-sdk/core/errcode"
"git.apinb.com/bsm-sdk/core/infra"
@@ -231,16 +234,35 @@ func ArchiveUser(ctx *gin.Context) {
}
func addressQuery(pointID uint64) *gorm.DB {
return common.ActiveRecords(db().Model(&models.UserAddress{})).
return addressQueryWithDatabase(db(), pointID)
}
// addressQueryWithDatabase 构造配送点有效服务用户的地址范围,便于独立验证查询约束。
func addressQueryWithDatabase(database *gorm.DB, pointID uint64) *gorm.DB {
return common.ActiveRecords(database.Model(&models.UserAddress{})).
Joins("JOIN user_service_relation ON user_service_relation.user_account_id = user_address.user_account_id AND user_service_relation.status <> ?",
common.StatusArchived).Where("user_service_relation.delivery_basic_id = ?", pointID)
}
// addressQueryForContract 将当前配送点地址进一步限定为合同签约用户。
func addressQueryForContract(query *gorm.DB, userAccountID uint64) *gorm.DB {
return query.Where("user_address.user_account_id = ?", userAccountID)
}
func ListAddress(ctx *gin.Context) {
point, _, ok := currentScope(ctx)
if ok {
listScoped(ctx, &models.UserAddress{}, addressQuery(point.ID), "user_address.created_at desc")
if !ok {
return
}
query := addressQuery(point.ID)
if contractIdentity := strings.TrimSpace(ctx.Query("gasorder_contract_identity")); contractIdentity != "" {
contract, valid := scopedContract(ctx, contractIdentity, point.ID)
if !valid {
return
}
query = addressQueryForContract(query, contract.UserAccountID)
}
listScoped(ctx, &models.UserAddress{}, query, "user_address.is_default desc, user_address.created_at desc")
}
func GetAddress(ctx *gin.Context) {