package service import ( "bytes" "database/sql" "encoding/json" "errors" "fmt" "io/ioutil" "log" "net/http" "strconv" "strings" "time" "xiaoniaokuaiyan.com/xiaoniao/config" "xiaoniaokuaiyan.com/xiaoniao/pay/wx" "gopkg.in/guregu/null.v3" "xiaoniaokuaiyan.com/xiaoniao/dal" "xiaoniaokuaiyan.com/xiaoniao/entity" "xiaoniaokuaiyan.com/xiaoniao/util" ) type ActivityService struct { *WeixinService } func (srv *ActivityService) AddReporter(reporter *entity.ActReporter) (interface{}, error) { if !util.IsMobile(reporter.Mobile) { return nil, errors.New("wrong mobile phone number") } db := util.GetWriteSqlDB() reporter.CreatedAt = time.Now().Format("2006-01-02 15:04:05") strSql, mkv := util.GenerateInsertSqlFromStruct("t_activity_reporter", reporter) result, err := db.NamedExec(strSql, mkv) if err != nil { return nil, err } if ra, _ := result.RowsAffected(); ra <= 0 { return nil, errors.New("add failed") } return true, nil } func (srv *ActivityService) AddActInfo(item *entity.ActInfo) (interface{}, error) { db := util.GetWriteSqlDB() if strings.HasPrefix(item.Source, "-") { item.Source = item.Source[1:] strSql := "select count(*) from t_activity_info where mobile = ? and source = ?;" var tc int derr := db.Get(&tc, strSql, item.Mobile.String, item.Source) if derr != nil { return nil, derr } if tc > 0 { return nil, errors.New("1::already submit") } } var params = map[string]string{} if item.Extra.Valid && item.Extra.String != "" { err := json.Unmarshal([]byte(item.Extra.String), ¶ms) if err != nil { return nil, err } } if item.Source == "medicine" || item.Source == "SendBack" || item.Source == "directbind" { smsSvc := &SMSService{ ISMSCode: dal.DefaultSMSCodeDal, } _, err := smsSvc.ValidateCode(item.Mobile.String, params["vcode"], 8) if err != nil { return nil, errors.New("2::wrong validate code") } var bindTimes int var todayStr = time.Now().Format("2006-01-02") db.Get(&bindTimes, "SELECT count(distinct ex_code) from t_activity_info where mobile = ? and source =? and (created_at between ? and ?);", item.Mobile.String, item.Source, todayStr, todayStr+" 23:59:59") //20211127 从1 改成5 if bindTimes >= 5 { return nil, errors.New("3::beyond binding times today") } } item.CreatedAt = time.Now().Format("2006-01-02 15:04:05") strSql, mkv := util.GenerateInsertSqlFromStruct("t_activity_info", item) result, err := db.NamedExec(strSql, mkv) if err != nil { return nil, err } if ra, _ := result.RowsAffected(); ra <= 0 { return nil, errors.New("add failed") } id, _ := result.LastInsertId() item.Id = int(id) //保存订单信息 if item.Source == "medicine" || item.Source == "SendBack" { if !item.ExCode.Valid || item.ExCode.String == "" { //20220623 如果ExCode 是空,直接跳转结尾并且通知redis goto JUMP } var upItem = struct { CustomName string `db:"custom_name"` Mobile string `db:"mobile"` Age int `db:"age"` Birthday string `db:"birthday"` Gender string `db:"gender"` ExpressStatus string `db:"expressstatus"` }{} err = db.Get(&upItem, "select name as custom_name, gender, age, mobile,birthday, expressstatus from t_order t1 left join t_order_extra t2 on t1.id = t2.order_id where id = ?;", item.ExCode.String) if err != nil { //return nil, err //20220623 去除返回报错逻辑,直接跳转结尾并且通知redis goto JUMP } //20220520 修改生日逻辑 var sqlResult sql.Result if _, ok := params["birthday"]; ok { btime, _ := time.Parse("2006-01-02", params["birthday"]) age := time.Now().Year() - btime.Year() sqlResult, err = db.Exec("update t_order set name =?, gender =?, age =?, mobile =?, birthday =? where id = ?", item.CustomName.String, item.Gender.String, age, item.Mobile.String, params["birthday"], item.ExCode.String) if err != nil { } else if ra, _ := sqlResult.RowsAffected(); ra > 0 { go util.InsertMongo(item.ExCode.String, "回寄/活动", 1, map[string]interface{}{"name": item.CustomName.String, "gender": item.Gender.String, "age": age, "mobile": item.Mobile.String, "birthday": params["birthday"], "url": "/act/addinfo"}) } } else { sqlResult, err = db.Exec("update t_order set name =?, mobile =? where id = ?", item.CustomName.String, item.Mobile.String, item.ExCode.String) if err != nil { } else if ra, _ := sqlResult.RowsAffected(); ra > 0 { go util.InsertMongo(item.ExCode.String, "回寄/活动", 1, map[string]interface{}{"name": item.CustomName.String, "mobile": item.Mobile.String, "url": "/act/addinfo"}) } } //20220704 熠保项目 修改 blood_code sqlResult, _ = db.Exec("update t_order set blood_codes =? where id = ? and (trim(blood_codes)='' or blood_codes is null)", item.Address.String, item.ExCode.String) if ra, _ := sqlResult.RowsAffected(); ra > 0 { go util.InsertMongo(item.ExCode.String, "回寄/活动", 1, map[string]interface{}{"blood_codes": item.Address.String, "url": "/act/addinfo"}) db.Exec("insert into t_activity_info(custom_name,age,gender,mobile,address,ex_code,source,created_at) values(?,?,?,?,?,?,'order_update',?);", upItem.CustomName, upItem.Age, upItem.Gender, upItem.Mobile, upItem.Birthday, item.ExCode.String, item.CreatedAt) } } JUMP: //推送消息 msg := map[string]string{ "user": "system", "oper": "add", "source": item.Source, } buf, _ := json.Marshal(msg) client := util.GetRedis() client.Publish("act-change", string(buf)) return item, nil } func (srv *ActivityService) GetActInfo(mobile string, source string) (interface{}, error) { var strSql = "select * from t_activity_info where mobile = ? and source = ?;" if source == "BCODE" { return _getActInfoByBloodcode(mobile) } else if source == "fapiao" || source == "daneng" || source == "renbao" { return _getActInfoByExCode(mobile) } var infos = []entity.ActInfo{} db := util.GetSqlDB() err := db.Select(&infos, strSql, mobile, source) if err != nil { return nil, fmt.Errorf("failed to query actinfo: %v", err) } return infos, nil } func _getActInfoByBloodcode(bcode string) (interface{}, error) { strSql := "select * from t_activity_info where address = ? order by id desc;" var infos = []entity.ActInfo{} db := util.GetSqlDB() err := db.Select(&infos, strSql, bcode) if err != nil { return nil, fmt.Errorf("failed to query actinfo: %v", err) } return infos, nil } // qz add 添加按照excode 查询,20200810 // qz add 添加人保 按照excode 查询 20210629 func _getActInfoByExCode(exCode string) (interface{}, error) { strSql := "select * from t_activity_info where ex_code = ? order by id desc;" var infos = []entity.ActInfo{} db := util.GetSqlDB() err := db.Select(&infos, strSql, exCode) if err != nil { return nil, fmt.Errorf("failed to query actinfo: %v", err) } return infos, nil } func (src *ActivityService) UpdateActInfo(item *entity.ActInfo) (interface{}, error) { var params = map[string]string{} if item.Extra.Valid && item.Extra.String != "" { err := json.Unmarshal([]byte(item.Extra.String), ¶ms) if err != nil { return nil, err } } if item.Source == "fapiao" || item.Source == "daneng" { smsSvc := &SMSService{ ISMSCode: dal.DefaultSMSCodeDal, } _, err := smsSvc.ValidateCode(item.Mobile.String, params["vcode"], 9) if err != nil { return nil, errors.New("2::wrong validate code") } } var source = item.Source item.Source = "" strSql, mkv := util.GenerateUpdateSqlFromStruct("t_activity_info", item, fmt.Sprintf(" where id =%d", item.Id)) db := util.GetWriteSqlDB() _, err := db.NamedExec(strSql, mkv) if err != nil { return nil, err } if source == "SendBack" && item.ExCode.Valid { return _updateSendBack(item) } return false, nil } //func _updateSendBack(item *entity.ActInfo) (interface{}, error) { // var params = map[string]string{} // if item.Extra.Valid && item.Extra.String != "" { // err := json.Unmarshal([]byte(item.Extra.String), ¶ms) // if err != nil { // return nil, err // } // } // var expressStatus string // db := util.GetWriteSqlDB() // err := db.Get(&expressStatus, "select expressstatus from t_order_extra where order_id = ?;", item.ExCode.String) // if err != nil { // return nil, err // } // //20220518 外面source 给洗掉了,而且外面判断sendback了,所以这里去掉sendback判断 // //if item.Source == "SendBack" && (expressStatus == "200" || expressStatus == "100") { // if expressStatus == "200" || expressStatus == "100" { // db.Exec("update t_order_extra set expressstatus='300', express_user=?, expressnumber_user=? where order_id = ?;", params["express"], params["expressno"], item.ExCode.String) // } // return true, nil //} func _updateSendBack(item *entity.ActInfo) (interface{}, error) { var params = map[string]string{} if item.Extra.Valid && item.Extra.String != "" { err := json.Unmarshal([]byte(item.Extra.String), ¶ms) if err != nil { return nil, err } } var data struct { ExpressStatus string `db:"expressstatus"` ExpressTime null.String `db:"express_time"` } db := util.GetWriteSqlDB() err := db.Get(&data, "select expressstatus,express_time from t_order_extra where order_id = ?;", item.ExCode.String) if err != nil { return nil, err } //20220518 外面source 给洗掉了,而且外面判断sendback了,所以这里去掉sendback判断 if data.ExpressStatus == "200" || data.ExpressStatus == "100" { //20220519 修改原来改成状态300 换成改为210 同时判断extra 里面是否有sendStartTime 更新到express_time 字段中 db.Exec("update t_order_extra set expressstatus='210', express_user=?, expressnumber_user=? where order_id = ?;", params["express"], params["expressno"], item.ExCode.String) sst, ok := params["sendStartTime"] if !ok { sst = time.Now().Format("2006-01-02 15:04:05") } if !data.ExpressTime.Valid || data.ExpressTime.String == "" { db.Exec("update t_order_extra set express_time = ? where order_id = ?;", fmt.Sprintf("{\"setStartTime\": \"%s\"}", sst), item.ExCode.String) } else { _, err := db.Exec("update t_order_extra set express_time = JSON_SET(express_time,'$.setStartTime','"+sst+"') where order_id = ?;", item.ExCode.String) fmt.Println(err) } } return true, nil } func (srv *ActivityService) WithdrawActInfo(item *entity.ActInfo) (interface{}, error) { //根据id 获取信息 var strSql = "select * from t_activity_info where id=? and source in ('fapiao','daneng') and status='500'" var infos = entity.ActInfo{} db := util.GetSqlDB() err := db.Get(&infos, strSql, item.Id) if err != nil { return nil, fmt.Errorf("1::failed to query actinfo: %v", err) } var params = map[string]string{} if infos.Extra.Valid && infos.Extra.String != "" { err := json.Unmarshal([]byte(infos.Extra.String), ¶ms) if err != nil { return nil, err } } if params["openid"] == "" || params["price"] == "" { return nil, fmt.Errorf("2::none openid [%s], or price: [%s]", params["openid"], params["price"]) } _, err = strconv.ParseInt(params["price"], 10, 64) if err != nil { return nil, fmt.Errorf("3::price: [%s] not real int ", params["price"]) } strSql = "update t_activity_info set status = '600' where id = ? " tx := db.MustBegin() sqlResult, err := tx.Exec(strSql, item.Id) if err != nil { return false, err } if la, err := sqlResult.RowsAffected(); la <= 0 { return false, err } wxJsSdk := wx.NewJsSdk() weixin := wx.NewWeixin(wx.DefaultConfig["appid"], wx.DefaultConfig["secret"]) nonceStr := wxJsSdk.GenerateNoncestr(32) billno := fmt.Sprintf("HB%s%s", time.Now().Format("20060102150405"), util.RandNumString(6)) reqItem := map[string]string{ "mch_id": wx.DefaultConfig["mch_id"], "nonce_str": nonceStr, "mch_billno": billno, "wxappid": wx.DefaultConfig["appid"], "send_name": "小鸟快验", "re_openid": params["openid"], "total_amount": params["price"], "total_num": "1", "wishing": "报销费用", "client_ip": "127.0.0.1", "act_name": "红包提现", "remark": "readpack", "scene_id": "PRODUCT_4", } sign := wxJsSdk.ComputePaySignature(reqItem, wx.DefaultConfig["apikey"]) reqItem["sign"] = sign rel, err := weixin.SendRedpack(reqItem, wx.DefaultConfig["cert_file"], wx.DefaultConfig["key_file"]) log.Println(rel) str := "" if err != nil { log.Println(err) str = err.Error() } else { arrayByte, _ := json.Marshal(rel) str = string(arrayByte) } if rel["return_code"] == "SUCCESS" && rel["result_code"] == "SUCCESS" { tx.Exec("insert into t_activity_withdraw_record(billno, money, activity_id,openid,result,is_success) values(?,?,?,?,?,1);", billno, params["price"], item.Id, params["openid"], str) //tx.Exec("insert into t_deliver_msg(deliver_user_id, title, content,created_at) values(?,?,?,?);", duId, "余额提取成功", fmt.Sprintf("您于%s成提取%d元,系统以微信红包的形式发送至您的微信账号,注意查收。", time.Now().Format("2006-01-02"), money/100), time.Now().Format("2006-01-02 15:04:05")) tx.Commit() } else { tx.Tx.Rollback() db.Exec("insert into t_activity_withdraw_record(billno, money, activity_id,openid,result,is_success) values(?,?,?,?,?,0);", billno, params["price"], item.Id, params["openid"], str) errCode := 0 var errMsg string switch rel["err_code"] { case "NO_AUTH": errCode = 10 errMsg = "发放失败,此请求可能存在风险,已被微信拦截" case "SENDNUM_LIMIT": errCode = 11 errMsg = "该用户今日领取红包个数超过限制" case "ILLEGAL_APPID": errCode = 13 errMsg = "非法appid,请确认是否为公众号的appid,不能为APP的appid" case "MONEY_LIMIT": errCode = 14 errMsg = "红包金额发放限制" case "SEND_FAILED": errCode = 15 errMsg = "红包发放失败,请更换单号再重试" case "FATAL_ERROR": errCode = 16 errMsg = "openid和原始单参数不一致" case "CA_ERROR": errCode = 17 errMsg = "商户API证书校验出错" case "SIGN_ERROR": errCode = 18 errMsg = "签名错误" case "SYSTEMERROR": errCode = 19 errMsg = "请求已受理,请稍后使用原单号查询发放结果" case "XML_ERROR": errCode = 20 errMsg = "输入xml参数格式错误" case "FREQ_LIMIT": errCode = 21 errMsg = "超过频率限制,请稍后再试" case "API_METHOD_CLOSED": errCode = 22 errMsg = "你的商户号API发放方式已关闭,请联系管理员在商户平台开启" case "NOTENOUGH": errCode = 23 errMsg = "帐号余额不足,请到商户平台充值后再重试" case "OPENID_ERROR": errCode = 24 errMsg = "openid和appid不匹配" case "MSGAPPID_ERROR": errCode = 25 errMsg = "触达消息给用户appid有误" case "ACCEPTMODE_ERROR": errCode = 26 errMsg = "主、子商户号关系校验失败" case "PROCESSING": errCode = 27 errMsg = "请求已受理,请稍后使用原单号查询发放结果" case "PARAM_ERROR": errCode = 28 errMsg = "参数错误" case "SENDAMOUNT_LIMIT": errCode = 29 errMsg = "您的商户号今日发放金额超过限制,如有需要请登录微信支付商户平台更改API安全配置" case "RCVDAMOUNT_LIMIT": errCode = 30 errMsg = "该用户今日领取金额超过限制,如有需要请登录微信支付商户平台更改API安全配置" default: errCode = 4 errMsg = fmt.Sprintf("failure withdraw , check db for more information with billno [%s]", billno) } return nil, fmt.Errorf("%d::[%s]", errCode, errMsg) //return false,nil } return true, nil } // 20220505 开票 func (srv *ActivityService) AddInvoice(item *entity.ActInfo) (interface{}, error) { //todo 查询是否有开票item.excode count, err := GetInvoiceCount(item.ExCode.String) if err != nil || count > 0 { return nil, fmt.Errorf("1::already fapiao record") } url := config.IniConf.Section("server").Key("fapiaoapi").String() param := map[string]string{} err = json.Unmarshal([]byte(item.Extra.String), ¶m) if !item.Extra.Valid || err != nil { return nil, fmt.Errorf("2::data extra error") } param["order_id"] = item.ExCode.String db := util.GetSqlDB() var price int db.Get(&price, "select actual_payment from t_order where id = ?", item.ExCode.String) if price == 0 { return nil, fmt.Errorf("3::payment is 0") } param["price"] = strconv.FormatFloat(float64(price)/100, 'f', -1, 64) path := "/fp/send" b, err := json.Marshal(param) reader := bytes.NewReader(b) resp, err := http.Post(url+path, "application/json", reader) if err != nil { return nil, fmt.Errorf("4::send response error %s", err.Error()) } r, err := ioutil.ReadAll(resp.Body) if err != nil { return nil, fmt.Errorf("5::response read error %s", err.Error()) } defer resp.Body.Close() result := struct { Code int `json:"code"` Msg string `json:"msg"` }{} err = json.Unmarshal(r, &result) if err != nil || result.Code != 0 { return nil, fmt.Errorf("6::response Unmarshal error %s", string(r)) } return "success", nil } // 20220505 获取开票 func GetInvoiceCount(oid string) (int, error) { db := util.GetSqlDB() var count int //err:=db.Get(&count,"select count(1) from t_fapiao_trd where order_id = ? and status !=4",oid) //这里不做状态判断,如果提交过,不论成功失败,不可重复提交,后续问题交由财务或开发处理 err := db.Get(&count, "select count(1) from t_fapiao_trd where order_id = ? ", oid) return count, err } func (srv *ActivityService) GetInvoice(oid string) ([]entity.ActInfo, error) { db := util.GetSqlDB() data := struct { Type string `json:"type"` Title string `json:"title"` Num string `json:"num"` Email string `json:"email"` }{} //20220524 防止之前开票过,这次又开票 var strSql = "select * from t_activity_info where ex_code = ? and source = ?;" var infos = []entity.ActInfo{} db.Select(&infos, strSql, oid, "invoice") if len(infos) > 0 { return infos, nil } err := db.Get(&data, "select type,title,tax_num as num,email from t_fapiao_trd where order_id = ? order by created_at desc limit 1", oid) if err != nil { return nil, fmt.Errorf("failed to query invoice: %v", err) } b, _ := json.Marshal(data) return []entity.ActInfo{{ ExCode: null.StringFrom(oid), Extra: null.StringFrom(string(b)), }}, nil }