Browse Source

Merge branch 'master' into dev/2.2_daokuan

# Conflicts:
#	models/fms/contract_register.go
xiexiaoyuan 2 years ago
parent
commit
f2b38902fe

+ 325 - 0
controller/contract/pre_payment.go

@@ -0,0 +1,325 @@
+package contract
+
+import (
+	"fmt"
+	"github.com/gin-gonic/gin"
+	"github.com/go-playground/validator/v10"
+	"hongze/fms_api/controller/resp"
+	"hongze/fms_api/global"
+	"hongze/fms_api/models/base"
+	"hongze/fms_api/models/fms"
+	"hongze/fms_api/models/system"
+	fmsService "hongze/fms_api/services/fms"
+	"hongze/fms_api/utils"
+	"time"
+)
+
+// // RegisterController 合同登记
+type PrePaymentController struct{}
+
+// List
+// @Title 到款预登记列表
+// @Description 到款预登记列表
+// @Param   Keyword			query	string	false	"关键词"
+// @Param   StartDate		query	string	false	"约定开始时间"
+// @Param   EndDate			query	string	false	"约定结束时间"
+// @Param   SortType   		query   string  true       "如何排序,是正序还是倒序,枚举值:`asc 正序`,`desc 倒叙`"
+// @Success 200 {object} fms.ContractRegisterItem
+// @router /contract/pre_pay/list [get]
+func (rg *PrePaymentController) List(c *gin.Context) {
+	var req fms.PrePayListReq
+	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 seller_name LIKE ? )`
+		pars = append(pars, 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)
+	}
+
+	// 货币列表
+	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)
+	for i := range currencyList {
+		unitMap[currencyList[i].Code] = currencyList[i].UnitName
+	}
+
+	page := new(base.Page)
+	page.SetPageSize(req.PageSize)
+	page.SetCurrent(req.Current)
+	sortTypeMap := map[int]bool{0: false, 1: true, 2: false}
+	page.AddOrderItem(base.OrderItem{Column: "create_time", Asc: sortTypeMap[req.SortType]})
+
+	total, list, e := fms.GetPrePayItemPageList(page, cond, pars)
+	if e != nil {
+		resp.FailMsg("获取失败", "获取预登记列表失败, Err: "+e.Error(), c)
+		return
+	}
+	for i := range list {
+		list[i].UnitName = unitMap[list[i].CurrencyUnit]
+	}
+
+	page.SetTotal(total)
+	baseData := new(base.BaseData)
+	baseData.SetPage(page)
+	baseData.SetList(list)
+	resp.OkData("获取成功", baseData, c)
+}
+
+// Add
+// @Title 新增到款预登记
+// @Description 新增到款预登记
+// @Param	request  body  fms.PrepayAddReq  true  "type json string"
+// @Success 200 string "操作成功"
+// @router /contract/pre_pay/add [post]
+func (rg *PrePaymentController) Add(c *gin.Context) {
+	req := new(fms.PrepayAddReq)
+	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
+	}
+
+	// 货币及汇率
+	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
+	}
+
+	ob := new(fms.ContractPrePayment)
+	ob.CompanyName = req.CompanyName
+	ob.SellerId = req.SellerId
+	ob.SellerName = req.SellerName
+	ob.CurrencyUnit = req.CurrencyUnit
+	ob.StartDate = startDate
+	ob.EndDate = endDate
+	ob.AdminId = int(adminInfo.AdminId)
+	ob.AdminName = adminInfo.AdminName
+	ob.Amount = req.Amount / rate
+	ob.OriginAmount = req.Amount
+	ob.CurrencyUnit = req.CurrencyUnit
+	ob.Remark = req.Remark
+	ob.NewCompany = req.NewCompany
+	ob.Set()
+
+
+	// 新增合同及套餐
+	if e = ob.Create(); e != nil {
+		resp.FailMsg("操作失败", "新增合同及套餐失败, Err: "+e.Error(), c)
+		return
+	}
+	//// 开票到款汇总
+	//nowTime := time.Now().Local()
+	//v := new(fms.InvoicePaymentSummary)
+	//v.CreateTime = nowTime
+	//v.ModifyTime = nowTime
+	//v.PrePayid = ob.PrePayId
+	//
+	//if e = v.Create(); e != nil {
+	//	err = fmt.Errorf("新增汇总数据失败, Err: %s", e.Error())
+	//}
+
+	resp.Ok("操作成功", c)
+}
+
+// Edit
+// @Title 编辑到款预登记
+// @Description 编辑到款预登记
+// @Param	request  body  fms.ContractRegisterEditReq  true  "type json string"
+// @Success 200 string "操作成功"
+// @router /contract/pre_pay/edit [post]
+func (rg *PrePaymentController) Edit(c *gin.Context) {
+	req := new(fms.PrepayEditReq)
+	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
+	}
+
+	// 货币及汇率
+	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
+	}
+
+	ob := new(fms.ContractPrePayment)
+
+	item, e := ob.Fetch(req.PrePayId)
+	if e != nil {
+		if e == utils.ErrNoRow {
+			resp.Fail("预到款登记记录不存在或已被删除", c)
+			return
+		}
+		resp.FailMsg("操作失败", "获取预到款登记信息失败, Err:"+e.Error(), c)
+		return
+	}
+	item.CompanyName = req.CompanyName
+	item.SellerId = req.SellerId
+	item.SellerName = req.SellerName
+	item.CurrencyUnit = req.CurrencyUnit
+	item.StartDate = startDate
+	item.EndDate = endDate
+	item.AdminId = int(adminInfo.AdminId)
+	item.AdminName = adminInfo.AdminName
+	item.Amount = req.Amount / rate
+	item.OriginAmount = req.Amount
+	item.CurrencyUnit = req.CurrencyUnit
+	item.Remark = req.Remark
+	item.NewCompany = req.NewCompany
+	item.ModifyTime = time.Now().Local()
+
+	updateCols := []string{
+		"ContractCode", "CompanyName", "SellerId", "SellerName", "Amount", "StartDate", "EndDate",
+		"Remark", "ModifyTime","NewCompany", "OriginAmount", "CurrencyUnit",
+	}
+	if e = item.Update(updateCols); e != nil {
+		resp.FailMsg("操作失败", "更新到预款登记失败, Err:"+e.Error(), c)
+		return
+	}
+
+	resp.Ok("操作成功", c)
+}
+
+// Del
+// @Title 删除到款预登记
+// @Description 删除到款预登记
+// @Param	request  body  fms.ContractRegisterDelReq  true  "type json string"
+// @Success 200 string "操作成功"
+// @router /contract/pre_pay/del [post]
+func (rg *PrePaymentController) Del(c *gin.Context) {
+	req := new(fms.PrepayDelReq)
+	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
+	}
+
+	ob := new(fms.ContractPrePayment)
+	item, e := ob.Fetch(req.PrePayId)
+	if e != nil {
+		if e == utils.ErrNoRow {
+			resp.Fail("合同登记不存在或已被删除", c)
+			return
+		}
+		resp.FailMsg("获取合同登记失败", "Err:"+e.Error(), c)
+		return
+	}
+	e = item.Delete()
+	if 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 = 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)
+}

+ 106 - 3
controller/contract/register.go

@@ -273,9 +273,112 @@ func (rg *RegisterController) Add(c *gin.Context) {
 	}
 
 	// 新增合同及套餐
-	if e = fms.CreateContractRegisterAndServices(ob, serviceList); 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); e != nil {
+			resp.FailMsg("操作失败", "新增合同及套餐失败, Err: "+e.Error(), c)
+			return
+		}
 	}
 
 	// 操作日志

+ 107 - 0
controller/statistic.go

@@ -0,0 +1,107 @@
+package controller
+
+import (
+	"context"
+	"encoding/json"
+	"fmt"
+	"github.com/gin-gonic/gin"
+	"hongze/fms_api/controller/resp"
+	"hongze/fms_api/global"
+	"hongze/fms_api/models"
+	"hongze/fms_api/services/alarm_msg"
+	"hongze/fms_api/utils"
+	"time"
+)
+
+// // StatisticController 统计报告
+type StatisticController struct{}
+
+
+// Home
+// @Title 获取首页工作台数据
+// @Description 获取首页工作台数据接口
+// @Success 200 {object} response.WorktopResp
+// @router /statistic [get]
+func (this *StatisticController) Statistic(c *gin.Context) {
+
+	//近6收入统计
+	var incomeList models.IncomeChartResp
+	ch := make(chan models.IncomeChartResp, 1)
+	go getIncomeList(ch)
+
+	for v := range ch {
+		incomeList = v
+		close(ch)
+	}
+
+	resp.OkData("获取成功", incomeList, c)
+}
+
+//获取收入统计
+func getIncomeList(ch chan models.IncomeChartResp) (incomeChart models.IncomeChartResp, err error) {
+	defer func() {
+		if err != nil {
+			go alarm_msg.SendAlarmMsg("获取近两年的收入统计数据异常,Err:"+err.Error(), 3)
+			//go utils.SendEmail(utils.APPNAME+"获取近12个月的收入统计数据异常:"+time.Now().Format("2006-01-02 15:04:05"), err.Error(), utils.EmailSendToUsers)
+		}
+		ch <- incomeChart
+	}()
+	todayStr := utils.GetToday("20060102")
+	key := "admin:home:fmsIncomeList:" + todayStr
+
+	redisJsonData, redisErr := global.Redis.Get(context.TODO(), key).Result()
+	if redisErr != nil {
+		var dateSlice []string
+		var contractMoneySlice []float64
+		var ArrivalMoneySlice []float64
+
+		yearNum := time.Now().Year() - time.Now().AddDate(-2, 0, 0).Year()
+		monthNum := time.Now().Month() - 1
+		numMonth := yearNum*12 + int(monthNum) //距离2021-01存在多少个月
+
+		for i := numMonth; i >= 0; i-- {
+			timeNow, _ := time.Parse("2006-01", time.Now().Format("2006-01"))
+			dateSlice = append(dateSlice, timeNow.AddDate(0, -i, 0).Format("06/01"))
+			//开始日期
+			startDate := timeNow.AddDate(0, -i, 0).Format("2006-01")
+			startDate = fmt.Sprint(startDate, "-01")
+
+			//结束日期
+			endDateTime := timeNow.AddDate(0, -i+1, 0)
+			endDate := endDateTime.Format("2006-01")
+
+			//因为就算是当月的后续事件还没到,也要计入数据统计,所以不做限制到当天处理
+			//if endDateTime.After(time.Now()) {
+			//	endDate = time.Now().AddDate(0, 0, 1).Format(utils.FormatDate)
+			//} else {
+			//	endDate = fmt.Sprint(endDate, "-01")
+			//}
+			endDate = fmt.Sprint(endDate, "-01")
+			cond := ` AND create_time >= '`+startDate +`' AND create_time < '`+endDate +`' `
+
+			item, countErr := models.GetIncomeListCount(cond)
+			if countErr != nil && countErr != utils.ErrNoRow {
+				err = countErr
+				return
+			}
+			contractMoneySlice = append(contractMoneySlice, item.ContractMoney)
+			ArrivalMoneySlice = append(ArrivalMoneySlice, item.ArrivalMoney)
+		}
+		incomeChart.Title = "开票到款统计图"
+		incomeChart.Date = dateSlice
+		incomeChart.ContractMoney = contractMoneySlice
+		incomeChart.ArrivalMoney = ArrivalMoneySlice
+
+		redisJsonData, err := json.Marshal(incomeChart)
+		if err == nil {
+			global.Redis.SetEX(context.TODO(), key, string(redisJsonData), time.Minute*30)
+		}
+	} else {
+		err = json.Unmarshal([]byte(redisJsonData), &incomeChart)
+		if err != nil {
+			fmt.Println("近两年的收入统计数据,json转换失败")
+		}
+	}
+
+	return
+}

+ 1 - 1
go.mod

@@ -15,7 +15,7 @@ require (
 	github.com/go-redis/redis/v8 v8.11.4
 	github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0
 	github.com/jonboulle/clockwork v0.2.2 // indirect
-	github.com/json-iterator/go v1.1.12 // indirect
+	github.com/json-iterator/go v1.1.12
 	github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible
 	github.com/lestrrat-go/strftime v1.0.5 // indirect
 	github.com/mattn/go-isatty v0.0.14 // indirect

+ 4 - 0
init_serve/router.go

@@ -44,5 +44,9 @@ func InitRouter() (r *gin.Engine) {
 	// 统计相关路由
 	censusGroup := rBase.Group("census/")
 	routers.InitCensus(censusGroup)
+
+	// 统计报告
+	routers.InitStatistic(rBase)
+
 	return
 }

+ 2 - 0
models/fms/constants.go

@@ -25,10 +25,12 @@ const (
 	ContractRegisterOpTypeStatus  = 4 // 修改合同状态
 	ContractRegisterOpTypeDel     = 5 // 删除合同登记
 	ContractRegisterOpTypeEdit    = 6 // 合规编辑
+	ContractPrePayOpTypeEdit      = 7 // 到款预登记
 
 	// 合同登记开票类型
 	ContractInvoiceTypeMake = 1 // 开票登记
 	ContractInvoiceTypePay  = 2 // 到款登记
+	ContractInvoiceTypePrePay  = 3 // 到款预登记
 
 	// 到款登记付款方式
 	ContractPaymentPayTypeYear     = 1 // 年付

+ 5 - 1
models/fms/contract_invoice.go

@@ -29,6 +29,7 @@ type ContractInvoice struct {
 	AdminName          string    `gorm:"column:admin_name" json:"admin_name" description:"操作人姓名"`
 	Remark             string    `gorm:"column:remark" json:"remark" description:"备注信息"`
 	IsDeleted          int       `gorm:"column:is_deleted" json:"is_deleted" description:"是否已删除: 0-正常; 1-已删除"`
+	IsPrePay           int       `gorm:"column:is_pre_pay" json:"is_pre_pay" description:"是否预付款: 0-不是; 1-是"`
 	base.TimeBase
 }
 
@@ -52,6 +53,7 @@ type ContractInvoiceItem struct {
 	SellerName         string  `gorm:"column:seller_name" json:"seller_name" description:"销售名称"`
 	PayType            int     `gorm:"column:pay_type" json:"pay_type" description:"付款方式:0-无;1-年付;2-半年付;3-季付;4-次付;5-异常"`
 	Remark             string  `gorm:"column:remark" json:"remark" description:"备注信息"`
+	IsPrePay           int     `gorm:"column:is_pre_pay" json:"is_pre_pay" description:"是否预付款: 0-不是; 1-是"`
 	CreateTime         string  `gorm:"column:create_time" json:"create_time" description:"创建时间"`
 }
 
@@ -145,7 +147,7 @@ func (c *ContractInvoice) DeleteAndCreateNewInvoice(contractRegisterId, invoiceT
 // ContractInvoiceSaveReq 合同开票-请求体
 type ContractInvoiceSaveReq struct {
 	ContractRegisterId int                        `json:"contract_register_id" binding:"required,gte=1" description:"登记ID"`
-	InvoiceType        int                        `json:"invoice_type" binding:"oneof=1 2" description:"类型: 1-开票登记; 2-到款登记"`
+	InvoiceType        int                        `json:"invoice_type" binding:"oneof=1 2 3" description:"类型: 1-开票登记; 2-到款登记; 3-预到款登记"`
 	AmountList         []*ContractInvoiceSaveItem `json:"amount_list"`
 }
 
@@ -191,6 +193,7 @@ func formatContractInvoice2ItemList(list []*ContractInvoice) (itemList []*Contra
 			SellerName:         list[i].SellerName,
 			PayType:            list[i].PayType,
 			Remark:             list[i].Remark,
+			IsPrePay:           list[i].IsPrePay,
 			CreateTime:         utils.TimeTransferString(utils.FormatDateTime, list[i].CreateTime),
 		})
 	}
@@ -244,6 +247,7 @@ func formatContractInvoice2Item(item *ContractInvoice) (formatItem *ContractInvo
 	formatItem.SellerName = item.SellerName
 	formatItem.PayType = item.PayType
 	formatItem.Remark = item.Remark
+	formatItem.IsPrePay = item.IsPrePay
 	formatItem.CreateTime = utils.TimeTransferString(utils.FormatDateTime, item.CreateTime)
 	return
 }

+ 149 - 0
models/fms/contract_pre_payment.go

@@ -0,0 +1,149 @@
+package fms
+
+import (
+	"hongze/fms_api/global"
+	"hongze/fms_api/models/base"
+	"hongze/fms_api/utils"
+	"time"
+)
+
+// ContractInvoice 合同开票表
+type ContractPrePayment struct {
+	PrePayId           int       `gorm:"primaryKey;column:pre_pay_id" json:"pre_pay_id" description:"预付款ID"`
+	CompanyName        string    `json:"company_name" description:"客户名称"`
+	ContractRegisterId int       `gorm:"column:contract_register_id" json:"contract_register_id" description:"登记ID"`
+	ContractCode       string    `gorm:"column:contract_code" json:"contract_code" description:"合同编号"`
+	Amount             float64   `gorm:"column:amount" json:"amount" description:"换算后的金额(人民币)"`
+	OriginAmount       float64   `gorm:"column:origin_amount" json:"origin_amount" description:"到款金额"`
+	CurrencyUnit       string    `gorm:"column:currency_unit" json:"currency_unit" description:"货币国际代码"`
+	SellerId           int       `gorm:"column:seller_id" json:"seller_id" description:"销售ID"`
+	SellerName         string    `gorm:"column:seller_name" json:"seller_name" description:"销售名称"`
+	AdminId            int       `gorm:"column:admin_id" json:"admin_id" description:"操作人ID"`
+	AdminName          string    `gorm:"column:admin_name" json:"admin_name" description:"操作人姓名"`
+	Remark             string    `gorm:"column:remark" json:"remark" description:"备注信息"`
+	StartDate          time.Time `gorm:"column:start_date" json:"start_date" description:"约定开始时间"`
+	EndDate            time.Time `gorm:"column:end_date" json:"end_date" description:"约定结束时间"`
+	NewCompany         int       `gorm:"column:new_company" json:"new_company" description:"是否为新客户: 0-否; 1-是"`
+	base.TimeBase
+}
+
+type ContractPrePaymentRespItem struct {
+	PrePayId           int     `gorm:"primaryKey;column:pre_pay_id" json:"pre_pay_id" description:"预付款ID"`
+	CompanyName        string  `json:"company_name" description:"客户名称"`
+	ContractRegisterId int     `gorm:"column:contract_register_id" json:"contract_register_id" description:"登记ID"`
+	ContractCode       string  `gorm:"column:contract_code" json:"contract_code" description:"合同编号"`
+	Amount             float64 `gorm:"column:amount" json:"amount" description:"换算后的金额(人民币)"`
+	OriginAmount       float64 `gorm:"column:origin_amount" json:"origin_amount" description:"到款金额"`
+	CurrencyUnit       string  `gorm:"column:currency_unit" json:"currency_unit" description:"货币国际代码"`
+	UnitName           string  `gorm:"unit_name" json:"unit_name" description:"单位名称"`
+	SellerId           int     `gorm:"column:seller_id" json:"seller_id" description:"销售ID"`
+	SellerName         string  `gorm:"column:seller_name" json:"seller_name" description:"销售名称"`
+	AdminId            int     `gorm:"column:admin_id" json:"admin_id" description:"操作人ID"`
+	AdminName          string  `gorm:"column:admin_name" json:"admin_name" description:"操作人姓名"`
+	Remark             string  `gorm:"column:remark" json:"remark" description:"备注信息"`
+	StartDate          string  `gorm:"column:start_date" json:"start_date" description:"约定开始时间"`
+	EndDate            string  `gorm:"column:end_date" json:"end_date" description:"约定结束时间"`
+	NewCompany         int     `gorm:"column:new_company" json:"new_company" description:"是否为新客户: 0-否; 1-是"`
+	CreateTime         string  `gorm:"autoCreateTime;column:create_time" json:"create_time" description:"创建时间"`
+	ModifyTime         string  `gorm:"autoUpdateTime:milli;column:modify_time" json:"modify_time" description:"最后更新时间"`
+}
+
+func (c *ContractPrePayment) TableName() string {
+	return "contract_pre_payment"
+}
+
+// ContractRegisterListReq 合同登记列表请求体
+type PrePayListReq struct {
+	Keyword   string `json:"keyword" form:"keyword" binding:"omitempty" description:"关键词"`
+	StartDate string `json:"start_date" form:"start_date" binding:"omitempty,datetime=2006-01-02" description:"约定开始时间"`
+	EndDate   string `json:"end_date" form:"end_date" binding:"omitempty,datetime=2006-01-02" description:"约定结束时间"`
+	SortType  int    `json:"sort_type" form:"sort_type" description:"排序方式: 1-正序; 2-倒序"`
+	base.PageReq
+}
+
+// GetPrePayItemPageList 获取预登记列表-分页
+func GetPrePayItemPageList(page base.IPage, condition string, pars []interface{}) (count int64, results []*ContractPrePaymentRespItem, err error) {
+	list := make([]*ContractPrePayment, 0)
+	query := global.DEFAULT_MYSQL.Table("contract_pre_payment").
+		Where(condition, pars...)
+	query.Count(&count)
+	if len(page.GetOrderItemsString()) > 0 {
+		query = query.Order(page.GetOrderItemsString())
+	}
+	err = query.Limit(int(page.GetPageSize())).Offset(int(page.Offset())).Find(&list).Error
+	if err != nil {
+		return
+	}
+	for i := range list {
+		results = append(results, formatPrePay2Item(list[i]))
+	}
+	return
+}
+
+// formatPrePay2Item 格式化PrePay
+func formatPrePay2Item(item *ContractPrePayment) (formatItem *ContractPrePaymentRespItem) {
+	formatItem = new(ContractPrePaymentRespItem)
+	formatItem.PrePayId = item.PrePayId
+	formatItem.ContractRegisterId = item.ContractRegisterId
+	formatItem.ContractCode = item.ContractCode
+	formatItem.CompanyName = item.CompanyName
+	formatItem.SellerId = item.SellerId
+	formatItem.SellerName = item.SellerName
+	formatItem.Amount = item.Amount
+	formatItem.OriginAmount = item.OriginAmount
+	formatItem.CurrencyUnit = item.CurrencyUnit
+	formatItem.StartDate = utils.TimeTransferString(utils.FormatDate, item.StartDate)
+	formatItem.EndDate = utils.TimeTransferString(utils.FormatDate, item.EndDate)
+	formatItem.AdminId = item.AdminId
+	formatItem.AdminName = item.AdminName
+	formatItem.Remark = item.Remark
+	formatItem.NewCompany = item.NewCompany
+	formatItem.CreateTime = utils.TimeTransferString(utils.FormatDateTime, item.CreateTime)
+	formatItem.ModifyTime = utils.TimeTransferString(utils.FormatDateTime, item.ModifyTime)
+	return
+}
+
+// PrepayAddReq 新增到款预登记请求体
+type PrepayAddReq struct {
+	CompanyName  string  `json:"company_name" binding:"required" description:"客户名称"`
+	SellerId     int     `json:"seller_id" binding:"required" description:"CRM系统-销售ID"`
+	SellerName   string  `json:"seller_name" binding:"required" description:"CRM系统-销售名称"`
+	Amount       float64 `json:"amount" binding:"required" description:"到款金额"`
+	CurrencyUnit string  `json:"currency_unit" binding:"required" description:"货币单位"`
+	StartDate    string  `json:"start_date" binding:"required" description:"约定开始日期"`
+	EndDate      string  `json:"end_date" binding:"required" description:"约定结束日期"`
+	Remark       string  `json:"remark" description:"备注信息"`
+	NewCompany   int     `json:"new_company" description:"是否为新客户: 0-否; 1-是"`
+}
+
+func (c *ContractPrePayment) Create() (err error) {
+	err = global.DEFAULT_MYSQL.Create(c).Error
+	return
+}
+
+func (c *ContractPrePayment) Fetch(id int) (item *ContractPrePayment, err error) {
+	err = global.DEFAULT_MYSQL.Model(c).Where(" pre_pay_id = ?", id).First(&item).Error
+	return
+}
+
+func (c *ContractPrePayment) Update(updateCols []string) (err error) {
+	err = global.DEFAULT_MYSQL.Model(c).Select(updateCols).Updates(c).Error
+	return
+}
+
+// 删除
+func (c *ContractPrePayment) Delete() (err error) {
+	err = global.DEFAULT_MYSQL.Delete(c).Error
+	return
+}
+
+// PrepayEditReq 编辑到款预登记请求体
+type PrepayEditReq struct {
+	PrePayId int `json:"pre_pay_id" binding:"required,gte=1" description:"预付款ID"`
+	PrepayAddReq
+}
+
+// PrepayDelReq 删除到款预登记
+type PrepayDelReq struct {
+	PrePayId int `json:"pre_pay_id" binding:"required,gte=1" description:"预付款ID"`
+}

+ 51 - 1
models/fms/contract_register.go

@@ -176,6 +176,8 @@ type ContractRegisterAddReq struct {
 	ServiceRemark      string                  `json:"service_remark" description:"套餐备注"`
 	HasPayment         int                     `json:"has_payment" description:"是否有代付: 0-无; 1-有"`
 	NewCompany         int                     `json:"new_company" description:"是否为新客户: 0-否; 1-是"`
+	Supplement         int                     `json:"supplement" description:"是否为补录合同: 0-否; 1-是"`
+	PrePayId           int                     `json:"pre_pay_id" description:"预到款信息ID"`
 	Services           []ContractServiceAddReq `json:"services" description:"服务套餐内容"`
 }
 
@@ -426,9 +428,57 @@ func CreateImportContractRegister(item *ContractRegister, serviceList []*Contrac
 	return
 }
 
+
 func GetContractInfoByRegisterIds(registerIds []int) (list []ContractRegister,err error) {
 	err = global.DEFAULT_MYSQL.Model(ContractRegister{}).
 		Where("is_deleted = 0 AND contract_register_id in ?", registerIds).
 		Find(&list).Error
 	return
-}
+}
+
+// CreateContractRegisterAndServices 新增合同登记及套餐
+func CreateContractRegisterAndServicesAndPayMent(item *ContractRegister, serviceDetail []*ContractServiceAndDetail, prePayId int) (err error) {
+	tx := global.DEFAULT_MYSQL.Begin()
+	defer func() {
+		if err != nil {
+			tx.Rollback()
+		} else {
+			tx.Commit()
+		}
+	}()
+
+	// 合同登记
+	tx.Create(item)
+
+	//nowTime := time.Now().Local()
+	for i := 0; i < len(serviceDetail); i++ {
+		// 合同服务
+		t := serviceDetail[i]
+		contractService := &ContractService{
+			ContractRegisterId: item.ContractRegisterId,
+			ProductId:          item.ProductId,
+			ServiceTemplateId:  t.ServiceTemplateId,
+			Title:              t.Title,
+			Value:              t.Value,
+			TableValue:         t.TableValue,
+			HasDetail:          t.HasDetail,
+			ChartPermissionId:  t.ChartPermissionId,
+			ChartPermissionIds: t.ChartPermissionIds,
+		}
+		contractService.Set()
+		tx.Create(contractService)
+
+		//// 合同服务详情
+		//for j := 0; j < len(t.Detail); j++ {
+		//	contractServiceDetail := t.Detail[j]
+		//	contractServiceDetail.ContractServiceId = contractService.ContractServiceId
+		//	contractServiceDetail.ContractRegisterId = item.ContractRegisterId
+		//	contractServiceDetail.ServiceTemplateId = contractService.ServiceTemplateId
+		//	contractServiceDetail.CreateTime = nowTime
+		//	tx.Create(contractServiceDetail)
+		//	t.Detail[j] = contractServiceDetail
+		//}
+	}
+
+	return
+}

+ 4 - 0
models/fms/invoice_payment_summary.go

@@ -21,6 +21,10 @@ func (c *InvoicePaymentSummary) TableName() string {
 	return "invoice_payment_summary"
 }
 
+func (c *InvoicePaymentSummary) Create() (err error) {
+	err = global.DEFAULT_MYSQL.Create(c).Error
+	return
+}
 // DeleteAndCreate 删除并新增汇总
 func (c *InvoicePaymentSummary) DeleteAndCreate(registerId int, summaryList []*InvoicePaymentSummary) (err error) {
 	tx := global.DEFAULT_MYSQL.Begin()

+ 27 - 0
models/statistic.go

@@ -0,0 +1,27 @@
+package models
+
+import (
+	"hongze/fms_api/global"
+)
+
+// 收入统计图表数据
+type IncomeChartResp struct {
+	Title         string    `description:"图表名称"`
+	Date          []string  `description:"月份"`
+	ContractMoney []float64 `description:"开票金额"`
+	ArrivalMoney  []float64 `description:"到款金额"`
+}
+
+type IncomeItem struct {
+	ContractMoney float64 `description:"开票金额"`
+	ArrivalMoney  float64 `description:"到款金额"`
+}
+
+func GetIncomeListCount(cond string) (results *IncomeItem, err error) {
+	sql := `SELECT a.contract_money, b.arrival_money FROM (
+SELECT SUM(amount) contract_money  FROM contract_invoice  WHERE is_deleted = 0 AND invoice_type = 1 `+cond+` ) AS a,
+(SELECT SUM(amount) arrival_money FROM  contract_invoice  WHERE is_deleted = 0 AND invoice_type = 2 `+cond+` ) AS b WHERE 1=1 `
+
+	err = global.DEFAULT_MYSQL.Raw(sql).First(&results).Error
+	return
+}

+ 8 - 0
routers/contract.go

@@ -33,4 +33,12 @@ func InitContract(rg *gin.RouterGroup) {
 	payGroup := rg.Group("payment/").Use(middleware.Token())
 	payGroup.POST("update_pay_type", pay.UpdatePaymentPayType)
 	payGroup.POST("distribute_service_amount", pay.DistributePaymentServiceAmount)
+
+	//到款预登记
+	prepay := new(contract.PrePaymentController)
+	prepayGroup := rg.Group("pre_pay/").Use(middleware.Token())
+	prepayGroup.GET("list", prepay.List)
+	prepayGroup.POST("add", prepay.Add)
+	prepayGroup.POST("edit", prepay.Edit)
+	prepayGroup.POST("del", prepay.Del)
 }

+ 13 - 0
routers/statistic.go

@@ -0,0 +1,13 @@
+package routers
+
+import (
+	"github.com/gin-gonic/gin"
+	"hongze/fms_api/controller"
+)
+
+func InitStatistic(baseGroup *gin.RouterGroup) {
+	//统计报告
+	statisticController := new(controller.StatisticController)
+	statisticGroup := baseGroup.Group("home/")
+	statisticGroup.GET("statistic", statisticController.Statistic)
+}