Pārlūkot izejas kodu

Merge branch '2.1.0' of http://git.ycjcjy.com/SpaceOfCheng/services into 2.1.0

wangfei 6 gadus atpakaļ
vecāks
revīzija
971bb894dd

+ 25
- 0
bootstrap/bootstrap.go Parādīt failu

@@ -0,0 +1,25 @@
1
+package bootstrap
2
+
3
+import (
4
+	"spaceofcheng/services/models"
5
+	"spaceofcheng/services/service/events"
6
+	"spaceofcheng/services/utils"
7
+)
8
+
9
+// SystemInit 系统初始化
10
+func SystemInit() {
11
+	// 数据库连接
12
+	models.InitDB()
13
+
14
+	// 系统日志
15
+	utils.LogInit()
16
+
17
+	// 微信系统
18
+	utils.WechatInit()
19
+
20
+	// 消息系统
21
+	utils.MessageInit()
22
+
23
+	// 事件系统
24
+	events.EventInit()
25
+}

+ 0
- 21
controllers/base.go Parādīt failu

@@ -97,27 +97,6 @@ func (c *BaseController) ResponseData(data interface{}, msg interface{}, code in
97 97
 	c.StopRun()
98 98
 }
99 99
 
100
-// Options 解决跨域先发送 options
101
-func (c *BaseController) Options() {
102
-	c.ResponseJSON("")
103
-}
104
-
105
-// crosPolicy 跨域策略
106
-func (c *BaseController) crosPolicy() {
107
-	runMode := beego.AppConfig.String("runmode")
108
-	allowMode := beego.AppConfig.String("cros::allowMode")
109
-	allowMethods := beego.AppConfig.String("cros::allowMethods")
110
-	allowOrigin := beego.AppConfig.String("cros::allowOrigin")
111
-	allowCredentials := beego.AppConfig.String("cros::allowCredentials")
112
-
113
-	if runMode == allowMode {
114
-		c.Ctx.Output.Header("Access-Control-Allow-Origin", allowOrigin)
115
-		c.Ctx.Output.Header("Access-Control-Allow-Methods", allowMethods)
116
-		c.Ctx.Output.Header("Access-Control-Allow-Credentials", allowCredentials)
117
-		c.Ctx.Output.Header("Access-Control-Allow-Headers", "X-Token,Authorization")
118
-	}
119
-}
120
-
121 100
 // initAppController 执行当前路由请求对应的 Controller 初始化
122 101
 func (c *BaseController) initController() {
123 102
 	if ctrl, ok := c.AppController.(ControllerInterface); ok {

+ 2
- 7
controllers/bodycheck/bodycheck.go Parādīt failu

@@ -14,9 +14,9 @@ import (
14 14
 
15 15
 // 二维码不多次获取, 只获取一次即可
16 16
 // 临时的解决方案是放到全局单例对象中
17
-var qrCodes map[string]string
17
+var qrCodes = make(map[string]string)
18 18
 
19
-var mtx *sync.Mutex
19
+var mtx = new(sync.Mutex)
20 20
 
21 21
 // BodyCheckController 商品
22 22
 type BodyCheckController struct {
@@ -105,8 +105,3 @@ func (c *BodyCheckController) PostCheckResult() {
105 105
 		"Message": "",
106 106
 	})
107 107
 }
108
-
109
-func init() {
110
-	qrCodes = make(map[string]string)
111
-	mtx = new(sync.Mutex)
112
-}

+ 12
- 14
controllers/config.go Parādīt failu

@@ -3,44 +3,42 @@ package controllers
3 3
 import (
4 4
 	"spaceofcheng/services/utils"
5 5
 
6
-	"github.com/astaxie/beego"
7 6
 	"github.com/astaxie/beego/config"
8 7
 )
9 8
 
10 9
 // 配置文件列表
11 10
 const (
11
+	AppConf    = "app"
12 12
 	AliYunConf = "aliyun"
13 13
 	WeChatConf = "wechat"
14 14
 	SMSConf    = "sms"
15 15
 )
16 16
 
17 17
 func (c *BaseController) initConfig() {
18
-	c.RunMode = beego.AppConfig.String("runmode")
18
+	// c.RunMode = beego.AppConfig.String("runmode")
19 19
 
20 20
 	if c.Configer == nil {
21 21
 		c.Configer = make(map[string]config.Configer)
22 22
 	}
23 23
 
24
+	// 系统
25
+	appConf, _ := utils.GetConfiger("conf/app.conf")
26
+	if appConf != nil {
27
+		c.Configer[AppConf] = appConf
28
+	}
29
+
30
+	c.RunMode = appConf.String("runmode")
31
+
24 32
 	// 阿里云
25
-	aliConf := c.getConfig("conf/aliyun.conf")
33
+	aliConf, _ := utils.GetConfiger("conf/aliyun.conf")
26 34
 	if aliConf != nil {
27 35
 		c.Configer[AliYunConf] = aliConf
28 36
 	}
29 37
 
30 38
 	// 短信
31
-	smsConf := c.getConfig("conf/sms.conf")
39
+	smsConf, _ := utils.GetConfiger("conf/sms.conf")
32 40
 	if smsConf != nil {
33 41
 		c.Configer[SMSConf] = smsConf
34 42
 	}
35 43
 	utils.ResetSMSEngine(smsConf)
36 44
 }
37
-
38
-func (c *BaseController) getConfig(confPath string) config.Configer {
39
-	aliConf, err := config.NewConfig("ini", confPath)
40
-	if err != nil {
41
-		utils.LogError("读取配置文件失败: " + err.Error())
42
-		return nil
43
-	}
44
-
45
-	return aliConf
46
-}

+ 25
- 0
controllers/cros.go Parādīt failu

@@ -0,0 +1,25 @@
1
+package controllers
2
+
3
+// Options 解决跨域先发送 options
4
+func (c *BaseController) Options() {
5
+	c.ResponseJSON("")
6
+}
7
+
8
+// crosPolicy 跨域策略
9
+func (c *BaseController) crosPolicy() {
10
+	appConf, ok := c.Configer[AppConf]
11
+	if ok {
12
+		runMode := appConf.String("runmode")
13
+		allowMode := appConf.String("cros::allowMode")
14
+		allowMethods := appConf.String("cros::allowMethods")
15
+		allowOrigin := appConf.String("cros::allowOrigin")
16
+		allowCredentials := appConf.String("cros::allowCredentials")
17
+
18
+		if runMode == allowMode {
19
+			c.Ctx.Output.Header("Access-Control-Allow-Origin", allowOrigin)
20
+			c.Ctx.Output.Header("Access-Control-Allow-Methods", allowMethods)
21
+			c.Ctx.Output.Header("Access-Control-Allow-Credentials", allowCredentials)
22
+			c.Ctx.Output.Header("Access-Control-Allow-Headers", "X-Token,Authorization")
23
+		}
24
+	}
25
+}

+ 2
- 6
controllers/goods/order.go Parādīt failu

@@ -12,7 +12,7 @@ import (
12 12
 	"time"
13 13
 )
14 14
 
15
-var mtx *sync.Mutex
15
+var mtx = new(sync.Mutex)
16 16
 
17 17
 // GetOrderList 获取商品订单
18 18
 // 管理端 - 统计查询
@@ -140,7 +140,7 @@ func (c *GoodsController) PostOrder() {
140 140
 		)
141 141
 	}
142 142
 
143
-	if err := c.serv.Orders(&orderInfo, orderDetail, customercouponid, innerUser); err != nil {
143
+	if err := c.serv.PreOrders(&orderInfo, orderDetail, customercouponid, innerUser); err != nil {
144 144
 		c.ResponseError(err)
145 145
 	}
146 146
 
@@ -298,7 +298,3 @@ func (c *GoodsController) UpdateOrdersIntimidate() {
298 298
 	}
299 299
 	c.ResponseJSON("操作成功!")
300 300
 }
301
-
302
-func init() {
303
-	mtx = new(sync.Mutex)
304
-}

+ 4
- 0
main.go Parādīt failu

@@ -1,6 +1,7 @@
1 1
 package main
2 2
 
3 3
 import (
4
+	"spaceofcheng/services/bootstrap"
4 5
 	_ "spaceofcheng/services/routers"
5 6
 
6 7
 	"github.com/astaxie/beego"
@@ -11,5 +12,8 @@ func main() {
11 12
 		beego.BConfig.WebConfig.DirectoryIndex = true
12 13
 		beego.BConfig.WebConfig.StaticDir["/swagger"] = "swagger"
13 14
 	}
15
+
16
+	bootstrap.SystemInit()
17
+
14 18
 	beego.Run()
15 19
 }

+ 12
- 0
models/coupon/coupon.go Parādīt failu

@@ -236,6 +236,18 @@ func (m *CouponDAO) SaveCustomerCoupons(cps []model.TaCustomerCoupon) error {
236 236
 	return nil
237 237
 }
238 238
 
239
+// IncreseCouponUsedNum 增加优惠券使用数量
240
+func (m *CouponDAO) IncreseCouponUsedNum(cpID string, num ...int) error {
241
+	sql := `update ta_coupon set used_count=used_count+? where coupon_id=?`
242
+	numAdd := 1
243
+	if len(num) > 0 && num[0] != 0 {
244
+		numAdd = num[0]
245
+	}
246
+
247
+	_, err := m.db.Exec(sql, numAdd, cpID)
248
+	return err
249
+}
250
+
239 251
 // CheckCustCoupon 检查客户是否已经有了该卡券
240 252
 // 如果用户有了卡券, 但是用过了,或者卡券过期了,仍然可以再次拥有
241 253
 func (m *CouponDAO) CheckCustCoupon(custID, couponID string, startDate, endDate time.Time) ([]model.TaCustomerCoupon, error) {

+ 1
- 7
models/course/order.go Parādīt failu

@@ -62,12 +62,6 @@ func (m *CourseDAO) SaveOrdersCoupon(coupon *model.TaCourseOrdersCoupon, order *
62 62
 	coupon.OrdersCouponId = utils.GetGUID()
63 63
 	coupon.Status = models.STATUS_NORMAL
64 64
 	coupon.CreateDate = time.Now().Local()
65
-	if _, err := m.db.Insert(coupon); err != nil {
66
-		return err
67
-	}
68
-
69
-	// 更新优惠券已使用信息
70
-	sql := `update ta_coupon set used_count=used_count+1 where coupon_id='` + coupon.CouponId + `'`
71
-	_, err := m.db.Exec(sql)
65
+	_, err := m.db.Insert(coupon)
72 66
 	return err
73 67
 }

+ 48
- 43
models/goods/orders.go Parādīt failu

@@ -47,7 +47,7 @@ func (m *GoodsDAO) SaveOrders(order *model.TaGoodsOrders) error {
47 47
 	// order.OrdersId = guid.NewGUIDString()
48 48
 	order.OrgId = caseInfo.OrgId
49 49
 	order.CreateDate = now
50
-	order.Status = models.STATUS_NORMAL
50
+	order.Status = models.STATUS_READY
51 51
 	order.IsPay = models.BOOL_TRUE // 默认已支付
52 52
 	order.CouponAmount = "0"
53 53
 	order.IsIntimidate = INTIMIDATE_NO
@@ -77,6 +77,12 @@ func (m *GoodsDAO) UpdateOrdersIntimidate(id string) error {
77 77
 		"orders_id",
78 78
 		"is_intimidate",
79 79
 	}
80
+
81
+	return m.UpdateOrders(&orders, cols)
82
+}
83
+
84
+// UpdateOrders  更新订单
85
+func (m *GoodsDAO) UpdateOrders(orders *model.TaGoodsOrders, cols []string) error {
80 86
 	_, err := m.db.Cols(cols...).Where("orders_id=?", orders.OrdersId).Update(orders)
81 87
 	return err
82 88
 }
@@ -101,53 +107,29 @@ func (m *GoodsDAO) SaveOrdersDetail(list []model.TaGoodsOrdersDetail, ordersID s
101 107
 // SaveOrdersCoupon 保存订单优惠券
102 108
 func (m *GoodsDAO) SaveOrdersCoupon(coupon *model.TaGoodsOrdersCoupon, order *model.TaGoodsOrders) error {
103 109
 	if order.OrdersId == "" {
104
-		return errors.New("内部错误, 订单事务顺序出错")
110
+		return errors.New("保存订单券失败, 订单不存在")
105 111
 	}
106 112
 	coupon.OrdersCouponId = utils.GetGUID()
107 113
 	coupon.Status = models.STATUS_NORMAL
108 114
 	coupon.CreateDate = time.Now().Local()
109
-	if _, err := m.db.Insert(coupon); err != nil {
110
-		return err
111
-	}
115
+	_, err := m.db.Insert(coupon)
112 116
 
113
-	// 更新优惠券已使用信息
114
-	sql := `update ta_coupon set used_count=used_count+1 where coupon_id='` + coupon.CouponId + `'`
115
-	_, err := m.db.Exec(sql)
116 117
 	return err
118
+}
117 119
 
118
-	// var couponAmount float64 = 0
119
-
120
-	// // 补充优惠券表字段
121
-	// for inx := range coupons {
122
-	// 	coupons[inx].OrdersCouponId = guid.NewGUIDString()
123
-	// 	coupons[inx].OrdersId = order.OrdersId
124
-	// 	coupons[inx].OrdersNo = order.OrdersNo
125
-	// 	coupons[inx].OrgId = order.OrgId
126
-	// 	coupons[inx].Status = models.STATUS_NORMAL
127
-	// 	coupons[inx].CreateDate = time.Now().Local()
128
-
129
-	// 	userAmount, _ := strconv.ParseFloat(coupons[inx].UsedAmount, 64)
130
-	// 	couponAmount += userAmount
131
-	// }
132
-
133
-	// // 反向更新 订单主表
134
-	// totalAmount, _ := strconv.ParseFloat(order.Amount, 64)
135
-
136
-	// order.CouponAmount = strconv.FormatFloat(couponAmount, 'f', -1, 32)
137
-	// order.ActualAmount = strconv.FormatFloat((totalAmount - couponAmount), 'f', -1, 32)
138
-
139
-	// if _, err := m.db.Insert(&coupons); err != nil {
140
-	// 	return err
141
-	// }
142
-
143
-	// if _, err := m.db.
144
-	// 	Where("orders_id=?", order.OrdersId).
145
-	// 	Cols([]string{"coupon_amount", "actual_amount"}...).
146
-	// 	Update(order); err != nil {
147
-	// 	return err
148
-	// }
149
-
150
-	// return nil
120
+// GetCouponByOrdersID 获取优惠券订单
121
+func (m *GoodsDAO) GetCouponByOrdersID(ordersID string) ([]model.TaCoupon, error) {
122
+	var res []model.TaCoupon
123
+	query := `
124
+		SELECT t.*
125
+		FROM ta_coupon t
126
+		JOIN ta_goods_orders_coupon s ON t.coupon_id = s.coupon_id
127
+		WHERE s.orders_id = ?
128
+		ORDER BY t.create_date
129
+	`
130
+
131
+	err := m.db.SQL(query, ordersID).Find(&res)
132
+	return res, err
151 133
 }
152 134
 
153 135
 func (m *GoodsDAO) getCaseByID(caseID string) (*model.SysCase, error) {
@@ -237,6 +219,29 @@ func (m *GoodsDAO) GetOrdersByID(id string) (*OrdersWithGoods, error) {
237 219
 	return res, nil
238 220
 }
239 221
 
222
+func (m *GoodsDAO) GetOrdersDetailByID(id string, status ...int) (*OrdersDetail, error) {
223
+	sta := models.STATUS_NORMAL
224
+	if len(status) > 0 {
225
+		sta = status[0]
226
+	}
227
+
228
+	res := new(OrdersDetail)
229
+	if _, err := m.db.Table("ta_goods_orders").
230
+		Where("orders_id=?", id).
231
+		And("status=?", sta).
232
+		Get(res); err != nil {
233
+		return nil, err
234
+	}
235
+
236
+	details, err := m.GetOrderDetailByOrder(res.OrdersId)
237
+	if err != nil {
238
+		return nil, err
239
+	}
240
+
241
+	res.Goods = details
242
+	return res, nil
243
+}
244
+
240 245
 // GetOrdersByRecord 根据
241 246
 func (m *GoodsDAO) GetOrdersByRecord(recordid string) ([]OrdersWithGoods, error) {
242 247
 	var orderList []OrdersWithGoods
@@ -338,8 +343,8 @@ func (m *GoodsDAO) GetOrderDetailByUser(caseid, userid string) ([]model.TaGoodsO
338 343
 	var details []model.TaGoodsOrdersDetail
339 344
 	sql := `select a.* from ta_goods_orders_detail a inner join ta_goods_orders b on a.orders_id=b.orders_id
340 345
 		inner join ta_customer c on b.user_id = c.customer_id
341
-	where c.user_id=? and b.status>? and b.case_id=? and b.pay_type = ? order by b.create_date desc`
342
-	if err := m.db.Sql(sql, userid, models.STATUS_DEL, caseid, models.CONSUME_INNER).Find(&details); err != nil {
346
+	where c.user_id=? and b.status=? and b.case_id=? and b.pay_type = ? order by b.create_date desc`
347
+	if err := m.db.Sql(sql, userid, models.STATUS_NORMAL, caseid, models.CONSUME_INNER).Find(&details); err != nil {
343 348
 		return nil, err
344 349
 	}
345 350
 	return details, nil

+ 7
- 0
models/goods/types.go Parādīt failu

@@ -46,3 +46,10 @@ type OrdersWithGoods struct {
46 46
 	AreaIconWhite       string
47 47
 	Goods               []DetailWithType
48 48
 }
49
+
50
+// OrdersDetail 订单详情
51
+type OrdersDetail struct {
52
+	model.TaGoodsOrders `xorm:"extends"`
53
+	Goods               []DetailWithType
54
+	Coupons             []model.TaGoodsOrdersCoupon
55
+}

+ 8
- 5
models/models.go Parādīt failu

@@ -1,6 +1,8 @@
1 1
 package models
2 2
 
3 3
 import (
4
+	"spaceofcheng/services/utils"
5
+
4 6
 	"github.com/astaxie/beego/config"
5 7
 	_ "github.com/go-sql-driver/mysql"
6 8
 	"github.com/go-xorm/xorm"
@@ -10,7 +12,7 @@ var (
10 12
 	DBEngine *xorm.Engine
11 13
 )
12 14
 
13
-func init() {
15
+func InitDB() {
14 16
 	DBEngine = NewDBEngine()
15 17
 }
16 18
 
@@ -29,8 +31,9 @@ func NewDBEngine() *xorm.Engine {
29 31
 	return engine
30 32
 }
31 33
 
32
-func getMySQLDNS() string {
33
-	dbconf, _ := config.NewConfig("ini", "conf/db.conf")
34
+func getMySQLDNS() (dns string) {
35
+	appRoot := utils.GetAppRoot()
36
+	dbconf, _ := config.NewConfig("ini", appRoot+"/conf/db.conf")
34 37
 
35 38
 	conProt := dbconf.DefaultString("con_protocol", "tcp")
36 39
 	dbAddr := dbconf.DefaultString("db_addr", "localhost")
@@ -40,7 +43,7 @@ func getMySQLDNS() string {
40 43
 	database := dbconf.String("database")
41 44
 	charSet := dbconf.DefaultString("char_set", "utf8")
42 45
 
43
-	dns := userName
46
+	dns = userName
44 47
 
45 48
 	if len(password) > 0 {
46 49
 		dns += ":" + password
@@ -48,5 +51,5 @@ func getMySQLDNS() string {
48 51
 
49 52
 	dns += "@" + conProt + "(" + dbAddr + ":" + dbPort + ")" + "/" + database + "?charset=" + charSet
50 53
 
51
-	return dns
54
+	return
52 55
 }

+ 1
- 3
routers/common.go Parādīt failu

@@ -24,9 +24,7 @@ import (
24 24
 	"github.com/astaxie/beego"
25 25
 )
26 26
 
27
-func getCommonRoutes() beego.LinkNamespace {
28
-	prefix := beego.AppConfig.String("api::common")
29
-
27
+func getCommonRoutes(prefix string) beego.LinkNamespace {
30 28
 	return beego.NSNamespace(prefix,
31 29
 		// 商品分类
32 30
 		beego.NSRouter("/type/goods", &goods.GoodsController{}, "get:GetGoodsType"),

+ 1
- 3
routers/guest.go Parādīt failu

@@ -13,9 +13,7 @@ import (
13 13
 	"github.com/astaxie/beego"
14 14
 )
15 15
 
16
-func getGuestRoutes() beego.LinkNamespace {
17
-	prefix := beego.AppConfig.String("api::guest")
18
-
16
+func getGuestRoutes(prefix string) beego.LinkNamespace {
19 17
 	return beego.NSNamespace(prefix,
20 18
 		// cms
21 19
 		beego.NSRouter("/cms/info", &message.MessageController{}, "get:GetCmsInfoByLocation"),

+ 15
- 4
routers/router.go Parādīt failu

@@ -9,25 +9,36 @@ package routers
9 9
 
10 10
 import (
11 11
 	"spaceofcheng/services/controllers"
12
+	"spaceofcheng/services/utils"
12 13
 
13 14
 	"github.com/astaxie/beego"
14 15
 )
15 16
 
16 17
 func init() {
17
-	prefix := beego.AppConfig.String("api::prefix")
18
+	appRoot := utils.GetAppRoot()
19
+
20
+	appConf, _ := utils.GetConfiger(appRoot + "/conf/app.conf")
21
+	if appConf == nil {
22
+		return
23
+	}
24
+
25
+	prefix := appConf.String("api::prefix")
26
+	guestPrefix := appConf.String("api::guest")
27
+	commonPrefix := appConf.String("api::common")
28
+	wechatPrefix := appConf.String("api::wechat")
18 29
 
19 30
 	ns := beego.NewNamespace(prefix,
20 31
 		// 解决跨域时 先发送 options 问题
21 32
 		beego.NSRouter("*", &controllers.BaseController{}, "options:Options"),
22 33
 
23 34
 		// 通用需要鉴权路由
24
-		getCommonRoutes(),
35
+		getCommonRoutes(commonPrefix),
25 36
 
26 37
 		// 微信路由
27
-		getWechatRoutes(),
38
+		getWechatRoutes(wechatPrefix),
28 39
 
29 40
 		// 不需要鉴权的路由
30
-		getGuestRoutes(),
41
+		getGuestRoutes(guestPrefix),
31 42
 	)
32 43
 
33 44
 	beego.AddNamespace(ns)

+ 1
- 3
routers/wechat.go Parādīt failu

@@ -15,9 +15,7 @@ import (
15 15
 	"github.com/astaxie/beego"
16 16
 )
17 17
 
18
-func getWechatRoutes() beego.LinkNamespace {
19
-	prefix := beego.AppConfig.String("api::wechat")
20
-
18
+func getWechatRoutes(prefix string) beego.LinkNamespace {
21 19
 	return beego.NSNamespace(prefix,
22 20
 		// 会员
23 21
 		beego.NSRouter("/customer", &customer.CustomerController{}, "get:GetCustWXByID"),

+ 4
- 0
service/course/order.go Parādīt failu

@@ -138,6 +138,10 @@ func (s *CourseServ) Orders(
138 138
 			return errors.New("保存优惠信息出错")
139 139
 		}
140 140
 
141
+		if err := s.couponDAO.IncreseCouponUsedNum(coupon.CouponId); err != nil {
142
+			return utils.LogError("保存优惠信息出错", err.Error())
143
+		}
144
+
141 145
 		// 优惠券核销
142 146
 		err = s.couponDAO.VerifyCustomerCoupon(customercouponid)
143 147
 		if err != nil {

+ 1
- 1
service/events/events.go Parādīt failu

@@ -85,7 +85,7 @@ var tsAction = func(e tinyevent.Event) error {
85 85
 	return nil
86 86
 }
87 87
 
88
-func init() {
88
+func EventInit() {
89 89
 	cases, err := models.GetAllCases()
90 90
 	if err != nil {
91 91
 		utils.LogError("获取有效案场列表失败: " + err.Error())

+ 88
- 35
service/goods/orders.go Parādīt failu

@@ -16,8 +16,8 @@ import (
16 16
 	"github.com/yl10/kit/guid"
17 17
 )
18 18
 
19
-// Orders 下单
20
-func (s *GoodsServ) Orders(
19
+// PreOrders 下单
20
+func (s *GoodsServ) PreOrders(
21 21
 	info *model.TaGoodsOrders,
22 22
 	details []model.TaGoodsOrdersDetail,
23 23
 	customercouponid,
@@ -104,7 +104,7 @@ func (s *GoodsServ) Orders(
104 104
 				GoodsId: "",
105 105
 			}
106 106
 			for _, detail := range details {
107
-				if coupon.IsAll == 1 {
107
+				if coupon.IsAll == models.BOOL_TRUE {
108 108
 					dyprice, _ := strconv.ParseFloat(dyGoods.Price, 64)
109 109
 					detailprice, _ := strconv.ParseFloat(detail.Price, 64)
110 110
 					if dyprice < detailprice {
@@ -141,13 +141,6 @@ func (s *GoodsServ) Orders(
141 141
 				}
142 142
 				info.CouponAmount = dyGoods.Price
143 143
 				// info.ActualAmount = "0.0"
144
-
145
-				// 优惠券核销
146
-				err := s.couponDAO.VerifyCustomerCoupon(customercouponid)
147
-				if err != nil {
148
-					utils.LogError("优惠券核销出错: " + err.Error())
149
-					return errors.New("优惠券核销出错")
150
-				}
151 144
 			} else {
152 145
 				return errors.New("优惠券不可抵用商品")
153 146
 			}
@@ -169,13 +162,6 @@ func (s *GoodsServ) Orders(
169 162
 		if payMoney > 0 && couponAmount > 0 && info.PayType != models.CONSUME_INNER {
170 163
 			info.PayType = models.CONSUME_COUPON_COIN
171 164
 		}
172
-
173
-		// 如果是城币, 则插入用户账户消费记录
174
-		if payMoney > 0 {
175
-			if err := s.saveCustomerPayRec(account, info); err != nil {
176
-				return err
177
-			}
178
-		}
179 165
 	}
180 166
 
181 167
 	// 保存主订单
@@ -188,32 +174,102 @@ func (s *GoodsServ) Orders(
188 174
 		return err
189 175
 	}
190 176
 
191
-	// 通知后端有新订单 - websocket
192
-	// orderList, err := s.GetOnLineOrders(info.CaseId, false)
193
-	// if err != nil {
194
-	// 	utils.LogError("获取新单列表出错: " + err.Error())
195
-	// 	return nil
196
-	// }
197
-	newOrder, err := s.GetNewGoods(info.OrdersId)
177
+	return nil
178
+}
179
+
180
+// ConfirmOrder 订单确认
181
+// 1、订单状态修改为有效
182
+// 2、订单修改为支付状态
183
+// 3、卡券核销
184
+// 4、账户或者 VIP 卡扣钱
185
+func (s *GoodsServ) ConfirmOrder(ordersID string) error {
186
+	orders, err := s.dao.GetOrdersByID(ordersID)
198 187
 	if err != nil {
199
-		// 下单流程已经结束, 不反馈错误
200
-		utils.LogError("获取数据失败:", err.Error())
201
-		return nil
188
+		return utils.LogError("获取订单失败", err)
202 189
 	}
203 190
 
191
+	// 如果是内部人员
192
+	if orders.PayType == models.CONSUME_INNER {
193
+		// 查找禁用名单
194
+		fibUsers, err := s.userDAO.GetForbidUserByUserID(orders.UserId)
195
+		if err != nil {
196
+			return utils.LogError("校验下单人出错", err)
197
+		}
198
+
199
+		if fibUsers != nil && len(fibUsers) > 0 {
200
+			for _, u := range fibUsers {
201
+				if u.ForbidType == models.FORBID_ORDER && u.Status == models.STATUS_NORMAL {
202
+					return errors.New("当前下单人被禁止点单")
203
+				}
204
+			}
205
+		}
206
+	} else {
207
+		// 如果不是内部人员
208
+
209
+		// 如果使用了优惠券
210
+		coupons, err := s.dao.GetCouponByOrdersID(ordersID)
211
+		if err != nil {
212
+			return utils.LogError("校验订单优惠券失败", err)
213
+		}
214
+		if coupons != nil && len(coupons) > 0 {
215
+			for _, cp := range coupons {
216
+				if cp.Status != models.STATUS_NORMAL {
217
+					return errors.New("订单优惠券已经被使用, 请重新选择优惠券")
218
+				}
219
+
220
+				// 优惠券核销
221
+				err := s.couponDAO.VerifyCustomerCoupon(cp.CouponId)
222
+				if err != nil {
223
+					return utils.LogError("优惠券核销出错", err)
224
+				}
225
+
226
+				// 优惠券使用数量 + 1
227
+				if err := s.couponDAO.IncreseCouponUsedNum(cp.CouponId); err != nil {
228
+					return utils.LogError("更新优惠券使用出错", err)
229
+				}
230
+			}
231
+		}
232
+
233
+		// 如果使用了城币
234
+		actualPay, _ := strconv.ParseFloat(orders.ActualAmount, 64)
235
+		if actualPay > 0.01 {
236
+			account, err := s.custDAO.GetAccountByCust(orders.UserId)
237
+			if err != nil {
238
+				return utils.LogError("查询用户账户信息出错", err)
239
+			}
240
+
241
+			accMoney, _ := strconv.ParseFloat(account.Amount, 64)
242
+			if accMoney < actualPay {
243
+				return errors.New("下单错误, 用户账户余额不足")
244
+			}
245
+
246
+			if err := s.saveCustomerPayRec(account, &orders.TaGoodsOrders); err != nil {
247
+				return err
248
+			}
249
+		}
250
+
251
+		// 不去校验商品及库存
252
+		// 因为暂时没有库存的概念
253
+	}
254
+
255
+	// 更新订单状态
256
+	orders.Status = models.STATUS_NORMAL
257
+	orders.IsPay = models.BOOL_TRUE
258
+	if err := s.dao.UpdateOrders(&orders.TaGoodsOrders, []string{"status", "is_pay"}); err != nil {
259
+		return utils.LogError("下单失败, 更新状态出错", err)
260
+	}
261
+
262
+	// 通知后端有新订单 - websocket
204 263
 	msg := utils.Message{
205 264
 		To: utils.ClientID{
206
-			Groups: []string{info.CaseId},
265
+			Groups: []string{orders.CaseId},
207 266
 		},
208 267
 		Data: map[string][]interface{}{
209
-			"refreshOnlineGoodsOrders": []interface{}{*newOrder},
268
+			"refreshOnlineGoodsOrders": []interface{}{*orders},
210 269
 		},
211 270
 	}
212 271
 
213
-	utils.LogError("调用下单 Websocket ")
214
-
215 272
 	utils.SendMessage(msg, utils.WsMessage)
216
-
217 273
 	return nil
218 274
 }
219 275
 
@@ -311,9 +367,6 @@ func (s *GoodsServ) validOrdersInfo(info *model.TaGoodsOrders) error {
311 367
 				if info.UserName == "" {
312 368
 					info.UserName = cust.CustomerName
313 369
 				}
314
-				// if ut.CaseId == caseID {
315
-
316
-				// }
317 370
 			}
318 371
 		}
319 372
 

+ 54
- 0
tests/cases_test.go Parādīt failu

@@ -0,0 +1,54 @@
1
+package tests
2
+
3
+import (
4
+	"net/http"
5
+	"net/url"
6
+	"spaceofcheng/services/controllers"
7
+	"testing"
8
+
9
+	. "github.com/smartystreets/goconvey/convey"
10
+)
11
+
12
+func TestGetCmsCaseList(t *testing.T) {
13
+
14
+	Convey("获取案场列表", t, func() {
15
+
16
+		Convey("正常业务", func() {
17
+			params := url.Values{}
18
+			params.Add("orgid", "1")
19
+
20
+			result := &controllers.JSONMessage{}
21
+
22
+			code, _, err := NewRequestMock().Request(http.MethodGet, "/api/guest/MQ/cms/case", params, result)
23
+
24
+			// http 常规判断, 可以省略
25
+			So(code, ShouldEqual, http.StatusOK)
26
+			So(err, ShouldBeNil)
27
+
28
+			// 业务返回判断
29
+			Convey("结果码 200", func() {
30
+				So(result.Code, ShouldEqual, http.StatusOK)
31
+			})
32
+
33
+			Convey("结果不为空", func() {
34
+				So(result.Result, ShouldNotBeEmpty)
35
+			})
36
+		})
37
+
38
+		Convey("机构不传报错", func() {
39
+			result := &controllers.JSONMessage{}
40
+
41
+			code, _, err := NewRequestMock().Request(http.MethodGet, "/api/guest/MQ/cms/case", nil, result)
42
+
43
+			// http 常规判断, 可以省略
44
+			So(code, ShouldEqual, http.StatusOK)
45
+			So(err, ShouldBeNil)
46
+
47
+			// 业务返回判断
48
+			Convey("结果码 不是200", func() {
49
+				So(result.Code, ShouldNotEqual, http.StatusOK)
50
+			})
51
+		})
52
+
53
+	})
54
+}

+ 29
- 0
tests/tests.go Parādīt failu

@@ -0,0 +1,29 @@
1
+package tests
2
+
3
+/**
4
+*
5
+* 使用的测试框架为  http://labix.org/gocheck
6
+*
7
+**/
8
+
9
+import (
10
+	"spaceofcheng/services/bootstrap"
11
+	"spaceofcheng/services/utils"
12
+	"testing"
13
+
14
+	_ "spaceofcheng/services/routers"
15
+
16
+	"github.com/astaxie/beego"
17
+	. "github.com/smartystreets/goconvey/convey"
18
+)
19
+
20
+func TestHelloWorld(t *testing.T) {
21
+	Convey("Hello go tester !", t, func() {
22
+		So(2, ShouldEqual, 2)
23
+	})
24
+}
25
+
26
+func init() {
27
+	bootstrap.SystemInit()
28
+	beego.TestBeegoInit(utils.GetAppRoot())
29
+}

+ 212
- 0
tests/utils.go Parādīt failu

@@ -0,0 +1,212 @@
1
+package tests
2
+
3
+import (
4
+	"bytes"
5
+	"encoding/json"
6
+	"errors"
7
+	"fmt"
8
+	"io"
9
+	"io/ioutil"
10
+	"mime/multipart"
11
+	"net/http"
12
+	"net/http/httptest"
13
+	"net/url"
14
+	"os"
15
+	"strconv"
16
+	"strings"
17
+	"time"
18
+
19
+	"github.com/astaxie/beego"
20
+)
21
+
22
+// RequestMock 模拟请求
23
+type RequestMock struct {
24
+	Headers map[string]string
25
+	Host    string
26
+}
27
+
28
+// NewRequestMock new inst
29
+func NewRequestMock() *RequestMock {
30
+	return &RequestMock{
31
+		Headers: make(map[string]string),
32
+	}
33
+}
34
+
35
+// SetHeaders 设置自定义请求头
36
+func (t *RequestMock) SetHeaders(headers map[string]string) *RequestMock {
37
+	t.Headers = headers
38
+	return t
39
+}
40
+
41
+// SetHost 设置 host 包含 port
42
+func (t *RequestMock) SetHost(host string) *RequestMock {
43
+	t.Host = host
44
+	return t
45
+}
46
+
47
+// Request 请求
48
+// 暂时只支持 params 是 url.Values 及 map[string]interface{} 两种类型
49
+// url.Values 将被理解为 content-type="application/x-www-form-urlencoded"
50
+// map[string]interface{} 将被理解为 content-type="multipart/form-data"
51
+func (t *RequestMock) Request(meth, addr string, params interface{}, result interface{}) (code int, body []byte, err error) {
52
+	var r *http.Request
53
+	defer t.SetHeaders(nil)
54
+
55
+	code = 0
56
+	body = nil
57
+	err = nil
58
+
59
+	if t.Host != "" {
60
+		addr = t.Host + addr
61
+	} else {
62
+		addr = "http://127.0.0.1:8080" + addr
63
+	}
64
+
65
+	switch meth {
66
+
67
+	// get 请求, 只支持 params 为 url.Values 的参数
68
+	case http.MethodGet:
69
+		if params != nil {
70
+			if dt, ok := params.(url.Values); ok {
71
+				searchStr := dt.Encode()
72
+				if strings.Index(addr, "?") > -1 {
73
+					searchStr = "&" + searchStr
74
+				} else {
75
+					searchStr = "?" + searchStr
76
+				}
77
+				r, _ = http.NewRequest(meth, addr+searchStr, nil)
78
+			}
79
+		} else {
80
+			r, _ = http.NewRequest(meth, addr, nil)
81
+		}
82
+
83
+	// post, put, delete
84
+	case http.MethodPost, http.MethodPut, http.MethodDelete:
85
+		rb, ct, e := GetBody(params)
86
+		if e != nil {
87
+			err = e
88
+			return
89
+		}
90
+
91
+		r, _ = http.NewRequest(meth, addr, rb)
92
+		if ct != "" {
93
+			r.Header.Set("Content-Type", ct)
94
+		}
95
+
96
+	// 其他的本系统没有使用
97
+	default:
98
+		err = errors.New("不支持的请求类型")
99
+		return
100
+	}
101
+
102
+	// 自定义的 header 头
103
+	if t.Headers != nil {
104
+		for k, v := range t.Headers {
105
+			r.Header.Set(k, v)
106
+		}
107
+	}
108
+
109
+	w := httptest.NewRecorder()
110
+	beego.BeeApp.Handlers.ServeHTTP(w, r)
111
+
112
+	code = w.Code
113
+	body, _ = ioutil.ReadAll(w.Result().Body)
114
+
115
+	beego.Trace("testing", meth+" - "+addr)
116
+
117
+	if result != nil {
118
+		err = json.Unmarshal(body, result)
119
+		return
120
+	}
121
+
122
+	return
123
+}
124
+
125
+func GetBody(params interface{}) (body io.Reader, contentType string, err error) {
126
+	body = nil
127
+	contentType = ""
128
+	err = nil
129
+
130
+	if params == nil {
131
+		return
132
+	}
133
+
134
+	t := fmt.Sprintf("%T", params)
135
+	switch t {
136
+
137
+	// 被会解析为 application/x-www-form-urlencoded
138
+	case "url.Values":
139
+		data, _ := params.(url.Values)
140
+		body = strings.NewReader(data.Encode())
141
+		contentType = "application/x-www-form-urlencoded"
142
+		return
143
+
144
+	// 被会解析为 multipart/form-data
145
+	case "map[string]interface {}":
146
+		var b bytes.Buffer
147
+		var fw io.Writer
148
+
149
+		w := multipart.NewWriter(&b)
150
+		data, _ := params.(map[string]interface{})
151
+
152
+		// 遍历字段
153
+		for k, v := range data {
154
+			switch x := v.(type) {
155
+
156
+			// 文件
157
+			case *os.File:
158
+				if fw, err = w.CreateFormFile(k, x.Name()); err != nil {
159
+					return
160
+				}
161
+
162
+				if _, err = io.Copy(fw, x); err != nil {
163
+					return
164
+				}
165
+
166
+			// 字符串
167
+			case string:
168
+				err = w.WriteField(k, x)
169
+				if err != nil {
170
+					return
171
+				}
172
+
173
+			// 整数, 暂不支持 int 各种原始类型, 比如 int32, int64 等
174
+			case int:
175
+				dt := strconv.Itoa(x)
176
+				err = w.WriteField(k, dt)
177
+				if err != nil {
178
+					return
179
+				}
180
+
181
+			// 小数, 暂时不支持其他类型的浮点数
182
+			case float64:
183
+				dt := strconv.FormatFloat(x, 'f', -1, 64)
184
+				err = w.WriteField(k, dt)
185
+				if err != nil {
186
+					return
187
+				}
188
+
189
+			// 时间
190
+			case time.Time:
191
+				dt := x.Format("2006-01-02 15:04:05")
192
+				err = w.WriteField(k, dt)
193
+				if err != nil {
194
+					return
195
+				}
196
+
197
+			// 其他
198
+			default:
199
+				err = fmt.Errorf("暂时不支持 key "+k+" 对应的数据类型 %T", x)
200
+				return
201
+			}
202
+		}
203
+
204
+		body = bytes.NewReader(b.Bytes())
205
+		contentType = w.FormDataContentType()
206
+		return
207
+
208
+	default:
209
+		err = fmt.Errorf("暂时不支持的参数类型 " + t)
210
+		return
211
+	}
212
+}

+ 1
- 5
utils/captcha.go Parādīt failu

@@ -19,7 +19,7 @@ type CaptchaEngine struct {
19 19
 	capList map[string]cap
20 20
 }
21 21
 
22
-var capEngine *CaptchaEngine
22
+var capEngine = NewCaptchaEngine()
23 23
 
24 24
 // NewCaptchaEngine 创建验证码引擎
25 25
 func NewCaptchaEngine() *CaptchaEngine {
@@ -108,7 +108,3 @@ func (c *CaptchaEngine) DestoryCaptcha(phone string) {
108 108
 	// 如果成功, 则注销
109 109
 	delete(c.capList, phone)
110 110
 }
111
-
112
-func init() {
113
-	capEngine = NewCaptchaEngine()
114
-}

+ 15
- 0
utils/configer.go Parādīt failu

@@ -0,0 +1,15 @@
1
+package utils
2
+
3
+import (
4
+	"github.com/astaxie/beego/config"
5
+)
6
+
7
+// GetConfiger 获取配置
8
+func GetConfiger(file string) (config.Configer, error) {
9
+	conf, err := config.NewConfig("ini", file)
10
+	if err != nil {
11
+		return nil, LogError("读取配置文件失败", err.Error())
12
+	}
13
+
14
+	return conf, nil
15
+}

+ 2
- 6
utils/log.go Parādīt failu

@@ -9,8 +9,7 @@ import (
9 9
 	"github.com/astaxie/beego/logs"
10 10
 )
11 11
 
12
-var defaultLogger *logs.BeeLogger
13
-var instances map[string]*logs.BeeLogger
12
+var instances = make(map[string]*logs.BeeLogger)
14 13
 
15 14
 // NewLog 构造日志对象
16 15
 func NewLog(tp ...string) *logs.BeeLogger {
@@ -101,9 +100,6 @@ func GetDefaultLogger() *logs.BeeLogger {
101 100
 	return log
102 101
 }
103 102
 
104
-func init() {
105
-	instances = make(map[string]*logs.BeeLogger)
103
+func LogInit() {
106 104
 	NewLog()
107
-
108
-	defaultLogger = GetDefaultLogger()
109 105
 }

+ 1
- 1
utils/message.go Parādīt failu

@@ -45,6 +45,6 @@ func SendMessage(message Message, msgType string) {
45 45
 	}
46 46
 }
47 47
 
48
-func init() {
48
+func MessageInit() {
49 49
 	go websocket.Run()
50 50
 }

+ 1
- 5
utils/sms.go Parādīt failu

@@ -19,7 +19,7 @@ type SMSEngine struct {
19 19
 }
20 20
 
21 21
 var defaultSMS *SMSEngine
22
-var mtx *sync.Mutex
22
+var mtx = new(sync.Mutex)
23 23
 
24 24
 // ResetSMSEngine 重置引擎
25 25
 func ResetSMSEngine(conf config.Configer) {
@@ -71,7 +71,3 @@ func SendSMS(smsType, tel string, messages ...string) {
71 71
 
72 72
 	}()
73 73
 }
74
-
75
-func init() {
76
-	mtx = new(sync.Mutex)
77
-}

+ 9
- 0
utils/utils.go Parādīt failu

@@ -4,6 +4,8 @@ import (
4 4
 	"encoding/base64"
5 5
 	"math/rand"
6 6
 	"net/http"
7
+	"path/filepath"
8
+	"runtime"
7 9
 	"strconv"
8 10
 	"strings"
9 11
 	"time"
@@ -156,3 +158,10 @@ func GetFiveSeconds(t time.Time) string {
156 158
 
157 159
 	return str[:strLen-1] + strconv.Itoa(lastNum)
158 160
 }
161
+
162
+// GetAppRoot 获取系统根目录
163
+func GetAppRoot() string {
164
+	_, file, _, _ := runtime.Caller(1)
165
+	appRoot, _ := filepath.Abs(filepath.Dir(filepath.Join(file, ".."+string(filepath.Separator))))
166
+	return appRoot
167
+}

+ 4
- 3
utils/wechat.go Parādīt failu

@@ -60,9 +60,10 @@ func GetWxAppID(org string) string {
60 60
 	return wxClients[org].GetAppID()
61 61
 }
62 62
 
63
-func init() {
64
-	wx.SetLogInst(defaultLogger)
65
-	mini.SetLogInst(defaultLogger)
63
+func WechatInit() {
64
+	logger := GetDefaultLogger()
65
+	wx.SetLogInst(logger)
66
+	mini.SetLogInst(logger)
66 67
 }
67 68
 
68 69
 // MapToWechatUser 映射微信人员