diff --git a/business/jxstore/cms/job.go b/business/jxstore/cms/job.go index 946e22a61..cbea17bcd 100644 --- a/business/jxstore/cms/job.go +++ b/business/jxstore/cms/job.go @@ -4,6 +4,8 @@ import ( "fmt" "time" + "git.rosy.net.cn/jx-callback/business/jxstore/financial" + "git.rosy.net.cn/baseapi/utils" "git.rosy.net.cn/jx-callback/business/jxutils" @@ -30,9 +32,20 @@ func PublishJob(ctx *jxcontext.Context, job *model.Job) (err error) { // switch job.JobCategoryID { // case 1: // } - // if ctx.GetUserID() != job.UserID { - // return fmt.Errorf("用户信息已过期,请重新登录!") - // } + if ctx.GetUserID() != job.UserID { + return fmt.Errorf("用户信息已过期,请重新登录!") + } + //发布任务要扣除任务总额的保证金,不够扣就要进行充值 + userBill, err := dao.GetUserBill(db, job.UserID, "") + if userBill == nil { + return fmt.Errorf("未查询到该用户的账单!") + } + job.TotalPrice = job.Count * job.AvgPrice + if userBill.DepositBalance < job.TotalPrice { + job.Status = model.JobStatusFailed + } else { + job.Status = model.JobStatusDoing + } if job.Count <= 0 { return fmt.Errorf("任务数量不能为0!") } @@ -57,8 +70,6 @@ func PublishJob(ctx *jxcontext.Context, job *model.Job) (err error) { job.Lng = jxutils.StandardCoordinate2Int(lng) job.Lat = jxutils.StandardCoordinate2Int(lat) } - job.TotalPrice = job.Count * job.AvgPrice - job.Status = model.JobStatusDoing dao.WrapAddIDCULEntity(job, ctx.GetUserName()) dao.Begin(db) defer func() { @@ -76,6 +87,18 @@ func PublishJob(ctx *jxcontext.Context, job *model.Job) (err error) { if err != nil { dao.Rollback(db) } + //发布任务要扣除任务总额的保证金,不够扣就要进行充值 + if err == nil && job.Status != model.JobStatusFailed { + //1、账户支出增加一条记录 + if err = financial.AddBillExpend(db, userBill.BillID, model.OrderTypeDeposit, job.TotalPrice); err != nil { + dao.Rollback(db) + } + //2、账户表保证金总额增加相应值 + userBill.DepositBalance -= job.TotalPrice + if _, err = dao.UpdateEntity(db, userBill, "DepositBalance"); err != nil { + dao.Rollback(db) + } + } dao.Commit(db) return err } diff --git a/business/jxstore/cms/order.go b/business/jxstore/cms/order.go index b1ef27c56..b7653767a 100644 --- a/business/jxstore/cms/order.go +++ b/business/jxstore/cms/order.go @@ -11,10 +11,6 @@ import ( "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() @@ -47,8 +43,24 @@ func Pay(ctx *jxcontext.Context, orderID, payType int, vendorPayType string) (er order = &model.Order{ OrderID: int64(orderID), } + payHandler = &financial.PayHandler{ + PayType: payType, + Ctx: ctx, + VendorPayType: vendorPayType, + } ) err = dao.GetEntity(db, order, "OrderID") - err = financial.IPayHandler.CreatePay(order, payType, vendorPayType) + payHandler.Order = order + //如果用户没有对应账单信息就给他生成一条 + userBill, err := dao.GetUserBill(db, order.UserID, "") + if userBill == nil { + userBillInsert := &model.UserBill{ + BillID: jxutils.GenBillID(), + UserID: order.UserID, + } + dao.WrapAddIDCULDEntity(userBillInsert, jxcontext.AdminCtx.GetUserName()) + err = dao.CreateEntity(db, userBillInsert) + } + err = payHandler.CreatePay() return err } diff --git a/business/jxstore/cms/user2.go b/business/jxstore/cms/user2.go index c92d4c9f3..e829bcc23 100644 --- a/business/jxstore/cms/user2.go +++ b/business/jxstore/cms/user2.go @@ -206,12 +206,25 @@ func RegisterUserWithMobile(ctx *jxcontext.Context, user *model.User, mobileVeri } else { outAuthInfo, err = auth2.BindUser(inAuthInfo, user) } + //给用户添加一条账单记录 + err = AddUserBill(user) } else if dao.IsDuplicateError(err) { err = auth2.ErrUserID2AlreadyExist } return outAuthInfo, err } +func AddUserBill(user *model.User) (err error) { + var ( + db = dao.GetDB() + ) + userBill := &model.UserBill{ + BillID: jxutils.GenBillID(), + UserID: user.UserID, + } + return dao.CreateEntity(db, userBill) +} + func GetUserBindAuthInfo(ctx *jxcontext.Context) (authList []*model.AuthBind, err error) { authInfo, err := ctx.GetV2AuthInfo() if err == nil { diff --git a/business/jxstore/financial/bill.go b/business/jxstore/financial/bill.go new file mode 100644 index 000000000..81f85dea9 --- /dev/null +++ b/business/jxstore/financial/bill.go @@ -0,0 +1,27 @@ +package financial + +import ( + "git.rosy.net.cn/jx-callback/business/jxutils/jxcontext" + "git.rosy.net.cn/jx-callback/business/model" + "git.rosy.net.cn/jx-callback/business/model/dao" +) + +func AddBillIncome(db *dao.DaoDB, billID int64, billType, incomePrice int) (err error) { + billIncome := &model.BillIncome{ + BillID: billID, + Type: billType, + IncomePrice: incomePrice, + } + dao.WrapAddIDCULEntity(billIncome, jxcontext.AdminCtx.GetUserName()) + return dao.CreateEntity(db, billIncome) +} + +func AddBillExpend(db *dao.DaoDB, billID int64, billType, expendPrice int) (err error) { + billExpend := &model.BillExpend{ + BillID: billID, + Type: billType, + ExpendPrice: expendPrice, + } + dao.WrapAddIDCULEntity(billExpend, jxcontext.AdminCtx.GetUserName()) + return dao.CreateEntity(db, billExpend) +} diff --git a/business/jxstore/financial/financial.go b/business/jxstore/financial/financial.go index eb6706f55..9d1618453 100644 --- a/business/jxstore/financial/financial.go +++ b/business/jxstore/financial/financial.go @@ -17,21 +17,17 @@ import ( "git.rosy.net.cn/jx-callback/globals/api" ) -var ( - IPayHandler PayHandlerInterface -) - -func (p *PayHandler) CreatePay(order *model.Order, payType int, vendorPayType string) (err error) { - switch payType { +func (p *PayHandler) CreatePay() (err error) { + switch p.PayType { case model.PayTypeTL: param := &tonglianpayapi.CreateUnitorderOrderParam{ - Trxamt: int(order.PayPrice), + Trxamt: int(p.Order.PayPrice), NotifyUrl: globals.TLPayNotifyURL, - Reqsn: utils.Int64ToStr(order.OrderID), - PayType: vendorPayType, + Reqsn: utils.Int64ToStr(p.Order.OrderID), + PayType: p.VendorPayType, } - if vendorPayType == tonglianpayapi.PayTypeWxXcx { - if authInfo, err := ctx.GetV2AuthInfo(); err == nil && authInfo.GetAuthType() == weixin.AuthTypeMini { + if p.VendorPayType == tonglianpayapi.PayTypeWxXcx { + if authInfo, err := p.Ctx.GetV2AuthInfo(); err == nil && authInfo.GetAuthType() == weixin.AuthTypeMini { param.Acct = authInfo.GetAuthID() } } @@ -39,66 +35,17 @@ func (p *PayHandler) CreatePay(order *model.Order, payType int, vendorPayType st if err == nil { var result2 tonglianpayapi.PayInfo json.Unmarshal([]byte(result.PayInfo), &result2) - order.PrepayID = result2.Package[strings.LastIndex(result2.Package, "=")+1 : len(result2.Package)] - order.TransactionID = result.TrxID - order.OriginalData = utils.LimitUTF8StringLen(result.PayInfo, 3200) - + p.Order.PrepayID = result2.Package[strings.LastIndex(result2.Package, "=")+1 : len(result2.Package)] + p.Order.TransactionID = result.TrxID + // p.Order.OriginalData = utils.LimitUTF8StringLen(result.PayInfo, 3200) + _, err = dao.UpdateEntity(dao.GetDB(), p.Order, "PrepayID", "TransactionID", "OriginalData") } default: - err = fmt.Errorf("支付方式:%d当前不支持", payType) + err = fmt.Errorf("支付方式:%d当前不支持", p.PayType) } return err } -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, - } - //暂时做兼容处理 - 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() - } - } - 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 orderPay, err -} - func OnTLPayCallback(call *tonglianpayapi.CallBackResult) (err error) { globals.SugarLogger.Debugf("OnTLPayCallback msg:%s", utils.Format4Output(call, true)) switch call.TrxCode { @@ -111,30 +58,28 @@ func OnTLPayCallback(call *tonglianpayapi.CallBackResult) (err error) { } func onTLpayFinished(call *tonglianpayapi.CallBackResult) (err error) { - orderPay := &model.OrderPay{ - PayOrderID: call.CusorderID, - // PayType: model.PayTypeTL, + order := &model.Order{ + OrderID: utils.Str2Int64(call.CusorderID), } - orderPay.DeletedAt = utils.DefaultTimeValue db := dao.GetDB() - if err = dao.GetEntity(db, orderPay, "PayOrderID", "DeletedAt"); err == nil { - if orderPay.Status != 0 { + if err = dao.GetEntity(db, order, "OrderID"); err == nil { + if order.Status != model.OrderStatusWait4Pay { 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) + order.PayFinishedAt = utils.Time2Pointer(t1) + // order.TransactionID = call.ChnlTrxID + order.OriginalData = utils.Format4Output(call, true) if call.TrxStatus == tonglianpayapi.TrxStatusSuccess { - orderPay.Status = model.PayStatusYes + order.Status = model.OrderStatusFinished } else { - orderPay.Status = model.PayStatusFailed + order.Status = model.OrderStatusCanceled } - dao.UpdateEntity(db, orderPay) + dao.UpdateEntity(db, order) if call.TrxStatus == tonglianpayapi.TrxStatusSuccess { - // err = OnPayFinished(orderPay) + err = OnPayFinished(order) } } else { globals.SugarLogger.Debugf("onTLpayFinished msg:%s, err:%v", utils.Format4Output(call, true), err) diff --git a/business/jxstore/financial/pay.go b/business/jxstore/financial/pay.go index 6f82107b6..d2219cc08 100644 --- a/business/jxstore/financial/pay.go +++ b/business/jxstore/financial/pay.go @@ -1,13 +1,64 @@ package financial import ( + "fmt" + + "git.rosy.net.cn/baseapi/utils" + "git.rosy.net.cn/jx-callback/globals" + + "git.rosy.net.cn/jx-callback/business/jxutils/jxcontext" "git.rosy.net.cn/jx-callback/business/model" + "git.rosy.net.cn/jx-callback/business/model/dao" ) type PayHandler struct { - PayType int `json:"-"` //支付方式 + PayType int `json:"-"` //支付方式 + Ctx *jxcontext.Context + Order *model.Order + VendorPayType string } type PayHandlerInterface interface { - CreatePay(order *model.Order, payType int, vendorPayType string) (err error) + CreatePay() (err error) +} + +func OnPayFinished(order *model.Order) (err error) { + var ( + db = dao.GetDB() + billID int64 + ) + globals.SugarLogger.Debugf("OnPayFinished begin modify account order: %v", utils.Format4Output(order, false)) + dao.Begin(db) + defer func() { + if r := recover(); r != nil { + dao.Rollback(db) + panic(r) + } + }() + //如果用户没有对应账单信息就给他生成一条 + userBill, err := dao.GetUserBill(db, order.UserID, "") + if userBill == nil { + globals.SugarLogger.Debugf("OnPayFinished 未找到该用户的账单 order: %v", utils.Format4Output(order, false)) + return fmt.Errorf("未找到该用户的账单!%v", order.UserID) + } + //根据订单类型来操作账户 + switch order.Type { + case model.OrderTypeDeposit: + //如果是发布任务的保证金 + //1、账户收入表增加一条保证金记录 + if err = AddBillIncome(db, billID, order.Type, order.PayPrice); err != nil { + dao.Rollback(db) + } + //2、账户表保证金总额增加相应值 + userBill.DepositBalance += order.PayPrice + if _, err = dao.UpdateEntity(db, userBill, "DepositBalance"); err != nil { + dao.Rollback(db) + } + default: + globals.SugarLogger.Debugf("OnPayFinished 暂不支持此订单类型 order: %v", utils.Format4Output(order, false)) + return fmt.Errorf("暂不支持此订单类型!") + } + dao.Commit(db) + globals.SugarLogger.Debugf("OnPayFinished end modify account ...") + return err } diff --git a/business/jxutils/jxutils.go b/business/jxutils/jxutils.go index 049519bad..06868d4f8 100644 --- a/business/jxutils/jxutils.go +++ b/business/jxutils/jxutils.go @@ -186,6 +186,21 @@ func GenOrderNo() (orderNo int64) { return orderNo } +func GenBillID() (billID int64) { + const prefix = 66 + const randPartNum = 100 + billID = time.Now().Unix() - orderNoBeginTimestamp + billID = billID * randPartNum + md5Bytes := md5.Sum([]byte(utils.GetUUID())) + randPart := 0 + for k, v := range md5Bytes { + randPart += int(v) << ((k % 3) * 8) + } + billID += int64(randPart % randPartNum) + billID += int64(math.Pow10(int(math.Log10(float64(billID)))+1)) * prefix + return billID +} + func GenAfsOrderNo() (orderNo int64) { const prefix = 80 const randPartNum = 100 diff --git a/business/model/bill.go b/business/model/bill.go index e587793a4..6bea28f79 100644 --- a/business/model/bill.go +++ b/business/model/bill.go @@ -34,18 +34,23 @@ func (v *BillExpend) TableIndex() [][]string { //用户账单表 type UserBill struct { - ModelIDCUL + ModelIDCULD BillID int64 `orm:"column(bill_id)" json:"billID"` //账单ID UserID string `orm:"column(user_id)" json:"userID"` //用户ID AccountBalance int `json:"accountBalance"` //账户余额 - DepositBalance int `json:"DepositBalance"` //保证金余额 + DepositBalance int `json:"depositBalance"` //保证金余额 +} + +func (v *UserBill) TableUnique() [][]string { + return [][]string{ + []string{"UserID"}, + } } func (v *UserBill) TableIndex() [][]string { return [][]string{ []string{"BillID"}, - []string{"UserID"}, []string{"CreatedAt"}, []string{"AccountBalance"}, } diff --git a/business/model/dao/dao_bill.go b/business/model/dao/dao_bill.go new file mode 100644 index 000000000..10194b4af --- /dev/null +++ b/business/model/dao/dao_bill.go @@ -0,0 +1,23 @@ +package dao + +import ( + "git.rosy.net.cn/baseapi/utils" + "git.rosy.net.cn/jx-callback/business/model" +) + +func GetUserBill(db *DaoDB, userID, billID string) (userBill *model.UserBill, err error) { + sql := ` + SELECT * FROM user_bill WHERE deleted_at = ? + ` + sqlParams := []interface{}{utils.DefaultTimeValue} + if userID != "" { + sql += ` AND user_id = ?` + sqlParams = append(sqlParams, userID) + } + if billID != "" { + sql += ` AND bill_id = ?` + sqlParams = append(sqlParams, billID) + } + err = GetRow(db, &userBill, sql, sqlParams) + return userBill, err +} diff --git a/business/model/dao/job.go b/business/model/dao/job.go index 512934637..59d5ecf2a 100644 --- a/business/model/dao/job.go +++ b/business/model/dao/job.go @@ -51,9 +51,9 @@ func GetJobs(db *DaoDB, userIDs []string, categoryIDs []int, includeStep bool, f sql += ` AND a.created_at <= ?` sqlParams = append(sqlParams, toTime) } - sql += " LIMIT ? OFFSET ?" + sql += " AND a.status <> ? LIMIT ? OFFSET ?" pageSize = jxutils.FormalizePageSize(pageSize) - sqlParams = append(sqlParams, pageSize, offset) + sqlParams = append(sqlParams, model.JobStatusFailed, pageSize, offset) Begin(db) defer Commit(db) if err = GetRows(db, &jobs, sql, sqlParams...); err == nil { diff --git a/business/model/job.go b/business/model/job.go index ae3b99da3..40d66c4cc 100644 --- a/business/model/job.go +++ b/business/model/job.go @@ -5,6 +5,7 @@ import "time" const ( JobStatusDoing = 0 JobStatusFinished = 1 + JobStatusFailed = -1 JobOrderStatusAccept = 5 JobOrderStatusWaitAudit = 10 diff --git a/business/model/order.go b/business/model/order.go index b729be96d..922963294 100644 --- a/business/model/order.go +++ b/business/model/order.go @@ -32,6 +32,8 @@ const ( OrderTypeMatter = 1 //物料订单 OrderTypeSupplyGoods = 2 //进货订单 OrderTypeDefendPrice = 3 //守价订单 + + OrderTypeDeposit = 1 //保证金 ) var ( @@ -457,10 +459,15 @@ type Order struct { Comment string `orm:"size(255)" json:"comment"` //备注 } +func (v *Order) TableUnique() [][]string { + return [][]string{ + []string{"OrderID"}, + } +} + func (v *Order) TableIndex() [][]string { return [][]string{ []string{"CreatedAt"}, - []string{"OrderID"}, []string{"UserID"}, } } diff --git a/conf/app.conf b/conf/app.conf index 1154d9d97..3b1038393 100644 --- a/conf/app.conf +++ b/conf/app.conf @@ -65,12 +65,12 @@ weixinMiniSecret = "e7ec67c86cbd4dfa531af7af7533cdc9" wxpayAppID = "wx4b5930c13f8b1170" wxpayAppKey = "XKJPOIHJ233adf01KJIXlIeQDSDKFJAD" wxpayAppMchID = "1390686702" -wxpayNotifyURL = "http://callback.test.jxc4.com/wxpay/msg/" +wxpayNotifyURL = "http://callback.jxc4team.com/wxpay/msg/" tonglianPayAppID = "00183083" tonglianPayKey = "18048531223" tonglianPayCusID = "56065105499TVAH" -tonglianPayNotifyURL = "http://callback.test.jxc4.com/tonglian/msg/" +tonglianPayNotifyURL = "http://callback.jxc4team.com/tonglian/msg/" backstageHost = "http://www.jxc4.com" wxBackstageHost = "http://wx.jxc4.com" diff --git a/controllers/order_controller.go b/controllers/order_controller.go index 564377ff6..cb136c6d9 100644 --- a/controllers/order_controller.go +++ b/controllers/order_controller.go @@ -39,16 +39,3 @@ func (c *OrderController) CreateOrder() { return retVal, "", err }) } - -// @Title 请求支付订单 -// @Description 请求支付订单 -// @Param token header string true "认证token" -// @Param vendorOrderID formData string true "订单ID" -// @Param payType formData int true "支付类型" -// @Param vendorPayType formData string true "平台支付类型" -// @Success 200 {object} controllers.CallResult -// @Failure 200 {object} controllers.CallResult -// @router /Pay4Order [post] -func (c *OrderController) Pay4Order() { - -} diff --git a/controllers/tonglian_callback.go b/controllers/tonglian_callback.go index 6d33cb8c2..bf64cb480 100644 --- a/controllers/tonglian_callback.go +++ b/controllers/tonglian_callback.go @@ -5,10 +5,11 @@ import ( "io/ioutil" "net/http" + "git.rosy.net.cn/jx-callback/business/jxstore/financial" + "git.rosy.net.cn/jx-callback/globals/api" "git.rosy.net.cn/baseapi/utils" - "git.rosy.net.cn/jx-callback/business/partner/purchase/jx/localjx" "git.rosy.net.cn/jx-callback/globals" "github.com/astaxie/beego" @@ -24,7 +25,7 @@ func (c *TongLianController) Msg() { call, err := api.TLpayAPI.GetCallbackMsg(getUsefulRequest2(c.Ctx)) globals.SugarLogger.Debugf("tonglianapi callback callbackResponse:%s", utils.Format4Output(call, true)) if err == nil { - err = localjx.OnTLPayCallback(call) + err = financial.OnTLPayCallback(call) } c.Data["json"] = call c.ServeJSON()