diff --git a/commission.go b/commission.go new file mode 100644 index 0000000..4681e79 --- /dev/null +++ b/commission.go @@ -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 +} diff --git a/commission_test.go b/commission_test.go new file mode 100644 index 0000000..1be751a --- /dev/null +++ b/commission_test.go @@ -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) +} diff --git a/order_sign.go b/order_sign.go new file mode 100644 index 0000000..12eb663 --- /dev/null +++ b/order_sign.go @@ -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() +} diff --git a/order_sn.go b/order_sn.go new file mode 100644 index 0000000..15a7602 --- /dev/null +++ b/order_sn.go @@ -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() + +} diff --git a/order_sn_test.go b/order_sn_test.go new file mode 100644 index 0000000..e575782 --- /dev/null +++ b/order_sn_test.go @@ -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) +} diff --git a/order_status.go b/order_status.go new file mode 100644 index 0000000..f96d198 --- /dev/null +++ b/order_status.go @@ -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 +}