|
@@ -0,0 +1,437 @@
|
|
|
+package timetask
|
|
|
+
|
|
|
+import (
|
|
|
+ "bytes"
|
|
|
+ "database/sql"
|
|
|
+ "fmt"
|
|
|
+ "log"
|
|
|
+ "math/rand"
|
|
|
+ "qfw/util"
|
|
|
+ "qfw/util/jy"
|
|
|
+ . "service/config"
|
|
|
+ "strconv"
|
|
|
+ "strings"
|
|
|
+ "time"
|
|
|
+ . "util"
|
|
|
+
|
|
|
+ "github.com/tealeg/xlsx"
|
|
|
+)
|
|
|
+
|
|
|
+type timetaskConf struct {
|
|
|
+ Settlement struct {
|
|
|
+ Day int
|
|
|
+ Time string
|
|
|
+ }
|
|
|
+ ToCashout struct {
|
|
|
+ Day int
|
|
|
+ Time string
|
|
|
+ }
|
|
|
+ FlyerUserTime string
|
|
|
+ ShareAutoInc map[string][]*shareAutoInc
|
|
|
+ Finance struct {
|
|
|
+ ReTry int
|
|
|
+ From string
|
|
|
+ Title string
|
|
|
+ Fname string
|
|
|
+ Mails []string
|
|
|
+ }
|
|
|
+}
|
|
|
+type shareAutoInc struct {
|
|
|
+ Hour string
|
|
|
+ Inc string
|
|
|
+ Duration string
|
|
|
+}
|
|
|
+
|
|
|
+var (
|
|
|
+ TimetaskConf *timetaskConf
|
|
|
+)
|
|
|
+
|
|
|
+func init() {
|
|
|
+ util.ReadConfig("./timetask.json", &TimetaskConf)
|
|
|
+}
|
|
|
+
|
|
|
+var ShareUser []map[string]interface{}
|
|
|
+
|
|
|
+type myWrite struct {
|
|
|
+ Byte *bytes.Buffer
|
|
|
+}
|
|
|
+
|
|
|
+func (m *myWrite) Write(p []byte) (n int, err error) {
|
|
|
+ n, err = m.Byte.Write(p)
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+type settlementFx struct {
|
|
|
+ name string //姓名
|
|
|
+ idcard string //身份证号
|
|
|
+ commission float64 //佣金
|
|
|
+ tax float64 //个税
|
|
|
+}
|
|
|
+
|
|
|
+var fx *xlsx.File
|
|
|
+
|
|
|
+func init() {
|
|
|
+ //20号把已结算的佣金转入可提现金额
|
|
|
+ go toCashOut()
|
|
|
+ //虚拟分享次数
|
|
|
+ go func() {
|
|
|
+ for k, v := range TimetaskConf.ShareAutoInc {
|
|
|
+ shareCount(k, v)
|
|
|
+ time.Sleep(50 * time.Millisecond)
|
|
|
+ }
|
|
|
+ }()
|
|
|
+ //介绍页用户头像姓名
|
|
|
+ //go util.SimpleCrontab(true, TimetaskConf.FlyerUserTime, Getshareinfo)
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+/*
|
|
|
+应纳税额计算方法
|
|
|
+
|
|
|
+劳务报酬所得
|
|
|
+级数 预扣预缴应纳税所得额 预扣税率 速算扣除数
|
|
|
+1 不超过20000元的部分 20% 0
|
|
|
+2 超过20000元至50000元的部分 30% 2000
|
|
|
+3 超过50000元的部分 40% 7000
|
|
|
+
|
|
|
+预扣预缴应纳税所得额的计算方式:
|
|
|
+预扣预缴应纳税所得额=劳务报酬(小于4000元)-800元
|
|
|
+预扣预缴应纳税所得额=劳务报酬(超过4000元)*(1-20%)
|
|
|
+应纳税额的计算公式:
|
|
|
+应纳税额=预扣预缴应纳税所得额*适用税率-速算扣除数
|
|
|
+备注:
|
|
|
+1.劳务报酬所得在800元以下的,不需要缴纳个人所得税
|
|
|
+2.劳务报酬所得大于800元且没有超过4000元,可减除800元的扣除费用
|
|
|
+3.劳务报酬所得超过4000元的,可减除劳务报酬收入20%的扣除费用
|
|
|
+
|
|
|
+举例:
|
|
|
+1.劳务报酬收入为2000
|
|
|
+预扣预缴应纳税所得额=2000-800=1200
|
|
|
+应纳税额=1200*20%=240
|
|
|
+
|
|
|
+2.劳务报酬收入为4500
|
|
|
+预扣预缴应纳税所得额=4500*(1-20%)=3600
|
|
|
+应纳税额=3600*20%=720
|
|
|
+
|
|
|
+3.劳务报酬收入为30000
|
|
|
+预扣预缴应纳税所得额=30000*(1*20%)=24000
|
|
|
+应纳税额=24000*30%-2000=5200
|
|
|
+*/
|
|
|
+func TaxPayable(commission float64) int64 {
|
|
|
+ var tax_cash float64 //应纳税额
|
|
|
+ var ynssde float64 //预扣预缴应纳税所得额
|
|
|
+ if commission > 800 && commission <= 4000 {
|
|
|
+ ynssde = commission - 800
|
|
|
+ } else if commission > 4000 {
|
|
|
+ ynssde = commission * 0.8
|
|
|
+ }
|
|
|
+ if ynssde > 0 {
|
|
|
+ sysl := 0.2 //适用税率
|
|
|
+ var sskcs float64 //速算扣除数
|
|
|
+ if ynssde > 20000 && ynssde <= 50000 {
|
|
|
+ sysl = 0.3
|
|
|
+ sskcs = 2000
|
|
|
+ } else if ynssde > 50000 {
|
|
|
+ sysl = 0.4
|
|
|
+ sskcs = 7000
|
|
|
+ }
|
|
|
+ tax_cash = ynssde*sysl - sskcs
|
|
|
+ }
|
|
|
+ return int64(util.RetainDecimal(tax_cash, 2) * 100)
|
|
|
+}
|
|
|
+
|
|
|
+//虚拟分享次数
|
|
|
+func shareCount(product string, shareAutoIncs []*shareAutoInc) {
|
|
|
+ defer util.Catch()
|
|
|
+ hour := time.Now().Hour()
|
|
|
+ for _, v := range shareAutoIncs {
|
|
|
+ hour_array := strings.Split(v.Hour, "-")
|
|
|
+ if len(hour_array) != 2 {
|
|
|
+ log.Println("配置项 hour error")
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ hour_min, err := strconv.Atoi(hour_array[0])
|
|
|
+ if err != nil {
|
|
|
+ log.Println("配置项 hour_min error", err)
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ hour_max, err := strconv.Atoi(hour_array[1])
|
|
|
+ if err != nil {
|
|
|
+ log.Println("配置项 hour_max error", err)
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ if hour < hour_min || hour > hour_max {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ inc_array := strings.Split(v.Inc, "-")
|
|
|
+ if len(inc_array) != 2 {
|
|
|
+ log.Println("配置项 inc error")
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ duration_array := strings.Split(v.Duration, "-")
|
|
|
+ if len(duration_array) != 2 {
|
|
|
+ log.Println("配置项 duration error")
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ //
|
|
|
+ inc_min, err := strconv.Atoi(inc_array[0])
|
|
|
+ if err != nil {
|
|
|
+ log.Println("配置项 inc_min error", err)
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ inc_max, err := strconv.Atoi(inc_array[1])
|
|
|
+ if err != nil {
|
|
|
+ log.Println("配置项 inc_max error", err)
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ //
|
|
|
+ duration_min, err := strconv.Atoi(duration_array[0])
|
|
|
+ if err != nil {
|
|
|
+ log.Println("配置项 duration_min error", err)
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ duration_max, err := strconv.Atoi(duration_array[1])
|
|
|
+ if err != nil {
|
|
|
+ log.Println("配置项 duration_max error", err)
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ //
|
|
|
+ r := rand.New(rand.NewSource(time.Now().UnixNano()))
|
|
|
+ inc := r.Intn(inc_max)
|
|
|
+ if inc < inc_min {
|
|
|
+ inc += inc_min
|
|
|
+ }
|
|
|
+ duration_m := r.Intn(duration_max)
|
|
|
+ if duration_m < duration_min {
|
|
|
+ duration_m += duration_min
|
|
|
+ }
|
|
|
+ duration_s := r.Intn(duration_max)
|
|
|
+ if duration_s < duration_min {
|
|
|
+ duration_s += duration_min
|
|
|
+ }
|
|
|
+ d := time.Duration(duration_m)*time.Minute + time.Duration(duration_s)*time.Second
|
|
|
+ MQFW.Update("dis_product", map[string]interface{}{
|
|
|
+ "s_name": product,
|
|
|
+ }, map[string]interface{}{
|
|
|
+ "$inc": map[string]interface{}{
|
|
|
+ "i_shareCount": inc,
|
|
|
+ },
|
|
|
+ }, false, false)
|
|
|
+ log.Println(product, "分享次数自增", "hour", hour, "inc", inc, "duration", d)
|
|
|
+ time.AfterFunc(d, func() {
|
|
|
+ shareCount(product, shareAutoIncs)
|
|
|
+ })
|
|
|
+ return
|
|
|
+ }
|
|
|
+ log.Println("没有符合条件的配置项,请检查配置项!")
|
|
|
+}
|
|
|
+
|
|
|
+func Getshareinfo() {
|
|
|
+ log.Println("开始获取1000名用户头像")
|
|
|
+ ShareUser = []map[string]interface{}{}
|
|
|
+ data, ok := MQFW.Find("user", map[string]interface{}{
|
|
|
+ "$or": []map[string]interface{}{
|
|
|
+ map[string]interface{}{"s_headimageurl": map[string]interface{}{"$exists": true}},
|
|
|
+ map[string]interface{}{"s_headimage": map[string]interface{}{"$exists": true}},
|
|
|
+ },
|
|
|
+ "i_appid": 2,
|
|
|
+ }, `{"l_registedate":-1}`, `{"s_headimageurl":1,"s_headimage":1,"s_phone":1,"s_m_phone":1,"s_nickname":1}`, false, 0, 300)
|
|
|
+ if ok && data != nil && *data != nil {
|
|
|
+ for _, v := range *data {
|
|
|
+ nickname := ""
|
|
|
+ info := map[string]interface{}{}
|
|
|
+ if s_phone, _ := v["s_phone"].(string); s_phone != "" {
|
|
|
+ nickname = s_phone
|
|
|
+ } else if s_m_phone, _ := v["s_m_phone"].(string); s_m_phone != "" {
|
|
|
+ nickname = s_m_phone
|
|
|
+ } else if s_nickname, _ := v["s_nickname"].(string); s_nickname != "" {
|
|
|
+ nickname = s_nickname
|
|
|
+ }
|
|
|
+ if s_headimageurl, _ := v["s_headimageurl"].(string); s_headimageurl != "" {
|
|
|
+ info["headimageurl"] = s_headimageurl
|
|
|
+ } else if s_headimage, _ := v["s_headimage"].(string); s_headimage != "" {
|
|
|
+ info["headimageurl"] = Sysconfig.Webdomain + s_headimage
|
|
|
+ }
|
|
|
+ info["nickname"] = EncryptionInfo(nickname)
|
|
|
+ if util.ObjToString(info["nickname"]) == "" || util.ObjToString(info["headimageurl"]) == "" {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ ShareUser = append(ShareUser, info)
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func EncryptionInfo(s string) string {
|
|
|
+ if jy.IsPhone(s) {
|
|
|
+ s = string(s[0:3]) + "****" + string(s[len(s)-4:])
|
|
|
+ } else {
|
|
|
+ strArray := []rune(s)
|
|
|
+ length := strings.Count(s, "") - 1
|
|
|
+ if length > 2 {
|
|
|
+ star := ""
|
|
|
+ for i := 0; i < length-2; i++ {
|
|
|
+ star += "*"
|
|
|
+ }
|
|
|
+ s = string(strArray[0:1]) + star + string(strArray[len(strArray)-1:])
|
|
|
+ } else if length == 2 {
|
|
|
+ s = string(strArray[0:1]) + "*"
|
|
|
+ } else {
|
|
|
+ s = ""
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return s
|
|
|
+}
|
|
|
+
|
|
|
+func createSettlementFx(sFxs []*settlementFx) []byte {
|
|
|
+ fx_sheet := fx.Sheets[0]
|
|
|
+ var index = 0
|
|
|
+ var count_commission float64 //合计佣金
|
|
|
+ var count_tax float64 //合计个税
|
|
|
+ for _, v := range sFxs {
|
|
|
+ index++
|
|
|
+ var row *xlsx.Row
|
|
|
+ if index < len(fx_sheet.Rows) {
|
|
|
+ row = fx_sheet.Rows[index]
|
|
|
+ } else {
|
|
|
+ row = fx_sheet.AddRow()
|
|
|
+ }
|
|
|
+ var cell *xlsx.Cell
|
|
|
+ //姓名
|
|
|
+ if len(row.Cells) > 0 {
|
|
|
+ cell = row.Cells[0]
|
|
|
+ } else {
|
|
|
+ cell = row.AddCell()
|
|
|
+ }
|
|
|
+ cell.SetValue(v.name)
|
|
|
+ //身份证号
|
|
|
+ if len(row.Cells) > 1 {
|
|
|
+ cell = row.Cells[1]
|
|
|
+ } else {
|
|
|
+ cell = row.AddCell()
|
|
|
+ }
|
|
|
+ cell.SetValue(v.idcard)
|
|
|
+ //佣金
|
|
|
+ if len(row.Cells) > 2 {
|
|
|
+ cell = row.Cells[2]
|
|
|
+ } else {
|
|
|
+ cell = row.AddCell()
|
|
|
+ }
|
|
|
+ cell.SetValue(fmt.Sprintf("%.2f", v.commission))
|
|
|
+ count_commission += v.commission
|
|
|
+ //个税
|
|
|
+ cell = row.AddCell()
|
|
|
+ if len(row.Cells) > 3 {
|
|
|
+ cell = row.Cells[3]
|
|
|
+ } else {
|
|
|
+ cell = row.AddCell()
|
|
|
+ }
|
|
|
+ cell.SetValue(fmt.Sprintf("%.2f", v.tax))
|
|
|
+ count_tax += v.tax
|
|
|
+ }
|
|
|
+ index += 3
|
|
|
+ fx_sheet.AddRow()
|
|
|
+ fx_sheet.AddRow()
|
|
|
+ fx_sheet.AddRow()
|
|
|
+ //小计上面空三行
|
|
|
+ //小计
|
|
|
+ index++
|
|
|
+ var row *xlsx.Row
|
|
|
+ if index < len(fx_sheet.Rows) {
|
|
|
+ row = fx_sheet.Rows[index]
|
|
|
+ } else {
|
|
|
+ row = fx_sheet.AddRow()
|
|
|
+ }
|
|
|
+ //姓名
|
|
|
+ if len(row.Cells) == 0 {
|
|
|
+ row.AddCell()
|
|
|
+ }
|
|
|
+ //身份证号
|
|
|
+ if len(row.Cells) == 1 {
|
|
|
+ row.AddCell()
|
|
|
+ }
|
|
|
+ var cell *xlsx.Cell
|
|
|
+ //合计佣金
|
|
|
+ if len(row.Cells) > 2 {
|
|
|
+ cell = row.Cells[2]
|
|
|
+ } else {
|
|
|
+ cell = row.AddCell()
|
|
|
+ }
|
|
|
+ cell.SetValue(fmt.Sprintf("小计:%.2f", count_commission))
|
|
|
+ //合计个税
|
|
|
+ cell = row.AddCell()
|
|
|
+ if len(row.Cells) > 3 {
|
|
|
+ cell = row.Cells[3]
|
|
|
+ } else {
|
|
|
+ cell = row.AddCell()
|
|
|
+ }
|
|
|
+ cell.SetValue(fmt.Sprintf("小计:%.2f", count_tax))
|
|
|
+ fpath := "./res/settlement/" + util.NowFormat("20060102150405") + ".xlsx"
|
|
|
+ //
|
|
|
+ w := &myWrite{
|
|
|
+ Byte: &bytes.Buffer{},
|
|
|
+ }
|
|
|
+ if err := fx.Write(w); err != nil {
|
|
|
+ log.Println(fpath, "获取结算列表xlsx文件的byte出错", err)
|
|
|
+ } else {
|
|
|
+ log.Println(fpath, "成功获取结算列表xlsx文件的byte", len(w.Byte.Bytes()))
|
|
|
+ }
|
|
|
+ //
|
|
|
+ if err := fx.Save(fpath); err != nil {
|
|
|
+ log.Println(fpath, "生成结算列表xlsx出错", err)
|
|
|
+ } else {
|
|
|
+ log.Println(fpath, "成功生成结算列表xlsx")
|
|
|
+ }
|
|
|
+ return w.Byte.Bytes()
|
|
|
+}
|
|
|
+
|
|
|
+//20号把已结算的佣金转入可提现金额
|
|
|
+func toCashOut() {
|
|
|
+ util.SimpleCrontab(false, TimetaskConf.ToCashout.Time, func() {
|
|
|
+ defer util.Catch()
|
|
|
+ now := time.Now()
|
|
|
+ if TimetaskConf.ToCashout.Day != now.Day() {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ log.Println("开始执行转入可提现定时任务。。。")
|
|
|
+ stmtOut, err := Mysql.DB.Prepare(`select id,uid,count_cash from dis_count where count_status=0`)
|
|
|
+ if err != nil {
|
|
|
+ log.Println(err)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ defer stmtOut.Close()
|
|
|
+ rows, err := stmtOut.Query()
|
|
|
+ if err != nil {
|
|
|
+ log.Println(err)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if rows != nil {
|
|
|
+ defer rows.Close()
|
|
|
+ }
|
|
|
+ for rows.Next() {
|
|
|
+ var id int64
|
|
|
+ var uid_uint8 []uint8 //用户id
|
|
|
+ var count_cash int64 //结算金额
|
|
|
+ err = rows.Scan(&id, &uid_uint8, &count_cash)
|
|
|
+ if err != nil {
|
|
|
+ log.Println(err)
|
|
|
+ break
|
|
|
+ }
|
|
|
+ uid := string(uid_uint8)
|
|
|
+ nowFormat := util.NowFormat(util.Date_Full_Layout)
|
|
|
+ if Mysql.ExecTx("转入可提现定时任务", func(tx *sql.Tx) bool {
|
|
|
+ ok_1 := int64(1)
|
|
|
+ if count_cash > 0 {
|
|
|
+ ok_1 = Mysql.UpdateOrDeleteBySqlByTx(tx, `update account set money=money+? where uid=?`, count_cash, uid)
|
|
|
+ }
|
|
|
+ ok_2 := Mysql.UpdateOrDeleteBySqlByTx(tx, `update dis_count set count_status=1,timestamp=? where id=?`, nowFormat, id)
|
|
|
+ return ok_1 > 0 && ok_2 > 0
|
|
|
+ }) {
|
|
|
+ log.Println("转入可提现成功", uid, "id", id, "结算金额", count_cash)
|
|
|
+ } else {
|
|
|
+ log.Println("转入可提现失败", uid, "id", id, "结算金额", count_cash)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ log.Println("转入可提现定时任务执行完成。。。")
|
|
|
+ })
|
|
|
+}
|