wangfei 6 年前
父节点
当前提交
c646c656e3
共有 5 个文件被更改,包括 325 次插入55 次删除
  1. 3
    7
      controllers/course/order.go
  2. 2
    2
      models/course/order.go
  3. 3
    0
      service/course/course.go
  4. 316
    46
      service/course/order.go
  5. 1
    0
      service/vipcard/vipcard.go

+ 3
- 7
controllers/course/order.go 查看文件

@@ -15,10 +15,6 @@ func (c *CourseController) PostOrder() {
15 15
 		c.ResponseError(errors.New("无有效订单信息"))
16 16
 	}
17 17
 
18
-	// 订单优惠券
19
-	customercouponid := c.GetString("customercouponid")
20
-
21
-	//
22 18
 	var orderInfo model.TaCourseOrders
23 19
 	//	var orderCoupon []model.TaCourseOrdersCoupon
24 20
 
@@ -39,10 +35,10 @@ func (c *CourseController) PostOrder() {
39 35
 			http.StatusNotAcceptable,
40 36
 		)
41 37
 	}
42
-
43
-	if err := c.serv.Orders(&orderInfo, customercouponid); err != nil {
38
+	newOrders, err := c.serv.PreOrders(&orderInfo)
39
+	if err != nil {
44 40
 		c.ResponseError(err)
45 41
 	}
46 42
 
47
-	c.ResponseJSON("ok")
43
+	c.ResponseJSON(newOrders)
48 44
 }

+ 2
- 2
models/course/order.go 查看文件

@@ -12,7 +12,7 @@ import (
12 12
 )
13 13
 
14 14
 // SaveCourseOrder 保存订单
15
-func (m *CourseDAO) SaveCourseOrder(order *model.TaCourseOrders) error {
15
+func (m *CourseDAO) SaveCourseOrder(order *model.TaCourseOrders) (*model.TaCourseOrders, error) {
16 16
 
17 17
 	if order.OrdersId == "" {
18 18
 		order.OrdersId = guid.NewGUIDString()
@@ -26,7 +26,7 @@ func (m *CourseDAO) SaveCourseOrder(order *model.TaCourseOrders) error {
26 26
 	order.OrdersNo = ordersno
27 27
 	order.CreateDate = time.Now()
28 28
 	_, err := m.db.Insert(order)
29
-	return err
29
+	return order, err
30 30
 }
31 31
 
32 32
 // GetOrderByID 根据id获取订单明细

+ 3
- 0
service/course/course.go 查看文件

@@ -9,6 +9,7 @@ import (
9 9
 	"spaceofcheng/services/models/customer"
10 10
 	"spaceofcheng/services/models/model"
11 11
 	"spaceofcheng/services/models/system"
12
+	"spaceofcheng/services/models/vipcard"
12 13
 	"spaceofcheng/services/service"
13 14
 	"spaceofcheng/services/utils"
14 15
 	"strings"
@@ -22,6 +23,7 @@ type CourseServ struct {
22 23
 	custDAO   *customer.CustomerDAO
23 24
 	userDAO   *system.UserDAO
24 25
 	couponDAO *coupon.CouponDAO
26
+	vipDAO    *vipcard.VipcardDAO
25 27
 }
26 28
 
27 29
 // NewCourseServ 初始化
@@ -33,6 +35,7 @@ func NewCourseServ(ctx *utils.Context) *CourseServ {
33 35
 		custDAO:   customer.NewCustomerDAO(ctx),
34 36
 		userDAO:   system.NewUserDAO(ctx),
35 37
 		couponDAO: coupon.NewCouponDAO(ctx),
38
+		vipDAO:    vipcard.NewVipcardDAO(ctx),
36 39
 	}
37 40
 }
38 41
 

+ 316
- 46
service/course/order.go 查看文件

@@ -13,13 +13,12 @@ import (
13 13
 )
14 14
 
15 15
 // PreOrders 预下单
16
+// 保存订单信息
16 17
 func (s *CourseServ) PreOrders(
17 18
 	couseOrder *model.TaCourseOrders,
18
-	customercouponid string,
19
-) error {
19
+) (*model.TaCourseOrders, error) {
20 20
 	org := s.ctx.Get("org").(model.SysOrg)
21 21
 	cust := s.ctx.Get("customer").(model.TaCustomer)
22
-
23 22
 	// 校验人员
24 23
 	couseOrder.CustomerId = cust.CustomerId
25 24
 	if cust.UserId != "" {
@@ -30,16 +29,14 @@ func (s *CourseServ) PreOrders(
30 29
 		// 默认是卡券支付
31 30
 		couseOrder.PayType = models.CONSUME_COUPON
32 31
 	}
33
-
34 32
 	// 校验课程
35 33
 	course, err := s.validCourse(couseOrder)
36 34
 	if err != nil {
37
-		return err
35
+		return nil, err
38 36
 	}
39 37
 	if course.CourseDetail == nil || len(course.CourseDetail) == 0 {
40
-		return errors.New("定单课程尚未排课, 不能下单")
38
+		return nil, errors.New("定单课程尚未排课, 不能下单")
41 39
 	}
42
-
43 40
 	couseOrder.OrdersId = guid.NewGUIDString()
44 41
 	couseOrder.Price = course.Price // 课程价格, 即为订单价格
45 42
 	couseOrder.ActualAmount = course.Price
@@ -54,19 +51,42 @@ func (s *CourseServ) PreOrders(
54 51
 	} else {
55 52
 		couseOrder.CustomerName = cust.CustomerName
56 53
 	}
54
+	// 入库
55
+	neworder, err := s.AddOrder(couseOrder)
56
+	if err != nil {
57
+		utils.LogError("课程下单失败: " + err.Error())
58
+		return nil, errors.New("下单失败, 请重试")
59
+	}
60
+	return neworder, nil
61
+}
62
+
63
+// ConfirmOrders 确认订单
64
+func (s *CourseServ) ConfirmOrders(ordersID, customercouponid string) error {
57 65
 
58
-	// 客户 VIP 卡
59
-	var vipAccount float64 = 0.0
60
-	vips, err := s.custDAO.GetValidVIPCards(cust.CustomerId)
66
+	couseOrder, err := s.dao.GetOrderByID(ordersID)
61 67
 	if err != nil {
62
-		return nil, utils.LogError("查询用户VIP卡信息出错", err.Error())
68
+		return utils.LogError("获取订单失败", err)
63 69
 	}
64 70
 
65
-	if vips != nil && len(vips) > 0 {
66
-		for _, vip := range vips {
67
-			vipMoney, _ := strconv.ParseFloat(vip.Balance, 64)
68
-			vipAccount += vipMoney
69
-		}
71
+	if couseOrder.Status != models.STATUS_READY {
72
+		return errors.New("没有订单信息")
73
+	}
74
+	cust := s.ctx.Get("customer").(model.TaCustomer)
75
+
76
+	// TODO
77
+	// 校验案场
78
+	// caseID := couseOrder.CaseId
79
+	// if err := utils.NewAuthEngine(s.ctx).CheckCase(caseID); err != nil {
80
+	// 	return err
81
+	// }
82
+
83
+	// 校验课程
84
+	course, err := s.validCourse(couseOrder)
85
+	if err != nil {
86
+		return err
87
+	}
88
+	if course.CourseDetail == nil || len(course.CourseDetail) == 0 {
89
+		return errors.New("定单课程尚未排课, 不能下单")
70 90
 	}
71 91
 
72 92
 	account, err := s.custDAO.GetAccountByCust(cust.CustomerId)
@@ -143,10 +163,6 @@ func (s *CourseServ) PreOrders(
143 163
 			return errors.New("保存优惠信息出错")
144 164
 		}
145 165
 
146
-		if err := s.couponDAO.IncreseCouponUsedNum(coupon.CouponId); err != nil {
147
-			return utils.LogError("保存优惠信息出错", err.Error())
148
-		}
149
-
150 166
 		// 优惠券核销
151 167
 		err = s.couponDAO.VerifyCustomerCoupon(customercouponid)
152 168
 		if err != nil {
@@ -174,23 +190,60 @@ func (s *CourseServ) PreOrders(
174 190
 
175 191
 	// 用户账户  -- 内部人员也可以购买
176 192
 	if actualAmount > 0 {
193
+		var leftPay = actualAmount
194
+		vips, err := s.custDAO.GetValidVIPCards(cust.CustomerId)
195
+		if err != nil {
196
+			return utils.LogError("查询用户 VIP卡 出错", err)
197
+		}
198
+
199
+		var vipAccount float64
200
+		if vips != nil && len(vips) > 0 {
201
+			for _, vip := range vips {
202
+				vipMoney, _ := strconv.ParseFloat(vip.Balance, 64)
203
+				vipAccount += vipMoney
204
+
205
+				// 当前扣款
206
+				var vipPay float64
207
+				if vipMoney > leftPay {
208
+					// 如果卡余额比 需要扣款的多, 那么就只扣这一张卡
209
+					// 通过 leftPay < 0.01 来判断
210
+					vipPay = leftPay
211
+					leftPay = 0
212
+				} else {
213
+					// 如果余额不够, 先扣掉本张卡余额, 继续循环
214
+					vipPay = vipMoney
215
+					leftPay -= vipMoney
216
+				}
217
+
218
+				if err := s.saveVipChangeRec(vipPay, &vip, couseOrder); err != nil {
219
+					return utils.LogError("VIP卡扣款失败", err.Error())
220
+				}
177 221
 
178
-		if actualAmount > accMoney+vipAccount {
179
-			return errors.New("账户余额不足")
222
+				if leftPay < 0.01 {
223
+					break
224
+				}
225
+			}
180 226
 		}
181 227
 
182
-		// 插入账户流水
183
-		if err := s.saveCustomerPayRec(account, couseOrder); err != nil {
184
-			utils.LogError("插入账户流水出错: " + err.Error())
185
-			return errors.New("写入账户流水出错")
228
+		// 如果 VIP 卡余额不足, 则使用账户余额
229
+		if leftPay > 0.01 {
230
+			if leftPay > accMoney {
231
+				return errors.New("账户余额不足")
232
+			}
233
+
234
+			// 插入账户流水
235
+			if err := s.saveCustomerPayRec(account, couseOrder, leftPay); err != nil {
236
+				utils.LogError("插入账户流水出错: " + err.Error())
237
+				return errors.New("写入账户流水出错")
238
+			}
186 239
 		}
187 240
 	}
188 241
 
189
-	// 入库
190
-	if err := s.SaveOrder(couseOrder, course); err != nil {
191
-		utils.LogError("课程下单失败: " + err.Error())
192
-		return errors.New("下单失败, 请重试")
193
-	}
242
+	// 更新订单信息
243
+	// if err := s.SaveOrder(couseOrder, course); err != nil {
244
+	// 	utils.LogError("课程下单失败: " + err.Error())
245
+	// 	return errors.New("下单失败, 请重试")
246
+	// }
194 247
 
195 248
 	// 发送短信
196 249
 	utils.SendSMS("orders", cust.Phone, course.CourseName)
@@ -198,19 +251,225 @@ func (s *CourseServ) PreOrders(
198 251
 	return nil
199 252
 }
200 253
 
201
-func (s *CourseServ) ConfirmOrders(ordersID string) error {
202
-	orders, err := s.dao.GetOrderByID(ordersID)
203
-	if err != nil {
204
-		return utils.LogError("获取订单失败", err)
205
-	}
206
-
207
-	if orders.Status != models.STATUS_READY {
208
-		return errors.New("没有订单信息")
254
+// saveVipChangeRec 保存vip消费记录
255
+func (s *CourseServ) saveVipChangeRec(payMoney float64, custVIP *model.TaCustomerVip, info *model.TaCourseOrders) error {
256
+	vipChange := new(model.TaCustomerVipChange)
257
+	vipChange.CustomerVipId = custVIP.CustomerVipId
258
+	vipChange.CustomerId = info.CustomerId
259
+	vipChange.OrgId = info.OrgId
260
+	vipChange.CaseId = info.CaseId
261
+	vipChange.ChangeType = models.CONSUME_COINCHG
262
+	vipChange.FloatType = models.ACCOUNT_SPENT
263
+	vipChange.SourceId = info.OrdersId
264
+	vipChange.SourceName = info.CustomerName + "课程下单"
265
+	vipChange.Amount = strconv.FormatFloat(payMoney, 'f', -1, 64)
266
+
267
+	if err := s.vipDAO.InsertCustomerVipChange(*vipChange); err != nil {
268
+		return err
209 269
 	}
210 270
 
211
-	return nil
271
+	return s.custDAO.UpdateCustVipCardAmount(custVIP, payMoney)
212 272
 }
213 273
 
274
+// // PreOrders 预下单
275
+// func (s *CourseServ) PreOrders(
276
+// 	couseOrder *model.TaCourseOrders,
277
+// 	customercouponid string,
278
+// ) (*course.CourseDetail, error) {
279
+// 	org := s.ctx.Get("org").(model.SysOrg)
280
+// 	cust := s.ctx.Get("customer").(model.TaCustomer)
281
+
282
+// 	// 校验人员
283
+// 	couseOrder.CustomerId = cust.CustomerId
284
+// 	if cust.UserId != "" {
285
+// 		// 内部人员
286
+// 		// 如果是内部人员购买或者兑换课程, 卡券或者城币就从内部人员自己的账户走
287
+// 		couseOrder.PayType = models.CONSUME_INNER
288
+// 	} else {
289
+// 		// 默认是卡券支付
290
+// 		couseOrder.PayType = models.CONSUME_COUPON
291
+// 	}
292
+
293
+// 	// 校验课程
294
+// 	course, err := s.validCourse(couseOrder)
295
+// 	if err != nil {
296
+// 		return nil, err
297
+// 	}
298
+// 	if course.CourseDetail == nil || len(course.CourseDetail) == 0 {
299
+// 		return nil, errors.New("定单课程尚未排课, 不能下单")
300
+// 	}
301
+
302
+// 	couseOrder.OrdersId = guid.NewGUIDString()
303
+// 	couseOrder.Price = course.Price // 课程价格, 即为订单价格
304
+// 	couseOrder.ActualAmount = course.Price
305
+// 	couseOrder.CourseName = course.CourseName
306
+// 	couseOrder.CourseNum = course.CourseNum
307
+// 	couseOrder.OrgId = org.OrgId
308
+// 	couseOrder.Status = models.STATUS_READY
309
+// 	couseOrder.IsPay = models.BOOL_FALSE
310
+
311
+// 	if cust.Name != "" {
312
+// 		couseOrder.CustomerName = cust.Name
313
+// 	} else {
314
+// 		couseOrder.CustomerName = cust.CustomerName
315
+// 	}
316
+
317
+// 	// 客户 VIP 卡
318
+// 	var vipAccount float64 = 0.0
319
+// 	vips, err := s.custDAO.GetValidVIPCards(cust.CustomerId)
320
+// 	if err != nil {
321
+// 		return nil, utils.LogError("查询用户VIP卡信息出错", err.Error())
322
+// 	}
323
+
324
+// 	if vips != nil && len(vips) > 0 {
325
+// 		for _, vip := range vips {
326
+// 			vipMoney, _ := strconv.ParseFloat(vip.Balance, 64)
327
+// 			vipAccount += vipMoney
328
+// 		}
329
+// 	}
330
+
331
+// 	account, err := s.custDAO.GetAccountByCust(cust.CustomerId)
332
+// 	if err != nil {
333
+// 		utils.LogError("查询用户账户信息出错: " + err.Error())
334
+// 		return nil, errors.New("查询用户账户信息出错")
335
+// 	}
336
+// 	accMoney, _ := strconv.ParseFloat(account.Amount, 64)
337
+
338
+// 	if customercouponid != "" {
339
+// 		// 校验卡券, 同时进行卡券的注销或者已使用的更新操作
340
+// 		// TODO
341
+// 		couseOrder.PayType = models.CONSUME_COUPON
342
+
343
+// 		// 优惠券校验
344
+// 		customerCoupon, err := s.couponDAO.GetCustomerCouponByID(customercouponid)
345
+// 		if err != nil {
346
+// 			utils.LogError("查询优惠券信息失败: " + err.Error())
347
+// 			return nil, errors.New("查询优惠券信息失败")
348
+// 		}
349
+// 		if customerCoupon == nil || customerCoupon.CustomerCouponId == "" {
350
+// 			return nil, errors.New("优惠券无效!")
351
+// 		}
352
+
353
+// 		if customerCoupon.CaseId != couseOrder.CaseId {
354
+// 			return nil, errors.New("优惠券对应案场与下单案场不一致,不允许下单!")
355
+// 		}
356
+
357
+// 		if customerCoupon.Status != models.STATUS_NORMAL || !customerCoupon.UseDate.IsZero() {
358
+// 			return nil, errors.New("优惠券已被使用!请重新选择优惠券!")
359
+// 		}
360
+
361
+// 		// 根据id获取优惠券信息
362
+// 		coupon, err := s.couponDAO.GetCouponInfoByCustomerCouponID(customercouponid)
363
+// 		if err != nil {
364
+// 			utils.LogError("查询优惠券信息失败: " + err.Error())
365
+// 			return nil, errors.New("查询优惠券信息失败")
366
+// 		}
367
+
368
+// 		if coupon.StartDate.After(time.Now().Local()) {
369
+// 			return nil, errors.New("该优惠券还未到有效期,不允许下单!")
370
+// 		}
371
+// 		if coupon.EndDate.Before(time.Now().Local()) {
372
+// 			return nil, errors.New("优惠券已失效,不允许下单!")
373
+// 		}
374
+
375
+// 		// 判断优惠券是否可以抵用商品
376
+// 		var isdy = false
377
+// 		if coupon.IsAll == 1 {
378
+// 			isdy = true
379
+// 			couseOrder.CouponAmount = coupon.Price
380
+// 		} else {
381
+// 			for _, target := range coupon.Targets {
382
+// 				if target.TargetId == course.CourseId {
383
+// 					isdy = true
384
+// 				}
385
+// 			}
386
+// 			couseOrder.CouponAmount = coupon.Price
387
+// 		}
388
+// 		if !isdy {
389
+// 			return nil, errors.New("优惠券不可抵用该课程")
390
+// 		}
391
+// 		var ordersCoupon = model.TaCourseOrdersCoupon{
392
+// 			OrdersId:         couseOrder.OrdersId,
393
+// 			CouponId:         coupon.CouponId,
394
+// 			CouponName:       coupon.CouponName,
395
+// 			UsedAmount:       couseOrder.CouponAmount,
396
+// 			CustomerCouponId: customerCoupon.CustomerCouponId,
397
+// 			CourseId:         course.CourseId,
398
+// 			CourseName:       course.CourseName,
399
+// 		}
400
+// 		if err := s.dao.SaveOrdersCoupon(&ordersCoupon, couseOrder); err != nil {
401
+// 			utils.LogError("保存优惠信息出错: " + err.Error())
402
+// 			return nil, errors.New("保存优惠信息出错")
403
+// 		}
404
+
405
+// 		if err := s.couponDAO.IncreseCouponUsedNum(coupon.CouponId); err != nil {
406
+// 			return nil, utils.LogError("保存优惠信息出错", err.Error())
407
+// 		}
408
+
409
+// 		// 优惠券核销
410
+// 		err = s.couponDAO.VerifyCustomerCoupon(customercouponid)
411
+// 		if err != nil {
412
+// 			utils.LogError("优惠券核销出错: " + err.Error())
413
+// 			return nil, errors.New("优惠券核销出错")
414
+// 		}
415
+// 	} else {
416
+// 		couseOrder.PayType = models.CONSUME_COINCHG
417
+// 		couseOrder.CouponAmount = "0.0"
418
+// 	}
419
+
420
+// 	couponAmount, _ := strconv.ParseFloat(couseOrder.CouponAmount, 64)
421
+// 	payMoney, _ := strconv.ParseFloat(couseOrder.Price, 64)
422
+// 	payMoney = payMoney - couponAmount
423
+
424
+// 	couseOrder.ActualAmount = strconv.FormatFloat(payMoney, 'f', -1, 64)
425
+
426
+// 	// 校验金额
427
+// 	// if err := s.validBillCharges(couseOrder, coupons); err != nil {
428
+// 	// 	return err
429
+// 	// }
430
+
431
+// 	// 实际支付
432
+// 	actualAmount := payMoney
433
+
434
+// 	// 用户账户  -- 内部人员也可以购买
435
+// 	if actualAmount > 0 {
436
+
437
+// 		if actualAmount > accMoney+vipAccount {
438
+// 			return nil, errors.New("账户余额不足")
439
+// 		}
440
+
441
+// 		// 插入账户流水
442
+// 		// if err := s.saveCustomerPayRec(account, couseOrder); err != nil {
443
+// 		// 	utils.LogError("插入账户流水出错: " + err.Error())
444
+// 		// 	return nil, errors.New("写入账户流水出错")
445
+// 		// }
446
+// 	}
447
+
448
+// 	// 入库
449
+// 	if err := s.SaveOrder(couseOrder, course); err != nil {
450
+// 		utils.LogError("课程下单失败: " + err.Error())
451
+// 		return nil, errors.New("下单失败, 请重试")
452
+// 	}
453
+
454
+// 	// 发送短信
455
+// 	utils.SendSMS("orders", cust.Phone, course.CourseName)
456
+
457
+// 	return nil, nil
458
+// }
459
+
460
+// func (s *CourseServ) ConfirmOrders(ordersID string) error {
461
+// 	orders, err := s.dao.GetOrderByID(ordersID)
462
+// 	if err != nil {
463
+// 		return utils.LogError("获取订单失败", err)
464
+// 	}
465
+
466
+// 	if orders.Status != models.STATUS_READY {
467
+// 		return errors.New("没有订单信息")
468
+// 	}
469
+
470
+// 	return nil
471
+// }
472
+
214 473
 // validCourse 校验课程
215 474
 func (s *CourseServ) validCourse(order *model.TaCourseOrders) (*course.CourseDetail, error) {
216 475
 	if order.CourseId == "" {
@@ -301,10 +560,10 @@ func (s *CourseServ) validBillCharges(
301 560
 }
302 561
 
303 562
 // saveCustomerPayRec 保存账户消费流水
304
-func (s *CourseServ) saveCustomerPayRec(account *model.TaCustomerAccount, info *model.TaCourseOrders) error {
563
+func (s *CourseServ) saveCustomerPayRec(account *model.TaCustomerAccount, info *model.TaCourseOrders, leftPay float64) error {
305 564
 	accBill := new(model.TaAccountChange)
306 565
 	accBill.AccountId = account.AccountId
307
-	accBill.Amount = info.ActualAmount
566
+	accBill.Amount = strconv.FormatFloat(leftPay, 'f', -1, 64)
308 567
 	accBill.CaseId = info.CaseId
309 568
 	accBill.ChangeSource = models.ACCSOURCE_COURSE_ORDERS
310 569
 	accBill.ChangeType = models.CONSUME_COINCHG
@@ -317,13 +576,24 @@ func (s *CourseServ) saveCustomerPayRec(account *model.TaCustomerAccount, info *
317 576
 	return s.custDAO.InsertAccountRecords(accBill)
318 577
 }
319 578
 
320
-// SaveOrder 保存订单明细
321
-func (s *CourseServ) SaveOrder(order *model.TaCourseOrders, course *course.CourseDetail) error {
579
+// AddOrder 保存订单信息
580
+func (s *CourseServ) AddOrder(order *model.TaCourseOrders) (*model.TaCourseOrders, error) {
322 581
 	// 订单信息
323
-	if err := s.dao.SaveCourseOrder(order); err != nil {
582
+	neworder, err := s.dao.SaveCourseOrder(order)
583
+	if err != nil {
324 584
 		utils.LogError("课程下单失败: " + err.Error())
325
-		return errors.New("下单失败, 请重试")
585
+		return nil, errors.New("下单失败, 请重试")
326 586
 	}
587
+	return neworder, nil
588
+}
589
+
590
+// SaveOrder 保存订单明细
591
+func (s *CourseServ) SaveOrder(order *model.TaCourseOrders, course *course.CourseDetail) error {
592
+	// 订单信息
593
+	// if err := s.dao.SaveCourseOrder(order); err != nil {
594
+	// 	utils.LogError("课程下单失败: " + err.Error())
595
+	// 	return errors.New("下单失败, 请重试")
596
+	// }
327 597
 
328 598
 	// 默认城币购买
329 599
 	// courseObtaimType := models.COURSE_GETBY_COINCHG

+ 1
- 0
service/vipcard/vipcard.go 查看文件

@@ -127,6 +127,7 @@ func (s *VipcardServ) SaveCustomerVip(vipchild *model.TaVipCardChild, createUser
127 127
 		OrgId:          vipchild.OrgId,
128 128
 		SalesId:        vipchild.SalesId,
129 129
 		SalesName:      vipchild.SalesName,
130
+		PayAmount:      "0",
130 131
 	}
131 132
 	info, err := s.dao.AddCustomerVip(customerVip)
132 133
 	if err != nil {