Files
platforms/backend/api/internal/logic/gas/gasorder.go

370 lines
12 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.
// 功能描述:实现气站范围内的配送合同、合同气瓶和燃气配送订单接口。
// 版本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()
}