order
This commit is contained in:
56
business/jxstore/cms/order.go
Normal file
56
business/jxstore/cms/order.go
Normal file
@@ -0,0 +1,56 @@
|
||||
package cms
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
)
|
||||
|
||||
const (
|
||||
OrderTypeDeposit = 1 //保证金
|
||||
)
|
||||
|
||||
func CreateOrder(ctx *jxcontext.Context, price, orderType int) (order *model.Order, err error) {
|
||||
var (
|
||||
db = dao.GetDB()
|
||||
)
|
||||
order = &model.Order{
|
||||
OrderID: jxutils.GenOrderNo(),
|
||||
UserID: ctx.GetUserID(),
|
||||
Type: orderType,
|
||||
Status: model.OrderStatusWait4Pay,
|
||||
PayPrice: price,
|
||||
}
|
||||
dao.WrapAddIDCULEntity(order, ctx.GetUserName())
|
||||
dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
dao.Rollback(db)
|
||||
panic(r)
|
||||
}
|
||||
}()
|
||||
if err = dao.CreateEntity(db, order); err != nil {
|
||||
dao.Rollback(db)
|
||||
}
|
||||
dao.Commit(db)
|
||||
return order, err
|
||||
}
|
||||
|
||||
func Pay(ctx *jxcontext.Context, orderID, payType int, vendorPayType string) (err error) {
|
||||
switch payType {
|
||||
case model.PayTypeTL:
|
||||
// if orderPay, err = financial.Pay4OrderByTL(ctx, order, payType, vendorPayType); err == nil && orderPay != nil {
|
||||
// dao.WrapAddIDCULDEntity(orderPay, ctx.GetUserName())
|
||||
// err = dao.CreateEntity(dao.GetDB(), orderPay)
|
||||
// }
|
||||
default:
|
||||
err = fmt.Errorf("支付方式:%d当前不支持", payType)
|
||||
}
|
||||
return err
|
||||
}
|
||||
@@ -1,119 +1,174 @@
|
||||
package financial
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"mime/multipart"
|
||||
"path"
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/baseapi/platformapi/tonglianpayapi"
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/auth2/authprovider/weixin"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/weixinmsg"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/business/model/legacymodel"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
"github.com/qiniu/api.v7/storage"
|
||||
)
|
||||
|
||||
type tUploadFileInfo struct {
|
||||
FileHeader *multipart.FileHeader
|
||||
StoreID int
|
||||
}
|
||||
|
||||
func SendFilesToStores(ctx *jxcontext.Context, files []*multipart.FileHeader, title, shopName string, isAsync bool, userName string) (hint string, err error) {
|
||||
globals.SugarLogger.Debugf("SendFilesToStores, fileCount:%d isAsync:%t, userName:%s", len(files), isAsync, userName)
|
||||
if len(files) == 0 {
|
||||
return "", errors.New("没有文件上传!")
|
||||
func Pay4OrderByTL(ctx *jxcontext.Context, order *model.GoodsOrder, payType int, vendorPayType string) (orderPay *model.OrderPay, err error) {
|
||||
payCreatedAt := time.Now()
|
||||
param := &tonglianpayapi.CreateUnitorderOrderParam{
|
||||
Trxamt: int(order.ActualPayPrice),
|
||||
NotifyUrl: globals.TLPayNotifyURL,
|
||||
Reqsn: order.VendorOrderID,
|
||||
PayType: vendorPayType,
|
||||
}
|
||||
|
||||
fileList := make([]*tUploadFileInfo, len(files))
|
||||
for k, fileHeader := range files {
|
||||
fileList[k] = &tUploadFileInfo{
|
||||
FileHeader: fileHeader,
|
||||
}
|
||||
fileNameParts := strings.Split(fileHeader.Filename, "_")
|
||||
if len(fileNameParts) < 3 {
|
||||
return "", fmt.Errorf("文件名:%s不规范,没有包含三个必要的部分", fileHeader.Filename)
|
||||
}
|
||||
fileList[k].StoreID = int(utils.Str2Int64WithDefault(fileNameParts[0], 0))
|
||||
if fileList[k].StoreID < 100000 || fileList[k].StoreID > 1000000 {
|
||||
return "", fmt.Errorf("文件名:%s不规范,不以合法的京西门店ID开始", fileHeader.Filename)
|
||||
//暂时做兼容处理
|
||||
if vendorPayType == "JSAPI" {
|
||||
param.PayType = tonglianpayapi.PayTypeWxXcx
|
||||
}
|
||||
if vendorPayType == tonglianpayapi.PayTypeWxXcx {
|
||||
if authInfo, err := ctx.GetV2AuthInfo(); err == nil && authInfo.GetAuthType() == weixin.AuthTypeMini {
|
||||
param.Acct = authInfo.GetAuthID()
|
||||
}
|
||||
}
|
||||
putPolicy := storage.PutPolicy{
|
||||
Scope: globals.QiniuBucket,
|
||||
Expires: 10 * 60,
|
||||
}
|
||||
upToken := putPolicy.UploadToken(api.QiniuAPI)
|
||||
cfg := &storage.Config{}
|
||||
task := tasksch.NewParallelTask("SendFilesToStores", tasksch.NewParallelConfig().SetIsContinueWhenError(true), ctx,
|
||||
func(t *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
fileInfo := batchItemList[0].(*tUploadFileInfo)
|
||||
fileHeader := fileInfo.FileHeader
|
||||
db := dao.GetDB()
|
||||
storeID, _ := dao.GetRealLinkStoreID(db, fileInfo.StoreID)
|
||||
file, err := fileHeader.Open()
|
||||
globals.SugarLogger.Debugf("SendFilesToStores upload file:%s", fileHeader.Filename)
|
||||
if err == nil {
|
||||
ret := storage.PutRet{}
|
||||
key := "storeBill/" + utils.Int2Str(storeID) + "_" + strings.ToLower(utils.GetUUID()) + path.Ext(fileHeader.Filename)
|
||||
formUploader := storage.NewFormUploader(cfg)
|
||||
for i := 0; i < 3; i++ {
|
||||
if err = formUploader.Put(context.Background(), &ret, upToken, key, file, fileHeader.Size, &storage.PutExtra{}); err == nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
file.Close()
|
||||
if err == nil {
|
||||
billRec := &legacymodel.StoreBill{
|
||||
Date: time.Now(),
|
||||
Url: strings.Replace(jxutils.ComposeQiniuResURL(ret.Key), "http://", "https://", -1),
|
||||
StoreId: storeID,
|
||||
BillName: fileHeader.Filename,
|
||||
ShopName: shopName,
|
||||
BillTitle: title,
|
||||
}
|
||||
if err = dao.CreateEntity(db, billRec); err == nil {
|
||||
err = weixinmsg.NotifySaleBill(storeID, title, shopName, fmt.Sprintf("%s/billshow/?path=%s", globals.BackstageHost, billRec.Url))
|
||||
if err != nil {
|
||||
globals.SugarLogger.Infof("SendFilesToStores NotifySaleBill file:%s error:%v", fileHeader.Filename, err)
|
||||
}
|
||||
err = nil // 忽略微信发送错误
|
||||
} else {
|
||||
globals.SugarLogger.Warnf("SendFilesToStores CreateEntity file:%s error:%v", fileHeader.Filename, err)
|
||||
}
|
||||
} else {
|
||||
globals.SugarLogger.Warnf("SendFilesToStores file:%s failed with error:%v", fileHeader.Filename, err)
|
||||
}
|
||||
} else {
|
||||
globals.SugarLogger.Warnf("SendFilesToStores open file:%s failed with error:%v", fileHeader.Filename, err)
|
||||
if vendorPayType == tonglianpayapi.PayTypeH5 {
|
||||
param2 := &tonglianpayapi.CreateH5UnitorderOrderParam{
|
||||
Trxamt: int(order.ActualPayPrice),
|
||||
NotifyUrl: globals.TLPayNotifyURL,
|
||||
Body: "京西菜市",
|
||||
Charset: "UTF-8",
|
||||
}
|
||||
err = api.TLpayAPI.CreateH5UnitorderOrder(param2)
|
||||
} else {
|
||||
result, err := api.TLpayAPI.CreateUnitorderOrder(param)
|
||||
if err == nil {
|
||||
var result2 tonglianpayapi.PayInfo
|
||||
json.Unmarshal([]byte(result.PayInfo), &result2)
|
||||
prePayID := result2.Package[strings.LastIndex(result2.Package, "=")+1 : len(result2.Package)]
|
||||
orderPay = &model.OrderPay{
|
||||
PayOrderID: param.Reqsn,
|
||||
PayType: payType,
|
||||
VendorPayType: vendorPayType,
|
||||
TransactionID: result.TrxID,
|
||||
VendorOrderID: order.VendorOrderID,
|
||||
VendorID: order.VendorID,
|
||||
Status: 0,
|
||||
PayCreatedAt: payCreatedAt,
|
||||
PrepayID: prePayID,
|
||||
CodeURL: utils.LimitUTF8StringLen(result.PayInfo, 3200),
|
||||
TotalFee: int(order.ActualPayPrice),
|
||||
}
|
||||
return retVal, err
|
||||
}, fileList)
|
||||
tasksch.HandleTask(task, nil, true).Run()
|
||||
hint = task.ID
|
||||
if !isAsync {
|
||||
_, err = task.GetResult(0)
|
||||
}
|
||||
}
|
||||
return task.ID, err
|
||||
return orderPay, err
|
||||
}
|
||||
|
||||
func GetStoreBills(ctx *jxcontext.Context, storeID int) (bills []*legacymodel.StoreBill, err error) {
|
||||
db := dao.GetDB()
|
||||
if err = dao.GetRows(db, &bills, `
|
||||
SELECT *
|
||||
FROM store_bill
|
||||
WHERE store_id = ?
|
||||
ORDER BY date DESC
|
||||
LIMIT 10
|
||||
`, storeID); err != nil {
|
||||
return nil, err
|
||||
func OnTLPayCallback(call *tonglianpayapi.CallBackResult) (err error) {
|
||||
globals.SugarLogger.Debugf("OnTLPayCallback msg:%s", utils.Format4Output(call, true))
|
||||
switch call.TrxCode {
|
||||
case tonglianpayapi.MsgTypePay:
|
||||
err = onTLpayFinished(call)
|
||||
case tonglianpayapi.MsgTypeRefund:
|
||||
err = onTLpayRefund(call)
|
||||
}
|
||||
return bills, err
|
||||
return err
|
||||
}
|
||||
|
||||
func onTLpayFinished(call *tonglianpayapi.CallBackResult) (err error) {
|
||||
orderPay := &model.OrderPay{
|
||||
PayOrderID: call.CusorderID,
|
||||
// PayType: model.PayTypeTL,
|
||||
}
|
||||
orderPay.DeletedAt = utils.DefaultTimeValue
|
||||
db := dao.GetDB()
|
||||
if err = dao.GetEntity(db, orderPay, "PayOrderID", "DeletedAt"); err == nil {
|
||||
if orderPay.Status != 0 {
|
||||
globals.SugarLogger.Debugf("already pay msg:%s, err:%v", utils.Format4Output(call, true), err)
|
||||
return err
|
||||
}
|
||||
loc, _ := time.LoadLocation("Local")
|
||||
t1, _ := time.ParseInLocation("20060102150405", call.PayTime, loc)
|
||||
orderPay.PayFinishedAt = utils.Time2Pointer(t1)
|
||||
// orderPay.TransactionID = call.ChnlTrxID
|
||||
orderPay.OriginalData = utils.Format4Output(call, true)
|
||||
if call.TrxStatus == tonglianpayapi.TrxStatusSuccess {
|
||||
orderPay.Status = model.PayStatusYes
|
||||
} else {
|
||||
orderPay.Status = model.PayStatusFailed
|
||||
}
|
||||
dao.UpdateEntity(db, orderPay)
|
||||
if call.TrxStatus == tonglianpayapi.TrxStatusSuccess {
|
||||
// err = OnPayFinished(orderPay)
|
||||
}
|
||||
} else {
|
||||
globals.SugarLogger.Debugf("onTLpayFinished msg:%s, err:%v", utils.Format4Output(call, true), err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func onTLpayRefund(call *tonglianpayapi.CallBackResult) (err error) {
|
||||
orderPayRefund := &model.OrderPayRefund{
|
||||
RefundID: call.CusorderID,
|
||||
}
|
||||
db := dao.GetDB()
|
||||
if err = dao.GetEntity(db, orderPayRefund, "RefundID"); err == nil {
|
||||
if call.TrxStatus == tonglianpayapi.TrxStatusSuccess {
|
||||
orderPayRefund.Status = model.RefundStatusYes
|
||||
} else {
|
||||
orderPayRefund.Status = model.RefundStatusFailed
|
||||
}
|
||||
orderPayRefund.OriginalData = utils.Format4Output(call, true)
|
||||
dao.UpdateEntity(db, orderPayRefund)
|
||||
} else if dao.IsNoRowsError(err) {
|
||||
globals.SugarLogger.Warnf("收到异常的退款事件, call:%s", utils.Format4Output(call, true))
|
||||
}
|
||||
|
||||
orderPay := &model.OrderPay{
|
||||
VendorOrderID: orderPayRefund.VendorOrderID,
|
||||
VendorID: jxutils.GetPossibleVendorIDFromVendorOrderID(orderPayRefund.VendorOrderID),
|
||||
PayType: model.PayTypeWX,
|
||||
Status: model.PayStatusYes,
|
||||
}
|
||||
orderPay.DeletedAt = utils.DefaultTimeValue
|
||||
if err = dao.GetEntity(db, orderPay, "VendorOrderID", "VendorID", "PayType", "Status", "DeletedAt"); err == nil {
|
||||
orderPay.Status = model.PayStatusRefund
|
||||
dao.UpdateEntity(db, orderPay)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func RefundOrderByTL(ctx *jxcontext.Context, orderPay *model.OrderPay, refundID string, refundFee int, refundDesc string) (orderPayRefund *model.OrderPayRefund, err error) {
|
||||
result, err := api.TLpayAPI.PayRefund(&tonglianpayapi.PayRefundParam{
|
||||
Trxamt: refundFee,
|
||||
Reqsn: utils.GetUUID(),
|
||||
Remark: refundDesc,
|
||||
OldTrxID: orderPay.TransactionID,
|
||||
})
|
||||
if err == nil {
|
||||
orderPayRefund = &model.OrderPayRefund{
|
||||
RefundID: refundID,
|
||||
VendorRefundID: result.TrxID,
|
||||
VendorOrderID: orderPay.VendorOrderID,
|
||||
VendorID: orderPay.VendorID,
|
||||
Status: model.RefundStatusNo,
|
||||
TransactionID: orderPay.TransactionID,
|
||||
RefundFee: refundFee,
|
||||
RefundCreatedAt: time.Now(),
|
||||
}
|
||||
dao.WrapAddIDCULDEntity(orderPayRefund, ctx.GetUserName())
|
||||
db := dao.GetDB()
|
||||
if result.TrxStatus == tonglianpayapi.TrxStatusSuccess {
|
||||
orderPayRefund.Status = model.RefundStatusYes
|
||||
} else {
|
||||
orderPayRefund.Status = model.RefundStatusFailed
|
||||
}
|
||||
orderPayRefund.OriginalData = utils.Format4Output(result, true)
|
||||
dao.CreateEntity(db, orderPayRefund)
|
||||
|
||||
orderPay.Status = model.PayStatusRefund
|
||||
dao.UpdateEntity(db, orderPay)
|
||||
}
|
||||
return orderPayRefund, err
|
||||
}
|
||||
|
||||
@@ -172,7 +172,7 @@ func GetPossibleVendorIDFromVendorOrderID(vendorOrderID string) (vendorID int) {
|
||||
}
|
||||
|
||||
func GenOrderNo() (orderNo int64) {
|
||||
const prefix = 88
|
||||
var prefix = utils.Str2Int64(time.Now().Format("20060102"))
|
||||
const randPartNum = 1000
|
||||
orderNo = time.Now().Unix() - orderNoBeginTimestamp
|
||||
orderNo = orderNo * randPartNum
|
||||
|
||||
@@ -9,9 +9,8 @@ const (
|
||||
)
|
||||
|
||||
const (
|
||||
PayTypeWX = 1 // 微信支付
|
||||
PayTypeTL = 2 // 通联宝支付
|
||||
PayTypeTL_DiscountCard = 3 // 通联宝支付(会员折扣卡)
|
||||
PayTypeWX = 1 // 微信支付
|
||||
PayTypeTL = 2 // 通联宝支付
|
||||
|
||||
PayStatusNo = 0
|
||||
PayStatusYes = 1
|
||||
@@ -449,7 +448,7 @@ type Order struct {
|
||||
OrderID int64 `orm:"column(order_id)" json:"orderID"` //订单号
|
||||
UserID string `orm:"column(user_id);size(48)" json:"userID"` //用户ID
|
||||
Type int `json:"type"` //订单类型
|
||||
Status int `json:"status"` //订单状态
|
||||
Status int `json:"status"` //订单状态,待支付2,已支付5,支付成功110,支付失败115
|
||||
PayPrice int `json:"payPrice"` //支付金额
|
||||
Comment string `orm:"size(255)" json:"comment"` //备注
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"git.rosy.net.cn/jx-callback/business/jxstore/cms"
|
||||
"github.com/astaxie/beego"
|
||||
)
|
||||
|
||||
@@ -11,31 +12,30 @@ type OrderController struct {
|
||||
// @Title 支付
|
||||
// @Description 支付
|
||||
// @Param token header string true "认证token"
|
||||
// @Param type formData int true "支付类型/账单类型"
|
||||
// @Param price formData int true "支付金额"
|
||||
// @Param orderID formData int true "订单号"
|
||||
// @Param payType formData int true "支付平台类型"
|
||||
// @Param vendorPayType formData string true "平台支付类型"
|
||||
// @Success 200 {object} controllers.CallResult
|
||||
// @Failure 200 {object} controllers.CallResult
|
||||
// @router /Pay [post]
|
||||
func (c *OrderController) Pay() {
|
||||
|
||||
c.callPay(func(params *tOrderPayParams) (retVal interface{}, errCode string, err error) {
|
||||
err = cms.Pay(params.Ctx, params.OrderID, params.PayType, params.VendorPayType)
|
||||
return retVal, "", err
|
||||
})
|
||||
}
|
||||
|
||||
// @Title 创建订单
|
||||
// @Description 创建订单
|
||||
// @Param token header string true "认证token"
|
||||
// @Param jxOrder formData string true "订单信息"
|
||||
// @Param addressID formData int64 true "配送地址ID"
|
||||
// @Param fromStoreID formData int fasle "物料配送门店"
|
||||
// @Param createType formData int false "创建类型, 0:预创建, 1:创建"
|
||||
// @Param isDeliverySelf formData bool false "是否是自提单"
|
||||
// @Param type formData int true "支付类型/账单类型"
|
||||
// @Param price formData int true "支付金额"
|
||||
// @Success 200 {object} controllers.CallResult
|
||||
// @Failure 200 {object} controllers.CallResult
|
||||
// @router /CreateOrder [post]
|
||||
func (c *OrderController) CreateOrder() {
|
||||
c.callCreateOrder(func(params *tOrderCreateOrderParams) (retVal interface{}, errCode string, err error) {
|
||||
|
||||
retVal, err = cms.CreateOrder(params.Ctx, params.Type, params.Price)
|
||||
return retVal, "", err
|
||||
})
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ func Init() {
|
||||
orm.RegisterModel(&model.Job{}, &model.JobCategory{}, &model.JobStep{})
|
||||
orm.RegisterModel(&model.JobOrder{})
|
||||
|
||||
orm.RegisterModel(&model.OperateEvent{})
|
||||
orm.RegisterModel(&model.NewConfig{}, &legacymodel.Config{})
|
||||
// create table
|
||||
orm.RunSyncdb("default", false, true)
|
||||
|
||||
Reference in New Issue
Block a user