| @ -0,0 +1,234 @@ | |||||
| /** | |||||
| * 计算佣金 | |||||
| * 2020/05/22 | |||||
| */ | |||||
| package ordercalc | |||||
| import ( | |||||
| "errors" | |||||
| "strings" | |||||
| ) | |||||
| /** | |||||
| * 计算某一商品对分销商的分销价 | |||||
| * @param business 分销商信息 | |||||
| * @param productSpecialPrice 分销特殊价格 | |||||
| * @param distributionPrice 基础分销价 | |||||
| * @param percentage 分销比例 | |||||
| * @param productPrice 商品销售价 | |||||
| * 2020/05/22 | |||||
| * gz | |||||
| */ | |||||
| func DistributionPrice(business map[string]string, productSpecialPrice []map[string]string, distributionPrice interface{}, percentAge interface{}, productPrice interface{}) (float64, error) { | |||||
| product_price := ToString(productPrice) | |||||
| if len(business) < 1 { | |||||
| return 0, errors.New("参数错误") | |||||
| } | |||||
| _, idExist := business["Id"] | |||||
| _, levelIdExist := business["LevelId"] | |||||
| if !idExist || !levelIdExist { | |||||
| return 0, errors.New("分销商参数错误") | |||||
| } | |||||
| distribution_price := ToString(distributionPrice) | |||||
| distribution_price_float, err := ToFloat64(distributionPrice) | |||||
| if err != nil { | |||||
| return 0, err | |||||
| } | |||||
| percent_age := ToString(percentAge) | |||||
| if len(productSpecialPrice) < 1 && percent_age == "" { | |||||
| return distribution_price_float, nil //没有特殊价格,没有分销比例,返回原分销价 | |||||
| } | |||||
| var formula string //分销价计算公式 | |||||
| var is_special_price bool = false //是否使用特殊价格方式,因特殊价格中可能只能会员价,记录以供再次判断 | |||||
| var ok bool | |||||
| if len(productSpecialPrice) > 0 { //特殊价格方式 | |||||
| is_special_price = true //有一条特殊价格,则是使用特殊价 | |||||
| for _, item := range productSpecialPrice { | |||||
| if _, ok = item["BusinessId"]; ok { | |||||
| if item["BusinessId"] != "0" && item["BusinessId"] == business["Id"] { | |||||
| formula = item["DistributionPrice"] | |||||
| break | |||||
| } | |||||
| } | |||||
| if _, ok = item["BusinessLevelId"]; ok { | |||||
| if item["BusinessLevelId"] != "0" && item["BusinessLevelId"] == business["LevelId"] { | |||||
| formula = item["DistributionPrice"] | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| var price []string | |||||
| var result float64 = 0 //最终分销价 | |||||
| if is_special_price { | |||||
| if formula != "" { | |||||
| formula = strings.Replace(formula, "#distribution_price#", distribution_price, 1) | |||||
| } else { | |||||
| formula = distribution_price | |||||
| } | |||||
| //计算表达式 | |||||
| switch { | |||||
| case strings.Contains(formula, "+"): | |||||
| price = strings.Split(formula, "+") | |||||
| result = FloatAdd(price[0], price[1]) | |||||
| case strings.Contains(formula, "-"): | |||||
| price = strings.Split(formula, "-") | |||||
| result = FloatSub(price[0], price[1]) | |||||
| case strings.Contains(formula, "*"): | |||||
| price = strings.Split(formula, "*") | |||||
| result = FloatMul(price[0], price[1], 2) | |||||
| case strings.Contains(formula, "/"): | |||||
| price = strings.Split(formula, "/") | |||||
| result = FloatQuo(price[0], price[1], 2) | |||||
| default: | |||||
| //使用固定价格或者使用基础分销价 | |||||
| if formula != "" { | |||||
| result, _ = ToFloat64(formula) | |||||
| } else { | |||||
| result = distribution_price_float | |||||
| } | |||||
| } | |||||
| } else { | |||||
| //使用分销比例 | |||||
| if product_price == "" { | |||||
| return 0, errors.New("商品价格错误") | |||||
| } | |||||
| price = strings.Split(percent_age, ":") | |||||
| totalCommission := FloatSub(productPrice, distributionPrice) //总佣金 | |||||
| if totalCommission <= 0 { | |||||
| return ToFloat64(productPrice) //总佣金为负,返回商品原价 | |||||
| } | |||||
| if _, ok = business["Grade"]; ok { | |||||
| level_count := len(price) //分销级数 | |||||
| var totalPercent, cent, commission float64 //总分配份数,分销比例,获得的佣金 | |||||
| switch level_count { | |||||
| case 3: | |||||
| totalPercent = FloatAdd(price[0], price[1], price[2]) | |||||
| if totalPercent <= 0 { | |||||
| result = distribution_price_float //佣金分配比例为0,返回基础分销价 | |||||
| } else { | |||||
| switch business["Grade"] { | |||||
| case "1": | |||||
| //一级分销商得到所有佣金 | |||||
| cent = 1 //分销比例 | |||||
| case "2": | |||||
| //二级分销商得到所有佣金 | |||||
| cent = FloatQuo(FloatAdd(price[0], price[1]), totalPercent) //分销比例 | |||||
| case "0", "3": | |||||
| //三级或无级别分销商得到所有佣金 | |||||
| cent = FloatQuo(price[0], totalPercent) //分销比例 | |||||
| } | |||||
| commission = FloatMul(totalCommission, cent, 2) | |||||
| result = FloatSub(productPrice, commission) //分销价=商品价-佣金 | |||||
| } | |||||
| case 2: | |||||
| totalPercent = FloatAdd(price[0], price[1]) | |||||
| if totalPercent <= 0 { | |||||
| result = distribution_price_float //佣金分配比例为0,返回基础分销价 | |||||
| } else { | |||||
| switch business["Grade"] { | |||||
| case "1": | |||||
| //一级分销商得到所有佣金 | |||||
| cent = 1 //分销比例 | |||||
| case "0", "2": | |||||
| //二级或无级别分销商得到所有佣金 | |||||
| cent = FloatQuo(price[0], totalPercent) //分销比例 | |||||
| } | |||||
| commission = FloatMul(totalCommission, cent, 2) | |||||
| result = FloatSub(productPrice, commission) //分销价=商品价-佣金 | |||||
| } | |||||
| case 1: | |||||
| //只有一级 | |||||
| result = distribution_price_float | |||||
| } | |||||
| } else { | |||||
| return 0, errors.New("分销商参数错误,没有分销级别") | |||||
| } | |||||
| } | |||||
| if result < 0 { | |||||
| result, _ = ToFloat64(productPrice) | |||||
| } | |||||
| return result, nil | |||||
| } | |||||
| /** | |||||
| * 计算某一商品的VIP价 | |||||
| * @param productSpecialPrice 特殊价格 | |||||
| * @param productPrice 商品销售价 | |||||
| * 2020/06/05 | |||||
| * gz | |||||
| */ | |||||
| func VipPrice(productSpecialPrice []map[string]string, productPrice interface{}) (float64, error) { | |||||
| product_price := ToString(productPrice) | |||||
| product_price_float, _ := ToFloat64(productPrice) | |||||
| if len(productSpecialPrice) < 1 { | |||||
| return product_price_float, nil //没有特殊价格,返回原价 | |||||
| } | |||||
| var formula string //VIP价计算公式 | |||||
| var ok bool | |||||
| for _, item := range productSpecialPrice { | |||||
| if _, ok = item["RetailPrice"]; ok { | |||||
| if item["RetailPrice"] != "" { | |||||
| formula = item["RetailPrice"] | |||||
| break | |||||
| } | |||||
| } | |||||
| } | |||||
| if formula != "" { | |||||
| formula = strings.Replace(formula, "#retail_price#", product_price, 1) | |||||
| } else { | |||||
| formula = product_price | |||||
| } | |||||
| //计算表达式 | |||||
| var price []string | |||||
| var result float64 = 0 //最终VIP价 | |||||
| switch { | |||||
| case strings.Contains(formula, "+"): | |||||
| price = strings.Split(formula, "+") | |||||
| result = FloatAdd(price[0], price[1]) | |||||
| case strings.Contains(formula, "-"): | |||||
| price = strings.Split(formula, "-") | |||||
| result = FloatSub(price[0], price[1]) | |||||
| case strings.Contains(formula, "*"): | |||||
| price = strings.Split(formula, "*") | |||||
| result = FloatMul(price[0], price[1], 2) | |||||
| case strings.Contains(formula, "/"): | |||||
| price = strings.Split(formula, "/") | |||||
| result = FloatQuo(price[0], price[1], 2) | |||||
| default: | |||||
| result = product_price_float | |||||
| } | |||||
| if result < 0 || result > product_price_float { | |||||
| result = product_price_float | |||||
| } | |||||
| return result, nil | |||||
| } | |||||
| @ -0,0 +1,37 @@ | |||||
| package ordercalc | |||||
| import ( | |||||
| "testing" | |||||
| ) | |||||
| func Test_DistributionPrice(t *testing.T) { | |||||
| business := map[string]string{"Id": "4", "LevelId": "3", "Grade": "3"} | |||||
| productSpecialPrice := make([]map[string]string, 0) | |||||
| price := make(map[string]string) | |||||
| price["BusinessId"] = "0" | |||||
| price["BusinessLevelId"] = "2" | |||||
| // price["DistributionPrice"] = "#distribution_price#+5" | |||||
| price["DistributionPrice"] = "0.05" | |||||
| // productSpecialPrice = append(productSpecialPrice, price) | |||||
| price = make(map[string]string) | |||||
| price["BusinessId"] = "0" | |||||
| price["BusinessLevelId"] = "3" | |||||
| price["DistributionPrice"] = "0.05" | |||||
| // productSpecialPrice = append(productSpecialPrice, price) | |||||
| price = make(map[string]string) | |||||
| price["BusinessId"] = "0" | |||||
| price["BusinessLevelId"] = "" | |||||
| price["DistributionPrice"] = "12" | |||||
| // productSpecialPrice = append(productSpecialPrice, price) | |||||
| dis, err := DistributionPrice(business, productSpecialPrice, 0.07, "7:2:1", 0.5) | |||||
| t.Log(dis) | |||||
| t.Log(err) | |||||
| } | |||||
| @ -0,0 +1,41 @@ | |||||
| package ordercalc | |||||
| import ( | |||||
| "crypto/md5" | |||||
| "encoding/hex" | |||||
| "strings" | |||||
| ) | |||||
| /** | |||||
| * 通知订单状态时签名 | |||||
| * 签名方式:md5(order_sn-status--time---appid) | |||||
| * 2020/08/21 | |||||
| *gz | |||||
| */ | |||||
| func Sign(order_sn, status, time, appid string) string { | |||||
| return Md5Password(StringJoin(order_sn, "--", status, "--", time, "--", appid)) | |||||
| } | |||||
| //密码加密 | |||||
| func Md5Password(password string) string { | |||||
| h := md5.New() | |||||
| h.Write([]byte(password)) // 需要加密的字符串 | |||||
| cipher2Str := h.Sum(nil) | |||||
| sMd5 := hex.EncodeToString(cipher2Str) // 输出加密结果 | |||||
| return sMd5 | |||||
| } | |||||
| /* | |||||
| * 连接多个字符串 | |||||
| * 2019/05/05 | |||||
| */ | |||||
| func StringJoin(s ...string) string { | |||||
| var build strings.Builder | |||||
| if len(s) > 0 { | |||||
| for _, v := range s { | |||||
| build.WriteString(v) | |||||
| } | |||||
| } | |||||
| return build.String() | |||||
| } | |||||
| @ -0,0 +1,69 @@ | |||||
| package ordercalc | |||||
| import ( | |||||
| "math/rand" | |||||
| "strconv" | |||||
| "strings" | |||||
| "time" | |||||
| ) | |||||
| /** | |||||
| * 订单号规则 | |||||
| * id后4位(随机4位)+当前时间(10位) | |||||
| * 2020/08/10 | |||||
| */ | |||||
| func NewOrderSn(user_id string) string { | |||||
| var prefix string | |||||
| if user_id != "" { | |||||
| if len(user_id) > 4 { | |||||
| prefix = user_id[len(user_id)-4:] //截取后4位 | |||||
| } else { | |||||
| prefix = user_id | |||||
| } | |||||
| } else { | |||||
| //随机4位 | |||||
| str := "123456789" | |||||
| bytes := []byte(str) | |||||
| result := []byte{} | |||||
| r := rand.New(rand.NewSource(time.Now().UnixNano())) | |||||
| for i := 0; i < 4; i++ { | |||||
| result = append(result, bytes[r.Intn(len(bytes))]) | |||||
| } | |||||
| prefix = string(result) | |||||
| } | |||||
| //拼接 | |||||
| var build strings.Builder | |||||
| build.WriteString(prefix) | |||||
| build.WriteString(strconv.FormatInt(time.Now().Unix(), 10)) //当前时间 | |||||
| return build.String() | |||||
| } | |||||
| /** | |||||
| * 核销码规则 | |||||
| * 随机2位+当前时间(6位) | |||||
| * 2020/08/10 | |||||
| */ | |||||
| func VerifyNumber() string { | |||||
| var prefix string | |||||
| //随机4位 | |||||
| str := "123456789" | |||||
| bytes := []byte(str) | |||||
| result := []byte{} | |||||
| r := rand.New(rand.NewSource(time.Now().UnixNano())) | |||||
| for i := 0; i < 1; i++ { | |||||
| result = append(result, bytes[r.Intn(len(bytes))]) | |||||
| } | |||||
| prefix = string(result) | |||||
| //拼接 | |||||
| var build strings.Builder | |||||
| build.WriteString(prefix) | |||||
| build.WriteString(strconv.FormatInt(time.Now().UnixNano(), 10)[10:17]) //当前时间 | |||||
| return build.String() | |||||
| } | |||||
| @ -0,0 +1,30 @@ | |||||
| package ordercalc | |||||
| import ( | |||||
| "testing" | |||||
| "time" | |||||
| ) | |||||
| func Test_NewNumber(t *testing.T) { | |||||
| t.Log(time.Now().UnixNano()) | |||||
| var set map[string]int | |||||
| set = make(map[string]int) | |||||
| var i, reply int = 0, 0 | |||||
| var num string | |||||
| for i < 100000 { | |||||
| i++ | |||||
| num = VerifyNumber() | |||||
| if _, ok := set[num]; ok { | |||||
| reply++ | |||||
| } else { | |||||
| set[num] = i | |||||
| } | |||||
| } | |||||
| t.Log("reply:", reply) | |||||
| // t.Log(set) | |||||
| } | |||||
| @ -0,0 +1,176 @@ | |||||
| package ordercalc | |||||
| /** | |||||
| '0': 待支付 下单,尚未支付 created | |||||
| '1':已支付 付款成功,此状态可退款 payed | |||||
| '5':已验证 虚拟订单,验证核销码 using | |||||
| '6':已完成 与供应商结算后,订单结束。配送订单配送完成 finished | |||||
| '7':已取消 订单取消 canceled | |||||
| '8':自动取消 到期未支付自动取消,此状态可由管理员手动延期取消 autocanceled | |||||
| '9':申请退款 用户自助申请退订单,此状态可退款 | |||||
| '13':已退款 订单完成退款 refunded | |||||
| '15':自动完成 使用时间过期,自动完成。 finished | |||||
| cancel,received,payed,created,finished,using | |||||
| ## 发货 | |||||
| is_delivery 是否发货 '1': 已发货 | |||||
| delivery 发货时间 | |||||
| ## 收货 | |||||
| is_received 是否收货 '1': 已收货 | |||||
| received 收货时间 | |||||
| */ | |||||
| var statusList map[string]string = map[string]string{ | |||||
| "0": "created", | |||||
| "1": "payed", | |||||
| "5": "using", | |||||
| "6": "finished", | |||||
| "7": "canceled", | |||||
| "8": "autocanceled", | |||||
| "9": "askForRefund", | |||||
| "13": "refunded", | |||||
| "15": "autofinished", | |||||
| } | |||||
| var statusExtendList map[string]string = map[string]string{ | |||||
| "6": "received", //已收货归入已完成, | |||||
| } | |||||
| /*串货订单,供应商系统订单状态*/ | |||||
| var channelOrderStatusList map[string]string = map[string]string{ | |||||
| "1": "nosend", | |||||
| "2": "created", | |||||
| "3": "payed", | |||||
| "4": "askForRefund", | |||||
| "5": "refunded", | |||||
| "6": "canceled", | |||||
| "7": "finished", | |||||
| "8": "payFailed", //支付失败 | |||||
| "9": "breakoff", //断开 | |||||
| "10": "fullRefund", //全额退款 | |||||
| "14": "autocanceled", | |||||
| "15": "autofinished", | |||||
| "16": "delivered", | |||||
| } | |||||
| func GetOrderStatusKey(status string) (key string) { | |||||
| for k, val := range statusList { | |||||
| if val == status { | |||||
| key = k | |||||
| break | |||||
| } | |||||
| } | |||||
| if key == "" { //再找扩展的状态 | |||||
| for k, val := range statusExtendList { | |||||
| if val == status { | |||||
| key = k | |||||
| break | |||||
| } | |||||
| } | |||||
| } | |||||
| return | |||||
| } | |||||
| func GetOrderStatusText(key string) (text string) { | |||||
| for k, val := range statusList { | |||||
| if k == key { | |||||
| text = val | |||||
| break | |||||
| } | |||||
| } | |||||
| if text == "" { //再找扩展的状态 | |||||
| for k, val := range statusExtendList { | |||||
| if k == key { | |||||
| text = val | |||||
| break | |||||
| } | |||||
| } | |||||
| } | |||||
| return | |||||
| } | |||||
| /** | |||||
| * 返回订单状态描述 | |||||
| * 2021/01/28 | |||||
| */ | |||||
| func GetOrderStatusDescByFlag(flag string) (text string) { | |||||
| status := GetStatusText(flag) | |||||
| return GetStatusDesc(status) | |||||
| } | |||||
| /** | |||||
| * 返回订单状态描述 | |||||
| * 2020/10/22 | |||||
| */ | |||||
| func GetOrderStatusDesc(key string) (text string) { | |||||
| var statusDesc map[string]string = map[string]string{ | |||||
| "created": "已创建", | |||||
| "payed": "已支付", | |||||
| "askForRefund": "请求退款", | |||||
| "using": "使用中", | |||||
| "finished": "已完成", | |||||
| "canceled": "已取消", | |||||
| "autocanceled": "自动取消", | |||||
| "refunded": "已退款", | |||||
| "autofinished": "自动完成", | |||||
| "received": "已收货", | |||||
| } | |||||
| for k, val := range statusDesc { | |||||
| if k == key { | |||||
| text = val | |||||
| break | |||||
| } | |||||
| } | |||||
| return | |||||
| } | |||||
| func GetChannelOrderStatusKey(status string) (key string) { | |||||
| for k, val := range channelOrderStatusList { | |||||
| if val == status { | |||||
| key = k | |||||
| break | |||||
| } | |||||
| } | |||||
| return | |||||
| } | |||||
| func GetChannelOrderStatusText(key string) (text string) { | |||||
| for k, val := range channelOrderStatusList { | |||||
| if k == key { | |||||
| text = val | |||||
| break | |||||
| } | |||||
| } | |||||
| return | |||||
| } | |||||
| /** | |||||
| * 返回订单状态描述 | |||||
| * 2020/10/22 | |||||
| */ | |||||
| func GetChannelOrderStatusDesc(key string) (text string) { | |||||
| var statusDesc map[string]string = map[string]string{ | |||||
| "nosend": "未发送", | |||||
| "created": "已创建", | |||||
| "payed": "已支付", | |||||
| "askForRefund": "请求退款", | |||||
| "refunded": "已退款", | |||||
| "canceled": "已取消", | |||||
| "finished": "已完成", | |||||
| "payFailed": "支付失败", | |||||
| "breakoff": "断开", | |||||
| "fullRefund": "全额退款", | |||||
| "autocanceled": "自动取消", | |||||
| "autofinished": "自动取消", | |||||
| "delivered": "已发货", | |||||
| } | |||||
| for k, val := range statusDesc { | |||||
| if k == key { | |||||
| text = val | |||||
| break | |||||
| } | |||||
| } | |||||
| return | |||||
| } | |||||