package contract import ( "bytes" "encoding/json" "fmt" "github.com/gin-gonic/gin" "github.com/go-playground/validator/v10" "github.com/shopspring/decimal" "github.com/tealeg/xlsx" "hongze/fms_api/controller/resp" "hongze/fms_api/global" "hongze/fms_api/models/base" "hongze/fms_api/models/crm" "hongze/fms_api/models/fms" "hongze/fms_api/models/system" "hongze/fms_api/services/alarm_msg" crmService "hongze/fms_api/services/crm" fmsService "hongze/fms_api/services/fms" "hongze/fms_api/utils" "net/http" "os" "path" "strconv" "strings" "time" ) // RegisterController 合同登记 type RegisterController struct{} // List // @Title 合同登记列表 // @Description 合同登记列表 // @Param Keyword query string false "关键词" // @Param StartDate query string false "合同开始日期" // @Param EndDate query string false "合同结束日期" // @Param ServiceType query int false "套餐类型" // @Param ContractType query int false "合同类型" // @Param RegisterStatus query int false "登记状态" // @Success 200 {object} fms.ContractRegisterItem // @router /contract/register/list [get] func (rg *RegisterController) List(c *gin.Context) { var req fms.ContractRegisterListReq if e := c.BindQuery(&req); e != nil { err, ok := e.(validator.ValidationErrors) if !ok { resp.FailData("参数解析失败", "Err:"+e.Error(), c) return } resp.FailData("参数解析失败", err.Translate(global.Trans), c) return } cond := `1 = 1` pars := make([]interface{}, 0) // 合同编号/客户姓名/销售/实际使用方 if req.Keyword != "" { kw := "%" + req.Keyword + "%" cond += ` AND (company_name LIKE ? OR contract_code LIKE ? OR seller_name LIKE ? OR rai_seller_name LIKE ? OR actual_company_name LIKE ?)` pars = append(pars, kw, kw, kw, kw, kw) } if req.StartDate != "" && req.EndDate != "" { st := fmt.Sprint(req.StartDate, " 00:00:00") ed := fmt.Sprint(req.EndDate, " 23:59:59") cond += ` AND (create_time BETWEEN ? AND ?)` pars = append(pars, st, ed) } if req.ContractType != 0 { cond += ` AND contract_type = ?` pars = append(pars, req.ContractType) } if req.RegisterStatus != 0 { cond += ` AND register_status = ?` pars = append(pars, req.RegisterStatus) } // 套餐筛选 if req.ServiceTypes != "" { serviceTypes := strings.Split(req.ServiceTypes, ",") registerIds, e := fms.GetContractRegisterIdsByTempId(serviceTypes) if e != nil { resp.FailMsg("获取失败", "获取合同登记IDs失败, Err: "+e.Error(), c) return } if len(registerIds) > 0 { cond += ` AND contract_register_id IN ?` pars = append(pars, registerIds) } else { cond += ` AND 1 = 2` } } page := new(base.Page) page.SetPageSize(req.PageSize) page.SetCurrent(req.Current) page.AddOrderItem(base.OrderItem{Column: "create_time", Asc: false}) total, list, e := fms.GetContractRegisterItemPageList(page, cond, pars) if e != nil { resp.FailMsg("获取失败", "获取合同登记列表失败, Err: "+e.Error(), c) return } registerIds := make([]int, 0) for i := range list { registerIds = append(registerIds, list[i].ContractRegisterId) } serviceMap := make(map[int]string, 0) invoiceMap := make(map[int][]*fms.ContractInvoiceItem, 0) paymentMap := make(map[int][]*fms.ContractInvoiceItem, 0) if len(registerIds) > 0 { // 获取所有的服务套餐 serviceMap, _, e = fmsService.GetContractServiceNameFormat(registerIds) if e != nil { resp.FailMsg("获取失败", e.Error(), c) return } // 获取开票/到款列表 invoiceCond := `contract_register_id IN ?` invoicePars := make([]interface{}, 0) invoicePars = append(invoicePars, registerIds) invoiceList, e := fms.GetContractInvoiceItemList(invoiceCond, invoicePars) if e != nil { resp.FailMsg("获取失败", "获取开票/到款列表失败, Err: "+e.Error(), c) return } for i := range invoiceList { if invoiceMap[invoiceList[i].ContractRegisterId] == nil { invoiceMap[invoiceList[i].ContractRegisterId] = make([]*fms.ContractInvoiceItem, 0) } if paymentMap[invoiceList[i].ContractRegisterId] == nil { paymentMap[invoiceList[i].ContractRegisterId] = make([]*fms.ContractInvoiceItem, 0) } if invoiceList[i].InvoiceType == fms.ContractInvoiceTypeMake { invoiceMap[invoiceList[i].ContractRegisterId] = append(invoiceMap[invoiceList[i].ContractRegisterId], invoiceList[i]) } if invoiceList[i].InvoiceType == fms.ContractInvoiceTypePay { paymentMap[invoiceList[i].ContractRegisterId] = append(paymentMap[invoiceList[i].ContractRegisterId], invoiceList[i]) } } } respList := make([]*fms.ContractRegisterList, 0) for i := range list { v := new(fms.ContractRegisterList) v.ContractRegisterItem = list[i] v.ServicesName = serviceMap[list[i].ContractRegisterId] v.InvoiceList = invoiceMap[list[i].ContractRegisterId] v.PaymentList = paymentMap[list[i].ContractRegisterId] respList = append(respList, v) } page.SetTotal(total) baseData := new(base.BaseData) baseData.SetPage(page) baseData.SetList(respList) resp.OkData("获取成功", baseData, c) } // Add // @Title 新增合同登记 // @Description 新增合同登记 // @Param request body fms.ContractRegisterAddReq true "type json string" // @Success 200 string "操作成功" // @router /contract/register/add [post] func (rg *RegisterController) Add(c *gin.Context) { req := new(fms.ContractRegisterAddReq) err := c.ShouldBind(&req) if err != nil { errs, ok := err.(validator.ValidationErrors) if !ok { resp.FailData("参数解析失败", "Err:"+err.Error(), c) return } resp.FailData("参数解析失败", errs.Translate(global.Trans), c) return } claims, _ := c.Get("adminInfo") adminInfo := claims.(*system.SysAdmin) // 日期校验 startDate, e := time.ParseInLocation(utils.FormatDate, req.StartDate, time.Local) if e != nil { resp.FailMsg("合同开始日期格式有误", "合同开始日期格式有误, Err: "+e.Error(), c) return } endDate, e := time.ParseInLocation(utils.FormatDate, req.EndDate, time.Local) if e != nil { resp.FailMsg("合同结束日期格式有误", "合同结束日期格式有误, Err: "+e.Error(), c) return } signDate, _ := time.ParseInLocation(utils.FormatDate, "0000-00-00", time.Local) if req.SignDate != "" { signDateTime, e := time.ParseInLocation(utils.FormatDate, req.SignDate, time.Local) if e != nil { resp.FailMsg("合同签订日期格式有误", "合同签订日期格式有误, Err: "+e.Error(), c) return } signDate = signDateTime } // 是否存在相同合同编号的登记 ob := new(fms.ContractRegister) existCond := `contract_code = ?` existPars := make([]interface{}, 0) existPars = append(existPars, req.ContractCode) exist, e := ob.FetchByCondition(existCond, existPars) if e != nil && e != utils.ErrNoRow { resp.FailMsg("操作失败", "获取相同登记号失败, Err: "+e.Error(), c) return } if exist != nil && exist.ContractRegisterId > 0 { resp.Fail("合同编号已存在", c) return } // 货币及汇率 rateList, e := fmsService.GetTodayCurrencyRateList() if e != nil { resp.FailMsg("操作失败", "获取今日货币汇率失败, Err: "+e.Error(), c) return } var rate float64 for i := range rateList { if req.CurrencyUnit == rateList[i].Code { rate = rateList[i].RMBRate break } } if rate <= 0 { resp.FailMsg("操作失败", "货币汇率信息有误", c) return } // 查询销售信息 var ( sellerId int raiSellerId int sellerName string raiSellerName string ) if req.SellerIds != "" { admin := new(crm.Admin) sellerIds := strings.Split(req.SellerIds, ",") if len(sellerIds) > 2 { resp.Fail("最多只能选择两个销售", c) return } var pars []interface{} cond := ` admin_id in (?) ` pars = append(pars, sellerIds) sellers, e := admin.List(cond, pars) if e != nil { resp.FailMsg("获取销售信息失败", "获取销售信息失败, Err: "+e.Error(), c) return } for _, v := range sellers { if v.DepartmentId == crm.SellerDepartmentId { sellerId = v.AdminId sellerName = v.AdminName }else if v.DepartmentId == crm.RaiSellerDepartmentId { raiSellerId = v.AdminId raiSellerName = v.AdminName } } } //新老客户判断 /*newCompany := req.NewCompany if req.ContractType == 1 { newCompany = 1 }else if req.ContractType == 2 || req.ContractType == 3 { newCompany = 0 } if newCompany != req.NewCompany { resp.Fail("请输入正确的客户类型", c) return }*/ nowTime := time.Now().Local() ob.ContractCode = req.ContractCode ob.RelateContractCode = req.RelateContractCode ob.CrmContractId = req.CrmContractId ob.ContractSource = req.ContractSource ob.CompanyName = req.CompanyName ob.ActualCompanyName = req.ActualCompanyName ob.ProductIds = req.ProductIds ob.SellerId = sellerId ob.SellerName = sellerName ob.RaiSellerId = raiSellerId ob.RaiSellerName = raiSellerName ob.ContractType = req.ContractType ob.ContractAmount = req.ContractAmount ob.CurrencyUnit = req.CurrencyUnit ob.RMBRate = rate ob.StartDate = startDate ob.EndDate = endDate ob.SignDate = signDate ob.AgreedPayTime = req.AgreedPayTime ob.ContractStatus = req.ContractStatus ob.RegisterStatus = fms.ContractRegisterStatusIng ob.Remark = req.Remark ob.ServiceRemark = req.ServiceRemark ob.HasPayment = req.HasPayment ob.NewCompany = req.NewCompany ob.Set() // 存在代付的直接完成登记, 且不允许进行开票/到款登记 if req.HasPayment == 1 || req.ContractStatus == fms.ContractStatusEnd { ob.RegisterStatus = fms.ContractRegisterStatusComplete } // 新增套餐金额详情内容 serviceAmountMap := make(map[int]float64) serviceAmountList, e := fmsService.HandleContractServiceAmount(req.ServiceAmount, serviceAmountMap, req.CurrencyUnit) if e != nil { resp.FailMsg("操作失败", "新增合同套餐金额信息失败, Err: "+e.Error(), c) return } //判断产品信息 productIds := make(map[int]struct{}) productIdsStr := "" for _, v := range serviceAmountList { productIds[v.ProductId] = struct{}{} } for proId, _ := range productIds { productIdsStr += strconv.Itoa(proId)+"," } productIdsStr = strings.Trim(productIdsStr, ",") ob.ProductIds = productIdsStr // 套餐信息 serviceList, e := fmsService.HandleContractServiceAndDetail(req.Services, true, serviceAmountMap) if e != nil { resp.FailMsg("操作失败", "获取合同套餐详情失败, Err: "+e.Error(), c) return } // 新增合同及套餐 if req.Supplement == 1 { //新增到款信息 if ob.HasPayment == 1 { resp.Fail("合同存在代付不允许添加开票/到款登记", c) return } //新增合同信息 if e = fms.CreateContractRegisterAndServicesAndPayMent(ob, serviceList, req.PrePayId); e != nil { resp.FailMsg("操作失败", "新增合同及套餐失败, Err: "+e.Error(), c) return } prePayOB := new(fms.ContractPrePayment) ppItem, e := prePayOB.Fetch(req.PrePayId) if e != nil { if e == utils.ErrNoRow { resp.Fail("预到款不存在或已被删除", c) return } resp.FailMsg("获取预到款记录失败", "Err:"+e.Error(), c) return } // 合同有效时长(计算付款方式) dayDiff := ob.EndDate.Sub(ob.StartDate).Hours() / 24 // 获取销售分组信息 sellerList, e := crmService.GetSellerDepartmentListWithGroupAndTeam() if e != nil { resp.FailData("获取销售失败", "Err:"+e.Error(), c) return } sellerMap := make(map[int]*crm.SellerAdminWithGroupTeam) for i := range sellerList { sellerMap[sellerList[i].SellerId] = sellerList[i] } v := &fms.ContractInvoice{ ContractRegisterId: ob.ContractRegisterId, ContractCode: ob.ContractCode, Amount: ppItem.Amount, OriginAmount: ppItem.OriginAmount, CurrencyUnit: ppItem.CurrencyUnit, InvoiceType: fms.ContractInvoiceTypePay, InvoiceDate: ppItem.CreateTime, AdminId: int(adminInfo.AdminId), AdminName: adminInfo.RealName, Remark: ppItem.Remark, IsPrePay: 1, } v.Set() // 到款登记-付款方式 v.PayType = fmsService.CalculateContractPaymentType(ppItem.Amount, ob.ContractAmount, dayDiff) // 新增的记录 logList := make([]*fms.ContractRegisterLog, 0) opData := "" opDataByte, e := json.Marshal(req) if e != nil { return } opData = string(opDataByte) opType := fms.ContractInvoiceTypePrePay newAmount := decimal.NewFromFloat(0).Round(2) a := decimal.NewFromFloat(v.Amount).Round(2) newAmount = newAmount.Add(a) ia, _ := newAmount.Round(2).Float64() logList = append(logList, &fms.ContractRegisterLog{ ContractRegisterId: ob.ContractRegisterId, AdminId: int(adminInfo.AdminId), AdminName: adminInfo.RealName, OpData: opData, OpType: opType, CreateTime: nowTime, AmountRemark: fmt.Sprint("新增", fms.ContractInvoiceKeyNameMap[opType], "金额", ia, "元"), }) if e := v.Create(); e != nil { resp.FailData("日期格式有误", "Err:"+e.Error(), c) return } //最后删除预到款记录 e = ppItem.Delete() if e != nil { resp.FailMsg("删除预到款记录失败", "Err:"+e.Error(), c) return } // 校验金额-是否修改状态 go fmsService.CheckContractRegisterAmount(ob.ContractRegisterId) // 开票到款汇总 go fmsService.SummaryInvoicePaymentByContractRegisterId(ob.ContractRegisterId) // 操作日志 go func() { logOB := new(fms.ContractRegisterLog) if e := logOB.AddInBatches(logList); e != nil { return } }() } else { if e = fms.CreateContractRegisterAndServices(ob, serviceList, serviceAmountList); e != nil { resp.FailMsg("操作失败", "新增合同及套餐失败, Err: "+e.Error(), c) return } } // 操作日志 go func() { opData := "" opDataByte, e := json.Marshal(req) if e != nil { return } opData = string(opDataByte) logItem := new(fms.ContractRegisterLog) logItem.ContractRegisterId = ob.ContractRegisterId logItem.AdminId = int(adminInfo.AdminId) logItem.AdminName = adminInfo.RealName logItem.OpData = opData logItem.OpType = fms.ContractRegisterOpTypeSave logItem.CreateTime = nowTime logItem.Remark = req.Remark if e = logItem.Create(); e != nil { return } }() resp.Ok("操作成功", c) } // Edit // @Title 编辑合同登记 // @Description 编辑合同登记 // @Param request body fms.ContractRegisterEditReq true "type json string" // @Success 200 string "操作成功" // @router /contract/register/edit [post] func (rg *RegisterController) Edit(c *gin.Context) { req := new(fms.ContractRegisterEditReq) err := c.ShouldBind(&req) if err != nil { errs, ok := err.(validator.ValidationErrors) if !ok { resp.FailData("参数解析失败", "Err:"+err.Error(), c) return } resp.FailData("参数解析失败", errs.Translate(global.Trans), c) return } claims, _ := c.Get("adminInfo") adminInfo := claims.(*system.SysAdmin) // 日期校验 startDate, e := time.ParseInLocation(utils.FormatDate, req.StartDate, time.Local) if e != nil { resp.FailMsg("合同开始日期格式有误", "合同开始日期格式有误, Err: "+e.Error(), c) return } endDate, e := time.ParseInLocation(utils.FormatDate, req.EndDate, time.Local) if e != nil { resp.FailMsg("合同结束日期格式有误", "合同结束日期格式有误, Err: "+e.Error(), c) return } signDate, _ := time.ParseInLocation(utils.FormatDate, "0000-00-00", time.Local) if req.SignDate != "" { signDateTime, e := time.ParseInLocation(utils.FormatDate, req.SignDate, time.Local) if e != nil { resp.FailMsg("合同签订日期格式有误", "合同签订日期格式有误, Err: "+e.Error(), c) return } signDate = signDateTime } ob := new(fms.ContractRegister) item, e := ob.Fetch(req.ContractRegisterId) if e != nil { if e == utils.ErrNoRow { resp.Fail("登记记录不存在或已被删除", c) return } resp.FailMsg("操作失败", "获取合同登记信息失败, Err:"+e.Error(), c) return } // 查询销售信息 var ( sellerId int raiSellerId int sellerName string raiSellerName string ) if req.SellerIds != "" { admin := new(crm.Admin) sellerIds := strings.Split(req.SellerIds, ",") if len(sellerIds) > 2 { resp.Fail("最多只能选择两个销售", c) return } var pars []interface{} cond := ` admin_id in (?) ` pars = append(pars, sellerIds) sellers, e := admin.List(cond, pars) if e != nil { resp.FailMsg("获取销售信息失败", "获取销售信息失败, Err: "+e.Error(), c) return } for _, v := range sellers { if v.DepartmentId == crm.SellerDepartmentId { sellerId = v.AdminId sellerName = v.AdminName }else if v.DepartmentId == crm.RaiSellerDepartmentId { raiSellerId = v.AdminId raiSellerName = v.AdminName } } } // 是否存在相同合同编号的登记 existCond := `contract_code = ?` existPars := make([]interface{}, 0) existPars = append(existPars, req.ContractCode) exist, e := ob.FetchByCondition(existCond, existPars) if e != nil && e != utils.ErrNoRow { resp.FailMsg("操作失败", "获取相同登记号失败, Err: "+e.Error(), c) return } if exist != nil && exist.ContractRegisterId > 0 && exist.ContractRegisterId != item.ContractRegisterId { resp.Fail("合同编号已存在", c) return } originHasPayment := item.HasPayment updateCols := []string{ "ProductIds","ContractCode", "RelateContractCode", "CrmContractId", "ContractSource", "CompanyName", "ActualCompanyName", "SellerId", "SellerName", "ContractType", "ContractAmount", "StartDate", "EndDate", "SignDate", "AgreedPayTime", "ContractStatus", "RegisterStatus", "Remark", "ServiceRemark", "HasPayment", "NewCompany", "ModifyTime", } nowTime := time.Now().Local() item.ProductIds = req.ProductIds item.ContractCode = req.ContractCode item.RelateContractCode = req.RelateContractCode item.CrmContractId = req.CrmContractId item.ContractSource = req.ContractSource item.CompanyName = req.CompanyName item.ActualCompanyName = req.ActualCompanyName item.SellerId = sellerId item.SellerName = sellerName item.RaiSellerId = raiSellerId item.RaiSellerName = raiSellerName item.ContractType = req.ContractType item.ContractAmount = req.ContractAmount item.StartDate = startDate item.EndDate = endDate item.SignDate = signDate item.AgreedPayTime = req.AgreedPayTime item.ContractStatus = req.ContractStatus item.RegisterStatus = fms.ContractRegisterStatusIng item.Remark = req.Remark item.ServiceRemark = req.ServiceRemark item.HasPayment = req.HasPayment item.NewCompany = req.NewCompany item.ModifyTime = nowTime // 存在代付的直接完成登记, 且不允许进行开票/到款登记 if req.HasPayment == 1 { item.RegisterStatus = fms.ContractRegisterStatusComplete updateCols = append(updateCols, "RegisterStatus") } // 开票到款信息 invoiceOB := new(fms.ContractInvoice) invoiceCond := `contract_register_id = ?` invoicePars := make([]interface{}, 0) invoicePars = append(invoicePars, req.ContractRegisterId) invoiceList, e := invoiceOB.List(invoiceCond, invoicePars, "") if e != nil { resp.FailMsg("操作失败", "获取合同开票到款列表失败, Err: "+e.Error(), c) return } invoiceUpdateCols := make([]string, 0) // 开票到款操作类型: 0-无; 1-更新; 2-删除; logRemark := req.Remark invoiceHandleType := 0 if originHasPayment == 0 && req.HasPayment == 1 { // 若从无代付修改为有代付, 则删除无代付期间新增的所有开票到款登记 invoiceHandleType = 2 } else { // 修改了货币单位后,同步更新汇率及开票到款的换算金额 if req.CurrencyUnit != item.CurrencyUnit { rateList, e := fmsService.GetTodayCurrencyRateList() if e != nil { resp.FailMsg("操作失败", "获取货币列表及汇率失败, Err: "+e.Error(), c) return } var rate float64 for i := range rateList { if rateList[i].Code == req.CurrencyUnit { rate = rateList[i].RMBRate break } } if rate < 0 { resp.FailMsg("操作失败", "货币汇率有误", c) return } item.CurrencyUnit = req.CurrencyUnit item.RMBRate = rate updateCols = append(updateCols, "CurrencyUnit", "RMBRate") // 调整开票到款换算后的金额, 保留两位小数 for i := range invoiceList { invoiceList[i].CurrencyUnit = req.CurrencyUnit a, _ := strconv.ParseFloat(fmt.Sprintf("%.2f", invoiceList[i].OriginAmount/rate), 64) invoiceList[i].Amount = a } invoiceUpdateCols = append(invoiceUpdateCols, "CurrencyUnit", "Amount") invoiceHandleType = 1 logRemark = fmt.Sprintf("金额单位由%s修改为%s\n%s", item.CurrencyUnit, req.CurrencyUnit, logRemark) } } // 新增套餐金额详情内容 serviceAmountMap := make(map[int]float64) serviceAmountList, e := fmsService.HandleContractServiceAmount(req.ServiceAmount, serviceAmountMap, req.CurrencyUnit) if e != nil { resp.FailMsg("操作失败", "新增合同套餐金额信息失败, Err: "+e.Error(), c) return } //判断产品信息 productIds := make(map[int]struct{}) productIdsStr := "" for _, v := range serviceAmountList { productIds[v.ProductId] = struct{}{} } for proId, _ := range productIds { productIdsStr += strconv.Itoa(proId)+"," } productIdsStr = strings.Trim(productIdsStr, ",") item.ProductIds = productIdsStr // 套餐信息 serviceList, e := fmsService.HandleContractServiceAndDetail(req.Services, true, serviceAmountMap) if e != nil { resp.FailMsg("操作失败", "获取合同套餐详情失败, Err: "+e.Error(), c) return } // 更新合同登记、套餐、开票到款 if e = fms.UpdateContractRegister(item, updateCols, serviceList, invoiceList, invoiceUpdateCols, invoiceHandleType, serviceAmountList); e != nil { resp.FailMsg("操作失败", "更新合同及套餐失败, Err: "+e.Error(), c) return } // 自动分配套餐金额 go fmsService.CalculatePaymentServiceAmount(item.ContractRegisterId) // 校验金额-是否修改状态 go fmsService.CheckContractRegisterAmount(item.ContractRegisterId) // 操作日志 go func() { opData := "" opDataByte, e := json.Marshal(req) if e != nil { return } opData = string(opDataByte) logItem := new(fms.ContractRegisterLog) logItem.ContractRegisterId = item.ContractRegisterId logItem.AdminId = int(adminInfo.AdminId) logItem.AdminName = adminInfo.RealName logItem.OpData = opData logItem.OpType = fms.ContractRegisterOpTypeEdit logItem.CreateTime = nowTime logItem.Remark = logRemark if e = logItem.Create(); e != nil { return } }() resp.Ok("操作成功", c) } // Del // @Title 删除合同登记 // @Description 删除合同登记 // @Param request body fms.ContractRegisterDelReq true "type json string" // @Success 200 string "操作成功" // @router /contract/register/del [post] func (rg *RegisterController) Del(c *gin.Context) { req := new(fms.ContractRegisterDelReq) err := c.ShouldBind(&req) if err != nil { errs, ok := err.(validator.ValidationErrors) if !ok { resp.FailData("参数解析失败", "Err:"+err.Error(), c) return } resp.FailData("参数解析失败", errs.Translate(global.Trans), c) return } claims, _ := c.Get("adminInfo") adminInfo := claims.(*system.SysAdmin) ob := new(fms.ContractRegister) item, e := ob.Fetch(req.ContractRegisterId) if e != nil { if e == utils.ErrNoRow { resp.Fail("合同登记不存在或已被删除", c) return } resp.FailMsg("获取合同登记失败", "Err:"+e.Error(), c) return } nowTime := time.Now().Local() item.IsDeleted = 1 item.ModifyTime = nowTime updateCols := []string{"IsDeleted", "ModifyTime"} if e = item.Update(updateCols); e != nil { resp.FailMsg("操作失败", "更新合同登记失败, Err:"+e.Error(), c) return } // 删除对应的开票到款登记 go func() { if e = fms.DeleteContractInvoicesByRegisterId(item.ContractRegisterId); e != nil { alarm_msg.SendAlarmMsg(fmt.Sprintf("删除合同登记%d后, 删除开票到款记录失败, ErrMsg: %s", item.ContractRegisterId, e.Error()), 3) return } if e = fms.DeleteInvoicePaymentSummaryByRegisterId(item.ContractRegisterId); e != nil { alarm_msg.SendAlarmMsg(fmt.Sprintf("删除合同登记%d后, 删除开票到款汇总数据失败, ErrMsg: %s", item.ContractRegisterId, e.Error()), 3) return } }() // 操作日志 go func() { opData := "" opDataByte, e := json.Marshal(req) if e != nil { return } opData = string(opDataByte) logItem := new(fms.ContractRegisterLog) logItem.ContractRegisterId = req.ContractRegisterId logItem.AdminId = int(adminInfo.AdminId) logItem.AdminName = adminInfo.RealName logItem.OpData = opData logItem.OpType = fms.ContractRegisterOpTypeDel logItem.CreateTime = nowTime if e = logItem.Create(); e != nil { return } }() resp.Ok("操作成功", c) } // Detail // @Title 合同登记详情 // @Description 合同登记详情 // @Param ContractRegisterId query int false "合同登记ID" // @Success 200 {object} fms.ContractRegisterDetail // @router /contract/register/detail [get] func (rg *RegisterController) Detail(c *gin.Context) { var req fms.ContractRegisterDetailReq if e := c.BindQuery(&req); e != nil { err, ok := e.(validator.ValidationErrors) if !ok { resp.FailData("参数解析失败", "Err:"+e.Error(), c) return } resp.FailData("参数解析失败", err.Translate(global.Trans), c) return } result := new(fms.ContractRegisterDetail) // 合同登记信息 item, e := fms.GetContractRegisterItemById(req.ContractRegisterId) if e != nil { resp.FailData("获取失败", "获取合同登记详情失败, Err:"+e.Error(), c) return } result.ContractRegisterItem = item // 套餐信息 serviceAmountTempList, e := fms.GetContractServiceAmountByRegisterId(req.ContractRegisterId) if e != nil { resp.FailData("获取失败", "获取合同套餐信息失败, Err: "+e.Error(), c) return } serviceAmountList := make([]*fms.ContractServiceAmountItem, 0) for _, v := range serviceAmountTempList { tmp := &fms.ContractServiceAmountItem{ ContractRegisterId: v.ContractRegisterId, ProductId: v.ProductId, ServiceAmount: v.ServiceAmount, CurrencyUnit: v.CurrencyUnit, } serviceAmountList = append(serviceAmountList, tmp) } result.ServiceAmountList = serviceAmountList // 套餐金额信息 serviceList, e := fmsService.GetContractServiceAndDetail(req.ContractRegisterId) if e != nil { resp.FailData("获取失败", "获取合同套餐信息失败, Err: "+e.Error(), c) return } result.ServiceList = serviceList // 开票/到款信息 invoiceCond := `contract_register_id = ?` invoicePars := make([]interface{}, 0) invoicePars = append(invoicePars, req.ContractRegisterId) invoiceList, e := fms.GetContractInvoiceItemList(invoiceCond, invoicePars) if e != nil { resp.FailData("获取失败", "获取合同开票/到款信息失败, Err: "+e.Error(), c) return } result.InvoiceList = make([]*fms.ContractInvoiceItem, 0) result.PaymentList = make([]*fms.ContractInvoiceItem, 0) for i := range invoiceList { if invoiceList[i].InvoiceType == fms.ContractInvoiceTypeMake { result.InvoiceList = append(result.InvoiceList, invoiceList[i]) continue } if invoiceList[i].InvoiceType == fms.ContractInvoiceTypePay { result.PaymentList = append(result.PaymentList, invoiceList[i]) } } // 合同登记进度 logCond := `contract_register_id = ?` logPars := make([]interface{}, 0) logPars = append(logPars, req.ContractRegisterId) logList, e := fms.GetContractRegisterLogItemList(logCond, logPars) if e != nil { resp.FailData("获取失败", "获取合同登记进度失败, Err: "+e.Error(), c) return } result.Logs = logList resp.OkData("获取成功", result, c) } // UpdateStatus // @Title 修改合同状态 // @Description 修改合同状态 // @Param request body fms.ContractRegisterUpdateStatusReq true "type json string" // @Success 200 string "操作成功" // @router /contract/register/update_status [post] func (rg *RegisterController) UpdateStatus(c *gin.Context) { req := new(fms.ContractRegisterUpdateStatusReq) err := c.ShouldBind(&req) if err != nil { errs, ok := err.(validator.ValidationErrors) if !ok { resp.FailData("参数解析失败", "Err:"+err.Error(), c) return } resp.FailData("参数解析失败", errs.Translate(global.Trans), c) return } claims, _ := c.Get("adminInfo") adminInfo := claims.(*system.SysAdmin) ob := new(fms.ContractRegister) item, e := ob.Fetch(req.ContractRegisterId) if e != nil { if e == utils.ErrNoRow { resp.Fail("合同登记不存在或已被删除", c) return } resp.FailMsg("获取合同登记失败", "Err:"+e.Error(), c) return } nowTime := time.Now().Local() item.ContractStatus = req.ContractStatus item.ModifyTime = nowTime updateCols := []string{"ContractStatus", "ModifyTime"} if e = item.Update(updateCols); e != nil { resp.FailMsg("操作失败", "更新合同登记失败, Err:"+e.Error(), c) return } // 校验金额-是否修改状态 go fmsService.CheckContractRegisterAmount(req.ContractRegisterId) // 操作日志 go func() { opData := "" opDataByte, e := json.Marshal(req) if e != nil { return } opData = string(opDataByte) logItem := new(fms.ContractRegisterLog) logItem.ContractRegisterId = req.ContractRegisterId logItem.AdminId = int(adminInfo.AdminId) logItem.AdminName = adminInfo.RealName logItem.OpData = opData logItem.OpType = fms.ContractRegisterOpTypeStatus logItem.CreateTime = nowTime if e = logItem.Create(); e != nil { return } }() resp.Ok("操作成功", c) } // Invoice // @Title 开票/到款登记 // @Description 开票/到款登记 // @Param request body fms.ContractInvoiceSaveReq true "type json string" // @Success 200 string "操作成功" // @router /contract/register/invoice [post] func (rg *RegisterController) Invoice(c *gin.Context) { req := new(fms.ContractInvoiceSaveReq) err := c.ShouldBind(&req) if err != nil { errs, ok := err.(validator.ValidationErrors) if !ok { resp.FailData("参数解析失败", "Err:"+err.Error(), c) return } resp.FailData("参数解析失败", errs.Translate(global.Trans), c) return } claims, _ := c.Get("adminInfo") adminInfo := claims.(*system.SysAdmin) registerOB := new(fms.ContractRegister) item, e := registerOB.Fetch(req.ContractRegisterId) if e != nil { if e == utils.ErrNoRow { resp.Fail("合同登记不存在或已被删除", c) return } resp.FailMsg("获取合同登记失败", "Err:"+e.Error(), c) return } // 合同存在代付不允许开票/到款登记 if item.HasPayment == 1 { resp.Fail("合同存在代付不允许添加开票/到款登记", c) return } noChangeInvoiceIds := make([]int, 0) newInvoice := make([]*fms.ContractInvoice, 0) if len(req.AmountList) > 0 { // 合同有效时长(计算付款方式) dayDiff := item.EndDate.Sub(item.StartDate).Hours() / 24 // 获取销售分组信息 sellerList, e := crmService.GetSellerDepartmentListWithGroupAndTeam() if e != nil { resp.FailData("获取销售失败", "Err:"+e.Error(), c) return } sellerMap := make(map[int]*crm.SellerAdminWithGroupTeam) for i := range sellerList { sellerMap[sellerList[i].SellerId] = sellerList[i] } for i := range req.AmountList { if req.AmountList[i].Amount <= 0 { resp.Fail("登记金额有误", c) return } if req.AmountList[i].InvoiceDate == "" { resp.Fail("请选择日期", c) return } if req.AmountList[i].ServiceProductId != 1 && req.AmountList[i].ServiceProductId !=2 { resp.Fail("请选择套餐类型", c) return } // 开票登记销售必填 if req.InvoiceType == fms.ContractInvoiceTypeMake && req.AmountList[i].SellerId <= 0 { resp.Fail("请选择销售", c) return } t, e := time.ParseInLocation(utils.FormatDate, req.AmountList[i].InvoiceDate, time.Local) if e != nil { resp.FailData("日期格式有误", "Err:"+e.Error(), c) return } if req.AmountList[i].InvoiceId > 0 { noChangeInvoiceIds = append(noChangeInvoiceIds, req.AmountList[i].InvoiceId) continue } if req.AmountList[i].InvoiceId == 0 { v := &fms.ContractInvoice{ ContractRegisterId: req.ContractRegisterId, ContractCode: item.ContractCode, Amount: req.AmountList[i].Amount, OriginAmount: req.AmountList[i].OriginAmount, CurrencyUnit: item.CurrencyUnit, InvoiceType: req.InvoiceType, ServiceProductId: req.AmountList[i].ServiceProductId, InvoiceDate: t, AdminId: int(adminInfo.AdminId), AdminName: adminInfo.RealName, Remark: req.AmountList[i].Remark, } v.Set() // 开票登记-销售信息 if req.InvoiceType == fms.ContractInvoiceTypeMake { sellerItem := sellerMap[req.AmountList[i].SellerId] if sellerItem == nil { resp.Fail("销售信息异常", c) return } if req.AmountList[i].ServiceProductId == crm.CompanyProductFicc && sellerItem.DepartmentId != crm.SellerDepartmentId { resp.Fail("销售类型和所选套餐类型不一致", c) return } if req.AmountList[i].ServiceProductId == crm.CompanyProductRai && sellerItem.DepartmentId != crm.RaiSellerDepartmentId { resp.Fail("销售类型和所选套餐类型不一致", c) return } v.SellerId = sellerItem.SellerId v.SellerName = sellerItem.SellerName v.SellerGroupId = sellerItem.GroupId v.SellerGroupName = sellerItem.GroupName v.SellerTeamId = sellerItem.TeamId v.SellerTeamName = sellerItem.TeamName } // 到款登记-付款方式 if req.InvoiceType == fms.ContractInvoiceTypePay { v.PayType = fmsService.CalculateContractPaymentType(req.AmountList[i].Amount, item.ContractAmount, dayDiff) } newInvoice = append(newInvoice, v) } } } // 获取原有的登记信息 invoiceCond := `contract_register_id = ? AND invoice_type = ? ` invoicePars := make([]interface{}, 0) invoicePars = append(invoicePars, req.ContractRegisterId, req.InvoiceType) originInvoiceList, e := fms.GetContractInvoiceItemList(invoiceCond, invoicePars) if e != nil { resp.FailMsg("获取失败", "获取开票/到款列表失败, Err: "+e.Error(), c) return } // 比对原有和现有的登记信息 logList := make([]*fms.ContractRegisterLog, 0) opData := "" opDataByte, e := json.Marshal(req) if e != nil { return } opData = string(opDataByte) opType := fms.ContractRegisterOpTypeInvoice if req.InvoiceType == fms.ContractInvoiceTypePay { opType = fms.ContractRegisterOpTypePayment } nowTime := time.Now().Local() // 需要删除的记录 deleteInvoiceIds := make([]int, 0) for i := range originInvoiceList { if !utils.InArrayByInt(noChangeInvoiceIds, originInvoiceList[i].ContractInvoiceId) { deleteInvoiceIds = append(deleteInvoiceIds, originInvoiceList[i].ContractInvoiceId) logList = append(logList, &fms.ContractRegisterLog{ ContractRegisterId: req.ContractRegisterId, AdminId: int(adminInfo.AdminId), AdminName: adminInfo.RealName, OpData: opData, OpType: opType, CreateTime: nowTime, AmountRemark: fmt.Sprint("删除", fms.ContractInvoiceKeyNameMap[opType], "金额", originInvoiceList[i].Amount, "元"), }) } } // todo 判断是否符合均分金额的条件,如果符合,需要生成金额分配记录表 if req.InvoiceType == fms.ContractInvoiceTypePay { err = fmsService.CalculatePaymentServiceAmount(req.ContractRegisterId) if err != nil { resp.FailMsg("自动分配金额失败", "自动分配金额失败, Err: "+err.Error(), c) return } } // 新增的记录 if len(newInvoice) > 0 { newAmount := decimal.NewFromFloat(0).Round(2) for i := range newInvoice { a := decimal.NewFromFloat(newInvoice[i].Amount).Round(2) newAmount = newAmount.Add(a) } ia, _ := newAmount.Round(2).Float64() logList = append(logList, &fms.ContractRegisterLog{ ContractRegisterId: req.ContractRegisterId, AdminId: int(adminInfo.AdminId), AdminName: adminInfo.RealName, OpData: opData, OpType: opType, CreateTime: nowTime, AmountRemark: fmt.Sprint("新增", fms.ContractInvoiceKeyNameMap[opType], "金额", ia, "元"), }) } // 删除并新增登记 ob := new(fms.ContractInvoice) if e := ob.DeleteAndCreateNewInvoice(req.ContractRegisterId, req.InvoiceType, deleteInvoiceIds, newInvoice); e != nil { resp.FailData("日期格式有误", "Err:"+e.Error(), c) return } // 校验金额-是否修改状态 go fmsService.CheckContractRegisterAmount(req.ContractRegisterId) // 开票到款汇总 go fmsService.SummaryInvoicePaymentByContractRegisterId(req.ContractRegisterId) // 操作日志 go func() { logOB := new(fms.ContractRegisterLog) if e := logOB.AddInBatches(logList); e != nil { return } }() resp.Ok("操作成功", c) } // Export // @Title 合同登记-导出 // @Description 合同登记-导出 // @Param Keyword query string false "关键词" // @Param StartDate query string false "合同开始日期" // @Param EndDate query string false "合同结束日期" // @Param ServiceType query int false "套餐类型" // @Param ContractType query int false "合同类型" // @Param RegisterStatus query int false "登记状态" // @Success 200 string "操作成功" // @router /contract/register/export [get] func (rg *RegisterController) Export(c *gin.Context) { var req fms.ContractRegisterListReq if e := c.BindQuery(&req); e != nil { err, ok := e.(validator.ValidationErrors) if !ok { resp.FailData("参数解析失败", "Err:"+e.Error(), c) return } resp.FailData("参数解析失败", err.Translate(global.Trans), c) return } cond := `1 = 1` pars := make([]interface{}, 0) // 合同编号/客户姓名/销售/实际使用方 if req.Keyword != "" { kw := "%" + req.Keyword + "%" cond += ` AND (company_name LIKE ? OR contract_code LIKE ? OR seller_name LIKE ? OR actual_company_name LIKE ?)` pars = append(pars, kw, kw, kw, kw) } if req.StartDate != "" && req.EndDate != "" { st := fmt.Sprint(req.StartDate, " 00:00:00") ed := fmt.Sprint(req.EndDate, " 23:59:59") cond += ` AND (create_time BETWEEN ? AND ?)` pars = append(pars, st, ed) } if req.ContractType != 0 { cond += ` AND contract_type = ?` pars = append(pars, req.ContractType) } if req.RegisterStatus != 0 { cond += ` AND register_status = ?` pars = append(pars, req.RegisterStatus) } if req.ServiceTypes != "" { serviceTypes := strings.Split(req.ServiceTypes, ",") registerIds, e := fms.GetContractRegisterIdsByTempId(serviceTypes) if e != nil { resp.FailMsg("获取失败", "获取合同登记IDs失败, Err: "+e.Error(), c) return } if len(registerIds) > 0 { cond += ` AND contract_register_id IN ?` pars = append(pars, registerIds) } else { cond += ` AND 1 = 2` } } // 获取列表数据 cr := new(fms.ContractRegister) list, e := cr.List(cond, pars) if e != nil { resp.FailData("获取合同列表失败", "Err:"+e.Error(), c) return } if len(list) == 0 { resp.Fail("无有效数据可导出", c) return } registerIds := make([]int, 0) for i := range list { registerIds = append(registerIds, list[i].ContractRegisterId) } // 获取小套餐品种 cpCond := `product_id = ? AND permission_name <> ?` cpPars := make([]interface{}, 0) cpPars = append(cpPars, crm.CompanyProductFicc, crm.ChartPermissionStrategyName) cp := new(crm.ChartPermission) permissionList, e := cp.List(cpCond, cpPars) if e != nil { resp.FailData("获取小套餐品种失败", "Err:"+e.Error(), c) return } permissionLen := len(permissionList) permissionNameIdMap := make(map[string]int) for i := range permissionList { permissionNameIdMap[permissionList[i].PermissionName] = permissionList[i].ChartPermissionId } // 获取所有FICC套餐服务 serviceList, e := fms.GetContractServiceTemplateMapByProductId(crm.CompanyProductFicc) if e != nil { resp.FailData("获取套餐服务失败", "Err:"+e.Error(), c) return } // 除大小套餐外的其他套餐(下面的导出需要以此动态处理) otherService := make([]*fms.ContractServiceTemplateItem, 0) for i := range serviceList { if serviceList[i].Title != "FICC大套餐" && serviceList[i].Title != "FICC小套餐" { otherService = append(otherService, serviceList[i]) } } otherServiceLen := len(otherService) // 获取所有权益套餐服务 raiServiceList, e := fms.GetContractServiceTemplateAllByProductId(crm.CompanyProductRai) if e != nil { resp.FailData("获取权益套餐服务失败", "Err:"+e.Error(), c) return } raiServiceIdMap := make(map[int]*fms.ContractServiceTemplateItem) for i := range raiServiceList { raiServiceIdMap[raiServiceList[i].ServiceTemplateId] = raiServiceList[i] } // 除大小套餐外的其他套餐(下面的导出需要以此动态处理) raiOtherService := make([]*fms.ContractServiceTemplateItem, 0) raiServiceNotShowMap := make(map[int]struct{}) for _, v := range raiServiceList { if v.Pid > 0 && raiServiceIdMap[v.Pid].Pid > 0 { raiServiceNotShowMap[v.Pid] = struct{}{} raiServiceNotShowMap[raiServiceIdMap[v.Pid].Pid] = struct{}{} }else if v.Pid > 0 { raiServiceNotShowMap[v.Pid] = struct{}{} } } for _, v := range raiServiceList { if _, ok := raiServiceNotShowMap[v.ServiceTemplateId]; !ok { if v.Pid > 0 { v.ParentTitle = raiServiceIdMap[v.Pid].Title } raiOtherService = append(raiOtherService, v) } } otherServiceLen += len(raiOtherService) //套餐金额map serviceAmountMap := make(map[int]map[int]*fms.ContractServiceAmount) // 套餐/开票/到款列表 serviceMap := make(map[int][]*fms.ContractServiceWithParentTitle) serviceChartPermissionsMap := make(map[int][]int) invoiceMap := make(map[int][]*fms.ContractInvoice) paymentMap := make(map[int][]*fms.ContractInvoice) maxInvoice := 0 maxPayment := 0 if len(registerIds) > 0 { // 获取套餐信息 csCond := `cv.contract_register_id IN ?` csPars := make([]interface{}, 0) csPars = append(csPars, registerIds) cs := new(fms.ContractService) serviceList, e := cs.ListWithWithParentTitle(csCond, csPars) if e != nil { resp.FailData("获取合同套餐列表失败", "Err:"+e.Error(), c) return } for i := range serviceList { cid := serviceList[i].ContractRegisterId if serviceMap[cid] == nil { serviceMap[cid] = make([]*fms.ContractServiceWithParentTitle, 0) } serviceMap[cid] = append(serviceMap[cid], serviceList[i]) // 小套餐权限 if serviceChartPermissionsMap[cid] == nil { serviceChartPermissionsMap[cid] = make([]int, 0) } if serviceList[i].ChartPermissionIds != "" { ids := utils.JoinStr2IntArr(serviceList[i].ChartPermissionIds, ",") serviceChartPermissionsMap[cid] = append(serviceChartPermissionsMap[cid], ids...) } } // 获取合同的套餐金额信息 serviceAmountList, e := fms.GetContractServiceAmountByContractRegisterIds(registerIds) if e != nil { resp.FailData("获取合同的套餐金额信息失败", "Err:"+e.Error(), c) return } for _, v := range serviceAmountList { if _, ok := serviceAmountMap[v.ContractRegisterId]; !ok { serviceAmountMap[v.ContractRegisterId] = make(map[int]*fms.ContractServiceAmount) } serviceAmountMap[v.ContractRegisterId][v.ProductId] = v } // 获取开票/到款详情, 并取最大的开票/到款数(用于动态扩展第二列表头) ci := new(fms.ContractInvoice) csCond = `contract_register_id IN ?` csPars = make([]interface{}, 0) csPars = append(csPars, registerIds) invoiceList, e := ci.List(csCond, csPars, "") if e != nil { resp.FailData("获取开票/到款列表失败", "Err:"+e.Error(), c) return } for k := range invoiceList { cid := invoiceList[k].ContractRegisterId if invoiceMap[cid] == nil { invoiceMap[cid] = make([]*fms.ContractInvoice, 0) } if paymentMap[cid] == nil { paymentMap[cid] = make([]*fms.ContractInvoice, 0) } if invoiceList[k].InvoiceType == fms.ContractInvoiceTypeMake { invoiceMap[cid] = append(invoiceMap[cid], invoiceList[k]) continue } if invoiceList[k].InvoiceType == fms.ContractInvoiceTypePay { paymentMap[cid] = append(paymentMap[cid], invoiceList[k]) continue } } // 取最大开票/到款数 for j := range invoiceMap { if len(invoiceMap[j]) > maxInvoice { maxInvoice = len(invoiceMap[j]) } } for p := range paymentMap { if len(paymentMap[p]) > maxPayment { maxPayment = len(paymentMap[p]) } } } serviceProductIdMap := map[int]string{ 1:"FICC套餐", 2:"权益套餐", } // 生成Excel文件 xlsxFile := xlsx.NewFile() style := xlsx.NewStyle() alignment := xlsx.Alignment{ Horizontal: "center", Vertical: "center", WrapText: true, } style.Alignment = alignment style.ApplyAlignment = true sheetName := "财务列表" sheet, err := xlsxFile.AddSheet(sheetName) if err != nil { resp.FailData("新增Sheet失败", "Err:"+err.Error(), c) return } // 1行表头 hInt := 0 titleRow := sheet.AddRow() titleRow.SetHeight(40) // 1行1列-右合并两格, 下合并1行 cell1 := titleRow.AddCell() cell1.HMerge = 4 cell1.VMerge = 1 cell1.SetString("FICC客户签约表") cell1.SetStyle(style) // 右增两列空白格用于第一列合并, 否则后续单元格合并会有问题 titleRow.AddCell().SetString("") titleRow.AddCell().SetString("") titleRow.AddCell().SetString("") titleRow.AddCell().SetString("") hInt += 5 // 1行2列 cell2 := titleRow.AddCell() cell2.VMerge = 1 cell2.SetString("FICC大套餐") cell2.SetStyle(style) hInt ++ // 1行3列-右合并小套餐数 if permissionLen >= 1 { cell3 := titleRow.AddCell() hInt ++ cell3.HMerge = permissionLen - 1 cell3.VMerge = 1 cell3.SetString("FICC小套餐") cell3.SetStyle(style) // 同上右增单元格小套餐数-1的空白单元格用于合并 for i := 0; i < permissionLen-1; i++ { titleRow.AddCell().SetString("") hInt ++ } } for i := range otherService { cellOther := titleRow.AddCell() cellOther.VMerge = 1 hInt ++ cellOther.SetString(otherService[i].Title) cellOther.SetStyle(style) } //权益大套餐 cell4 := titleRow.AddCell() cell4.HMerge = 1 cell4.VMerge = 1 cell4.SetString("权益大套餐") cell4.SetStyle(style) titleRow.AddCell().SetString("") hInt +=2 //权益分行业套餐 cell5 := titleRow.AddCell() cell5.HMerge = 8 cell5.SetString("权益分行业套餐") cell5.SetStyle(style) titleRow.AddCell().SetString("") titleRow.AddCell().SetString("") titleRow.AddCell().SetString("") titleRow.AddCell().SetString("") titleRow.AddCell().SetString("") titleRow.AddCell().SetString("") titleRow.AddCell().SetString("") titleRow.AddCell().SetString("") //第二行,前面几个单元格用于第一行的合并 titleRow2 := sheet.AddRow() titleRow2.SetHeight(30) for i:= 0; i 0 { for isv := range svList { if svList[isv].Title == col4Name { col4 = "是" break } } } dataRow.AddCell().SetString(col4) // 小套餐 serviceChartPermissionIds := serviceChartPermissionsMap[v.ContractRegisterId] for i := 0; i < permissionLen; i++ { k += 1 colName := row3Title[k] chartPermissionId := permissionNameIdMap[colName] if utils.InArray(chartPermissionId, serviceChartPermissionIds) { dataRow.AddCell().SetString("是") } else { dataRow.AddCell().SetString("") } } // 除大小套餐外的其他套餐(处理方式其实跟上面的大套餐一样, 只是中间隔了小套餐按照顺序要这么处理=_=!) for i := 0; i < otherServiceLen; i++ { k += 1 otherColName := row3Title[k] otherCol := "" if svList != nil && len(svList) > 0 { for isv := range svList { if svList[isv].Title == otherColName { // 判断权益套餐权限时,需要同时判断父级name if otherColName == "主观" || otherColName == "客观" { if row3TitleParent[k] == svList[isv].ParentTitle { otherCol = "是" break } }else{ otherCol = "是" break } } } } dataRow.AddCell().SetString(otherCol) } // 其他信息 ficcAmount, _ := serviceAmountMap[v.ContractRegisterId][crm.CompanyProductFicc] raiAmount, _ := serviceAmountMap[v.ContractRegisterId][crm.CompanyProductRai] dataRow.AddCell().SetString(v.ServiceRemark) // 套餐备注 dataRow.AddCell().SetString(utils.TimeTransferString("2006/01/02", v.StartDate)) // 开始时间 dataRow.AddCell().SetString(utils.TimeTransferString("2006/01/02", v.EndDate)) // 到期时间 dataRow.AddCell().SetString(fmt.Sprint("¥", v.ContractAmount)) // 2022年合同金额 dataRow.AddCell().SetString(v.CurrencyUnit) // 货币单位 dataRow.AddCell().SetString(fmt.Sprint("¥", ficcAmount.ServiceAmount)) // FICC套餐总金额 dataRow.AddCell().SetString(fmt.Sprint("¥", raiAmount.ServiceAmount)) // 权益套餐总金额 dataRow.AddCell().SetString(v.AgreedPayTime) // 约定付款时间 dataRow.AddCell().SetString(utils.TimeTransferString("2006/01/02", v.SignDate)) // 签订日 dataRow.AddCell().SetString(fms.ContractStatusKeyNameMap[v.ContractStatus]) // 合同状态 dataRow.AddCell().SetString(v.ContractCode) // 合同编号 dataRow.AddCell().SetString(v.Remark) // 合规备注 // 开票/到款信息 ivList := invoiceMap[v.ContractRegisterId] ivListLen := len(ivList) for ia := 0; ia < maxInvoice; ia++ { if ia < ivListLen { if ivList != nil && ivList[ia] != nil { dataRow.AddCell().SetString(utils.TimeTransferString("2006/01/02", ivList[ia].InvoiceDate)) // 开票日 dataRow.AddCell().SetString(fmt.Sprint(ivList[ia].OriginAmount)) // 开票金额 dataRow.AddCell().SetString(serviceProductIdMap[ivList[ia].ServiceProductId]) // 套餐类型 dataRow.AddCell().SetString(ivList[ia].SellerName) // 销售名称 dataRow.AddCell().SetString(ivList[ia].Remark) // 开票备注 continue } } // 这里要把不够的填充为空 dataRow.AddCell().SetString("") dataRow.AddCell().SetString("") dataRow.AddCell().SetString("") dataRow.AddCell().SetString("") dataRow.AddCell().SetString("") } pyList := paymentMap[v.ContractRegisterId] pyListLen := len(pyList) for ib := 0; ib < maxPayment; ib++ { if ib < pyListLen { if pyList != nil && pyList[ib] != nil { dataRow.AddCell().SetString(utils.TimeTransferString("2006/01/02", pyList[ib].InvoiceDate)) // 收款日 dataRow.AddCell().SetString(fmt.Sprint(pyList[ib].OriginAmount)) // 收款金额 dataRow.AddCell().SetString(serviceProductIdMap[pyList[ib].ServiceProductId]) // 套餐类型 dataRow.AddCell().SetString(pyList[ib].Remark) // 收款备注 continue } } // 这里要把不够的填充为空 dataRow.AddCell().SetString("") dataRow.AddCell().SetString("") dataRow.AddCell().SetString("") dataRow.AddCell().SetString("") } } // 输出文件 var buffer bytes.Buffer _ = xlsxFile.Write(&buffer) content := bytes.NewReader(buffer.Bytes()) randStr := time.Now().Format(utils.FormatDateTimeUnSpace) fileName := sheetName + randStr + ".xlsx" c.Writer.Header().Add("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, fileName)) c.Writer.Header().Add("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") http.ServeContent(c.Writer, c.Request, fileName, time.Now(), content) } // InvoiceList // @Title 开票/到款列表 // @Description 开票/到款列表 // @Param InvoiceType query int false "类型: 1-开票登记; 2-到款登记" // @Param ContractCode query string false "合同编号" // @Param StartDate query string false "开始日期" // @Param EndDate query string false "结束日期" // @Param MinAmount query float64 false "开票金额区间-最小值" // @Param MaxAmount query float64 false "开票金额区间-最大值" // @Param IsExport query int false "是否导出: 0-否; 1-是" // @Success 200 {object} fms.ContractInvoiceItem // @router /contract/register/invoice_list [get] func (rg *RegisterController) InvoiceList(c *gin.Context) { var req fms.ContractInvoiceListReq if e := c.BindQuery(&req); e != nil { err, ok := e.(validator.ValidationErrors) if !ok { resp.FailData("参数解析失败", "Err:"+e.Error(), c) return } resp.FailData("参数解析失败", err.Translate(global.Trans), c) return } pageSize := req.PageSize pageIndex := req.Current if pageSize <= 0 { pageSize = utils.PageSize20 } if pageIndex <= 0 { pageIndex = 1 } cond := `invoice_type = ?` pars := make([]interface{}, 0) pars = append(pars, req.InvoiceType) // 合同编号 if req.ContractCode != "" { kw := fmt.Sprint("%", req.ContractCode, "%") pars = append(pars, kw) // 开票列表同时模糊查询销售名称 if req.InvoiceType == fms.ContractInvoiceTypeMake { cond += ` AND (contract_code LIKE ? )` pars = append(pars, kw) } else { cond += ` AND contract_code LIKE ?` pars = append(pars, kw) } } if req.StartDate != "" && req.EndDate != "" { st := fmt.Sprint(req.StartDate, " 00:00:00") ed := fmt.Sprint(req.EndDate, " 23:59:59") cond += ` AND (invoice_time BETWEEN ? AND ?)` pars = append(pars, st, ed) } if req.MinAmount > 0 { cond += ` AND amount >= ?` pars = append(pars, req.MinAmount) } if req.MaxAmount > 0 { cond += ` AND amount <= ?` pars = append(pars, req.MaxAmount) } // 套餐类型 if req.ServiceProductId > 0 { cond += ` AND service_product_id = ?` pars = append(pars, req.ServiceProductId) } // 销售 if req.SellerIds != "" { sellerIds := strings.Split(req.SellerIds, ",") cond += ` AND (seller_id in (?))` pars = append(pars, sellerIds) } // 货币列表 currencyOB := new(fms.CurrencyUnit) currencyCond := `enable = 1` currencyPars := make([]interface{}, 0) currencyList, e := currencyOB.List(currencyCond, currencyPars) if e != nil { resp.FailMsg("获取失败", "获取货币列表失败, Err: "+e.Error(), c) return } unitMap := make(map[string]string) currencyTotals := make([]*fms.InvoiceListCurrencyTotal, 0) for i := range currencyList { unitMap[currencyList[i].Code] = currencyList[i].UnitName currencyTotals = append(currencyTotals, &fms.InvoiceListCurrencyTotal{ Name: currencyList[i].Name, UnitName: currencyList[i].UnitName, Code: currencyList[i].Code, FlagImg: currencyList[i].FlagImg, }) } page := new(base.Page) page.SetPageSize(pageSize) page.SetCurrent(pageIndex) page.AddOrderItem(base.OrderItem{Column: "invoice_time", Asc: false}) if req.IsExport == 1 { page.SetPageSize(10000) page.SetCurrent(1) } total, list, e := fms.GetContractInvoiceItemPageList(page, cond, pars) if e != nil { resp.FailMsg("获取失败", "获取合同开票/到款列表失败, Err: "+e.Error(), c) return } page.SetTotal(total) contractRegisterIds := make([]int, 0) contractStatusMap := make(map[int]int) for i := range list { list[i].UnitName = unitMap[list[i].CurrencyUnit] contractRegisterIds = append(contractRegisterIds, list[i].ContractRegisterId) } if len(contractRegisterIds) > 0 { contractRegisters, err := fms.GetContractInfoByRegisterIds(contractRegisterIds) if err != nil { resp.FailMsg("查询合同信息失败", "查询合同信息失败, Err: "+err.Error(), c) return } for _, v := range contractRegisters { contractStatusMap[v.ContractRegisterId] = v.ContractStatus } } for i := range list { list[i].ContractStatus = contractStatusMap[list[i].ContractRegisterId] } // 分币种合计金额 var amountTotal float64 sumList, e := fms.GetInvoiceListCurrencySum(cond, pars, "currency_unit") if e != nil { resp.FailMsg("获取失败", "获取开票/到款列表合计金额失败, Err: "+e.Error(), c) return } sumMap := make(map[string]float64) for i := range sumList { amountTotal += sumList[i].AmountTotal sumMap[sumList[i].CurrencyUnit] = sumList[i].OriginAmountTotal } amountTotal, _ = strconv.ParseFloat(fmt.Sprintf("%.2f", amountTotal), 64) for i := range currencyTotals { a, _ := strconv.ParseFloat(fmt.Sprintf("%.2f", sumMap[currencyTotals[i].Code]), 64) currencyTotals[i].Amount = a } respData := &fms.InvoiceListRespData{ Page: page, List: list, AmountTotal: amountTotal, CurrencyTotal: currencyTotals, } // 是否导出 if req.IsExport == 1 { ExportInvoiceList(c, req, respData) return } resp.OkData("获取成功", respData, c) } // ExportInvoiceList 导出开票/到款列表 func ExportInvoiceList(c *gin.Context, req fms.ContractInvoiceListReq, results *fms.InvoiceListRespData) { list := make([]*fms.ContractInvoiceItem, 0) if val, ok := results.List.([]*fms.ContractInvoiceItem); ok { list = val } else { resp.Fail("列表数据有误", c) return } if len(list) == 0 { resp.Fail("列表数据为空", c) return } listName := "开票" if req.InvoiceType == fms.ContractInvoiceTypePay { listName = "到款" } // 生成Excel文件 xlsxFile := xlsx.NewFile() style := xlsx.NewStyle() alignment := xlsx.Alignment{ Horizontal: "center", Vertical: "center", WrapText: true, } style.Alignment = alignment style.ApplyAlignment = true sheet, err := xlsxFile.AddSheet(fmt.Sprintf("%s列表", listName)) if err != nil { resp.FailData("新增Sheet失败", "Err:"+err.Error(), c) return } // 前两行显示合计金额, 第三行空出与列表数据隔一行 rowA := sheet.AddRow() cellAA := rowA.AddCell() cellAA.SetString(fmt.Sprintf("已开票合计金额(换算后):%.2f(元)", results.AmountTotal)) rowBData := "已开票金额:" for _, v := range results.CurrencyTotal { rowBData += fmt.Sprintf("%s%.2f(%s) ", v.Name, v.Amount, v.UnitName) } rowB := sheet.AddRow() rowB.AddCell().SetString(rowBData) sheet.AddRow() // 列表数据表头 titles := []string{"合同编号", "套餐类型", fmt.Sprintf("%s金额", listName), "金额单位", "换算金额(元)", fmt.Sprintf("%s日期", listName), "销售", "备注"} titleRow := sheet.AddRow() titleRow.SetHeight(40) for i := range titles { c := titleRow.AddCell() c.SetString(titles[i]) c.SetStyle(style) } ServiceTemplateStrMap := map[int]string{ crm.CompanyProductFicc: "FICC套餐", crm.CompanyProductRai: "权益套餐", } // 单元格赋值 for _, v := range list { dataRow := sheet.AddRow() dataRow.SetHeight(20) dataRow.AddCell().SetString(v.ContractCode) // 合同编号 dataRow.AddCell().SetString(ServiceTemplateStrMap[v.ServiceProductId]) // 套餐类型 dataRow.AddCell().SetString(fmt.Sprint(v.OriginAmount)) // 开票金额 dataRow.AddCell().SetString(v.UnitName) // 金额单位 dataRow.AddCell().SetString(fmt.Sprint(v.Amount)) // 换算金额(元) dataRow.AddCell().SetString(v.InvoiceDate) // 开票日 dataRow.AddCell().SetString(v.SellerName) // 销售 dataRow.AddCell().SetString(v.Remark) // 备注 } // 输出文件 var buffer bytes.Buffer _ = xlsxFile.Write(&buffer) content := bytes.NewReader(buffer.Bytes()) randStr := time.Now().Format(utils.FormatDateTimeUnSpace) fileName := fmt.Sprintf("%s列表_%s.xlsx", listName, randStr) c.Writer.Header().Add("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, fileName)) c.Writer.Header().Add("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") http.ServeContent(c.Writer, c.Request, fileName, time.Now(), content) } // Import // @Title 合同登记-导入 // @Description 合同登记-导入 // @Success 200 string "操作成功" // @router /contract/register/import [post] func (rg *RegisterController) Import(c *gin.Context) { h, err := c.FormFile("File") if err != nil { resp.FailData("获取文件失败", "Err:"+err.Error(), c) return } ext := path.Ext(h.Filename) if ext != ".xlsx" && ext != ".xls" { resp.Fail("请上传Excel文件", c) return } uploadDir := "static/xls" err = os.MkdirAll(uploadDir, 766) if err != nil { resp.FailData("存储目录创建失败", "Err:"+err.Error(), c) return } uploadPath := uploadDir + "/" + time.Now().Format(utils.FormatDateTimeUnSpace) + h.Filename err = c.SaveUploadedFile(h, uploadPath) if err != nil { resp.FailData("保存本地文件失败", "Err:"+err.Error(), c) return } defer func() { _ = os.Remove(uploadPath) }() xlFile, err := xlsx.OpenFile(uploadPath) if err != nil { resp.FailData("打开文件失败", "Err:"+err.Error(), c) return } // 获取所有已登记,根据合同编号去重 contractCodeArr := make([]string, 0) registerOB := new(fms.ContractRegister) registerCond := `` registerPars := make([]interface{}, 0) registerList, e := registerOB.List(registerCond, registerPars) if e != nil { resp.FailData("获取合同登记列表失败", "Err:"+e.Error(), c) return } for i := range registerList { contractCodeArr = append(contractCodeArr, registerList[i].ContractCode) } // 获取所有销售Map sellerList, e := crmService.GetSellerDepartmentListWithGroupAndTeam() if e != nil { resp.FailData("获取销售列表失败", "Err:"+e.Error(), c) return } sellerMap := make(map[string]*crm.SellerAdminWithGroupTeam) for i := range sellerList { sellerMap[sellerList[i].SellerName] = sellerList[i] } // 获取品种权限Map chartPermissionNameIdMap := make(map[string]int) cpCond := `product_id = ?` cpPars := make([]interface{}, 0) cpPars = append(cpPars, crm.CompanyProductFicc) cp := new(crm.ChartPermission) permissionList, e := cp.List(cpCond, cpPars) if e != nil { resp.FailData("获取权限列表失败", "Err:"+e.Error(), c) return } for i := range permissionList { chartPermissionNameIdMap[permissionList[i].PermissionName] = permissionList[i].ChartPermissionId } // 获取所有套餐模板 serviceTempCond := `` serviceTempPars := make([]interface{}, 0) serviceTempOB := new(fms.ContractServiceTemplate) serviceTempList, e := serviceTempOB.List(serviceTempCond, serviceTempPars) if e != nil { resp.FailData("获取套餐模板列表失败", "Err:"+e.Error(), c) return } serviceTempNameMap := make(map[string]*fms.ContractServiceTemplate) serviceTempFullNameMap := make(map[string]*fms.ContractServiceTemplate) serviceTempIdMap := make(map[int]*fms.ContractServiceTemplate) for i := range serviceTempList { serviceTempIdMap[serviceTempList[i].ServiceTemplateId] = serviceTempList[i] serviceTempNameMap[serviceTempList[i].Title] = serviceTempList[i] } for i := range serviceTempList { fullName := serviceTempList[i].Title if serviceTempList[i].Pid > 0 { parentItem := serviceTempIdMap[serviceTempList[i].Pid] fullName += "_"+parentItem.Title if parentItem.Pid > 0 { fullName += "_"+serviceTempIdMap[parentItem.Pid].Title } } serviceTempFullNameMap[fullName] = serviceTempList[i] } //权益行业套餐名称 raiIndustryMap := map[int]string{ 36:"医药", 37:"医药", 38:"消费", 39:"消费", 40:"科技", 41:"科技", 42:"智造", 43:"智造", 44:"策略", } // 获取货币列表及汇率(汇率为导入日的汇率) rateList, e := fmsService.GetTodayCurrencyRateList() if e != nil { resp.FailData("获取货币列表及汇率失败", "Err:"+e.Error(), c) return } rateMap := make(map[string]float64) for i := range rateList { rateMap[rateList[i].Code] = rateList[i].RMBRate } titleMap := make(map[int]string) newIds := make([]int, 0) newCompanyArr := []string{"0", "1"} newCompanyMap := map[string]int{"0": 1, "1": 0} contractTypeArr := []string{"0", "1", "2", "3"} contractTypeMap := map[string]int{ "0": fms.ContractTypeRenew, "1": fms.ContractTypeNew, "2": fms.ContractTypeAgentPay, "3": fms.ContractTypePlus, } // 更新登记状态 defer func() { if len(newIds) > 0 { go func() { for i := range newIds { fmsService.CheckContractRegisterAmount(newIds[i]) fmsService.SummaryInvoicePaymentByContractRegisterId(newIds[i]) } }() } }() invoiceMax := 3 checkDate := time.Date(1900, 1, 1, 0, 0, 0, 0, time.Local) for _, sheet := range xlFile.Sheets { // 遍历行读取 maxRow := sheet.MaxRow for i := 0; i < maxRow; i++ { // 第三行开始读取表头 if i == 2 { row := sheet.Row(i) cells := row.Cells for k, cell := range cells { text := cell.String() titleMap[k] = text // 只检验前面部分表头, 后面很多动态列 if k == 0 { if text != "客户名称" { resp.Fail("【客户名称】列名称有误, 请参考模板导入", c) return } continue } else if k == 1 { if !strings.Contains(text, "新客户") { resp.Fail("【新客户】列名称有误, 请参考模板导入", c) return } continue } else if k == 2 { if !strings.Contains(text, "合同类型") { resp.Fail("【合同类型】列名称有误, 请参考模板导入", c) return } continue } else if k == 3 { if text != "FICC销售" { resp.Fail("【FICC销售】列名称有误, 请参考模板导入", c) return } continue } else if k == 4 { if text != "权益销售" { resp.Fail("【权益销售】列名称有误, 请参考模板导入", c) return } continue } else if k == 5 { if text != "FICC大套餐" { resp.Fail("【FICC大套餐】列名称有误, 请参考模板导入", c) return } continue } } }else if i >= 3 { // 数据行 row := sheet.Row(i) cells := row.Cells // 登记信息 rowRegister := new(fms.ContractRegister) // 套餐 rowServices := make([]*fms.ContractService, 0) // 套餐金额 rowServiceAmount := make([]*fms.ContractServiceAmount, 0) // 开票/到款 rowInvoices := make([]*fms.ContractInvoice, 0) for ir := 0; ir < invoiceMax; ir++ { rowInvoices = append(rowInvoices, new(fms.ContractInvoice)) } rowPayments := make([]*fms.ContractInvoice, 0) for ir := 0; ir < invoiceMax; ir++ { rowPayments = append(rowPayments, new(fms.ContractInvoice)) } // 小套餐权限 rowChartPermissionIdArr := make([]string, 0) productIds := make(map[int]struct{}) isSkip := false for k, cell := range cells { v := utils.TrimStr(cell.String()) // 客户名称 if k == 0 { if v == "" { resp.Fail(fmt.Sprintf("第%d行客户名称不可为空, 请按模板导入", i+1), c) return } rowRegister.CompanyName = v continue } // 是否新客户 if k == 1 { if !utils.InArrayByStr(newCompanyArr, v) { resp.Fail(fmt.Sprintf("第%d行新客户有误, 请按模板导入", i+1), c) return } rowRegister.NewCompany = newCompanyMap[v] continue } // 合同类型 if k == 2 { if !utils.InArrayByStr(contractTypeArr, v) { resp.Fail(fmt.Sprintf("第%d行合同类型有误, 请按模板导入", i+1), c) return } rowRegister.ContractType = contractTypeMap[v] if rowRegister.ContractType == 0 { resp.Fail(fmt.Sprintf("第%d行合同类型匹配有误, 请按模板导入", i+1), c) return } continue } // FICC销售 if k == 3 { if v != "" { /*resp.Fail(fmt.Sprintf("第%d行销售名称不可为空, 请按模板导入", i+1), c) return*/ sellerItem := sellerMap[v] if sellerItem == nil { resp.Fail(fmt.Sprintf("第%d行销售名称与系统销售不匹配, 请核对名称后导入", i+1), c) return } rowRegister.SellerId = sellerItem.SellerId rowRegister.SellerName = sellerItem.SellerName } continue } // 权益销售 if k == 4 { if v == "" && rowRegister.SellerName == "" { resp.Fail(fmt.Sprintf("第FICC销售名称和权益销售名称不可都为空, 请按模板导入", i+1), c) return } sellerItem := sellerMap[v] if sellerItem == nil { resp.Fail(fmt.Sprintf("第%d行权益销售名称与系统销售不匹配, 请核对名称后导入", i+1), c) return } rowRegister.RaiSellerId = sellerItem.SellerId rowRegister.RaiSellerName = sellerItem.SellerName continue } // FICC大套餐 if k == 5 { if v == "是" { tempItem := serviceTempNameMap[titleMap[k]] if tempItem == nil { resp.Fail(fmt.Sprintf("第%d行套餐名称不匹配, 请按模板导入", i+1), c) return } cs := &fms.ContractService{ ProductId: crm.CompanyProductFicc, ServiceTemplateId: tempItem.ServiceTemplateId, Title: tempItem.Title, Value: tempItem.Value, TableValue: tempItem.TableValue, ChartPermissionId: tempItem.ChartPermissionId, } cs.Set() rowServices = append(rowServices, cs) productIds[crm.CompanyProductFicc] = struct{}{} } continue } // FICC小套餐 if k >= 6 && k <= 26 { // 小套餐权限 if v == "是" { rowChartPermissionIdArr = append(rowChartPermissionIdArr, strconv.Itoa(chartPermissionNameIdMap[titleMap[k]])) productIds[crm.CompanyProductFicc] = struct{}{} } continue } // 其他类型套餐 if k >= 27 && k <= 33 { if v == "是" { tempItem := serviceTempNameMap[titleMap[k]] if tempItem == nil { resp.Fail(fmt.Sprintf("第%d行套餐名称不匹配, 请按模板导入", i+1), c) return } cs := &fms.ContractService{ ProductId: crm.CompanyProductFicc, ServiceTemplateId: tempItem.ServiceTemplateId, Title: tempItem.Title, Value: tempItem.Value, TableValue: tempItem.TableValue, ChartPermissionId: tempItem.ChartPermissionId, } cs.Set() rowServices = append(rowServices, cs) productIds[crm.CompanyProductFicc] = struct{}{} } continue } if k >=34 && k<=44 { if v == "是" { // 权益大套餐 if k <= 35 { //新增 parentName := "权益大套餐" tempItem := serviceTempNameMap[titleMap[k]] if tempItem == nil { resp.Fail(fmt.Sprintf("第%d行套餐名称不匹配, 请按模板导入", i+1), c) return } cs := &fms.ContractService{ ProductId: crm.CompanyProductFicc, ServiceTemplateId: tempItem.ServiceTemplateId, Title: tempItem.Title, Value: tempItem.Value, TableValue: tempItem.TableValue, ChartPermissionId: tempItem.ChartPermissionId, } rowServices = append(rowServices, cs) tempItem = serviceTempNameMap[parentName] if tempItem == nil { resp.Fail(fmt.Sprintf("第%d行套餐名称不匹配, 请按模板导入", i+1), c) return } cs = &fms.ContractService{ ProductId: crm.CompanyProductRai, ServiceTemplateId: tempItem.ServiceTemplateId, Title: tempItem.Title, Value: tempItem.Value, TableValue: tempItem.TableValue, ChartPermissionId: tempItem.ChartPermissionId, } rowServices = append(rowServices, cs) } else { rootName := "行业套餐" // 新增三条套餐信息 parentName, _ := raiIndustryMap[k] childName := titleMap[k] fullName := childName+"_"+parentName+"_"+rootName if fullName != "" { //增加三级权限 tempItem := serviceTempFullNameMap[fullName] if tempItem == nil { resp.Fail(fmt.Sprintf("第%d行套餐名称不匹配, 请按模板导入", i+1), c) return } cs := &fms.ContractService{ ProductId: crm.CompanyProductRai, ServiceTemplateId: tempItem.ServiceTemplateId, Title: tempItem.Title, Value: tempItem.Value, TableValue: tempItem.TableValue, ChartPermissionId: tempItem.ChartPermissionId, } rowServices = append(rowServices, cs) //增加二级权限 tempItem = serviceTempFullNameMap[parentName+"_"+rootName] if tempItem == nil { resp.Fail(fmt.Sprintf("第%d行套餐名称不匹配, 请按模板导入", i+1), c) return } cs = &fms.ContractService{ ProductId: crm.CompanyProductRai, ServiceTemplateId: tempItem.ServiceTemplateId, Title: tempItem.Title, Value: tempItem.Value, TableValue: tempItem.TableValue, ChartPermissionId: tempItem.ChartPermissionId, } rowServices = append(rowServices, cs) //增加一级权限 tempItem = serviceTempFullNameMap[rootName] if tempItem == nil { resp.Fail(fmt.Sprintf("第%d行套餐名称不匹配, 请按模板导入", i+1), c) return } cs = &fms.ContractService{ ProductId: crm.CompanyProductRai, ServiceTemplateId: tempItem.ServiceTemplateId, Title: tempItem.Title, Value: tempItem.Value, TableValue: tempItem.TableValue, ChartPermissionId: tempItem.ChartPermissionId, } rowServices = append(rowServices, cs) } } productIds[crm.CompanyProductRai] = struct{}{} } continue } // 权益研选等套餐 if k >= 45 && k<=49 { if v == "是" { tempItem := serviceTempNameMap[titleMap[k]] if tempItem == nil { resp.Fail(fmt.Sprintf("第%d行套餐名称不匹配, 请按模板导入", i+1), c) return } cs := &fms.ContractService{ ProductId: crm.CompanyProductRai, ServiceTemplateId: tempItem.ServiceTemplateId, Title: tempItem.Title, Value: tempItem.Value, TableValue: tempItem.TableValue, ChartPermissionId: tempItem.ChartPermissionId, } cs.Set() rowServices = append(rowServices, cs) productIds[crm.CompanyProductRai] = struct{}{} } continue } // 套餐备注 if k == 50 { rowRegister.ServiceRemark = v continue } // 开始时间/到期时间 if k == 51 { // 转换失败可能是因为格式为Excel日期格式, 读取出来会是一串数字, 将其转换成日期字符串再处理 va := cell.Value if va == "" { resp.Fail(fmt.Sprintf("第%d行开始时间不可为空, 请按模板导入", i+1), c) return } startDate, e := time.ParseInLocation("2006/01/02", va, time.Local) if e != nil { d := utils.ConvertToFormatDay(va, "2006/01/02") startDate, e = time.ParseInLocation("2006/01/02", d, time.Local) if e != nil { resp.Fail(fmt.Sprintf("第%d行开始时间格式转换有误, 请按模板导入", i+1), c) return } } // 转换后的日期小于1900-01-01表示当前生成的日期是有问题的 if startDate.Before(checkDate) { resp.Fail(fmt.Sprintf("第%d行开始时间格式有误, 请按模板导入", i+1), c) return } rowRegister.StartDate = startDate continue } if k == 52 { va := cell.Value if va == "" { resp.Fail(fmt.Sprintf("第%d行到期时间不可为空, 请按模板导入", i+1), c) return } endDate, e := time.ParseInLocation("2006/01/02", va, time.Local) if e != nil { d := utils.ConvertToFormatDay(va, "2006/01/02") endDate, e = time.ParseInLocation("2006/01/02", d, time.Local) if e != nil { resp.Fail(fmt.Sprintf("第%d行到期时间格式转换有误, 请按模板导入", i+1), c) return } } if endDate.Before(checkDate) { resp.Fail(fmt.Sprintf("第%d行到期时间格式有误, 请按模板导入", i+1), c) return } rowRegister.EndDate = endDate continue } // 合同金额 if k == 53 { amountStr := v amount, e := strconv.ParseFloat(amountStr, 64) if e != nil { resp.Fail(fmt.Sprintf("第%d行合同金额有误, 请按模板导入", i+1), c) return } rowRegister.ContractAmount = amount continue } // 金额单位 if k == 54 { rate := rateMap[v] if rate <= 0 { resp.Fail(fmt.Sprintf("第%d行金额单位有误, 请按模板导入", i+1), c) return } rowRegister.CurrencyUnit = v rowRegister.RMBRate = rate continue } // FICC 套餐总金额 if k == 55 { amountStr := v amount, e := strconv.ParseFloat(amountStr, 64) if e != nil { resp.Fail(fmt.Sprintf("第%d行FICC套餐总金额有误, 请按模板导入", i+1), c) return } if amount > 0 { tmp := &fms.ContractServiceAmount{ ProductId: crm.CompanyProductFicc, ServiceAmount: amount, CurrencyUnit: rowRegister.CurrencyUnit, TimeBase: base.TimeBase{}, } rowServiceAmount = append(rowServiceAmount, tmp) } continue } // 权益套餐总金额 if k == 56 { amountStr := v amount, e := strconv.ParseFloat(amountStr, 64) if e != nil { resp.Fail(fmt.Sprintf("第%d行权益套餐总金额有误, 请按模板导入", i+1), c) return } if amount > 0 { tmp := &fms.ContractServiceAmount{ ProductId: crm.CompanyProductRai, ServiceAmount: amount, CurrencyUnit: rowRegister.CurrencyUnit, TimeBase: base.TimeBase{}, } rowServiceAmount = append(rowServiceAmount, tmp) } continue } // 约定付款日期 if k == 57 { rowRegister.AgreedPayTime = v continue } // 签订日 if k == 58 { va := cell.Value if va == "" { continue } signDate, e := time.ParseInLocation("2006/01/02", va, time.Local) if e != nil { d := utils.ConvertToFormatDay(va, "2006/01/02") signDate, e = time.ParseInLocation("2006/01/02", d, time.Local) if e != nil { resp.Fail(fmt.Sprintf("第%d行签订日格式转换有误, 请按模板导入", i+1), c) return } } if signDate.Before(checkDate) { resp.Fail(fmt.Sprintf("第%d行签订日格式有误, 请按模板导入", i+1), c) return } rowRegister.SignDate = signDate continue } // 合同状态 if k == 59 { rowRegister.ContractStatus = fms.ContractStatusNameKeyMap[v] if rowRegister.ContractStatus == 0 { resp.Fail(fmt.Sprintf("第%d行合同状态不匹配, 请按模板导入", i+1), c) return } continue } // 合同编号 if k == 60 { rowContractCode := v if rowContractCode == "" { resp.Fail(fmt.Sprintf("第%d行合同编号不可为空, 请按模板导入", i+1), c) return } if utils.InArrayByStr(contractCodeArr, rowContractCode) { // 此合同已登记, 跳过本行的读取 isSkip = true break } rowRegister.ContractCode = rowContractCode continue } // 合规备注 if k == 61 { rowRegister.Remark = v continue } // 开票列表 k2 := 61 for ir := 0; ir < invoiceMax; ir++ { n := ir + 1 // 开票日 k2 += 1 if k == k2 { if v != "" { va := cell.Value invoiceDate, e := time.ParseInLocation("2006/01/02", va, time.Local) if e != nil { d := utils.ConvertToFormatDay(va, "2006/01/02") invoiceDate, e = time.ParseInLocation("2006/01/02", d, time.Local) if e != nil { resp.Fail(fmt.Sprintf("第%d行开票时间%d格式转换有误, 请按模板导入", i+1, n), c) return } } if invoiceDate.Before(checkDate) { resp.Fail(fmt.Sprintf("第%d行开票时间%d格式有误, 请按模板导入", i+1, n), c) return } rowInvoices[ir].InvoiceDate = invoiceDate rowInvoices[ir].ContractCode = rowRegister.ContractCode rowInvoices[ir].InvoiceType = fms.ContractInvoiceTypeMake } continue } // 开票金额 k2 += 1 if k == k2 { if v != "" { amountStr := v amount, e := strconv.ParseFloat(amountStr, 64) if e != nil { resp.Fail(fmt.Sprintf("第%d行开票金额%d有误, 请按模板导入", i+1, n), c) return } if rowRegister.RMBRate <= 0 { resp.Fail(fmt.Sprintf("第%d行开票金额换算%d有误, 请按模板导入金额单位", i+1, n), c) return } a, _ := strconv.ParseFloat(fmt.Sprintf("%.2f", amount/rowRegister.RMBRate), 64) rowInvoices[ir].OriginAmount = amount rowInvoices[ir].Amount = a } continue } // 开票套餐类型 k2 += 1 if k == k2 { if v != "" { if v == "FICC套餐" { rowInvoices[ir].ServiceProductId = crm.CompanyProductFicc }else if v == "权益套餐"{ rowInvoices[ir].ServiceProductId = crm.CompanyProductRai }else{ resp.Fail(fmt.Sprintf("第%d行开票套餐类型%d:%s有误, 请按模板导入", i+1, n, v), c) return } } continue } // 开票销售 k2 += 1 if k == k2 { if v != "" { sellerItem := sellerMap[v] if sellerItem == nil { resp.Fail(fmt.Sprintf("第%d行开票销售名称与系统销售不匹配, 请核对名称后导入", i+1), c) return } rowInvoices[ir].SellerId = sellerItem.SellerId rowInvoices[ir].SellerName = sellerItem.SellerName rowInvoices[ir].SellerGroupId = sellerItem.GroupId rowInvoices[ir].SellerGroupName = sellerItem.GroupName rowInvoices[ir].SellerTeamId = sellerItem.TeamId rowInvoices[ir].SellerTeamName = sellerItem.TeamName } continue } // 备注 k2 += 1 if k == k2 { if v != "" { rowInvoices[ir].Remark = v } continue } } // 到款列表 for ir := 0; ir < invoiceMax; ir++ { n := ir + 1 // 到款日 k2 += 1 if k == k2 { if v != "" { va := cell.Value invoiceDate, e := time.ParseInLocation("2006/01/02", va, time.Local) if e != nil { d := utils.ConvertToFormatDay(va, "2006/01/02") invoiceDate, e = time.ParseInLocation("2006/01/02", d, time.Local) if e != nil { resp.Fail(fmt.Sprintf("第%d行到款时间%d格式转换有误, 请按模板导入", i+1, n), c) return } } if invoiceDate.Before(checkDate) { resp.Fail(fmt.Sprintf("第%d行到款时间%d格式有误, 请按模板导入", i+1, n), c) return } rowPayments[ir].InvoiceDate = invoiceDate rowPayments[ir].ContractCode = rowRegister.ContractCode rowPayments[ir].InvoiceType = fms.ContractInvoiceTypePay } continue } // 到款金额 k2 += 1 if k == k2 { if v != "" { amountStr := v amount, e := strconv.ParseFloat(amountStr, 64) if e != nil { resp.Fail(fmt.Sprintf("第%d行到款金额%d有误, 请按模板导入", i+1, n), c) return } if rowRegister.RMBRate <= 0 { resp.Fail(fmt.Sprintf("第%d行到款金额换算%d有误, 请按模板导入金额单位", i+1, n), c) return } // 付款方式 dayDiff := rowRegister.EndDate.Sub(rowRegister.StartDate).Hours() / 24 contractAmount := rowRegister.ContractAmount payType := fmsService.CalculateContractPaymentType(amount, contractAmount, dayDiff) rowPayments[ir].PayType = payType rowPayments[ir].OriginAmount = amount a, _ := strconv.ParseFloat(fmt.Sprintf("%.2f", amount/rowRegister.RMBRate), 64) rowPayments[ir].Amount = a } continue } // 到款套餐类型 k2 += 1 if k == k2 { if v != "" { if v == "FICC套餐" { rowPayments[ir].ServiceProductId = crm.CompanyProductFicc }else if v == "权益套餐"{ rowPayments[ir].ServiceProductId = crm.CompanyProductRai }else{ resp.Fail(fmt.Sprintf("第%d行到款套餐类型%d:%s有误, 请按模板导入", i+1, n, v), c) return } } continue } // 备注 k2 += 1 if k == k2 { if v != "" { rowPayments[ir].Remark = v } continue } } } if isSkip { continue } // 小套餐 if len(rowChartPermissionIdArr) > 0 { // 说明有小套餐 tempItem := serviceTempNameMap["FICC小套餐"] if tempItem == nil { resp.Fail(fmt.Sprintf("第%d行小套餐名称不匹配, 请按模板导入", i+1), c) return } rowChartPermissionIds := strings.Join(rowChartPermissionIdArr, ",") cs := &fms.ContractService{ ProductId: crm.CompanyProductFicc, ServiceTemplateId: tempItem.ServiceTemplateId, Title: tempItem.Title, Value: tempItem.Value, TableValue: tempItem.TableValue, ChartPermissionId: tempItem.ChartPermissionId, ChartPermissionIds: rowChartPermissionIds, } cs.Set() rowServices = append(rowServices, cs) } // 如果导入的最后一条合同编号为空并且合同编号之后的字段均为空 // excel这个包读行的时候不会再往后面没数据的地方读取, 所以此处需要重新判断一次 if rowRegister.ContractCode == "" { resp.Fail(fmt.Sprintf("第%d行合同编号为空", i+1), c) return } rowRegister.RegisterStatus = fms.ContractRegisterStatusIng rowInvoiceList := make([]*fms.ContractInvoice, 0) // 过滤信息不完整的开票到款 for l := range rowInvoices { if rowInvoices[l].ContractCode != "" { if rowInvoices[l].OriginAmount <= 0 || rowInvoices[l].SellerId == 0 { resp.Fail(fmt.Sprintf("第%d行开票信息必填项不完整", i+1), c) return } rowInvoiceList = append(rowInvoiceList, rowInvoices[l]) } } for l := range rowPayments { if rowPayments[l].ContractCode != "" { if rowPayments[l].OriginAmount <= 0 { resp.Fail(fmt.Sprintf("第%d行到款信息必填项不完整", i+1), c) return } rowInvoiceList = append(rowInvoiceList, rowPayments[l]) } } // 新增登记、套餐、开票到款信息 for proId, _ := range productIds { rowRegister.ProductIds += strconv.Itoa(proId)+"," } rowRegister.ProductIds = strings.Trim(rowRegister.ProductIds, ",") newId, e := fms.CreateImportContractRegister(rowRegister, rowServices, rowInvoiceList, rowServiceAmount) if e != nil { resp.FailData(fmt.Sprintf("第%d行导入失败", i+1), "新增导入登记失败, Err: "+e.Error(), c) return } // 自动分配套餐金额 go fmsService.CalculatePaymentServiceAmount(newId) newIds = append(newIds, newId) } } } resp.Ok("操作成功", c) } // CurrencyList // @Title 货币单位列表 // @Description 货币单位列表 // @Success 200 {object} fms.CurrencyUnitItem // @router /contract/register/currency_list [get] func (rg *RegisterController) CurrencyList(c *gin.Context) { list, e := fmsService.GetTodayCurrencyRateList() if e != nil { resp.FailData("获取失败", "获取今日货币汇率列表失败, Err: "+e.Error(), c) return } resp.OkData("获取成功", list, c) } // CheckContractName // @Title 货币单位列表 // @Description 货币单位列表 // @Success 200 {object} fms.CheckContractNameResp // @router /contract/register/check_contract_code [get] func (rg *RegisterController) CheckContractName(c *gin.Context) { var req fms.CheckContractNameReq if e := c.BindQuery(&req); e != nil { err, ok := e.(validator.ValidationErrors) if !ok { resp.FailData("参数解析失败", "Err:"+e.Error(), c) return } resp.FailData("参数解析失败", err.Translate(global.Trans), c) return } existCond :="" existPars := make([]interface{}, 0) if req.CompanyName != "" { // 是否存在相同的合同名称的登记 existCond = ` company_name = ?` existPars = append(existPars, req.CompanyName) } if req.StartDate != "" && req.EndDate != "" { // 日期校验 startDate, e := time.ParseInLocation(utils.FormatDate, req.StartDate, time.Local) if e != nil { resp.FailMsg("合同开始日期格式有误", "合同开始日期格式有误, Err: "+e.Error(), c) return } endDate, e := time.ParseInLocation(utils.FormatDate, req.EndDate, time.Local) if e != nil { resp.FailMsg("合同结束日期格式有误", "合同结束日期格式有误, Err: "+e.Error(), c) return } if existCond != "" { existCond += ` or (start_date =? and end_date=?)` }else{ existCond = ` start_date = ? and end_date=?` } existPars = append(existPars, startDate, endDate) } if existCond == "" { resp.Fail("请输入合同名称或者合同有效期", c) return } // 是否存在相同合同名称的登记 ob := new(fms.ContractRegister) data := fms.CheckContractNameResp{ Exist: 0, } _, e := ob.FetchByCondition(existCond, existPars) if e != nil { if e == utils.ErrNoRow { resp.OkData("查询成功", data, c) return } resp.FailMsg("查询失败", "查询相同登记号失败, Err: "+e.Error(), c) return } data.Exist = 1 resp.OkData("查询成功", data, c) return }