package pay import ( "crypto" "crypto/rand" "crypto/rsa" "crypto/sha256" "crypto/x509" "encoding/base64" "encoding/pem" "errors" "fmt" "hash" "log" "strings" "sync" "time" config "bp.jydev.jianyu360.cn/BaseService/payCenter/entity" // "util" qutil "app.yhyue.com/moapp/jybase/common" ) /* 数据库字段 | 页面dotype ----------------------- vip订阅 | subvip 企业商机管理 | entniche 历史数据 | dataexport 招投标课程 | course 数据报告 | datareport 中标必听课 | onlineCourse 大会员 | member AI中标预测包 | aiForecastPack 招标文件解读 | bidfile */ var ( vipMap = map[string]string{ "wx_js": WX_SUBVIP_JSAPI, "wx_app": WX_SUBVIP_APP, "wx_pc": WX_SUBVIP_NATIVE, "ali_app": ALI_SUBVIP_APP, "ali_pc": ALI_SUBVIP_NATIVE, } entnicheMap = map[string]string{ "wx_app": WX_ENTNICHE_APP, "wx_pc": WX_ENTNICHE_NATIVE, "ali_app": ALI_ENTNICHE_APP, "ali_pc": ALI_ENTNICHE_NATIVE, //"wx_js": "", } dataexportMap = map[string]string{ "wx_js": WX_DATAEXPORT_JSAPI, "wx_app": WX_DATAEXPORT_APP, "wx_pc": WX_DATAEXPORT_NATIVE, "ali_app": ALI_DATAEXPORT_APP, "ali_pc": ALI_DATAEXPORT_NATIVE, } courseMap = map[string]string{ "wx_js": WX_COURSE_JSAPI, "wx_app": WX_COURSE_APP, "wx_pc": WX_COURSE_NATIVE, "ali_app": ALI_COURSE_APP, "ali_pc": ALI_COURSE_NATIVE, } datareportMap = map[string]string{ "wx_js": WX_DATAREPORT_JSAPI, "wx_app": WX_DATAREPORT_APP, "wx_pc": WX_DATAREPORT_NATIVE, "ali_app": ALI_DATAREPORT_APP, "ali_pc": ALI_DATAREPORT_NATIVE, } onlineCourseMap = map[string]string{ "wx_js": WX_COURSEONLINE_JSAPI, "wx_app": WX_COURSEONLINE_APP, "wx_pc": WX_COURSEONLINE_NATIVE, "ali_app": ALI_COURSEONLINE_APP, "ali_pc": ALI_COURSEONLINE_NATIVE, } //大会员 memberMap = map[string]string{ "wx_js": WX_MEMBER_JSAPI, "wx_app": WX_MEMBER_APP, "wx_pc": WX_MEMBER_NATIVE, "ali_app": ALI_MEMBER_APP, "ali_pc": ALI_MEMBER_NATIVE, } //AI中标预测包 aiForecastPackMap = map[string]string{ "wx_js": WX_AIFORECASTPACK_JSAPI, "wx_app": WX_AIFORECASTPACK_APP, "wx_pc": WX_AIFORECASTPACK_NATIVE, "ali_app": ALI_AIFORECASTPACK_APP, "ali_pc": ALI_AIFORECASTPACK_NATIVE, } bifileMap = map[string]string{ "wx_js": WX_BIDFILE_JSAPI, "wx_app": WX_BIDFILE_APP, "wx_pc": WX_BIDFILE_NATIVE, "ali_app": ALI_BIDFILE_APP, "ali_pc": ALI_BIDFILE_NATIVE, } //剑鱼币 integralMap = map[string]string{ "wx_js": WX_INTEGRAL_JSAPI, "wx_app": WX_INTEGRAL_APP, "wx_pc": WX_INTEGRAL_NATIVE, "ali_app": ALI_INTEGRAL_APP, "ali_pc": ALI_INTEGRAL_NATIVE, } //数据流量包 dataPackMap = map[string]string{ "wx_js": WX_DATAPACK_JSAIP, "wx_app": WX_DATAPACK_APP, "wx_pc": WX_DATAPACK_NATIVE, "ali_app": ALI_DATAPACK_APP, "ali_pc": ALI_DATAPACK_NATIVE, } //省份订阅包 areaPackMap = map[string]string{ "wx_js": WX_AREAPACK_JSAPI, "wx_app": WX_AREAPACK_APP, "wx_pc": WX_AREAPACK_NATIVE, "ali_app": ALI_AREAPACK_APP, "ali_pc": ALI_AREAPACK_NATIVE, } //附件下载包 filePackMap = map[string]string{ "wx_js": WX_FILEPACK_JSAPI, "wx_app": WX_FILEPACK_APP, "wx_pc": WX_FILEPACK_NATIVE, "ali_app": ALI_FILEPACK_APP, "ali_pc": ALI_FILEPACK_NATIVE, } //采购单位画像包 buyerPortraitPackMap = map[string]string{ "wx_js": WX_BUYERPORTRAITPACK_JSAPI, "wx_app": WX_BUYERPORTRAITPACK_APP, "wx_pc": WX_BUYERPORTRAITPACK_NATIVE, "ali_app": ALI_BUYERPORTRAITPACK_APP, "ali_pc": ALI_BUYERPORTRAITPACK_NATIVE, } PayWayAndSign = map[string]map[string]string{ "subvip": vipMap, "entniche": entnicheMap, "dataexport": dataexportMap, "course": courseMap, "datareport": datareportMap, "onlineCourse": onlineCourseMap, "member": memberMap, "aiForecastPack": aiForecastPackMap, "bidfile": bifileMap, "integral": integralMap, "areaPack": areaPackMap, "filePack": filePackMap, "buyerPortraitPack": buyerPortraitPackMap, "VIP订阅": vipMap, "企业商机管理": entnicheMap, "历史数据": dataexportMap, "招投标课程": courseMap, "数据报告": datareportMap, "中标必听课": onlineCourseMap, "大会员": memberMap, "大会员-AI中标预测包": aiForecastPackMap, "招标文件解读": bifileMap, "大会员-招标文件解读": bifileMap, "剑鱼币": integralMap, "数据流量包": dataPackMap, "省份订阅包": areaPackMap, "附件下载包": filePackMap, "采购单位画像包": buyerPortraitPackMap, } varOrderCode *orderCode ProductType = map[string]string{ "subvip": "VIP订阅", "entniche": "企业商机管理", "dataexport": "历史数据", "datareport": "数据报告", "onlineCourse": "中标必听课", "member": "大会员", "aiForecastPack": "大会员-AI中标预测包", "integral": "剑鱼币", "dataPack": "数据流量包", "areaPack": "省份订阅包", "filePack": "附件下载包", } ) type orderCode struct { pool chan string all *sync.Map lock *sync.Mutex } func (o *orderCode) gc() { varOrderCode.all.Range(func(key, value interface{}) bool { if time.Now().Day() != value.(int) { varOrderCode.all.Delete(key) } return true }) time.AfterFunc(24*time.Hour, o.gc) } func init() { varOrderCode = &orderCode{ pool: make(chan string, 20), all: &sync.Map{}, lock: &sync.Mutex{}, } varOrderCode.gc() for i := 0; i < 10; i++ { go func() { varOrderCode.lock.Lock() defer varOrderCode.lock.Unlock() for { o := fmt.Sprintf("%d%s", time.Now().Unix()+900000000, qutil.GetRandom(2)) if _, ok := varOrderCode.all.Load(o); ok { continue } varOrderCode.all.Store(o, time.Now().Day()) varOrderCode.pool <- o } }() } } /* 公共创建订单 price 价格 productSign 产品种类标识 ip 用户ip(仅微信支付需要) openid 用户openid(仅微信支付需要) payWay 支付方式 */ func CreateOrderPay(price int, productSign, ip, openid, payWay string) (tradeno, prepayid, payParam string, err error) { switch payWay { case "wx_js", "wx_app", "wx_pc": //微信公众号支付,微信app支付,微信扫码支付 var ret *map[string]string tradeno, ret = WxStruct.CreatePrepayOrder(productSign, ip, openid, "", price) log.Println(tradeno, ret) if ret == nil { err = errors.New("创建异常") return } if (*ret)["status"] != "1" { errMsg := "创建微信订单出错" if (*ret)["errcodedes"] != "" { errMsg = (*ret)["errcodedes"] } else if (*ret)["errcode"] != "" { errMsg = (*ret)["errcode"] } err = errors.New(errMsg) return } prepayid = qutil.ObjToString((*ret)["prepayid"]) if payWay == "wx_js" { payParam = WxStruct.GetWxjsPaySign(prepayid) } else if payWay == "wx_app" { payParam = WxStruct.GetAppWxPayStr(prepayid) } else if payWay == "wx_pc" { payParam = (*ret)["codeurl"] } case "ali_app", "ali_pc": //支付宝app支付,支付宝扫码支付 payParam, tradeno, err = Alipay.GetOrderPayParam(qutil.Float64All(price), productSign) if err != nil { err = errors.New("创建支付宝订单出错") return } } return } //创建订单号 func GetOrderCode(id ...string) string { //2020-08-01之前的规则 fmt.Sprintf("%s%s", time.Now().Format("150405"), qutil.GetRandom(6)) return <-varOrderCode.pool } //关闭订单 func CloseDataExportOrder(payWay, tradeno, prepayTime string) (status bool) { //如果订单超时 则不用关闭订单 t, err := time.ParseInLocation("2006-01-02 15:04:05", prepayTime, time.Local) if err == nil { if t.Add(time.Hour * 2).Before(time.Now()) { return true } } //没有选择支付方式或者是测试数据 if payWay == "" || payWay == "测试使用" || payWay == "transferAccounts" || tradeno == "" { return true } log.Printf("%s取消订单,订单号%s\n", payWay, tradeno) if strings.HasPrefix(payWay, "ali_") { status = Alipay.CloseOrder(tradeno) } else if strings.HasPrefix(payWay, "wx_") { status = WxStruct.CloseOrder(tradeno, payWay) } if !status { log.Printf("%s订单关闭失败:%s\n", payWay, tradeno) } return status } //加载秘钥 func parsePrivateKey(key string) (*rsa.PrivateKey, error) { block, _ := pem.Decode([]byte(key)) if block == nil { return nil, errors.New("私钥格式不正确") } if strings.ToUpper(block.Type) != "RSA PRIVATE KEY" { return nil, errors.New("私钥类型不正确" + block.Type) } rsaPrivateKey, err := x509.ParsePKCS8PrivateKey(block.Bytes) if err != nil { return nil, err } return rsaPrivateKey.(*rsa.PrivateKey), nil } //加载支付宝后台公钥 func parseAliPayPublicKey(key string) (*rsa.PublicKey, error) { publicKeyDecoded, err := base64.StdEncoding.DecodeString(key) if err != nil { return nil, err } pub, err := x509.ParsePKIXPublicKey(publicKeyDecoded) if err != nil { return nil, err } if pub, ok := pub.(*rsa.PublicKey); ok { return pub, nil } return nil, errors.New("rsa.PublicKey 断言出错") } //生成加密token func (a *aliPayStruct) getSign(data []byte) (signature string, err error) { var h hash.Hash var hType crypto.Hash h = sha256.New() hType = crypto.SHA256 //} h.Write(data) d := h.Sum(nil) bs, err := rsa.SignPKCS1v15(rand.Reader, a.PrivateKey, hType, d) if err != nil { return "", err } signature = base64.StdEncoding.EncodeToString(bs) return } //处理商户订单号 func processTradeno(tradeno string) string { devTradenoSign := qutil.ObjToString(config.PayConf["devTradenoSign"]) if devTradenoSign != "" { tradeno = devTradenoSign + tradeno tradeno = string([]rune(tradeno)[:len([]rune(tradeno))-len([]rune(devTradenoSign))]) } return tradeno }