package settle_account_main import ( "dashoo.cn/micro_libary/request" "database/sql" "errors" "fmt" "github.com/gogf/gf/os/gtime" "github.com/gogf/gf/util/gconv" "lims_adapter/dao/account" "lims_adapter/model" accountModel "lims_adapter/model/account" "math" "strconv" "strings" ) // Service 会议室服务 type Service struct { Dao *account.SettleAccountMainDao Tenant string } // NewSrv 服务初始化 func NewService(tenant string) Service { return Service{Dao: account.NewSettleAccountMainDao(tenant), Tenant: tenant} } // List 结算明细 func (s Service) List(req model.ListReq, user request.UserInfo) ([]accountModel.MainInfo, int, error) { entityModel := s.Dao.M where := "1=1" if req.Entity != nil { entity := new(accountModel.SettleAccountMainReq) err := gconv.Struct(req.Entity, entity) if err != nil { return nil, 0, err } if entity.SearchType != "1" { // 1 查询全部;2 查询主用户;3或其他 查询从用户 if entity.SearchType == "2" { where += fmt.Sprintf(" AND MainUserId='%v'", user.Id) } else { where += fmt.Sprintf(" AND AttachUserId='%v'", user.Id) } } if entity.MainUserId != 0 { where += fmt.Sprintf(" AND MainUserId='%v'", entity.MainUserId) } if entity.MainUser != "" { where += fmt.Sprintf(" AND MainUser LIKE '%%%v%%'", entity.MainUser) } if entity.AttachUserId != 0 { where += fmt.Sprintf(" AND AttachUserId='%v'", entity.AttachUserId) } if entity.AttachUser != "" { where += fmt.Sprintf(" AND AttachUser LIKE '%%%v%%'", entity.AttachUser) } if entity.InstrumentId != 0 { where += fmt.Sprintf(" AND InstrumentId='%v'", entity.InstrumentId) } if entity.InstrumentName != "" { where += fmt.Sprintf(" AND InstrumentName LIKE '%%%v%%'", entity.InstrumentName) } if entity.AppointUserId != 0 { where += fmt.Sprintf(" AND AppointUserId='%v'", entity.AppointUserId) } if entity.AppointUser != "" { where += fmt.Sprintf(" AND AppointUser LIKE '%%%v%%'", entity.AppointUser) } if entity.Status != "" { where += fmt.Sprintf(" AND Status='%v'", entity.Status) } if entity.SettleStatus != "" { // 确认状态 where += fmt.Sprintf(" AND SettleStatus='%v'", entity.SettleStatus) } if entity.AccountStatus != "" { // 结算状态 where += fmt.Sprintf(" AND AccountStatus='%v'", entity.AccountStatus) } if entity.SettleUser != "" { // 结算人 where += fmt.Sprintf(" AND SettleUser LIKE '%%%v%%'", entity.SettleUser) } if entity.VerificationUser != "" { // 确认人 where += fmt.Sprintf(" AND VerificationUser LIKE '%%%v%%'", entity.VerificationUser) } if entity.FeeType != "" { where += fmt.Sprintf(" AND FeeType='%v'", entity.FeeType) } if entity.BillId != "" { where += fmt.Sprintf(" AND BillId='%v'", entity.BillId) } if entity.AppointStartDate != "" && entity.AppointEndDate != "" { where += fmt.Sprintf(" AND AppointStartDate>='%v' AND AppointEndDate<='%v'", entity.AppointStartDate, entity.AppointEndDate) } if entity.ActualStartDate != "" && entity.ActualEndDate != "" { where += fmt.Sprintf(" AND ActualStartDate>='%v' AND ActualEndDate<='%v'", entity.ActualStartDate, entity.ActualEndDate) } if entity.SettleStartDate != "" && entity.SettleEndDate != "" { where += fmt.Sprintf(" AND SettleDate>='%v' AND SettleDate<='%v'", entity.SettleStartDate, entity.SettleEndDate) } if entity.VerificationDate != "" { timelist := strings.Split(entity.VerificationDate,",") if len(timelist) == 2 { where += fmt.Sprintf(" AND VerificationDate>='%v' AND VerificationDate<='%v'", timelist[0],timelist[1]) } } if entity.NotInBill == "1" { where += fmt.Sprintf(" AND (SettleStatus='0' OR Status='0')") } } entityModel = entityModel.Where(where) total, err := entityModel.Count() if err != nil { return nil, 0, err } if total == 0 { return nil, 0, nil } res, err := entityModel.Page(req.Current, req.Size).Order("settle_account_main.CreateOn DESC").Fields("settle_account_main.*").FindAll() if err != nil { return nil, 0, err } if res.IsEmpty() { return nil, 0, nil } list := make([]accountModel.MainInfo, 0) err = res.Structs(&list) if err != nil { return nil, 0, err } var appoints []accountModel.SearchEntity appointMap := make(map[int]accountModel.SearchEntity, 0) ids := "-1" for _, item := range list { ids += fmt.Sprintf(",%v", item.AppointId) } res, err = s.Dao.DB.Model("appointment").Where(fmt.Sprintf("Id IN (%v)", ids)).FindAll() if err != nil { return nil, 0, err } err = res.Structs(&appoints) if err != nil { if err == sql.ErrNoRows { return list, total, nil } return list, total, err } for _, item := range appoints { appointMap[item.Id] = item } for index, item := range list { if appointMap[item.AppointId].Id != 0 { list[index].SignInTime = appointMap[item.AppointId].SignInTime list[index].SignOutTime = appointMap[item.AppointId].SignOutTime list[index].AppointStatus = appointMap[item.AppointId].Status } } return list, total, nil } // 新增 func (s Service) Add(req accountModel.AccountMainAddReq, user request.UserInfo) error { now := gtime.Now() // 获取当前时间 var baseAccount accountModel.BaseAccount var instrument accountModel.Instrument // 更新必要信息 req.Main.CreateUserId = int(user.Id) req.Main.CreateBy = user.RealName req.Main.CreateOn = now req.Main.UpdateUserId = int(user.Id) req.Main.UpdateBy = user.RealName req.Main.UpdateOn = now req.Main.ActualStartDate = nil // 默认有信息终端 req.Main.ActualEndDate = nil // 默认有信息终端 span := req.Main.AppointEndDate.Sub(req.Main.AppointStartDate) req.Main.FeeTime = int(math.Ceil(span.Minutes())) req.Main.ActualMachineHour = req.Main.FeeTime req.Main.Status = "0" req.Main.SettleStatus = "0" req.Main.AccountStatus = "0" // 获取账户 result1, err := s.Dao.DB.Model("base_account").Where(fmt.Sprintf("MainUserId='%v'", req.Main.MainUserId)).Order("Advance ASC, Id ASC").FindOne() if err != nil { return err } err = result1.Struct(&baseAccount) if err != nil { if err == sql.ErrNoRows { return errors.New("无可用账户") } return err } // 获取设备 result1, err = s.Dao.DB.Model("instrument").Where(fmt.Sprintf("Id='%v'", req.Main.InstrumentId)).FindOne() if err != nil { return err } err = result1.Struct(&instrument) if err != nil { if err == sql.ErrNoRows { return errors.New("无可用设备") } return err } if instrument.Terminal == "" { // 无信息终端时,按预约时间计算 req.Main.ActualStartDate = req.Main.AppointStartDate req.Main.ActualEndDate = req.Main.AppointEndDate } tx, err := s.Dao.DB.Begin() if err != nil { return err } result, err := tx.Insert("settle_account_main", req.Main) if err != nil { tx.Rollback() return err } req.Main.TotalPrice = 0 id , _ := result.LastInsertId() for index := range req.Details { // 更新必要信息 req.Details[index].CreateUserId = int(user.Id) req.Details[index].CreateBy = user.RealName req.Details[index].CreateOn = now req.Details[index].UpdateUserId = int(user.Id) req.Details[index].UpdateBy = user.RealName req.Details[index].UpdateOn = now req.Details[index].Pid = int(id) if req.Details[index].PaymentType == "0" { req.Details[index].ActualMinutes = strconv.Itoa(req.Main.ActualMachineHour) req.Details[index].Minutes = strconv.Itoa(req.Main.ActualMachineHour) discount := float64(1) // 计算折扣 if req.Details[index].Data5 != "" { d, _ := strconv.ParseFloat(req.Details[index].Data5, 64) discount = 1 - d / 100 } req.Details[index].PaymentAccount = float64(req.Main.ActualMachineHour) * req.Details[index].UnitPrice * discount / 60 // 计算实际费用 } req.Main.TotalPrice += req.Details[index].PaymentAccount } baseAccount.Available -= req.Main.TotalPrice // 账户可用金额计算 _, err = tx.Insert("settle_account_detail", req.Details) if err != nil { tx.Rollback() return err } _, err = tx.Save("base_account", baseAccount) if err != nil { tx.Rollback() return err } return tx.Commit() } // 确认 func (s Service) Confirm(req accountModel.AccountMainConfirmReq, user request.UserInfo) error { if req.MainId == 0 { return errors.New("参数缺失") } _, err := s.Dao.M.Update(fmt.Sprintf("SettleStatus='1',VerificationUserId='%v',VerificationUser='%v',VerificationDate='%v'", user.Id, user.RealName, gtime.Now()), fmt.Sprintf("Id='%v'", req.MainId)) return err } // 预约取消 func (s Service) Cancel(req accountModel.AccountMainCancelReq) error { if req.AppointId == 0 { return errors.New("参数缺失") } var main accountModel.SettleAccountMain var details []accountModel.SettleAccountDetail var baseAccount accountModel.BaseAccount var rules []Param now := gtime.Now() nowStr := now.Format("Y-m-d H:i:s") per := float64(0) userNumber := 0 one, err := s.Dao.M.Where(fmt.Sprintf("AppointId='%v'", req.AppointId)).FindOne() if err != nil { return err } err = one.Struct(&main) if err != nil { if err == sql.ErrNoRows { return nil } return err } if main.Id == 0 { // 该预约未生成账单 return nil } all, err := s.Dao.DB.Model("settle_account_detail").Where(fmt.Sprintf("pid='%v' AND PaymentType='0'", main.Id)).FindAll() if err != nil { return err } err = all.Structs(&details) if err != nil { return err } all, err = s.Dao.DB.Model("base_param").Where("Name LIKE '违约计费规则%'").Order("Code ASC").FindAll() if err != nil { return err } err = all.Structs(&rules) if err != nil { return err } // 计算当前机器占用数量 //1、上一个实验人未结束实验,未占用下一个预约开始时间,下一个实验取消预约,需要进行违约扣费 //2、上一个实验人未结束实验,占用了下一个预约开始时间,下一个实验取消预约,不需要进行违约扣费 //3、上一个实验人结束了实验,占用了下一个预约开始时间,下一个实验取消预约,不需要进行违约扣费 userNumber, err = s.Dao.DB.Model("appointment").Where(fmt.Sprintf("RelevanceId='%v' AND ((SignInTime IS NOT NULL AND SignOutTime IS NULL AND '%v' > '%v') OR (SignOutTime > '%v'))", main.InstrumentId, nowStr, main.AppointStartDate.Format("Y-m-d H:i:s"), main.AppointStartDate.Format("Y-m-d H:i:s"))).Count() if err != nil { return err } // 获取账户 result1, err := s.Dao.DB.Model("base_account").Where(fmt.Sprintf("MainUserId='%v'", main.MainUserId)).Order("Advance ASC, Id ASC").FindOne() if err != nil { return err } err = result1.Struct(&baseAccount) if err != nil { return err } var detail accountModel.SettleAccountDetail detail.PaymentType = "1" detail.PaymentAccount = 0 detail.Data1 = main.AppointStartDate.Format("Y-m-d H:i:s") detail.Data2 = main.AppointEndDate.Format("Y-m-d H:i:s") detail.Data3 = now.Format("Y-m-d H:i:s") // 取消时间 detail.Pid = main.Id mins := main.AppointStartDate.Sub(now).Minutes() if mins > 0 { // 正向超时,计算违约收费 r := "" for _, rule := range rules { value1, _ := strconv.ParseFloat(rule.Code, 64) if mins < value1 { per, _ = strconv.ParseFloat(rule.Value, 64) per /= 100 r = rule.Code + "分钟内" + rule.Value + "%" } } detail.Data4 = r // 扣费规则 } else { detail.Data4 = "已开始之后取消,100%" // 扣费规则 per = 1 } if userNumber > 0 { // 机器被占用,机器被占用,取消不扣费 detail.Data4 = "机器被占用,取消不扣费" per = 0 } main.ActualMachineHour = 0 for _, item := range details { // 计算费用 //discount := float64(1) // 计算折扣 //if item.Data5 != "" { // d, _ := strconv.ParseFloat(item.Data5, 64) // discount = 1 - d / 100 //} //detail.PaymentAccount += item.PaymentAccount * discount * per detail.PaymentAccount += item.PaymentAccount * 1 * per // 取消不算折扣 } main.ActualStartDate = nil main.ActualEndDate = nil oldAmount := main.TotalPrice main.TotalPrice = detail.PaymentAccount diffValue := oldAmount - detail.PaymentAccount main.ActualStartDate = nil main.ActualEndDate = nil baseAccount.Available += diffValue // 账户可用金额返还 tx, err := s.Dao.DB.Begin() if err != nil { return err } // 更新账单明细信息 _, err = tx.Save("settle_account_main", main) if err != nil { tx.Rollback() return err } // 计费明细费用设置为0 _, err = tx.Update("settle_account_detail", "PaymentAccount=0", fmt.Sprintf("pid='%v'", main.Id)) if err != nil { tx.Rollback() return err } // 新增违约计费 _, err = tx.Save("settle_account_detail", detail) if err != nil { tx.Rollback() return err } _, err = tx.Save("base_account", baseAccount) if err != nil { tx.Rollback() return err } return tx.Commit() } type Param struct { Id int32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` Code string `protobuf:"bytes,2,opt,name=code,proto3" json:"code,omitempty"` Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"` Value string `protobuf:"bytes,4,opt,name=value,proto3" json:"value,omitempty"` Sys string `protobuf:"bytes,5,opt,name=sys,proto3" json:"sys"` SortCode int32 `protobuf:"varint,6,opt,name=sort_code,json=sortCode,proto3" json:"sort_code"` Description string `protobuf:"bytes,7,opt,name=description,proto3" json:"description,omitempty"` CreateOn string `protobuf:"bytes,8,opt,name=create_on,json=createOn,proto3" json:"create_on,omitempty"` CreateUserId int32 `protobuf:"varint,9,opt,name=create_user_id,json=createUserId,proto3" json:"create_user_id,omitempty"` CreateBy string `protobuf:"bytes,10,opt,name=create_by,json=createBy,proto3" json:"create_by,omitempty"` ModifiedOn string `protobuf:"bytes,11,opt,name=modified_on,json=modifiedOn,proto3" json:"modified_on,omitempty"` ModifiedUserId int32 `protobuf:"varint,12,opt,name=modified_user_id,json=modifiedUserId,proto3" json:"modified_user_id,omitempty"` ModifiedBy string `protobuf:"bytes,13,opt,name=modified_by,json=modifiedBy,proto3" json:"modified_by,omitempty"` }