387 lines
14 KiB
Go
387 lines
14 KiB
Go
package exporter
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
type BuildRequest struct {
|
|
MainTable string
|
|
Datasource string
|
|
Fields []string // table.field
|
|
Filters map[string]interface{}
|
|
}
|
|
|
|
func BuildSQL(req BuildRequest, whitelist map[string]bool) (string, []interface{}, error) {
|
|
if req.MainTable != "order" && req.MainTable != "order_info" {
|
|
return "", nil, errors.New("unsupported main table")
|
|
}
|
|
cols := []string{}
|
|
need := map[string]bool{}
|
|
for _, tf := range req.Fields {
|
|
if !whitelist[tf] {
|
|
return "", nil, errors.New("field not allowed")
|
|
}
|
|
parts := strings.Split(tf, ".")
|
|
if len(parts) != 2 {
|
|
return "", nil, errors.New("invalid field format")
|
|
}
|
|
t, f := parts[0], parts[1]
|
|
need[t] = true
|
|
if t == "order" {
|
|
if req.MainTable == "order_info" {
|
|
switch f {
|
|
case "order_number": f = "order_no"
|
|
case "key": f = "key_code"
|
|
case "creator": f = "user_id"
|
|
case "out_trade_no": f = "out_order_no"
|
|
case "plan_id": f = "activity_id"
|
|
case "reseller_id": f = "merchant_id"
|
|
case "product_id": f = "goods_id"
|
|
case "pay_amount": f = "pay_price"
|
|
case "key_batch_id": f = "key_batch_name"
|
|
}
|
|
cols = append(cols, "`order_info`."+escape(f))
|
|
continue
|
|
}
|
|
if f == "status" {
|
|
cols = append(cols, "CASE `order`.type " +
|
|
"WHEN 1 THEN (CASE `order`.status WHEN 0 THEN '待充值' WHEN 1 THEN '充值中' WHEN 2 THEN '已完成' WHEN 3 THEN '充值失败' WHEN 4 THEN '已取消' WHEN 5 THEN '已过期' WHEN 6 THEN '待支付' END) " +
|
|
"WHEN 2 THEN (CASE `order`.status WHEN 0 THEN '待领取' WHEN 1 THEN '待领取' WHEN 2 THEN '已领取' WHEN 3 THEN '领取失败' WHEN 4 THEN '已取消' WHEN 5 THEN '已过期' WHEN 6 THEN '待支付' END) " +
|
|
"WHEN 3 THEN (CASE `order`.status WHEN 0 THEN '待领取' WHEN 1 THEN '待领取' WHEN 2 THEN '已核销' WHEN 3 THEN '领取失败' WHEN 4 THEN '已取消' WHEN 5 THEN '已过期' WHEN 6 THEN '' END) " +
|
|
"ELSE (CASE `order`.status WHEN 0 THEN '待充值' WHEN 1 THEN '充值中' WHEN 2 THEN '已完成' WHEN 3 THEN '充值失败' WHEN 4 THEN '已取消' WHEN 5 THEN '已过期' WHEN 6 THEN '待支付' END) END AS status")
|
|
} else if f == "type" {
|
|
cols = append(cols, "CASE `order`.type WHEN 1 THEN '直充卡密' WHEN 2 THEN '立减金' WHEN 3 THEN '红包' ELSE '' END AS type")
|
|
} else if f == "type" {
|
|
cols = append(cols, "CASE `order`.type WHEN 1 THEN '直充卡密' WHEN 2 THEN '立减金' WHEN 3 THEN '红包' ELSE '' END AS type")
|
|
} else if f == "pay_type" {
|
|
cols = append(cols, "CASE `order`.pay_type WHEN 1 THEN '支付宝' WHEN 5 THEN '微信' ELSE '' END AS pay_type")
|
|
} else if f == "pay_status" {
|
|
cols = append(cols, "CASE `order`.pay_status WHEN 1 THEN '待支付' WHEN 2 THEN '已支付' WHEN 3 THEN '已退款' ELSE '' END AS pay_status")
|
|
} else {
|
|
cols = append(cols, "`order`."+escape(f))
|
|
}
|
|
} else {
|
|
if t == "order_cash" && f == "receive_status" {
|
|
cols = append(cols, "CASE `order_cash`.receive_status WHEN 0 THEN '待领取' WHEN 1 THEN '领取中' WHEN 2 THEN '领取成功' WHEN 3 THEN '领取失败' ELSE '' END AS receive_status")
|
|
} else if t == "order_cash" && f == "channel" {
|
|
cols = append(cols, "CASE `order_cash`.channel WHEN 1 THEN '支付宝' WHEN 2 THEN '微信' WHEN 3 THEN '云闪付' ELSE '' END AS channel")
|
|
} else if t == "order_voucher" && f == "channel" {
|
|
cols = append(cols, "CASE `order_voucher`.channel WHEN 1 THEN '支付宝' WHEN 2 THEN '微信' ELSE '' END AS channel")
|
|
} else if t == "order_voucher" && f == "status" {
|
|
cols = append(cols, "CASE `order_voucher`.status WHEN 1 THEN '可用' WHEN 2 THEN '已实扣' WHEN 3 THEN '已过期' WHEN 4 THEN '已退款' WHEN 5 THEN '领取失败' WHEN 6 THEN '发放中' WHEN 7 THEN '部分退款' WHEN 8 THEN '已退回' WHEN 9 THEN '发放失败' ELSE '' END AS status")
|
|
} else if t == "order_voucher" && f == "receive_mode" {
|
|
cols = append(cols, "CASE `order_voucher`.receive_mode WHEN 1 THEN '渠道授权用户id' WHEN 2 THEN '手机号或邮箱' ELSE '' END AS receive_mode")
|
|
} else if t == "order_voucher" && f == "out_biz_no" {
|
|
cols = append(cols, "'' AS out_biz_no")
|
|
} else {
|
|
cols = append(cols, "`"+t+"`."+escape(f))
|
|
}
|
|
}
|
|
}
|
|
if len(cols) == 0 {
|
|
return "", nil, errors.New("no fields")
|
|
}
|
|
sb := strings.Builder{}
|
|
sb.WriteString("SELECT ")
|
|
sb.WriteString(strings.Join(cols, ","))
|
|
sb.WriteString(" FROM `" + req.MainTable + "`")
|
|
// JOINs based on need
|
|
// order_detail
|
|
if need["order_detail"] && req.MainTable == "order" {
|
|
sb.WriteString(" LEFT JOIN `order_detail` ON `order_detail`.order_number = `order`.order_number")
|
|
}
|
|
// order_cash
|
|
if need["order_cash"] {
|
|
if req.MainTable == "order_info" {
|
|
sb.WriteString(" LEFT JOIN `order_cash` ON `order_cash`.order_no = `order_info`.order_no")
|
|
} else {
|
|
sb.WriteString(" LEFT JOIN `order_cash` ON `order_cash`.order_number = `order`.order_number")
|
|
}
|
|
}
|
|
// order_voucher
|
|
if need["order_voucher"] {
|
|
if req.MainTable == "order_info" {
|
|
sb.WriteString(" LEFT JOIN `order_voucher` ON `order_voucher`.order_no = `order_info`.order_no")
|
|
} else {
|
|
sb.WriteString(" LEFT JOIN `order_voucher` ON `order_voucher`.order_number = `order`.order_number")
|
|
}
|
|
}
|
|
// order_digit (ymt only)
|
|
if need["order_digit"] && req.MainTable == "order_info" {
|
|
sb.WriteString(" LEFT JOIN `order_digit` ON `order_digit`.order_no = `order_info`.order_no")
|
|
}
|
|
// goods_voucher_batch (ymt)
|
|
if need["goods_voucher_batch"] && req.MainTable == "order_info" {
|
|
sb.WriteString(" LEFT JOIN `goods_voucher_batch` ON `goods_voucher_batch`.channel_batch_no = `order_voucher`.channel_batch_no")
|
|
}
|
|
// goods_voucher_subject_config (ymt)
|
|
if need["goods_voucher_subject_config"] && req.MainTable == "order_info" {
|
|
sb.WriteString(" LEFT JOIN `goods_voucher_subject_config` ON `goods_voucher_subject_config`.id = `goods_voucher_batch`.voucher_subject_id")
|
|
}
|
|
// merchant (ymt)
|
|
if need["merchant"] && req.MainTable == "order_info" {
|
|
sb.WriteString(" LEFT JOIN `merchant` ON `merchant`.id = `order_info`.merchant_id")
|
|
}
|
|
// activity (ymt)
|
|
if need["activity"] && req.MainTable == "order_info" {
|
|
sb.WriteString(" LEFT JOIN `activity` ON `activity`.id = `order_info`.activity_id")
|
|
}
|
|
// plan
|
|
if req.MainTable == "order" {
|
|
if need["plan"] || need["key_batch"] {
|
|
sb.WriteString(" LEFT JOIN `plan` ON `plan`.id = `order`.plan_id")
|
|
}
|
|
if need["key_batch"] {
|
|
sb.WriteString(" LEFT JOIN `key_batch` ON `key_batch`.plan_id = `plan`.id")
|
|
}
|
|
if need["code_batch"] {
|
|
sb.WriteString(" LEFT JOIN `code_batch` ON `code_batch`.key_batch_id = `key_batch`.id")
|
|
}
|
|
if need["voucher"] {
|
|
sb.WriteString(" LEFT JOIN `voucher` ON `voucher`.channel_activity_id = `order_voucher`.channel_activity_id")
|
|
}
|
|
if need["voucher_batch"] {
|
|
sb.WriteString(" LEFT JOIN `voucher_batch` ON `voucher_batch`.voucher_id = `voucher`.id")
|
|
}
|
|
if need["merchant_key_send"] {
|
|
sb.WriteString(" LEFT JOIN `merchant_key_send` ON `order`." + escape("key") + " = `merchant_key_send`.key")
|
|
}
|
|
}
|
|
|
|
args := []interface{}{}
|
|
where := []string{}
|
|
// collect need from filters referencing related tables
|
|
if _, ok := req.Filters["order_cash_cash_activity_id_eq"]; ok {
|
|
need["order_cash"] = true
|
|
}
|
|
if _, ok := req.Filters["order_voucher_channel_activity_id_eq"]; ok {
|
|
need["order_voucher"] = true
|
|
}
|
|
if _, ok := req.Filters["voucher_batch_channel_activity_id_eq"]; ok {
|
|
need["voucher_batch"] = true
|
|
need["voucher"] = true
|
|
need["order_voucher"] = true
|
|
}
|
|
if _, ok := req.Filters["merchant_out_biz_no_eq"]; ok {
|
|
need["merchant_key_send"] = true
|
|
}
|
|
if v, ok := req.Filters["creator_in"]; ok {
|
|
ids := []interface{}{}
|
|
switch t := v.(type) {
|
|
case []interface{}:
|
|
ids = t
|
|
case []int:
|
|
for _, x := range t {
|
|
ids = append(ids, x)
|
|
}
|
|
case []string:
|
|
for _, x := range t {
|
|
ids = append(ids, x)
|
|
}
|
|
}
|
|
if len(ids) == 0 {
|
|
return "", nil, errors.New("creator_in required")
|
|
}
|
|
ph := strings.Repeat("?,", len(ids))
|
|
ph = strings.TrimSuffix(ph, ",")
|
|
if req.MainTable == "order_info" {
|
|
where = append(where, "`order_info`.user_id IN ("+ph+")")
|
|
} else {
|
|
where = append(where, "`order`.creator IN ("+ph+")")
|
|
}
|
|
args = append(args, ids...)
|
|
}
|
|
if v, ok := req.Filters["create_time_between"]; ok {
|
|
var arr []interface{}
|
|
b, _ := json.Marshal(v)
|
|
json.Unmarshal(b, &arr)
|
|
if len(arr) != 2 {
|
|
return "", nil, errors.New("create_time_between requires 2 values")
|
|
}
|
|
if req.MainTable == "order_info" {
|
|
where = append(where, "`order_info`.create_time BETWEEN ? AND ?")
|
|
} else {
|
|
where = append(where, "`order`.create_time BETWEEN ? AND ?")
|
|
}
|
|
args = append(args, arr[0], arr[1])
|
|
}
|
|
if v, ok := req.Filters["type_eq"]; ok {
|
|
var tv int
|
|
switch t := v.(type) {
|
|
case float64:
|
|
tv = int(t)
|
|
case int:
|
|
tv = t
|
|
case string:
|
|
// simple digits parsing
|
|
for i := 0; i < len(t); i++ {
|
|
c := t[i]
|
|
if c < '0' || c > '9' {
|
|
continue
|
|
}
|
|
tv = tv*10 + int(c-'0')
|
|
}
|
|
}
|
|
if tv == 1 || tv == 2 || tv == 3 {
|
|
if req.MainTable == "order_info" {
|
|
where = append(where, "`order_info`.type = ?")
|
|
} else {
|
|
where = append(where, "`order`.type = ?")
|
|
}
|
|
args = append(args, tv)
|
|
}
|
|
}
|
|
if v, ok := req.Filters["out_trade_no_eq"]; ok {
|
|
s := toString(v)
|
|
if s != "" {
|
|
if req.MainTable == "order_info" {
|
|
where = append(where, "`order_info`.out_order_no = ?")
|
|
} else {
|
|
where = append(where, "`order`.out_trade_no = ?")
|
|
}
|
|
args = append(args, s)
|
|
}
|
|
}
|
|
if v, ok := req.Filters["account_eq"]; ok {
|
|
s := toString(v)
|
|
if s != "" {
|
|
if req.MainTable == "order_info" {
|
|
where = append(where, "`order_info`.account = ?")
|
|
} else {
|
|
where = append(where, "`order`.account = ?")
|
|
}
|
|
args = append(args, s)
|
|
}
|
|
}
|
|
if v, ok := req.Filters["plan_id_eq"]; ok {
|
|
s := toString(v)
|
|
if s != "" {
|
|
if req.MainTable == "order_info" {
|
|
where = append(where, "`order_info`.activity_id = ?")
|
|
} else {
|
|
where = append(where, "`order`.plan_id = ?")
|
|
}
|
|
args = append(args, s)
|
|
}
|
|
}
|
|
if v, ok := req.Filters["key_batch_id_eq"]; ok {
|
|
s := toString(v)
|
|
if s != "" {
|
|
if req.MainTable == "order_info" {
|
|
where = append(where, "`order_info`.key_batch_name = ?")
|
|
} else {
|
|
where = append(where, "`order`.key_batch_id = ?")
|
|
}
|
|
args = append(args, s)
|
|
}
|
|
}
|
|
if v, ok := req.Filters["product_id_eq"]; ok {
|
|
s := toString(v)
|
|
if s != "" {
|
|
if req.MainTable == "order_info" {
|
|
where = append(where, "`order_info`.goods_id = ?")
|
|
} else {
|
|
where = append(where, "`order`.product_id = ?")
|
|
}
|
|
args = append(args, s)
|
|
}
|
|
}
|
|
if v, ok := req.Filters["reseller_id_eq"]; ok {
|
|
s := toString(v)
|
|
if s != "" {
|
|
if req.MainTable == "order_info" {
|
|
where = append(where, "`order_info`.merchant_id = ?")
|
|
} else {
|
|
where = append(where, "`order`.reseller_id = ?")
|
|
}
|
|
args = append(args, s)
|
|
}
|
|
}
|
|
if v, ok := req.Filters["code_batch_id_eq"]; ok {
|
|
s := toString(v)
|
|
if s != "" {
|
|
if req.MainTable == "order_info" {
|
|
where = append(where, "`order_info`.supplier_product_id = ?")
|
|
} else {
|
|
where = append(where, "`order`.code_batch_id = ?")
|
|
}
|
|
args = append(args, s)
|
|
}
|
|
}
|
|
if v, ok := req.Filters["order_cash_cash_activity_id_eq"]; ok {
|
|
s := toString(v)
|
|
if s != "" {
|
|
if req.MainTable == "order_info" {
|
|
where = append(where, "`order_cash`.activity_id = ?")
|
|
} else {
|
|
where = append(where, "`order_cash`.cash_activity_id = ?")
|
|
}
|
|
args = append(args, s)
|
|
}
|
|
}
|
|
if v, ok := req.Filters["order_voucher_channel_activity_id_eq"]; ok {
|
|
s := toString(v)
|
|
if s != "" {
|
|
if req.MainTable == "order_info" {
|
|
where = append(where, "`order_voucher`.channel_batch_no = ?")
|
|
} else {
|
|
where = append(where, "`order_voucher`.channel_activity_id = ?")
|
|
}
|
|
args = append(args, s)
|
|
}
|
|
}
|
|
if v, ok := req.Filters["voucher_batch_channel_activity_id_eq"]; ok {
|
|
s := toString(v)
|
|
if s != "" {
|
|
if req.MainTable == "order" { // only marketing schema has voucher_batch
|
|
where = append(where, "`voucher_batch`.channel_activity_id = ?")
|
|
args = append(args, s)
|
|
}
|
|
}
|
|
}
|
|
if v, ok := req.Filters["merchant_out_biz_no_eq"]; ok {
|
|
s := toString(v)
|
|
if s != "" {
|
|
if req.MainTable == "order" { // marketing only
|
|
where = append(where, "`merchant_key_send`.out_biz_no = ?")
|
|
}
|
|
args = append(args, s)
|
|
}
|
|
}
|
|
if len(where) > 0 {
|
|
sb.WriteString(" WHERE ")
|
|
sb.WriteString(strings.Join(where, " AND "))
|
|
}
|
|
return sb.String(), args, nil
|
|
}
|
|
|
|
func escape(s string) string {
|
|
if s == "key" {
|
|
return "`key`"
|
|
}
|
|
if s == "index" {
|
|
return "`index`"
|
|
}
|
|
return s
|
|
}
|
|
|
|
func toString(v interface{}) string {
|
|
switch t := v.(type) {
|
|
case []byte:
|
|
return string(t)
|
|
case string:
|
|
return t
|
|
case int64:
|
|
return strconv.FormatInt(t, 10)
|
|
case int:
|
|
return strconv.Itoa(t)
|
|
case float64:
|
|
return strconv.FormatFloat(t, 'f', -1, 64)
|
|
default:
|
|
return ""
|
|
}
|
|
}
|