370 lines
12 KiB
Go
370 lines
12 KiB
Go
// 功能描述:实现气站范围内的配送合同、合同气瓶和燃气配送订单接口。
|
||
// 版本:v1.1.0
|
||
package gas
|
||
|
||
import (
|
||
"bytes"
|
||
"encoding/json"
|
||
"io"
|
||
"reflect"
|
||
"strings"
|
||
"time"
|
||
|
||
"git.apinb.com/bsm-sdk/core/errcode"
|
||
"git.apinb.com/bsm-sdk/core/infra"
|
||
"git.apinb.com/heqiapp/platforms/backend/api/internal/impl"
|
||
"git.apinb.com/heqiapp/platforms/backend/api/internal/logic/common"
|
||
platformgasorder "git.apinb.com/heqiapp/platforms/backend/api/internal/logic/platform/gasorder"
|
||
"git.apinb.com/heqiapp/platforms/backend/api/internal/models"
|
||
"github.com/gin-gonic/gin"
|
||
"gorm.io/gorm"
|
||
)
|
||
|
||
func rewriteJSON(ctx *gin.Context, mutate func(map[string]any) bool) bool {
|
||
body, err := io.ReadAll(ctx.Request.Body)
|
||
if err != nil {
|
||
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
|
||
return false
|
||
}
|
||
var values map[string]any
|
||
if err := json.Unmarshal(body, &values); err != nil || !mutate(values) {
|
||
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
|
||
return false
|
||
}
|
||
body, err = json.Marshal(values)
|
||
if err != nil {
|
||
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
|
||
return false
|
||
}
|
||
ctx.Request.Body = io.NopCloser(bytes.NewReader(body))
|
||
return true
|
||
}
|
||
|
||
func scopedContract(ctx *gin.Context, identity string, gasID uint64) (models.GasorderContract, bool) {
|
||
var contract models.GasorderContract
|
||
if err := common.ActiveRecords(impl.DBService).Where("identity = ? AND gas_basic_id = ?", identity, gasID).First(&contract).Error; err != nil {
|
||
common.RespondRecordError(ctx, err)
|
||
return contract, false
|
||
}
|
||
return contract, true
|
||
}
|
||
|
||
func scopedOrder(ctx *gin.Context, identity string, gasID uint64) (models.GasorderBasic, bool) {
|
||
var order models.GasorderBasic
|
||
if err := common.ActiveRecords(impl.DBService).Where("identity = ? AND gas_basic_id = ?", identity, gasID).First(&order).Error; err != nil {
|
||
common.RespondRecordError(ctx, err)
|
||
return order, false
|
||
}
|
||
return order, true
|
||
}
|
||
|
||
func ListGasorderContract(ctx *gin.Context) {
|
||
station, ok := currentGas(ctx)
|
||
if !ok {
|
||
return
|
||
}
|
||
page, size := common.PageSize(ctx)
|
||
query := common.ApplyKeywordFilter(ctx,
|
||
platformgasorder.ContractPartyDisplayQuery(impl.DBService).
|
||
Where("gasorder_contract.gas_basic_id = ?", station.ID),
|
||
&models.GasorderContract{})
|
||
candidate := strings.TrimSpace(ctx.Query("candidate"))
|
||
if candidate == "order" || candidate == "binding" {
|
||
query = platformgasorder.FilterGasorderContractCandidates(query, candidate, time.Now())
|
||
}
|
||
var total int64
|
||
if err := query.Count(&total).Error; err != nil {
|
||
infra.Response.Error(ctx, err)
|
||
return
|
||
}
|
||
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
|
||
}
|
||
respondList(ctx, list, total)
|
||
}
|
||
|
||
func GetGasorderContract(ctx *gin.Context) {
|
||
station, ok := currentGas(ctx)
|
||
if !ok {
|
||
return
|
||
}
|
||
if _, ok := scopedContract(ctx, ctx.Param("identity"), station.ID); ok {
|
||
platformgasorder.GetGasorderContract(ctx)
|
||
}
|
||
}
|
||
|
||
// UploadGasorderContractAttachment 为当前气站账号提供受控 PDF 临时上传。
|
||
func UploadGasorderContractAttachment(ctx *gin.Context) {
|
||
if _, ok := currentGas(ctx); !ok {
|
||
return
|
||
}
|
||
platformgasorder.UploadGasorderContractAttachment(ctx)
|
||
}
|
||
|
||
// CleanupGasorderContractAttachment 清理当前气站账号尚未绑定的临时附件。
|
||
func CleanupGasorderContractAttachment(ctx *gin.Context) {
|
||
if _, ok := currentGas(ctx); !ok {
|
||
return
|
||
}
|
||
platformgasorder.CleanupGasorderContractAttachment(ctx)
|
||
}
|
||
|
||
// ServeGasorderContractAttachment 仅预览当前气站合同范围内的正式附件。
|
||
func ServeGasorderContractAttachment(ctx *gin.Context) {
|
||
station, ok := currentGas(ctx)
|
||
if !ok {
|
||
return
|
||
}
|
||
if _, ok := scopedContract(ctx, ctx.Param("identity"), station.ID); ok {
|
||
platformgasorder.ServeGasorderContractAttachment(ctx)
|
||
}
|
||
}
|
||
|
||
func CreateGasorderContract(ctx *gin.Context) {
|
||
station, ok := currentGas(ctx)
|
||
if !ok {
|
||
return
|
||
}
|
||
if !rewriteJSON(ctx, func(values map[string]any) bool {
|
||
userIdentity, _ := values["user_account_identity"].(string)
|
||
if _, _, valid := requireUser(ctx, userIdentity, station.ID); !valid {
|
||
return false
|
||
}
|
||
if deliveryIdentity, _ := values["delivery_basic_identity"].(string); deliveryIdentity != "" {
|
||
if _, valid := requireDelivery(ctx, deliveryIdentity, station.ID); !valid {
|
||
return false
|
||
}
|
||
}
|
||
values["gas_basic_identity"] = station.Identity
|
||
return true
|
||
}) {
|
||
return
|
||
}
|
||
platformgasorder.CreateGasorderContract(ctx)
|
||
}
|
||
|
||
func withContract(ctx *gin.Context, handler gin.HandlerFunc) {
|
||
station, ok := currentGas(ctx)
|
||
if !ok {
|
||
return
|
||
}
|
||
if _, ok := scopedContract(ctx, ctx.Param("identity"), station.ID); ok {
|
||
handler(ctx)
|
||
}
|
||
}
|
||
|
||
func UpdateGasorderContract(ctx *gin.Context) {
|
||
withContract(ctx, platformgasorder.UpdateGasorderContract)
|
||
}
|
||
func ActivateGasorderContract(ctx *gin.Context) {
|
||
withContract(ctx, platformgasorder.ActivateGasorderContract)
|
||
}
|
||
func RenewGasorderContract(ctx *gin.Context) {
|
||
withContract(ctx, platformgasorder.RenewGasorderContract)
|
||
}
|
||
func TerminateGasorderContract(ctx *gin.Context) {
|
||
withContract(ctx, platformgasorder.TerminateGasorderContract)
|
||
}
|
||
|
||
func BindGasorderContractProduct(ctx *gin.Context) {
|
||
station, ok := currentGas(ctx)
|
||
if !ok {
|
||
return
|
||
}
|
||
if !rewriteJSON(ctx, func(values map[string]any) bool {
|
||
identity, _ := values["gasorder_contract_identity"].(string)
|
||
_, valid := scopedContract(ctx, identity, station.ID)
|
||
return valid
|
||
}) {
|
||
return
|
||
}
|
||
platformgasorder.BindGasorderContractProduct(ctx)
|
||
}
|
||
|
||
func UnbindGasorderContractProduct(ctx *gin.Context) {
|
||
station, ok := currentGas(ctx)
|
||
if !ok {
|
||
return
|
||
}
|
||
var binding models.GasorderContractProduct
|
||
err := common.ActiveRecords(impl.DBService.Model(&models.GasorderContractProduct{})).
|
||
Select("gasorder_contract_product.*").
|
||
Joins("JOIN gasorder_contract ON gasorder_contract.id = gasorder_contract_product.gasorder_contract_id").
|
||
Where("gasorder_contract_product.identity = ? AND gasorder_contract.gas_basic_id = ?", ctx.Param("identity"), station.ID).
|
||
First(&binding).Error
|
||
if err != nil {
|
||
common.RespondRecordError(ctx, err)
|
||
return
|
||
}
|
||
platformgasorder.UnbindGasorderContractProduct(ctx)
|
||
}
|
||
|
||
func ListGasorderContractProduct(ctx *gin.Context) {
|
||
station, ok := currentGas(ctx)
|
||
if !ok {
|
||
return
|
||
}
|
||
query := common.ActiveRecords(impl.DBService.Model(&models.GasorderContractProduct{})).
|
||
Joins("JOIN gasorder_contract ON gasorder_contract.id = gasorder_contract_product.gasorder_contract_id").
|
||
Where("gasorder_contract.gas_basic_id = ?", station.ID)
|
||
listScoped(ctx, &models.GasorderContractProduct{}, query, "gasorder_contract_product.created_at desc")
|
||
}
|
||
|
||
// GetGasorderContractProduct 返回当前气站合同范围内的单条合同气瓶。
|
||
func GetGasorderContractProduct(ctx *gin.Context) {
|
||
station, ok := currentGas(ctx)
|
||
if !ok {
|
||
return
|
||
}
|
||
query := common.ActiveRecords(impl.DBService.Model(&models.GasorderContractProduct{})).
|
||
Select("gasorder_contract_product.*").
|
||
Joins("JOIN gasorder_contract ON gasorder_contract.id = gasorder_contract_product.gasorder_contract_id").
|
||
Where("gasorder_contract_product.identity = ? AND gasorder_contract.gas_basic_id = ?", ctx.Param("identity"), station.ID)
|
||
respondScopedRecord(ctx, query, &models.GasorderContractProduct{})
|
||
}
|
||
|
||
// ListContractProductCandidate 仅返回当前气站服务用户名下可用于合同绑定的气瓶。
|
||
func ListContractProductCandidate(ctx *gin.Context) {
|
||
station, ok := currentGas(ctx)
|
||
if !ok {
|
||
return
|
||
}
|
||
query := common.ActiveRecords(impl.DBService.Model(&models.ProductInfo{})).
|
||
Joins("JOIN user_service_relation ON user_service_relation.user_account_id = product_info.user_account_id AND user_service_relation.status <> ?",
|
||
common.StatusArchived).
|
||
Where("user_service_relation.gas_basic_id = ?", station.ID)
|
||
listScoped(ctx, &models.ProductInfo{}, query, "product_info.created_at desc")
|
||
}
|
||
|
||
// GetContractProductCandidate 返回当前气站服务用户范围内的单条候选气瓶。
|
||
func GetContractProductCandidate(ctx *gin.Context) {
|
||
station, ok := currentGas(ctx)
|
||
if !ok {
|
||
return
|
||
}
|
||
query := common.ActiveRecords(impl.DBService.Model(&models.ProductInfo{})).
|
||
Select("product_info.*").
|
||
Joins("JOIN user_service_relation ON user_service_relation.user_account_id = product_info.user_account_id AND user_service_relation.status <> ?", common.StatusArchived).
|
||
Where("product_info.identity = ? AND user_service_relation.gas_basic_id = ?", ctx.Param("identity"), station.ID)
|
||
respondScopedRecord(ctx, query, &models.ProductInfo{})
|
||
}
|
||
|
||
func ListGasorderContractRevision(ctx *gin.Context) {
|
||
station, ok := currentGas(ctx)
|
||
if !ok {
|
||
return
|
||
}
|
||
query := common.ActiveRecords(impl.DBService.Model(&models.GasorderContractRevision{})).
|
||
Joins("JOIN gasorder_contract ON gasorder_contract.id = gasorder_contract_revision.gasorder_contract_id").
|
||
Where("gasorder_contract.gas_basic_id = ?", station.ID)
|
||
listScoped(ctx, &models.GasorderContractRevision{}, query, "gasorder_contract_revision.created_at desc")
|
||
}
|
||
|
||
// GetGasorderContractRevision 返回当前气站合同范围内的单条修订记录。
|
||
func GetGasorderContractRevision(ctx *gin.Context) {
|
||
station, ok := currentGas(ctx)
|
||
if !ok {
|
||
return
|
||
}
|
||
query := common.ActiveRecords(impl.DBService.Model(&models.GasorderContractRevision{})).
|
||
Select("gasorder_contract_revision.*").
|
||
Joins("JOIN gasorder_contract ON gasorder_contract.id = gasorder_contract_revision.gasorder_contract_id").
|
||
Where("gasorder_contract_revision.identity = ? AND gasorder_contract.gas_basic_id = ?", ctx.Param("identity"), station.ID)
|
||
respondScopedRecord(ctx, query, &models.GasorderContractRevision{})
|
||
}
|
||
|
||
func ListGasorderBasic(ctx *gin.Context) {
|
||
station, ok := currentGas(ctx)
|
||
if !ok {
|
||
return
|
||
}
|
||
listScoped(ctx, &models.GasorderBasic{}, common.ActiveRecords(impl.DBService.Model(&models.GasorderBasic{})).
|
||
Where("gas_basic_id = ?", station.ID), "gasorder_basic.created_at desc")
|
||
}
|
||
|
||
func GetGasorderBasic(ctx *gin.Context) {
|
||
station, ok := currentGas(ctx)
|
||
if !ok {
|
||
return
|
||
}
|
||
if _, ok := scopedOrder(ctx, ctx.Param("identity"), station.ID); ok {
|
||
platformgasorder.GetGasorderBasic(ctx)
|
||
}
|
||
}
|
||
|
||
func CreateGasorderBasic(ctx *gin.Context) {
|
||
station, ok := currentGas(ctx)
|
||
if !ok {
|
||
return
|
||
}
|
||
if !rewriteJSON(ctx, func(values map[string]any) bool {
|
||
contractIdentity, _ := values["gasorder_contract_identity"].(string)
|
||
if _, valid := scopedContract(ctx, contractIdentity, station.ID); !valid {
|
||
return false
|
||
}
|
||
values["creator_type"] = "gas"
|
||
values["creator_identity"] = station.Identity
|
||
return true
|
||
}) {
|
||
return
|
||
}
|
||
platformgasorder.CreateGasorderBasic(ctx)
|
||
}
|
||
|
||
func withOrder(ctx *gin.Context, handler gin.HandlerFunc) {
|
||
station, ok := currentGas(ctx)
|
||
if !ok {
|
||
return
|
||
}
|
||
if _, ok := scopedOrder(ctx, ctx.Param("identity"), station.ID); ok {
|
||
handler(ctx)
|
||
}
|
||
}
|
||
|
||
func AssignGasorderBasic(ctx *gin.Context) {
|
||
station, ok := currentGas(ctx)
|
||
if !ok {
|
||
return
|
||
}
|
||
if _, ok := scopedOrder(ctx, ctx.Param("identity"), station.ID); !ok {
|
||
return
|
||
}
|
||
if !rewriteJSON(ctx, func(values map[string]any) bool {
|
||
deliveryIdentity, _ := values["delivery_basic_identity"].(string)
|
||
staffIdentity, _ := values["staff_account_identity"].(string)
|
||
_, deliveryOK := requireDelivery(ctx, deliveryIdentity, station.ID)
|
||
_, staffOK := requireStaff(ctx, staffIdentity, station.ID)
|
||
return deliveryOK && staffOK
|
||
}) {
|
||
return
|
||
}
|
||
platformgasorder.AssignGasorderBasic(ctx)
|
||
}
|
||
|
||
func GasorderStartFilling(ctx *gin.Context) { withOrder(ctx, platformgasorder.GasorderStartFilling) }
|
||
func GasorderReady(ctx *gin.Context) { withOrder(ctx, platformgasorder.GasorderReady) }
|
||
func GasorderException(ctx *gin.Context) { withOrder(ctx, platformgasorder.GasorderException) }
|
||
func GasorderRecover(ctx *gin.Context) { withOrder(ctx, platformgasorder.GasorderRecover) }
|
||
func GasorderCancel(ctx *gin.Context) { withOrder(ctx, platformgasorder.GasorderCancel) }
|
||
|
||
func listScoped(ctx *gin.Context, model any, query *gorm.DB, order string) {
|
||
page, size := common.PageSize(ctx)
|
||
var total int64
|
||
if err := common.ApplyKeywordFilter(ctx, query, model).Count(&total).Error; err != nil {
|
||
infra.Response.Error(ctx, err)
|
||
return
|
||
}
|
||
list := sliceForModel(model)
|
||
if err := common.ApplyKeywordFilter(ctx, query, model).Order(order).Offset((page - 1) * size).Limit(size).Find(list).Error; err != nil {
|
||
infra.Response.Error(ctx, err)
|
||
return
|
||
}
|
||
respondList(ctx, list, total)
|
||
}
|
||
|
||
func sliceForModel(model any) any {
|
||
return reflect.New(reflect.SliceOf(reflect.TypeOf(model).Elem())).Interface()
|
||
}
|