2025-02-02 22:20:10 +08:00
|
|
|
package api
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
|
|
|
|
"git.solsynth.dev/hypernet/nexus/pkg/nex/sec"
|
|
|
|
"git.solsynth.dev/hypernet/passport/pkg/authkit"
|
|
|
|
"git.solsynth.dev/hypernet/wallet/pkg/internal/database"
|
|
|
|
"git.solsynth.dev/hypernet/wallet/pkg/internal/gap"
|
|
|
|
"git.solsynth.dev/hypernet/wallet/pkg/internal/models"
|
|
|
|
"git.solsynth.dev/hypernet/wallet/pkg/internal/server/exts"
|
|
|
|
"git.solsynth.dev/hypernet/wallet/pkg/internal/services"
|
|
|
|
"github.com/gofiber/fiber/v2"
|
|
|
|
"github.com/shopspring/decimal"
|
2025-02-02 23:17:08 +08:00
|
|
|
"golang.org/x/crypto/bcrypt"
|
2025-02-02 22:20:10 +08:00
|
|
|
)
|
|
|
|
|
|
|
|
func getOrder(c *fiber.Ctx) error {
|
|
|
|
orderId, _ := c.ParamsInt("orderId")
|
|
|
|
|
|
|
|
var order models.Order
|
|
|
|
if err := database.C.Where("id = ?", orderId).First(&order).Error; err != nil {
|
|
|
|
return fiber.NewError(fiber.StatusNotFound, err.Error())
|
|
|
|
}
|
|
|
|
|
|
|
|
return c.JSON(order)
|
|
|
|
}
|
|
|
|
|
2025-02-02 22:46:01 +08:00
|
|
|
func createOrder(c *fiber.Ctx) error {
|
2025-02-02 22:20:10 +08:00
|
|
|
var data struct {
|
|
|
|
ClientID string `json:"client_id" validate:"required"`
|
|
|
|
ClientSecret string `json:"client_secret" validate:"required"`
|
|
|
|
Remark string `json:"remark" validate:"required"`
|
|
|
|
Amount float64 `json:"amount" validate:"required"`
|
|
|
|
PayeeID *uint `json:"payee_id"`
|
|
|
|
PayerID *uint `json:"payer_id"`
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := exts.BindAndValidate(c, &data); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Validating client
|
|
|
|
client, err := authkit.GetThirdClientByAlias(gap.Nx, data.ClientID, &data.ClientSecret)
|
|
|
|
if err != nil {
|
|
|
|
return fiber.NewError(fiber.StatusForbidden, fmt.Sprintf("could not get client info: %v", err))
|
|
|
|
}
|
|
|
|
|
|
|
|
order := models.Order{
|
|
|
|
Status: models.OrderStatusPending,
|
|
|
|
Remark: data.Remark,
|
|
|
|
Amount: decimal.NewFromFloat(data.Amount),
|
|
|
|
ClientID: &client.ID,
|
|
|
|
}
|
|
|
|
|
|
|
|
// System client, spec payee was not allowed
|
|
|
|
if client.AccountID != nil && data.PayeeID != nil {
|
|
|
|
var payee models.Wallet
|
2025-02-03 12:09:43 +08:00
|
|
|
if err := database.C.Where("id = ? AND account_id = ?", data.PayeeID, client.AccountID).First(&payee).Error; err != nil {
|
2025-02-02 22:20:10 +08:00
|
|
|
return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("payee id %d not found", data.PayeeID))
|
|
|
|
} else {
|
|
|
|
order.Payee = &payee
|
|
|
|
order.PayeeID = &payee.ID
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if data.PayerID != nil {
|
|
|
|
var payer models.Wallet
|
|
|
|
if err := database.C.Where("id = ?", data.PayerID).First(&payer).Error; err != nil {
|
|
|
|
return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("payer id %d not found", data.PayerID))
|
|
|
|
} else {
|
|
|
|
order.Payer = &payer
|
|
|
|
order.PayerID = &payer.ID
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := database.C.Create(&order).Error; err != nil {
|
|
|
|
return fiber.NewError(fiber.StatusInternalServerError, err.Error())
|
|
|
|
}
|
|
|
|
|
|
|
|
return c.JSON(order)
|
|
|
|
}
|
|
|
|
|
|
|
|
func payOrder(c *fiber.Ctx) error {
|
|
|
|
if err := sec.EnsureAuthenticated(c); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2025-02-03 00:30:58 +08:00
|
|
|
user := c.Locals("nex_user").(*sec.UserInfo)
|
2025-02-02 22:20:10 +08:00
|
|
|
|
|
|
|
orderId, _ := c.ParamsInt("orderId")
|
|
|
|
|
2025-02-02 23:17:08 +08:00
|
|
|
var data struct {
|
|
|
|
WalletPassword string `json:"wallet_password" validate:"required"`
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := exts.BindAndValidate(c, &data); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2025-02-02 22:20:10 +08:00
|
|
|
var order models.Order
|
|
|
|
if err := database.C.Where("id = ?", orderId).First(&order).Error; err != nil {
|
|
|
|
return fiber.NewError(fiber.StatusNotFound, err.Error())
|
|
|
|
}
|
|
|
|
|
|
|
|
var payer *models.Wallet
|
|
|
|
if order.PayerID != nil {
|
|
|
|
if err := database.C.Where("id = ?", order.PayerID).First(&payer).Error; err != nil {
|
|
|
|
return fiber.NewError(fiber.StatusBadRequest, "order payer wallet was not found")
|
|
|
|
} else if payer.AccountID != user.ID {
|
|
|
|
return fiber.NewError(fiber.StatusForbidden, "the order cannot paid by you")
|
|
|
|
}
|
|
|
|
} else {
|
2025-02-03 00:34:51 +08:00
|
|
|
if err := database.C.Where("account_id = ?", user.ID).First(&payer).Error; err != nil {
|
2025-02-02 22:20:10 +08:00
|
|
|
return fiber.NewError(fiber.StatusBadRequest, "account wallet was not found")
|
|
|
|
}
|
|
|
|
}
|
2025-02-02 23:17:08 +08:00
|
|
|
if payer != nil {
|
|
|
|
if bcrypt.CompareHashAndPassword([]byte(payer.Password), []byte(data.WalletPassword)) != nil {
|
|
|
|
return fiber.NewError(fiber.StatusForbidden, "invalid wallet password")
|
|
|
|
}
|
|
|
|
}
|
2025-02-02 22:20:10 +08:00
|
|
|
|
|
|
|
var payee *models.Wallet
|
|
|
|
if order.PayeeID != nil {
|
|
|
|
if err := database.C.Where("id = ?", order.PayeeID).First(&payee).Error; err != nil {
|
|
|
|
return fiber.NewError(fiber.StatusBadRequest, "order payee wallet was not found")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if tran, err := services.MakeTransaction(order.Amount.InexactFloat64(), order.Remark, payer, payee); err != nil {
|
|
|
|
return fiber.NewError(fiber.StatusPaymentRequired, err.Error())
|
|
|
|
} else {
|
|
|
|
if err := database.C.Model(&order).Updates(&models.Order{
|
|
|
|
Status: models.OrderStatusPaid,
|
|
|
|
TransactionID: &tran.ID,
|
|
|
|
}).Error; err != nil {
|
|
|
|
// Do refund
|
|
|
|
_, _ = services.MakeTransaction(
|
|
|
|
order.Amount.InexactFloat64(),
|
|
|
|
fmt.Sprintf("%s - #%d Refund", order.Remark, order.ID),
|
|
|
|
payee,
|
|
|
|
payer,
|
|
|
|
)
|
|
|
|
return fiber.NewError(fiber.StatusInternalServerError, err.Error())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return c.JSON(order)
|
|
|
|
}
|
2025-02-03 13:23:45 +08:00
|
|
|
|
|
|
|
func cancelOrder(c *fiber.Ctx) error {
|
|
|
|
var data struct {
|
|
|
|
ClientID string `json:"client_id" validate:"required"`
|
|
|
|
ClientSecret string `json:"client_secret" validate:"required"`
|
|
|
|
}
|
|
|
|
|
|
|
|
orderId, _ := c.ParamsInt("orderId")
|
|
|
|
|
|
|
|
if err := exts.BindAndValidate(c, &data); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Validating client
|
|
|
|
client, err := authkit.GetThirdClientByAlias(gap.Nx, data.ClientID, &data.ClientSecret)
|
|
|
|
if err != nil {
|
|
|
|
return fiber.NewError(fiber.StatusForbidden, fmt.Sprintf("could not get client info: %v", err))
|
|
|
|
}
|
|
|
|
|
|
|
|
var order models.Order
|
|
|
|
if err := database.C.Where("id = ? AND client_id = ?", orderId, client.ID).First(&order).Error; err != nil {
|
|
|
|
return fiber.NewError(fiber.StatusNotFound, err.Error())
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := database.C.Model(&order).Updates(&models.Order{Status: models.OrderStatusCanceled}).Error; err != nil {
|
|
|
|
return fiber.NewError(fiber.StatusInternalServerError, err.Error())
|
|
|
|
}
|
|
|
|
|
|
|
|
return c.JSON(order)
|
|
|
|
}
|