Compare commits

..

No commits in common. "b9b7309edc85f7e87f15089292553f0d2c2ceed6" and "2aacbf1c3e7b29c4d76fba81962db8704cb12d37" have entirely different histories.

93 changed files with 1302 additions and 2809 deletions

4
.gitignore vendored
View File

@ -44,6 +44,4 @@ shared-state
*.zip
vendor
grpc_server/gen
vendor

View File

@ -3,7 +3,7 @@ package constants
// 订单类型
const (
DELIVERYMETHODDIRECTMAIL int64 = 1
DELIVERYMETHODDSCLOUDSTORE int64 = 2
DELIVERYMETHODDSCLOUDSTORE int64 = 1
)
// 货币
@ -23,8 +23,8 @@ type ExchangeRateUnit interface{}
type PayMethods string
const (
PAY_METHOD_CARD PayMethods = "CARD"
PayMethodVISA PayMethods = "VISA"
PAYMETHODCARD PayMethods = "CARD"
PayMethodVISA PayMethods = "VISA"
)
// 支付状态
@ -56,21 +56,18 @@ const (
type OrderStatusCode int64
const (
ORDER_STATUS_UNPAIDDEPOSIT OrderStatusCode = 0 // 0,未支付定金
ORDER_STATUS_DIRECTMAIL_ORDERED OrderStatusCode = 10100 // 10100,直邮单--已下单
ORDER_STATUS_DIRECTMAIL_ORDEREDMAINING OrderStatusCode = 10100001 // 10100001,直邮单--已下单--尾款
ORDER_STATUS_DIRECTMAIL_CANCEL OrderStatusCode = 10101 // 10101,直邮单--已取消
ORDER_STATUS_DIRECTMAIL_STARTPRODUCTION OrderStatusCode = 10200 // 10200,直邮单--开始生产
ORDER_STATUS_DIRECTMAIL_COMPLETEPRODUCTION OrderStatusCode = 10300 // 10300,直邮单--生产完成
ORDER_STATUS_DIRECTMAIL_SHIPPED OrderStatusCode = 10400 // 10400,直邮单--已发货
ORDER_STATUS_DIRECTMAIL_ARRIVED OrderStatusCode = 10500 // 10500,直邮单--已到达
ORDER_STATUS_CLOUDSTORE_ORDERED OrderStatusCode = 20100 // 20100,云仓单--已下单
ORDER_STATUS_CLOUDSTORE_ORDEREDMAINING OrderStatusCode = 20100001 // 20100001,云仓单--已下单-尾款
ORDER_STATUS_CLOUDSTORE_CANCEL OrderStatusCode = 20101 // 20101,云仓单--已取消
ORDER_STATUS_CLOUDSTORE_STARTPRODUCTION OrderStatusCode = 20200 // 20200,云仓单--开始生产
ORDER_STATUS_CLOUDSTORE_COMPLETEPRODUCTION OrderStatusCode = 20300 // 20300,云仓单--生产完成
ORDER_STATUS_CLOUDSTORE_ARRIVEDWAREHOUSE OrderStatusCode = 20400 // 20400,云仓单--直达仓库
ORDER_STATUS_COMPLETE OrderStatusCode = 30000 // 30000,订单完成
ORDERSTATUSUNPAIDDEPOSIT OrderStatusCode = 0 // 0,未支付定金
ORDERSTATUSDIRECTMAILORDERED OrderStatusCode = 10100 // 10100,直邮单--已下单
ORDERSTATUSDIRECTMAILCANCEL OrderStatusCode = 10101 // 10101,直邮单--已取消
ORDERSTATUSDIRECTMAILSTARTPRODUCTION OrderStatusCode = 10200 // 10200,直邮单--开始生产
ORDERSTATUSDIRECTMAILCOMPLETEPRODUCTION OrderStatusCode = 10300 // 10300,直邮单--生产完成
ORDERSTATUSDIRECTMAILSHIPPED OrderStatusCode = 10400 // 10400,直邮单--已发货
ORDERSTATUSDIRECTMAILARRIVED OrderStatusCode = 10500 // 10500,直邮单--已到达
ORDERSTATUSCLOUDSTOREORDERED OrderStatusCode = 20100 // 20100,云仓单--已下单
ORDERSTATUSCLOUDSTORECANCEL OrderStatusCode = 20101 // 20101,云仓单--已取消
ORDERSTATUSCLOUDSTORESTARTPRODUCTION OrderStatusCode = 20200 // 20200,云仓单--开始生产
ORDERSTATUSCLOUDSTOREOMPLETEPRODUCTION OrderStatusCode = 20300 // 20300,云仓单--生产完成
ORDERSTATUSCLOUDSTOREARRIVEDWAREHOUSE OrderStatusCode = 20400 // 20400,云仓单--直达仓库
)
// 订单状态名称
@ -88,35 +85,33 @@ var OrderStatusUserCLOUDSTORE []OrderStatusCode
func init() {
// 订单状态名称
PayStatusMessage = make(map[PayStatusCode]string)
PayStatusMessage[PAYSTATUSUNPAID] = "Unpaid"
PayStatusMessage[PAYSTATUSPAID] = "Paid"
PayStatusMessage[PAYSTATUSUNPAID] = "Paid"
PayStatusMessage[PAYSTATUSPAID] = "Unpaid"
PayStatusMessage[PAYSTATUSREFUNDED] = "Refunded"
// 订单状态名称
OrderStatusMessage = make(map[OrderStatusCode]string)
OrderStatusMessage[ORDER_STATUS_UNPAIDDEPOSIT] = "未支付定金"
OrderStatusMessage[ORDERSTATUSUNPAIDDEPOSIT] = "未支付定金"
OrderStatusMessage[ORDER_STATUS_DIRECTMAIL_ORDERED] = "直邮单--已下单"
OrderStatusMessage[ORDER_STATUS_DIRECTMAIL_STARTPRODUCTION] = "直邮单--开始生产"
OrderStatusMessage[ORDER_STATUS_DIRECTMAIL_COMPLETEPRODUCTION] = "直邮单--生产完成"
OrderStatusMessage[ORDER_STATUS_DIRECTMAIL_SHIPPED] = "直邮单--已发货"
OrderStatusMessage[ORDER_STATUS_DIRECTMAIL_ARRIVED] = "直邮单--已到达"
OrderStatusMessage[ORDERSTATUSDIRECTMAILORDERED] = "直邮单--已下单"
OrderStatusMessage[ORDERSTATUSDIRECTMAILSTARTPRODUCTION] = "直邮单--开始生产"
OrderStatusMessage[ORDERSTATUSDIRECTMAILCOMPLETEPRODUCTION] = "直邮单--生产完成"
OrderStatusMessage[ORDERSTATUSDIRECTMAILSHIPPED] = "直邮单--已发货"
OrderStatusMessage[ORDERSTATUSDIRECTMAILARRIVED] = "直邮单--已到达"
OrderStatusMessage[ORDER_STATUS_CLOUDSTORE_ORDERED] = "云仓单--已下单"
OrderStatusMessage[ORDER_STATUS_CLOUDSTORE_STARTPRODUCTION] = "云仓单--开始生产"
OrderStatusMessage[ORDER_STATUS_CLOUDSTORE_COMPLETEPRODUCTION] = "云仓单--生产完成"
OrderStatusMessage[ORDER_STATUS_CLOUDSTORE_ARRIVEDWAREHOUSE] = "云仓单--直达仓库"
OrderStatusMessage[ORDER_STATUS_COMPLETE] = "订单完成"
OrderStatusMessage[ORDERSTATUSCLOUDSTOREORDERED] = "云仓单--已下单"
OrderStatusMessage[ORDERSTATUSCLOUDSTORESTARTPRODUCTION] = "云仓单--开始生产"
OrderStatusMessage[ORDERSTATUSCLOUDSTOREOMPLETEPRODUCTION] = "云仓单--生产完成"
OrderStatusMessage[ORDERSTATUSCLOUDSTOREARRIVEDWAREHOUSE] = "云仓单--直达仓库"
// 订单状态--用户可见--直邮
OrderStatusUserDIRECTMAIL = []OrderStatusCode{
ORDER_STATUS_UNPAIDDEPOSIT, ORDER_STATUS_COMPLETE,
ORDER_STATUS_DIRECTMAIL_ORDERED, ORDER_STATUS_DIRECTMAIL_STARTPRODUCTION, ORDER_STATUS_DIRECTMAIL_COMPLETEPRODUCTION, ORDER_STATUS_DIRECTMAIL_SHIPPED, ORDER_STATUS_DIRECTMAIL_ARRIVED,
ORDERSTATUSUNPAIDDEPOSIT,
ORDERSTATUSDIRECTMAILORDERED, ORDERSTATUSDIRECTMAILSTARTPRODUCTION, ORDERSTATUSDIRECTMAILCOMPLETEPRODUCTION, ORDERSTATUSDIRECTMAILSHIPPED, ORDERSTATUSDIRECTMAILARRIVED,
}
// 订单状态--用户可见--云仓
OrderStatusUserCLOUDSTORE = []OrderStatusCode{
ORDER_STATUS_UNPAIDDEPOSIT, ORDER_STATUS_COMPLETE,
ORDER_STATUS_CLOUDSTORE_ORDERED, ORDER_STATUS_CLOUDSTORE_STARTPRODUCTION, ORDER_STATUS_CLOUDSTORE_COMPLETEPRODUCTION, ORDER_STATUS_CLOUDSTORE_ARRIVEDWAREHOUSE,
ORDERSTATUSUNPAIDDEPOSIT,
ORDERSTATUSCLOUDSTOREORDERED, ORDERSTATUSCLOUDSTORESTARTPRODUCTION, ORDERSTATUSCLOUDSTOREOMPLETEPRODUCTION, ORDERSTATUSCLOUDSTOREARRIVEDWAREHOUSE,
}
}

View File

@ -5,11 +5,3 @@ username: ...
password: ...
namespace: fs_server_api_dev
group: FS-SERVER-API
proxyserver:
key: /opt/server.dev.fusenpack.com.key
pem: /opt/server.dev.fusenpack.com.pem
serverbackend:
key: /opt/serverbackend.dev.fusenpack.com.key
pem: /opt/serverbackend.dev.fusenpack.com.pem

2
go.mod
View File

@ -18,7 +18,7 @@ require (
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
github.com/streadway/amqp v1.1.0
github.com/stripe/stripe-go/v75 v75.7.0
github.com/stripe/stripe-go/v74 v74.26.0
github.com/zeromicro/go-zero v1.5.4
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8
golang.org/x/oauth2 v0.10.0

4
go.sum
View File

@ -548,8 +548,8 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stripe/stripe-go/v75 v75.7.0 h1:Zk7trlj0kClZOwnpjGz7FgVQRBI0Koi28/eaNATgAs0=
github.com/stripe/stripe-go/v75 v75.7.0/go.mod h1:wT44gah+eCY8Z0aSpY/vQlYYbicU9uUAbAqdaUxxDqE=
github.com/stripe/stripe-go/v74 v74.26.0 h1:enbhLtjKGWvJKcGM0f2CazqFSXzpHXcQ42nG2PNsWK0=
github.com/stripe/stripe-go/v74 v74.26.0/go.mod h1:f9L6LvaXa35ja7eyvP6GQswoaIPaBRvGAimAO+udbBw=
github.com/tidwall/gjson v1.12.0 h1:61wEp/qfvFnqKH/WCI3M8HuRut+mHT6Mr82QrFmM2SY=
github.com/tidwall/gjson v1.12.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=

View File

@ -2,28 +2,24 @@ package gmodel
import (
"gorm.io/gorm"
"time"
)
// fs_address 用户地址表
type FsAddress struct {
AddressId int64 `gorm:"primary_key;default:0;auto_increment;" json:"address_id"` //
UserId *int64 `gorm:"index;default:0;" json:"user_id"` // 用户ID
AddressName *string `gorm:"default:'';" json:"address_name"` //
FirstName *string `gorm:"default:'';" json:"first_name"` // FirstName
LastName *string `gorm:"default:'';" json:"last_name"` // LastName
Mobile *string `gorm:"default:'';" json:"mobile"` // 手机号码
Street *string `gorm:"default:'';" json:"street"` // 街道
Suite *string `gorm:"default:'';" json:"suite"` // 房号
City *string `gorm:"default:'';" json:"city"` // 城市
State *string `gorm:"default:'';" json:"state"` //
Country *string `gorm:"default:'';" json:"country"` //
ZipCode *string `gorm:"default:'';" json:"zip_code"` //
Status *int64 `gorm:"default:0;" json:"status"` // 1正常 0异常
IsDefault *int64 `gorm:"index;default:0;" json:"is_default"` // 1默认地址0非默认地址
Ctime *time.Time `gorm:"default:'0000-00-00 00:00:00';" json:"ctime"` // 创建时间
Utime *time.Time `gorm:"default:'0000-00-00 00:00:00';" json:"utime"` // 更新时间
Ltime *time.Time `gorm:"index;default:'0000-00-00 00:00:00';" json:"ltime"` // 上次被使用的时间
Id int64 `gorm:"primary_key;default:0;auto_increment;" json:"id"` //
UserId *int64 `gorm:"index;default:0;" json:"user_id"` // 用户ID
Name *string `gorm:"default:'';" json:"name"` // 地址名称
FirstName *string `gorm:"default:'';" json:"first_name"` // FirstName
LastName *string `gorm:"default:'';" json:"last_name"` // LastName
Mobile *string `gorm:"default:'';" json:"mobile"` // 手机号码
Street *string `gorm:"default:'';" json:"street"` // 街道
Suite *string `gorm:"default:'';" json:"suite"` // 房号
City *string `gorm:"default:'';" json:"city"` // 城市
State *string `gorm:"default:'';" json:"state"` //
Country *string `gorm:"default:'';" json:"country"` //
ZipCode *string `gorm:"default:'';" json:"zip_code"` //
Status *int64 `gorm:"default:0;" json:"status"` // 1正常 0异常
IsDefault *int64 `gorm:"index;default:0;" json:"is_default"` // 1默认地址0非默认地址
}
type FsAddressModel struct {
db *gorm.DB

View File

@ -2,19 +2,17 @@ package gmodel
import (
"context"
"time"
"github.com/zeromicro/go-zero/core/logx"
"gorm.io/gorm"
)
func (a *FsAddressModel) GetOne(ctx context.Context, addressId int64, userId int64) (resp *FsAddress, err error) {
err = a.db.WithContext(ctx).Model(&FsAddress{}).Where("`address_id` = ? and `user_id` = ? and `status` = ? ", addressId, userId, 1).Take(&resp).Error
func (a *FsAddressModel) GetOne(ctx context.Context, id int64, userId int64) (resp *FsAddress, err error) {
err = a.db.WithContext(ctx).Model(&FsAddress{}).Where("`id` = ? and `user_id` = ? and `status` = ? ", id, userId, 1).Take(&resp).Error
return resp, err
}
func (a *FsAddressModel) GetUserAllAddress(ctx context.Context, userId int64) (resp []FsAddress, err error) {
err = a.db.WithContext(ctx).Model(&FsAddress{}).Where("`user_id` = ? and `status` = ?", userId, 1).Order("`ltime` DESC").Find(&resp).Error
err = a.db.WithContext(ctx).Model(&FsAddress{}).Where("`user_id` = ? and `status` = ?", userId, 1).Order("`id` DESC").Find(&resp).Error
if err != nil {
return nil, err
}
@ -23,42 +21,25 @@ func (a *FsAddressModel) GetUserAllAddress(ctx context.Context, userId int64) (r
func (a *FsAddressModel) CreateOne(ctx context.Context, address *FsAddress) (result *FsAddress, err error) {
err = a.db.WithContext(ctx).Model(&FsAddress{}).Transaction(func(tx *gorm.DB) error {
now := time.Now().UTC()
err = a.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
// now := time.Now().UTC().Unix()
result = &FsAddress{
UserId: address.UserId,
AddressName: address.AddressName,
FirstName: address.FirstName,
LastName: address.LastName,
Mobile: address.Mobile,
Street: address.Street,
Suite: address.Suite,
City: address.City,
State: address.State,
Country: address.Country,
ZipCode: address.ZipCode,
Status: address.Status,
IsDefault: address.IsDefault,
Ctime: &now,
Utime: &now,
Ltime: &now,
UserId: address.UserId,
Name: address.Name,
FirstName: address.FirstName,
LastName: address.LastName,
Mobile: address.Mobile,
Street: address.Street,
Suite: address.Suite,
City: address.City,
State: address.State,
Country: address.Country,
ZipCode: address.ZipCode,
Status: address.Status,
IsDefault: address.IsDefault,
}
// lastOne := &FsAddress{}
// err = tx.Where("user_id = ?", lastOne.UserId).Order("ltime ASC").Take(&lastOne).Error
// if err == gorm.ErrRecordNotFound {
// result.Ltime = &now
// return tx.Model(&FsAddress{}).Create(result).Error
// }
// if err != nil {
// return err
// }
// // 根据lastOne处理时间
// ltime := (*lastOne.Ltime).Add(-time.Second)
// result.Ltime = &ltime
return tx.Model(&FsAddress{}).Create(result).Error
return tx.Create(result).Error
})
if err != nil {
@ -68,47 +49,15 @@ func (a *FsAddressModel) CreateOne(ctx context.Context, address *FsAddress) (res
return result, nil
}
func (a *FsAddressModel) UpdateAddress(ctx context.Context, address *FsAddress) (err error) {
err = a.db.WithContext(ctx).Model(&FsAddress{}).Transaction(func(tx *gorm.DB) error {
err = tx.
Where("user_id = ? and address_id = ? and status = 1 ", address.UserId, address.AddressId).
Updates(address).Error
if err != nil {
return err
func (a *FsAddressModel) UpdateAddAddress(ctx context.Context, address *FsAddress) (err error) {
err = a.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
if *address.IsDefault > 0 {
err = tx.Model(&FsAddress{}).Where("user_id = ? and is_default = 1 ", address.UserId).Update("is_default", 0).Error
if err != nil {
return err
}
}
return err
return tx.Model(&FsAddress{}).Where("id = ? and user_id = ?", address.Id, address.UserId).Omit("id", "user_id").Updates(address).Error
})
return err
}
func (a *FsAddressModel) SettingUserDefaultAddress(ctx context.Context, userId int64, addressId int64) (err error) {
err = a.db.WithContext(ctx).Model(&FsAddress{}).Transaction(func(tx *gorm.DB) error {
now := time.Now().UTC()
err = tx.Model(&FsAddress{}).Where(" `user_id` = ? and `status` = ? and `address_id` = ? ", userId, 1, addressId).
UpdateColumn("ltime", now.AddDate(250, 0, 0)).
UpdateColumn("utime", now).Error
if err != nil {
return err
}
err = tx.Where(" `user_id` = ? and `status` = ? and `address_id` != ? and `ltime` > ? ", userId, 1, addressId, now.AddDate(10, 0, 0)).
UpdateColumn("ltime", now).Error
if err != nil {
logx.Error(err)
}
return nil
})
return
}
func (a *FsAddressModel) DeleteOne(ctx context.Context, addressId int64, userId int64) (err error) {
err = a.db.WithContext(ctx).Model(&FsAddress{}).
Where("`address_id` = ? and `user_id` = ? and `status` = ? ", addressId, userId, 1).
UpdateColumn("status", 0).Error
return err
}

View File

@ -2,18 +2,17 @@ package gmodel
import (
"gorm.io/gorm"
"time"
)
// fs_change_code 忘记密码code表
type FsChangeCode struct {
Id int64 `gorm:"primary_key;default:0;auto_increment;" json:"id"` // id
Email *string `gorm:"default:'';" json:"email"` //
Code *string `gorm:"default:'';" json:"code"` //
Ctime *time.Time `gorm:"default:'0000-00-00 00:00:00';" json:"ctime"` //
IsUse *int64 `gorm:"default:0;" json:"is_use"` // 是否使用 1已使用 0未使用
Metadata *[]byte `gorm:"default:'';" json:"metadata"` //
Module *string `gorm:"default:'logo';" json:"module"` //
Id int64 `gorm:"primary_key;default:0;auto_increment;" json:"id"` // id
Email *string `gorm:"default:'';" json:"email"` //
Code *string `gorm:"default:'';" json:"code"` //
CreatedAt *int64 `gorm:"default:0;" json:"created_at"` // 创建时间
IsUse *int64 `gorm:"default:0;" json:"is_use"` // 是否使用 1已使用 0未使用
Metadata *[]byte `gorm:"default:'';" json:"metadata"` //
Module *string `gorm:"default:'logo';" json:"module"` //
}
type FsChangeCodeModel struct {
db *gorm.DB

View File

@ -2,17 +2,20 @@ package gmodel
import (
"gorm.io/gorm"
"time"
)
// fs_guest 游客表
type FsGuest struct {
GuestId int64 `gorm:"primary_key;default:0;auto_increment;" json:"guest_id"` // ID
AuthKey *string `gorm:"default:'';" json:"auth_key"` // jwt token
Status *int64 `gorm:"index;default:1;" json:"status"` // 1正常 0不正常
IsDel *int64 `gorm:"index;default:0;" json:"is_del"` // 是否删除 1删除
Ctime *time.Time `gorm:"index;default:'0000-00-00 00:00:00';" json:"ctime"` //
Utime *time.Time `gorm:"default:'0000-00-00 00:00:00';" json:"utime"` //
GuestId int64 `gorm:"primary_key;default:0;auto_increment;" json:"guest_id"` // ID
AuthKey *string `gorm:"default:'';" json:"auth_key"` // jwt token
Status *int64 `gorm:"index;default:1;" json:"status"` // 1正常 0不正常
IsDel *int64 `gorm:"index;default:0;" json:"is_del"` // 是否删除 1删除
CreatedAt *int64 `gorm:"index;default:0;" json:"created_at"` // 添加时间
UpdatedAt *int64 `gorm:"default:0;" json:"updated_at"` // 更新时间
IsOpenRender *int64 `gorm:"default:0;" json:"is_open_render"` // 是否打开个性化渲染1开启0关闭
IsThousandFace *int64 `gorm:"default:0;" json:"is_thousand_face"` // 是否已经存在千人千面1存在0不存在
IsLowRendering *int64 `gorm:"default:0;" json:"is_low_rendering"` // 是否开启低渲染模型渲染
IsRemoveBg *int64 `gorm:"default:1;" json:"is_remove_bg"` // 用户上传logo是否去除背景
}
type FsGuestModel struct {
db *gorm.DB

View File

@ -12,11 +12,11 @@ import (
func (m *FsGuestModel) GenerateGuestID(ctx context.Context, AccessSecret uint64) (authKey string, err error) {
err = m.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
now := time.Now().UTC()
now := time.Now().UTC().Unix()
var record = &FsGuest{}
tx.Create(record)
authKey, err = auth.GenerateJwtTokenUint64(AccessSecret, now.Unix(), 31536000, 0, int64(record.GuestId))
authKey, err = auth.GenerateJwtTokenUint64(AccessSecret, now, 31536000, 0, int64(record.GuestId))
if err != nil {
logx.Error(err)
err = tx.Rollback().Error
@ -26,7 +26,7 @@ func (m *FsGuestModel) GenerateGuestID(ctx context.Context, AccessSecret uint64)
return err
}
record.AuthKey = &authKey
record.Ctime = &now
record.CreatedAt = &now
err = tx.Updates(record).Error
if err != nil {
logx.Error(err)

View File

@ -40,7 +40,7 @@ type PayInfo struct {
Metadata map[string]interface{} `json:"metadata"` // 额外参数
PayAmount AmountInfo `json:"pay_amount"` // 金额明细
PayMethod string `json:"pay_method"` // 交易方式
PayTime *time.Time `json:"pay_time"` // 支付时间
PayTime **time.Time `json:"pay_time"` // 支付时间
Status PayStatus `json:"status"` // 当前状态
StatusLink []PayStatus `json:"status_link"` // 状态链路
TradeNo string `json:"trade_no"` // 支付交易号
@ -95,26 +95,23 @@ type OrderStatus struct {
// 订单商品
type OrderProduct struct {
TotalPrice AmountInfo `json:"total_price"` // 商品总价
TotalPrice AmountInfo `json:"amount"` // 商品总价
ExpectedDeliveryTime *time.Time `json:"expected_delivery_time"` // 预计到货时间
PurchaseQuantity PurchaseQuantity `json:"purchase_quantity"` // 购买数量
PurchaseQuantity int64 `json:"purchase_quantity"` // 购买数量
ProductID int64 `json:"product_id"` // 商品ID
ProductName string `json:"product_name"` // 商品名称
ItemPrice AmountInfo `json:"item_price"` // 商品单价
ItemPrice AmountInfo `json:"product_price"` // 商品单价
ProductSnapshot interface{} `json:"product_snapshot"` // 商品快照
ShoppingCartSnapshot *FsShoppingCartData `json:"shopping_cart_snapshot"` // 购物车快照
ShoppingCartSnapshot *FsShoppingCart `json:"shopping_cart_snapshot"` // 购物车快照
ProductCover string `json:"product_cover"` // 商品封面
ProductCoverMetadata map[string]interface{} `json:"product_cover_metadata"` // 商品封面
ProductSn string `json:"product_sn"` // 商品编码
DiyInformation *UserDiyInformation `json:"diy_information"`
SizeInfo *OrderProductSizeInfo `json:"size_info"`
FittingInfo *OrderProductFittingInfo `json:"fitting_info"`
StepNum []int `json:"step_num"` // 阶梯数量
IsHighlyCustomized int64 `json:"is_highly_customized"`
}
type PurchaseQuantity struct {
Current interface{} `json:"current"`
Initiate interface{} `json:"initiate"`
}
type OrderProductSizeInfo struct {
SizeID int64 `json:"size_id"`

View File

@ -36,7 +36,6 @@ type FsProduct struct {
RecommendProductSort *string `gorm:"default:'';" json:"recommend_product_sort"` //
SceneIds *string `gorm:"default:'';" json:"scene_ids"` //
IsCustomization *int64 `gorm:"default:0;" json:"is_customization"` // 是否可定制
Unit *string `gorm:"default:'';" json:"unit"` //
}
type FsProductModel struct {
db *gorm.DB

View File

@ -2,34 +2,30 @@ package gmodel
import (
"gorm.io/gorm"
"time"
)
// fs_product_model3d 产品模型表
type FsProductModel3d struct {
Id int64 `gorm:"primary_key;default:0;auto_increment;" json:"id"` //
ProductId *int64 `gorm:"index;default:0;" json:"product_id"` // 产品ID
Tag *int64 `gorm:"default:1;" json:"tag"` // 类别1模型2配件3场景
Title *string `gorm:"default:'';" json:"title"` // 标题
Name *string `gorm:"default:'';" json:"name"` // 详情页展示名称
ModelInfo *string `gorm:"default:'';" json:"model_info"` // 模型详情
MaterialId *int64 `gorm:"default:0;" json:"material_id"` // 材质ID
SizeId *int64 `gorm:"default:0;" json:"size_id"` // 尺寸ID
Sort *int64 `gorm:"default:0;" json:"sort"` // 排序
Light *int64 `gorm:"default:0;" json:"light"` // 灯光组
LightList *string `gorm:"default:'';" json:"light_list"` // 灯光备选项
PartId *int64 `gorm:"default:0;" json:"part_id"` // 配件选项id配件就是模型的id
PartList *string `gorm:"default:'';" json:"part_list"` //
Status *int64 `gorm:"default:0;" json:"status"` // 状态位 显示 删除
Ctime *time.Time `gorm:"default:'0000-00-00 00:00:00';" json:"ctime"` //
OptionTemplate *int64 `gorm:"default:0;" json:"option_template"` // 配件绑定的公共模板
Price *int64 `gorm:"default:0;" json:"price"` //
Sku *string `gorm:"default:'';" json:"sku"` // sku
IsHot *int64 `gorm:"default:0;" json:"is_hot"` // 是否热门
IsCloudRender *int64 `gorm:"default:0;" json:"is_cloud_render"` // 是否设置为云渲染模型
Utime *time.Time `gorm:"default:'0000-00-00 00:00:00';" json:"utime"` //
StepPrice *[]byte `gorm:"default:'';" json:"step_price"` //
PackedUnit *int64 `gorm:"default:0;" json:"packed_unit"` // 被打包的数量单位
Id int64 `gorm:"primary_key;default:0;auto_increment;" json:"id"` //
ProductId *int64 `gorm:"index;default:0;" json:"product_id"` // 产品ID
Tag *int64 `gorm:"default:1;" json:"tag"` // 类别1模型2配件3场景
Title *string `gorm:"default:'';" json:"title"` // 标题
Name *string `gorm:"default:'';" json:"name"` // 详情页展示名称
ModelInfo *string `gorm:"default:'';" json:"model_info"` // 模型详情
MaterialId *int64 `gorm:"default:0;" json:"material_id"` // 材质ID
SizeId *int64 `gorm:"default:0;" json:"size_id"` // 尺寸ID
Sort *int64 `gorm:"default:0;" json:"sort"` // 排序
Light *int64 `gorm:"default:0;" json:"light"` // 灯光组
LightList *string `gorm:"default:'';" json:"light_list"` // 灯光备选项
PartId *int64 `gorm:"default:0;" json:"part_id"` // 配件选项id配件就是模型的id
PartList *string `gorm:"default:'';" json:"part_list"` //
Status *int64 `gorm:"default:0;" json:"status"` // 状态位 显示 删除
Ctime *int64 `gorm:"default:0;" json:"ctime"` // 添加时间
OptionTemplate *int64 `gorm:"default:0;" json:"option_template"` // 配件绑定的公共模板
Price *int64 `gorm:"default:0;" json:"price"` // 仅配件用,配件的价格, 单位:美分
Sku *string `gorm:"default:'';" json:"sku"` // sku
IsHot *int64 `gorm:"default:0;" json:"is_hot"` // 是否热门
IsCloudRender *int64 `gorm:"default:0;" json:"is_cloud_render"` // 是否设置为云渲染模型
}
type FsProductModel3dModel struct {
db *gorm.DB

View File

@ -4,19 +4,8 @@ import (
"context"
)
// 阶梯价结构
type StepPriceJsonStruct struct {
PriceRange []struct {
Label string `json:"label"`
Price int64 `json:"price"`
EndQuantity int64 `json:"end_quantity"`
StartQuantity int64 `json:"start_quantity"`
} `json:"price_range"`
MinBuyUnitsNum int64 `json:"min_buy_units_num"`
}
func (d *FsProductModel3dModel) FindOne(ctx context.Context, id int64, fields ...string) (resp *FsProductModel3d, err error) {
db := d.db.WithContext(ctx).Model(&FsProductModel3d{}).Where("`id` = ? and `status` =? ", id, 1)
db := d.db.WithContext(ctx).Model(&FsProductModel3d{}).Where("`id` = ? ", id)
if len(fields) > 0 {
db = db.Select(fields[0])
}
@ -41,7 +30,7 @@ func (d *FsProductModel3dModel) GetAllByIdsWithoutStatus(ctx context.Context, id
if len(ids) == 0 {
return
}
db := d.db.WithContext(ctx).Model(&FsProductModel3d{}).Where("`id` in (?) and `status` = ?", ids, 1)
db := d.db.WithContext(ctx).Model(&FsProductModel3d{}).Where("`id` in (?)", ids)
if len(fields) > 0 {
db = db.Select(fields[0])
}
@ -80,13 +69,13 @@ func (d *FsProductModel3dModel) Get3dModelsByParam(ctx context.Context, req Get3
return resp, err
}
func (d *FsProductModel3dModel) Update(ctx context.Context, id int64, data *FsProductModel3d) error {
return d.db.WithContext(ctx).Where("`id` = ? and `status` =? ", id, 1).Updates(&data).Error
return d.db.WithContext(ctx).Where("`id` = ? ", id).Updates(&data).Error
}
func (d *FsProductModel3dModel) GetAllBySizeIdsTag(ctx context.Context, sizeIds []int64, tag int64, fields ...string) (resp []FsProductModel3d, err error) {
if len(sizeIds) == 0 {
return
}
db := d.db.WithContext(ctx).Model(&FsProductModel3d{}).Where("`size_id` in (?) and `tag` = ? and `status` = ?", sizeIds, tag, 1)
db := d.db.WithContext(ctx).Model(&FsProductModel3d{}).Where("`size_id` in (?) and `tag` = ?", sizeIds, tag)
if len(fields) != 0 {
db = db.Select(fields[0])
}
@ -94,7 +83,7 @@ func (d *FsProductModel3dModel) GetAllBySizeIdsTag(ctx context.Context, sizeIds
return resp, err
}
func (d *FsProductModel3dModel) GetAll(ctx context.Context) (resp []FsProductModel3d, err error) {
err = d.db.WithContext(ctx).Model(&FsProductModel3d{}).Where("`status` = ?", 1).Find(&resp).Error
err = d.db.WithContext(ctx).Model(&FsProductModel3d{}).Find(&resp).Error
return resp, err
}
@ -107,7 +96,7 @@ func (d *FsProductModel3dModel) GetGroupPartListByProductIds(ctx context.Context
if len(productIds) == 0 {
return
}
err = d.db.WithContext(ctx).Model(&FsProductModel3d{}).Where("`product_id` in(?) and `status` =? ", productIds, 1).
err = d.db.WithContext(ctx).Model(&FsProductModel3d{}).
Select("product_id,group_concat(part_list) as part_list").
Group("product_id").Find(&resp).Error
return resp, err
@ -131,24 +120,3 @@ func (d *FsProductModel3dModel) GetOneBySizeIdTag(ctx context.Context, sizeId in
err = db.Take(&resp).Error
return resp, err
}
func (d *FsProductModel3dModel) GetAllByProductIdTag(ctx context.Context, productId int64, tag int64, fields ...string) (resp []FsProductModel3d, err error) {
db := d.db.WithContext(ctx).Model(&FsProductModel3d{}).
Where("`product_id` = ? and `tag` = ? and `status` = ?", productId, tag, 1).
Order("sort DESC")
if len(fields) != 0 {
db = db.Select(fields[0])
}
err = db.Find(&resp).Error
return resp, err
}
func (d *FsProductModel3dModel) FindOneByProductIdSizeIdTag(ctx context.Context, productId, sizeId, tag int64, fields ...string) (resp *FsProductModel3d, err error) {
db := d.db.WithContext(ctx).Model(&FsProductModel3d{}).
Where("`product_id` = ? and `size_id` = ? and `tag` = ? and `status` = ?", productId, sizeId, tag, 1).
Order("sort DESC")
if len(fields) != 0 {
db = db.Select(fields[0])
}
err = db.Take(&resp).Error
return resp, err
}

View File

@ -2,7 +2,6 @@ package gmodel
import (
"context"
"time"
)
func (m *FsShoppingCartModel) TableName() string {
@ -12,26 +11,10 @@ func (m *FsShoppingCartModel) TableName() string {
// 关联查询
type RelaFsShoppingCart struct {
FsShoppingCart
ShoppingCartProduct *RelaFsProduct `json:"shopping_cart_product" gorm:"foreignkey:product_id;references:id"`
ShoppingCartProductModel3d *FsProductModel3d `json:"shopping_cart_product_model3d_list" gorm:"foreignkey:model_id;references:id"`
ShoppingCartProductModel3dFitting *FsProductModel3d `json:"shopping_cart_product_model3d_list_fitting" gorm:"foreignkey:fitting_id;references:id"`
}
type FsShoppingCartData struct {
Id int64 `gorm:"primary_key;default:0;auto_increment;" json:"id"` // id
UserId *int64 `gorm:"default:0;" json:"user_id"` // 用户id
ProductId *int64 `gorm:"default:0;" json:"product_id"` // 产品id
TemplateId *int64 `gorm:"default:0;" json:"template_id"` // 模板id
ModelId *int64 `gorm:"default:0;" json:"model_id"` // 模型id
SizeId *int64 `gorm:"default:0;" json:"size_id"` // 尺寸id
LightId *int64 `gorm:"default:0;" json:"light_id"` // 灯光id
FittingId *int64 `gorm:"default:0;" json:"fitting_id"` // 配件id
PurchaseQuantity *int64 `gorm:"default:0;" json:"purchase_quantity"` // 购买数量
Snapshot *map[string]interface{} `gorm:"default:'';" json:"snapshot"` //
SnapshotData *string `gorm:"default:'';" json:"snapshot_data"` //
IsSelected *int64 `gorm:"default:0;" json:"is_selected"` // 是否被选中 0非 1是
IsHighlyCustomized *int64 `gorm:"default:0;" json:"is_highly_customized"` // 是否高度定制 0非 1是针对客人高度定制只能后台增加如购物车
Ctime *time.Time `gorm:"default:'0000-00-00 00:00:00';" json:"ctime"` //
Utime *time.Time `gorm:"default:'0000-00-00 00:00:00';" json:"utime"` //
ShoppingCartProduct *RelaFsProduct `json:"shopping_cart_product" gorm:"foreignkey:product_id;references:id"`
ShoppingCartProductPriceList []*FsProductPrice `json:"shopping_cart_product_price_list" gorm:"foreignkey:product_id;references:product_id"`
ShoppingCartProductModel3dList []*FsProductModel3d `json:"shopping_cart_product_model3d_list" gorm:"foreignkey:product_id;references:product_id"`
ShoppingCartProductModel3dFitting *FsProductModel3d `json:"shopping_cart_product_model3d_list_fitting" gorm:"foreignkey:fitting_id;references:id"`
}
// 快照json数据结构

View File

@ -2,28 +2,35 @@ package gmodel
import (
"gorm.io/gorm"
"time"
)
// fs_user 用户表
type FsUser struct {
Id int64 `gorm:"primary_key;default:0;auto_increment;" json:"id"` // ID
FaceId *string `gorm:"default:'0';" json:"face_id"` // facebook的userid
GoogleId *string `gorm:"default:'0';" json:"google_id"` // google的sub
FirstName *string `gorm:"default:'';" json:"first_name"` // FirstName
LastName *string `gorm:"default:'';" json:"last_name"` // LastName
Username *string `gorm:"index;default:'';" json:"username"` //
Company *string `gorm:"default:'';" json:"company"` // 公司名称
Mobile *string `gorm:"default:'';" json:"mobile"` //
PasswordHash *string `gorm:"default:'';" json:"password_hash"` //
VerificationToken *string `gorm:"default:'';" json:"verification_token"` //
PasswordResetToken *string `gorm:"default:'';" json:"password_reset_token"` //
Email *string `gorm:"unique_key;default:'';" json:"email"` // 邮箱
Type *int64 `gorm:"default:0;" json:"type"` // 1普通餐厅 2连锁餐厅
Status *int64 `gorm:"default:1;" json:"status"` // 1正常 0不正常
IsDel *int64 `gorm:"default:0;" json:"is_del"` // 是否删除 1删除
Ctime *time.Time `gorm:"default:'0000-00-00 00:00:00';" json:"ctime"` //
Utime *time.Time `gorm:"default:'0000-00-00 00:00:00';" json:"utime"` //
Id int64 `gorm:"primary_key;default:0;auto_increment;" json:"id"` // ID
FaceId *string `gorm:"default:'0';" json:"face_id"` // facebook的userid
GoogleId *string `gorm:"default:'0';" json:"google_id"` // google的sub
FirstName *string `gorm:"default:'';" json:"first_name"` // FirstName
LastName *string `gorm:"default:'';" json:"last_name"` // LastName
Username *string `gorm:"index;default:'';" json:"username"` //
Company *string `gorm:"default:'';" json:"company"` // 公司名称
Mobile *string `gorm:"default:'';" json:"mobile"` // 手机号码
PasswordHash *string `gorm:"default:'';" json:"password_hash"` //
VerificationToken *string `gorm:"default:'';" json:"verification_token"` //
PasswordResetToken *string `gorm:"default:'';" json:"password_reset_token"` //
Email *string `gorm:"unique_key;default:'';" json:"email"` // 邮箱
Type *int64 `gorm:"default:0;" json:"type"` // 1普通餐厅 2连锁餐厅
Status *int64 `gorm:"default:1;" json:"status"` // 1正常 0不正常
IsDel *int64 `gorm:"default:0;" json:"is_del"` // 是否删除 1删除
CreatedAt *int64 `gorm:"default:0;" json:"created_at"` // 添加时间
UpdatedAt *int64 `gorm:"default:0;" json:"updated_at"` // 更新时间
IsOrderStatusEmail *int64 `gorm:"default:0;" json:"is_order_status_email"` // 订单状态改变时是否接收邮件
IsEmailAdvertisement *int64 `gorm:"default:0;" json:"is_email_advertisement"` // 是否接收邮件广告
IsOrderStatusPhone *int64 `gorm:"default:0;" json:"is_order_status_phone"` // 订单状态改变是是否接收电话
IsPhoneAdvertisement *int64 `gorm:"default:0;" json:"is_phone_advertisement"` // 是否接收短信广告
IsOpenRender *int64 `gorm:"default:0;" json:"is_open_render"` // 是否打开个性化渲染1开启0关闭
IsThousandFace *int64 `gorm:"default:0;" json:"is_thousand_face"` // 是否已经存在千人千面1存在0不存在
IsLowRendering *int64 `gorm:"default:0;" json:"is_low_rendering"` //
IsRemoveBg *int64 `gorm:"default:1;" json:"is_remove_bg"` // 用户上传logo是否去除背景
}
type FsUserModel struct {
db *gorm.DB

View File

@ -4,9 +4,6 @@ package gmodel
import (
"context"
"encoding/json"
"fmt"
"fusenapi/utils/fssql"
"fusenapi/utils/handlers"
"gorm.io/gorm"
@ -45,39 +42,3 @@ func (p *FsUserInfoModel) CreateOrUpdate(gormDB *gorm.DB, req *FsUserInfo) (resp
}
return req, err
}
func (m *FsUserInfoModel) MergeMetadata(userId int64, meta any) error {
return fssql.MetadataModulePATCH(m.db, "profile", FsUserInfo{}, map[string]any{
"base": meta,
}, "user_id = ?", userId)
}
func (m *FsUserInfoModel) GetProfile(ctx context.Context, pkey string, userId int64) (map[string]any, error) {
var baseinfo map[string]any
tname := fssql.GetGormTableName(m.db, FsUserInfo{})
if pkey == "." {
pkey = ""
} else {
pkey = "." + pkey
}
rawsql := fmt.Sprintf("select JSON_EXTRACT(metadata,'$%s') as query from %s where user_id = ? and module = 'profile' order by ctime DESC limit 1", pkey, tname)
err := m.db.Raw(rawsql, userId).Take(&baseinfo).Error
if err != nil {
return nil, err
}
v, ok := baseinfo["query"].(string)
if !ok {
return nil, nil
}
var info map[string]any
err = json.Unmarshal([]byte(v), &info)
if err != nil {
return nil, err
}
return info, nil
}

View File

@ -4,11 +4,14 @@ import (
"context"
"encoding/json"
"fmt"
"log"
"fusenapi/utils/auth"
"fusenapi/utils/fssql"
"time"
"github.com/zeromicro/go-zero/core/logx"
"gorm.io/gorm"
)
@ -63,26 +66,28 @@ func InheritGuestIdResource(tx *gorm.DB, userId, guestId int64, afterDo func(txR
if guestId != 0 {
// 继承guest_id的资源表
err = txRes.
Where("guest_id = ? and source != 'temp' and version != '0.0.0'", guestId).
Where("guest_id = ?", guestId).
UpdateColumn("user_id", userId).Error
if err != nil && err != gorm.ErrRecordNotFound {
logx.Info(err, "找到user_id1 afterDo")
return err
}
err = txUserMaterial.
Where("guest_id = ? and module != 'clear' and module != 'temp'", guestId).
Where("guest_id = ?", guestId).
UpdateColumn("user_id", userId).Error
if err != nil && err != gorm.ErrRecordNotFound {
logx.Info(err, "找到user_id1 afterDo")
return err
}
err = txUserInfo.
Where("guest_id = ? and module != 'clear' and module != 'temp'", guestId).
Where("guest_id = ?", guestId).
UpdateColumn("user_id", userId).Error
if err != nil && err != gorm.ErrRecordNotFound {
logx.Info(err, "找到user_id1 afterDo")
return err
}
}
@ -115,9 +120,9 @@ func (u *FsUserModel) RegisterByGoogleOAuth(ctx context.Context, token *auth.Reg
if err != nil {
// 没有找到在数据库就创建注册
if err == gorm.ErrRecordNotFound {
createAt := time.Now().UTC()
createAt := time.Now().UTC().Unix()
user.Email = &token.Email
user.Ctime = &createAt
user.CreatedAt = &createAt
user.GoogleId = &googleId
user.PasswordHash = &token.Password
user.FirstName = &firstName
@ -145,6 +150,21 @@ func (u *FsUserModel) RegisterByGoogleOAuth(ctx context.Context, token *auth.Reg
return user, nil
}
// SubscriptionStatus 订阅状态
type SubscriptionStatus struct {
SubEmail bool `json:"all_emails"`
ItemMap *struct {
} `json:"item_map"`
}
// UserProfile 个人信息
type UserProfile struct {
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
Resetaurant string `json:"resetaurant"`
SubStatus SubscriptionStatus `json:"sub_status"`
}
// 自平台的注册流程
func (u *FsUserModel) RegisterByFusen(ctx context.Context, token *auth.RegisterToken) (user *FsUser, err error) {
@ -154,41 +174,44 @@ func (u *FsUserModel) RegisterByFusen(ctx context.Context, token *auth.RegisterT
var err error
err = tx.Model(&FsUser{}).Where("email = ?", token.Email).Take(user).Error
log.Println("success", token.TraceId)
if err == gorm.ErrRecordNotFound {
FirstName := token.Extend["first_name"].(string)
LastName := token.Extend["last_name"].(string)
Resetaurant := token.Extend["resetaurant"].(string)
createAt := time.Now().UTC()
createAt := time.Now().UTC().Unix()
user.Email = &token.Email
user.Ctime = &createAt
user.CreatedAt = &createAt
user.PasswordHash = &token.Password
user.FirstName = &FirstName
user.LastName = &LastName
err = tx.Model(&FsUser{}).Create(user).Error
if err != nil && err != gorm.ErrRecordNotFound {
logx.Error(err)
return err
}
log.Println("success", token.TraceId)
// 继承guest_id的资源表
err = InheritGuestIdResource(tx, user.Id, token.GuestId, func(txResouce, txUserMaterial, txUserInfo *gorm.DB) error {
userProfileBase := UserProfileBase{
log.Println("success", token.TraceId)
userProfile := &UserProfile{
FirstName: FirstName,
LastName: LastName,
Resetaurant: Resetaurant,
}
userProfile := &UserProfile{
ProfileBase: userProfileBase,
}
metadata, err := json.Marshal(userProfile)
if err != nil {
return err
}
// txUserInfo.Where("user_id = ?", user.Id).Row().Err()
now := time.Now().UTC()
uinfo := &FsUserInfo{
Module: FsString("profile"),
@ -199,18 +222,18 @@ func (u *FsUserModel) RegisterByFusen(ctx context.Context, token *auth.RegisterT
Utime: &now,
}
// logx.Error(metadata)
err = txUserInfo.Where("module = 'profile' and user_id = ?", *uinfo.UserId).Take(nil).Error
err = txUserInfo.Where("module = 'profile' and user_id = ?", uinfo.UserId).Take(nil).Error
// txUserInfo.Statement.Table
log.Println(err, "找到user_id1")
if err != nil {
if err == gorm.ErrRecordNotFound {
err = tx.Model(&FsUserInfo{}).Create(uinfo).Error
// logx.Info(err, "*uinfo.UserId:", *uinfo.UserId, " ", uinfo.Id)
err = txUserInfo.Create(uinfo).Error
if err == gorm.ErrRecordNotFound {
return nil
}
}
} else {
log.Println("找到user_id2")
err = fssql.MetadataModulePATCH(txUserInfo, "profile", FsUserInfo{}, metadata, "user_id = ?", *uinfo.UserId)
if err != nil {
return err

View File

@ -35,25 +35,3 @@ func FsFloat(v float64) *float64 {
func FsBool(v bool) *bool {
return &v
}
// SubscriptionStatus 订阅状态
type SubscriptionStatus struct {
SubEmail bool `json:"all_emails"`
ItemMap *struct {
} `json:"item_map"`
}
type UserProfile struct {
ProfileBase UserProfileBase `json:"base"`
SubStatus SubscriptionStatus `json:"sub_status"`
}
// UserProfileBase 个人信息
type UserProfileBase struct {
FirstName string `json:"first_name"` // 首名
LastName string `json:"last_name"` // 后名
UserName string `json:"user_name"` // 用户名
Mobile string `json:"mobile"` // 电话
Resetaurant string `json:"resetaurant"` // 不知道干什么
Company string `json:"company"` // 公司
}

View File

@ -18,6 +18,7 @@ import (
"time"
"github.com/gorilla/websocket"
"github.com/zeromicro/go-zero/core/logx"
"gopkg.in/yaml.v2"
_ "fusenapi/utils/auth"
@ -96,16 +97,14 @@ func main() {
indexHtmlPath := vueBuild + "/index.html"
mux.Handle("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if strings.HasPrefix(r.URL.Path, "/api/") {
r.ParseMultipartForm(100 << 20)
// if err != nil {
// logx.Error(err)
// }
err := r.ParseMultipartForm(100 << 20)
if err != nil {
logx.Error(err)
}
// 对/api开头的请求进行反向代理
proxy := httputil.NewSingleHostReverseProxy(apiURL)
proxy.ServeHTTP(w, r)
return
} else {
@ -209,22 +208,22 @@ func NewBackend(mux *http.ServeMux, httpAddress string, muxPaths ...string) *Bac
target := url.URL{Scheme: "ws", Host: strings.Split(backend.HttpAddress, "//")[1], Path: r.URL.Path}
var transfer = func(src, dest *websocket.Conn) {
defer src.Close()
defer dest.Close()
// TODO: 可以做错误处理
for {
mType, msg, err := src.ReadMessage()
if err != nil {
log.Println(err)
return
break
}
err = dest.WriteMessage(mType, msg)
if err != nil {
log.Println(err)
return
break
}
}
src.Close()
dest.Close()
}
header := r.Header.Clone()
@ -248,7 +247,6 @@ func NewBackend(mux *http.ServeMux, httpAddress string, muxPaths ...string) *Bac
}
conn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
// defer conn.Close()
@ -261,14 +259,14 @@ func NewBackend(mux *http.ServeMux, httpAddress string, muxPaths ...string) *Bac
// 解析目标URL包含了查询参数
targetURL, err := url.Parse(httpAddress + r.URL.String())
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
http.Error(w, "Error parsing target URL", http.StatusInternalServerError)
return
}
// 创建新的请求
proxyReq, err := http.NewRequest(r.Method, targetURL.String(), r.Body)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
http.Error(w, "Error creating proxy request", http.StatusInternalServerError)
return
}
@ -286,7 +284,7 @@ func NewBackend(mux *http.ServeMux, httpAddress string, muxPaths ...string) *Bac
// 发送请求
resp, err := backend.Client.Do(proxyReq)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
http.Error(w, "Error sending proxy request", http.StatusInternalServerError)
return
}
defer resp.Body.Close()
@ -302,7 +300,7 @@ func NewBackend(mux *http.ServeMux, httpAddress string, muxPaths ...string) *Bac
w.WriteHeader(resp.StatusCode)
_, err = io.Copy(w, resp.Body)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
http.Error(w, "Error copying proxy response", http.StatusInternalServerError)
return
}
}

View File

@ -4,94 +4,64 @@ single_server_name=$1
go mod tidy
go mod vendor
find /tmp/go-build* -mmin +5 -exec rm -rf {} +
find /tmp/go-link* -mmin +5 -exec rm -rf {} +
run_proxyserver() {
# 定义目录和screen名称
dir_path="./proxyserver"
screen_name="proxyserver"
# 进入目录
cd $dir_path
# 检查是否存在screen session
if screen -list | grep -q "$screen_name"; then
# 结束存在的screen session
screen -S $screen_name -X quit
fi
go build
# 启动新的screen session并运行go程序
echo "run $screen_name"
screen -dmS $screen_name -L ./$screen_name
}
# 定义一个函数来在每个服务器目录下运行 go run <server_name>.go
run_server() {
server_name=$1
# 导航到相应的目录
cd server/$server_name
echo "build $server_name"
go build
echo "Running $server_name"
# 如果之前存在相同名字的 screen 会话,先将其终止
# 首先尝试关闭已存在的screen会话
existing_session=$(screen -ls | grep -w "$server_name")
if [ -n "$existing_session" ]; then
echo "Terminating existing screen session for $server_name"
screen -S "$server_name" -X quit
while [[ $(screen -ls | grep "\.$server_name\s") ]]; do
sleep 0.1s # 等待0.1秒后再次检查
echo "wait for $server_name"
done
fi
# 循环检查screen进程是否存在
# 导航到相应的目录
cd server/$server_name
go build
[ -f .gitignore ] || echo $server_name > .gitignore
# 使用 screen 运行 go run <server_name>.go
echo "Running $server_name"
screen -dmS $server_name -L ./$server_name
# 返回到上一级目录
cd - > /dev/null
}
if [ "$single_server_name" = "proxyserver" ]; then
# 重启proxyserver的逻辑
run_proxyserver
else
find /tmp/go-build* -mmin +5 -exec rm -rf {} +
find /tmp/go-link* -mmin +5 -exec rm -rf {} +
server_dirs=() # 初始化一个空数组
server_dirs=() # 初始化一个空数组
if [ -n "$single_server_name" ]; then
server_dirs=("$single_server_name")
else
for dir in server/*/ ; do # 遍历 "server/" 下的所有子目录
dir=${dir%*/} # 删除末尾的 "/"
dir=${dir##*/} # 删除开头的 "server/"
server_dirs+=("$dir") # 添加到数组
done
fi
# 在每个服务器目录下运行相应的 go 程序
for server_dir in "${server_dirs[@]}"; do
run_server $server_dir
done
if [ -n "$single_server_name" ]; then
echo "no proxyserver restart"
else
run_proxyserver
fi
if [ -n "$single_server_name" ]; then
server_dirs=("$single_server_name")
else
for dir in server/*/ ; do # 遍历 "server/" 下的所有子目录
dir=${dir%*/} # 删除末尾的 "/"
dir=${dir##*/} # 删除开头的 "server/"
server_dirs+=("$dir") # 添加到数组
done
fi
# 在每个服务器目录下运行相应的 go 程序
for server_dir in "${server_dirs[@]}"; do
run_server $server_dir
done
# 定义目录和screen名称
dir_path="./proxyserver"
screen_name="proxyserver"
# 进入目录
cd $dir_path
# 检查是否存在screen session
if screen -list | grep -q "$screen_name"; then
# 结束存在的screen session
screen -S $screen_name -X quit
fi
go build
# 启动新的screen session并运行go程序
screen -dmS $screen_name -L ./$screen_name

View File

@ -97,7 +97,7 @@ func CommonNotify(WebsocketAddr, wid string, event *wevent.WebsocketEvent) error
func (l *UserEmailConfirmationLogic) UserEmailConfirmation(req *types.RequestEmailConfirmation, userinfo *auth.UserInfo) (resp *basic.Response) {
// 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data)
// userinfo 传入值时, 一定不为null
logx.Error("找到user_id1 UserEmailConfirmation")
switch auth.OperateType(req.OpType) {
case auth.OpTypeRegister:

View File

@ -49,50 +49,50 @@ func (l *UserAddAddressLogic) UserAddAddress(req *types.RequestAddAddress, useri
isDefautl int64 = 1 // 默认地址为1
)
createOne := &gmodel.FsAddress{ // 构建FsAddress结构体
AddressName: &req.Name,
FirstName: &req.FirstName,
LastName: &req.LastName,
Mobile: &req.Mobile,
Street: &req.Street,
Suite: &req.Suite,
City: &req.City,
State: &req.State,
Country: &country,
Status: &status,
UserId: &userinfo.UserId,
ZipCode: &req.ZipCode,
IsDefault: &isDefautl,
Name: &req.Name,
FirstName: &req.FirstName,
LastName: &req.LastName,
Mobile: &req.Mobile,
Street: &req.Street,
Suite: &req.Suite,
City: &req.City,
State: &req.State,
Country: &country,
Status: &status,
UserId: &userinfo.UserId,
ZipCode: &req.ZipCode,
IsDefault: &isDefautl,
}
created, err := m.CreateOne(l.ctx, createOne) // 新增地址
if err != nil {
logx.Error(err) // 日志记录错误
return resp.SetStatus(basic.CodeDbCreateErr) // 返回数据库创建错误
}
return resp.SetStatus(basic.CodeOK, map[string]int64{"id": created.AddressId}) // 返回成功并返回地址ID
return resp.SetStatus(basic.CodeOK, map[string]int64{"id": created.Id}) // 返回成功并返回地址ID
}
address := &gmodel.FsAddress{
AddressId: req.Id,
AddressName: &req.Name,
FirstName: &req.FirstName,
LastName: &req.LastName,
Mobile: &req.Mobile,
Street: &req.Street,
Suite: &req.Suite,
City: &req.City,
State: &req.State,
Status: &status,
UserId: &userinfo.UserId,
ZipCode: &req.ZipCode,
IsDefault: &req.IsDefault,
Id: req.Id,
Name: &req.Name,
FirstName: &req.FirstName,
LastName: &req.LastName,
Mobile: &req.Mobile,
Street: &req.Street,
Suite: &req.Suite,
City: &req.City,
State: &req.State,
Status: &status,
UserId: &userinfo.UserId,
ZipCode: &req.ZipCode,
IsDefault: &req.IsDefault,
}
// 插入数据库 更新地址
err := m.UpdateAddress(l.ctx, address)
err := m.UpdateAddAddress(l.ctx, address)
if err != nil {
logx.Error(err)
return resp.SetStatus(basic.CodeDbUpdateErr)
}
return resp.SetStatus(basic.CodeOK, map[string]int64{"id": address.AddressId})
return resp.SetStatus(basic.CodeOK, map[string]int64{"id": address.Id})
}

View File

@ -7,7 +7,6 @@ import (
"fusenapi/server/home-user-auth/internal/types"
"fusenapi/utils/auth"
"fusenapi/utils/basic"
"gorm.io/gorm"
"github.com/zeromicro/go-zero/core/logx"
@ -46,13 +45,13 @@ func (l *UserBasicInfoLogic) UserBasicInfo(req *types.Request, userinfo *auth.Us
}
return resp.SetStatus(basic.CodeOK, types.DataUserBasicInfo{
Type: *user.Type,
// IsOrderStatusEmail: *user.IsOrderStatusEmail,
// IsEmailAdvertisement: *user.IsEmailAdvertisement,
// IsOrderStatusPhone: *user.IsOrderStatusPhone,
// IsPhoneAdvertisement: *user.IsPhoneAdvertisement,
// IsOpenRender: *user.IsOpenRender,
// IsLowRendering: *user.IsLowRendering,
// IsRemoveBg: *user.IsRemoveBg,
Type: *user.Type,
IsOrderStatusEmail: *user.IsOrderStatusEmail,
IsEmailAdvertisement: *user.IsEmailAdvertisement,
IsOrderStatusPhone: *user.IsOrderStatusPhone,
IsPhoneAdvertisement: *user.IsPhoneAdvertisement,
IsOpenRender: *user.IsOpenRender,
IsLowRendering: *user.IsLowRendering,
IsRemoveBg: *user.IsRemoveBg,
})
}

View File

@ -45,31 +45,8 @@ func (l *UserLogoSetLogic) UserLogoSet(req *types.UserLogoSetReq, userinfo *auth
// 如果是,返回未授权的错误码
return resp.SetStatus(basic.CodeUnAuth)
}
var nowTime = time.Now().UTC()
if req.LogoSelectedId == 0 {
NewFsUserMaterialModel1 := gmodel.NewFsUserMaterialModel(l.svcCtx.MysqlConn)
NewFsUserMaterialModelRow1 := NewFsUserMaterialModel1.RowSelectBuilder(nil).Where("id = ?", 0)
defaultMaterialInfo, err := NewFsUserMaterialModel1.FindOne(l.ctx, NewFsUserMaterialModelRow1.Model(&gmodel.FsUserMaterial{}))
if err != nil {
logc.Errorf(l.ctx, "defaultMaterialInfo FindOne err%+v", err)
return resp.SetStatus(basic.CodeLogoSetCategory, "logo not find")
}
var defaultMaterial = gmodel.FsUserMaterial{
Module: defaultMaterialInfo.Module,
UserId: &userinfo.UserId,
GuestId: &userinfo.GuestId,
ResourceId: defaultMaterialInfo.ResourceId,
ResourceUrl: defaultMaterialInfo.ResourceUrl,
Ctime: &nowTime,
}
MaterialCreateRes := l.svcCtx.MysqlConn.Create(&defaultMaterial)
err = MaterialCreateRes.Error
if err != nil {
logc.Errorf(l.ctx, "defaultMaterialInfo Create err%+v", err)
return resp.SetStatus(basic.CodeLogoSetCategory, "logo not find")
}
req.LogoSelectedId = defaultMaterial.Id
return resp.SetStatus(basic.CodeLogoSetCategory, "logo logo_selected_id not null")
}
if req.SetLogoCategory == 1 && req.CategoryId == 0 {
return resp.SetStatus(basic.CodeLogoSetCategory, "logo category_id not null")
@ -96,6 +73,7 @@ func (l *UserLogoSetLogic) UserLogoSet(req *types.UserLogoSetReq, userinfo *auth
return resp.SetStatus(basic.CodeLogoSetCategory, "logo not find")
}
var nowTime = time.Now().UTC()
err = l.svcCtx.MysqlConn.WithContext(l.ctx).Transaction(func(tx *gorm.DB) error {
var metadataMapOldUserMaterial map[string]interface{}
if userMaterialInfo.Metadata != nil {

View File

@ -1,35 +0,0 @@
package handler
import (
"net/http"
"reflect"
"fusenapi/utils/basic"
"fusenapi/server/info/internal/logic"
"fusenapi/server/info/internal/svc"
"fusenapi/server/info/internal/types"
)
func AddressDefaultHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.AddressIdRequest
userinfo, err := basic.RequestParse(w, r, svcCtx, &req)
if err != nil {
return
}
// 创建一个业务逻辑层实例
l := logic.NewAddressDefaultLogic(r.Context(), svcCtx)
rl := reflect.ValueOf(l)
basic.BeforeLogic(w, r, rl)
resp := l.AddressDefault(&req, userinfo)
if !basic.AfterLogic(w, r, rl, resp) {
basic.NormalAfterLogic(w, r, resp)
}
}
}

View File

@ -1,35 +0,0 @@
package handler
import (
"net/http"
"reflect"
"fusenapi/utils/basic"
"fusenapi/server/info/internal/logic"
"fusenapi/server/info/internal/svc"
"fusenapi/server/info/internal/types"
)
func AddressDeleteHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.AddressIdRequest
userinfo, err := basic.RequestParse(w, r, svcCtx, &req)
if err != nil {
return
}
// 创建一个业务逻辑层实例
l := logic.NewAddressDeleteLogic(r.Context(), svcCtx)
rl := reflect.ValueOf(l)
basic.BeforeLogic(w, r, rl)
resp := l.AddressDelete(&req, userinfo)
if !basic.AfterLogic(w, r, rl, resp) {
basic.NormalAfterLogic(w, r, resp)
}
}
}

View File

@ -1,35 +0,0 @@
package handler
import (
"net/http"
"reflect"
"fusenapi/utils/basic"
"fusenapi/server/info/internal/logic"
"fusenapi/server/info/internal/svc"
"fusenapi/server/info/internal/types"
)
func AddressListHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.Request
userinfo, err := basic.RequestParse(w, r, svcCtx, &req)
if err != nil {
return
}
// 创建一个业务逻辑层实例
l := logic.NewAddressListLogic(r.Context(), svcCtx)
rl := reflect.ValueOf(l)
basic.BeforeLogic(w, r, rl)
resp := l.AddressList(&req, userinfo)
if !basic.AfterLogic(w, r, rl, resp) {
basic.NormalAfterLogic(w, r, resp)
}
}
}

View File

@ -1,35 +0,0 @@
package handler
import (
"net/http"
"reflect"
"fusenapi/utils/basic"
"fusenapi/server/info/internal/logic"
"fusenapi/server/info/internal/svc"
"fusenapi/server/info/internal/types"
)
func AddressUpdateHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.AddressRequest
userinfo, err := basic.RequestParse(w, r, svcCtx, &req)
if err != nil {
return
}
// 创建一个业务逻辑层实例
l := logic.NewAddressUpdateLogic(r.Context(), svcCtx)
rl := reflect.ValueOf(l)
basic.BeforeLogic(w, r, rl)
resp := l.AddressUpdate(&req, userinfo)
if !basic.AfterLogic(w, r, rl, resp) {
basic.NormalAfterLogic(w, r, resp)
}
}
}

View File

@ -17,41 +17,6 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
Path: "/api/info/user",
Handler: InfoHandler(serverCtx),
},
{
Method: http.MethodPost,
Path: "/api/info/user/profile",
Handler: UserGetProfileHandler(serverCtx),
},
{
Method: http.MethodPost,
Path: "/api/info/user/profile/base/update",
Handler: UpdateProfileBaseHandler(serverCtx),
},
{
Method: http.MethodPost,
Path: "/api/info/address/default",
Handler: AddressDefaultHandler(serverCtx),
},
{
Method: http.MethodPost,
Path: "/api/info/address/add",
Handler: AddressAddHandler(serverCtx),
},
{
Method: http.MethodPost,
Path: "/api/info/address/update",
Handler: AddressUpdateHandler(serverCtx),
},
{
Method: http.MethodPost,
Path: "/api/info/address/delete",
Handler: AddressDeleteHandler(serverCtx),
},
{
Method: http.MethodGet,
Path: "/api/info/address/list",
Handler: AddressListHandler(serverCtx),
},
},
)
}

View File

@ -1,35 +0,0 @@
package handler
import (
"net/http"
"reflect"
"fusenapi/utils/basic"
"fusenapi/server/info/internal/logic"
"fusenapi/server/info/internal/svc"
"fusenapi/server/info/internal/types"
)
func UpdateProfileBaseHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.ProfileBaseRequest
userinfo, err := basic.RequestParse(w, r, svcCtx, &req)
if err != nil {
return
}
// 创建一个业务逻辑层实例
l := logic.NewUpdateProfileBaseLogic(r.Context(), svcCtx)
rl := reflect.ValueOf(l)
basic.BeforeLogic(w, r, rl)
resp := l.UpdateProfileBase(&req, userinfo)
if !basic.AfterLogic(w, r, rl, resp) {
basic.NormalAfterLogic(w, r, resp)
}
}
}

View File

@ -1,35 +0,0 @@
package handler
import (
"net/http"
"reflect"
"fusenapi/utils/basic"
"fusenapi/server/info/internal/logic"
"fusenapi/server/info/internal/svc"
"fusenapi/server/info/internal/types"
)
func UserGetProfileHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.QueryProfileRequest
userinfo, err := basic.RequestParse(w, r, svcCtx, &req)
if err != nil {
return
}
// 创建一个业务逻辑层实例
l := logic.NewUserGetProfileLogic(r.Context(), svcCtx)
rl := reflect.ValueOf(l)
basic.BeforeLogic(w, r, rl)
resp := l.UserGetProfile(&req, userinfo)
if !basic.AfterLogic(w, r, rl, resp) {
basic.NormalAfterLogic(w, r, resp)
}
}
}

View File

@ -1,93 +0,0 @@
package logic
import (
"fusenapi/model/gmodel"
"fusenapi/utils/auth"
"fusenapi/utils/basic"
"context"
"fusenapi/server/info/internal/svc"
"fusenapi/server/info/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type AddressAddLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewAddressAddLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AddressAddLogic {
return &AddressAddLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
// 处理进入前逻辑w,r
// func (l *AddressAddLogic) BeforeLogic(w http.ResponseWriter, r *http.Request) {
// }
func (l *AddressAddLogic) AddressAdd(req *types.AddressRequest, userinfo *auth.UserInfo) (resp *basic.Response) {
// 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data)
// userinfo 传入值时, 一定不为null
if !userinfo.IsUser() {
return resp.SetStatus(basic.CodeUnAuth)
}
// 确认这个IsDefault的值范围
if !auth.CheckValueRange(req.IsDefault, 0, 1) {
return resp.SetStatus(basic.CodeSafeValueRangeErr) // IsDefault值超出范围, 返回安全值范围错误
}
m := l.svcCtx.AllModels.FsAddress // 创建地址模型
// 如果ID为0, 表示新增地址
var (
country string = "USA" // 国家默认为美国
isDefautl int64 = 1 // 默认地址为1
status int64 = 1 // 默认地址状态为1(正常)
)
createOne := &gmodel.FsAddress{ // 构建FsAddress结构体
AddressName: &req.AddressName,
FirstName: &req.FirstName,
LastName: &req.LastName,
Mobile: &req.Mobile,
Street: &req.Street,
Suite: &req.Suite,
City: &req.City,
State: &req.State,
Country: &country,
Status: &status,
UserId: &userinfo.UserId,
ZipCode: &req.ZipCode,
IsDefault: &isDefautl,
}
_, err := m.CreateOne(l.ctx, createOne) // 新增地址
if err != nil {
logx.Error(err) // 日志记录错误
return resp.SetStatus(basic.CodeDbCreateErr) // 返回数据库创建错误
}
addresses, err := m.GetUserAllAddress(l.ctx, userinfo.UserId)
if err != nil {
logx.Error(err)
return resp.SetStatus(basic.CodeDbSqlErr) // 返回数据库创建错误
}
return resp.SetStatus(basic.CodeOK, map[string]any{
"address_list": addresses,
}) // 返回成功并返回地址ID
}
// 处理逻辑后 w,r 如:重定向, resp 必须重新处理
// func (l *AddressAddLogic) AfterLogic(w http.ResponseWriter, r *http.Request, resp *basic.Response) {
// // httpx.OkJsonCtx(r.Context(), w, resp)
// }

View File

@ -1,52 +0,0 @@
package logic
import (
"fusenapi/utils/auth"
"fusenapi/utils/basic"
"context"
"fusenapi/server/info/internal/svc"
"fusenapi/server/info/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type AddressDefaultLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewAddressDefaultLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AddressDefaultLogic {
return &AddressDefaultLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
// 处理进入前逻辑w,r
// func (l *AddressDefaultLogic) BeforeLogic(w http.ResponseWriter, r *http.Request) {
// }
func (l *AddressDefaultLogic) AddressDefault(req *types.AddressIdRequest, userinfo *auth.UserInfo) (resp *basic.Response) {
// 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data)
// userinfo 传入值时, 一定不为null
if !userinfo.IsUser() {
return resp.SetStatus(basic.CodeUnAuth)
}
err := l.svcCtx.AllModels.FsAddress.SettingUserDefaultAddress(l.ctx, userinfo.UserId, req.AddressId)
if err != nil {
return resp.SetStatusWithMessage(basic.CodeApiErr, err.Error())
}
return resp.SetStatus(basic.CodeOK)
}
// 处理逻辑后 w,r 如:重定向, resp 必须重新处理
// func (l *AddressDefaultLogic) AfterLogic(w http.ResponseWriter, r *http.Request, resp *basic.Response) {
// // httpx.OkJsonCtx(r.Context(), w, resp)
// }

View File

@ -1,52 +0,0 @@
package logic
import (
"fusenapi/utils/auth"
"fusenapi/utils/basic"
"context"
"fusenapi/server/info/internal/svc"
"fusenapi/server/info/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type AddressDeleteLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewAddressDeleteLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AddressDeleteLogic {
return &AddressDeleteLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
// 处理进入前逻辑w,r
// func (l *AddressDeleteLogic) BeforeLogic(w http.ResponseWriter, r *http.Request) {
// }
func (l *AddressDeleteLogic) AddressDelete(req *types.AddressIdRequest, userinfo *auth.UserInfo) (resp *basic.Response) {
// 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data)
// userinfo 传入值时, 一定不为null
if !userinfo.IsUser() {
return resp.SetStatus(basic.CodeUnAuth)
}
err := l.svcCtx.AllModels.FsAddress.DeleteOne(l.ctx, req.AddressId, userinfo.UserId)
if err != nil {
return resp.SetStatusWithMessage(basic.CodeApiErr, err.Error())
}
return resp.SetStatus(basic.CodeOK)
}
// 处理逻辑后 w,r 如:重定向, resp 必须重新处理
// func (l *AddressDeleteLogic) AfterLogic(w http.ResponseWriter, r *http.Request, resp *basic.Response) {
// // httpx.OkJsonCtx(r.Context(), w, resp)
// }

View File

@ -1,56 +0,0 @@
package logic
import (
"fusenapi/utils/auth"
"fusenapi/utils/basic"
"context"
"fusenapi/server/info/internal/svc"
"fusenapi/server/info/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type AddressListLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewAddressListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AddressListLogic {
return &AddressListLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
// 处理进入前逻辑w,r
// func (l *AddressListLogic) BeforeLogic(w http.ResponseWriter, r *http.Request) {
// }
func (l *AddressListLogic) AddressList(req *types.Request, userinfo *auth.UserInfo) (resp *basic.Response) {
// 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data)
// userinfo 传入值时, 一定不为null
if !userinfo.IsUser() {
return resp.SetStatus(basic.CodeUnAuth)
}
m := l.svcCtx.AllModels.FsAddress // 创建地址模型
result, err := m.GetUserAllAddress(l.ctx, userinfo.UserId)
if err != nil {
logx.Error(err) // 日志记录错误
return resp.SetStatusWithMessage(basic.CodeDbSqlErr, err.Error()) // 返回数据库创建错误
}
return resp.SetStatus(basic.CodeOK, map[string]any{
"address_list": result,
})
}
// 处理逻辑后 w,r 如:重定向, resp 必须重新处理
// func (l *AddressListLogic) AfterLogic(w http.ResponseWriter, r *http.Request, resp *basic.Response) {
// // httpx.OkJsonCtx(r.Context(), w, resp)
// }

View File

@ -1,76 +0,0 @@
package logic
import (
"fusenapi/model/gmodel"
"fusenapi/utils/auth"
"fusenapi/utils/basic"
"time"
"context"
"fusenapi/server/info/internal/svc"
"fusenapi/server/info/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type AddressUpdateLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewAddressUpdateLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AddressUpdateLogic {
return &AddressUpdateLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
// 处理进入前逻辑w,r
// func (l *AddressUpdateLogic) BeforeLogic(w http.ResponseWriter, r *http.Request) {
// }
func (l *AddressUpdateLogic) AddressUpdate(req *types.AddressRequest, userinfo *auth.UserInfo) (resp *basic.Response) {
// 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data)
// userinfo 传入值时, 一定不为null
if !userinfo.IsUser() {
return resp.SetStatus(basic.CodeUnAuth)
}
now := time.Now().UTC()
if req.AddressId == 0 {
return resp.SetStatusWithMessage(basic.CodeApiErr, "address_id must setting")
}
address := gmodel.FsAddress{
AddressId: req.AddressId,
UserId: &userinfo.UserId,
IsDefault: &req.IsDefault,
AddressName: &req.AddressName,
FirstName: &req.FirstName,
LastName: &req.LastName,
Mobile: &req.Mobile,
ZipCode: &req.ZipCode,
Street: &req.Street,
Suite: &req.Suite,
City: &req.City,
State: &req.State,
Utime: &now,
}
err := l.svcCtx.AllModels.FsAddress.UpdateAddress(l.ctx, &address)
if err != nil {
return resp.SetStatusWithMessage(basic.CodeApiErr, err.Error())
}
return resp.SetStatus(basic.CodeOK)
}
// 处理逻辑后 w,r 如:重定向, resp 必须重新处理
// func (l *AddressUpdateLogic) AfterLogic(w http.ResponseWriter, r *http.Request, resp *basic.Response) {
// // httpx.OkJsonCtx(r.Context(), w, resp)
// }

View File

@ -39,7 +39,6 @@ func NewInfoLogic(ctx context.Context, svcCtx *svc.ServiceContext) *InfoLogic {
var ModuleTable map[string]string = map[string]string{
"userinfo": "fs_user_info",
"material": "fs_user_material",
"address": "fs_address", // TODO: 地址列表
}
type ModuleQuery struct {
@ -83,38 +82,6 @@ func (mquery *ModuleQuery) EncodeEmpty() map[string]any {
return qstr
}
func QueryDefault(conn *gorm.DB, module string, moduleQuery string, tname string) map[string]any {
qname := strings.Split(moduleQuery, ".")
queryAsName := qname[len(qname)-1]
sqlstr := fmt.Sprintf(
"select JSON_EXTRACT(metadata,'$.%s') as %s from %s where module = '%s' and user_id = 0 and guest_id = 0 order by ctime DESC limit 1",
moduleQuery, // logo_selected
queryAsName, // logo_selected
tname, // fs_user_info
module, // profile
)
raw := conn.Raw(sqlstr)
var info map[string]any
err := raw.Scan(&info).Error
if err == gorm.ErrRecordNotFound {
logx.Error(err)
}
if v, ok := info[queryAsName]; ok {
var qinfo map[string]any
err := json.Unmarshal([]byte(v.(string)), &qinfo)
if err != nil {
logx.Error(err)
} else {
info[queryAsName] = qinfo
}
}
return info
}
func (l *InfoLogic) Info(req *types.UserInfoRequest, userinfo *auth.UserInfo) (resp *basic.Response) {
// 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data)
// userinfo 传入值时, 一定不为null
@ -211,70 +178,9 @@ func (l *InfoLogic) Info(req *types.UserInfoRequest, userinfo *auth.UserInfo) (r
}
}
// 隐含白板用户逻辑
if v, ok := metadict["userinfo.profile"]; ok {
if v == nil {
info := QueryDefault(l.svcCtx.MysqlConn, "profile", "logo_selected", "fs_user_info")
metadict["userinfo.profile"] = info
} else {
profileDict := v.(map[string]any)
if _, ok := profileDict["logo_selected"]; !ok {
info := QueryDefault(l.svcCtx.MysqlConn, "profile", "logo_selected", "fs_user_info")
profileDict["logo_selected"] = info["logo_selected"]
}
}
} else if v, ok := metadict["userinfo.profile.logo_selected"]; ok {
if v == nil {
info := QueryDefault(l.svcCtx.MysqlConn, "profile", "logo_selected", "fs_user_info")
metadict["userinfo.profile.logo_selected"] = info
}
} else {
var info map[string]any
for k, v := range metadict {
if v == nil {
if strings.HasPrefix(k, "userinfo.profile.logo_selected") {
if info == nil {
info = QueryDefault(l.svcCtx.MysqlConn, "profile", "logo_selected", "fs_user_info")
}
curValue, err := GetMapValueByKey(info, strings.Split(k, ".")[2:])
if err != nil {
logx.Error(err, info)
continue
// return resp.SetStatus(basic.CodeOK, metadict)
}
metadict[k] = curValue
// curValue
}
}
}
}
return resp.SetStatus(basic.CodeOK, metadict)
}
func GetMapValueByKey(info map[string]interface{}, keys []string) (interface{}, error) {
// keys := strings.Split(key, ".")[2:]
for _, k := range keys {
if cur, ok := info[k]; ok {
if curMap, ok := cur.(map[string]interface{}); ok {
info = curMap
} else {
// logx.Error(cur)
return cur, nil
}
} else {
return nil, fmt.Errorf("info keys is not exists %#v", keys)
}
}
return info, nil
}
// 处理逻辑后 w,r 如:重定向, resp 必须重新处理
// func (l *InfoLogic) AfterLogic(w http.ResponseWriter, r *http.Request, resp *basic.Response) {
// // httpx.OkJsonCtx(r.Context(), w, resp)

View File

@ -6,7 +6,6 @@ import (
"fusenapi/initalize"
"fusenapi/model/gmodel"
"fusenapi/utils/check"
"fusenapi/utils/fssql"
"log"
"strings"
"testing"
@ -118,47 +117,57 @@ func TestMain(t *testing.T) {
if v == nil {
info := QueryDefault(conn, "profile", "logo_selected", "fs_user_info")
log.Println(info)
metadict["userinfo.profile"] = info
// log.Println(metadict)
} else {
profileDict := v.(map[string]any)
if _, ok := profileDict["logo_selected"]; !ok {
info := QueryDefault(conn, "profile", "logo_selected", "fs_user_info")
profileDict["logo_selected"] = info["logo_selected"]
}
}
} else if v, ok := metadict["userinfo.profile.logo_selected"]; ok {
if v == nil {
info := QueryDefault(conn, "profile", "logo_selected", "fs_user_info")
metadict["userinfo.profile.logo_selected"] = info
}
} else {
var info map[string]any
for k, v := range metadict {
if v == nil {
if strings.HasPrefix(k, "userinfo.profile.logo_selected") {
if info == nil {
info = QueryDefault(conn, "profile", "logo_selected", "fs_user_info")
}
curValue, err := GetMapValueByKey(info, strings.Split(k, ".")[2:])
if err != nil {
logx.Error(err, info)
continue
// return resp.SetStatus(basic.CodeOK, metadict)
}
metadict[k] = curValue
// curValue
}
}
}
}
log.Println(metadict)
return
}
func QueryDefault(conn *gorm.DB, module string, moduleQuery string, tname string) map[string]any {
qname := strings.Split(moduleQuery, ".")
queryAsName := qname[len(qname)-1]
sqlstr := fmt.Sprintf(
"select JSON_EXTRACT(metadata,'$.%s') as %s from %s where module = '%s' and user_id = 0 and guest_id = 0 order by ctime DESC limit 1",
moduleQuery, // logo_selected
queryAsName, // logo_selected
tname, // fs_user_info
module, // profile
)
raw := conn.Raw(sqlstr)
var info map[string]any
err := raw.Scan(&info).Error
if err == gorm.ErrRecordNotFound {
logx.Error(err)
}
return info
}
func TestCaseJSON_EXTRACT(t *testing.T) {
userProfile := &gmodel.UserProfile{}
userProfile := &gmodel.UserProfile{
FirstName: "FirstName",
LastName: "LastName",
Resetaurant: "Resetaurant",
}
metadata, err := json.Marshal(userProfile)
if err != nil {
panic(err)
@ -176,14 +185,6 @@ func TestCaseJSON_EXTRACT(t *testing.T) {
conn := initalize.InitMysql("fsreaderwriter:XErSYmLELKMnf3Dh@tcp(fusen.cdmigcvz3rle.us-east-2.rds.amazonaws.com:3306)/fusen")
// err = conn.Exec(updatesql, 6).Error
info := gmodel.UserProfileBase{}
var baseinfo map[string]any
tname := fssql.GetGormTableName(conn, gmodel.FsUserInfo{})
rawsql := fmt.Sprintf("select JSON_EXTRACT(metadata,'$.base') as base from %s where user_id = ? and module = ? order by ctime DESC limit 1", tname)
tx := conn.Raw(rawsql, 162, "profile").Take(&baseinfo)
log.Println(tx.Error)
json.Unmarshal([]byte(baseinfo["base"].(string)), &info)
log.Println(conn.Model(&gmodel.FsChangeCode{}).Select("id").Where("id = 5").Take(nil).Error)
log.Println(err)
}

View File

@ -1,52 +0,0 @@
package logic
import (
"fusenapi/utils/auth"
"fusenapi/utils/basic"
"context"
"fusenapi/server/info/internal/svc"
"fusenapi/server/info/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type UpdateProfileBaseLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewUpdateProfileBaseLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UpdateProfileBaseLogic {
return &UpdateProfileBaseLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
// 处理进入前逻辑w,r
// func (l *UpdateProfileBaseLogic) BeforeLogic(w http.ResponseWriter, r *http.Request) {
// }
func (l *UpdateProfileBaseLogic) UpdateProfileBase(req *types.ProfileBaseRequest, userinfo *auth.UserInfo) (resp *basic.Response) {
// 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data)
// userinfo 传入值时, 一定不为null
if !userinfo.IsUser() {
return resp.SetStatus(basic.CodeUnAuth)
}
err := l.svcCtx.AllModels.FsUserInfo.MergeMetadata(userinfo.UserId, req)
if err != nil {
logx.Error(err) // 日志记录错误
return resp.SetStatus(basic.CodeDbSqlErr, err.Error()) // 返回数据库创建错误
}
return resp.SetStatus(basic.CodeOK)
}
// 处理逻辑后 w,r 如:重定向, resp 必须重新处理
// func (l *UpdateProfileBaseLogic) AfterLogic(w http.ResponseWriter, r *http.Request, resp *basic.Response) {
// // httpx.OkJsonCtx(r.Context(), w, resp)
// }

View File

@ -1,52 +0,0 @@
package logic
import (
"fusenapi/utils/auth"
"fusenapi/utils/basic"
"context"
"fusenapi/server/info/internal/svc"
"fusenapi/server/info/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type UserGetProfileLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewUserGetProfileLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UserGetProfileLogic {
return &UserGetProfileLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
// 处理进入前逻辑w,r
// func (l *UserGetProfileLogic) BeforeLogic(w http.ResponseWriter, r *http.Request) {
// }
func (l *UserGetProfileLogic) UserGetProfile(req *types.QueryProfileRequest, userinfo *auth.UserInfo) (resp *basic.Response) {
// 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data)
// userinfo 传入值时, 一定不为null
if !userinfo.IsUser() {
return resp.SetStatus(basic.CodeUnAuth)
}
profileBase, err := l.svcCtx.AllModels.FsUserInfo.GetProfile(l.ctx, req.TopKey, userinfo.UserId)
if err != nil {
return resp.SetStatusWithMessage(basic.CodeApiErr, err.Error())
}
return resp.SetStatus(basic.CodeOK, profileBase)
}
// 处理逻辑后 w,r 如:重定向, resp 必须重新处理
// func (l *UserGetProfileLogic) AfterLogic(w http.ResponseWriter, r *http.Request, resp *basic.Response) {
// // httpx.OkJsonCtx(r.Context(), w, resp)
// }

View File

@ -9,46 +9,6 @@ type UserInfoRequest struct {
Module []string `json:"module"`
}
type AddressObjectRequest struct {
AddressId int64 `json:"address_id"` // 地址id
AddressName string `json:"address_name"` // 地址
}
type AddressIdRequest struct {
AddressId int64 `json:"address_id"` // 地址id
}
type AddressNameRequest struct {
AddressName string `json:"address_name"` // 地址
}
type AddressRequest struct {
AddressId int64 `json:"address_id,optional"`
IsDefault int64 `json:"is_default"` //是否默认
AddressName string `json:"address_name"` //收货人
FirstName string `json:"first_name"` //first_name
LastName string `json:"last_name"` //last_name
Mobile string `json:"mobile"` //手机
ZipCode string `json:"zip_code"` //邮编
Street string `json:"street"` //街道
Suite string `json:"suite"` //房号
City string `json:"city"` //城市
State string `json:"state"` //州
}
type ProfileBaseRequest struct {
FirstName *string `json:"first_name,optional,omitempty"` // 首名
LastName *string `json:"last_name,optional,omitempty"` // 后名
UserName *string `json:"user_name,optional,omitempty"` // 用户名
Mobile *string `json:"mobile,optional,omitempty"` // 电话
Resetaurant *string `json:"resetaurant,optional,omitempty"` // 不知道干什么
Company *string `json:"company,optional,omitempty"` // 公司
}
type QueryProfileRequest struct {
TopKey string `json:"top_key"` // 首名
}
type Request struct {
}
@ -72,10 +32,10 @@ type File struct {
}
type Meta struct {
TotalCount int64 `json:"total_count"`
PageCount int64 `json:"page_count"`
CurrentPage int `json:"current_page"`
PerPage int `json:"per_page"`
TotalCount int64 `json:"totalCount"`
PageCount int64 `json:"pageCount"`
CurrentPage int `json:"currentPage"`
PerPage int `json:"perPage"`
}
// Set 设置Response的Code和Message值

View File

@ -3,7 +3,7 @@ Host: 0.0.0.0
Port: 9907
Timeout: 15000 #服务超时时间(毫秒)
SourceMysql: fsreaderwriter:XErSYmLELKMnf3Dh@tcp(fusen.cdmigcvz3rle.us-east-2.rds.amazonaws.com:3306)/fusen
SourceRabbitMq: 213
SourceRabbitMq:
Log:
Stat: false
Auth:

View File

@ -47,7 +47,7 @@ func (l *CreateOrderLogic) CreateOrder(req *types.CreateOrderReq, userinfo *auth
OriginalCurrency: string(constants.CURRENCYUSD),
UserId: userinfo.UserId,
CartIds: req.CartIds,
DeliveryMethod: constants.DELIVERYMETHODDSCLOUDSTORE,
DeliveryMethod: req.DeliveryMethod,
})
if err != nil {

View File

@ -1,7 +1,6 @@
package logic
import (
"fusenapi/service/repositories"
"fusenapi/utils/auth"
"fusenapi/utils/basic"
@ -39,22 +38,7 @@ func (l *CreatePrePaymentByBalanceLogic) CreatePrePaymentByBalance(req *types.Cr
return resp.SetStatus(basic.CodeUnAuth)
}
res, err := l.svcCtx.Repositories.NewOrder.CreatePrePaymentByBalance(l.ctx, &repositories.CreatePrePaymentByBalanceReq{
UserId: userinfo.UserId,
OrderSn: req.OrderSn,
Country: "US",
Currency: "usd",
StripeKey: l.svcCtx.Config.PayConfig.Stripe.Key,
})
if err != nil {
return resp.SetStatus(&res.ErrorCode)
}
return resp.SetStatus(basic.CodeOK, map[string]interface{}{
"order_detail": res.OrderDetail,
"order_pay": res.OrderPay,
})
return resp.SetStatus(basic.CodeOK)
}
// 处理逻辑后 w,r 如:重定向, resp 必须重新处理

View File

@ -10,7 +10,8 @@ type OrderDetailReq struct {
}
type CreateOrderReq struct {
CartIds []int64 `json:"cart_ids"`
CartIds []int64 `json:"cart_ids"`
DeliveryMethod int64 `json:"delivery_method,options=[1,2]"`
}
type CreatePrePaymentByDepositReq struct {

View File

@ -6,27 +6,27 @@ import (
"fusenapi/utils/basic"
"fusenapi/server/info/internal/logic"
"fusenapi/server/info/internal/svc"
"fusenapi/server/info/internal/types"
"fusenapi/server/pay/internal/logic"
"fusenapi/server/pay/internal/svc"
"fusenapi/server/pay/internal/types"
)
func AddressAddHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
func OrderPaymentIntentHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.AddressRequest
var req types.OrderPaymentIntentReq
userinfo, err := basic.RequestParse(w, r, svcCtx, &req)
if err != nil {
return
}
// 创建一个业务逻辑层实例
l := logic.NewAddressAddLogic(r.Context(), svcCtx)
l := logic.NewOrderPaymentIntentLogic(r.Context(), svcCtx)
rl := reflect.ValueOf(l)
basic.BeforeLogic(w, r, rl)
resp := l.AddressAdd(&req, userinfo)
resp := l.OrderPaymentIntent(&req, userinfo)
if !basic.AfterLogic(w, r, rl, resp) {
basic.NormalAfterLogic(w, r, resp)

View File

@ -12,6 +12,11 @@ import (
func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
server.AddRoutes(
[]rest.Route{
{
Method: http.MethodPost,
Path: "/api/pay/payment-intent",
Handler: OrderPaymentIntentHandler(serverCtx),
},
{
Method: http.MethodPost,
Path: "/api/pay/refund",

View File

@ -0,0 +1,181 @@
package logic
import (
"fusenapi/utils/auth"
"fusenapi/utils/basic"
"context"
"fusenapi/server/pay/internal/svc"
"fusenapi/server/pay/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type OrderPaymentIntentLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewOrderPaymentIntentLogic(ctx context.Context, svcCtx *svc.ServiceContext) *OrderPaymentIntentLogic {
return &OrderPaymentIntentLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
// 处理进入前逻辑w,r
// func (l *OrderPaymentIntentLogic) BeforeLogic(w http.ResponseWriter, r *http.Request) {
// }
// 处理逻辑后 w,r 如:重定向, resp 必须重新处理
// func (l *OrderPaymentIntentLogic) AfterLogic(w http.ResponseWriter, r *http.Request, resp *basic.Response) {
// // httpx.OkJsonCtx(r.Context(), w, resp)
// }
func (l *OrderPaymentIntentLogic) OrderPaymentIntent(req *types.OrderPaymentIntentReq, userinfo *auth.UserInfo) (resp *basic.Response) {
// 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data)
// userinfo 传入值时, 一定不为null
// if userinfo == nil || userinfo.UserId == 0 {
// return resp.SetStatusWithMessage(basic.CodeDbRecordNotFoundErr, "order not found")
// }
// // 查询订单数据
// orderModel := gmodel.NewFsOrderModel(l.svcCtx.MysqlConn)
// orderInfo, err := orderModel.FindOneBySn(l.ctx, userinfo.UserId, req.Sn)
// if err != nil {
// if errors.Is(err, gorm.ErrRecordNotFound) {
// return resp.SetStatusWithMessage(basic.CodeDbRecordNotFoundErr, "order not found")
// }
// logx.Error(err)
// return resp.SetStatusWithMessage(basic.CodeServiceErr, "failed to get order info")
// }
// // 校验订单状态
// if *orderInfo.IsCancel == 1 {
// return resp.SetStatusWithMessage(basic.CodeServiceErr, "order cancelled")
// }
// // 校验地址信息
// addressModel := gmodel.NewFsAddressModel(l.svcCtx.MysqlConn)
// _, err = addressModel.GetOne(l.ctx, req.AddressId, userinfo.UserId)
// if err != nil {
// if errors.Is(err, gorm.ErrRecordNotFound) {
// return resp.SetStatusWithMessage(basic.CodeDbRecordNotFoundErr, "address not found")
// }
// logx.Error(err)
// return resp.SetStatusWithMessage(basic.CodeServiceErr, "failed to get address info")
// }
// // 校验订单支付信息
// if *orderInfo.IsPayCompleted == 1 {
// return resp.SetStatusWithMessage(basic.CodeServiceErr, "order is pay completed")
// }
// // 判断订单状态以及该支付金额
// var nowAt int64 = time.Now().UTC().Unix()
// var payAmount int64
// if *orderInfo.Status == int64(constants.STATUS_NEW_NOT_PAY) {
// payAmount = *orderInfo.TotalAmount / 2
// *orderInfo.DeliveryMethod = req.DeliveryMethod
// *orderInfo.AddressId = req.AddressId
// *orderInfo.PayMethod = req.PayMethod
// } else {
// payAmount = *orderInfo.TotalAmount - *orderInfo.TotalAmount/2
// }
// payConfig := &pay.Config{}
// var generatePrepaymentReq = &pay.GeneratePrepaymentReq{
// OrderSn: req.Sn,
// ProductName: "支付标题",
// Amount: payAmount,
// Currency: "eur",
// Quantity: 1,
// ProductDescription: "支付描述",
// }
// var resData types.OrderPaymentIntentRes
// // 事务处理
// ctx := l.ctx
// err = l.svcCtx.MysqlConn.Transaction(func(connGorm *gorm.DB) error {
// // 支付记录--处理 //支付记录改为一条订单多条,分首款尾款
// var payStatus int64 = 0
// var orderSource int64 = 1
// var payStage int64
// var fspay *gmodel.FsPay
// newFsPayModel := gmodel.NewFsPayModel(connGorm)
// if *orderInfo.Status == int64(constants.STATUS_NEW_NOT_PAY) {
// fspay, err = newFsPayModel.RBGetListByOrderNumberStage(ctx, *orderInfo.Sn, 1)
// if err != nil {
// if !errors.Is(err, gorm.ErrRecordNotFound) {
// return err
// }
// }
// payStage = 1
// } else {
// fspay, err = newFsPayModel.RBGetListByOrderNumberStage(ctx, *orderInfo.Sn, 2)
// if err != nil {
// if !errors.Is(err, gorm.ErrRecordNotFound) {
// return err
// }
// }
// payStage = 2
// }
// // 支付预付--生成
// if constants.PayMethod(req.PayMethod) == constants.PAYMETHOD_STRIPE {
// payConfig.Stripe.Key = l.svcCtx.Config.PayConfig.Stripe.Key
// generatePrepaymentReq.SuccessURL = l.svcCtx.Config.PayConfig.Stripe.SuccessURL
// generatePrepaymentReq.CancelURL = l.svcCtx.Config.PayConfig.Stripe.CancelURL
// }
// payDriver := pay.NewPayDriver(req.PayMethod, payConfig)
// prepaymentRes, err := payDriver.GeneratePrepayment(generatePrepaymentReq)
// if err != nil {
// return err
// }
// // 订单信息--修改
// err = gmodel.NewFsOrderModel(connGorm).RBUpdate(ctx, orderInfo)
// if err != nil {
// return err
// }
// if fspay == nil {
// fspay = &gmodel.FsPay{
// UserId: orderInfo.UserId,
// OrderNumber: orderInfo.Sn,
// CreatedAt: &nowAt,
// }
// } else {
// fspay.UpdatedAt = &nowAt
// }
// fspay.PayAmount = &payAmount
// fspay.PayStage = &payStage
// //fspay.TradeNo = &prepaymentRes.TradeNo
// fspay.PaymentMethod = &req.PayMethod
// fspay.OrderSource = &orderSource
// fspay.PayStatus = &payStatus
// _, err = newFsPayModel.RBCreateOrUpdate(ctx, fspay)
// if err != nil {
// return err
// }
// resData.RedirectUrl = prepaymentRes.URL
// resData.ClientSecret = prepaymentRes.ClientSecret
// return nil
// })
// if err != nil {
// logx.Error(err)
// return resp.SetStatusWithMessage(basic.CodeServiceErr, "failed to make payment")
// }
return resp.SetStatusWithMessage(basic.CodeOK, "success")
}

View File

@ -1,24 +1,16 @@
package logic
import (
"encoding/json"
"errors"
"fmt"
"fusenapi/constants"
"fusenapi/model/gmodel"
"fusenapi/service/repositories"
"fusenapi/utils/auth"
"fusenapi/utils/basic"
"time"
"context"
"fusenapi/server/pay/internal/svc"
"fusenapi/server/pay/internal/types"
"github.com/stripe/stripe-go/v75"
"github.com/stripe/stripe-go/v75/webhook"
"github.com/zeromicro/go-zero/core/logc"
"github.com/stripe/stripe-go/v74"
"github.com/zeromicro/go-zero/core/logx"
)
@ -50,116 +42,110 @@ func (l *StripeWebhookLogic) StripeWebhook(req *types.StripeWebhookReq, userinfo
// 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data)
// userinfo 传入值时, 一定不为null
stripe.Key = l.svcCtx.Config.PayConfig.Stripe.Key
event := stripe.Event{}
// stripe.Key = l.svcCtx.Config.PayConfig.Stripe.Key
// event := stripe.Event{}
if err := json.Unmarshal(req.Payload, &event); err != nil {
logc.Errorf(l.ctx, "StripeWebhookLogic StripeWebhook Unmarshal err:%v", err)
return resp.SetStatusWithMessage(basic.CodeAesCbcDecryptionErr, "pay notify Unmarshal fail")
}
// fmt.Println(req)
// fmt.Println(event)
// if err := json.Unmarshal(req.Payload, &event); err != nil {
// logx.Error(err)
// return resp.SetStatusWithMessage(basic.CodeAesCbcDecryptionErr, "pay notify Unmarshal fail")
// }
endpointSecret := l.svcCtx.Config.PayConfig.Stripe.EndpointSecret
signatureHeader := req.StripeSignature
fmt.Println(endpointSecret)
event, err := webhook.ConstructEvent(req.Payload, signatureHeader, endpointSecret)
if err != nil {
logc.Errorf(l.ctx, "webhook.ConstructEvent err:%v", err)
return resp.SetStatusWithMessage(basic.CodeAesCbcDecryptionErr, "Webhook signature verification failed")
}
// endpointSecret := l.svcCtx.Config.PayConfig.Stripe.EndpointSecret
// signatureHeader := req.StripeSignature
// event, err := webhook.ConstructEvent(req.Payload, signatureHeader, endpointSecret)
// if err != nil {
// logx.Error(err)
// return resp.SetStatusWithMessage(basic.CodeAesCbcDecryptionErr, "Webhook signature verification failed")
// }
// 支付回调事件日志
var payMethod = int64(constants.PAYMETHOD_STRIPE)
var nowTime = time.Now().UTC()
var eventData = []byte(event.Data.Raw)
eventType := string(event.Type)
l.HandlePayEventCreate(&gmodel.FsOrderTradeEvent{
PayMethod: &payMethod,
EventId: &event.ID,
EventType: &eventType,
EventData: &eventData,
Ctime: &nowTime,
})
// // 新增支付回调事件日志
// var payMethod = int64(constants.PAYMETHOD_STRIPE)
// var nowTime = time.Now().UTC().Unix()
// var eventData = string(event.Data.Raw)
// var fsPayEvent = &gmodel.FsPayEvent{
// PayMethod: &payMethod,
// EventId: &event.ID,
// EventType: &event.Type,
// EventData: &eventData,
// EventCreated: &event.Created,
// Ip: &req.RemoteAddr,
// CreatedAt: &nowTime,
// }
// l.HandlePayEventCreate(fsPayEvent)
// Unmarshal the event data into an appropriate struct depending on its Type
fmt.Println("事件类型", event.Type)
switch event.Type {
case "charge.succeeded":
var charge stripe.Charge
err := json.Unmarshal(event.Data.Raw, &charge)
if err != nil {
logx.Errorf("err%+vdesc%s", err, "pay notify Unmarshal fail event.Type charge.succeeded")
return resp.SetStatusWithMessage(basic.CodeAesCbcDecryptionErr, "pay notify Unmarshal fail event.Type charge.succeeded")
}
err = l.HandleChargeSucceeded(&charge, event.ID)
if err != nil {
logx.Errorf("err%+vdesc%s", err, "pay notify handle payment_intent.succeeded")
return resp.SetStatusWithMessage(basic.CodePaybackNotOk, "pay notify handle payment_intent.succeeded")
}
case "checkout.session.completed":
// checkout checkout.session.completed 处理逻辑
// var session stripe.CheckoutSession
// err := json.Unmarshal(event.Data.Raw, &session)
// if err != nil {
// logx.Error(err)
// return resp.SetStatusWithMessage(basic.CodeAesCbcDecryptionErr, "pay notify Unmarshal fail event.Type payment_intent.succeeded")
// }
// fmt.Println("checkout.session.completed")
// err = l.handlePaymentSessionCompleted(session.ID, session.PaymentIntent.ID)
// if err != nil {
// return resp.SetStatusWithMessage(basic.CodeAesCbcDecryptionErr, "checkout.session.completed fail")
// }
case "payment_intent.succeeded":
// var paymentIntent stripe.PaymentIntent
// err := json.Unmarshal(event.Data.Raw, &paymentIntent)
// if err != nil {
// logx.Errorf("err%+vdesc%s", err, "pay notify Unmarshal fail event.Type payment_intent.succeeded")
// return resp.SetStatusWithMessage(basic.CodeAesCbcDecryptionErr, "pay notify Unmarshal fail event.Type payment_intent.succeeded")
// }
// err = l.HandlePaymentIntentSucceeded(&paymentIntent, event.ID)
// if err != nil {
// logx.Errorf("err%+vdesc%s", err, "pay notify handle payment_intent.succeeded")
// return resp.SetStatusWithMessage(basic.CodePaybackNotOk, "pay notify handle payment_intent.succeeded")
// }
case "payment_method.attached":
// var paymentMethod stripe.PaymentMethod
// err := json.Unmarshal(event.Data.Raw, &paymentMethod)
// if err != nil {
// logx.Error(err)
// return resp.SetStatusWithMessage(basic.CodeAesCbcDecryptionErr, "pay notify Unmarshal fail event.Type payment_method.attached")
// }
case "charge.refunded":
var chargeRefunded stripe.Charge
err := json.Unmarshal(event.Data.Raw, &chargeRefunded)
if err != nil {
logx.Errorf("err%+vdesc%s", err, "pay notify Unmarshal fail event.Type charge.refunded")
return resp.SetStatusWithMessage(basic.CodeAesCbcDecryptionErr, "pay notify Unmarshal fail event.Type charge.refunded")
}
err = l.HandleChargeRefunded(&chargeRefunded)
if err != nil {
logx.Errorf("err%+vdesc%s", err, "pay notify handle charge.refunded")
return resp.SetStatusWithMessage(basic.CodeAesCbcDecryptionErr, "pay notify handle charge.refunded")
}
// // Unmarshal the event data into an appropriate struct depending on its Type
// switch event.Type {
// case "charge.succeeded":
// // var charge stripe.Charge
// // err := json.Unmarshal(event.Data.Raw, &charge)
// // if err != nil {
// // logx.Error(err)
// // return resp.SetStatusWithMessage(basic.CodeAesCbcDecryptionErr, "pay notify Unmarshal fail event.Type charge.succeeded")
// // }
// ... handle other event types
default:
logx.Error("Unhandled event")
return resp.SetStatusWithMessage(basic.CodeAesCbcDecryptionErr, "pay notify Unmarshal fail event.Type Unhandled")
}
// case "checkout.session.completed":
// // checkout checkout.session.completed 处理逻辑
// // var session stripe.CheckoutSession
// // err := json.Unmarshal(event.Data.Raw, &session)
// // if err != nil {
// // logx.Error(err)
// // return resp.SetStatusWithMessage(basic.CodeAesCbcDecryptionErr, "pay notify Unmarshal fail event.Type payment_intent.succeeded")
// // }
// // fmt.Println("checkout.session.completed")
// // err = l.handlePaymentSessionCompleted(session.ID, session.PaymentIntent.ID)
// // if err != nil {
// // return resp.SetStatusWithMessage(basic.CodeAesCbcDecryptionErr, "checkout.session.completed fail")
// // }
// case "payment_intent.succeeded":
// var paymentIntent stripe.PaymentIntent
// err := json.Unmarshal(event.Data.Raw, &paymentIntent)
// if err != nil {
// logx.Errorf("err%+vdesc%s", err, "pay notify Unmarshal fail event.Type payment_intent.succeeded")
// return resp.SetStatusWithMessage(basic.CodeAesCbcDecryptionErr, "pay notify Unmarshal fail event.Type payment_intent.succeeded")
// }
// err = l.HandlePaymentIntentSucceeded(&paymentIntent)
// if err != nil {
// logx.Errorf("err%+vdesc%s", err, "pay notify handle payment_intent.succeeded")
// return resp.SetStatusWithMessage(basic.CodePaybackNotOk, "pay notify handle payment_intent.succeeded")
// }
// case "payment_method.attached":
// var paymentMethod stripe.PaymentMethod
// err := json.Unmarshal(event.Data.Raw, &paymentMethod)
// if err != nil {
// logx.Error(err)
// return resp.SetStatusWithMessage(basic.CodeAesCbcDecryptionErr, "pay notify Unmarshal fail event.Type payment_method.attached")
// }
// case "charge.refunded":
// var chargeRefunded stripe.Charge
// err := json.Unmarshal(event.Data.Raw, &chargeRefunded)
// if err != nil {
// logx.Errorf("err%+vdesc%s", err, "pay notify Unmarshal fail event.Type charge.refunded")
// return resp.SetStatusWithMessage(basic.CodeAesCbcDecryptionErr, "pay notify Unmarshal fail event.Type charge.refunded")
// }
// err = l.HandleChargeRefunded(&chargeRefunded)
// if err != nil {
// logx.Errorf("err%+vdesc%s", err, "pay notify handle charge.refunded")
// return resp.SetStatusWithMessage(basic.CodeAesCbcDecryptionErr, "pay notify handle charge.refunded")
// }
// // ... handle other event types
// default:
// logx.Error("Unhandled event")
// return resp.SetStatusWithMessage(basic.CodeAesCbcDecryptionErr, "pay notify Unmarshal fail event.Type Unhandled")
// }
return resp.SetStatus(basic.CodeOK)
}
// 回调事件日志
func (l *StripeWebhookLogic) HandlePayEventCreate(fsPayEvent *gmodel.FsOrderTradeEvent) error {
result := l.svcCtx.MysqlConn.Create(fsPayEvent)
return result.Error
func (l *StripeWebhookLogic) HandlePayEventCreate(fsPayEvent *gmodel.FsPayEvent) error {
_, err := gmodel.NewFsPayEventModel(l.svcCtx.MysqlConn).CreateOrUpdate(l.ctx, fsPayEvent)
return err
}
// 退款成功
func (l *StripeWebhookLogic) HandleChargeRefunded(chargeRefunded *stripe.Charge) (err error) {
// 退款成功
// // 退款成功
// if chargeRefunded.Status == "succeeded" {
// ctx := l.ctx
// err = l.svcCtx.MysqlConn.Transaction(func(connGorm *gorm.DB) error {
@ -241,27 +227,162 @@ func (l *StripeWebhookLogic) HandleChargeRefunded(chargeRefunded *stripe.Charge)
// }
// 付款成功
func (l *StripeWebhookLogic) HandleChargeSucceeded(charge *stripe.Charge, eventId string) error {
// 支付成功
if charge.Status == "succeeded" {
model, ok := charge.Metadata["model"]
if !ok {
err := errors.New("model is empty")
logc.Errorf(l.ctx, "PaymentSuccessful failed param, eventId:%s,err:%v", eventId, err)
return err
}
switch model {
case "product_order":
res, err := l.svcCtx.Repositories.NewOrder.PaymentSuccessful(l.ctx, &repositories.PaymentSuccessfulReq{
EventId: eventId,
PaymentMethod: "stripe",
Charge: charge,
})
if err != nil {
return err
}
fmt.Println(res)
}
}
func (l *StripeWebhookLogic) HandlePaymentIntentSucceeded(paymentIntent *stripe.PaymentIntent) error {
// orderSn, ok := paymentIntent.Metadata["order_sn"]
// if !ok || orderSn == "" {
// return errors.New("order_sn not found")
// }
// // 查询支付记录
// payModel := gmodel.NewFsPayModel(l.svcCtx.MysqlConn)
// rsbPay := payModel.RowSelectBuilder(nil)
// rsbPay = rsbPay.Where("order_number = ?", orderSn).Where("pay_status = ?", constants.PAYSTATUS_UNSUCCESS)
// payInfo, err := payModel.FindOneByQuery(l.ctx, rsbPay, nil)
// if err != nil {
// return err
// }
// //订单信息
// orderDetailTemplateModel := gmodel.NewFsOrderDetailTemplateModel(l.svcCtx.MysqlConn)
// orderModel := gmodel.NewFsOrderModel(l.svcCtx.MysqlConn)
// fsOrderDetailModel := gmodel.NewFsOrderDetailModel(l.svcCtx.MysqlConn)
// fsProductDesignModel := gmodel.NewFsProductDesignModel(l.svcCtx.MysqlConn)
// rsbOrder := orderModel.RowSelectBuilder(nil)
// rsbOrder = rsbOrder.Where("sn =?", orderSn).Preload("FsOrderDetails")
// rsbOrder = rsbOrder.Preload("FsOrderDetails", func(dbPreload *gorm.DB) *gorm.DB {
// return dbPreload.Table(fsOrderDetailModel.TableName()).Preload("FsOrderDetailTemplateInfo", func(dbPreload *gorm.DB) *gorm.DB {
// return dbPreload.Table(orderDetailTemplateModel.TableName()).Preload("FsProductDesignInfo", func(dbPreload *gorm.DB) *gorm.DB {
// return dbPreload.Table(fsProductDesignModel.TableName())
// })
// })
// })
// fsOrderRelInfo, err := orderModel.FindOneByQuery(l.ctx, rsbOrder, nil)
// if err != nil {
// return err
// }
// var designIds []int64
// var cartIds []int64
// if len(fsOrderRelInfo.FsOrderDetails) > 0 {
// for _, fsOrderDetail := range fsOrderRelInfo.FsOrderDetails {
// if fsOrderDetail.FsOrderDetailTemplateInfo.FsProductDesignInfo.Id != 0 {
// designIds = append(designIds, fsOrderDetail.FsOrderDetailTemplateInfo.FsProductDesignInfo.Id)
// }
// cartIds = append(cartIds, *fsOrderDetail.CartId)
// }
// }
// var nowTime int64 = time.Now().UTC().Unix()
// // 支付成功
// if paymentIntent.Status == "succeeded" {
// var card string
// var brand string
// if paymentIntent.LatestCharge.PaymentMethodDetails != nil {
// if paymentIntent.LatestCharge.PaymentMethodDetails.Card != nil {
// if paymentIntent.LatestCharge.PaymentMethodDetails.Card.Last4 != "" {
// card = paymentIntent.LatestCharge.PaymentMethodDetails.Card.Last4
// }
// if paymentIntent.LatestCharge.PaymentMethodDetails.Card.Brand != "" {
// brand = string(paymentIntent.LatestCharge.PaymentMethodDetails.Card.Brand)
// }
// }
// }
// ctx := l.ctx
// err = l.svcCtx.MysqlConn.Transaction(func(connGorm *gorm.DB) error {
// // 更新支付信息
// payModelT := gmodel.NewFsPayModel(connGorm)
// *payInfo.PayStatus = 1
// *payInfo.PayTime = nowTime
// *payInfo.CardNo = card
// *payInfo.Brand = brand
// *payInfo.TradeNo = paymentIntent.ID
// _, err = payModelT.RBCreateOrUpdate(ctx, payInfo)
// if err != nil {
// return err
// }
// // 更新设计数据
// productDesignModelT := gmodel.NewFsProductDesignModel(connGorm)
// productDesignModelTRSB := productDesignModelT.BuilderTrans(ctx, nil)
// var isPay int64 = 1
// err = productDesignModelT.RBUpdateByIds(productDesignModelTRSB, designIds, &gmodel.FsProductDesign{IsPay: &isPay})
// if err != nil {
// return err
// }
// var orderInfo = &gmodel.FsOrder{}
// var orderStatus int64
// var orderIsPartPay int64
// var orderPayedAmount int64
// var orderIsPayCompleted int64
// // 支付记录是首款
// if *payInfo.PayStage == int64(constants.PAYSTAGE_DEPOSIT) {
// orderStatus = int64(constants.STATUS_NEW_PART_PAY)
// orderIsPartPay = 1
// orderInfo.IsPartPay = &orderIsPartPay
// orderPayedAmount = paymentIntent.Amount
// // 删除购物车
// cartModelT := gmodel.NewFsCartModel(connGorm)
// cartModelTRSB := cartModelT.BuilderTrans(ctx, nil)
// err = cartModelT.RBDeleteCartsByIds(cartModelTRSB, cartIds)
// if err != nil {
// return err
// }
// }
// // 支付记录是尾款
// if *payInfo.PayStage == int64(constants.PAYSTAGE_REMAINING) {
// if *fsOrderRelInfo.Status < int64(constants.STATUS_NEW_PAY_COMPLETED) {
// orderStatus = int64(constants.STATUS_NEW_PAY_COMPLETED)
// }
// orderIsPayCompleted = 1
// orderInfo.IsPayCompleted = &orderIsPayCompleted
// orderPayedAmount = *fsOrderRelInfo.PayedAmount + paymentIntent.Amount
// }
// // 更新订单信息
// orderInfo.Id = fsOrderRelInfo.Id
// orderInfo.Status = &orderStatus
// orderInfo.Ptime = &nowTime
// orderInfo.PayedAmount = &orderPayedAmount
// orderModelT := gmodel.NewFsOrderModel(connGorm)
// err = orderModelT.RBUpdate(ctx, orderInfo)
// if err != nil {
// return err
// }
// return err
// })
// if err != nil {
// return err
// }
// //千人千面的处理
// // $renderServer = (new RenderService());
// // $renderServer->thousandsFacesV2($order->id);
// // //清除用户最新的设计
// // $cache = \Yii::$app->cache;
// // $cache->delete(CacheConfigHelper::LAST_DESIGN . $order->user_id);
// // //缓存最新订单编号
// // $cache->set(CacheConfigHelper::USER_ORDERNO . $order->user_id, $order->sn);
// // //查询用户邮箱信息
// // $user = \api\models\User::find()->where(['id' => $order->user_id])->one();
// // $redisData = [
// // 'key' => 'receipt_download',
// // 'param' => [
// // 'email' => $user->email,
// // 'order_id' => $order->id,
// // 'pay_id' => $pay->id,
// // 'type' => 1,//付款成功为1
// // ]
// // ];
// // Email::timely($redisData);
// }
// 订单记录
return nil
}

View File

@ -18,9 +18,8 @@ type ServiceContext struct {
Config config.Config
SharedState *shared.SharedState
MysqlConn *gorm.DB
AllModels *gmodel.AllModelsGen
Repositories *initalize.Repositories
MysqlConn *gorm.DB
AllModels *gmodel.AllModelsGen
}
func NewServiceContext(c config.Config) *ServiceContext {
@ -32,9 +31,6 @@ func NewServiceContext(c config.Config) *ServiceContext {
MysqlConn: conn,
SharedState: nil,
AllModels: gmodel.NewAllModels(initalize.InitMysql(c.SourceMysql)),
Repositories: initalize.NewAllRepositories(&initalize.NewAllRepositorieData{
GormDB: conn,
}),
}
}

View File

@ -11,6 +11,18 @@ type OrderRefundReq struct {
type OrderRefundRes struct {
}
type OrderPaymentIntentReq struct {
Sn string `form:"sn"` //订单编号
DeliveryMethod int64 `form:"delivery_method"` //发货方式
AddressId int64 `form:"address_id"` //地址id
PayMethod int64 `form:"pay_method"` //支付方式
}
type OrderPaymentIntentRes struct {
RedirectUrl string `json:"redirect_url"`
ClientSecret string `json:"clientSecret"`
}
type StripeWebhookReq struct {
Payload []byte `json:"base_byte_slice,optional"`
StripeSignature string `json:"Stripe-Signature"`
@ -40,10 +52,10 @@ type File struct {
}
type Meta struct {
TotalCount int64 `json:"total_count"`
PageCount int64 `json:"page_count"`
CurrentPage int `json:"current_page"`
PerPage int `json:"per_page"`
TotalCount int64 `json:"totalCount"`
PageCount int64 `json:"pageCount"`
CurrentPage int `json:"currentPage"`
PerPage int `json:"perPage"`
}
// Set 设置Response的Code和Message值

View File

@ -106,7 +106,7 @@ func (l *GetProductTemplateTagsLogic) GetProductTemplateTags(req *types.GetProdu
for templateTag, _ := range mapMaterialTemplateTagColors {
templateTagNameList = append(templateTagNameList, templateTag)
}
productTemplateTags, err = l.svcCtx.AllModels.FsProductTemplateTags.GetListByTagNames(l.ctx, templateTagNameList, len(templateTagNameList), 1, "id DESC")
productTemplateTags, err = l.svcCtx.AllModels.FsProductTemplateTags.GetListByTagNames(l.ctx, templateTagNameList, req.Limit, 1, "id DESC")
if err != nil {
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get template tags")
@ -135,7 +135,6 @@ func (l *GetProductTemplateTagsLogic) GetProductTemplateTags(req *types.GetProdu
for k, v := range productTemplateTags {
if templateTagStr == *v.TemplateTag {
productTemplateTags[k], productTemplateTags[index] = productTemplateTags[index], productTemplateTags[k]
break
}
}
}

View File

@ -11,22 +11,4 @@ type Config struct {
SourceMysql string
Auth types.Auth
ReplicaId uint64
AWS struct {
S3 struct {
Credentials struct {
AccessKeyID string
Secret string
Token string
}
}
}
BLMService struct {
Url string
LogoCombine struct {
Url string
}
}
Unity struct {
Host string
}
}

View File

@ -1,35 +0,0 @@
package handler
import (
"net/http"
"reflect"
"fusenapi/utils/basic"
"fusenapi/server/product/internal/logic"
"fusenapi/server/product/internal/svc"
"fusenapi/server/product/internal/types"
)
func CalculateProductPriceHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.CalculateProductPriceReq
userinfo, err := basic.RequestParse(w, r, svcCtx, &req)
if err != nil {
return
}
// 创建一个业务逻辑层实例
l := logic.NewCalculateProductPriceLogic(r.Context(), svcCtx)
rl := reflect.ValueOf(l)
basic.BeforeLogic(w, r, rl)
resp := l.CalculateProductPrice(&req, userinfo)
if !basic.AfterLogic(w, r, rl, resp) {
basic.NormalAfterLogic(w, r, resp)
}
}
}

View File

@ -1,35 +0,0 @@
package handler
import (
"net/http"
"reflect"
"fusenapi/utils/basic"
"fusenapi/server/product/internal/logic"
"fusenapi/server/product/internal/svc"
"fusenapi/server/product/internal/types"
)
func GetProductStepPriceHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.GetProductStepPriceReq
userinfo, err := basic.RequestParse(w, r, svcCtx, &req)
if err != nil {
return
}
// 创建一个业务逻辑层实例
l := logic.NewGetProductStepPriceLogic(r.Context(), svcCtx)
rl := reflect.ValueOf(l)
basic.BeforeLogic(w, r, rl)
resp := l.GetProductStepPrice(&req, userinfo)
if !basic.AfterLogic(w, r, rl, resp) {
basic.NormalAfterLogic(w, r, resp)
}
}
}

View File

@ -72,16 +72,6 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
Path: "/api/product/get_price_by_pid",
Handler: GetPriceByPidHandler(serverCtx),
},
{
Method: http.MethodGet,
Path: "/api/product/get_product_step_price",
Handler: GetProductStepPriceHandler(serverCtx),
},
{
Method: http.MethodPost,
Path: "/api/product/calculate_product_price",
Handler: CalculateProductPriceHandler(serverCtx),
},
{
Method: http.MethodGet,
Path: "/api/product/get_size_by_pid",

View File

@ -1,101 +0,0 @@
package logic
import (
"encoding/json"
"errors"
"fusenapi/constants"
"fusenapi/model/gmodel"
"fusenapi/utils/auth"
"fusenapi/utils/basic"
"fusenapi/utils/format"
"gorm.io/gorm"
"context"
"fusenapi/server/product/internal/svc"
"fusenapi/server/product/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type CalculateProductPriceLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewCalculateProductPriceLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CalculateProductPriceLogic {
return &CalculateProductPriceLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
// 处理进入前逻辑w,r
// func (l *CalculateProductPriceLogic) BeforeLogic(w http.ResponseWriter, r *http.Request) {
// }
func (l *CalculateProductPriceLogic) CalculateProductPrice(req *types.CalculateProductPriceReq, userinfo *auth.UserInfo) (resp *basic.Response) {
if req.ProductId <= 0 {
return resp.SetStatusWithMessage(basic.CodeRequestParamsErr, "err param:product id")
}
if req.SizeId <= 0 {
return resp.SetStatusWithMessage(basic.CodeRequestParamsErr, "err param:size id")
}
if req.PurchaseQuantity <= 0 {
return resp.SetStatusWithMessage(basic.CodeRequestParamsErr, "err param:purchase quantity")
}
//获取产品信息(只是获取id)
_, err := l.svcCtx.AllModels.FsProduct.FindOne(l.ctx, req.ProductId, "id")
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return resp.SetStatusWithMessage(basic.CodeDbRecordNotFoundErr, "the product is not exists")
}
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get product info")
}
//根据产品跟尺寸获取模型价格信息
modelInfo, err := l.svcCtx.AllModels.FsProductModel3d.FindOneByProductIdSizeIdTag(l.ctx, req.ProductId, req.SizeId, constants.TAG_MODEL, "id,step_price")
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return resp.SetStatusWithMessage(basic.CodeDbRecordNotFoundErr, "model info is not exists")
}
return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get model info")
}
var stepPrice gmodel.StepPriceJsonStruct
if modelInfo.StepPrice != nil && len(*modelInfo.StepPrice) != 0 {
if err = json.Unmarshal(*modelInfo.StepPrice, &stepPrice); err != nil {
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeJsonErr, "failed to parse step price")
}
}
//配件
fittingPrice := int64(0)
if req.FittingId > 0 {
fittingInfo, err := l.svcCtx.AllModels.FsProductModel3d.FindOne(l.ctx, req.FittingId, "id,price")
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return resp.SetStatusWithMessage(basic.CodeDbRecordNotFoundErr, "fitting info is not exists")
}
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get fitting info")
}
fittingPrice = *fittingInfo.Price
}
totalPrice, itemPrice, err := l.svcCtx.Repositories.NewShoppingCart.CaculateStepPrice(req.PurchaseQuantity, stepPrice, fittingPrice)
if err != nil {
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeServiceErr, "failed to calculate product price ")
}
return resp.SetStatusWithMessage(basic.CodeOK, "success", types.CalculateProductPriceRsp{
ItemPrice: format.CentitoDollar(itemPrice, 3),
TotalPrice: format.CentitoDollarWithNoHalfAdjust(totalPrice, 2),
PurchaseQuantity: req.PurchaseQuantity,
})
}
// 处理逻辑后 w,r 如:重定向, resp 必须重新处理
// func (l *CalculateProductPriceLogic) AfterLogic(w http.ResponseWriter, r *http.Request, resp *basic.Response) {
// // httpx.OkJsonCtx(r.Context(), w, resp)
// }

View File

@ -2,9 +2,12 @@ package logic
import (
"context"
"errors"
"fusenapi/utils/auth"
"fusenapi/utils/basic"
"gorm.io/gorm"
"fusenapi/server/product/internal/svc"
"fusenapi/server/product/internal/types"
@ -30,18 +33,18 @@ func (l *GetLastProductDesignLogic) GetLastProductDesign(req *types.Request, use
return resp.SetStatusAddMessage(basic.CodeUnAuth, "please sign in")
}
//获取用户信息
// user, err := l.svcCtx.AllModels.FsUser.FindUserById(l.ctx, userinfo.UserId)
// if err != nil {
// if errors.Is(err, gorm.ErrRecordNotFound) {
// return resp.SetStatusWithMessage(basic.CodeUnAuth, "user not found")
// }
// logx.Error(err)
// return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get user info")
// }
// //若没打开了个性化渲染按钮
// if *user.IsOpenRender != 1 {
// return resp.SetStatusWithMessage(basic.CodeOK, "success:IsOpenRender switch is closed")
// }
user, err := l.svcCtx.AllModels.FsUser.FindUserById(l.ctx, userinfo.UserId)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return resp.SetStatusWithMessage(basic.CodeUnAuth, "user not found")
}
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get user info")
}
//若没打开了个性化渲染按钮
if *user.IsOpenRender != 1 {
return resp.SetStatusWithMessage(basic.CodeOK, "success:IsOpenRender switch is closed")
}
//查询用户最近下单成功的数据
// orderInfo, err := l.svcCtx.AllModels.FsOrder.FindLastSuccessOneOrder(l.ctx, user.Id, int64(constants.STATUS_NEW_NOT_PAY))
// if err != nil {

View File

@ -377,8 +377,8 @@ func (l *GetProductInfoLogic) GetProductInfo(req *types.GetProductInfoReq, useri
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get user info")
}
isLowRendering = true
isRemoveBg = true
isLowRendering = *user.IsLowRendering > 0
isRemoveBg = *user.IsRemoveBg > 0
lastDesign = l.getLastDesign(user)
}
var renderDesign interface{}

View File

@ -12,13 +12,12 @@ import (
"fusenapi/utils/basic"
"fusenapi/utils/format"
"fusenapi/utils/image"
"math"
"sort"
"strings"
"github.com/zeromicro/go-zero/core/logx"
"github.com/zeromicro/go-zero/core/stores/sqlc"
"gorm.io/gorm"
"math"
"sort"
"strings"
)
type GetProductListLogic struct {
@ -164,7 +163,7 @@ func (l *GetProductListLogic) GetProductList(req *types.GetProductListReq, useri
UserId: user.Id,
}
if user.Id != 0 {
r.IsThousandFace = 1
r.IsThousandFace = int(*user.IsThousandFace)
}
image.ThousandFaceImageFormat(&r)
item.Cover = r.Cover

View File

@ -1,137 +0,0 @@
package logic
import (
"context"
"encoding/json"
"errors"
"fmt"
"fusenapi/constants"
"fusenapi/model/gmodel"
"fusenapi/utils/auth"
"fusenapi/utils/basic"
"fusenapi/utils/format"
"gorm.io/gorm"
"fusenapi/server/product/internal/svc"
"fusenapi/server/product/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type GetProductStepPriceLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewGetProductStepPriceLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetProductStepPriceLogic {
return &GetProductStepPriceLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
// 处理进入前逻辑w,r
// func (l *GetProductStepPriceLogic) BeforeLogic(w http.ResponseWriter, r *http.Request) {
// }
func (l *GetProductStepPriceLogic) GetProductStepPrice(req *types.GetProductStepPriceReq, userinfo *auth.UserInfo) (resp *basic.Response) {
if req.ProductId <= 0 {
return resp.SetStatusWithMessage(basic.CodeRequestParamsErr, "err param:product id")
}
//获取产品信息(只是获取id)
_, err := l.svcCtx.AllModels.FsProduct.FindOne(l.ctx, req.ProductId, "id")
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return resp.SetStatusWithMessage(basic.CodeDbRecordNotFoundErr, "the product is not exists")
}
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get product info")
}
//查询产品价格
modelPriceList, err := l.svcCtx.AllModels.FsProductModel3d.GetAllByProductIdTag(l.ctx, req.ProductId, constants.TAG_MODEL, "id,size_id,part_id,step_price,packed_unit")
if err != nil {
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get model price list")
}
fittingIds := make([]int64, 0, len(modelPriceList))
for _, v := range modelPriceList {
if *v.PartId > 0 {
fittingIds = append(fittingIds, *v.PartId)
}
}
//查询配件价格列表
fittingPriceList, err := l.svcCtx.AllModels.FsProductModel3d.GetAllByIdsTag(l.ctx, fittingIds, constants.TAG_PARTS, "id,price,packed_unit")
if err != nil {
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get fitting price list")
}
mapFitting := make(map[int64]gmodel.FsProductModel3d)
for _, v := range fittingPriceList {
mapFitting[v.Id] = v
}
//遍历处理模型价格
mapRsp := make(map[string]interface{})
for _, modelPriceInfo := range modelPriceList {
var stepPrice gmodel.StepPriceJsonStruct
if err = json.Unmarshal(*modelPriceInfo.StepPrice, &stepPrice); err != nil {
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeJsonErr, "failed to parse step price json")
}
rangeLen := len(stepPrice.PriceRange)
if rangeLen == 0 {
return resp.SetStatusWithMessage(basic.CodeServiceErr, fmt.Sprintf("step price is not set:%d", modelPriceInfo.Id))
}
//最小单价
minPrice := stepPrice.PriceRange[rangeLen-1].Price
//最大单价
maxPrice := stepPrice.PriceRange[0].Price
//购买数步进基数
stepPurchaseQuantity := *modelPriceInfo.PackedUnit
//购买数步进基数描述
stepPurchaseQuantityDescription := "主体装箱数为步进基数"
if *modelPriceInfo.PartId > 0 {
fittingPriceInfo, ok := mapFitting[*modelPriceInfo.PartId]
if !ok {
return resp.SetStatusWithMessage(basic.CodeServiceErr, fmt.Sprintf("fitting price is not exists:%d", *modelPriceInfo.PartId))
}
//最小价格要加配件
minPrice += *fittingPriceInfo.Price
//如果配件装箱基数比主体大,则基数以配件为主
if *fittingPriceInfo.PackedUnit > stepPurchaseQuantity {
stepPurchaseQuantity = *fittingPriceInfo.PackedUnit
stepPurchaseQuantityDescription = "配件装箱数为步进基数"
}
}
stepRange := make([]interface{}, 0, rangeLen)
for rIndex, rangeInfo := range stepPrice.PriceRange {
//最后一个
if rIndex+1 == rangeLen {
stepRange = append(stepRange, map[string]interface{}{
"range_description": fmt.Sprintf(">=%s Units", format.NumToStringWithThousandthPercentile(rangeInfo.StartQuantity)),
"item_price": format.CentitoDollar(rangeInfo.Price, 3),
})
break
}
stepRange = append(stepRange, map[string]interface{}{
"range_description": fmt.Sprintf("%s-%s Units", format.NumToStringWithThousandthPercentile(rangeInfo.StartQuantity), format.NumToStringWithThousandthPercentile(rangeInfo.EndQuantity)),
"item_price": format.CentitoDollar(rangeInfo.Price, 3),
})
}
mapRsp[fmt.Sprintf("_%d", *modelPriceInfo.SizeId)] = map[string]interface{}{
"step_purchase_quantity": stepPurchaseQuantity,
"step_purchase_quantity_description": stepPurchaseQuantityDescription,
"min_price": minPrice,
"max_price": maxPrice,
"step_range": stepRange,
"min_buy_units_quantity": stepPrice.MinBuyUnitsNum,
}
}
return resp.SetStatusWithMessage(basic.CodeOK, "success", mapRsp)
}
// 处理逻辑后 w,r 如:重定向, resp 必须重新处理
// func (l *GetProductStepPriceLogic) AfterLogic(w http.ResponseWriter, r *http.Request, resp *basic.Response) {
// // httpx.OkJsonCtx(r.Context(), w, resp)
// }

View File

@ -77,8 +77,8 @@ func (l *GetRenderSettingByPidLogic) GetRenderSettingByPid(req *types.GetRenderS
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get user info")
}
isLowRendering = true
isRemoveBg = true
isLowRendering = *user.IsLowRendering > 0
isRemoveBg = *user.IsRemoveBg > 0
lastDesign, err = l.checkLastDesignExists(user.Id)
if err != nil {
logx.Error(err)

View File

@ -59,10 +59,7 @@ func (l *GetSizeByPidLogic) GetSizeByPid(req *types.GetSizeByPidReq, userinfo *a
} else {
//根据模板找到模型sizeId
defaultModel3d, err := l.svcCtx.AllModels.FsProductModel3d.FindOne(l.ctx, *defaultTemplate.ModelId, "size_id")
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "the template`s model is not exists ")
}
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get default model ")
}

View File

@ -1,10 +1,16 @@
package logic
import (
"context"
"errors"
"fmt"
"fusenapi/constants"
"fusenapi/model/gmodel"
"fusenapi/utils/auth"
"fusenapi/utils/basic"
"context"
"fusenapi/utils/format"
"fusenapi/utils/step_price"
"strings"
"fusenapi/server/product/internal/svc"
"fusenapi/server/product/internal/types"
@ -26,18 +32,157 @@ func NewGetSizeByProductLogic(ctx context.Context, svcCtx *svc.ServiceContext) *
}
}
// 处理进入前逻辑w,r
// func (l *GetSizeByProductLogic) BeforeLogic(w http.ResponseWriter, r *http.Request) {
// }
// 获取分类下的产品以及尺寸
func (l *GetSizeByProductLogic) GetSizeByProduct(req *types.Request, userinfo *auth.UserInfo) (resp *basic.Response) {
// 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data)
// userinfo 传入值时, 一定不为null
return resp.SetStatus(basic.CodeOK)
if userinfo.GetIdType() != auth.IDTYPE_User {
return resp.SetStatusWithMessage(basic.CodeUnAuth, "please sign in first")
}
//获取所有网站目录
tagsModel := gmodel.NewFsTagsModel(l.svcCtx.MysqlConn)
tagsList, err := tagsModel.GetAllByLevel(l.ctx, constants.TYPE_WEBSITE)
if err != nil {
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeServiceErr, "failed to get website tags")
}
if len(tagsList) == 0 {
return resp.SetStatusWithMessage(basic.CodeOK, "tag list is null")
}
tagIds := make([]int64, 0, len(tagsList))
for _, v := range tagsList {
tagIds = append(tagIds, v.Id)
}
//获取这些类型的产品
productModel := gmodel.NewFsProductModel(l.svcCtx.MysqlConn)
productList, err := productModel.GetProductListByIds(l.ctx, tagIds, "sort-desc")
if err != nil {
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeServiceErr, "failed to get tag product list")
}
productIds := make([]int64, 0, len(productList))
for _, v := range productList {
productIds = append(productIds, v.Id)
}
productSizeModel := gmodel.NewFsProductSizeModel(l.svcCtx.MysqlConn)
productSizeList, err := productSizeModel.GetAllByProductIds(l.ctx, productIds, "sort DESC")
if err != nil {
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeServiceErr, "failed to get product size list")
}
sizeIds := make([]int64, 0, len(productSizeList))
for _, v := range productSizeList {
sizeIds = append(sizeIds, v.Id)
}
//获取价格列表
productPriceModel := gmodel.NewFsProductPriceModel(l.svcCtx.MysqlConn)
productPriceList, err := productPriceModel.GetPriceListByProductIdsSizeIds(l.ctx, productIds, sizeIds)
if err != nil {
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeServiceErr, "failed to get product proce list")
}
mapProductPrice := make(map[string]gmodel.FsProductPrice)
for _, v := range productPriceList {
mapProductPrice[fmt.Sprintf("%d_%d", *v.ProductId, *v.SizeId)] = v
}
//组装返回
list := make([]types.GetSizeByProductRsp, 0, len(tagsList))
for _, tag := range tagsList {
//获取第一层子类
firstChildrenList, err := l.GetFirstChildrenList(tag, productList, productSizeList, mapProductPrice)
if err != nil {
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeServiceErr, "failed to get first level children list")
}
data := types.GetSizeByProductRsp{
Id: tag.Id,
Name: *tag.Title,
Children: firstChildrenList,
}
list = append(list, data)
}
return resp.SetStatusWithMessage(basic.CodeOK, "success", list)
}
// 处理逻辑后 w,r 如:重定向, resp 必须重新处理
// func (l *GetSizeByProductLogic) AfterLogic(w http.ResponseWriter, r *http.Request, resp *basic.Response) {
// // httpx.OkJsonCtx(r.Context(), w, resp)
// }
// 第一层子层
func (l *GetSizeByProductLogic) GetFirstChildrenList(tag gmodel.FsTags, productList []gmodel.FsProduct, productSizeList []gmodel.FsProductSize, mapProductPrice map[string]gmodel.FsProductPrice) (childrenList []types.Children, err error) {
childrenList = make([]types.Children, 0, len(productList))
for _, product := range productList {
if *product.Type != tag.Id {
continue
}
childrenObjList, err := l.GetSecondChildrenList(product, productSizeList, mapProductPrice)
if err != nil {
return nil, err
}
//获取第二层子类
data := types.Children{
Id: product.Id,
Name: *product.Title,
Cycle: int(*product.DeliveryDays + *product.ProduceDays),
ChildrenList: childrenObjList,
}
childrenList = append(childrenList, data)
}
return
}
// 第2层子层
func (l *GetSizeByProductLogic) GetSecondChildrenList(product gmodel.FsProduct, productSizeList []gmodel.FsProductSize, mapProductPrice map[string]gmodel.FsProductPrice) (childrenObjList []types.ChildrenObj, err error) {
childrenObjList = make([]types.ChildrenObj, 0, len(productSizeList))
for _, productSize := range productSizeList {
if product.Id != *productSize.ProductId {
continue
}
priceList := make([]types.PriceObj, 0, len(productSizeList))
price, ok := mapProductPrice[fmt.Sprintf("%d_%d", *productSize.ProductId, productSize.Id)]
//无对应尺寸价格
if !ok {
priceList = []types.PriceObj{
{Num: 1, Price: 0},
{Num: 1, Price: 0},
{Num: 1, Price: 0},
}
childrenObjList = append(childrenObjList, types.ChildrenObj{
Id: productSize.Id,
Name: *productSize.Capacity,
PriceList: priceList,
})
continue
}
if price.StepNum == nil || price.StepPrice == nil {
continue
}
*price.StepNum = strings.Trim(*price.StepNum, " ")
*price.StepPrice = strings.Trim(*price.StepPrice, " ")
//阶梯数量切片
stepNum, err := format.StrSlicToIntSlice(strings.Split(*price.StepNum, ","))
if err != nil {
return nil, err
}
//阶梯价格切片
stepPrice, err := format.StrSlicToIntSlice(strings.Split(*price.StepPrice, ","))
if err != nil {
return nil, err
}
if len(stepNum) == 0 || len(stepPrice) == 0 {
return nil, errors.New(fmt.Sprintf("stepNum count or stepPrice count is empty: product size id :%d ,product price id :%d", productSize.Id, price.Id))
}
index := 0
// 最小购买数量小于 最大阶梯数量+5
for int(*price.MinBuyNum) < (stepNum[len(stepNum)-1]+5) && index < 3 {
priceList = append(priceList, types.PriceObj{
Num: int(*price.MinBuyNum * *price.EachBoxNum),
Price: step_price.GetStepPrice(int(*price.MinBuyNum), stepNum, stepPrice),
})
*price.MinBuyNum++
index++
}
data := types.ChildrenObj{
Id: productSize.Id,
Name: *productSize.Capacity,
PriceList: priceList,
}
childrenObjList = append(childrenObjList, data)
}
return
}

View File

@ -9,7 +9,6 @@ import (
"fusenapi/utils/auth"
"fusenapi/utils/basic"
"fusenapi/utils/image"
"github.com/zeromicro/go-zero/core/logx"
"gorm.io/gorm"
)
@ -76,7 +75,7 @@ func (l *GetSuccessRecommandLogic) GetSuccessRecommand(req *types.GetSuccessReco
UserId: user.Id,
}
if user.Id > 0 {
r.IsThousandFace = int(1)
r.IsThousandFace = int(*user.IsThousandFace)
}
image.ThousandFaceImageFormat(&r)
data.Cover = r.Cover

View File

@ -8,9 +8,8 @@ import (
"fusenapi/utils/basic"
"fusenapi/utils/format"
"fusenapi/utils/image"
"strings"
"gorm.io/gorm"
"strings"
"fusenapi/server/product/internal/svc"
"fusenapi/server/product/internal/types"
@ -84,7 +83,7 @@ func (l *OtherProductListLogic) OtherProductList(req *types.OtherProductListReq,
UserId: user.Id,
}
if user.Id > 0 {
r.IsThousandFace = 1
r.IsThousandFace = int(*user.IsThousandFace)
}
image.ThousandFaceImageFormat(r)
v.Cover = r.Cover

View File

@ -5,9 +5,6 @@ import (
"fmt"
"fusenapi/server/product/internal/config"
"fusenapi/shared"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/session"
"net/http"
"fusenapi/initalize"
@ -21,28 +18,15 @@ type ServiceContext struct {
Config config.Config
SharedState *shared.SharedState
MysqlConn *gorm.DB
AllModels *gmodel.AllModelsGen
Repositories *initalize.Repositories
AwsSession *session.Session
MysqlConn *gorm.DB
AllModels *gmodel.AllModelsGen
}
func NewServiceContext(c config.Config) *ServiceContext {
conn := initalize.InitMysql(c.SourceMysql)
config := aws.Config{
Credentials: credentials.NewStaticCredentials(c.AWS.S3.Credentials.AccessKeyID, c.AWS.S3.Credentials.Secret, c.AWS.S3.Credentials.Token),
}
return &ServiceContext{
Config: c,
MysqlConn: initalize.InitMysql(c.SourceMysql),
AllModels: gmodel.NewAllModels(initalize.InitMysql(c.SourceMysql)),
AwsSession: session.Must(session.NewSession(&config)),
Repositories: initalize.NewAllRepositories(&initalize.NewAllRepositorieData{
GormDB: conn,
BLMServiceUrl: &c.BLMService.Url,
AwsSession: session.Must(session.NewSession(&config)),
}),
Config: c,
MysqlConn: initalize.InitMysql(c.SourceMysql),
AllModels: gmodel.NewAllModels(initalize.InitMysql(c.SourceMysql)),
}
}

View File

@ -331,23 +331,6 @@ type PriceItem struct {
Price int64 `json:"price"`
}
type GetProductStepPriceReq struct {
ProductId int64 `form:"product_id"`
}
type CalculateProductPriceReq struct {
ProductId int64 `json:"product_id"`
SizeId int64 `json:"size_id"`
FittingId int64 `json:"fitting_id,optional"`
PurchaseQuantity int64 `json:"purchase_quantity"`
}
type CalculateProductPriceRsp struct {
ItemPrice string `json:"item_price"`
TotalPrice string `json:"total_price"`
PurchaseQuantity int64 `json:"purchase_quantity"`
}
type GetSizeByPidReq struct {
Pid string `form:"pid"`
TemplateTag string `form:"template_tag"`
@ -457,10 +440,10 @@ type File struct {
}
type Meta struct {
TotalCount int64 `json:"total_count"`
PageCount int64 `json:"page_count"`
CurrentPage int `json:"current_page"`
PerPage int `json:"per_page"`
TotalCount int64 `json:"totalCount"`
PageCount int64 `json:"pageCount"`
CurrentPage int `json:"currentPage"`
PerPage int `json:"perPage"`
}
// Set 设置Response的Code和Message值

View File

@ -10,8 +10,6 @@ import (
"fusenapi/server/shopping-cart/internal/types"
"fusenapi/utils/auth"
"fusenapi/utils/basic"
"fusenapi/utils/file"
"fusenapi/utils/hash"
"gorm.io/gorm"
"time"
@ -53,31 +51,6 @@ func (l *AddToCartLogic) AddToCart(req *types.AddToCartReq, userinfo *auth.UserI
if cartCount >= 100 {
return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "sorry,the count of your carts can`t greater than 100")
}
if req.RenderImage != "" {
//上传base64文件
// 上传文件
var upload = file.Upload{
Ctx: l.ctx,
MysqlConn: l.svcCtx.MysqlConn,
AwsSession: l.svcCtx.AwsSession,
}
uploadRes, err := upload.UploadFileByBase64(&file.UploadBaseReq{
Source: "webGl render image",
FileHash: hash.JsonHashKey(req.RenderImage),
FileData: req.RenderImage,
Metadata: "",
UploadBucket: 1,
ApiType: 2,
UserId: userinfo.UserId,
GuestId: userinfo.GuestId,
FileByte: nil,
})
if err != nil {
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeFileUploadErr, "failed to upload webGl render image")
}
req.RenderImage = uploadRes.ResourceUrl
}
//获取产品是否存在
productInfo, err := l.svcCtx.AllModels.FsProduct.FindOne(l.ctx, req.ProductId)
if err != nil {

View File

@ -2,9 +2,9 @@ package logic
import (
"context"
"encoding/json"
"errors"
"fmt"
"fusenapi/constants"
"fusenapi/model/gmodel"
"fusenapi/server/shopping-cart/internal/svc"
"fusenapi/server/shopping-cart/internal/types"
@ -53,7 +53,7 @@ func (l *CalculateCartPriceLogic) CalculateCartPrice(req *types.CalculateCartPri
//获取购物车列表
carts, _, err := l.svcCtx.AllModels.FsShoppingCart.GetAllCartsByParam(l.ctx, gmodel.GetAllCartsByParamReq{
Ids: cartIds,
Fields: "id,size_id,product_id,fitting_id,model_id",
Fields: "id,size_id,product_id,fitting_id",
UserId: userinfo.UserId,
Page: 1,
Limit: len(cartIds),
@ -67,24 +67,33 @@ func (l *CalculateCartPriceLogic) CalculateCartPrice(req *types.CalculateCartPri
}
sizeIds := make([]int64, 0, len(carts))
productIds := make([]int64, 0, len(carts))
modelIds := make([]int64, 0, len(carts)) //模型+配件
fittingIds := make([]int64, 0, len(carts))
for _, v := range carts {
sizeIds = append(sizeIds, *v.SizeId)
productIds = append(productIds, *v.ProductId)
modelIds = append(modelIds, *v.ModelId)
if *v.FittingId > 0 {
modelIds = append(modelIds, *v.FittingId)
fittingIds = append(fittingIds, *v.FittingId)
}
}
//获取配件列表(只有id跟价格)
modelList, err := l.svcCtx.AllModels.FsProductModel3d.GetAllByIds(l.ctx, modelIds, "id,step_price,price")
//根据sizeid获取价格列表
priceList, err := l.svcCtx.AllModels.FsProductPrice.GetPriceListByProductIdsSizeIds(l.ctx, productIds, sizeIds)
if err != nil {
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get model list")
return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get price list")
}
mapModel := make(map[int64]gmodel.FsProductModel3d)
for _, v := range modelList {
mapModel[v.Id] = v
mapPrice := make(map[string]gmodel.FsProductPrice)
for _, v := range priceList {
mapPrice[fmt.Sprintf("%d_%d", *v.ProductId, *v.SizeId)] = v
}
//获取配件列表(只有id跟价格)
fittingList, err := l.svcCtx.AllModels.FsProductModel3d.GetAllByIdsTag(l.ctx, fittingIds, constants.TAG_PARTS, "id,price")
if err != nil {
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get fitting list")
}
mapFitting := make(map[int64]int64)
for _, v := range fittingList {
mapFitting[v.Id] = *v.Price
}
//开始计算价格
calculateResultList := make([]types.CalculateResultItem, 0, len(req.CalculateList))
@ -93,16 +102,9 @@ func (l *CalculateCartPriceLogic) CalculateCartPrice(req *types.CalculateCartPri
err = l.svcCtx.MysqlConn.Transaction(func(tx *gorm.DB) error {
shoppingCartModel := gmodel.NewFsShoppingCartModel(tx)
for _, cart := range carts {
modelInfo, ok := mapModel[*cart.ModelId]
sizePrice, ok := mapPrice[fmt.Sprintf("%d_%d", *cart.ProductId, *cart.SizeId)]
if !ok {
return err
}
var stepPrice gmodel.StepPriceJsonStruct
if modelInfo.StepPrice != nil && len(*modelInfo.StepPrice) != 0 {
if err = json.Unmarshal(*modelInfo.StepPrice, &stepPrice); err != nil {
logx.Error(err)
return err
}
return errors.New(fmt.Sprintf("there carts contain some one which have no price info:%d_%d", *cart.ProductId, *cart.SizeId))
}
//请求的数量
reqPurchaseQuantity := mapCalculateQuantity[cart.Id].PurchaseQuantity
@ -113,15 +115,16 @@ func (l *CalculateCartPriceLogic) CalculateCartPrice(req *types.CalculateCartPri
//如果有配件,单价也要加入配件价格
fittingPrice := int64(0)
if *cart.FittingId > 0 {
if fittingInfo, ok := mapModel[*cart.FittingId]; ok {
fittingPrice = *fittingInfo.Price
if fPrice, ok := mapFitting[*cart.FittingId]; ok {
fittingPrice = fPrice
} else {
return errors.New(fmt.Sprintf("cart contain some one witch lose fitting:%d", *cart.FittingId))
}
}
//计算价格
totalPrice, itemPrice, err := l.svcCtx.Repositories.NewShoppingCart.CaculateStepPrice(reqPurchaseQuantity, stepPrice, fittingPrice)
itemPrice, totalPrice, _, _, err := l.svcCtx.Repositories.NewShoppingCart.CaculateCartPrice(reqPurchaseQuantity, &sizePrice, fittingPrice)
if err != nil {
logx.Error(err)
return err
}
calculateResultList = append(calculateResultList, types.CalculateResultItem{
@ -146,7 +149,6 @@ func (l *CalculateCartPriceLogic) CalculateCartPrice(req *types.CalculateCartPri
return nil
})
if err != nil {
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeDbSqlErr, err.Error())
}
return resp.SetStatusWithMessage(basic.CodeOK, "success", types.CalculateCartPriceRsp{

View File

@ -41,28 +41,37 @@ func (l *GetCartsLogic) GetCarts(req *types.GetCartsReq, userinfo *auth.UserInfo
if !userinfo.IsUser() {
return resp.SetStatusWithMessage(basic.CodeUnAuth, "please sign in")
}
currentPage := constants.DEFAULT_PAGE
if req.CurrentPage <= 0 {
req.CurrentPage = constants.DEFAULT_PAGE
}
limit := 300
//获取用户购物车列表
var cartIds []int64
if req.CartId > 0 {
cartIds = append(cartIds, req.CartId)
}
carts, total, err := l.svcCtx.AllModels.FsShoppingCart.GetAllCartsByParam(l.ctx, gmodel.GetAllCartsByParamReq{
Ids: cartIds,
UserId: userinfo.UserId,
Sort: "id DESC",
Page: currentPage,
Page: req.CurrentPage,
Limit: limit,
})
if err != nil {
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "system err:failed to get your shopping carts")
}
if len(carts) == 0 {
return resp.SetStatusWithMessage(basic.CodeOK, "success", types.GetCartsRsp{
Meta: types.Meta{
TotalCount: total,
PageCount: int64(math.Ceil(float64(total) / float64(limit))),
CurrentPage: req.CurrentPage,
PerPage: limit,
},
CartList: nil,
})
}
var (
mapSize = make(map[int64]gmodel.FsProductSize)
mapModel = make(map[int64]gmodel.FsProductModel3d)
mapTemplate = make(map[int64]gmodel.FsProductTemplateV2)
mapSizePrice = make(map[string]gmodel.FsProductPrice)
mapProduct = make(map[int64]gmodel.FsProduct)
mapResourceMetadata = make(map[string]interface{})
)
@ -72,6 +81,7 @@ func (l *GetCartsLogic) GetCarts(req *types.GetCartsReq, userinfo *auth.UserInfo
MapSize: mapSize,
MapModel: mapModel,
MapTemplate: mapTemplate,
MapSizePrice: mapSizePrice,
MapProduct: mapProduct,
MapResourceMetadata: mapResourceMetadata,
})
@ -99,34 +109,21 @@ func (l *GetCartsLogic) GetCarts(req *types.GetCartsReq, userinfo *auth.UserInfo
list := make([]types.CartItem, 0, len(carts))
for _, cart := range carts {
snapShot := mapSnapshot[cart.Id]
modelInfo, ok := mapModel[*cart.ModelId]
sizePrice, ok := mapSizePrice[fmt.Sprintf("%d_%d", *cart.ProductId, *cart.SizeId)]
if !ok {
return resp.SetStatusWithMessage(basic.CodeServiceErr, fmt.Sprintf("the size`s model info is not exists:%d_%d", *cart.ProductId, *cart.SizeId))
return resp.SetStatusWithMessage(basic.CodeServiceErr, fmt.Sprintf("the size`s price info is not exists:%d_%d", *cart.ProductId, *cart.SizeId))
}
var stepPrice gmodel.StepPriceJsonStruct
if modelInfo.StepPrice != nil && len(*modelInfo.StepPrice) != 0 {
if err = json.Unmarshal(*modelInfo.StepPrice, &stepPrice); err != nil {
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeJsonErr, fmt.Sprintf("failed to parse model step price:%d", *cart.ModelId))
}
}
//购买数量步进量
stepPurchaseQuantity := *modelInfo.PackedUnit
//如果有配件,单价也要加入配件价格
fittingPrice := int64(0)
if *cart.FittingId > 0 {
curFittingInfo, ok := mapModel[*cart.FittingId]
if !ok {
if curFittingInfo, ok := mapModel[*cart.FittingId]; ok {
fittingPrice = *curFittingInfo.Price
} else {
return resp.SetStatusWithMessage(basic.CodeServiceErr, fmt.Sprintf("cart contain some one witch lose fitting:%d", *cart.FittingId))
}
fittingPrice = *curFittingInfo.Price
//取大的为步进量基数
if *curFittingInfo.PackedUnit > stepPurchaseQuantity {
stepPurchaseQuantity = *curFittingInfo.PackedUnit
}
}
//计算阶梯价格
totalPrice, itemPrice, err := l.svcCtx.Repositories.NewShoppingCart.CaculateStepPrice(*cart.PurchaseQuantity, stepPrice, fittingPrice)
//计算价格
itemPrice, totalPrice, _, _, err := l.svcCtx.Repositories.NewShoppingCart.CaculateCartPrice(*cart.PurchaseQuantity, &sizePrice, fittingPrice)
if err != nil {
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeServiceErr, err.Error())
@ -155,10 +152,6 @@ func (l *GetCartsLogic) GetCarts(req *types.GetCartsReq, userinfo *auth.UserInfo
productCoverMetadata = metadata
}
}
templateTag := ""
if templateInfo, ok := mapTemplate[*cart.TemplateId]; ok {
templateTag = *templateInfo.TemplateTag
}
item := types.CartItem{
CartId: cart.Id,
ProductInfo: types.ProductInfo{
@ -190,12 +183,10 @@ func (l *GetCartsLogic) GetCarts(req *types.GetCartsReq, userinfo *auth.UserInfo
Slogan: snapShot.UserDiyInformation.Slogan,
},
PurchaseQuantity: *cart.PurchaseQuantity,
MinPurchaseQuantity: stepPrice.MinBuyUnitsNum,
StepPurchaseQuantity: stepPurchaseQuantity,
MinPurchaseQuantity: *sizePrice.EachBoxNum * (*sizePrice.MinBuyNum),
StepPurchaseQuantity: *sizePrice.EachBoxNum,
IsHighlyCustomized: *cart.IsHighlyCustomized > 0,
IsSelected: *cart.IsSelected > 0,
TemplateTag: templateTag,
Logo: snapShot.Logo,
}
//是否有失效的
if description, ok := mapCartChange[cart.Id]; ok {
@ -210,7 +201,7 @@ func (l *GetCartsLogic) GetCarts(req *types.GetCartsReq, userinfo *auth.UserInfo
Meta: types.Meta{
TotalCount: total,
PageCount: int64(math.Ceil(float64(total) / float64(limit))),
CurrentPage: currentPage,
CurrentPage: req.CurrentPage,
PerPage: limit,
},
CartList: list,
@ -223,6 +214,7 @@ type GetRelationInfoReq struct {
MapSize map[int64]gmodel.FsProductSize
MapModel map[int64]gmodel.FsProductModel3d
MapTemplate map[int64]gmodel.FsProductTemplateV2
MapSizePrice map[string]gmodel.FsProductPrice
MapProduct map[int64]gmodel.FsProduct
MapResourceMetadata map[string]interface{}
}
@ -290,6 +282,15 @@ func (l *GetCartsLogic) GetRelationInfo(req GetRelationInfoReq) error {
for _, v := range templateList {
req.MapTemplate[v.Id] = v
}
//根据sizeid获取价格列表
priceList, err := l.svcCtx.AllModels.FsProductPrice.GetPriceListByProductIdsSizeIds(l.ctx, productIds, sizeIds)
if err != nil {
logx.Error(err)
return errors.New("failed to get cart`s product price list")
}
for _, v := range priceList {
req.MapSizePrice[fmt.Sprintf("%d_%d", *v.ProductId, *v.SizeId)] = v
}
return nil
}

View File

@ -16,7 +16,6 @@ type ServiceContext struct {
AllModels *gmodel.AllModelsGen
RabbitMq *initalize.RabbitMqHandle
Repositories *initalize.Repositories
AwsSession *session.Session
}
func NewServiceContext(c config.Config) *ServiceContext {
@ -25,11 +24,10 @@ func NewServiceContext(c config.Config) *ServiceContext {
Credentials: credentials.NewStaticCredentials(c.AWS.S3.Credentials.AccessKeyID, c.AWS.S3.Credentials.Secret, c.AWS.S3.Credentials.Token),
}
return &ServiceContext{
Config: c,
MysqlConn: conn,
AllModels: gmodel.NewAllModels(initalize.InitMysql(c.SourceMysql)),
RabbitMq: initalize.InitRabbitMq(c.SourceRabbitMq, nil),
AwsSession: session.Must(session.NewSession(&config)),
Config: c,
MysqlConn: conn,
AllModels: gmodel.NewAllModels(initalize.InitMysql(c.SourceMysql)),
RabbitMq: initalize.InitRabbitMq(c.SourceRabbitMq, nil),
Repositories: initalize.NewAllRepositories(&initalize.NewAllRepositorieData{
GormDB: conn,
BLMServiceUrl: &c.BLMService.Url,

View File

@ -30,7 +30,7 @@ type DeleteCartReq struct {
}
type GetCartsReq struct {
CartId int64 `form:"cart_id,optional"` //购物车ids可选
CurrentPage int `form:"current_page"` //当前页
}
type GetCartsRsp struct {
@ -53,8 +53,6 @@ type CartItem struct {
IsInvalid bool `json:"is_invalid"` //是否无效
InvalidDescription string `json:"invalid_description"` //无效原因
IsSelected bool `json:"is_selected"` //是否选中
TemplateTag string `json:"template_tag"` //模板标签
Logo string `json:"logo"`
}
type ProductInfo struct {

View File

@ -67,9 +67,9 @@ var (
//websocket连接存储
mapConnPool = sync.Map{}
//每个websocket连接入口缓冲队列长度默认值
websocketInChanLen = 2000
websocketInChanLen = 500
//每个websocket连接出口缓冲队列长度默认值
websocketOutChanLen = 2000
websocketOutChanLen = 500
//是否开启debug
openDebug = true
//允许跨域的origin
@ -192,7 +192,7 @@ func (l *DataTransferLogic) setConnPool(conn *websocket.Conn, userInfo *auth.Use
userId: userInfo.UserId,
guestId: userInfo.GuestId,
extendRenderProperty: extendRenderProperty{
renderChan: make(chan websocket_data.RenderImageReqMsg, renderChanLen),
renderChan: make(chan []byte, renderChanLen),
},
}
//保存连接

View File

@ -22,8 +22,6 @@ import (
var (
//每个websocket渲染任务缓冲队列长度默认值
renderChanLen = 500
//每个websocket渲染并发数
renderChanConcurrency = 500
)
// 渲染处理器
@ -32,25 +30,16 @@ type renderProcessor struct {
// 云渲染属性
type extendRenderProperty struct {
renderChan chan websocket_data.RenderImageReqMsg //渲染消息入口的缓冲队列
renderChan chan []byte //渲染消息入口的缓冲队列
}
// 处理分发到这里的数据
func (r *renderProcessor) allocationMessage(w *wsConnectItem, data []byte) {
logx.Info("收到渲染任务消息")
var renderImageData websocket_data.RenderImageReqMsg
if err := json.Unmarshal(data, &renderImageData); err != nil {
w.renderErrResponse(renderImageData.RenderId, renderImageData.RenderData.TemplateTag, "", "数据格式错误", renderImageData.RenderData.ProductId, w.userId, w.guestId, 0, 0, 0, 0)
logx.Error("invalid format of websocket render image message", err)
return
}
//logx.Info("开始处理渲染任务消息:", string(data))
select {
case <-w.closeChan: //已经关闭
return
case w.extendRenderProperty.renderChan <- renderImageData: //发入到缓冲队列
return
case <-time.After(time.Millisecond * 50): //超过50毫秒丢弃
w.renderErrResponse(renderImageData.RenderId, renderImageData.RenderData.TemplateTag, "", "渲染队列溢出,请稍后再发", renderImageData.RenderData.ProductId, w.userId, w.guestId, 0, 0, 0, 0)
case w.extendRenderProperty.renderChan <- data: //发入到缓冲队列
return
}
}
@ -59,37 +48,29 @@ func (r *renderProcessor) allocationMessage(w *wsConnectItem, data []byte) {
func (w *wsConnectItem) consumeRenderImageData() {
defer func() {
if err := recover(); err != nil {
logx.Error("func consumeRenderImageData panic:", err)
logx.Error("func renderImage err:", err)
}
}()
//限制并发
limitChan := make(chan struct{}, renderChanConcurrency)
defer close(limitChan)
var data []byte
for {
select {
case <-w.closeChan: //已关闭
return
case data := <-w.extendRenderProperty.renderChan: //消费数据
logx.Info("准备执行任务。。。。。")
limitChan <- struct{}{}
logx.Info("执行任务中。。。。。")
go func(d websocket_data.RenderImageReqMsg) {
defer func() {
if err := recover(); err != nil {
logx.Error("func renderImage panic:", err)
}
}()
defer func() {
<-limitChan
}()
w.renderImage(d)
}(data)
case data = <-w.extendRenderProperty.renderChan: //消费数据
w.renderImage(data)
}
}
}
// 执行渲染任务
func (w *wsConnectItem) renderImage(renderImageData websocket_data.RenderImageReqMsg) {
func (w *wsConnectItem) renderImage(data []byte) {
//logx.Info("消费渲染数据:", string(data))
var renderImageData websocket_data.RenderImageReqMsg
if err := json.Unmarshal(data, &renderImageData); err != nil {
w.renderErrResponse(renderImageData.RenderId, renderImageData.RenderData.TemplateTag, "", "数据格式错误", renderImageData.RenderData.ProductId, w.userId, w.guestId, 0, 0, 0, 0)
logx.Error("invalid format of websocket render image message", err)
return
}
if renderImageData.RenderData.Logo == "" {
w.renderErrResponse(renderImageData.RenderId, renderImageData.RenderData.TemplateTag, "", "请传入logo", renderImageData.RenderData.ProductId, w.userId, w.guestId, 0, 0, 0, 0)
return
@ -207,7 +188,6 @@ func (w *wsConnectItem) renderImage(renderImageData websocket_data.RenderImageRe
logx.Error("failed to find render resource:", err)
return
}
logx.Info("无缓存的渲染图需要unity")
} else {
//返回给客户端
w.sendRenderResultData(websocket_data.RenderImageRspMsg{

View File

@ -12,71 +12,10 @@ import "basic.api"
service info {
@handler InfoHandler
post /api/info/user(UserInfoRequest) returns (response);
@handler UserGetProfileHandler
post /api/info/user/profile(QueryProfileRequest) returns (response);
@handler UpdateProfileBaseHandler
post /api/info/user/profile/base/update(ProfileBaseRequest) returns (response);
@handler AddressDefaultHandler
post /api/info/address/default(AddressIdRequest) returns (response);
@handler AddressAddHandler
post /api/info/address/add(AddressRequest) returns (response);
@handler AddressUpdateHandler
post /api/info/address/update(AddressRequest) returns (response);
@handler AddressDeleteHandler
post /api/info/address/delete(AddressIdRequest) returns (response);
@handler AddressListHandler
get /api/info/address/list(request) returns (response);
}
type (
UserInfoRequest {
Module []string `json:"module"`
}
AddressObjectRequest {
AddressId int64 `json:"address_id"` // 地址id
AddressName string `json:"address_name"` // 地址
}
AddressIdRequest {
AddressId int64 `json:"address_id"` // 地址id
}
AddressNameRequest {
AddressName string `json:"address_name"` // 地址
}
AddressRequest {
AddressId int64 `json:"address_id,optional"`
IsDefault int64 `json:"is_default"` //是否默认
AddressName string `json:"address_name"` //收货人
FirstName string `json:"first_name"` //first_name
LastName string `json:"last_name"` //last_name
Mobile string `json:"mobile"` //手机
ZipCode string `json:"zip_code"` //邮编
Street string `json:"street"` //街道
Suite string `json:"suite"` //房号
City string `json:"city"` //城市
State string `json:"state"` //州
}
ProfileBaseRequest {
FirstName *string `json:"first_name,optional,omitempty"` // 首名
LastName *string `json:"last_name,optional,omitempty"` // 后名
UserName *string `json:"user_name,optional,omitempty"` // 用户名
Mobile *string `json:"mobile,optional,omitempty"` // 电话
Resetaurant *string `json:"resetaurant,optional,omitempty"` // 不知道干什么
Company *string `json:"company,optional,omitempty"` // 公司
}
QueryProfileRequest {
TopKey string `json:"top_key"` // 首名
}
)

View File

@ -33,8 +33,8 @@ type OrderDetailReq {
}
type CreateOrderReq {
CartIds []int64 `json:"cart_ids"`
// DeliveryMethod int64 `json:"delivery_method,optional,options=[1,2],default=2"`
CartIds []int64 `json:"cart_ids"`
DeliveryMethod int64 `json:"delivery_method,options=[1,2]"`
}
type CreatePrePaymentByDepositReq {

View File

@ -11,6 +11,9 @@ import "basic.api"
service pay {
@handler OrderPaymentIntentHandler
post /api/pay/payment-intent(OrderPaymentIntentReq) returns (response);
@handler OrderRefundHandler
post /api/pay/refund(OrderRefundReq) returns (response);
@ -25,6 +28,20 @@ type (
OrderRefundRes struct{}
)
// 生成预付款
type (
OrderPaymentIntentReq {
Sn string `form:"sn"` //订单编号
DeliveryMethod int64 `form:"delivery_method"` //发货方式
AddressId int64 `form:"address_id"` //地址id
PayMethod int64 `form:"pay_method"` //支付方式
}
OrderPaymentIntentRes {
RedirectUrl string `json:"redirect_url"`
ClientSecret string `json:"clientSecret"`
}
)
// StripeWebhook支付通知
type (
StripeWebhookReq {

View File

@ -44,15 +44,9 @@ service product {
//获取产品模型信息
@handler GetModelByPidHandler
get /api/product/get_model_by_pid(GetModelByPidReq) returns (response);
//获取产品阶梯价格列表(即将废弃)
//获取产品阶梯价格列表
@handler GetPriceByPidHandler
get /api/product/get_price_by_pid(GetPriceByPidReq) returns (response);
//获取产品阶梯价格信息
@handler GetProductStepPriceHandler
get /api/product/get_product_step_price(GetProductStepPriceReq) returns (response);
//根据产品+配件搭配计算价格
@handler CalculateProductPriceHandler
post /api/product/calculate_product_price(CalculateProductPriceReq) returns (response);
//获取产品尺寸列表
@handler GetSizeByPidHandler
get /api/product/get_size_by_pid(GetSizeByPidReq) returns (response);
@ -382,22 +376,6 @@ type PriceItem {
TotalNum int64 `json:"total_num"`
Price int64 `json:"price"`
}
//获取产品阶梯价格信息
type GetProductStepPriceReq {
ProductId int64 `form:"product_id"`
}
//根据产品+配件搭配计算价格
type CalculateProductPriceReq {
ProductId int64 `json:"product_id"`
SizeId int64 `json:"size_id"`
FittingId int64 `json:"fitting_id,optional"`
PurchaseQuantity int64 `json:"purchase_quantity"`
}
type CalculateProductPriceRsp {
ItemPrice string `json:"item_price"`
TotalPrice string `json:"total_price"`
PurchaseQuantity int64 `json:"purchase_quantity"`
}
//获取产品尺寸列表
type GetSizeByPidReq {
Pid string `form:"pid"`

View File

@ -49,7 +49,7 @@ type DeleteCartReq {
//获取购物车列表
type GetCartsReq {
CartId int64 `form:"cart_id,optional"` //购物车ids可选
CurrentPage int `form:"current_page"` //当前页
}
type GetCartsRsp {
Meta Meta `json:"meta"` //分页信息
@ -70,8 +70,6 @@ type CartItem {
IsInvalid bool `json:"is_invalid"` //是否无效
InvalidDescription string `json:"invalid_description"` //无效原因
IsSelected bool `json:"is_selected"` //是否选中
TemplateTag string `json:"template_tag"` //模板标签
Logo string `json:"logo"`
}
type ProductInfo {
ProductId int64 `json:"product_id"` //产品id

View File

@ -316,9 +316,8 @@ func (l *defaultImageHandle) LogoCombine(ctx context.Context, in *LogoCombineReq
var resultBLM constants.BLMServiceUrlResult
err = curl.NewClient(ctx, &curl.Config{
BaseUrl: *l.BLMServiceUrl,
Url: constants.BLMServiceUrlLogoCombine,
RequireTimeout: time.Second * 15,
BaseUrl: *l.BLMServiceUrl,
Url: constants.BLMServiceUrlLogoCombine,
}).PostJson(postMap, &resultBLM)
logc.Infof(ctx, "合图--算法请求--合图--结束时间:%v", time.Now().UTC())

View File

@ -15,8 +15,6 @@ import (
"time"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/stripe/stripe-go/v75"
"github.com/zeromicro/go-zero/core/logc"
"github.com/zeromicro/go-zero/core/logx"
"gorm.io/gorm"
)
@ -36,22 +34,10 @@ type (
Create(ctx context.Context, in *CreateReq) (res *CreateRes, err error)
// 预支付--定金
CreatePrePaymentByDeposit(ctx context.Context, in *CreatePrePaymentByDepositReq) (res *CreatePrePaymentByDepositRes, err error)
// 预支付--定金
CreatePrePaymentByBalance(ctx context.Context, in *CreatePrePaymentByBalanceReq) (res *CreatePrePaymentByBalanceRes, err error)
// 列表
List(ctx context.Context, in *ListReq) (res *ListRes, err error)
// 详情
Detail(ctx context.Context, in *DetailReq) (res *DetailRes, err error)
// 支付成功
PaymentSuccessful(ctx context.Context, in *PaymentSuccessfulReq) (res *PaymentSuccessfulRes, err error)
}
PayInfo struct {
PayMethod string `json:"pay_method"` // 交易方式
PayTime time.Time `json:"pay_time"` // 支付时间
Status gmodel.PayStatus `json:"status"` // 当前状态
StatusLink []gmodel.PayStatus `json:"status_link"` // 状态链路
TradeNo string `json:"trade_no"` // 支付交易号
}
OrderAddress struct {
@ -75,16 +61,6 @@ type (
Amount int64 `json:"amount"` // 金额
Label string `json:"label"` // 标签
}
/* 支付成功 */
PaymentSuccessfulReq struct {
EventId string
PaymentMethod string
Charge *stripe.Charge
}
PaymentSuccessfulRes struct{}
/* 支付成功 */
/* 预支付--定金 */
CreatePrePaymentByDepositReq struct {
StripeKey string `json:"stripe_key"`
@ -93,7 +69,7 @@ type (
UserId int64 `json:"user_id"`
OrderSn string `json:"order_sn"`
DeliveryMethod int64 `json:"delivery_method"`
DeliveryAddress *OrderAddress `json:"delivery_address"`
DeliveryAddress *OrderAddress `json:"delivery_address"` // 收货地址
}
CreatePrePaymentByDepositRes struct {
ErrorCode basic.StatusResponse
@ -102,21 +78,6 @@ type (
}
/* 预支付--定金 */
/* 预支付--尾款 */
CreatePrePaymentByBalanceReq struct {
StripeKey string `json:"stripe_key"`
Currency string `json:"currency"`
Country string `json:"country"`
UserId int64 `json:"user_id"`
OrderSn string `json:"order_sn"`
}
CreatePrePaymentByBalanceRes struct {
ErrorCode basic.StatusResponse
OrderDetail gmodel.OrderDetail
OrderPay OrderPay
}
/* 预支付--尾款 */
/* 下单 */
CreateReq struct {
ExpectedDeliveryTime time.Time `json:"expected_delivery_time"` // 预计到货时间
@ -161,312 +122,6 @@ type (
/* 列表 */
)
// 支付成功
func (d *defaultOrder) PaymentSuccessful(ctx context.Context, in *PaymentSuccessfulReq) (res *PaymentSuccessfulRes, err error) {
var orderSn string
var payStage string
var ok bool
var card string
var brand string
var country string
var currency string
var tradeSn string
var payAmount int64
var payTitle string
var payTime time.Time
var paymentMethod int64 = 1
if in.PaymentMethod == "stripe" {
paymentMethod = 1
}
if in.PaymentMethod == "paypal" {
paymentMethod = 2
}
if in.Charge != nil {
charge := in.Charge
orderSn, ok = charge.Metadata["order_sn"]
if !ok || orderSn == "" {
err = errors.New("order_sn is empty")
logc.Errorf(ctx, "PaymentSuccessful failed param, eventId:%s,err:%v", in.EventId, err)
return &PaymentSuccessfulRes{}, err
}
payStage, ok = charge.Metadata["pay_stage"]
if !ok || payStage == "" {
err = errors.New("pay_stage is empty")
logc.Errorf(ctx, "PaymentSuccessful failed param, eventId:%s,err:%v", in.EventId, err)
return &PaymentSuccessfulRes{}, err
}
country, ok = charge.Metadata["country"]
if !ok || country == "" {
err = errors.New("country is empty")
logc.Errorf(ctx, "PaymentSuccessful failed param, eventId:%s,err:%v", in.EventId, err)
return &PaymentSuccessfulRes{}, err
}
if charge.PaymentMethodDetails != nil {
if charge.PaymentMethodDetails.Card != nil {
if charge.PaymentMethodDetails.Card.Last4 != "" {
card = charge.PaymentMethodDetails.Card.Last4
}
if charge.PaymentMethodDetails.Card.Brand != "" {
brand = string(charge.PaymentMethodDetails.Card.Brand)
}
}
}
if charge.Currency != "" {
currency = string(charge.Currency)
}
tradeSn = charge.ID
payAmount = charge.Amount
payTitle = charge.Description
payTime = time.Unix(charge.Created, 0).UTC()
}
err = d.MysqlConn.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
var orderInfo gmodel.FsOrder
result := tx.Where("is_del = ?", 0).Where("order_sn = ?", orderSn).Take(&orderInfo)
err = result.Error
if err != nil {
logx.Errorf("PaymentSuccessful failed order Take, eventId:%s,err: %v", in.EventId, err)
return err
}
ress, err := d.OrderDetailHandler(ctx, &orderInfo, 0)
if err != nil {
logx.Errorf("PaymentSuccessful failed DetailOrderDetailHandler,eventId:%s, err: %v", in.EventId, err)
return err
}
var ntime = time.Now().UTC()
if (payStage == "deposit" && *orderInfo.PayStatus == int64(constants.ORDERPAYSTATUSUNPAIDDEPOSIT)) || (payStage == "remaining_balance" && *orderInfo.PayStatus == int64(constants.ORDERPAYSTATUSPAIDDEPOSIT)) {
var payStatus = int64(constants.PAYSTATUSPAID)
var payStageInt int64
var orderPayStatusCode constants.OrderPayStatusCode
// 订单状态--当前
var status gmodel.OrderStatus
var statusLink []gmodel.OrderStatus
var uOrderDetail = make(map[string]interface{})
var payInfo PayInfo
payInfo.PayMethod = in.PaymentMethod
payInfo.PayTime = payTime
payInfo.TradeNo = tradeSn
// 当前状态
var statusCode constants.OrderStatusCode
var statusCodePre constants.OrderStatusCode
if payStage == "deposit" {
if *orderInfo.DeliveryMethod == constants.DELIVERYMETHODDIRECTMAIL {
// 直邮
statusCode = constants.ORDER_STATUS_DIRECTMAIL_ORDERED
}
if *orderInfo.DeliveryMethod == constants.DELIVERYMETHODDSCLOUDSTORE {
// 云仓
statusCode = constants.ORDER_STATUS_CLOUDSTORE_ORDERED
}
payStageInt = 1
orderPayStatusCode = constants.ORDERPAYSTATUSPAIDDEPOSIT
status = gmodel.OrderStatus{
Ctime: &ntime,
Utime: &ntime,
StatusCode: statusCode,
StatusTitle: constants.OrderStatusMessage[statusCode],
}
statusLink = order.UpdateOrderStatusLink(ress.OrderDetailOriginal.OrderInfo.StatusLink, gmodel.OrderStatus{
Ctime: &ntime,
Utime: &ntime,
StatusCode: statusCode,
StatusTitle: constants.OrderStatusMessage[statusCode],
})
payInfo.Status = gmodel.PayStatus{
StatusCode: int64(constants.PAYSTATUSPAID),
StatusTitle: constants.PayStatusMessage[constants.PAYSTATUSPAID],
}
payInfo.StatusLink = append(ress.OrderDetail.OrderAmount.Deposit.StatusLink, payInfo.Status)
uOrderDetail["order_amount"] = struct {
Deposit PayInfo `json:"deposit"`
}{
Deposit: payInfo,
}
}
if payStage == "remaining_balance" {
if *orderInfo.DeliveryMethod == constants.DELIVERYMETHODDIRECTMAIL {
// 直邮
statusCodePre = constants.ORDER_STATUS_DIRECTMAIL_ORDERED
statusCode = constants.ORDER_STATUS_DIRECTMAIL_ORDEREDMAINING
}
if *orderInfo.DeliveryMethod == constants.DELIVERYMETHODDSCLOUDSTORE {
// 云仓
statusCodePre = constants.ORDER_STATUS_CLOUDSTORE_ORDERED
statusCode = constants.ORDER_STATUS_CLOUDSTORE_ORDEREDMAINING
}
payStageInt = 2
orderPayStatusCode = constants.ORDERPAYSTATUSPAIDDREMAINING
var statusChildren []*gmodel.OrderStatus
// 更新订单状态链路--子状态
for oStatusLinkKey, oStatusLink := range ress.OrderDetail.OrderInfo.StatusLink {
if oStatusLink.StatusCode == statusCodePre {
statusChildren = append(oStatusLink.Children, &gmodel.OrderStatus{
Ctime: &ntime,
Utime: &ntime,
StatusCode: statusCode,
StatusTitle: constants.OrderStatusMessage[statusCode],
})
ress.OrderDetail.OrderInfo.StatusLink[oStatusLinkKey].Children = statusChildren
}
}
statusLink = ress.OrderDetail.OrderInfo.StatusLink
if ress.OrderDetail.OrderInfo.Status.StatusCode == constants.ORDER_STATUS_DIRECTMAIL_ORDERED || ress.OrderDetail.OrderInfo.Status.StatusCode == constants.ORDER_STATUS_CLOUDSTORE_ORDERED {
status = ress.OrderDetail.OrderInfo.Status
status.Children = statusChildren
}
payInfo.Status = gmodel.PayStatus{
StatusCode: int64(constants.PAYSTATUSPAID),
StatusTitle: constants.PayStatusMessage[constants.PAYSTATUSPAID],
}
payInfo.StatusLink = append(ress.OrderDetail.OrderAmount.RemainingBalance.StatusLink, payInfo.Status)
uOrderDetail["order_amount"] = struct {
RemainingBalance PayInfo `json:"remaining_balance"`
}{
RemainingBalance: payInfo,
}
}
// 新增交易信息
tx.Create(&gmodel.FsOrderTrade{
UserId: orderInfo.UserId,
OrderSn: &orderSn,
OrderSource: orderInfo.OrderSource,
TradeSn: &tradeSn,
PayAmount: &payAmount,
PayStatus: &payStatus,
PaymentMethod: &paymentMethod,
PayStage: &payStageInt,
CardSn: &card,
CardBrand: &brand,
Country: &country,
Currency: &currency,
Ctime: &ntime,
Utime: &ntime,
PayTitle: &payTitle,
})
var sql string
if *orderInfo.Status == int64(constants.ORDER_STATUS_UNPAIDDEPOSIT) {
sql = fmt.Sprintf(", `utime` = '%s', `pay_status` = %d, `status` = %d ", ntime, orderPayStatusCode, statusCode)
} else {
sql = fmt.Sprintf(", `utime` = '%s', `pay_status` = %d", ntime, orderPayStatusCode)
}
// 更新订单信息
uOrderDetail["pay_status"] = orderPayStatusCode
uOrderDetail["order_info"] = struct {
Utime *time.Time `json:"utime"`
Status gmodel.OrderStatus `json:"status"`
StatusLink []gmodel.OrderStatus `json:"status_link"`
}{
Utime: &ntime,
Status: status,
StatusLink: statusLink,
}
fmt.Printf("uOrderDetail :%+v", uOrderDetail)
if len(uOrderDetail) > 0 {
err = fssql.MetadataOrderPATCH(d.MysqlConn, sql, orderSn, gmodel.FsOrder{}, uOrderDetail, "id = ?", orderInfo.Id)
if err != nil {
logx.Errorf("PaymentSuccessful failed MetadataOrderPATCH,eventId:%s, err: %v", in.EventId, err)
return err
}
}
}
return nil
})
return &PaymentSuccessfulRes{}, nil
}
// 预支付--尾款
func (d *defaultOrder) CreatePrePaymentByBalance(ctx context.Context, in *CreatePrePaymentByBalanceReq) (res *CreatePrePaymentByBalanceRes, err error) {
var errorCode basic.StatusResponse
var order gmodel.FsOrder
model := d.MysqlConn.Where("is_del = ?", 0)
if in.UserId != 0 {
model.Where("user_id = ?", in.UserId)
}
if in.OrderSn != "" {
model.Where("order_sn = ?", in.OrderSn)
}
result := model.Take(&order)
if result.Error != nil {
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
errorCode = *basic.CodeErrOrderCreatePrePaymentInfoNoFound
} else {
errorCode = *basic.CodeServiceErr
}
logx.Errorf("create prePayment balance failed, err: %v", err)
return &CreatePrePaymentByBalanceRes{
ErrorCode: errorCode,
}, result.Error
}
// 非未支付
if *order.PayStatus != int64(constants.ORDERPAYSTATUSPAIDDEPOSIT) {
errorCode = *basic.CodeErrOrderCreatePrePaymentNoUnPaid
err = errors.New("order balance pay status is not unPaid")
logx.Errorf("create prePayment balance failed, err: %v", err)
return &CreatePrePaymentByBalanceRes{
ErrorCode: errorCode,
}, err
}
ress, err := d.OrderDetailHandler(ctx, &order, 1)
if err != nil {
logx.Errorf("create prePayment balance failed DetailOrderDetailHandler, err: %v", err)
errorCode = *basic.CodeServiceErr
return &CreatePrePaymentByBalanceRes{
ErrorCode: errorCode,
}, err
}
// 支付初始化
amount := int64(ress.OrderDetailOriginal.OrderAmount.RemainingBalance.PayAmount.Current.CurrentAmount.(float64) / float64(10))
payConfig := &pay.Config{}
payConfig.Stripe.PayType = "intent"
payConfig.Stripe.Key = in.StripeKey
var metadata = make(map[string]string, 2)
metadata["model"] = "product_order"
metadata["order_sn"] = in.OrderSn
metadata["pay_stage"] = "remaining_balance"
metadata["country"] = in.Country
var generatePrepaymentReq = &pay.GeneratePrepaymentReq{
Metadata: metadata,
ProductName: "支付尾款后期统一调整",
Amount: amount,
Currency: "usd",
Quantity: 1,
ProductDescription: "支付尾款后期统一调整",
}
payDriver := pay.NewPayDriver(1, payConfig)
prepaymentRes, err := payDriver.GeneratePrepayment(generatePrepaymentReq)
if err != nil {
logx.Errorf("create prePayment balance failed GeneratePrepayment, err: %v", err)
errorCode = *basic.CodeServiceErr
return &CreatePrePaymentByBalanceRes{
ErrorCode: errorCode,
}, nil
}
return &CreatePrePaymentByBalanceRes{
OrderDetail: ress.OrderDetail,
OrderPay: OrderPay{
ClientSecret: prepaymentRes.ClientSecret,
Country: in.Country,
Currency: in.Currency,
Method: payConfig.Stripe.PayType,
OrderSn: in.OrderSn,
PayStage: 2,
Total: OrderPayTotal{
Amount: amount,
Label: "支付尾款后期统一调整",
},
},
}, nil
}
// 预支付--定金
func (d *defaultOrder) CreatePrePaymentByDeposit(ctx context.Context, in *CreatePrePaymentByDepositReq) (res *CreatePrePaymentByDepositRes, err error) {
var errorCode basic.StatusResponse
@ -493,7 +148,7 @@ func (d *defaultOrder) CreatePrePaymentByDeposit(ctx context.Context, in *Create
// 非未支付
if *order.PayStatus != int64(constants.ORDERPAYSTATUSUNPAIDDEPOSIT) {
errorCode = *basic.CodeErrOrderCreatePrePaymentNoUnPaid
errorCode = *basic.CodeErrOrderCreatePrePaymentInfoNoFound
err = errors.New("order pay status is not unPaidDeposit")
logx.Errorf("create prePayment deposit failed, err: %v", err)
return &CreatePrePaymentByDepositRes{
@ -506,8 +161,6 @@ func (d *defaultOrder) CreatePrePaymentByDeposit(ctx context.Context, in *Create
ctime := *order.Ctime
ctimeTimeOut := ctime.Add(30 * time.Minute).UTC().Unix()
ntimeTimeOut := ntime.Unix()
// 测试超时支付不限制
if ctimeTimeOut == ntimeTimeOut {
errorCode = *basic.CodeErrOrderCreatePrePaymentTimeout
err = errors.New("order pay timeout")
@ -517,7 +170,7 @@ func (d *defaultOrder) CreatePrePaymentByDeposit(ctx context.Context, in *Create
}, err
}
ress, err := d.OrderDetailHandler(ctx, &order, 0)
ress, err := d.OrderDetailHandler(ctx, &order)
if err != nil {
logx.Errorf("create prePayment deposit failed DetailOrderDetailHandler, err: %v", err)
errorCode = *basic.CodeServiceErr
@ -529,11 +182,13 @@ func (d *defaultOrder) CreatePrePaymentByDeposit(ctx context.Context, in *Create
var uOrderDetail = make(map[string]interface{})
var orderAddress *gmodel.OrderAddress
if in.DeliveryMethod == constants.DELIVERYMETHODDIRECTMAIL {
orderAddress = &gmodel.OrderAddress{
Name: in.DeliveryAddress.Name,
Mobile: in.DeliveryAddress.Mobile,
Address: in.DeliveryAddress.Address,
if in.DeliveryAddress != nil {
if in.DeliveryAddress.Name != ress.OrderDetailOriginal.DeliveryAddress.Name || in.DeliveryAddress.Address != ress.OrderDetail.DeliveryAddress.Address || in.DeliveryAddress.Mobile != ress.OrderDetail.DeliveryAddress.Mobile {
orderAddress = &gmodel.OrderAddress{
Name: in.DeliveryAddress.Name,
Mobile: in.DeliveryAddress.Mobile,
Address: in.DeliveryAddress.Address,
}
}
}
@ -568,7 +223,31 @@ func (d *defaultOrder) CreatePrePaymentByDeposit(ctx context.Context, in *Create
}
}
}
// 支付初始化
amount := int64(ress.OrderDetailOriginal.OrderAmount.Deposit.PayAmount.Current.CurrentAmount.(float64) / float64(10))
payConfig := &pay.Config{}
payConfig.Stripe.PayType = "intent"
payConfig.Stripe.Key = in.StripeKey
var generatePrepaymentReq = &pay.GeneratePrepaymentReq{
OrderSn: in.OrderSn,
ProductName: "支付标题",
Amount: amount,
Currency: "usd",
Quantity: 1,
ProductDescription: "支付描述",
}
payDriver := pay.NewPayDriver(1, payConfig)
prepaymentRes, err := payDriver.GeneratePrepayment(generatePrepaymentReq)
if err != nil {
logx.Errorf("create prePayment deposit failed GeneratePrepayment, err: %v", err)
errorCode = *basic.CodeServiceErr
return &CreatePrePaymentByDepositRes{
ErrorCode: errorCode,
}, nil
} else {
//uOrderDetail["order_amount"] = map[type]type
}
if len(uOrderDetail) > 0 {
err = fssql.MetadataOrderPATCH(d.MysqlConn, sql, in.OrderSn, gmodel.FsOrder{}, uOrderDetail, "id = ?", order.Id)
if err != nil {
@ -584,34 +263,6 @@ func (d *defaultOrder) CreatePrePaymentByDeposit(ctx context.Context, in *Create
ress.OrderDetail.OrderInfo.DeliveryMethod = in.DeliveryMethod
ress.OrderDetail.DeliveryAddress = orderAddress
// 支付初始化
amount := int64(ress.OrderDetailOriginal.OrderAmount.Deposit.PayAmount.Current.CurrentAmount.(float64) / float64(10))
payConfig := &pay.Config{}
payConfig.Stripe.PayType = "intent"
payConfig.Stripe.Key = in.StripeKey
var metadata = make(map[string]string, 2)
metadata["model"] = "product_order"
metadata["order_sn"] = in.OrderSn
metadata["pay_stage"] = "deposit"
metadata["country"] = in.Country
var generatePrepaymentReq = &pay.GeneratePrepaymentReq{
Metadata: metadata,
ProductName: "支付首款",
Amount: amount,
Currency: "usd",
Quantity: 1,
ProductDescription: "支付首款",
}
payDriver := pay.NewPayDriver(1, payConfig)
prepaymentRes, err := payDriver.GeneratePrepayment(generatePrepaymentReq)
if err != nil {
logx.Errorf("create prePayment deposit failed GeneratePrepayment, err: %v", err)
errorCode = *basic.CodeServiceErr
return &CreatePrePaymentByDepositRes{
ErrorCode: errorCode,
}, nil
}
return &CreatePrePaymentByDepositRes{
OrderDetail: ress.OrderDetail,
OrderPay: OrderPay{
@ -669,7 +320,7 @@ func (d *defaultOrder) List(ctx context.Context, in *ListReq) (res *ListRes, err
return nil, result.Error
}
for _, order := range orderList {
ress, err := d.OrderDetailHandler(ctx, &order, 1)
ress, err := d.OrderDetailHandler(ctx, &order)
if err != nil {
return nil, err
}
@ -714,21 +365,19 @@ func (d *defaultOrder) Detail(ctx context.Context, in *DetailReq) (res *DetailRe
}
// 是否超时支付
if *order.Status == int64(constants.ORDER_STATUS_UNPAIDDEPOSIT) {
ctime := *order.Ctime
ctimeTimeOut := ctime.Add(30 * time.Minute).UTC().Unix()
ntimeTimeOut := time.Now().UTC().Unix()
if ctimeTimeOut < ntimeTimeOut {
errorCode = *basic.CodeErrOrderCreatePrePaymentTimeout
err = errors.New("order pay timeout")
logx.Errorf("order detail failed, err: %v", err)
return &DetailRes{
ErrorCode: errorCode,
}, err
}
ctime := *order.Ctime
ctimeTimeOut := ctime.Add(30 * time.Minute).UTC().Unix()
ntimeTimeOut := time.Now().UTC().Unix()
if ctimeTimeOut < ntimeTimeOut {
errorCode = *basic.CodeErrOrderCreatePrePaymentTimeout
err = errors.New("order pay timeout")
logx.Errorf("order detail failed, err: %v", err)
return &DetailRes{
ErrorCode: errorCode,
}, err
}
ress, err := d.OrderDetailHandler(ctx, &order, 1)
ress, err := d.OrderDetailHandler(ctx, &order)
if err != nil {
logx.Errorf("order detail failed, err: %v", err)
errorCode = *basic.CodeServiceErr
@ -754,8 +403,8 @@ func (d *defaultOrder) Create(ctx context.Context, in *CreateReq) (res *CreateRe
resShoppingCartFind := tx.Table(gmodel.NewFsShoppingCartModel(tx).TableName()).
Preload("ShoppingCartProduct", func(dbPreload *gorm.DB) *gorm.DB {
return dbPreload.Table(gmodel.NewFsProductModel(tx).TableName()).Preload("CoverResource")
}).
Preload("ShoppingCartProductModel3d").
}).Preload("ShoppingCartProductPriceList").
Preload("ShoppingCartProductModel3dList").
Preload("ShoppingCartProductModel3dFitting").
Where("id IN ?", in.CartIds).
Where("user_id = ?", in.UserId).
@ -816,6 +465,10 @@ func (d *defaultOrder) Create(ctx context.Context, in *CreateReq) (res *CreateRe
for _, shoppingCart := range shoppingCartList {
// 购物车快照
var shoppingCartSnapshot gmodel.CartSnapshot
// 购物车商品价格
var shoppingCartProductPrice *gmodel.FsProductPrice
// 购物车商品模型
var shoppingCartProductModel3d *gmodel.FsProductModel3d
if shoppingCart.Snapshot != nil {
json.Unmarshal([]byte(*shoppingCart.Snapshot), &shoppingCartSnapshot)
}
@ -825,21 +478,69 @@ func (d *defaultOrder) Create(ctx context.Context, in *CreateReq) (res *CreateRe
errorCode.Message = "create order failed, product '" + shoppingCartSnapshot.ProductInfo.ProductName + "'is absent"
return errors.New(errorCode.Message)
}
var stepPriceJson gmodel.StepPriceJsonStruct
if shoppingCart.ShoppingCartProductModel3d.StepPrice != nil {
err = json.Unmarshal(*shoppingCart.ShoppingCartProductModel3d.StepPrice, &stepPriceJson)
if err != nil {
return err
}
// 商品价格异常
if len(shoppingCart.ShoppingCartProductPriceList) == 0 {
errorCode = *basic.CodeErrOrderCreatProductPriceAbsent
errorCode.Message = "create order failed, price of product '" + shoppingCartSnapshot.ProductInfo.ProductName + "'is absent"
return errors.New(errorCode.Message)
} else {
var isProductPrice bool
for _, shoppingCartProductPriceInfo := range shoppingCart.ShoppingCartProductPriceList {
if *shoppingCart.SizeId == *shoppingCartProductPriceInfo.SizeId {
shoppingCartProductPrice = shoppingCartProductPriceInfo
isProductPrice = true
break
}
}
if !isProductPrice {
errorCode = *basic.CodeErrOrderCreatProductPriceAbsent
errorCode.Message = "create order failed, price of product '" + shoppingCartSnapshot.ProductInfo.ProductName + "'is absent"
return errors.New(errorCode.Message)
}
shoppingCart.ShoppingCartProductPriceList = []*gmodel.FsProductPrice{shoppingCartProductPrice}
}
// 商品模型异常
if len(shoppingCart.ShoppingCartProductModel3dList) == 0 {
errorCode = *basic.CodeErrOrderCreatProductAccessoryAbsent
errorCode.Message = "create order failed, accessoryof product '" + shoppingCartSnapshot.ProductInfo.ProductName + "'is absent"
return errors.New(errorCode.Message)
} else {
var isProductModel bool
for _, shoppingCartProductModel3dInfo := range shoppingCart.ShoppingCartProductModel3dList {
if *shoppingCart.SizeId == *shoppingCartProductModel3dInfo.SizeId {
shoppingCartProductModel3d = shoppingCartProductModel3dInfo
isProductModel = true
break
}
}
if !isProductModel {
errorCode = *basic.CodeErrOrderCreatProductAccessoryAbsent
errorCode.Message = "create order failed, accessory of product '" + shoppingCartSnapshot.ProductInfo.ProductName + "'is absent"
return errors.New(errorCode.Message)
}
shoppingCart.ShoppingCartProductModel3dList = []*gmodel.FsProductModel3d{shoppingCartProductModel3d}
}
var stepNum []int
var stepPrice []int
if *shoppingCartProductPrice.StepNum == "" {
errorCode = *basic.CodeErrOrderCreatProductPriceAbsent
errorCode.Message = "create order failed, step num of product '" + shoppingCartSnapshot.ProductInfo.ProductName + "'is failed"
return errors.New(errorCode.Message)
} else {
json.Unmarshal([]byte(*shoppingCartProductPrice.StepNum), &stepNum)
}
if *shoppingCartProductPrice.StepPrice == "" {
errorCode = *basic.CodeErrOrderCreatProductPriceAbsent
errorCode.Message = "create order failed, step price of product '" + shoppingCartSnapshot.ProductInfo.ProductName + "'is failed"
return errors.New("shoppingCartProductModel3d.StepPrice nil")
return errors.New(errorCode.Message)
} else {
json.Unmarshal([]byte(*shoppingCartProductPrice.StepPrice), &stepPrice)
}
/* 计算价格 */
productTotalPrice, productPrice, err := NewShoppingCart(tx, nil, nil).CaculateStepPrice(*shoppingCart.PurchaseQuantity, stepPriceJson, *shoppingCart.ShoppingCartProductModel3dFitting.Price)
productPrice, productTotalPrice, stepNum, stepPrice, err := NewShoppingCart(tx, nil, nil).CaculateCartPrice(*shoppingCart.PurchaseQuantity, shoppingCartProductPrice, *shoppingCart.ShoppingCartProductModel3dFitting.Price)
if err != nil {
errorCode = *basic.CodeErrOrderCreatProductPriceAbsent
errorCode.Message = "create order failed, step price of product '" + shoppingCartSnapshot.ProductInfo.ProductName + "'is failed"
@ -855,32 +556,7 @@ func (d *defaultOrder) Create(ctx context.Context, in *CreateReq) (res *CreateRe
if shoppingCart.ShoppingCartProduct.CoverResource != nil && shoppingCart.ShoppingCartProduct.CoverResource.Metadata != nil {
json.Unmarshal(*shoppingCart.ShoppingCartProduct.CoverResource.Metadata, &productCoverMetadata)
}
snapshot, err := d.OrderDetailSnapshotHandler(ctx, shoppingCart.FsShoppingCart.Snapshot)
if err != nil {
return err
}
var shoppingCartSnapshotInter = &gmodel.FsShoppingCartData{
Id: shoppingCart.FsShoppingCart.Id,
UserId: shoppingCart.FsShoppingCart.UserId,
ProductId: shoppingCart.FsShoppingCart.ProductId,
TemplateId: shoppingCart.FsShoppingCart.TemplateId,
ModelId: shoppingCart.FsShoppingCart.ModelId,
SizeId: shoppingCart.FsShoppingCart.SizeId,
LightId: shoppingCart.FsShoppingCart.LightId,
FittingId: shoppingCart.FsShoppingCart.FittingId,
PurchaseQuantity: shoppingCart.FsShoppingCart.PurchaseQuantity,
Snapshot: &snapshot,
SnapshotData: shoppingCart.FsShoppingCart.Snapshot,
IsSelected: shoppingCart.FsShoppingCart.IsSelected,
IsHighlyCustomized: shoppingCart.FsShoppingCart.IsHighlyCustomized,
Ctime: shoppingCart.FsShoppingCart.Ctime,
Utime: shoppingCart.FsShoppingCart.Utime,
}
var purchaseQuantityInter = gmodel.PurchaseQuantity{
Current: *shoppingCart.PurchaseQuantity,
Initiate: *shoppingCart.PurchaseQuantity,
}
productInter := gmodel.OrderProduct{
orderProductList = append(orderProductList, gmodel.OrderProduct{
TotalPrice: order.GetAmountInfo(order.GetAmountInfoReq{
ExchangeRate: in.ExchangeRate,
Initiate: productTotalPrice,
@ -889,7 +565,7 @@ func (d *defaultOrder) Create(ctx context.Context, in *CreateReq) (res *CreateRe
OriginalCurrency: in.OriginalCurrency,
}),
ExpectedDeliveryTime: &in.ExpectedDeliveryTime,
PurchaseQuantity: purchaseQuantityInter,
PurchaseQuantity: *shoppingCart.PurchaseQuantity,
ProductID: *shoppingCart.ProductId,
ProductCover: *shoppingCart.ShoppingCartProduct.Cover,
ProductCoverMetadata: productCoverMetadata,
@ -902,7 +578,7 @@ func (d *defaultOrder) Create(ctx context.Context, in *CreateReq) (res *CreateRe
OriginalCurrency: in.OriginalCurrency,
}),
ProductSnapshot: shoppingCart.ShoppingCartProduct,
ShoppingCartSnapshot: shoppingCartSnapshotInter,
ShoppingCartSnapshot: &shoppingCart.FsShoppingCart,
ProductSn: *shoppingCart.ShoppingCartProduct.Sn,
DiyInformation: &shoppingCartSnapshot.UserDiyInformation,
FittingInfo: &gmodel.OrderProductFittingInfo{
@ -917,9 +593,9 @@ func (d *defaultOrder) Create(ctx context.Context, in *CreateReq) (res *CreateRe
Cm: shoppingCartSnapshot.SizeInfo.Cm,
},
},
StepNum: stepNum,
IsHighlyCustomized: *shoppingCart.IsHighlyCustomized,
}
orderProductList = append(orderProductList, productInter)
})
}
subtotal = order.GetAmountInfo(order.GetAmountInfoReq{
@ -945,7 +621,6 @@ func (d *defaultOrder) Create(ctx context.Context, in *CreateReq) (res *CreateRe
StatusCode: int64(constants.PAYSTATUSUNPAID),
StatusTitle: constants.PayStatusMessage[constants.PAYSTATUSUNPAID],
},
StatusLink: make([]gmodel.PayStatus, 0),
PayAmount: order.GetAmountInfo(order.GetAmountInfoReq{
ExchangeRate: in.ExchangeRate,
Initiate: depositInt,
@ -962,7 +637,6 @@ func (d *defaultOrder) Create(ctx context.Context, in *CreateReq) (res *CreateRe
StatusCode: int64(constants.PAYSTATUSUNPAID),
StatusTitle: constants.PayStatusMessage[constants.PAYSTATUSUNPAID],
},
StatusLink: make([]gmodel.PayStatus, 0),
PayAmount: order.GetAmountInfo(order.GetAmountInfoReq{
ExchangeRate: in.ExchangeRate,
Initiate: remainingBalanceInt,
@ -985,8 +659,8 @@ func (d *defaultOrder) Create(ctx context.Context, in *CreateReq) (res *CreateRe
var status = gmodel.OrderStatus{
Ctime: &nowTime,
Utime: &nowTime,
StatusCode: constants.ORDER_STATUS_UNPAIDDEPOSIT,
StatusTitle: constants.OrderStatusMessage[constants.ORDER_STATUS_UNPAIDDEPOSIT],
StatusCode: constants.ORDERSTATUSUNPAIDDEPOSIT,
StatusTitle: constants.OrderStatusMessage[constants.ORDERSTATUSUNPAIDDEPOSIT],
}
// 订单状态--链路
var statusLink = order.GenerateOrderStatusLink(in.DeliveryMethod, nowTime, in.ExpectedDeliveryTime)
@ -1045,68 +719,8 @@ func (d *defaultOrder) Create(ctx context.Context, in *CreateReq) (res *CreateRe
}, nil
}
// 处理订单购物车快照
func (d *defaultOrder) OrderDetailSnapshotHandler(ctx context.Context, req *string) (res map[string]interface{}, err error) {
var snapshot map[string]interface{}
json.Unmarshal([]byte(*req), &snapshot)
snapshotFittingInfoData, snapshotFittingInfoEx := snapshot["fitting_info"]
var fittingInfoMap map[string]interface{}
if snapshotFittingInfoEx {
var snapshotFittingInfoJson map[string]interface{}
var fittingName string
snapshotFittingInfo := snapshotFittingInfoData.(map[string]interface{})
snapshotFittingInfoJsonData, snapshotFittingInfoJsonEx := snapshotFittingInfo["fitting_json"]
if snapshotFittingInfoJsonEx {
json.Unmarshal([]byte(snapshotFittingInfoJsonData.(string)), &snapshotFittingInfoJson)
}
fittingNameData, fittingNameEx := snapshotFittingInfo["fitting_name"]
if fittingNameEx {
fittingName = fittingNameData.(string)
}
fittingInfoMap = make(map[string]interface{}, 2)
fittingInfoMap["fitting_json"] = snapshotFittingInfoJson
fittingInfoMap["fitting_name"] = fittingName
}
snapshot["fitting_info"] = fittingInfoMap
snapshotModelInfoData, snapshotModelInfoEx := snapshot["model_info"]
var modelInfoMap map[string]interface{}
if snapshotModelInfoEx {
var snapshotModelInfoJson map[string]interface{}
snapshotModelInfo := snapshotModelInfoData.(map[string]interface{})
snapshotModelInfoJsonData, snapshotModelInfoJsonEx := snapshotModelInfo["model_json"]
if snapshotModelInfoJsonEx {
json.Unmarshal([]byte(snapshotModelInfoJsonData.(string)), &snapshotModelInfoJson)
}
modelInfoMap = make(map[string]interface{}, 1)
modelInfoMap["model_json"] = snapshotModelInfoJson
}
snapshot["model_info"] = modelInfoMap
snapshotTemplateInfoData, snapshotTemplateInfoEx := snapshot["template_info"]
var templateInfoMap map[string]interface{}
if snapshotTemplateInfoEx {
var snapshotTemplateInfoJson map[string]interface{}
var templateTag string
snapshotTemplateInfo := snapshotTemplateInfoData.(map[string]interface{})
snapshotTemplateInfoJsonData, snapshotTemplateInfoJsonEx := snapshotTemplateInfo["template_json"]
if snapshotTemplateInfoJsonEx {
json.Unmarshal([]byte(snapshotTemplateInfoJsonData.(string)), &snapshotTemplateInfoJson)
}
templateTagData, templateTagEx := snapshotTemplateInfo["template_tag"]
if templateTagEx {
templateTag = templateTagData.(string)
}
templateInfoMap = make(map[string]interface{}, 2)
templateInfoMap["template_json"] = snapshotTemplateInfoJson
templateInfoMap["template_tag"] = templateTag
}
snapshot["template_info"] = templateInfoMap
return snapshot, nil
}
// 详情处理
func (d *defaultOrder) OrderDetailHandler(ctx context.Context, orderInfo *gmodel.FsOrder, original int64) (res *DetailRes, err error) {
func (d *defaultOrder) OrderDetailHandler(ctx context.Context, orderInfo *gmodel.FsOrder) (res *DetailRes, err error) {
var orderDetail gmodel.OrderDetail
err = json.Unmarshal(*orderInfo.Metadata, &orderDetail)
@ -1115,21 +729,18 @@ func (d *defaultOrder) OrderDetailHandler(ctx context.Context, orderInfo *gmodel
return nil, err
}
orderDetailOriginal := orderDetail
if original == 1 {
for orderProductKey, orderProduct := range orderDetail.OrderProduct {
orderDetail.OrderProduct[orderProductKey].TotalPrice = order.GetAmountInfoFormat(&orderProduct.TotalPrice)
orderDetail.OrderProduct[orderProductKey].TotalPrice = order.GetAmountInfoFormat(&orderProduct.TotalPrice)
orderDetail.OrderProduct[orderProductKey].PurchaseQuantity = order.GetPurchaseQuantity(&orderProduct.PurchaseQuantity)
orderDetail.OrderProduct[orderProductKey].ProductSnapshot = nil
orderDetail.OrderProduct[orderProductKey].ShoppingCartSnapshot.SnapshotData = nil
}
orderDetail.OrderInfo.StatusLink = order.GetOrderStatusLinkUser(orderDetail.OrderInfo.DeliveryMethod, orderDetail.OrderInfo.StatusLink)
orderDetail.OrderAmount.Deposit.PayAmount = order.GetAmountInfoFormat(&orderDetail.OrderAmount.Deposit.PayAmount)
orderDetail.OrderAmount.RemainingBalance.PayAmount = order.GetAmountInfoFormat(&orderDetail.OrderAmount.RemainingBalance.PayAmount)
orderDetail.OrderAmount.Subtotal = order.GetAmountInfoFormat(&orderDetail.OrderAmount.Subtotal)
orderDetail.OrderAmount.Total = order.GetAmountInfoFormat(&orderDetail.OrderAmount.Total)
orderDetail.PayTimeout = time.Duration(orderDetail.OrderInfo.Ctime.Add(orderDetail.PayTimeout).UTC().Unix() - time.Now().UTC().Unix())
for orderProductKey, orderProduct := range orderDetail.OrderProduct {
orderDetail.OrderProduct[orderProductKey].TotalPrice = order.GetAmountInfoFormat(&orderProduct.TotalPrice)
orderDetail.OrderProduct[orderProductKey].ItemPrice = order.GetAmountInfoFormat(&orderProduct.ItemPrice)
orderDetail.OrderProduct[orderProductKey].ShoppingCartSnapshot = nil
orderDetail.OrderProduct[orderProductKey].ProductSnapshot = nil
}
orderDetail.OrderInfo.StatusLink = order.GetOrderStatusLinkUser(orderDetail.OrderInfo.DeliveryMethod, orderDetail.OrderInfo.StatusLink)
orderDetail.OrderAmount.Deposit.PayAmount = order.GetAmountInfoFormat(&orderDetail.OrderAmount.Deposit.PayAmount)
orderDetail.OrderAmount.RemainingBalance.PayAmount = order.GetAmountInfoFormat(&orderDetail.OrderAmount.RemainingBalance.PayAmount)
orderDetail.OrderAmount.Subtotal = order.GetAmountInfoFormat(&orderDetail.OrderAmount.Subtotal)
orderDetail.OrderAmount.Total = order.GetAmountInfoFormat(&orderDetail.OrderAmount.Total)
orderDetail.PayTimeout = time.Duration(orderDetail.OrderInfo.Ctime.Add(orderDetail.PayTimeout).UTC().Unix() - time.Now().UTC().Unix())
return &DetailRes{
OrderDetail: orderDetail,

View File

@ -3,10 +3,15 @@ package repositories
import (
"encoding/json"
"errors"
"fmt"
"fusenapi/model/gmodel"
"fusenapi/utils/format"
"fusenapi/utils/hash"
"fusenapi/utils/step_price"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/zeromicro/go-zero/core/logx"
"gorm.io/gorm"
"math"
"strings"
)
@ -28,7 +33,7 @@ type (
// 校验订单
VerifyShoppingCartSnapshotDataChange(req VerifyShoppingCartSnapshotDataChangeReq) error
//计算购物车价格
CaculateStepPrice(purchaseQuantity int64, stepPrice gmodel.StepPriceJsonStruct, fittingPrice int64) (totalPrice, itemPrice int64, err error)
CaculateCartPrice(purchaseQuantity int64, productPrice *gmodel.FsProductPrice, fittingPrice int64) (ItemPrice, totalPrice int64, stepNum, stepPrice []int, err error)
}
)
@ -127,23 +132,33 @@ func (d *defaultShoppingCart) VerifyShoppingCartSnapshotDataChange(req VerifySho
}
// 计算价格
func (d *defaultShoppingCart) CaculateStepPrice(purchaseQuantity int64, stepPrice gmodel.StepPriceJsonStruct, fittingPrice int64) (totalPrice, itemPrice int64, err error) {
l := len(stepPrice.PriceRange)
if l == 0 {
return 0, 0, errors.New("price range is not set")
func (d *defaultShoppingCart) CaculateCartPrice(purchaseQuantity int64, productPrice *gmodel.FsProductPrice, fittingPrice int64) (ItemPrice, totalPrice int64, stepNum, stepPrice []int, err error) {
//阶梯数量切片
stepNum, err = format.StrSlicToIntSlice(strings.Split(*productPrice.StepNum, ","))
if err != nil {
logx.Error(err)
return 0, 0, nil, nil, errors.New(fmt.Sprintf("failed to parse step number:%d_%d", *productPrice.ProductId, *productPrice.SizeId))
}
//遍历查询合适的价格
for k, v := range stepPrice.PriceRange {
//购买数量>起点
if purchaseQuantity > v.StartQuantity {
//最后一个 || 小于等于终点
if k == l-1 || purchaseQuantity <= v.EndQuantity {
itemPrice = v.Price + fittingPrice
return itemPrice * purchaseQuantity, itemPrice, nil
}
}
lenStepNum := len(stepNum)
//阶梯价格切片
stepPrice, err = format.StrSlicToIntSlice(strings.Split(*productPrice.StepPrice, ","))
if err != nil {
logx.Error(err)
return 0, 0, nil, nil, errors.New(fmt.Sprintf("failed to parse step price:%d_%d", *productPrice.ProductId, *productPrice.SizeId))
}
//遍历里面没有则返回第一个
itemPrice = stepPrice.PriceRange[0].Price + fittingPrice
return itemPrice * purchaseQuantity, itemPrice, nil
lenStepPrice := len(stepPrice)
if lenStepPrice == 0 || lenStepNum == 0 {
return 0, 0, nil, nil, errors.New(fmt.Sprintf("step price or step number is not set:%d_%d", *productPrice.ProductId, *productPrice.SizeId))
}
//请求的数量
reqPurchaseQuantity := purchaseQuantity
//购买箱数
boxQuantity := int(math.Ceil(float64(reqPurchaseQuantity) / float64(*productPrice.EachBoxNum)))
//根据数量获取阶梯价格中对应的价格
itemPrice := step_price.GetCentStepPrice(boxQuantity, stepNum, stepPrice)
//如果有配件,单价也要加入配件价格
itemPrice += fittingPrice
//单个购物车总价
totalPrice = itemPrice * reqPurchaseQuantity
return itemPrice, totalPrice, stepNum, stepPrice, nil
}

View File

@ -107,10 +107,9 @@ var (
CodeErrOrderCreatProductPriceAbsent = &StatusResponse{5304, "create order failed, price of product is absent"} // 订单创建失败,商品价格不存在
CodeErrOrderCreatProductAccessoryAbsent = &StatusResponse{5305, "create order failed, accessory of product is absent"} // 订单创建失败,商品配件不存在
CodeErrOrderCreatePrePaymentParam = &StatusResponse{5306, "create payment failed, the shipping address is illegal"} // 订单创建失败,商品配件不存在
CodeErrOrderCreatePrePaymentInfoNoFound = &StatusResponse{5307, "order info not found"}
CodeErrOrderCreatePrePaymentNoUnPaid = &StatusResponse{5308, "create payment failed, order is not unpaid"}
CodeErrOrderCreatePrePaymentPaid = &StatusResponse{5309, "create payment failed, order is paid"}
CodeErrOrderCreatePrePaymentTimeout = &StatusResponse{5310, "create payment failed, timeout"}
CodeErrOrderCreatePrePaymentInfoNoFound = &StatusResponse{5307, "create payment failed, order info not found"}
CodeErrOrderCreatePrePaymentPaidDeposit = &StatusResponse{5308, "create payment failed, order is paid"}
CodeErrOrderCreatePrePaymentTimeout = &StatusResponse{5309, "create payment failed, timeout"}
)
type Response struct {

View File

@ -20,9 +20,8 @@ func NewClient(ctx context.Context, c *Config) Client {
client := resty.New().SetBaseURL(c.BaseUrl)
// 设置超时时间为 5 分钟
if c.RequireTimeout == 0 {
client.SetTimeout(5 * time.Minute)
}
client.SetTimeout(5 * time.Minute)
/* 传输链路 */
tracer := otel.GetTracerProvider().Tracer(trace.TraceName)
spanCtx, span := tracer.Start(
@ -61,12 +60,11 @@ func NewClient(ctx context.Context, c *Config) Client {
type (
Config struct {
BaseUrl string `json:"base_url"`
Url string `json:"url"`
HeaderData map[string]string `json:"header_data"`
RetryCount int64 `json:"retry_count"`
RetryWaitTime int64 `json:"retry_wait_time"`
RequireTimeout time.Duration `json:"require_timeout"`
BaseUrl string `json:"base_url"`
Url string `json:"url"`
HeaderData map[string]string `json:"header_data"`
RetryCount int64 `json:"retry_count"`
RetryWaitTime int64 `json:"retry_wait_time"`
}
defaultClient struct {
c *Config

View File

@ -1,25 +0,0 @@
package format
import (
"fmt"
"strings"
)
// 数字变成带千分位的字符串
func NumToStringWithThousandthPercentile(number int64) string {
s := fmt.Sprintf("%d", number)
l := len(s)
if l <= 3 {
return s
}
r := l % 3 //前面第几位开始加入千分位
b := strings.Builder{}
for i := 0; i < l; i++ {
b.WriteString(string(s[i]))
if i+1 == r && i != l-1 {
b.WriteString(",")
r += 3
}
}
return b.String()
}

View File

@ -59,7 +59,7 @@ func MetadataModulePATCH(tx *gorm.DB, module string, tableStructPointer any, upd
WHEN metadata IS NULL THEN ?
ELSE JSON_MERGE_PATCH(metadata, ?)
END
WHERE module = '%s' and %s;`
WHERE order_sn = '%s' and %s;`
var err error
var metadata []byte
@ -191,12 +191,3 @@ func MetadataOrderPATCH(tx *gorm.DB, sql string, orderSn string, tableStructPoin
return nil
}
func GetGormTableName(tx *gorm.DB, tableStructPointer any) string {
stype := reflect.TypeOf(tableStructPointer)
if stype.Kind() == reflect.Pointer {
stype = stype.Elem()
}
tname := tx.NamingStrategy.TableName(stype.Name())
return tname
}

View File

@ -8,7 +8,10 @@ import (
)
func TestCase1(t *testing.T) {
u := gmodel.UserProfile{}
u := gmodel.UserProfile{
FirstName: "h",
LastName: "sm",
}
conn := initalize.InitMysql("fsreaderwriter:XErSYmLELKMnf3Dh@tcp(fusen.cdmigcvz3rle.us-east-2.rds.amazonaws.com:3306)/fusen")
err := fssql.MetadataModulePATCH(conn, "profile", gmodel.FsUserInfo{}, u, "id = ?", 90)

View File

@ -5,7 +5,6 @@ import (
"fusenapi/constants"
"fusenapi/model/gmodel"
"fusenapi/utils/format"
"strconv"
"time"
)
@ -113,14 +112,6 @@ func GetAmountInfoFormat(req *gmodel.AmountInfo) gmodel.AmountInfo {
}
}
// 处理商品数量
func GetPurchaseQuantity(req *gmodel.PurchaseQuantity) gmodel.PurchaseQuantity {
return gmodel.PurchaseQuantity{
Initiate: strconv.FormatInt(int64(req.Initiate.(float64)), 10),
Current: strconv.FormatInt(int64(req.Current.(float64)), 10),
}
}
// 生成订单编号
func GenerateOrderNumber() string {
t := time.Now()
@ -129,7 +120,7 @@ func GenerateOrderNumber() string {
return orderNumber
}
// 初始化订单状态--链路
// 初始化订单状态
func GenerateOrderStatusLink(deliveryMethod int64, noTime time.Time, expectedTime time.Time) []gmodel.OrderStatus {
var list []gmodel.OrderStatus
@ -151,42 +142,6 @@ func GenerateOrderStatusLink(deliveryMethod int64, noTime time.Time, expectedTim
return list
}
// 更新订单状态--链路
func UpdateOrderStatusLink(statusLink []gmodel.OrderStatus, status gmodel.OrderStatus) []gmodel.OrderStatus {
var list []gmodel.OrderStatus
for _, v := range statusLink {
if v.StatusCode == status.StatusCode {
item := v
if status.StatusTitle != "" {
item.StatusTitle = status.StatusTitle
}
if status.StatusCode != 0 {
item.StatusCode = status.StatusCode
}
if status.Utime != nil {
item.Utime = status.Utime
}
if status.Ctime != nil {
item.Ctime = status.Ctime
}
if status.Metadata != nil {
item.Metadata = status.Metadata
}
if status.ExpectedTime != nil {
item.ExpectedTime = status.ExpectedTime
}
if status.Children != nil || len(status.Children) > 0 {
item.Children = status.Children
}
list = append(list, item)
} else {
list = append(list, v)
}
}
return list
}
// 获取订单状态
func GetOrderStatusLinkUser(deliveryMethod int64, statusLink []gmodel.OrderStatus) []gmodel.OrderStatus {
var list []gmodel.OrderStatus

View File

@ -29,15 +29,15 @@ type Pay interface {
}
type GeneratePrepaymentReq struct {
Metadata map[string]string `json:"metadata"` // 元数据
Amount int64 `json:"amount"` // 支付金额
Currency string `json:"currency"` // 支付货币
ProductName string `json:"product_name"` // 商品名称
ProductDescription string `json:"product_description"` // 商品描述
ProductImages []*string `json:"product_imageso"` // 商品照片
Quantity int64 `json:"quantity"` //数量
SuccessURL string `json:"success_url"` // 支付成功回调
CancelURL string `json:"cancel_url"` // 支付取消回调
OrderSn string `json:"order_sn"` // 订单编号
Amount int64 `json:"amount"` // 支付金额
Currency string `json:"currency"` // 支付货币
ProductName string `json:"product_name"` // 商品名称
ProductDescription string `json:"product_description"` // 商品描述
ProductImages []*string `json:"product_imageso"` // 商品照片
Quantity int64 `json:"quantity"` //数量
SuccessURL string `json:"success_url"` // 支付成功回调
CancelURL string `json:"cancel_url"` // 支付取消回调
}
type GeneratePrepaymentRes struct {

View File

@ -1,10 +1,10 @@
package pay
import (
"github.com/stripe/stripe-go/v75"
"github.com/stripe/stripe-go/v75/checkout/session"
"github.com/stripe/stripe-go/v75/paymentintent"
"github.com/stripe/stripe-go/v75/refund"
"github.com/stripe/stripe-go/v74"
"github.com/stripe/stripe-go/v74/checkout/session"
"github.com/stripe/stripe-go/v74/paymentintent"
"github.com/stripe/stripe-go/v74/refund"
"github.com/zeromicro/go-zero/core/logx"
)
@ -50,7 +50,7 @@ func (stripePay *Stripe) GeneratePrepayment(req *GeneratePrepaymentReq) (res *Ge
case "session":
// session 方式
params := &stripe.CheckoutSessionParams{
PaymentIntentData: &stripe.CheckoutSessionPaymentIntentDataParams{Metadata: req.Metadata},
PaymentIntentData: &stripe.CheckoutSessionPaymentIntentDataParams{Metadata: map[string]string{"order_sn": req.OrderSn}},
// Params: stripe.Params{Metadata: map[string]string{"order_id": "1111111111111"}},
PaymentMethodTypes: stripe.StringSlice([]string{
"card",
@ -86,9 +86,6 @@ func (stripePay *Stripe) GeneratePrepayment(req *GeneratePrepaymentReq) (res *Ge
// "ideal",
}),
}
for key, item := range req.Metadata {
params.AddMetadata(key, item)
}
resPaymentintent, err := paymentintent.New(params)
if err != nil {
return nil, err

View File

@ -1,6 +1,22 @@
package step_price
// 旧的返回厘(即将废弃)
// 返回美元
func GetStepPrice(minBuyNum int, stepNum []int, stepPrice []int) float64 {
if minBuyNum > stepNum[len(stepNum)-1] {
return float64(stepPrice[len(stepPrice)-1]) / float64(1000)
}
for k, v := range stepNum {
if minBuyNum <= v {
if k <= (len(stepPrice) - 1) {
return float64(stepPrice[k]) / float64(1000)
}
return float64(stepPrice[len(stepPrice)-1]) / float64(1000)
}
}
return float64(stepPrice[len(stepPrice)-1]) / float64(1000)
}
// 返回厘
func GetCentStepPrice(minBuyNum int, stepNum []int, stepPrice []int) int64 {
if minBuyNum > stepNum[len(stepNum)-1] {
return int64(stepPrice[len(stepPrice)-1])