Browse Source

test 合同登记

hsun 2 years ago
parent
commit
de36fe3311

+ 168 - 43
controller/contract/register.go

@@ -9,6 +9,7 @@ import (
 	"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"
 )
@@ -25,7 +26,7 @@ type RegisterController struct{}
 // @Param   ServiceType		query	int		false	"套餐类型"
 // @Param   ContractType	query	int		false	"合同类型"
 // @Param   RegisterStatus	query	int		false	"登记状态"
-// @Success 200 {object} fms.ContractRegisterListResp
+// @Success 200 {object} fms.ContractRegisterItem
 // @router /contract/register/list [get]
 func (rg *RegisterController) List(c *gin.Context) {
 	var req fms.ContractRegisterListReq
@@ -39,7 +40,7 @@ func (rg *RegisterController) List(c *gin.Context) {
 		return
 	}
 
-	cond := ``
+	cond := `1 = 1`
 	pars := make([]interface{}, 0)
 	if req.Keyword != "" {
 		kw := "%" + req.Keyword + "%"
@@ -50,10 +51,6 @@ func (rg *RegisterController) List(c *gin.Context) {
 		cond += ` AND (start_time >= ? AND end_time <= ?)`
 		pars = append(pars, req.StartDate, req.EndDate)
 	}
-	if req.ServiceType != 0 {
-		cond += ` AND service_type = ?`
-		pars = append(pars, req.ServiceType)
-	}
 	if req.ContractType != 0 {
 		cond += ` AND contract_type = ?`
 		pars = append(pars, req.ContractType)
@@ -62,39 +59,83 @@ func (rg *RegisterController) List(c *gin.Context) {
 		cond += ` AND register_status = ?`
 		pars = append(pars, req.RegisterStatus)
 	}
+	// 套餐筛选
+	if req.ServiceType != 0 {
+		registerIds, e := fms.GetContractRegisterIdsByTempId(req.ServiceType)
+		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})
 
-	ob := new(fms.ContractRegister)
-	total, list, e := ob.PageList(page, cond, pars)
+	total, list, e := fms.GetContractRegisterItemPageList(page, cond, pars)
 	if e != nil {
-		resp.FailMsg("获取失败", "获取合同登记列表, Err: "+e.Error(), c)
+		resp.FailMsg("获取失败", "获取合同登记列表失败, Err: "+e.Error(), c)
 		return
 	}
-	respList := make([]*fms.ContractRegisterListResp, 0)
+	registerIds := make([]int, 0)
 	for i := range list {
-		// TODO:套餐信息
-		respList = append(respList, &fms.ContractRegisterListResp{
-			ContractRegisterId: list[i].ContractRegisterId,
-			ContractCode:       list[i].ContractCode,
-			CompanyName:        list[i].CompanyName,
-			SellerId:           list[i].SellerId,
-			SellerName:         list[i].SellerName,
-			ContractType:       list[i].ContractType,
-			ContractAmount:     list[i].ContractAmount,
-			InvoicedAmount:     list[i].InvoicedAmount,
-			PaymentAmount:      list[i].PaymentAmount,
-			StartDate:          utils.TimeTransferString(utils.FormatDate, list[i].StartDate),
-			EndDate:            utils.TimeTransferString(utils.FormatDate, list[i].EndDate),
-			SignDate:           utils.TimeTransferString(utils.FormatDate, list[i].SignDate),
-			AgreedPayTime:      list[i].AgreedPayTime,
-			ContractStatus:     list[i].ContractStatus,
-			RegisterStatus:     list[i].RegisterStatus,
-			Remark:             list[i].Remark,
-			CreateTime:         utils.TimeTransferString(utils.FormatDateTime, list[i].CreateTime),
-		})
+		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 {
+		// 获取服务套餐
+		servicesNameList, e := fms.GetContractRegisterServicesNameByRegisterIds(registerIds)
+		if e != nil {
+			resp.FailMsg("获取失败", "获取套餐拼接字符串失败, Err: "+e.Error(), c)
+			return
+		}
+		for i := range servicesNameList {
+			serviceMap[servicesNameList[i].ContractRegisterId] = servicesNameList[i].ServicesName
+		}
+
+		// 获取开票/到款列表
+		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)
+		list[i].ServicesName = serviceMap[list[i].ContractRegisterId]
+		v.ContractRegisterItem = *list[i]
+		v.InvoiceList = invoiceMap[list[i].ContractRegisterId]
+		v.PaymentList = paymentMap[list[i].ContractRegisterId]
+		respList = append(respList, v)
 	}
 
 	page.SetTotal(total)
@@ -175,9 +216,16 @@ func (rg *RegisterController) Add(c *gin.Context) {
 	ob.Remark = req.Remark
 	ob.Set()
 
-	// TODO:套餐信息
-	if e = ob.Create(); e != nil {
-		resp.FailMsg("操作失败", "新增合同登记失败, Err:"+e.Error(), c)
+	// 套餐信息
+	serviceList, e := fmsService.HandleContractServiceAndDetail(req.ProductId, req.Services)
+	if e != nil {
+		resp.FailMsg("操作失败", "获取合同套餐详情失败, Err: "+e.Error(), c)
+		return
+	}
+
+	// 新增合同及套餐
+	if e = fms.CreateContractRegisterAndServices(ob, serviceList); e != nil {
+		resp.FailMsg("操作失败", "新增合同及套餐失败, Err: "+e.Error(), c)
 		return
 	}
 
@@ -288,14 +336,22 @@ func (rg *RegisterController) Edit(c *gin.Context) {
 		"ContractType", "ContractAmount", "StartDate", "EndDate", "SignDate", "AgreedPayTime", "ContractStatus",
 		"RegisterStatus", "Remark", "ModifyTime",
 	}
-	if e = item.Update(updateCols); e != nil {
-		resp.FailMsg("操作失败", "更新合同登记失败, Err: "+e.Error(), c)
+
+	// 套餐信息
+	serviceList, e := fmsService.HandleContractServiceAndDetail(req.ProductId, req.Services)
+	if e != nil {
+		resp.FailMsg("操作失败", "获取合同套餐详情失败, Err: "+e.Error(), c)
 		return
 	}
 
-	// TODO:套餐信息
+	// 更新合同及套餐
+	if e = fms.UpdateContractRegisterAndServices(ob, updateCols, serviceList); e != nil {
+		resp.FailMsg("操作失败", "更新合同及套餐失败, Err: "+e.Error(), c)
+		return
+	}
 
-	// TODO:校验金额-是否修改状态
+	// 校验金额-是否修改状态
+	go fmsService.CheckContractRegisterAmount(item.ContractRegisterId)
 
 	// 操作日志
 	go func() {
@@ -384,9 +440,75 @@ func (rg *RegisterController) Del(c *gin.Context) {
 	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
+
+	// 套餐信息
+	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.InvoiceList = append(result.InvoiceList, 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
@@ -453,11 +575,6 @@ func (rg *RegisterController) UpdateStatus(c *gin.Context) {
 	resp.Ok("操作成功", c)
 }
 
-// 导出
-func (rg *RegisterController) Export(c *gin.Context) {
-
-}
-
 // Invoice
 // @Title 开票/到款登记
 // @Description 开票/到款登记
@@ -515,6 +632,9 @@ func (rg *RegisterController) Invoice(c *gin.Context) {
 		return
 	}
 
+	// 校验金额-是否修改状态
+	go fmsService.CheckContractRegisterAmount(req.ContractRegisterId)
+
 	// 操作日志
 	go func() {
 		opData := ""
@@ -541,3 +661,8 @@ func (rg *RegisterController) Invoice(c *gin.Context) {
 	}()
 	resp.Ok("操作成功", c)
 }
+
+// 导出
+func (rg *RegisterController) Export(c *gin.Context) {
+
+}

+ 2 - 1
controller/crm/contract.go

@@ -39,7 +39,7 @@ func (rg *ContractController) SearchList(c *gin.Context) {
 	if req.Keyword != "" {
 		kw := "%" + req.Keyword + "%"
 		cond += ` AND (company_name LIKE ? OR contract_code LIKE ?)`
-		pars = append(pars, kw, kw, kw)
+		pars = append(pars, kw, kw)
 	}
 	if req.ProductId > 0 {
 		cond += ` AND product_id = ?`
@@ -84,6 +84,7 @@ func (rg *ContractController) SearchList(c *gin.Context) {
 		respList = append(respList, &crm.ContractSearchListResp{
 			ContractId:      list[i].ContractId,
 			ContractCode:    list[i].ContractCode,
+			ProductId:       list[i].ProductId,
 			CompanyName:     list[i].CompanyName,
 			PayCompanyName:  payCompanyMap[list[i].ContractId],
 			SellerId:        list[i].SellerId,

+ 1 - 0
models/crm/contract.go

@@ -74,6 +74,7 @@ type ContractSearchListReq struct {
 type ContractSearchListResp struct {
 	ContractId      int     `json:"contract_id" description:"合同ID"`
 	ContractCode    string  `json:"contract_code" description:"合同编号"`
+	ProductId       int     `json:"product_id" description:"产品ID"`
 	CompanyName     string  `json:"company_name" description:"客户名称"`
 	PayCompanyName  string  `json:"Pay_company_name" description:"代付客户名称"`
 	SellerId        int     `json:"seller_id" description:"销售ID"`

+ 22 - 0
models/fms/contract_invoice.go

@@ -20,6 +20,17 @@ type ContractInvoice struct {
 	base.TimeBase
 }
 
+// ContractInvoiceItem 合同开票/到款
+type ContractInvoiceItem struct {
+	ContractInvoiceId  int     `gorm:"column:contract_invoice_id" json:"contract_invoice_id" description:"开票ID"`
+	ContractRegisterId int     `gorm:"column:contract_register_id" json:"contract_register_id" description:"登记ID"`
+	Amount             float64 `gorm:"column:amount" json:"amount" description:"金额"`
+	InvoiceType        int     `gorm:"column:invoice_type" json:"invoice_type" description:"类型: 1-开票登记; 2-到款登记"`
+	InvoiceDate        string  `gorm:"column:invoice_time" json:"invoice_time" description:"开票日期/到款月"`
+	Remark             string  `gorm:"column:remark" json:"remark" description:"备注信息"`
+	CreateTime         string  `gorm:"column:create_time" json:"create_time" description:"创建时间"`
+}
+
 func (c *ContractInvoice) TableName() string {
 	return "contract_register"
 }
@@ -99,3 +110,14 @@ type ContractInvoiceSaveItem struct {
 	Amount      float64 `json:"amount" description:"开票金额/到款金额"`
 	InvoiceDate string  `json:"invoice_date" description:"开票日期/到款月"`
 }
+
+// GetContractInvoiceItemList 获取开票到款列表
+func GetContractInvoiceItemList(condition string, pars []interface{}) (list []*ContractInvoiceItem, err error) {
+	list = make([]*ContractInvoiceItem, 0)
+	err = global.DEFAULT_MYSQL.Model(ContractInvoice{}).
+		Where("is_deleted = 0").
+		Where(condition, pars...).
+		Order("contract_invoice_id ASC").
+		Find(&list).Error
+	return
+}

+ 162 - 18
models/fms/contract_register.go

@@ -13,6 +13,7 @@ type ContractRegister struct {
 	CrmContractId      int       `gorm:"column:crm_contract_id" json:"crm_contract_id" description:"CRM系统-合同ID"`
 	ContractSource     int       `gorm:"column:contract_source" json:"contract_source" description:"合同来源: 0-非系统合同导入; 1-CRM合同导入"`
 	CompanyName        string    `gorm:"column:company_name" json:"company_name" description:"客户名称"`
+	ProductId          int       `gorm:"column:product_id" json:"product_id" description:"产品ID: 1-FICC; 2-权益"`
 	SellerId           int       `gorm:"column:seller_id" json:"seller_id" description:"CRM系统-销售ID"`
 	SellerName         int       `gorm:"column:seller_name" json:"seller_name" description:"CRM系统-销售名称"`
 	ContractType       int       `gorm:"column:contract_type" json:"contract_type" description:"合同类型: 1-新签; 2-续约"`
@@ -95,8 +96,8 @@ type ContractRegisterListReq struct {
 	base.PageReq
 }
 
-// ContractRegisterListResp 合同登记列表响应体
-type ContractRegisterListResp struct {
+// ContractRegisterItem 合同登记
+type ContractRegisterItem struct {
 	ContractRegisterId int     `json:"contract_register_id" description:"登记ID"`
 	ContractCode       string  `json:"contract_code" description:"合同编号"`
 	CompanyName        string  `json:"company_name" description:"客户名称"`
@@ -114,7 +115,14 @@ type ContractRegisterListResp struct {
 	RegisterStatus     int     `json:"register_status" description:"登记状态: 1-进行中; 2-已完成;"`
 	Remark             string  `json:"remark" description:"备注信息"`
 	CreateTime         string  `json:"create_time" description:"登记时间"`
-	// TODO: 套餐信息
+	ServicesName       string  `json:"services" description:"套餐名称"`
+}
+
+// ContractRegisterList 合同登记列表
+type ContractRegisterList struct {
+	ContractRegisterItem
+	InvoiceList []*ContractInvoiceItem `json:"invoice_list" description:"开票信息"`
+	PaymentList []*ContractInvoiceItem `json:"payment_list" description:"到款信息"`
 }
 
 // ContractRegisterDelReq 合同登记-删除请求体
@@ -130,21 +138,22 @@ type ContractRegisterUpdateStatusReq struct {
 
 // ContractRegisterAddReq 新增合同登记请求体
 type ContractRegisterAddReq struct {
-	ContractCode   string  `json:"contract_code" binding:"required" description:"合同编号"`
-	CrmContractId  int     `json:"crm_contract_id" description:"CRM系统-合同ID"`
-	ContractSource int     `json:"contract_source" binding:"oneof=0 1" description:"合同来源: 0-非系统合同导入; 1-CRM合同导入"`
-	CompanyName    string  `gorm:"column:company_name" binding:"required" json:"company_name" description:"客户名称"`
-	SellerId       int     `json:"seller_id" binding:"required" description:"CRM系统-销售ID"`
-	SellerName     int     `json:"seller_name" binding:"required" description:"CRM系统-销售名称"`
-	ContractType   int     `json:"contract_type" binding:"oneof=1 2" description:"合同类型: 1-新签; 2-续约"`
-	ContractAmount float64 `json:"contract_amount" binding:"required" description:"合同金额"`
-	StartDate      string  `json:"start_date" binding:"required" description:"合同开始日期"`
-	EndDate        string  `json:"end_date" binding:"required" description:"合同结束日期"`
-	SignDate       string  `json:"sign_date" binding:"required" description:"合同签订日期"`
-	AgreedPayTime  string  `json:"agreed_pay_time" binding:"required" description:"约定付款时间(如:生效日起10日内)"`
-	ContractStatus int     `json:"contract_status" binding:"oneof=1 2 3" description:"合同状态: 1-已审批; 2-单章寄出; 3-已签回"`
-	Remark         string  `json:"remark" description:"备注信息"`
-	// TODO:套餐信息
+	ContractCode   string                  `json:"contract_code" binding:"required" description:"合同编号"`
+	CrmContractId  int                     `json:"crm_contract_id" description:"CRM系统-合同ID"`
+	ContractSource int                     `json:"contract_source" binding:"oneof=0 1" description:"合同来源: 0-非系统合同导入; 1-CRM合同导入"`
+	CompanyName    string                  `json:"company_name" binding:"required" description:"客户名称"`
+	SellerId       int                     `json:"seller_id" binding:"required" description:"CRM系统-销售ID"`
+	SellerName     int                     `json:"seller_name" binding:"required" description:"CRM系统-销售名称"`
+	ContractType   int                     `json:"contract_type" binding:"oneof=1 2" description:"合同类型: 1-新签; 2-续约"`
+	ContractAmount float64                 `json:"contract_amount" binding:"required" description:"合同金额"`
+	StartDate      string                  `json:"start_date" binding:"required" description:"合同开始日期"`
+	EndDate        string                  `json:"end_date" binding:"required" description:"合同结束日期"`
+	SignDate       string                  `json:"sign_date" binding:"required" description:"合同签订日期"`
+	AgreedPayTime  string                  `json:"agreed_pay_time" binding:"required" description:"约定付款时间(如:生效日起10日内)"`
+	ContractStatus int                     `json:"contract_status" binding:"oneof=1 2 3" description:"合同状态: 1-已审批; 2-单章寄出; 3-已签回"`
+	Remark         string                  `json:"remark" description:"备注信息"`
+	ProductId      int                     `json:"remark" binding:"oneof=1 2" description:"产品ID"`
+	Services       []ContractServiceAddReq `json:"services" description:"服务套餐内容"`
 }
 
 // ContractRegisterEditReq 编辑合同登记请求体
@@ -152,3 +161,138 @@ type ContractRegisterEditReq struct {
 	ContractRegisterId int `json:"contract_register_id" binding:"required,gte=1" description:"登记ID"`
 	ContractRegisterAddReq
 }
+
+// CreateContractRegisterAndServices 新增合同登记及套餐
+func CreateContractRegisterAndServices(item *ContractRegister, serviceDetail []*ContractServiceAndDetail) (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,
+		}
+		contractService.Set()
+		tx.Create(contractService)
+
+		// 合同服务详情
+		for j := 0; j < len(t.DetailList); j++ {
+			contractServiceDetail := t.DetailList[j]
+			contractServiceDetail.ContractServiceId = contractService.ContractServiceId
+			contractServiceDetail.ContractRegisterId = item.ContractRegisterId
+			contractServiceDetail.ServiceTemplateId = contractService.ServiceTemplateId
+			contractServiceDetail.CreateTime = nowTime
+			tx.Create(contractServiceDetail)
+			t.DetailList[j] = contractServiceDetail
+		}
+	}
+	return
+}
+
+// UpdateContractRegisterAndServices 新增合同登记及套餐
+func UpdateContractRegisterAndServices(item *ContractRegister, updateCols []string, serviceDetail []*ContractServiceAndDetail) (err error) {
+	tx := global.DEFAULT_MYSQL.Begin()
+	defer func() {
+		if err != nil {
+			tx.Rollback()
+		} else {
+			tx.Commit()
+		}
+	}()
+
+	// 更新合同登记
+	if e := item.Update(updateCols); e != nil {
+		return
+	}
+
+	// 删除原服务及详情信息
+	sql := `DELETE FROM contract_service WHERE contract_register_id = ?`
+	tx.Exec(sql, item.ContractRegisterId)
+	sql = `DELETE FROM contract_service_detail WHERE contract_register_id = ?`
+	tx.Exec(sql, item.ContractRegisterId)
+
+	// 新增合同服务
+	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,
+		}
+		contractService.Set()
+		tx.Create(contractService)
+
+		// 合同服务详情
+		for j := 0; j < len(t.DetailList); j++ {
+			contractServiceDetail := t.DetailList[j]
+			contractServiceDetail.ContractServiceId = contractService.ContractServiceId
+			contractServiceDetail.ContractRegisterId = item.ContractRegisterId
+			contractServiceDetail.ServiceTemplateId = contractService.ServiceTemplateId
+			contractServiceDetail.CreateTime = nowTime
+			tx.Create(contractServiceDetail)
+			t.DetailList[j] = contractServiceDetail
+		}
+	}
+	return
+}
+
+// ContractRegisterDetailReq 合同登记-详情请求体
+type ContractRegisterDetailReq struct {
+	ContractRegisterId int `json:"contract_register_id" form:"contract_register_id" binding:"required,gte=1"`
+}
+
+// ContractRegisterDetail-合同登记详情
+type ContractRegisterDetail struct {
+	ContractRegisterItem
+	ServiceList []*ContractServiceAndDetail `json:"service_list" description:"合同服务及详情"`
+	InvoiceList []*ContractInvoiceItem      `json:"invoice_list" description:"开票信息"`
+	PaymentList []*ContractInvoiceItem      `json:"payment_list" description:"到款信息"`
+	Logs        []*ContractRegisterLogItem  `json:"logs" description:"登记日志"`
+}
+
+// GetContractRegisterItemById 获取合同登记信息
+func GetContractRegisterItemById(id int) (item *ContractRegisterItem, err error) {
+	err = global.DEFAULT_MYSQL.Model(ContractRegister{}).
+		Where("is_deleted = 0 AND contract_register_id = ?", id).
+		First(&item).Error
+	return
+}
+
+// GetContractRegisterItemPageList 获取合同登记列表-分页
+func GetContractRegisterItemPageList(page base.IPage, condition string, pars []interface{}) (count int64, results []*ContractRegisterItem, err error) {
+	results = make([]*ContractRegisterItem, 0)
+	query := global.DEFAULT_MYSQL.Model(ContractRegister{}).
+		Where("is_deleted = 0").
+		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(&results).Error
+	return
+}

+ 20 - 0
models/fms/contract_register_log.go

@@ -17,6 +17,17 @@ type ContractRegisterLog struct {
 	CreateTime         time.Time `gorm:"autoCreateTime;column:create_time" json:"create_time" description:"创建时间"`
 }
 
+// ContractRegisterLogItem 合同登记-操作记录表
+type ContractRegisterLogItem struct {
+	ContractRegisterId int    `gorm:"column:contract_register_id" json:"contract_register_id" description:"登记ID"`
+	AdminId            int    `gorm:"column:admin_id" json:"admin_id" description:"操作人ID"`
+	AdminName          string `gorm:"column:admin_name" json:"admin_name" description:"当时操作人姓名"`
+	OpData             string `gorm:"column:op_data" json:"-" description:"操作数据-JSON"`
+	OpType             int    `gorm:"column:op_type" json:"op_type" description:"操作类型: 1-合规登记; 2-开票登记; 3-到款登记; 4-修改合同状态; 5-删除合同登记;"`
+	Remark             string `gorm:"column:remark" json:"remark" description:"备注信息"`
+	CreateTime         string `gorm:"autoCreateTime;column:create_time" json:"create_time" description:"创建时间"`
+}
+
 func (c *ContractRegisterLog) TableName() string {
 	return "contract_register_log"
 }
@@ -38,3 +49,12 @@ func (c *ContractRegisterLog) List(condition string, pars []interface{}) (list [
 		Find(&list).Error
 	return
 }
+
+// GetContractRegisterLogItemList 获取合同登记操作记录
+func GetContractRegisterLogItemList(condition string, pars []interface{}) (list []*ContractRegisterLogItem, err error) {
+	list = make([]*ContractRegisterLogItem, 0)
+	err = global.DEFAULT_MYSQL.Model(ContractRegisterLog{}).
+		Where(condition, pars...).
+		Find(&list).Error
+	return
+}

+ 79 - 0
models/fms/contract_service.go

@@ -1,5 +1,84 @@
 package fms
 
+import (
+	"hongze/fms_api/global"
+	"hongze/fms_api/models/base"
+)
+
 // ContractService 合同服务套餐
 type ContractService struct {
+	ContractServiceId  int    `gorm:"primaryKey;column:contract_service_id" json:"contract_service_id"`
+	ContractRegisterId int    `gorm:"column:contract_register_id" json:"contract_register_id" description:"登记ID"`
+	ProductId          int    `gorm:"column:product_id" json:"product_id" description:"产品ID"`
+	ServiceTemplateId  int    `gorm:"column:service_template_id" json:"service_template_id" description:"合同服务模板ID"`
+	Title              string `gorm:"column:title" json:"title" description:"套餐名称"`
+	Value              string `gorm:"column:value" json:"value" description:"套餐的值"`
+	TableValue         string `gorm:"column:table_value" json:"table_value" description:"表格数据,用于word生成时的json数据"`
+	HasDetail          string `gorm:"column:has_detail" json:"has_detail" description:"是否有详情: 无; 有"`
+	ChartPermissionId  int    `gorm:"column:chart_permission_id" json:"chart_permission_id" description:"权限ID"`
+	base.TimeBase
+}
+
+func (c *ContractService) List(condition string, pars []interface{}) (list []*ContractService, err error) {
+	list = make([]*ContractService, 0)
+	err = global.DEFAULT_MYSQL.Model(c).
+		Where(condition, pars...).
+		Find(&list).Error
+	return
+}
+
+// ContractServiceAddReq 新增合同套餐请求体
+type ContractServiceAddReq struct {
+	ServiceTemplateId int                             `json:"service_template_id" description:"服务套餐id"`
+	Title             string                          `json:"title" description:"服务套餐名称"`
+	Value             string                          `json:"value" description:"服务套餐内容"`
+	Detail            [][]ContractServiceDetailAddReq `json:"detail" description:"详情数据"`
+}
+
+// ContractServiceAndDetail 合同的服务内容
+type ContractServiceAndDetail struct {
+	ContractServiceId int    `description:"合同服务ID"`
+	ContractId        int    `description:"合同id"`
+	ProductId         int    `description:"产品id,1:ficc;2:权益"`
+	ServiceTemplateId int    `description:"合同服务模板id"`
+	Title             string `description:"套餐标题"`
+	Value             string `description:"套餐的值"`
+	HasDetail         string `description:"是否有详情,枚举值:是、否;默认:否"`
+	TableValue        string `description:"表格数据,用于word生成时的json数据"`
+	ChartPermissionId int    `description:"权限id"`
+	DetailList        []*ContractServiceDetail
+}
+
+// GetContractServiceAndDetailList 根据id获取合同列表数据
+func GetContractServiceAndDetailList(contractRegisterId int) (list []*ContractServiceAndDetail, err error) {
+	err = global.DEFAULT_MYSQL.Model(ContractService{}).
+		Where("contract_register_id = ?", contractRegisterId).
+		Find(&list).Error
+	return
+}
+
+// GetContractRegisterIdsByTempId 套餐模板ID获取关联的合同登记ID
+func GetContractRegisterIdsByTempId(tempId int) (registerIds []int, err error) {
+	err = global.DEFAULT_MYSQL.Model(ContractService{}).
+		Select("DISTINCT contract_register_id").
+		Where("service_template_id = ?", tempId).
+		Find(&registerIds).Error
+	return
+}
+
+// ContractRegisterServicesName 合同登记套餐信息
+type ContractRegisterServicesName struct {
+	ContractRegisterId int    `json:"contract_register_id" description:"登记ID"`
+	ServicesName       string `json:"services_name" description:"套餐信息, 英文逗号拼接"`
+}
+
+// GetContractRegisterServicesNameByRegisterIds 合同登记IDs获取套餐拼接字符串
+func GetContractRegisterServicesNameByRegisterIds(registerIds []int) (list []*ContractRegisterServicesName, err error) {
+	list = make([]*ContractRegisterServicesName, 0)
+	err = global.DEFAULT_MYSQL.Model(ContractService{}).
+		Select("contract_register_id, GROUP_CONCAT(title) AS services_name").
+		Where("contract_register_id IN ?", registerIds).
+		Group("contract_register_id").
+		Find(&list).Error
+	return
 }

+ 21 - 0
models/fms/contract_service_detail.go

@@ -30,3 +30,24 @@ func GetContractServiceDetailByTemplateId(serviceTemplateId int) (items []*Contr
 		Find(&items).Error
 	return
 }
+
+type ContractServiceDetailAddReq struct {
+	CanEdit    bool   `json:"CanEdit" description:"是否可编辑"`
+	Type       string `json:"Type" description:"类型"`
+	Value      string `json:"Value" description:"值"`
+	ValueId    []int  `json:"ValueId" description:"类型"`
+	HeadName   string `json:"HeadName" description:"表头名称"`
+	Tag        string `json:"Tag" description:"表头名称"`
+	RowDisable bool   `json:"RowDisable" description:"该行是否禁用操作"`
+	RowName    string `json:"RowName" description:"该行关联名称"`
+	Name       string `json:"Name" description:"行名称"`
+}
+
+// GetContractServiceDetailByServiceId 根据合同服务id获取对应的套餐表格数据详情
+func GetContractServiceDetailByServiceId(serviceId int) (list []*ContractServiceDetail, err error) {
+	err = global.DEFAULT_MYSQL.Model(ContractServiceDetail{}).
+		Where("contract_service_id = ?", serviceId).
+		Order("id ASC").
+		Find(&list).Error
+	return
+}

+ 8 - 0
models/fms/contract_service_template.go

@@ -54,3 +54,11 @@ func GetContractServiceTemplateMapByParentId(parentId int) (items []*ContractSer
 		Find(&items).Error
 	return
 }
+
+// GetContractServiceTemplateById 主键获取合同套餐模板
+func GetContractServiceTemplateById(templateId int) (item *ContractServiceTemplate, err error) {
+	err = global.DEFAULT_MYSQL.Model(ContractServiceTemplate{}).
+		Where("service_template_id = ?", templateId).
+		First(&item).Error
+	return
+}

+ 218 - 1
services/fms/contract_register.go

@@ -1,5 +1,222 @@
 package fms
 
-func CheckContractRegisterAmount() {
+import (
+	"encoding/json"
+	"errors"
+	"fmt"
+	"github.com/shopspring/decimal"
+	"hongze/fms_api/models/fms"
+	"hongze/fms_api/services/alarm_msg"
+	"time"
+)
 
+// CheckContractRegisterAmount 校验合同登记金额-判断是否需要更新合同登记状态
+func CheckContractRegisterAmount(registerId int) {
+	var err error
+	defer func() {
+		if err != nil {
+			alarm_msg.SendAlarmMsg("校验合同登记金额失败, ErrMsg: "+err.Error(), 3)
+		}
+	}()
+
+	// 获取合同登记信息
+	cr := new(fms.ContractRegister)
+	item, e := cr.Fetch(registerId)
+	if e != nil {
+		err = errors.New("获取合同登记信息失败, Err: " + e.Error())
+		return
+	}
+	amount := decimal.NewFromFloat(item.ContractAmount)
+	amount.Round(2)
+
+	// 获取开票/到款信息
+	invoiceCond := `contract_register_id = ?`
+	invoicePars := make([]interface{}, 0)
+	invoicePars = append(invoicePars, registerId)
+	ci := new(fms.ContractInvoice)
+	invoiceList, e := ci.List(invoiceCond, invoicePars)
+	if e != nil {
+		err = errors.New("获取开票到款信息失败, Err: " + e.Error())
+		return
+	}
+	invoiceAmount := decimal.NewFromFloat(0.00)
+	paymentAmount := decimal.NewFromFloat(0.00)
+	for i := range invoiceList {
+		a := decimal.NewFromFloat(invoiceList[i].Amount)
+		if invoiceList[i].InvoiceType == fms.ContractInvoiceTypeMake {
+			invoiceAmount.Add(a)
+		}
+		if invoiceList[i].InvoiceType == fms.ContractInvoiceTypePay {
+			paymentAmount.Add(a)
+		}
+	}
+	invoiceAmount.Round(2)
+	paymentAmount.Round(2)
+
+	// 核对金额是否相等, 并更新状态
+	status := fms.ContractRegisterStatusIng
+	if amount.Equal(invoiceAmount) && invoiceAmount.Equal(paymentAmount) {
+		status = fms.ContractRegisterStatusComplete
+	}
+	updateCols := []string{"InvoicedAmount", "PaymentAmount", "RegisterStatus", "ModifyTime"}
+	ia, _ := invoiceAmount.Float64()
+	pa, _ := paymentAmount.Float64()
+	item.InvoicedAmount = ia
+	item.PaymentAmount = pa
+	item.RegisterStatus = status
+	item.ModifyTime = time.Now().Local()
+	if e = item.Update(updateCols); e != nil {
+		err = errors.New("更新合同登记金额及状态失败, Err: " + e.Error())
+		return
+	}
+	return
+}
+
+// HandleContractServiceAndDetail 根据请求数据获取套餐服务详情信息
+func HandleContractServiceAndDetail(productId int, serviceList []fms.ContractServiceAddReq) (serviceDetailList []*fms.ContractServiceAndDetail, err error) {
+	serviceDetailList = make([]*fms.ContractServiceAndDetail, 0)
+	if len(serviceList) < 0 {
+		err = errors.New("请至少选择一种套餐")
+		return
+	}
+	for i := 0; i < len(serviceList); i++ {
+		item := serviceList[i]
+		detail := item.Detail
+
+		detailList := make([]*fms.ContractServiceDetail, 0)
+		if len(detail) > 0 {
+			for j := 0; j < len(detail); j++ {
+				detailItem := detail[j]
+				cellMap := make(map[string]string)
+				for k := 0; k < len(detailItem); k++ {
+					key := fmt.Sprint("cell_", k+1)
+					v, e := json.Marshal(detailItem[k])
+					if e != nil {
+						err = errors.New(fmt.Sprint("json转换失败:", e))
+						return
+					}
+					cellMap[key] = string(v)
+				}
+				contractServiceDetail := &fms.ContractServiceDetail{
+					Col1: func(cellMap map[string]string) string {
+						v, ok := cellMap["cell_1"]
+						if ok {
+							return v
+						} else {
+							return ""
+						}
+					}(cellMap),
+					Col2: func(cellMap map[string]string) string {
+						v, ok := cellMap["cell_2"]
+						if ok {
+							return v
+						} else {
+							return ""
+						}
+					}(cellMap),
+					Col3: func(cellMap map[string]string) string {
+						v, ok := cellMap["cell_3"]
+						if ok {
+							return v
+						} else {
+							return ""
+						}
+					}(cellMap),
+					Col4: func(cellMap map[string]string) string {
+						v, ok := cellMap["cell_4"]
+						if ok {
+							return v
+						} else {
+							return ""
+						}
+					}(cellMap),
+					Col5: func(cellMap map[string]string) string {
+						v, ok := cellMap["cell_5"]
+						if ok {
+							return v
+						} else {
+							return ""
+						}
+					}(cellMap),
+					Col6: func(cellMap map[string]string) string {
+						v, ok := cellMap["cell_6"]
+						if ok {
+							return v
+						} else {
+							return ""
+						}
+					}(cellMap),
+					Col7: func(cellMap map[string]string) string {
+						v, ok := cellMap["cell_7"]
+						if ok {
+							return v
+						} else {
+							return ""
+						}
+					}(cellMap),
+					ServiceTemplateId: item.ServiceTemplateId,
+					CreateTime:        time.Now(),
+				}
+				detailList = append(detailList, contractServiceDetail)
+			}
+		}
+		hasDetail := "否"
+		if len(detailList) > 0 {
+			hasDetail = "是"
+		}
+		// 报价单图片地址(暂无)
+		newValue := item.Value
+		//if base642Image {
+		//	b, _ := regexp.MatchString(`^data:\s*image\/(\w+);base64,`, newValue)
+		//	if b {
+		//		imageUrl, uploadErr := UploadImageBase64(newValue)
+		//		if uploadErr != nil {
+		//			err = errors.New(fmt.Sprint("base64图片上传失败:", uploadErr))
+		//			return
+		//		}
+		//		newValue = imageUrl
+		//	}
+		//}
+
+		// 合同模板
+		serviceTemp, e := fms.GetContractServiceTemplateById(item.ServiceTemplateId)
+		if e != nil {
+			err = errors.New("找不到该模板")
+			return
+		}
+		serviceDetail := &fms.ContractServiceAndDetail{
+			ServiceTemplateId: item.ServiceTemplateId,
+			Title:             item.Title,
+			Value:             newValue,
+			ProductId:         productId,
+			HasDetail:         hasDetail,
+			TableValue:        serviceTemp.TableValue,
+			DetailList:        detailList,
+			ChartPermissionId: serviceTemp.ChartPermissionId,
+		}
+		serviceDetailList = append(serviceDetailList, serviceDetail)
+	}
+	return
+}
+
+// GetContractServiceAndDetail 根据合同登记ID获取服务详情
+func GetContractServiceAndDetail(contractRegisterId int) (serviceList []*fms.ContractServiceAndDetail, err error) {
+	list, e := fms.GetContractServiceAndDetailList(contractRegisterId)
+	if e != nil {
+		err = errors.New(fmt.Sprint("查找合同服务异常", e))
+		return
+	}
+	serviceList = list
+	newLen := len(serviceList)
+	for i := 0; newLen > i; i++ {
+		if serviceList[i].HasDetail == "是" {
+			detail, e := fms.GetContractServiceDetailByServiceId(serviceList[i].ContractServiceId)
+			if e != nil {
+				err = errors.New(fmt.Sprint("查找合同服务详情异常", e))
+				return
+			}
+			serviceList[i].DetailList = detail
+		}
+	}
+	return
 }