6 changed files with 23 additions and 471 deletions
-
12controllers/pc/order_draw.go
-
466controllers/pc/order_draw_special.go
-
6go.mod
-
6go.sum
-
1main.go
-
3models/customer_order.go
@ -1,466 +0,0 @@ |
|||||
package pc |
|
||||
|
|
||||
import ( |
|
||||
"fmt" |
|
||||
"hudongzhuanjia/controllers" |
|
||||
"hudongzhuanjia/models" |
|
||||
activity_service "hudongzhuanjia/services/activity" |
|
||||
lottery_service "hudongzhuanjia/services/lottery" |
|
||||
"hudongzhuanjia/utils/code" |
|
||||
"hudongzhuanjia/utils/define" |
|
||||
"time" |
|
||||
|
|
||||
"github.com/ouxuanserver/osmanthuswine/src/core" |
|
||||
) |
|
||||
|
|
||||
// 订单
|
|
||||
type OrderDrawSpecialCtl struct { |
|
||||
controllers.AuthorCtl |
|
||||
} |
|
||||
|
|
||||
// 屏蔽
|
|
||||
func (t *OrderDrawSpecialCtl) Block() { |
|
||||
activityId := t.MustGetInt("activity_id") |
|
||||
status := t.MustGet("status") |
|
||||
|
|
||||
module, exist, err := activity_service.GetModuleService(define.MODULE_ORDERLY, activityId) |
|
||||
t.CheckErr(err) |
|
||||
t.Assert(exist, code.MSG_MODULE_NOT_EXIST, "模块不存在") |
|
||||
module.BesideRepeat = status |
|
||||
_, err = models.Update(module.Id, module, "beside_repeat") |
|
||||
t.CheckErr(err) |
|
||||
t.SUCCESS("操作成功") |
|
||||
} |
|
||||
|
|
||||
// 开启订单活动
|
|
||||
func (t *OrderDrawSpecialCtl) Switch() { |
|
||||
activityId := t.MustGetInt("activity_id") |
|
||||
status := t.MustGetInt("status") |
|
||||
|
|
||||
activity := models.Activity{} |
|
||||
exist, err := models.Get(&activity, activityId) |
|
||||
t.CheckErr(err) |
|
||||
t.Assert(exist, code.MSG_ACTIVITY_NOT_EXIST, "互动不存在") |
|
||||
|
|
||||
option := &models.CustomerOrderOption{} |
|
||||
exist, err = option.GetByActivityId(activityId) |
|
||||
t.CheckErr(err) |
|
||||
t.Assert(exist, code.MSG_MODULE_NOT_EXIST, "订单活动不存在") |
|
||||
|
|
||||
if option.Status == status { |
|
||||
t.SUCCESS("操作成功") |
|
||||
return |
|
||||
} |
|
||||
|
|
||||
option.Status = status |
|
||||
_, err = models.Update(option.Id, option, "status") |
|
||||
t.CheckErr(err) |
|
||||
t.SUCCESS("操作成功") |
|
||||
} |
|
||||
|
|
||||
// ===================== 订单抽奖
|
|
||||
|
|
||||
// 开始抽奖
|
|
||||
func (t *OrderDrawSpecialCtl) Start() { |
|
||||
ladderId := t.MustGetInt("order_draw_ladder_id") |
|
||||
|
|
||||
ladder := new(models.OrderDrawRuleLadder) |
|
||||
exist, err := models.Get(ladder, ladderId) |
|
||||
t.CheckErr(err) |
|
||||
t.Assert(exist, code.MSG_ORDER_RULE_NOT_EXIST, "订单抽奖规则不存在") |
|
||||
|
|
||||
if ladder.Status != define.StatusNotBegin { |
|
||||
t.ERROR(fmt.Sprintf("该活动%s", ladder.Status), code.MSG_ERR) |
|
||||
} |
|
||||
ladder.Status = define.StatusRunning |
|
||||
ladder.UpdatedAt = time.Now() |
|
||||
err = models.Save(map[string]interface{}{ |
|
||||
"id=": ladder.Id, |
|
||||
"is_delete=": 0, |
|
||||
}, ladder, "status", "updated_at") |
|
||||
t.CheckErr(err) |
|
||||
t.SUCCESS("操作成功") |
|
||||
} |
|
||||
|
|
||||
// 开始抽奖
|
|
||||
func (t *OrderDrawSpecialCtl) Stop() { |
|
||||
ladderId := t.MustGetInt("order_draw_ladder_id") |
|
||||
|
|
||||
ladder := new(models.OrderDrawRuleLadder) |
|
||||
exist, err := models.Get(ladder, ladderId) |
|
||||
t.CheckErr(err) |
|
||||
t.Assert(exist, code.MSG_ORDER_RULE_NOT_EXIST, "订单抽奖规则不存在") |
|
||||
|
|
||||
if ladder.Status != define.StatusRunning { |
|
||||
t.ERROR(fmt.Sprintf("该活动%s", ladder.Status), code.MSG_ERR) |
|
||||
} |
|
||||
|
|
||||
ladder.Status = define.StatusEnding |
|
||||
ladder.UpdatedAt = time.Now() |
|
||||
err = models.Save(map[string]interface{}{ |
|
||||
"id=": ladder.Id, |
|
||||
"is_delete=": 0, |
|
||||
}, ladder, "status", "updated_at") |
|
||||
t.CheckErr(err) |
|
||||
t.SUCCESS("操作成功") |
|
||||
} |
|
||||
|
|
||||
type SpecialOrderLadderResult struct { |
|
||||
OrderDrawRuleId int `json:"order_draw_rule_id"` |
|
||||
OrderDrawLadderId int `json:"order_draw_ladder_id"` |
|
||||
PrizeName string `json:"prize_name"` |
|
||||
Status string `json:"status"` |
|
||||
PrizeImg string `json:"prize_img"` |
|
||||
PrizeNumber int `json:"prize_number"` |
|
||||
} |
|
||||
|
|
||||
type SpecialOrderListResult struct { |
|
||||
OrderDrawActivityId int `json:"order_draw_activity_id"` |
|
||||
OrderDrawRuleId int `json:"order_draw_rule_id"` |
|
||||
OrderDrawActivityName string `json:"order_draw_activity_name"` |
|
||||
OrderDrawLadders []*OrderLadderResult `json:"order_draw_ladders"` |
|
||||
PrizeNumber int `json:"prize_number"` |
|
||||
} |
|
||||
|
|
||||
//获取所有订单奖品
|
|
||||
func (t *OrderDrawSpecialCtl) List() { |
|
||||
activityId := t.MustGetInt("activity_id") |
|
||||
customerId := t.GetAccountId() |
|
||||
//
|
|
||||
area := &models.AreaStore{} |
|
||||
exist, err := area.GetByCustomerId(customerId, activityId) |
|
||||
t.CheckErr(err) |
|
||||
t.Assert(exist, code.MSG_AREASTORE_NOT_EXIST, "地区信息异常") |
|
||||
|
|
||||
activity := models.Activity{} |
|
||||
exist, err = models.Get(&activity, activityId) |
|
||||
t.CheckErr(err) |
|
||||
t.Assert(exist, code.MSG_ACTIVITY_NOT_EXIST, "互动信息异常") |
|
||||
|
|
||||
// 订单的开启或关闭
|
|
||||
option := &models.CustomerOrderOption{} |
|
||||
exist, err = option.GetByActivityId(activityId) |
|
||||
t.CheckErr(err) |
|
||||
t.Assert(exist, code.MSG_DATA_NOT_EXIST, "订单信息异常") |
|
||||
|
|
||||
result := make([]*OrderListResult, 0) |
|
||||
core.GetXormAuto().Table(&models.OrderDrawActivity{}).Alias("a"). |
|
||||
Select("a.id as order_draw_activity_id, r.id as order_draw_rule_id, a.order_draw_activity_name"). |
|
||||
Join("LEFT", (&models.OrderDrawRule{}).Alias("r"), |
|
||||
"a.id=r.order_draw_activity_id and r.is_delete=0"). |
|
||||
Where("a.is_delete=0 and a.activity_id=?", activityId).Find(&result) |
|
||||
|
|
||||
ruleIds := make([]int, 0) |
|
||||
for _, v := range result { |
|
||||
ruleIds = append(ruleIds, v.OrderDrawRuleId) |
|
||||
} |
|
||||
|
|
||||
ladders := make([]*OrderLadderResult, 0) |
|
||||
err = core.GetXormAuto().Table(&models.OrderDrawRuleLadder{}).Alias("l"). |
|
||||
Select("id as order_draw_ladder_id, status, prize_name, prize_img, prize_number, order_draw_rule_id"). |
|
||||
Where("is_delete=0").In("order_draw_rule_id", ruleIds).Find(&ladders) |
|
||||
t.CheckErr(err) |
|
||||
|
|
||||
ladderIds := make([]int, 0) |
|
||||
for _, ladder := range ladders { |
|
||||
ladderIds = append(ladderIds, ladder.OrderDrawLadderId) |
|
||||
} |
|
||||
|
|
||||
records := make([]map[string]int, 0) |
|
||||
err = core.GetXormAuto().Table(&models.OrderDrawRecord{}).Alias("r"). |
|
||||
Select("r.order_draw_rule_ladder_id as ladder_id, count(id) as num"). |
|
||||
Where("is_delete=0 and rehearsal_id=? and arch_id=? and area_id=?", |
|
||||
activity.RehearsalId, activity.ArchId, area.Id). |
|
||||
In("r.order_draw_rule_ladder_id", ladderIds).GroupBy("ladder_id").Find(&records) |
|
||||
t.CheckErr(err) |
|
||||
|
|
||||
for i := range ladders { |
|
||||
for j := range records { |
|
||||
if ladders[i].OrderDrawLadderId == records[j]["ladder_id"] { |
|
||||
ladders[i].PrizeNumber = ladders[i].PrizeNumber - records[j]["num"] |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
for i := range result { |
|
||||
for j := range ladders { |
|
||||
if result[i].OrderDrawRuleId == ladders[j].OrderDrawRuleId { |
|
||||
result[i].PrizeNumber += ladders[j].PrizeNumber |
|
||||
result[i].OrderDrawLadders = append(result[i].OrderDrawLadders, ladders[j]) |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
t.JSON(map[string]interface{}{ |
|
||||
"total": len(result), |
|
||||
"list": result, |
|
||||
"status": option.Status, |
|
||||
}) |
|
||||
} |
|
||||
|
|
||||
//抽奖奖品
|
|
||||
func (t *OrderDrawSpecialCtl) Prize() { |
|
||||
ruleId := t.MustGetInt("order_draw_rule_id") |
|
||||
|
|
||||
list, err := models.GetOrderDrawRuleLaddersByRuleId(ruleId) |
|
||||
t.CheckErr(err) |
|
||||
|
|
||||
for index := range list { |
|
||||
list[index].Des = "在该活动的所有订单用户中随机抽奖品数量的用户" |
|
||||
} |
|
||||
t.JSON(map[string]interface{}{ |
|
||||
"total": len(list), |
|
||||
"lise": list, |
|
||||
}) |
|
||||
} |
|
||||
|
|
||||
type SpecialOrderUsersResult struct { |
|
||||
UserId int `json:"user_id"` |
|
||||
Username string `json:"username"` |
|
||||
Avatar string `json:"avatar"` |
|
||||
} |
|
||||
|
|
||||
//统计人数和订单数量
|
|
||||
func (t *OrderDrawSpecialCtl) Users() { |
|
||||
activityId := t.MustGetInt("activity_id") |
|
||||
ruleId := t.MustGetInt("order_draw_rule_id") |
|
||||
|
|
||||
activity := models.Activity{} |
|
||||
exist, err := models.Get(&activity, activityId) |
|
||||
t.CheckErr(err) |
|
||||
t.Assert(exist, code.MSG_ACTIVITY_NOT_EXIST, "互动不存在") |
|
||||
|
|
||||
result := make([]*SpecialOrderUsersResult, 0) |
|
||||
session := core.GetXormAuto().Table(&models.CustomerOrder{}).Alias("o"). |
|
||||
Select("o.buyer_id as user_id, u.nickname as username, u.avatar").Distinct("o.buyer_id"). |
|
||||
Join("LEFT", (&models.User{}).Alias("u"), "o.buyer_id=u.id and u.is_delete=0"). |
|
||||
Where("o.activity_id=? and o.is_delete=0 and o.rehearsal_id=? and o.arch_id=?", activityId, |
|
||||
activity.RehearsalId, activity.ArchId) |
|
||||
|
|
||||
moduleService, exist, err := activity_service.GetModuleService(define.MODULE_ORDERLY, activity.Id) |
|
||||
t.CheckErr(err) |
|
||||
t.Assert(exist, code.MSG_MODULE_NOT_EXIST, "模块服务不存在") |
|
||||
if moduleService.BesideRepeat == define.MODULE_BESIDE_REPEAT { |
|
||||
recordIds := make([]int, 0) |
|
||||
err = core.GetXormAuto().Table(&models.OrderDrawRecord{}).Select("user_id"). |
|
||||
Where("order_draw_rule_id=? and rehearsal_id=? and arch_id=? and is_delete=0", |
|
||||
ruleId, activity.RehearsalId, activity.ArchId).Find(&recordIds) |
|
||||
t.CheckErr(err) |
|
||||
session = session.NotIn("o.buyer_id", recordIds) |
|
||||
} |
|
||||
err = session.Find(&result) |
|
||||
t.CheckErr(err) |
|
||||
|
|
||||
t.JSON(map[string]interface{}{ |
|
||||
"total": len(result), |
|
||||
"list": result, |
|
||||
}) |
|
||||
} |
|
||||
|
|
||||
// 订单抽奖动作
|
|
||||
func (t *OrderDrawSpecialCtl) Draw() { |
|
||||
activityId := t.MustGetInt("activity_id") |
|
||||
ladderId := t.MustGetInt("order_draw_rule_ladder_id") |
|
||||
number := t.MustGetInt("number") |
|
||||
customerId := t.GetAccountId() |
|
||||
|
|
||||
customer := models.Customer{} |
|
||||
exist, err := models.Get(&customer, customerId) |
|
||||
t.CheckErr(err) |
|
||||
t.Assert(exist, code.MSG_CUSTOMER_NOT_EXIST, "客户不存在") |
|
||||
|
|
||||
activity := models.Activity{} |
|
||||
exist, err = models.Get(&activity, activityId) |
|
||||
t.CheckErr(err) |
|
||||
t.Assert(exist, code.MSG_ACTIVITY_NOT_EXIST, "互动不存在") |
|
||||
t.CheckRunning(activity.Status) |
|
||||
|
|
||||
area := &models.AreaStore{} |
|
||||
exist, err = area.GetByCustomerId(customerId, activityId) |
|
||||
t.CheckErr(err) |
|
||||
t.Assert(exist, code.MSG_DATA_NOT_EXIST, "地区不存在") |
|
||||
|
|
||||
// 查询奖品
|
|
||||
ladder := models.OrderDrawRuleLadder{} |
|
||||
exist, err = models.Get(&ladder, ladderId) |
|
||||
t.CheckErr(err) |
|
||||
t.Assert(exist, code.MSG_ORDER_LADDER_NOT_EXIST, "订单抽奖等级不存在") |
|
||||
t.CheckRunning(ladder.Status) |
|
||||
|
|
||||
rule := models.OrderDrawRule{} |
|
||||
exist, err = models.Get(&rule, ladder.OrderDrawRuleId) |
|
||||
t.CheckErr(err) |
|
||||
t.Assert(exist, code.MSG_ORDER_RULE_NOT_EXIST, "订单抽奖规则不存在") |
|
||||
|
|
||||
count, err := (&models.OrderDrawRecord{}).Count(ladder.Id, activity.RehearsalId, activity.ArchId) |
|
||||
t.CheckErr(err) |
|
||||
prizeNum := ladder.PrizeNumber - int(count) |
|
||||
if prizeNum <= 0 || prizeNum < number { |
|
||||
t.ERROR("奖品数量不足", code.MSG_LOTTERY_PRIZE_NOT_ENOUGH) |
|
||||
} |
|
||||
|
|
||||
module, exist, err := activity_service.GetModuleService(define.MODULE_ORDERLY, activity.Id) |
|
||||
t.CheckErr(err) |
|
||||
t.Assert(exist, code.MSG_MODULE_NOT_EXIST, "模块服务不存在") |
|
||||
orders, err := lottery_service.GetSpecialOrderLottery(module.BesideRepeat, activity.Id, rule.Id, ladder.Id, activity.RehearsalId, area.Id, activity.ArchId) |
|
||||
if len(orders) < number { |
|
||||
t.ERROR("抽奖订单数量不足", code.MSG_LOTTERY_PEOPLE_NOT_ENOUGH) |
|
||||
} |
|
||||
|
|
||||
lottery_service.RandSpecialOrderLottery(orders) |
|
||||
winnerOrders := orders[:number] |
|
||||
userIds := make([]int, 0) |
|
||||
for _, v := range winnerOrders { |
|
||||
userIds = append(userIds, v.BuyerId) |
|
||||
} |
|
||||
users, err := models.GetUsersByIds(userIds) |
|
||||
t.CheckErr(err) |
|
||||
|
|
||||
winners := make([]*lottery_service.SpecialOrderLotteryUser, 0) |
|
||||
t.CheckErr(err) |
|
||||
for _, o := range winnerOrders { |
|
||||
for _, u := range users { |
|
||||
if u.Id == o.BuyerId { |
|
||||
winners = append(winners, &lottery_service.SpecialOrderLotteryUser{ |
|
||||
UserId: u.Id, |
|
||||
Username: o.Receiver, |
|
||||
UserPhone: o.Phone, |
|
||||
Avatar: u.Avatar, |
|
||||
PrizeName: ladder.PrizeName, |
|
||||
LadderId: ladder.Id, |
|
||||
PrizeImg: ladder.PrizeImg, |
|
||||
EntryPersonName: o.OrderEntryPersonName, |
|
||||
}) |
|
||||
} |
|
||||
} |
|
||||
prize := models.UserPrize{} |
|
||||
prize.ActivityId = activityId |
|
||||
prize.RehearsalId = activity.RehearsalId |
|
||||
prize.ActivityName = activity.Name |
|
||||
prize.UserId = o.BuyerId |
|
||||
prize.CustomerOrderId = o.Id |
|
||||
prize.PrizeImg = ladder.PrizeImg |
|
||||
prize.PrizeName = ladder.PrizeName |
|
||||
prize.ArchId = activity.ArchId |
|
||||
prize.PrizeType = 2 |
|
||||
_, err = models.Add(&prize) |
|
||||
t.CheckErr(err) |
|
||||
|
|
||||
record := models.OrderDrawRecord{} |
|
||||
record.UserPrizeId = prize.Id |
|
||||
record.ActivityId = activityId |
|
||||
record.RehearsalId = activity.RehearsalId |
|
||||
record.ArchId = activity.ArchId |
|
||||
record.OrderDrawActivityId = rule.OrderDrawActivityId |
|
||||
record.OrderDrawRuleId = rule.Id |
|
||||
record.UserId = o.BuyerId |
|
||||
record.CustomerOrderId = o.BuyerId |
|
||||
record.OrderDrawRuleLadderId = ladder.Id |
|
||||
record.PrizeName = ladder.PrizeName |
|
||||
record.AreaId = area.Id |
|
||||
record.AreaName = area.Name |
|
||||
_, err = models.Add(&record) |
|
||||
t.CheckErr(err) |
|
||||
} |
|
||||
t.JSON(winners) |
|
||||
} |
|
||||
|
|
||||
func (t *OrderDrawSpecialCtl) ListOfWinners() { |
|
||||
ruleId := t.MustGetInt("order_draw_rule_id") |
|
||||
|
|
||||
rule := &models.OrderDrawRule{} |
|
||||
exist, err := models.Get(rule, ruleId) |
|
||||
t.CheckErr(err) |
|
||||
t.Assert(exist, code.MSG_ORDER_RULE_NOT_EXIST, "订单抽奖规则不存在") |
|
||||
|
|
||||
lottery := &models.OrderDrawActivity{} |
|
||||
exist, err = models.Get(lottery, rule.OrderDrawActivityId) |
|
||||
t.CheckErr(err) |
|
||||
t.Assert(exist, code.MSG_ORDER_RULE_NOT_EXIST, "订单抽奖规则不存在") |
|
||||
|
|
||||
activity := &models.Activity{} |
|
||||
exist, err = models.Get(activity, lottery.ActivityId) |
|
||||
t.CheckErr(err) |
|
||||
t.Assert(exist, code.MSG_ACTIVITY_NOT_EXIST, "互动不存在") |
|
||||
|
|
||||
result, err := lottery_service.GetSpecialOrderWinnersResult(rule.Id, activity.RehearsalId, activity.ArchId) |
|
||||
t.CheckErr(err) |
|
||||
t.JSON(map[string]interface{}{ |
|
||||
"total": len(result), |
|
||||
"list": result, |
|
||||
}) |
|
||||
} |
|
||||
|
|
||||
// 获取所有订单
|
|
||||
type SpecialOrdersResult struct { |
|
||||
Id int `json:"id"` |
|
||||
UserId int `json:"user_id"` |
|
||||
AreaName string `json:"area_name"` |
|
||||
EntryPersonName string `json:"entry_person_name"` |
|
||||
Username string `json:"username"` |
|
||||
Phone string `json:"phone"` |
|
||||
Address string `json:"address"` |
|
||||
Goods []map[string]string `json:"goods"` |
|
||||
} |
|
||||
|
|
||||
func (t *OrderDrawSpecialCtl) Orders() { |
|
||||
activityId := t.MustGetInt("activity_id") |
|
||||
|
|
||||
activity := models.Activity{} |
|
||||
exist, err := models.Get(&activity, activityId) |
|
||||
t.CheckErr(err) |
|
||||
t.Assert(exist, code.MSG_ACTIVITY_NOT_EXIST, "互动不存在") |
|
||||
|
|
||||
orders := make([]*SpecialOrdersResult, 0) |
|
||||
err = core.GetXormAuto().Table(&models.CustomerOrder{}).Alias("o").Select("o.id as id, "+ |
|
||||
" o.area_name as area_name, o.order_entry_person_name as entry_person_name, o.buyer_id as user_id, "+ |
|
||||
" o.receiver as username, o.phone as phone, o.address as address, o.created_at"). |
|
||||
Where("o.is_delete=0 and o.activity_id=? and o.rehearsal_id=? and o.arch_id=?", |
|
||||
activityId, activity.RehearsalId, activity.ArchId).Asc("o.created_at").Find(&orders) |
|
||||
t.CheckErr(err) |
|
||||
|
|
||||
orderIds := make([]int, 0) |
|
||||
for _, o := range orders { |
|
||||
orderIds = append(orderIds, o.Id) |
|
||||
} |
|
||||
subs, err := models.GetCustomerOrderSubsByOrderIds(orderIds) |
|
||||
t.CheckErr(err) |
|
||||
for i := range orders { |
|
||||
for j := range subs { |
|
||||
if fmt.Sprint(orders[i].Id) == subs[j]["order_id"] { |
|
||||
orders[i].Goods = append(orders[i].Goods, subs[j]) |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
// 下订单人数
|
|
||||
buyerCount, err := (&models.CustomerOrder{}).CountCustomerOrder(activity.Id, activity.RehearsalId, activity.ArchId) |
|
||||
t.CheckErr(err) |
|
||||
|
|
||||
t.JSON(map[string]interface{}{ |
|
||||
"orders": orders, |
|
||||
"total": len(orders), |
|
||||
"buyer_count": buyerCount, |
|
||||
}) |
|
||||
} |
|
||||
|
|
||||
// 录入人员排行榜
|
|
||||
func (t *OrderDrawSpecialCtl) OrderRank() { |
|
||||
activityId := t.MustGetInt("activity_id") |
|
||||
limit := t.MustGetInt("limit") |
|
||||
|
|
||||
activity := models.Activity{} |
|
||||
exist, err := models.Get(&activity, activityId) |
|
||||
t.CheckErr(err) |
|
||||
t.Assert(exist, code.MSG_ACTIVITY_NOT_EXIST, "互动不存在") |
|
||||
|
|
||||
order := &models.CustomerOrder{} |
|
||||
res, err := order.SumCustomerOrder(activity.Id, activity.RehearsalId, activity.ArchId, limit) |
|
||||
t.CheckErr(err) |
|
||||
total, err := order.TotalCustomerOrderGoodsNum(activity.Id, activity.RehearsalId, activity.ArchId) |
|
||||
t.CheckErr(err) |
|
||||
t.JSON(map[string]interface{}{ |
|
||||
"list": res, |
|
||||
"total": total, |
|
||||
}) |
|
||||
} |
|
Write
Preview
Loading…
Cancel
Save
Reference in new issue