feat: implement gas and delivery admin systems
This commit is contained in:
105
backend/api/internal/routers/delivery.go
Normal file
105
backend/api/internal/routers/delivery.go
Normal file
@@ -0,0 +1,105 @@
|
||||
package routers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
sdkmiddleware "git.apinb.com/bsm-sdk/core/middleware"
|
||||
deliverylogic "git.apinb.com/heqiapp/platforms/backend/api/internal/logic/delivery"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func RegisterDelivery(serviceKey string, engine *gin.Engine) {
|
||||
basePath := fmt.Sprintf("/%s/delivery/v1", serviceKey)
|
||||
anonymous := engine.Group(basePath)
|
||||
anonymous.POST("/auth/login", deliverylogic.Login)
|
||||
|
||||
protected := engine.Group(basePath)
|
||||
protected.Use(sdkmiddleware.JwtAuth(true))
|
||||
protected.Use(deliverylogic.RequireDeliveryAdmin())
|
||||
protected.GET("/auth/profile", deliverylogic.CurrentProfile)
|
||||
protected.PUT("/auth/password", deliverylogic.ChangePassword)
|
||||
protected.GET("/delivery_menu", deliverylogic.ListMenu)
|
||||
protected.GET("/invitation/qrcode", deliverylogic.InvitationQRCode)
|
||||
protected.GET("/dashboard/overview", deliverylogic.Dashboard)
|
||||
protected.GET("/dashboard/reports", deliverylogic.DashboardReport)
|
||||
protected.GET("/delivery_profile", deliverylogic.ListProfile)
|
||||
|
||||
staff := protected.Group("/staff_account")
|
||||
staff.GET("", deliverylogic.ListStaff)
|
||||
staff.POST("", deliverylogic.CreateStaff)
|
||||
staff.GET("/:identity", deliverylogic.GetStaff)
|
||||
staff.PUT("/:identity", deliverylogic.UpdateStaff)
|
||||
staff.PUT("/:identity/password", deliverylogic.ResetStaffPassword)
|
||||
staff.PATCH("/:identity/status", deliverylogic.UpdateStaffStatus)
|
||||
staff.DELETE("/:identity", deliverylogic.ArchiveStaff)
|
||||
credential := protected.Group("/staff_credential")
|
||||
credential.GET("", deliverylogic.ListCredential)
|
||||
credential.POST("", deliverylogic.CreateCredential)
|
||||
credential.GET("/:identity", deliverylogic.GetCredential)
|
||||
credential.PUT("/:identity", deliverylogic.UpdateCredential)
|
||||
credential.PATCH("/:identity/status", deliverylogic.UpdateCredentialStatus)
|
||||
credential.DELETE("/:identity", deliverylogic.ArchiveCredential)
|
||||
|
||||
user := protected.Group("/user_account")
|
||||
user.GET("", deliverylogic.ListUser)
|
||||
user.POST("", deliverylogic.CreateUser)
|
||||
user.GET("/:identity", deliverylogic.GetUser)
|
||||
user.PUT("/:identity", deliverylogic.UpdateUser)
|
||||
user.PUT("/:identity/password", deliverylogic.ResetUserPassword)
|
||||
user.PATCH("/:identity/status", deliverylogic.UpdateUserStatus)
|
||||
user.DELETE("/:identity", deliverylogic.ArchiveUser)
|
||||
address := protected.Group("/user_address")
|
||||
address.GET("", deliverylogic.ListAddress)
|
||||
address.POST("", deliverylogic.CreateAddress)
|
||||
address.GET("/:identity", deliverylogic.GetAddress)
|
||||
address.PUT("/:identity", deliverylogic.UpdateAddress)
|
||||
address.PATCH("/:identity/status", deliverylogic.UpdateAddressStatus)
|
||||
address.DELETE("/:identity", deliverylogic.ArchiveAddress)
|
||||
|
||||
contract := protected.Group("/gasorder_contract")
|
||||
contract.GET("", deliverylogic.ListContract)
|
||||
contract.POST("", deliverylogic.CreateContract)
|
||||
contract.GET("/:identity", deliverylogic.GetContract)
|
||||
contract.PUT("/:identity", deliverylogic.UpdateContract)
|
||||
contract.POST("/:identity/activate", deliverylogic.ActivateContract)
|
||||
contract.POST("/:identity/renew", deliverylogic.RenewContract)
|
||||
contract.POST("/:identity/terminate", deliverylogic.TerminateContract)
|
||||
product := protected.Group("/gasorder_contract_product")
|
||||
product.GET("", deliverylogic.ListContractProduct)
|
||||
product.POST("", deliverylogic.BindContractProduct)
|
||||
product.GET("/:identity", deliverylogic.GetContractProduct)
|
||||
product.POST("/:identity/unbind", deliverylogic.UnbindContractProduct)
|
||||
protected.GET("/gasorder_contract_revision", deliverylogic.ListContractRevision)
|
||||
protected.GET("/gasorder_contract_revision/:identity", deliverylogic.GetContractRevision)
|
||||
protected.GET("/product_info", deliverylogic.ListProductCandidate)
|
||||
protected.GET("/product_info/:identity", deliverylogic.GetProductCandidate)
|
||||
|
||||
order := protected.Group("/gasorder_basic")
|
||||
order.GET("", deliverylogic.ListOrder)
|
||||
order.POST("", deliverylogic.CreateOrder)
|
||||
order.GET("/:identity", deliverylogic.GetOrder)
|
||||
order.POST("/:identity/assign", deliverylogic.AssignOrder)
|
||||
order.POST("/:identity/reclaim", deliverylogic.ReclaimOrder)
|
||||
order.POST("/:identity/adjust-amount", deliverylogic.AdjustOrderAmount)
|
||||
order.POST("/:identity/exception", deliverylogic.OrderException)
|
||||
order.POST("/:identity/recover", deliverylogic.OrderRecover)
|
||||
order.POST("/:identity/cancel", deliverylogic.OrderCancel)
|
||||
|
||||
protected.GET("/wallet_basic", deliverylogic.ListWallet)
|
||||
protected.GET("/wallet_basic/:identity", deliverylogic.GetWallet)
|
||||
protected.POST("/wallet_basic/recharge", deliverylogic.Recharge)
|
||||
protected.POST("/wallet_recharge", deliverylogic.Recharge)
|
||||
protected.GET("/wallet_bank", deliverylogic.ListBank)
|
||||
protected.GET("/wallet_bank/:identity", deliverylogic.GetBank)
|
||||
protected.GET("/wallet_payment", deliverylogic.ListPayment)
|
||||
protected.GET("/wallet_payment/:identity", deliverylogic.GetPayment)
|
||||
protected.GET("/wallet_record", deliverylogic.ListRecord)
|
||||
protected.GET("/wallet_record/:identity", deliverylogic.GetRecord)
|
||||
protected.GET("/wallet_refund", deliverylogic.ListRefund)
|
||||
protected.GET("/wallet_refund/:identity", deliverylogic.GetRefund)
|
||||
protected.GET("/wallet_apply_cash", deliverylogic.ListApplyCash)
|
||||
protected.POST("/wallet_apply_cash", deliverylogic.CreateApplyCash)
|
||||
protected.GET("/wallet_apply_cash/:identity", deliverylogic.GetApplyCash)
|
||||
protected.GET("/fin_settlement", deliverylogic.ListSettlement)
|
||||
protected.GET("/fin_settlement/:identity", deliverylogic.GetSettlement)
|
||||
}
|
||||
51
backend/api/internal/routers/delivery_test.go
Normal file
51
backend/api/internal/routers/delivery_test.go
Normal file
@@ -0,0 +1,51 @@
|
||||
package routers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func TestDeliveryRoutesRequireAuthentication(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
engine := gin.New()
|
||||
RegisterDelivery("heqi", engine)
|
||||
response := httptest.NewRecorder()
|
||||
engine.ServeHTTP(response, httptest.NewRequest(http.MethodGet, "/heqi/delivery/v1/delivery_menu", nil))
|
||||
if response.Code == http.StatusOK {
|
||||
t.Fatal("delivery menu must reject anonymous access")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeliveryOrderActionBoundary(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
engine := gin.New()
|
||||
RegisterDelivery("heqi", engine)
|
||||
routes := map[string]bool{}
|
||||
for _, route := range engine.Routes() {
|
||||
routes[route.Method+" "+route.Path] = true
|
||||
}
|
||||
for _, forbidden := range []string{
|
||||
"POST /heqi/delivery/v1/gasorder_basic/:identity/filling",
|
||||
"POST /heqi/delivery/v1/gasorder_basic/:identity/ready",
|
||||
"POST /heqi/delivery/v1/gasorder_basic/:identity/delivering",
|
||||
"POST /heqi/delivery/v1/gasorder_basic/:identity/awaiting-confirmation",
|
||||
"POST /heqi/delivery/v1/gasorder_basic/:identity/complete",
|
||||
} {
|
||||
if routes[forbidden] {
|
||||
t.Fatalf("delivery web must not expose app or gas action %s", forbidden)
|
||||
}
|
||||
}
|
||||
for _, required := range []string{
|
||||
"POST /heqi/delivery/v1/gasorder_basic",
|
||||
"POST /heqi/delivery/v1/gasorder_basic/:identity/assign",
|
||||
"POST /heqi/delivery/v1/gasorder_basic/:identity/reclaim",
|
||||
"POST /heqi/delivery/v1/gasorder_basic/:identity/adjust-amount",
|
||||
} {
|
||||
if !routes[required] {
|
||||
t.Fatalf("missing confirmed delivery action %s", required)
|
||||
}
|
||||
}
|
||||
}
|
||||
26
backend/api/internal/routers/gas.go
Normal file
26
backend/api/internal/routers/gas.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package routers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
sdkmiddleware "git.apinb.com/bsm-sdk/core/middleware"
|
||||
gaslogic "git.apinb.com/heqiapp/platforms/backend/api/internal/logic/gas"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// RegisterGas 注册 /heqi/gas/v1 气站后台路由。
|
||||
func RegisterGas(serviceKey string, engine *gin.Engine) {
|
||||
basePath := fmt.Sprintf("/%s/gas/v1", serviceKey)
|
||||
anonymous := engine.Group(basePath)
|
||||
anonymous.POST("/auth/login", gaslogic.Login)
|
||||
|
||||
protected := engine.Group(basePath)
|
||||
protected.Use(sdkmiddleware.JwtAuth(true))
|
||||
protected.Use(gaslogic.RequireGasAdmin())
|
||||
protected.GET("/auth/profile", gaslogic.CurrentProfile)
|
||||
protected.PUT("/auth/password", gaslogic.ChangePassword)
|
||||
protected.GET("/gas_menu", gaslogic.ListMenu)
|
||||
protected.GET("/invitation/qrcode", gaslogic.InvitationQRCode)
|
||||
|
||||
registerGasBusinessRoutes(protected)
|
||||
}
|
||||
107
backend/api/internal/routers/gas_business.go
Normal file
107
backend/api/internal/routers/gas_business.go
Normal file
@@ -0,0 +1,107 @@
|
||||
package routers
|
||||
|
||||
import (
|
||||
gaslogic "git.apinb.com/heqiapp/platforms/backend/api/internal/logic/gas"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func registerGasBusinessRoutes(group *gin.RouterGroup) {
|
||||
group.GET("/dashboard/overview", gaslogic.DashboardOverview)
|
||||
group.GET("/dashboard/reports", gaslogic.DashboardReport)
|
||||
|
||||
delivery := group.Group("/delivery_basic")
|
||||
delivery.GET("", gaslogic.ListDelivery)
|
||||
delivery.POST("", gaslogic.CreateDelivery)
|
||||
delivery.GET("/:identity", gaslogic.GetDelivery)
|
||||
delivery.PUT("/:identity", gaslogic.UpdateDelivery)
|
||||
delivery.PATCH("/:identity/status", gaslogic.UpdateDeliveryStatus)
|
||||
delivery.DELETE("/:identity", gaslogic.ArchiveDelivery)
|
||||
|
||||
deliveryAccount := group.Group("/delivery_account")
|
||||
deliveryAccount.GET("", gaslogic.ListDeliveryAccount)
|
||||
deliveryAccount.POST("", gaslogic.CreateDeliveryAccount)
|
||||
deliveryAccount.GET("/:identity", gaslogic.GetDeliveryAccount)
|
||||
deliveryAccount.PUT("/:identity", gaslogic.UpdateDeliveryAccount)
|
||||
deliveryAccount.PUT("/:identity/password", gaslogic.ResetDeliveryAccountPassword)
|
||||
deliveryAccount.PATCH("/:identity/status", gaslogic.UpdateDeliveryAccountStatus)
|
||||
deliveryAccount.DELETE("/:identity", gaslogic.ArchiveDeliveryAccount)
|
||||
|
||||
staff := group.Group("/staff_account")
|
||||
staff.GET("", gaslogic.ListStaff)
|
||||
staff.POST("", gaslogic.CreateStaff)
|
||||
staff.GET("/:identity", gaslogic.GetStaff)
|
||||
staff.PUT("/:identity", gaslogic.UpdateStaff)
|
||||
staff.PUT("/:identity/password", gaslogic.ResetStaffPassword)
|
||||
staff.PATCH("/:identity/status", gaslogic.UpdateStaffStatus)
|
||||
staff.DELETE("/:identity", gaslogic.ArchiveStaff)
|
||||
|
||||
credential := group.Group("/staff_credential")
|
||||
credential.GET("", gaslogic.ListCredential)
|
||||
credential.POST("", gaslogic.CreateCredential)
|
||||
credential.GET("/:identity", gaslogic.GetCredential)
|
||||
credential.PUT("/:identity", gaslogic.UpdateCredential)
|
||||
credential.PATCH("/:identity/status", gaslogic.UpdateCredentialStatus)
|
||||
credential.DELETE("/:identity", gaslogic.ArchiveCredential)
|
||||
|
||||
user := group.Group("/user_account")
|
||||
user.GET("", gaslogic.ListUser)
|
||||
user.POST("", gaslogic.CreateUser)
|
||||
user.GET("/:identity", gaslogic.GetUser)
|
||||
user.PUT("/:identity", gaslogic.UpdateUser)
|
||||
user.PUT("/:identity/password", gaslogic.ResetUserPassword)
|
||||
user.PATCH("/:identity/status", gaslogic.UpdateUserStatus)
|
||||
user.DELETE("/:identity", gaslogic.ArchiveUser)
|
||||
|
||||
address := group.Group("/user_address")
|
||||
address.GET("", gaslogic.ListUserAddress)
|
||||
address.POST("", gaslogic.CreateUserAddress)
|
||||
address.GET("/:identity", gaslogic.GetUserAddress)
|
||||
address.PUT("/:identity", gaslogic.UpdateUserAddress)
|
||||
address.PATCH("/:identity/status", gaslogic.UpdateUserAddressStatus)
|
||||
address.DELETE("/:identity", gaslogic.ArchiveUserAddress)
|
||||
|
||||
contract := group.Group("/gasorder_contract")
|
||||
contract.GET("", gaslogic.ListGasorderContract)
|
||||
contract.POST("", gaslogic.CreateGasorderContract)
|
||||
contract.GET("/:identity", gaslogic.GetGasorderContract)
|
||||
contract.PUT("/:identity", gaslogic.UpdateGasorderContract)
|
||||
contract.POST("/:identity/activate", gaslogic.ActivateGasorderContract)
|
||||
contract.POST("/:identity/renew", gaslogic.RenewGasorderContract)
|
||||
contract.POST("/:identity/terminate", gaslogic.TerminateGasorderContract)
|
||||
|
||||
contractProduct := group.Group("/gasorder_contract_product")
|
||||
contractProduct.GET("", gaslogic.ListGasorderContractProduct)
|
||||
contractProduct.POST("", gaslogic.BindGasorderContractProduct)
|
||||
contractProduct.POST("/:identity/unbind", gaslogic.UnbindGasorderContractProduct)
|
||||
group.GET("/gasorder_contract_revision", gaslogic.ListGasorderContractRevision)
|
||||
group.GET("/product_info", gaslogic.ListContractProductCandidate)
|
||||
|
||||
order := group.Group("/gasorder_basic")
|
||||
order.GET("", gaslogic.ListGasorderBasic)
|
||||
order.POST("", gaslogic.CreateGasorderBasic)
|
||||
order.GET("/:identity", gaslogic.GetGasorderBasic)
|
||||
order.POST("/:identity/assign", gaslogic.AssignGasorderBasic)
|
||||
order.POST("/:identity/filling", gaslogic.GasorderStartFilling)
|
||||
order.POST("/:identity/ready", gaslogic.GasorderReady)
|
||||
order.POST("/:identity/exception", gaslogic.GasorderException)
|
||||
order.POST("/:identity/recover", gaslogic.GasorderRecover)
|
||||
order.POST("/:identity/cancel", gaslogic.GasorderCancel)
|
||||
|
||||
group.GET("/wallet_basic", gaslogic.ListWalletBasic)
|
||||
group.GET("/wallet_bank", gaslogic.ListWalletBank)
|
||||
group.GET("/wallet_payment", gaslogic.ListWalletPayment)
|
||||
group.GET("/wallet_record", gaslogic.ListWalletRecord)
|
||||
group.GET("/wallet_refund", gaslogic.ListWalletRefund)
|
||||
group.GET("/wallet_apply_cash", gaslogic.ListWalletApplyCash)
|
||||
group.POST("/wallet_apply_cash", gaslogic.CreateWalletApplyCash)
|
||||
group.GET("/fin_settlement", gaslogic.ListFinSettlement)
|
||||
group.GET("/fin_reconciliation", gaslogic.ListFinReconciliation)
|
||||
|
||||
ticket := group.Group("/cs_ticket")
|
||||
ticket.GET("", gaslogic.ListTicket)
|
||||
ticket.POST("", gaslogic.CreateTicket)
|
||||
ticket.GET("/:identity", gaslogic.GetTicket)
|
||||
ticket.PUT("/:identity", gaslogic.UpdateTicket)
|
||||
ticket.PATCH("/:identity/status", gaslogic.UpdateTicketStatus)
|
||||
ticket.DELETE("/:identity", gaslogic.ArchiveTicket)
|
||||
}
|
||||
54
backend/api/internal/routers/gas_test.go
Normal file
54
backend/api/internal/routers/gas_test.go
Normal file
@@ -0,0 +1,54 @@
|
||||
package routers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func TestGasRoutesRequireAuthentication(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
engine := gin.New()
|
||||
RegisterGas("heqi", engine)
|
||||
|
||||
request := httptest.NewRequest(http.MethodGet, "/heqi/gas/v1/gas_menu", nil)
|
||||
response := httptest.NewRecorder()
|
||||
engine.ServeHTTP(response, request)
|
||||
if response.Code == http.StatusOK {
|
||||
t.Fatal("gas menu must reject anonymous requests")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGasOrderRoutesDoNotExposeDownstreamActions(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
engine := gin.New()
|
||||
RegisterGas("heqi", engine)
|
||||
|
||||
routes := map[string]bool{}
|
||||
for _, route := range engine.Routes() {
|
||||
routes[route.Method+" "+route.Path] = true
|
||||
}
|
||||
for _, path := range []string{
|
||||
"POST /heqi/gas/v1/gasorder_basic/:identity/delivering",
|
||||
"POST /heqi/gas/v1/gasorder_basic/:identity/awaiting-confirmation",
|
||||
"POST /heqi/gas/v1/gasorder_basic/:identity/complete",
|
||||
} {
|
||||
if routes[path] {
|
||||
t.Fatalf("gas admin must not expose downstream action %s", path)
|
||||
}
|
||||
}
|
||||
for _, path := range []string{
|
||||
"POST /heqi/gas/v1/gasorder_basic/:identity/assign",
|
||||
"POST /heqi/gas/v1/gasorder_basic/:identity/filling",
|
||||
"POST /heqi/gas/v1/gasorder_basic/:identity/ready",
|
||||
"POST /heqi/gas/v1/gasorder_basic/:identity/exception",
|
||||
"POST /heqi/gas/v1/gasorder_basic/:identity/recover",
|
||||
"POST /heqi/gas/v1/gasorder_basic/:identity/cancel",
|
||||
} {
|
||||
if !routes[path] {
|
||||
t.Fatalf("missing gas order action %s", path)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,5 +6,7 @@ import "github.com/gin-gonic/gin"
|
||||
// Register 注册路由。
|
||||
func Register(serviceKey string, engine *gin.Engine) {
|
||||
RegisterPlatform(serviceKey, engine)
|
||||
RegisterGas(serviceKey, engine)
|
||||
RegisterDelivery(serviceKey, engine)
|
||||
registerUploadRoute(serviceKey, engine)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user