From 116948bcec330a6dde841708515c222fcebf51a7 Mon Sep 17 00:00:00 2001
From: jiangshuai <291802688@qq.com>
Date: 星期二, 06 二月 2024 10:12:10 +0800
Subject: [PATCH] Merge branch 'master' of http://192.168.5.5:10010/r/aps/crm

---
 proto/crm_aps/server.go                         |  115 ++
 api/v1/client.go                                |    6 
 model/city.go                                   |   35 
 service/system_set_service.go                   |   20 
 model/response/salesDetails.go                  |   15 
 go.mod                                          |   10 
 docs/swagger.yaml                               |  167 +++
 api/v1/quotation.go                             |   36 
 model/request/system_set_request.go             |    7 
 model/product.go                                |    5 
 proto/product_inventory/product_inventory.pb.go |  179 ++-
 api/v1/salesDetails.go                          |   42 
 proto/product/product.pb.go                     |  200 +++
 proto/crm_aps.proto                             |   33 
 proto/product_inventory.proto                   |    6 
 api/v1/index.go                                 |    1 
 model/request/product.go                        |    5 
 api/v1/product.go                               |   32 
 proto/crm_aps/crm_aps.pb.go                     |  579 ++++++++++++-
 model/quotation.go                              |   13 
 model/province.go                               |   23 
 docs/docs.go                                    |  265 +++++
 docs/swagger.json                               |  265 +++++
 model/grpc_init/crm_aps_init.go                 |   20 
 constvar/const.go                               |   40 
 constvar/salesDetails.go                        |    4 
 go.sum                                          |   21 
 proto/product.proto                             |   11 
 model/index.go                                  |    3 
 proto/crm_aps/crm_aps_grpc.pb.go                |  138 +++
 router/index.go                                 |   10 
 router/quotation.go                             |    9 
 main.go                                         |    5 
 api/v1/system_set.go                            |  116 ++
 model/system_set.go                             |   97 ++
 35 files changed, 2,189 insertions(+), 344 deletions(-)

diff --git a/api/v1/client.go b/api/v1/client.go
index ff33fad..6caa2bf 100644
--- a/api/v1/client.go
+++ b/api/v1/client.go
@@ -193,8 +193,10 @@
 //	@Tags		Client
 //	@Summary	瀹㈡埛鍒楄〃
 //	@Produce	application/json
-//	@Param		object	body		request.GetClientList	true	"鍙傛暟"
-//	@Success	200		{object}	contextx.Response{data=response.ClientResponse}
+//
+// @Param		object	body		request.GetClientList	true	"鍙傛暟"
+// @Success	200		{object}	contextx.Response{data=response.ClientResponse}
+//
 //	@Router		/api/client/list [post]
 func (cli *ClientApi) List(c *gin.Context) {
 	var params request.GetClientList
diff --git a/api/v1/index.go b/api/v1/index.go
index b7d9326..a25ded4 100644
--- a/api/v1/index.go
+++ b/api/v1/index.go
@@ -67,6 +67,7 @@
 	AssignApi
 	CollectionProjectionApi
 	ContactInformationApi
+	SystemSetApi
 }
 
 var ApiGroup = new(Group)
diff --git a/api/v1/product.go b/api/v1/product.go
index 86ee33d..a58e4a2 100644
--- a/api/v1/product.go
+++ b/api/v1/product.go
@@ -55,6 +55,19 @@
 		return
 	}
 
+	if params.QuotationNumber != "" {
+		find, err := model.NewQuotationSearch(nil).SetNumber(params.QuotationNumber).Find()
+		if err != nil {
+			ctx.FailWithMsg(ecode.UnknownErr, "鎶ヤ环鍗曚俊鎭煡璇㈠け璐�")
+			return
+		}
+		products := find.Products
+		ctx.OkWithDetailed(response.ListResponse{
+			Data:  products,
+			Count: int64(len(products)),
+		})
+		return
+	}
 	cli := product.NewProductServiceClient(grpc_init.CrmApsGrpcServiceConn)
 	getProductListResponse, err := cli.GetProductList(ctx.GetCtx(), &product.GetProductListRequest{
 		Page:          cast.ToInt32(params.Page),
@@ -82,6 +95,8 @@
 		productList[k].Amount = decimal.NewFromFloat(1)
 		productList[k].Total = productList[k].Price.Mul(productList[k].Amount).Round(2)
 		productList[k].Unit = v.Unit
+		productList[k].Type = v.Type
+		productList[k].Specs = v.Specs
 	}
 
 	ctx.OkWithDetailed(response.ListResponse{
@@ -127,7 +142,7 @@
 // @Summary	鑾峰彇浜у搧璁㈠崟淇℃伅
 // @Produce	application/json
 // @Param		number	path		string	true	"鏄庣粏缂栫爜"
-// @Success	200	{object}	contextx.Response{data=[]product.WorkOrderInfo}	"鎴愬姛"
+// @Success	200	{object}	contextx.Response{data=response.Info}	"鎴愬姛"
 //
 //	@Router		/api/product/getProductOrderInfo/{number} [get]
 func (ci *ProductApi) GetProductOrderInfo(c *gin.Context) {
@@ -147,6 +162,7 @@
 		ctx.FailWithMsg(ecode.UnknownErr, "鍐呴儴閿欒")
 		return
 	}
+	var result response.Info
 	var list []response.WorkOrderInfo
 	for _, orderInfo := range info.List {
 		var wo response.WorkOrderInfo
@@ -159,5 +175,17 @@
 		wo.EndTime = orderInfo.EndTime
 		list = append(list, wo)
 	}
-	ctx.OkWithDetailed(list)
+	result.MakeInfo = list
+	var purchaseInfo []response.Purchase
+	for _, pl := range info.PurchaseList {
+		var p response.Purchase
+		p.Amount = pl.Amount
+		p.Status = pl.Status
+		p.PurchaseName = pl.PurchaseName
+		p.PurchaseNumber = pl.PurchaseNumber
+		p.SupplierName = pl.SupplierName
+		purchaseInfo = append(purchaseInfo, p)
+	}
+	result.PurchaseInfo = purchaseInfo
+	ctx.OkWithDetailed(result)
 }
diff --git a/api/v1/quotation.go b/api/v1/quotation.go
index d237955..ecbe7da 100644
--- a/api/v1/quotation.go
+++ b/api/v1/quotation.go
@@ -9,6 +9,7 @@
 	"aps_crm/pkg/ecode"
 	"aps_crm/utils"
 	"github.com/gin-gonic/gin"
+	"github.com/shopspring/decimal"
 )
 
 type QuotationApi struct{}
@@ -195,8 +196,43 @@
 		return
 	}
 
+	for _, quotation := range quotations {
+		amount := decimal.NewFromInt(0)
+		for _, product := range quotation.Products {
+			amount = amount.Add(product.Total)
+		}
+		quotation.AmountTotal = amount
+	}
+
 	ctx.OkWithDetailed(response.QuotationResponse{
 		List:  quotations,
 		Count: int(total),
 	})
 }
+
+// Statistics
+//
+//	@Tags		Quotation
+//	@Summary	鎶ヤ环鍗曠粺璁�
+//	@Produce	application/json
+//	@Success	200		{object}	contextx.Response{data=map[string]int64}
+//	@Router		/api/quotation/statistics [get]
+func (con *QuotationApi) Statistics(c *gin.Context) {
+	ctx, ok := contextx.NewContext(c, nil)
+	if !ok {
+		return
+	}
+	m := make(map[string]int64)
+	total, _ := model.NewQuotationSearch(nil).Count()
+	m["total"] = total
+	//宸插垱寤�
+	created, _ := model.NewQuotationSearch(nil).SetQuotationStatusId(1).Count()
+	m["created"] = created
+	//宸插鎵�
+	approved, _ := model.NewQuotationSearch(nil).SetQuotationStatusId(3).Count()
+	m["approved"] = approved
+	//宸叉帴鍙�
+	accepted, _ := model.NewQuotationSearch(nil).SetQuotationStatusId(5).Count()
+	m["accepted"] = accepted
+	ctx.OkWithDetailed(m)
+}
diff --git a/api/v1/salesDetails.go b/api/v1/salesDetails.go
index abd1dd6..bae4856 100644
--- a/api/v1/salesDetails.go
+++ b/api/v1/salesDetails.go
@@ -1,7 +1,6 @@
 package v1
 
 import (
-	"aps_crm/conf"
 	"aps_crm/constvar"
 	"aps_crm/model"
 	"aps_crm/model/grpc_init"
@@ -16,9 +15,8 @@
 	"aps_crm/utils"
 	"github.com/gin-gonic/gin"
 	"github.com/shopspring/decimal"
-	"google.golang.org/grpc"
-	"google.golang.org/grpc/credentials/insecure"
 	"strconv"
+	"strings"
 )
 
 type SalesDetailsApi struct{}
@@ -239,25 +237,6 @@
 	ctx.Ok()
 }
 
-var (
-	ProductInventoryServiceConn *grpc.ClientConn
-)
-
-func InitProductInventoryServiceConn() {
-	var err error
-	ProductInventoryServiceConn, err = grpc.Dial(conf.Conf.GrpcServiceAddr.WMS, grpc.WithTransportCredentials(insecure.NewCredentials()))
-	if err != nil {
-		logx.Errorf("grpc dial product service error: %v", err.Error())
-		return
-	}
-}
-
-func CloseProductInventoryServiceConn() {
-	if ProductInventoryServiceConn != nil {
-		ProductInventoryServiceConn.Close()
-	}
-}
-
 // GetProductInventoryInfo
 //
 // @Tags		SalesDetails
@@ -273,9 +252,13 @@
 		return
 	}
 	number := c.Param("number")
-	client := product_inventory.NewProductInventoryServiceClient(ProductInventoryServiceConn)
+	client := product_inventory.NewProductInventoryServiceClient(grpc_init.ProductInventoryServiceConn)
 	info, err := client.GetInventoryProductInfo(ctx.GetCtx(), &product_inventory.GetInventoryProductInfoRequest{Number: number})
 	if err != nil {
+		if strings.Contains(err.Error(), "record not found") {
+			ctx.Ok()
+			return
+		}
 		logx.Errorf("GetProductInfo err: %v", err.Error())
 		ctx.FailWithMsg(ecode.UnknownErr, "grpc璋冪敤閿欒")
 		return
@@ -327,6 +310,15 @@
 	if !ok {
 		return
 	}
+	clientName := ""
+	if params.ClientId > 0 {
+		first, err := model.NewClientSearch(nil).SetId(params.ClientId).First()
+		if err != nil {
+			ctx.FailWithMsg(ecode.UnknownErr, "瀹㈡埛淇℃伅鏌ヨ澶辫触")
+			return
+		}
+		clientName = first.Name
+	}
 	m := make(map[string]interface{})
 	m["status"] = params.Status
 	m["project_id"] = params.ProjectId
@@ -344,7 +336,7 @@
 		p.Amount = product.Amount.String()
 		wmsProducts = append(wmsProducts, &p)
 	}
-	clientWms := product_inventory.NewProductInventoryServiceClient(ProductInventoryServiceConn)
+	clientWms := product_inventory.NewProductInventoryServiceClient(grpc_init.ProductInventoryServiceConn)
 	_, err = clientWms.CreateOperation(ctx.GetCtx(), &product_inventory.CreateOperationRequest{
 		Number:      params.Number,
 		Addressee:   params.Addressee,
@@ -352,6 +344,8 @@
 		Phone:       params.Phone,
 		DeliverType: int32(params.DeliverType),
 		Source:      "CRM",
+		ClientId:    int64(params.ClientId),
+		ClientName:  clientName,
 		ProductList: wmsProducts,
 	})
 	if err != nil {
diff --git a/api/v1/system_set.go b/api/v1/system_set.go
new file mode 100644
index 0000000..53403e8
--- /dev/null
+++ b/api/v1/system_set.go
@@ -0,0 +1,116 @@
+package v1
+
+import (
+	"aps_crm/constvar"
+	"aps_crm/model"
+	"aps_crm/model/request"
+	"aps_crm/pkg/contextx"
+	"aps_crm/pkg/ecode"
+	"aps_crm/service"
+	"github.com/gin-gonic/gin"
+	"gorm.io/gorm"
+)
+
+type SystemSetApi struct{}
+
+// GetSystemSet
+//
+//	@Tags		绯荤粺璁剧疆
+//	@Summary	鑾峰彇绯荤粺璁剧疆
+//	@Produce	application/json
+//	@Success	200		{object}	contextx.Response{data=map[string]interface{}}	"鎴愬姛"
+//	@Router		/api/system/getSystemSet [get]
+func (slf SystemSetApi) GetSystemSet(c *gin.Context) {
+	ctx, ok := contextx.NewContext(c, nil)
+	if !ok {
+		return
+	}
+	systemSet, err := service.GetSystemSet()
+	if err != nil {
+		ctx.FailWithMsg(ecode.UnknownErr, "鏌ヨ澶辫触")
+		return
+	}
+	constvar.SystemSet["CRM"] = systemSet
+	ctx.OkWithDetailed(constvar.SystemSet)
+}
+
+// SaveSystemSet
+//
+//	@Tags		绯荤粺璁剧疆
+//	@Summary	淇濆瓨绯荤粺璁剧疆
+//	@Produce	application/json
+//	@Param		object	body		request.SaveSystemSet	true	"鏌ヨ鍙傛暟"
+//	@Success	200		{object}	contextx.Response{}	"鎴愬姛"
+//	@Router		/api/system/saveSystemSet [post]
+func (slf SystemSetApi) SaveSystemSet(c *gin.Context) {
+	var params request.SaveSystemSet
+	ctx, ok := contextx.NewContext(c, &params)
+	if !ok {
+		return
+	}
+	err := model.WithTransaction(func(db *gorm.DB) error {
+		err := model.NewSystemSetSearch().SetOrm(db).DeleteAll()
+		if err != nil {
+			return err
+		}
+		err = model.NewSystemSetSearch().SetOrm(db).CreateBatch(params.Sets)
+		return err
+	})
+	if err != nil {
+		ctx.FailWithMsg(ecode.UnknownErr, "淇濆瓨澶辫触")
+		return
+	}
+	ctx.Ok()
+}
+
+// UseSystemSet
+//
+//	@Tags			绯荤粺璁剧疆
+//	@Summary		浣跨敤绯荤粺璁剧疆
+//	@Produce		application/json
+//	@Param			modeType	path		string	true	"鏌ヨ鍙傛暟"
+//	@Success		200	{object}	response.ListResponse
+//	@Router			/api/system/useSystemSet/{modeType} [get]
+func (slf *SystemSetApi) UseSystemSet(c *gin.Context) {
+	ctx, ok := contextx.NewContext(c, nil)
+	if !ok {
+		return
+	}
+	modeType := c.Param("modeType")
+	if modeType == "" {
+		ctx.FailWithMsg(ecode.UnknownErr, "鍙傛暟閿欒")
+		return
+	}
+	m := make(map[string]string)
+	systemSet, err := service.GetSystemSet()
+	if err != nil {
+		ctx.FailWithMsg(ecode.UnknownErr, "鏌ヨ澶辫触")
+		return
+	}
+	switch constvar.ModeType(modeType) {
+	case constvar.BjdMode:
+		value := systemSet["鎶ヤ环鍗曟槸鍚﹀繀椤诲叧鑱旈攢鍞満浼�"].((map[string]interface{}))["value"]
+		if value == "鏄�" {
+			m["Xsjh"] = "yes"
+		} else {
+			m["Xsjh"] = "no"
+		}
+	case constvar.XsmxMode:
+		value := systemSet["閿�鍞槑缁嗗崟鏄惁蹇呴』鍏宠仈鎶ヤ环鍗�"].((map[string]interface{}))["value"]
+		if value == "鏄�" {
+			m["Bjd"] = "yes"
+		} else {
+			m["Bjd"] = "no"
+		}
+		value = systemSet["閿�鍞槑缁嗗崟鏄惁蹇呴』鍏宠仈涓氬姟鏈轰細"].((map[string]interface{}))["value"]
+		if value == "鏄�" {
+			m["Ywjh"] = "yes"
+		} else {
+			m["Ywjh"] = "no"
+		}
+	default:
+		ctx.FailWithMsg(ecode.UnknownErr, "鍙傛暟閿欒")
+		return
+	}
+	ctx.OkWithDetailed(m)
+}
diff --git a/constvar/const.go b/constvar/const.go
index 1107c6f..c81270e 100644
--- a/constvar/const.go
+++ b/constvar/const.go
@@ -207,3 +207,43 @@
 const (
 	SystemType = 2
 )
+
+// ModeType 妯″潡绫诲瀷
+type ModeType string
+
+const (
+	BjdMode  ModeType = "bjd"
+	XsmxMode ModeType = "xsmx"
+)
+
+var SystemSet = map[string]interface{}{
+	"CRM": map[string]interface{}{
+		"鎶ヤ环鍗曟槸鍚﹀繀椤诲叧鑱旈攢鍞満浼�": map[string]interface{}{
+			"value": "鏄�",
+			"type":  "select",
+			"select": map[string]string{
+				"1": "鏄�",
+				"2": "鍚�",
+			},
+			"modeType": "bjd",
+		},
+		"閿�鍞槑缁嗗崟鏄惁蹇呴』鍏宠仈鎶ヤ环鍗�": map[string]interface{}{
+			"value": "鏄�",
+			"type":  "select",
+			"select": map[string]string{
+				"1": "鏄�",
+				"2": "鍚�",
+			},
+			"modeType": "xsmx",
+		},
+		"閿�鍞槑缁嗗崟鏄惁蹇呴』鍏宠仈涓氬姟鏈轰細": map[string]interface{}{
+			"value": "鏄�",
+			"type":  "select",
+			"select": map[string]string{
+				"1": "鏄�",
+				"2": "鍚�",
+			},
+			"modeType": "xsmx",
+		},
+	},
+}
diff --git a/constvar/salesDetails.go b/constvar/salesDetails.go
index b36d534..85902ec 100644
--- a/constvar/salesDetails.go
+++ b/constvar/salesDetails.go
@@ -18,3 +18,7 @@
 	OverOutbound                                //鍑哄簱瀹屾垚
 	OverCLose                                   //宸插叧闂�
 )
+
+func (s SalesDetailsStatus) Valid() bool {
+	return s == WaitConfirmed || s == WaitOutbound || s == OverOutbound || s == OverCLose
+}
diff --git a/docs/docs.go b/docs/docs.go
index f41e352..1455302 100644
--- a/docs/docs.go
+++ b/docs/docs.go
@@ -4947,10 +4947,7 @@
                                     "type": "object",
                                     "properties": {
                                         "data": {
-                                            "type": "array",
-                                            "items": {
-                                                "$ref": "#/definitions/product.WorkOrderInfo"
-                                            }
+                                            "$ref": "#/definitions/response.Info"
                                         }
                                     }
                                 }
@@ -5032,6 +5029,12 @@
                         "type": "string",
                         "description": "浜у搧缂栫爜",
                         "name": "productNumber",
+                        "in": "query"
+                    },
+                    {
+                        "type": "string",
+                        "description": "鎶ヤ环鍗曠紪鐮�",
+                        "name": "quotationNumber",
                         "in": "query"
                     }
                 ],
@@ -5311,6 +5314,40 @@
                                     "properties": {
                                         "data": {
                                             "$ref": "#/definitions/response.QuotationResponse"
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/quotation/statistics": {
+            "get": {
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "Quotation"
+                ],
+                "summary": "鎶ヤ环鍗曠粺璁�",
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/contextx.Response"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "object",
+                                            "additionalProperties": {
+                                                "type": "integer"
+                                            }
                                         }
                                     }
                                 }
@@ -9786,6 +9823,96 @@
                 }
             }
         },
+        "/api/system/getSystemSet": {
+            "get": {
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "绯荤粺璁剧疆"
+                ],
+                "summary": "鑾峰彇绯荤粺璁剧疆",
+                "responses": {
+                    "200": {
+                        "description": "鎴愬姛",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/contextx.Response"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "object",
+                                            "additionalProperties": true
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/system/saveSystemSet": {
+            "post": {
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "绯荤粺璁剧疆"
+                ],
+                "summary": "淇濆瓨绯荤粺璁剧疆",
+                "parameters": [
+                    {
+                        "description": "鏌ヨ鍙傛暟",
+                        "name": "object",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/request.SaveSystemSet"
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "鎴愬姛",
+                        "schema": {
+                            "$ref": "#/definitions/contextx.Response"
+                        }
+                    }
+                }
+            }
+        },
+        "/api/system/useSystemSet/{modeType}": {
+            "get": {
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "绯荤粺璁剧疆"
+                ],
+                "summary": "浣跨敤绯荤粺璁剧疆",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "鏌ヨ鍙傛暟",
+                        "name": "modeType",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/response.ListResponse"
+                        }
+                    }
+                }
+            }
+        },
         "/api/timeSpent/add": {
             "post": {
                 "produces": [
@@ -11843,11 +11970,17 @@
                 "amount": {
                     "type": "number"
                 },
+                "cost": {
+                    "type": "string"
+                },
                 "desc": {
                     "type": "string"
                 },
                 "id": {
                     "type": "integer"
+                },
+                "margin": {
+                    "type": "string"
                 },
                 "name": {
                     "type": "string"
@@ -11857,6 +11990,9 @@
                 },
                 "price": {
                     "type": "number"
+                },
+                "profit": {
+                    "type": "string"
                 },
                 "total": {
                     "type": "number"
@@ -11886,6 +12022,10 @@
         "model.Quotation": {
             "type": "object",
             "properties": {
+                "amountTotal": {
+                    "description": "浠锋牸鍚堣",
+                    "type": "number"
+                },
                 "client": {
                     "$ref": "#/definitions/model.Client"
                 },
@@ -13335,6 +13475,23 @@
                 }
             }
         },
+        "model.SystemSet": {
+            "type": "object",
+            "properties": {
+                "id": {
+                    "type": "integer"
+                },
+                "modeType": {
+                    "type": "string"
+                },
+                "name": {
+                    "type": "string"
+                },
+                "value": {
+                    "type": "string"
+                }
+            }
+        },
         "model.TimeSpent": {
             "type": "object",
             "properties": {
@@ -13474,32 +13631,6 @@
                     "type": "string"
                 },
                 "Unit": {
-                    "type": "string"
-                }
-            }
-        },
-        "product.WorkOrderInfo": {
-            "type": "object",
-            "properties": {
-                "EndTime": {
-                    "type": "string"
-                },
-                "OrderId": {
-                    "type": "string"
-                },
-                "OrderStatus": {
-                    "type": "string"
-                },
-                "ProductName": {
-                    "type": "string"
-                },
-                "StartTime": {
-                    "type": "string"
-                },
-                "WorkOrderId": {
-                    "type": "string"
-                },
-                "WorkOrderStatus": {
                     "type": "string"
                 }
             }
@@ -16310,6 +16441,17 @@
                             "$ref": "#/definitions/constvar.SalesReturnSourceType"
                         }
                     ]
+                }
+            }
+        },
+        "request.SaveSystemSet": {
+            "type": "object",
+            "properties": {
+                "sets": {
+                    "type": "array",
+                    "items": {
+                        "$ref": "#/definitions/model.SystemSet"
+                    }
                 }
             }
         },
@@ -19173,6 +19315,23 @@
                 }
             }
         },
+        "response.Info": {
+            "type": "object",
+            "properties": {
+                "makeInfo": {
+                    "type": "array",
+                    "items": {
+                        "$ref": "#/definitions/response.WorkOrderInfo"
+                    }
+                },
+                "purchaseInfo": {
+                    "type": "array",
+                    "items": {
+                        "$ref": "#/definitions/response.Purchase"
+                    }
+                }
+            }
+        },
         "response.IsInvoiceResponse": {
             "type": "object",
             "properties": {
@@ -19307,6 +19466,26 @@
                     "items": {
                         "$ref": "#/definitions/model.Province"
                     }
+                }
+            }
+        },
+        "response.Purchase": {
+            "type": "object",
+            "properties": {
+                "amount": {
+                    "type": "integer"
+                },
+                "purchaseName": {
+                    "type": "string"
+                },
+                "purchaseNumber": {
+                    "type": "string"
+                },
+                "status": {
+                    "type": "integer"
+                },
+                "supplierName": {
+                    "type": "string"
                 }
             }
         },
@@ -19615,6 +19794,32 @@
                     }
                 }
             }
+        },
+        "response.WorkOrderInfo": {
+            "type": "object",
+            "properties": {
+                "endTime": {
+                    "type": "string"
+                },
+                "orderId": {
+                    "type": "string"
+                },
+                "orderStatus": {
+                    "type": "string"
+                },
+                "productName": {
+                    "type": "string"
+                },
+                "startTime": {
+                    "type": "string"
+                },
+                "workOrderId": {
+                    "type": "string"
+                },
+                "workOrderStatus": {
+                    "type": "string"
+                }
+            }
         }
     }
 }`
diff --git a/docs/swagger.json b/docs/swagger.json
index 349a879..431fd5d 100644
--- a/docs/swagger.json
+++ b/docs/swagger.json
@@ -4935,10 +4935,7 @@
                                     "type": "object",
                                     "properties": {
                                         "data": {
-                                            "type": "array",
-                                            "items": {
-                                                "$ref": "#/definitions/product.WorkOrderInfo"
-                                            }
+                                            "$ref": "#/definitions/response.Info"
                                         }
                                     }
                                 }
@@ -5020,6 +5017,12 @@
                         "type": "string",
                         "description": "浜у搧缂栫爜",
                         "name": "productNumber",
+                        "in": "query"
+                    },
+                    {
+                        "type": "string",
+                        "description": "鎶ヤ环鍗曠紪鐮�",
+                        "name": "quotationNumber",
                         "in": "query"
                     }
                 ],
@@ -5299,6 +5302,40 @@
                                     "properties": {
                                         "data": {
                                             "$ref": "#/definitions/response.QuotationResponse"
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/quotation/statistics": {
+            "get": {
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "Quotation"
+                ],
+                "summary": "鎶ヤ环鍗曠粺璁�",
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/contextx.Response"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "object",
+                                            "additionalProperties": {
+                                                "type": "integer"
+                                            }
                                         }
                                     }
                                 }
@@ -9774,6 +9811,96 @@
                 }
             }
         },
+        "/api/system/getSystemSet": {
+            "get": {
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "绯荤粺璁剧疆"
+                ],
+                "summary": "鑾峰彇绯荤粺璁剧疆",
+                "responses": {
+                    "200": {
+                        "description": "鎴愬姛",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/contextx.Response"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "object",
+                                            "additionalProperties": true
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/system/saveSystemSet": {
+            "post": {
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "绯荤粺璁剧疆"
+                ],
+                "summary": "淇濆瓨绯荤粺璁剧疆",
+                "parameters": [
+                    {
+                        "description": "鏌ヨ鍙傛暟",
+                        "name": "object",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/request.SaveSystemSet"
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "鎴愬姛",
+                        "schema": {
+                            "$ref": "#/definitions/contextx.Response"
+                        }
+                    }
+                }
+            }
+        },
+        "/api/system/useSystemSet/{modeType}": {
+            "get": {
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "绯荤粺璁剧疆"
+                ],
+                "summary": "浣跨敤绯荤粺璁剧疆",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "鏌ヨ鍙傛暟",
+                        "name": "modeType",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/response.ListResponse"
+                        }
+                    }
+                }
+            }
+        },
         "/api/timeSpent/add": {
             "post": {
                 "produces": [
@@ -11831,11 +11958,17 @@
                 "amount": {
                     "type": "number"
                 },
+                "cost": {
+                    "type": "string"
+                },
                 "desc": {
                     "type": "string"
                 },
                 "id": {
                     "type": "integer"
+                },
+                "margin": {
+                    "type": "string"
                 },
                 "name": {
                     "type": "string"
@@ -11845,6 +11978,9 @@
                 },
                 "price": {
                     "type": "number"
+                },
+                "profit": {
+                    "type": "string"
                 },
                 "total": {
                     "type": "number"
@@ -11874,6 +12010,10 @@
         "model.Quotation": {
             "type": "object",
             "properties": {
+                "amountTotal": {
+                    "description": "浠锋牸鍚堣",
+                    "type": "number"
+                },
                 "client": {
                     "$ref": "#/definitions/model.Client"
                 },
@@ -13323,6 +13463,23 @@
                 }
             }
         },
+        "model.SystemSet": {
+            "type": "object",
+            "properties": {
+                "id": {
+                    "type": "integer"
+                },
+                "modeType": {
+                    "type": "string"
+                },
+                "name": {
+                    "type": "string"
+                },
+                "value": {
+                    "type": "string"
+                }
+            }
+        },
         "model.TimeSpent": {
             "type": "object",
             "properties": {
@@ -13462,32 +13619,6 @@
                     "type": "string"
                 },
                 "Unit": {
-                    "type": "string"
-                }
-            }
-        },
-        "product.WorkOrderInfo": {
-            "type": "object",
-            "properties": {
-                "EndTime": {
-                    "type": "string"
-                },
-                "OrderId": {
-                    "type": "string"
-                },
-                "OrderStatus": {
-                    "type": "string"
-                },
-                "ProductName": {
-                    "type": "string"
-                },
-                "StartTime": {
-                    "type": "string"
-                },
-                "WorkOrderId": {
-                    "type": "string"
-                },
-                "WorkOrderStatus": {
                     "type": "string"
                 }
             }
@@ -16298,6 +16429,17 @@
                             "$ref": "#/definitions/constvar.SalesReturnSourceType"
                         }
                     ]
+                }
+            }
+        },
+        "request.SaveSystemSet": {
+            "type": "object",
+            "properties": {
+                "sets": {
+                    "type": "array",
+                    "items": {
+                        "$ref": "#/definitions/model.SystemSet"
+                    }
                 }
             }
         },
@@ -19161,6 +19303,23 @@
                 }
             }
         },
+        "response.Info": {
+            "type": "object",
+            "properties": {
+                "makeInfo": {
+                    "type": "array",
+                    "items": {
+                        "$ref": "#/definitions/response.WorkOrderInfo"
+                    }
+                },
+                "purchaseInfo": {
+                    "type": "array",
+                    "items": {
+                        "$ref": "#/definitions/response.Purchase"
+                    }
+                }
+            }
+        },
         "response.IsInvoiceResponse": {
             "type": "object",
             "properties": {
@@ -19295,6 +19454,26 @@
                     "items": {
                         "$ref": "#/definitions/model.Province"
                     }
+                }
+            }
+        },
+        "response.Purchase": {
+            "type": "object",
+            "properties": {
+                "amount": {
+                    "type": "integer"
+                },
+                "purchaseName": {
+                    "type": "string"
+                },
+                "purchaseNumber": {
+                    "type": "string"
+                },
+                "status": {
+                    "type": "integer"
+                },
+                "supplierName": {
+                    "type": "string"
                 }
             }
         },
@@ -19603,6 +19782,32 @@
                     }
                 }
             }
+        },
+        "response.WorkOrderInfo": {
+            "type": "object",
+            "properties": {
+                "endTime": {
+                    "type": "string"
+                },
+                "orderId": {
+                    "type": "string"
+                },
+                "orderStatus": {
+                    "type": "string"
+                },
+                "productName": {
+                    "type": "string"
+                },
+                "startTime": {
+                    "type": "string"
+                },
+                "workOrderId": {
+                    "type": "string"
+                },
+                "workOrderStatus": {
+                    "type": "string"
+                }
+            }
         }
     }
 }
\ No newline at end of file
diff --git a/docs/swagger.yaml b/docs/swagger.yaml
index 853f908..cd49b10 100644
--- a/docs/swagger.yaml
+++ b/docs/swagger.yaml
@@ -1118,16 +1118,22 @@
     properties:
       amount:
         type: number
+      cost:
+        type: string
       desc:
         type: string
       id:
         type: integer
+      margin:
+        type: string
       name:
         type: string
       number:
         type: string
       price:
         type: number
+      profit:
+        type: string
       total:
         type: number
       unit:
@@ -1146,6 +1152,9 @@
     type: object
   model.Quotation:
     properties:
+      amountTotal:
+        description: 浠锋牸鍚堣
+        type: number
       client:
         $ref: '#/definitions/model.Client'
       client_id:
@@ -2111,6 +2120,17 @@
           $ref: '#/definitions/model.Product'
         type: array
     type: object
+  model.SystemSet:
+    properties:
+      id:
+        type: integer
+      modeType:
+        type: string
+      name:
+        type: string
+      value:
+        type: string
+    type: object
   model.TimeSpent:
     properties:
       id:
@@ -2207,23 +2227,6 @@
         description: 鍨嬪彿
         type: string
       Unit:
-        type: string
-    type: object
-  product.WorkOrderInfo:
-    properties:
-      EndTime:
-        type: string
-      OrderId:
-        type: string
-      OrderStatus:
-        type: string
-      ProductName:
-        type: string
-      StartTime:
-        type: string
-      WorkOrderId:
-        type: string
-      WorkOrderStatus:
         type: string
     type: object
   request.AddAccountId:
@@ -4154,6 +4157,13 @@
         allOf:
         - $ref: '#/definitions/constvar.SalesReturnSourceType'
         description: 婧愬崟绫诲瀷锛�1閿�鍞槑缁嗭級
+    type: object
+  request.SaveSystemSet:
+    properties:
+      sets:
+        items:
+          $ref: '#/definitions/model.SystemSet'
+        type: array
     type: object
   request.SetAuthorityMenu:
     properties:
@@ -6087,6 +6097,17 @@
           $ref: '#/definitions/model.Industry'
         type: array
     type: object
+  response.Info:
+    properties:
+      makeInfo:
+        items:
+          $ref: '#/definitions/response.WorkOrderInfo'
+        type: array
+      purchaseInfo:
+        items:
+          $ref: '#/definitions/response.Purchase'
+        type: array
+    type: object
   response.IsInvoiceResponse:
     properties:
       list:
@@ -6174,6 +6195,19 @@
         items:
           $ref: '#/definitions/model.Province'
         type: array
+    type: object
+  response.Purchase:
+    properties:
+      amount:
+        type: integer
+      purchaseName:
+        type: string
+      purchaseNumber:
+        type: string
+      status:
+        type: integer
+      supplierName:
+        type: string
     type: object
   response.QuotationResponse:
     properties:
@@ -6370,6 +6404,23 @@
         items:
           $ref: '#/definitions/model.TimelyRate'
         type: array
+    type: object
+  response.WorkOrderInfo:
+    properties:
+      endTime:
+        type: string
+      orderId:
+        type: string
+      orderStatus:
+        type: string
+      productName:
+        type: string
+      startTime:
+        type: string
+      workOrderId:
+        type: string
+      workOrderStatus:
+        type: string
     type: object
 info:
   contact: {}
@@ -9408,9 +9459,7 @@
             - $ref: '#/definitions/contextx.Response'
             - properties:
                 data:
-                  items:
-                    $ref: '#/definitions/product.WorkOrderInfo'
-                  type: array
+                  $ref: '#/definitions/response.Info'
               type: object
       summary: 鑾峰彇浜у搧璁㈠崟淇℃伅
       tags:
@@ -9456,6 +9505,10 @@
       - description: 浜у搧缂栫爜
         in: query
         name: productNumber
+        type: string
+      - description: 鎶ヤ环鍗曠紪鐮�
+        in: query
+        name: quotationNumber
         type: string
       produces:
       - application/json
@@ -9632,6 +9685,25 @@
                   $ref: '#/definitions/response.QuotationResponse'
               type: object
       summary: 鎶ヤ环鍗曞垪琛�
+      tags:
+      - Quotation
+  /api/quotation/statistics:
+    get:
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            allOf:
+            - $ref: '#/definitions/contextx.Response'
+            - properties:
+                data:
+                  additionalProperties:
+                    type: integer
+                  type: object
+              type: object
+      summary: 鎶ヤ环鍗曠粺璁�
       tags:
       - Quotation
   /api/quotation/update:
@@ -12395,6 +12467,61 @@
       summary: 鏇存柊瀛愯鍗�
       tags:
       - SubOrder
+  /api/system/getSystemSet:
+    get:
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: 鎴愬姛
+          schema:
+            allOf:
+            - $ref: '#/definitions/contextx.Response'
+            - properties:
+                data:
+                  additionalProperties: true
+                  type: object
+              type: object
+      summary: 鑾峰彇绯荤粺璁剧疆
+      tags:
+      - 绯荤粺璁剧疆
+  /api/system/saveSystemSet:
+    post:
+      parameters:
+      - description: 鏌ヨ鍙傛暟
+        in: body
+        name: object
+        required: true
+        schema:
+          $ref: '#/definitions/request.SaveSystemSet'
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: 鎴愬姛
+          schema:
+            $ref: '#/definitions/contextx.Response'
+      summary: 淇濆瓨绯荤粺璁剧疆
+      tags:
+      - 绯荤粺璁剧疆
+  /api/system/useSystemSet/{modeType}:
+    get:
+      parameters:
+      - description: 鏌ヨ鍙傛暟
+        in: path
+        name: modeType
+        required: true
+        type: string
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/response.ListResponse'
+      summary: 浣跨敤绯荤粺璁剧疆
+      tags:
+      - 绯荤粺璁剧疆
   /api/timeSpent/add:
     post:
       parameters:
diff --git a/go.mod b/go.mod
index 6fb32ea..93dacb0 100644
--- a/go.mod
+++ b/go.mod
@@ -13,8 +13,7 @@
 	github.com/gofrs/uuid v4.4.0+incompatible
 	github.com/golang-jwt/jwt/v4 v4.5.0
 	github.com/gorilla/websocket v1.5.0
-	github.com/mojocn/base64Captcha v1.3.5
-	github.com/pkg/errors v0.9.1
+	github.com/hashicorp/golang-lru/v2 v2.0.7
 	github.com/robfig/cron/v3 v3.0.1
 	github.com/shopspring/decimal v1.3.1
 	github.com/songzhibin97/gkit v1.2.11
@@ -35,10 +34,7 @@
 	moul.io/zapgorm2 v1.3.0
 )
 
-require (
-	github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
-	google.golang.org/genproto/googleapis/api v0.0.0-20230726155614-23370e0ffb3e // indirect
-)
+require google.golang.org/genproto/googleapis/api v0.0.0-20230726155614-23370e0ffb3e // indirect
 
 require (
 	github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible // indirect
@@ -68,7 +64,6 @@
 	github.com/gogo/protobuf v1.3.2 // indirect
 	github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect
 	github.com/golang-sql/sqlexp v0.1.0 // indirect
-	github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
 	github.com/golang/protobuf v1.5.3 // indirect
 	github.com/google/uuid v1.3.0 // indirect
 	github.com/hashicorp/hcl v1.0.0 // indirect
@@ -104,7 +99,6 @@
 	go.etcd.io/etcd/api/v3 v3.5.9 // indirect
 	go.uber.org/multierr v1.10.0 // indirect
 	golang.org/x/arch v0.3.0 // indirect
-	golang.org/x/image v0.5.0 // indirect
 	golang.org/x/net v0.14.0 // indirect
 	golang.org/x/sys v0.11.0 // indirect
 	golang.org/x/text v0.12.0 // indirect
diff --git a/go.sum b/go.sum
index 15a16ee..03c9ac9 100644
--- a/go.sum
+++ b/go.sum
@@ -46,8 +46,6 @@
 github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
 github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
 github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
-github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
-github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
 github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
 github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A=
 github.com/bsm/ginkgo/v2 v2.7.0 h1:ItPMPH90RbmZJt5GtkcNvIRuGEdwlBItdNVoyzaNQao=
@@ -144,7 +142,6 @@
 github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
 github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI=
 github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
-github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
 github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
 github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
 github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
@@ -162,8 +159,6 @@
 github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
 github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A=
 github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI=
-github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
-github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
 github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
 github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
 github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
@@ -232,7 +227,6 @@
 github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
 github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
 github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
-github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
 github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
 github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
 github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
@@ -243,16 +237,10 @@
 github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
 github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
 github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
-github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
-github.com/jackc/pgconn v1.13.0/go.mod h1:AnowpAqO4CMIIJNZl2VJp+KrkAZciAkhEl0W0JIobpI=
-github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8=
 github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
 github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
-github.com/jackc/pgproto3/v2 v2.3.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
 github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
 github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
-github.com/jackc/pgtype v1.12.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4=
-github.com/jackc/pgx/v4 v4.17.2/go.mod h1:lcxIZN44yMIrWI78a5CpucdD14hX0SBDbNRvjDBItsw=
 github.com/jackc/pgx/v5 v5.3.1 h1:Fcr8QJ1ZeLi5zsPZqQeUZhNhxfkkKBOgJuYkJHoBOtU=
 github.com/jackc/pgx/v5 v5.3.1/go.mod h1:t3JDKnCBlYIc0ewLF0Q7B8MXmoIaBOZj/ic7iHozM/8=
 github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs=
@@ -291,7 +279,6 @@
 github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
 github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
 github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8=
-github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
 github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
 github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
 github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
@@ -312,12 +299,9 @@
 github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
 github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
 github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8=
-github.com/mojocn/base64Captcha v1.3.5 h1:Qeilr7Ta6eDtG4S+tQuZ5+hO+QHbiGAJdi4PfoagaA0=
-github.com/mojocn/base64Captcha v1.3.5/go.mod h1:/tTTXn4WTpX9CfrmipqRytCpJ27Uw3G6I7NcP2WwcmY=
 github.com/montanaflynn/stats v0.7.0/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
 github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
 github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
-github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
 github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
 github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE=
 github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo=
@@ -326,7 +310,6 @@
 github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI=
 github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
 github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
-github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
 github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
@@ -449,10 +432,7 @@
 golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
 golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
 golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
-golang.org/x/image v0.0.0-20190501045829-6d32002ffd75/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
 golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
-golang.org/x/image v0.5.0 h1:5JMiNunQeQw++mMOz48/ISeNu3Iweh/JaZU8ZLqHRrI=
-golang.org/x/image v0.5.0/go.mod h1:FVC7BI/5Ym8R25iw5OLsgshdUBbT1h5jZTpA+mvAdZ4=
 golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
 golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
 golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@@ -784,7 +764,6 @@
 gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU=
 gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c=
 gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
-gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
 gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
diff --git a/main.go b/main.go
index bd94e74..04c6993 100644
--- a/main.go
+++ b/main.go
@@ -1,7 +1,6 @@
 package main
 
 import (
-	v1 "aps_crm/api/v1"
 	"aps_crm/conf"
 	"aps_crm/initialize"
 	"aps_crm/middleware"
@@ -53,7 +52,7 @@
 	}
 	//鍚姩grpc瀹㈡埛绔�
 	go middleware.InitUserConn()
-	go v1.InitProductInventoryServiceConn()
+	go grpc_init.InitProductInventoryServiceConn()
 	go grpc_init.InitCrmApsGrpcServiceConn()
 	//鍚姩grpc鏈嶅姟
 	go func() {
@@ -86,7 +85,7 @@
 	<-quit
 
 	middleware.StopRefreshUser()
-	v1.CloseProductInventoryServiceConn()
+	grpc_init.CloseProductInventoryServiceConn()
 	middleware.CloseUserConn()
 	grpc_init.CloseCrmApsGrpcServiceConn()
 
diff --git a/model/city.go b/model/city.go
index ade9ca7..26fdf5a 100644
--- a/model/city.go
+++ b/model/city.go
@@ -3,6 +3,7 @@
 import (
 	"aps_crm/pkg/mysqlx"
 	"gorm.io/gorm"
+	"sync"
 )
 
 type (
@@ -109,23 +110,23 @@
 	return list, err
 }
 
-// InitDefaultCity 鍒濆鍖栭粯璁ゅ煄甯�
-func InitDefaultCity() error {
-	records := []*City{
-		{
-			Name: "鍖椾含甯�",
-		},
+// InitDefaultData 鍒濆鍖栨暟鎹�
+func (slf *CitySearch) InitDefaultData(errCh chan<- error, wg *sync.WaitGroup) {
+	var (
+		db          = slf.Orm.Table(slf.TableName())
+		total int64 = 0
+	)
+	if err := db.Count(&total).Error; err != nil {
+		errCh <- err
+		return
 	}
-
-	var db = mysqlx.GetDB()
-	for _, record := range records {
-		var city City
-		if err := db.Where("name = ?", record.Name).First(&city).Error; err != nil {
-			if err := db.Create(record).Error; err != nil {
-				return err
-			}
-		}
+	if total != 0 {
+		return
 	}
-
-	return nil
+	sql := "INSERT INTO `city` VALUES (73,'鍖椾含甯�',29,NULL,NULL),(74,'澶╂触甯�',30,NULL,NULL),(75,'鐧介摱甯�',56,NULL,NULL),(76,'澶╂按甯�',56,NULL,NULL),(77,'姝﹀▉甯�',56,NULL,NULL),(78,'寮犳帠甯�',56,NULL,NULL),(79,'骞冲噳甯�',56,NULL,NULL),(80,'閰掓硥甯�',56,NULL,NULL),(81,'搴嗛槼甯�',56,NULL,NULL),(82,'瀹氳タ甯�',56,NULL,NULL),(83,'闄囧崡甯�',56,NULL,NULL),(84,'涓村鍥炴棌鑷不宸�',56,NULL,NULL),(85,'鐢樺崡钘忔棌鑷不宸�',56,NULL,NULL),(86,'瑗垮畞甯�',57,NULL,NULL),(87,'娴蜂笢甯�',57,NULL,NULL),(88,'娴峰寳钘忔棌鑷不宸�',57,NULL,NULL),(89,'榛勫崡钘忔棌鑷不宸�',57,NULL,NULL),(90,'娴峰崡钘忔棌鑷不宸�',57,NULL,NULL),(91,'鏋滄礇钘忔棌鑷不宸�',57,NULL,NULL),(92,'鐜夋爲钘忔棌鑷不宸�',57,NULL,NULL),(93,'娴疯タ钂欏彜鏃忚棌鏃忚嚜娌诲窞',57,NULL,NULL),(94,'閾跺窛甯�',58,NULL,NULL),(95,'鐭冲槾灞卞競',58,NULL,NULL),(96,'鍚村繝甯�',58,NULL,NULL),(97,'鍥哄師甯�',58,NULL,NULL),(98,'涓崼甯�',58,NULL,NULL),(99,'涔岄瞾鏈ㄩ綈甯�',59,NULL,NULL),(100,'鍏嬫媺鐜涗緷甯�',59,NULL,NULL),(101,'鍚愰瞾鐣競',59,NULL,NULL),(102,'鍝堝瘑甯�',59,NULL,NULL),(103,'鏄屽悏鍥炴棌鑷不宸�',59,NULL,NULL),(104,'鍗氬皵濉旀媺钂欏彜鑷不宸�',59,NULL,NULL),(105,'宸撮煶閮钂欏彜鑷不宸�',59,NULL,NULL),(106,'闃垮厠鑻忓湴鍖�',59,NULL,NULL),(107,'鍏嬪瓬鍕掕嫃鏌皵鍏嬪瓬鑷不宸�',59,NULL,NULL),(108,'鍠�浠�鍦板尯',59,NULL,NULL),(109,'鍜岀敯鍦板尯',59,NULL,NULL),(110,'浼婄妬鍝堣惃鍏嬭嚜娌诲窞',59,NULL,NULL),(111,'濉斿煄鍦板尯',59,NULL,NULL),(112,'闃垮嫆娉板湴鍖�',59,NULL,NULL),(113,'鐭虫渤瀛愬競',59,NULL,NULL),(114,'闃挎媺灏斿競',59,NULL,NULL),(115,'鍥炬湪鑸掑厠甯�',59,NULL,NULL),(116,'浜斿娓犲競',59,NULL,NULL),(117,'鍖楀悲甯�',59,NULL,NULL),(118,'閾侀棬鍏冲競',59,NULL,NULL),(119,'鍙屾渤甯�',59,NULL,NULL),(120,'鍙厠杈炬媺甯�',59,NULL,NULL),(121,'鏄嗙帀甯�',59,NULL,NULL),(122,'鍙板寳甯�',60,NULL,NULL),(123,'楂橀泟甯�',60,NULL,NULL),(124,'鏂板寳甯�',60,NULL,NULL),(125,'鍙颁腑甯�',60,NULL,NULL),(126,'鍙板崡甯�',60,NULL,NULL),(127,'妗冨洯甯�',60,NULL,NULL),(128,'鍩洪殕甯�',60,NULL,NULL),(129,'鏂扮甯�',60,NULL,NULL),(130,'鍢変箟甯�',60,NULL,NULL),(131,'鏂扮鍘�',60,NULL,NULL),(132,'瀹滃叞鍘�',60,NULL,NULL),(133,'鑻楁牀鍘�',60,NULL,NULL),(134,'褰板寲鍘�',60,NULL,NULL),(135,'浜戞灄鍘�',60,NULL,NULL),(136,'鍗楁姇鍘�',60,NULL,NULL),(137,'鍢変箟鍘�',60,NULL,NULL),(138,'灞忎笢鍘�',60,NULL,NULL),(139,'鍙颁笢鍘�',60,NULL,NULL),(140,'鑺辫幉鍘�',60,NULL,NULL),(141,'婢庢箹鍘�',60,NULL,NULL),(142,'棣欐腐',61,NULL,NULL),(143,'婢抽棬',62,NULL,NULL),(144,'鍏板窞甯�',56,NULL,NULL),(145,'鍢夊唱鍏冲競',56,NULL,NULL),(146,'閲戞槍甯�',56,NULL,NULL),(147,'骞垮厓甯�',51,NULL,NULL),(148,'閬傚畞甯�',51,NULL,NULL),(149,'鍐呮睙甯�',51,NULL,NULL),(150,'涔愬北甯�',51,NULL,NULL),(151,'鍗楀厖甯�',51,NULL,NULL),(152,'鐪夊北甯�',51,NULL,NULL),(153,'瀹滃甯�',51,NULL,NULL),(154,'骞垮畨甯�',51,NULL,NULL),(155,'杈惧窞甯�',51,NULL,NULL),(156,'闆呭畨甯�',51,NULL,NULL),(157,'宸翠腑甯�',51,NULL,NULL),(158,'璧勯槼甯�',51,NULL,NULL),(159,'闃垮潩钘忔棌缇屾棌鑷不宸�',51,NULL,NULL),(160,'鐢樺瓬钘忔棌鑷不宸�',51,NULL,NULL),(161,'鍑夊北褰濇棌鑷不宸�',51,NULL,NULL),(162,'璐甸槼甯�',52,NULL,NULL),(163,'鍏洏姘村競',52,NULL,NULL),(164,'閬典箟甯�',52,NULL,NULL),(165,'瀹夐『甯�',52,NULL,NULL),(166,'姣曡妭甯�',52,NULL,NULL),(167,'閾滀粊甯�',52,NULL,NULL),(168,'榛旇タ鍗楀竷渚濇棌鑻楁棌鑷不宸�',52,NULL,NULL),(169,'榛斾笢鍗楄嫍鏃忎緱鏃忚嚜娌诲窞',52,NULL,NULL),(170,'榛斿崡甯冧緷鏃忚嫍鏃忚嚜娌诲窞',52,NULL,NULL),(171,'鏄嗘槑甯�',53,NULL,NULL),(172,'鏇查潠甯�',53,NULL,NULL),(173,'鐜夋邯甯�',53,NULL,NULL),(174,'淇濆北甯�',53,NULL,NULL),(175,'鏄�氬競',53,NULL,NULL),(176,'涓芥睙甯�',53,NULL,NULL),(177,'鏅幢甯�',53,NULL,NULL),(178,'涓存钵甯�',53,NULL,NULL),(179,'妤氶泟褰濇棌鑷不宸�',53,NULL,NULL),(180,'绾㈡渤鍝堝凹鏃忓綕鏃忚嚜娌诲窞',53,NULL,NULL),(181,'鏂囧北澹棌鑻楁棌鑷不宸�',53,NULL,NULL),(182,'瑗垮弻鐗堢撼鍌f棌鑷不宸�',53,NULL,NULL),(183,'澶х悊鐧芥棌鑷不宸�',53,NULL,NULL),(184,'寰峰畯鍌f棌鏅鏃忚嚜娌诲窞',53,NULL,NULL),(185,'鎬掓睙鍌堝兂鏃忚嚜娌诲窞',53,NULL,NULL),(186,'杩簡钘忔棌鑷不宸�',53,NULL,NULL),(187,'鎷夎惃甯�',54,NULL,NULL),(188,'鏃ュ杸鍒欏競',54,NULL,NULL),(189,'鏄岄兘甯�',54,NULL,NULL),(190,'鏋楄姖甯�',54,NULL,NULL),(191,'灞卞崡甯�',54,NULL,NULL),(192,'閭f洸甯�',54,NULL,NULL),(193,'闃块噷鍦板尯',54,NULL,NULL),(194,'瑗垮畨甯�',55,NULL,NULL),(195,'閾滃窛甯�',55,NULL,NULL),(196,'瀹濋浮甯�',55,NULL,NULL),(197,'鍜搁槼甯�',55,NULL,NULL),(198,'娓崡甯�',55,NULL,NULL),(199,'寤跺畨甯�',55,NULL,NULL),(200,'姹変腑甯�',55,NULL,NULL),(201,'姒嗘灄甯�',55,NULL,NULL),(202,'瀹夊悍甯�',55,NULL,NULL),(203,'鍟嗘礇甯�',55,NULL,NULL),(204,'鍗楀畞甯�',48,NULL,NULL),(205,'鏌冲窞甯�',48,NULL,NULL),(206,'妗傛灄甯�',48,NULL,NULL),(207,'姊у窞甯�',48,NULL,NULL),(208,'鍖楁捣甯�',48,NULL,NULL),(209,'闃插煄娓競',48,NULL,NULL),(210,'閽﹀窞甯�',48,NULL,NULL),(211,'璐垫腐甯�',48,NULL,NULL),(212,'鐜夋灄甯�',48,NULL,NULL),(213,'鐧捐壊甯�',48,NULL,NULL),(214,'璐哄窞甯�',48,NULL,NULL),(215,'娌虫睜甯�',48,NULL,NULL),(216,'鏉ュ甯�',48,NULL,NULL),(217,'宕囧乏甯�',48,NULL,NULL),(218,'娴峰彛甯�',49,NULL,NULL),(219,'涓変簹甯�',49,NULL,NULL),(220,'涓夋矙甯�',49,NULL,NULL),(221,'鍎嬪窞甯�',49,NULL,NULL),(222,'浜旀寚灞卞競',49,NULL,NULL),(223,'鐞兼捣甯�',49,NULL,NULL),(224,'鏂囨槍甯�',49,NULL,NULL),(225,'涓囧畞甯�',49,NULL,NULL),(226,'涓滄柟甯�',49,NULL,NULL),(227,'瀹氬畨鍘�',49,NULL,NULL),(228,'灞槍鍘�',49,NULL,NULL),(229,'婢勮繄鍘�',49,NULL,NULL),(230,'涓撮珮鍘�',49,NULL,NULL),(231,'鐧芥矙榛庢棌鑷不鍘�',49,NULL,NULL),(232,'鏄屾睙榛庢棌鑷不鍘�',49,NULL,NULL),(233,'涔愪笢榛庢棌鑷不鍘�',49,NULL,NULL),(234,'闄垫按榛庢棌鑷不鍘�',49,NULL,NULL),(235,'淇濅涵榛庢棌鑻楁棌鑷不鍘�',49,NULL,NULL),(236,'鐞间腑榛庢棌鑻楁棌鑷不鍘�',49,NULL,NULL),(237,'閲嶅簡甯�',50,NULL,NULL),(238,'閲嶅簡甯�',50,NULL,NULL),(239,'鎴愰兘甯�',51,NULL,NULL),(240,'鑷础甯�',51,NULL,NULL),(241,'鏀�鏋濊姳甯�',51,NULL,NULL),(242,'娉稿窞甯�',51,NULL,NULL),(243,'寰烽槼甯�',51,NULL,NULL),(244,'缁甸槼甯�',51,NULL,NULL),(245,'涓婃捣甯�',37,NULL,NULL),(246,'鍗椾含甯�',38,NULL,NULL),(247,'鏃犻敗甯�',38,NULL,NULL),(248,'寰愬窞甯�',38,NULL,NULL),(249,'甯稿窞甯�',38,NULL,NULL),(250,'鑻忓窞甯�',38,NULL,NULL),(251,'鍗楅�氬競',38,NULL,NULL),(252,'杩炰簯娓競',38,NULL,NULL),(253,'娣畨甯�',38,NULL,NULL),(254,'鐩愬煄甯�',38,NULL,NULL),(255,'鎵窞甯�',38,NULL,NULL),(256,'闀囨睙甯�',38,NULL,NULL),(257,'娉板窞甯�',38,NULL,NULL),(258,'瀹胯縼甯�',38,NULL,NULL),(259,'鏉窞甯�',39,NULL,NULL),(260,'瀹佹尝甯�',39,NULL,NULL),(261,'娓╁窞甯�',39,NULL,NULL),(262,'鍢夊叴甯�',39,NULL,NULL),(263,'婀栧窞甯�',39,NULL,NULL),(264,'缁嶅叴甯�',39,NULL,NULL),(265,'閲戝崕甯�',39,NULL,NULL),(266,'琛㈠窞甯�',39,NULL,NULL),(267,'鑸熷北甯�',39,NULL,NULL),(268,'鍙板窞甯�',39,NULL,NULL),(269,'涓芥按甯�',39,NULL,NULL),(270,'鍚堣偉甯�',40,NULL,NULL),(271,'鑺滄箹甯�',40,NULL,NULL),(272,'铓屽煚甯�',40,NULL,NULL),(273,'娣崡甯�',40,NULL,NULL),(274,'椹瀺灞卞競',40,NULL,NULL),(275,'娣寳甯�',40,NULL,NULL),(276,'閾滈櫟甯�',40,NULL,NULL),(277,'瀹夊簡甯�',40,NULL,NULL),(278,'榛勫北甯�',40,NULL,NULL),(279,'婊佸窞甯�',40,NULL,NULL),(280,'闃滈槼甯�',40,NULL,NULL),(281,'瀹垮窞甯�',40,NULL,NULL),(282,'鍏畨甯�',40,NULL,NULL),(283,'浜冲窞甯�',40,NULL,NULL),(284,'姹犲窞甯�',40,NULL,NULL),(285,'瀹e煄甯�',40,NULL,NULL),(286,'绂忓窞甯�',41,NULL,NULL),(287,'鍘﹂棬甯�',41,NULL,NULL),(288,'鑾嗙敯甯�',41,NULL,NULL),(289,'涓夋槑甯�',41,NULL,NULL),(290,'娉夊窞甯�',41,NULL,NULL),(291,'婕冲窞甯�',41,NULL,NULL),(292,'鍗楀钩甯�',41,NULL,NULL),(293,'榫欏博甯�',41,NULL,NULL),(294,'瀹佸痉甯�',41,NULL,NULL),(295,'鍗楁槍甯�',42,NULL,NULL),(296,'鏅痉闀囧競',42,NULL,NULL),(297,'钀嶄埂甯�',42,NULL,NULL),(298,'涔濇睙甯�',42,NULL,NULL),(299,'鏂颁綑甯�',42,NULL,NULL),(300,'楣版江甯�',42,NULL,NULL),(301,'璧e窞甯�',42,NULL,NULL),(302,'鍚夊畨甯�',42,NULL,NULL),(303,'瀹滄槬甯�',42,NULL,NULL),(304,'鎶氬窞甯�',42,NULL,NULL),(305,'涓婇ザ甯�',42,NULL,NULL),(306,'娴庡崡甯�',43,NULL,NULL),(307,'闈掑矝甯�',43,NULL,NULL),(308,'娣勫崥甯�',43,NULL,NULL),(309,'鏋e簞甯�',43,NULL,NULL),(310,'涓滆惀甯�',43,NULL,NULL),(311,'鐑熷彴甯�',43,NULL,NULL),(312,'娼嶅潑甯�',43,NULL,NULL),(313,'娴庡畞甯�',43,NULL,NULL),(314,'娉板畨甯�',43,NULL,NULL),(315,'濞佹捣甯�',43,NULL,NULL),(316,'鏃ョ収甯�',43,NULL,NULL),(317,'涓存矀甯�',43,NULL,NULL),(318,'寰峰窞甯�',43,NULL,NULL),(319,'鑱婂煄甯�',43,NULL,NULL),(320,'婊ㄥ窞甯�',43,NULL,NULL),(321,'鑿忔辰甯�',43,NULL,NULL),(322,'閮戝窞甯�',44,NULL,NULL),(323,'寮�灏佸競',44,NULL,NULL),(324,'娲涢槼甯�',44,NULL,NULL),(325,'骞抽《灞卞競',44,NULL,NULL),(326,'瀹夐槼甯�',44,NULL,NULL),(327,'楣ゅ甯�',44,NULL,NULL),(328,'鏂颁埂甯�',44,NULL,NULL),(329,'鐒︿綔甯�',44,NULL,NULL),(330,'婵槼甯�',44,NULL,NULL),(331,'璁告槍甯�',44,NULL,NULL),(332,'婕渤甯�',44,NULL,NULL),(333,'涓夐棬宄″競',44,NULL,NULL),(334,'鍗楅槼甯�',44,NULL,NULL),(335,'鍟嗕笜甯�',44,NULL,NULL),(336,'淇¢槼甯�',44,NULL,NULL),(337,'鍛ㄥ彛甯�',44,NULL,NULL),(338,'椹婚┈搴楀競',44,NULL,NULL),(339,'娴庢簮甯�',44,NULL,NULL),(340,'姝︽眽甯�',45,NULL,NULL),(341,'榛勭煶甯�',45,NULL,NULL),(342,'鍗佸牥甯�',45,NULL,NULL),(343,'瀹滄槍甯�',45,NULL,NULL),(344,'瑗勯槼甯�',45,NULL,NULL),(345,'閯傚窞甯�',45,NULL,NULL),(346,'鑽嗛棬甯�',45,NULL,NULL),(347,'瀛濇劅甯�',45,NULL,NULL),(348,'鑽嗗窞甯�',45,NULL,NULL),(349,'榛勫唸甯�',45,NULL,NULL),(350,'鍜稿畞甯�',45,NULL,NULL),(351,'闅忓窞甯�',45,NULL,NULL),(352,'鎭╂柦鍦熷鏃忚嫍鏃忚嚜娌诲窞',45,NULL,NULL),(353,'浠欐甯�',45,NULL,NULL),(354,'娼滄睙甯�',45,NULL,NULL),(355,'澶╅棬甯�',45,NULL,NULL),(356,'绁炲啘鏋舵灄鍖�',45,NULL,NULL),(357,'闀挎矙甯�',46,NULL,NULL),(358,'鏍床甯�',46,NULL,NULL),(359,'婀樻江甯�',46,NULL,NULL),(360,'琛¢槼甯�',46,NULL,NULL),(361,'閭甸槼甯�',46,NULL,NULL),(362,'宀抽槼甯�',46,NULL,NULL),(363,'甯稿痉甯�',46,NULL,NULL),(364,'寮犲鐣屽競',46,NULL,NULL),(365,'鐩婇槼甯�',46,NULL,NULL),(366,'閮村窞甯�',46,NULL,NULL),(367,'姘稿窞甯�',46,NULL,NULL),(368,'鎬�鍖栧競',46,NULL,NULL),(369,'濞勫簳甯�',46,NULL,NULL),(370,'婀樿タ鍦熷鏃忚嫍鏃忚嚜娌诲窞',46,NULL,NULL),(371,'骞垮窞甯�',47,NULL,NULL),(372,'闊跺叧甯�',47,NULL,NULL),(373,'娣卞湷甯�',47,NULL,NULL),(374,'鐝犳捣甯�',47,NULL,NULL),(375,'姹曞ご甯�',47,NULL,NULL),(376,'浣涘北甯�',47,NULL,NULL),(377,'姹熼棬甯�',47,NULL,NULL),(378,'婀涙睙甯�',47,NULL,NULL),(379,'鑼傚悕甯�',47,NULL,NULL),(380,'鑲囧簡甯�',47,NULL,NULL),(381,'鎯犲窞甯�',47,NULL,NULL),(382,'姊呭窞甯�',47,NULL,NULL),(383,'姹曞熬甯�',47,NULL,NULL),(384,'娌虫簮甯�',47,NULL,NULL),(385,'闃虫睙甯�',47,NULL,NULL),(386,'娓呰繙甯�',47,NULL,NULL),(387,'涓滆帪甯�',47,NULL,NULL),(388,'涓北甯�',47,NULL,NULL),(389,'娼窞甯�',47,NULL,NULL),(390,'鎻槼甯�',47,NULL,NULL),(391,'浜戞诞甯�',47,NULL,NULL),(392,'闀挎槬甯�',35,NULL,NULL),(393,'鍚夋灄甯�',35,NULL,NULL),(394,'鍥涘钩甯�',35,NULL,NULL),(395,'杈芥簮甯�',35,NULL,NULL),(396,'閫氬寲甯�',35,NULL,NULL),(397,'鐧藉北甯�',35,NULL,NULL),(398,'鏉惧師甯�',35,NULL,NULL),(399,'鐧藉煄甯�',35,NULL,NULL),(400,'寤惰竟鏈濋矞鏃忚嚜娌诲窞',35,NULL,NULL),(401,'鍝堝皵婊ㄥ競',36,NULL,NULL),(402,'榻愰綈鍝堝皵甯�',36,NULL,NULL),(403,'楦¤タ甯�',36,NULL,NULL),(404,'楣ゅ矖甯�',36,NULL,NULL),(405,'鍙岄腑灞卞競',36,NULL,NULL),(406,'澶у簡甯�',36,NULL,NULL),(407,'浼婃槬甯�',36,NULL,NULL),(408,'浣虫湪鏂競',36,NULL,NULL),(409,'涓冨彴娌冲競',36,NULL,NULL),(410,'鐗′腹姹熷競',36,NULL,NULL),(411,'榛戞渤甯�',36,NULL,NULL),(412,'缁ュ寲甯�',36,NULL,NULL),(413,'澶у叴瀹夊箔鍦板尯',36,NULL,NULL),(414,'鍛煎拰娴╃壒甯�',33,NULL,NULL),(415,'鍖呭ご甯�',33,NULL,NULL),(416,'涔屾捣甯�',33,NULL,NULL),(417,'璧ゅ嘲甯�',33,NULL,NULL),(418,'閫氳窘甯�',33,NULL,NULL),(419,'閯傚皵澶氭柉甯�',33,NULL,NULL),(420,'鍛间鸡璐濆皵甯�',33,NULL,NULL),(421,'宸村溅娣栧皵甯�',33,NULL,NULL),(422,'涔屽叞瀵熷竷甯�',33,NULL,NULL),(423,'鍏村畨鐩�',33,NULL,NULL),(424,'閿℃灄閮嫆鐩�',33,NULL,NULL),(425,'闃挎媺鍠勭洘',33,NULL,NULL),(426,'娌堥槼甯�',34,NULL,NULL),(427,'澶ц繛甯�',34,NULL,NULL),(428,'闉嶅北甯�',34,NULL,NULL),(429,'鎶氶『甯�',34,NULL,NULL),(430,'鏈邯甯�',34,NULL,NULL),(431,'涓逛笢甯�',34,NULL,NULL),(432,'閿﹀窞甯�',34,NULL,NULL),(433,'钀ュ彛甯�',34,NULL,NULL),(434,'闃滄柊甯�',34,NULL,NULL),(435,'杈介槼甯�',34,NULL,NULL),(436,'鐩橀敠甯�',34,NULL,NULL),(437,'閾佸箔甯�',34,NULL,NULL),(438,'鏈濋槼甯�',34,NULL,NULL),(439,'钁姦宀涘競',34,NULL,NULL),(440,'鐭冲搴勫競',31,NULL,NULL),(441,'鍞愬北甯�',31,NULL,NULL),(442,'绉︾殗宀涘競',31,NULL,NULL),(443,'閭兏甯�',31,NULL,NULL),(444,'閭㈠彴甯�',31,NULL,NULL),(445,'淇濆畾甯�',31,NULL,NULL),(446,'寮犲鍙e競',31,NULL,NULL),(447,'鎵垮痉甯�',31,NULL,NULL),(448,'娌у窞甯�',31,NULL,NULL),(449,'寤婂潑甯�',31,NULL,NULL),(450,'琛℃按甯�',31,NULL,NULL),(451,'澶師甯�',32,NULL,NULL),(452,'澶у悓甯�',32,NULL,NULL),(453,'闃虫硥甯�',32,NULL,NULL),(454,'闀挎不甯�',32,NULL,NULL),(455,'鏅嬪煄甯�',32,NULL,NULL),(456,'鏈斿窞甯�',32,NULL,NULL),(457,'鏅嬩腑甯�',32,NULL,NULL),(458,'杩愬煄甯�',32,NULL,NULL),(459,'蹇诲窞甯�',32,NULL,NULL),(460,'涓存本甯�',32,NULL,NULL),(461,'鍚曟甯�',32,NULL,NULL);"
+	err := slf.Orm.Exec(sql).Error
+	if err != nil {
+		errCh <- err
+		return
+	}
 }
diff --git a/model/grpc_init/crm_aps_init.go b/model/grpc_init/crm_aps_init.go
index 6e82ec6..233b851 100644
--- a/model/grpc_init/crm_aps_init.go
+++ b/model/grpc_init/crm_aps_init.go
@@ -7,7 +7,10 @@
 	"google.golang.org/grpc/credentials/insecure"
 )
 
-var CrmApsGrpcServiceConn *grpc.ClientConn
+var (
+	ProductInventoryServiceConn *grpc.ClientConn
+	CrmApsGrpcServiceConn       *grpc.ClientConn
+)
 
 func InitCrmApsGrpcServiceConn() {
 	var err error
@@ -23,3 +26,18 @@
 		CrmApsGrpcServiceConn.Close()
 	}
 }
+
+func InitProductInventoryServiceConn() {
+	var err error
+	ProductInventoryServiceConn, err = grpc.Dial(conf.Conf.GrpcServiceAddr.WMS, grpc.WithTransportCredentials(insecure.NewCredentials()))
+	if err != nil {
+		logx.Errorf("grpc dial product service error: %v", err.Error())
+		return
+	}
+}
+
+func CloseProductInventoryServiceConn() {
+	if ProductInventoryServiceConn != nil {
+		ProductInventoryServiceConn.Close()
+	}
+}
diff --git a/model/index.go b/model/index.go
index d62248f..f526a3b 100644
--- a/model/index.go
+++ b/model/index.go
@@ -95,6 +95,7 @@
 		InvoiceType{},
 		Invoice{},
 		RefundType{},
+		SystemSet{},
 	)
 	return err
 }
@@ -142,6 +143,8 @@
 		NewPaymentTypeSearch(),
 		NewBankAccountSearch(),
 		NewRefundTypeSearch(),
+		NewProvinceSearch(nil),
+		NewCitySearch(),
 	}
 
 	for _, model := range models {
diff --git a/model/product.go b/model/product.go
index 2ac4adc..fa92985 100644
--- a/model/product.go
+++ b/model/product.go
@@ -16,6 +16,11 @@
 		Total      decimal.Decimal `json:"total" gorm:"column:total;type:decimal(10,2);comment:浜у搧鎬讳环"`
 		Desc       string          `json:"desc" gorm:"column:desc;type:varchar(255);comment:浜у搧鎻忚堪"`
 		Unit       string          `json:"unit" gorm:"column:unit;type:varchar(255);comment:鍗曚綅"`
+		Cost       string          `json:"cost" gorm:"column:cost;type:varchar(255);comment:浜у搧鎴愭湰"`
+		Profit     string          `json:"profit" gorm:"column:profit;type:varchar(255);comment:姣涘埄"`
+		Margin     string          `json:"margin" gorm:"column:margin;type:varchar(255);comment:姣涘埄鐜�"`
+		Specs      string          `gorm:"type:varchar(191);comment:鐗╂枡瑙勬牸" json:"specs"`
+		Type       string          `gorm:"type:varchar(191);comment:鐗╂枡鍨嬪彿" json:"type"`
 		gorm.Model `json:"-"`
 	}
 
diff --git a/model/province.go b/model/province.go
index 6e9e908..186a902 100644
--- a/model/province.go
+++ b/model/province.go
@@ -3,6 +3,7 @@
 import (
 	"aps_crm/pkg/mysqlx"
 	"gorm.io/gorm"
+	"sync"
 )
 
 type (
@@ -115,3 +116,25 @@
 	var db = slf.build()
 	return db.Updates(m).Error
 }
+
+// InitDefaultData 鍒濆鍖栨暟鎹�
+func (slf *ProvinceSearch) InitDefaultData(errCh chan<- error, wg *sync.WaitGroup) {
+	var (
+		db          = slf.Orm.Table(slf.TableName())
+		total int64 = 0
+	)
+	if err := db.Count(&total).Error; err != nil {
+		errCh <- err
+		return
+	}
+	if total != 0 {
+		return
+	}
+	sql := "INSERT INTO `province` VALUES (29,'鍖椾含甯�',3),(30,'澶╂触甯�',3),(31,'娌冲寳鐪�',3),(32,'灞辫タ鐪�',3),(33,'鍐呰挋鍙よ嚜娌诲尯',3),(34,'杈藉畞鐪�',3),(35,'鍚夋灄鐪�',3),(36,'榛戦緳姹熺渷',3),(37,'涓婃捣甯�',3),(38,'姹熻嫃鐪�',3),(39,'娴欐睙鐪�',3),(40,'瀹夊窘鐪�',3),(41,'绂忓缓鐪�',3),(42,'姹熻タ鐪�',3),(43,'灞变笢鐪�',3),(44,'娌冲崡鐪�',3),(45,'婀栧寳鐪�',3),(46,'婀栧崡鐪�',3),(47,'骞夸笢鐪�',3),(48,'骞胯タ澹棌鑷不鍖�',3),(49,'娴峰崡鐪�',3),(50,'閲嶅簡甯�',3),(51,'鍥涘窛鐪�',3),(52,'璐靛窞鐪�',3),(53,'浜戝崡鐪�',3),(54,'瑗胯棌鑷不鍖�',3),(55,'闄曡タ鐪�',3),(56,'鐢樿們鐪�',3),(57,'闈掓捣鐪�',3),(58,'瀹佸鍥炴棌鑷不鍖�',3),(59,'鏂扮枂缁村惥灏旇嚜娌诲尯',3),(60,'鍙版咕鐪�',3),(61,'棣欐腐',3),(62,'婢抽棬',3)"
+
+	err := slf.Orm.Exec(sql).Error
+	if err != nil {
+		errCh <- err
+		return
+	}
+}
diff --git a/model/quotation.go b/model/quotation.go
index 1c45c24..c4618ee 100644
--- a/model/quotation.go
+++ b/model/quotation.go
@@ -3,6 +3,7 @@
 import (
 	"aps_crm/pkg/mysqlx"
 	"fmt"
+	"github.com/shopspring/decimal"
 	"gorm.io/gorm"
 )
 
@@ -27,6 +28,7 @@
 		SaleChance        SaleChance      `json:"sale_chance" gorm:"foreignKey:SaleChanceId"`
 		Products          []Product       `json:"products" gorm:"many2many:quotation_product"`
 		CodeStandID       string          `json:"codeStandID" gorm:"column:code_stand_id;type:varchar(255);comment:缂栫爜id"`
+		AmountTotal       decimal.Decimal `gorm:"-" json:"amountTotal"` //浠锋牸鍚堣
 		gorm.Model        `json:"-"`
 	}
 
@@ -62,6 +64,9 @@
 	}
 	if slf.Number != "" {
 		db = db.Where("number = ?", slf.Number)
+	}
+	if slf.QuotationStatusId != 0 {
+		db = db.Where("quotation_status_id = ?", slf.QuotationStatusId)
 	}
 
 	if len(slf.SearchMap) > 0 {
@@ -132,7 +137,7 @@
 		db = db.Limit(slf.PageSize).Offset((slf.PageNum - 1) * slf.PageSize)
 	}
 
-	err := db.Preload("Products").Preload("Member").Preload("QuotationStatus").Preload("Client").Preload("Contact").Order("id desc").Find(&records).Error
+	err := db.Preload("Products").Preload("Member").Preload("QuotationStatus").Preload("Client").Preload("Contact").Preload("SaleChance").Order("id desc").Find(&records).Error
 	return records, total, err
 }
 
@@ -189,7 +194,13 @@
 	slf.Number = number
 	return slf
 }
+
 func (slf *QuotationSearch) SetIds(ids []int) *QuotationSearch {
 	slf.Orm = slf.Orm.Where("id in (?)", ids)
 	return slf
 }
+
+func (slf *QuotationSearch) SetQuotationStatusId(id int) *QuotationSearch {
+	slf.QuotationStatusId = id
+	return slf
+}
diff --git a/model/request/product.go b/model/request/product.go
index a81e429..1cce9d0 100644
--- a/model/request/product.go
+++ b/model/request/product.go
@@ -2,6 +2,7 @@
 
 type GetProductList struct {
 	PageInfo
-	ProductNumber string `json:"productNumber" form:"productNumber"` // 浜у搧缂栫爜
-	ProductName   string `json:"productName" form:"productName"`     // 浜у搧鍚嶇О
+	ProductNumber   string `json:"productNumber" form:"productNumber"`     // 浜у搧缂栫爜
+	ProductName     string `json:"productName" form:"productName"`         // 浜у搧鍚嶇О
+	QuotationNumber string `json:"quotationNumber" form:"quotationNumber"` //鎶ヤ环鍗曠紪鐮�
 }
diff --git a/model/request/system_set_request.go b/model/request/system_set_request.go
new file mode 100644
index 0000000..326aa7e
--- /dev/null
+++ b/model/request/system_set_request.go
@@ -0,0 +1,7 @@
+package request
+
+import "aps_crm/model"
+
+type SaveSystemSet struct {
+	Sets []*model.SystemSet `json:"sets"`
+}
diff --git a/model/response/salesDetails.go b/model/response/salesDetails.go
index 80ce00c..2c57379 100644
--- a/model/response/salesDetails.go
+++ b/model/response/salesDetails.go
@@ -1,5 +1,10 @@
 package response
 
+type Info struct {
+	MakeInfo     []WorkOrderInfo `json:"makeInfo"`
+	PurchaseInfo []Purchase      `json:"purchaseInfo"`
+}
+
 type WorkOrderInfo struct {
 	OrderId         string `json:"orderId"`
 	ProductName     string `json:"productName"`
@@ -10,8 +15,16 @@
 	EndTime         string `json:"endTime"`
 }
 
+type Purchase struct {
+	PurchaseNumber string `json:"purchaseNumber"`
+	PurchaseName   string `json:"purchaseName"`
+	SupplierName   string `json:"supplierName"`
+	Amount         int64  `json:"amount"`
+	Status         int64  `json:"status"`
+}
+
 type ProductInfo struct {
-	Id              string `json:"id"`
+	Number          string `json:"number"`
 	Name            string `json:"name"`
 	OrderAmount     string `json:"orderAmount"` //璁㈠崟鏁伴噺
 	Unit            string `json:"unit"`
diff --git a/model/system_set.go b/model/system_set.go
new file mode 100644
index 0000000..d623e96
--- /dev/null
+++ b/model/system_set.go
@@ -0,0 +1,97 @@
+package model
+
+import (
+	"aps_crm/pkg/mysqlx"
+	"fmt"
+	"gorm.io/gorm"
+)
+
+type (
+	SystemSet struct {
+		Id       int    `json:"id" gorm:"column:id;primaryKey;autoIncrement;not null"`
+		Name     string `json:"name" gorm:"type:varchar(255);comment:鍚嶇О"`
+		Value    string `json:"value" gorm:"type:varchar(255);comment:鍊�"`
+		ModeType string `json:"modeType" gorm:"type:varchar(255);comment:妯″潡绫诲瀷"`
+	}
+	SystemSetSearch struct {
+		SystemSet
+		Orm *gorm.DB
+	}
+)
+
+func (slf SystemSet) TableName() string {
+	return "system_set"
+}
+
+func NewSystemSetSearch() *SystemSetSearch {
+	return &SystemSetSearch{Orm: mysqlx.GetDB()}
+}
+
+func (slf *SystemSetSearch) SetOrm(tx *gorm.DB) *SystemSetSearch {
+	slf.Orm = tx
+	return slf
+}
+func (slf *SystemSetSearch) SetName(name string) *SystemSetSearch {
+	slf.Name = name
+	return slf
+}
+func (slf *SystemSetSearch) SetModeType(modeType string) *SystemSetSearch {
+	slf.ModeType = modeType
+	return slf
+}
+
+func (slf *SystemSetSearch) build() *gorm.DB {
+	var db = slf.Orm.Table(slf.TableName())
+
+	if slf.Name != "" {
+		db = db.Where("name = ?", slf.Name)
+	}
+	if slf.ModeType != "" {
+		db = db.Where("mode_type = ?", slf.ModeType)
+	}
+
+	return db
+}
+
+// CreateBatch 鎵归噺鎻掑叆
+func (slf *SystemSetSearch) CreateBatch(records []*SystemSet) error {
+	var db = slf.build()
+
+	if err := db.Create(&records).Error; err != nil {
+		return fmt.Errorf("create batch err: %v, records: %+v", err, records)
+	}
+
+	return nil
+}
+
+func (slf *SystemSetSearch) DeleteAll() (err error) {
+	var db = slf.build()
+	err = db.Where("1=1").Delete(&SystemSet{}).Error
+	return err
+}
+
+func (slf *SystemSetSearch) First() (*SystemSet, error) {
+	var (
+		record = new(SystemSet)
+		db     = slf.build()
+	)
+
+	if err := db.First(record).Error; err != nil {
+		return record, err
+	}
+
+	return record, nil
+}
+
+func (slf *SystemSetSearch) FindAll() ([]*SystemSet, error) {
+	var (
+		records = make([]*SystemSet, 0)
+		db      = slf.build()
+	)
+
+	if err := db.Find(&records).Error; err != nil {
+		return records, fmt.Errorf("find records err: %v", err)
+	}
+
+	return records, nil
+}
diff --git a/proto/crm_aps.proto b/proto/crm_aps.proto
index f740c1c..1676907 100644
--- a/proto/crm_aps.proto
+++ b/proto/crm_aps.proto
@@ -7,6 +7,9 @@
   rpc SendSalesDetailsToApsProject(SendSalesDetailsToApsProjectRequest) returns(SendSalesDetailsToApsProjectResponse) {}
   rpc GetCrmSalesDetailsList(GetCrmSalesDetailsListRequest) returns(GetCrmSalesDetailsListResponse) {}
   rpc SendSalesDetailsAndProjectToCrm(SendSalesDetailsAndProjectToCrmRequest) returns(SendSalesDetailsAndProjectToCrmResponse) {}
+  rpc GetClientList(GetClientListRequest) returns(GetClientListResponse) {}
+  rpc UpdateSalesDetail(UpdateSalesDetailRequest) returns(UpdateSalesDetailResponse) {}
+  rpc RemoveSalesDetail(RemoveSalesDetailRequest) returns(RemoveSalesDetailRequest) {}
 }
 
 //-----------------------------------------------------GetApsProjectList--------------------------------------
@@ -80,4 +83,34 @@
 
 }
 
+//------------------------------------------------------------GetClientList-----------------------------------
 
+message GetClientListRequest{
+  int64  page = 1;
+  int64  page_size = 2;
+  string keyword = 3;
+}
+
+message GetClientListResponse{
+  int64    total = 1;
+  repeated Client list = 2;
+}
+
+message Client {
+  string number = 1;
+  string name = 2;
+}
+
+
+message UpdateSalesDetailRequest {
+  string number = 1;//閿�鍞槑缁嗗崟鍙�
+  int32 status = 2;//鐘舵��
+}
+
+message UpdateSalesDetailResponse {}
+
+message RemoveSalesDetailRequest {
+  string number = 1;//閿�鍞槑缁嗗崟鍙�
+}
+
+message RemoveSalesDetailResponse {}
\ No newline at end of file
diff --git a/proto/crm_aps/crm_aps.pb.go b/proto/crm_aps/crm_aps.pb.go
index dd584ea..dec896d 100644
--- a/proto/crm_aps/crm_aps.pb.go
+++ b/proto/crm_aps/crm_aps.pb.go
@@ -1,7 +1,7 @@
 // Code generated by protoc-gen-go. DO NOT EDIT.
 // versions:
-// 	protoc-gen-go v1.26.0
-// 	protoc        v4.24.0
+// 	protoc-gen-go v1.31.0
+// 	protoc        v3.19.0
 // source: crm_aps.proto
 
 package crm_aps
@@ -678,6 +678,357 @@
 	return file_crm_aps_proto_rawDescGZIP(), []int{10}
 }
 
+type GetClientListRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Page     int64  `protobuf:"varint,1,opt,name=page,proto3" json:"page,omitempty"`
+	PageSize int64  `protobuf:"varint,2,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"`
+	Keyword  string `protobuf:"bytes,3,opt,name=keyword,proto3" json:"keyword,omitempty"`
+}
+
+func (x *GetClientListRequest) Reset() {
+	*x = GetClientListRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_crm_aps_proto_msgTypes[11]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *GetClientListRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetClientListRequest) ProtoMessage() {}
+
+func (x *GetClientListRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_crm_aps_proto_msgTypes[11]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use GetClientListRequest.ProtoReflect.Descriptor instead.
+func (*GetClientListRequest) Descriptor() ([]byte, []int) {
+	return file_crm_aps_proto_rawDescGZIP(), []int{11}
+}
+
+func (x *GetClientListRequest) GetPage() int64 {
+	if x != nil {
+		return x.Page
+	}
+	return 0
+}
+
+func (x *GetClientListRequest) GetPageSize() int64 {
+	if x != nil {
+		return x.PageSize
+	}
+	return 0
+}
+
+func (x *GetClientListRequest) GetKeyword() string {
+	if x != nil {
+		return x.Keyword
+	}
+	return ""
+}
+
+type GetClientListResponse struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Total int64     `protobuf:"varint,1,opt,name=total,proto3" json:"total,omitempty"`
+	List  []*Client `protobuf:"bytes,2,rep,name=list,proto3" json:"list,omitempty"`
+}
+
+func (x *GetClientListResponse) Reset() {
+	*x = GetClientListResponse{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_crm_aps_proto_msgTypes[12]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *GetClientListResponse) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetClientListResponse) ProtoMessage() {}
+
+func (x *GetClientListResponse) ProtoReflect() protoreflect.Message {
+	mi := &file_crm_aps_proto_msgTypes[12]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use GetClientListResponse.ProtoReflect.Descriptor instead.
+func (*GetClientListResponse) Descriptor() ([]byte, []int) {
+	return file_crm_aps_proto_rawDescGZIP(), []int{12}
+}
+
+func (x *GetClientListResponse) GetTotal() int64 {
+	if x != nil {
+		return x.Total
+	}
+	return 0
+}
+
+func (x *GetClientListResponse) GetList() []*Client {
+	if x != nil {
+		return x.List
+	}
+	return nil
+}
+
+type Client struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Number string `protobuf:"bytes,1,opt,name=number,proto3" json:"number,omitempty"`
+	Name   string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
+}
+
+func (x *Client) Reset() {
+	*x = Client{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_crm_aps_proto_msgTypes[13]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *Client) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Client) ProtoMessage() {}
+
+func (x *Client) ProtoReflect() protoreflect.Message {
+	mi := &file_crm_aps_proto_msgTypes[13]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Client.ProtoReflect.Descriptor instead.
+func (*Client) Descriptor() ([]byte, []int) {
+	return file_crm_aps_proto_rawDescGZIP(), []int{13}
+}
+
+func (x *Client) GetNumber() string {
+	if x != nil {
+		return x.Number
+	}
+	return ""
+}
+
+func (x *Client) GetName() string {
+	if x != nil {
+		return x.Name
+	}
+	return ""
+}
+
+type UpdateSalesDetailRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Number string `protobuf:"bytes,1,opt,name=number,proto3" json:"number,omitempty"`  //閿�鍞槑缁嗗崟鍙�
+	Status int32  `protobuf:"varint,2,opt,name=status,proto3" json:"status,omitempty"` //鐘舵��
+}
+
+func (x *UpdateSalesDetailRequest) Reset() {
+	*x = UpdateSalesDetailRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_crm_aps_proto_msgTypes[14]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *UpdateSalesDetailRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*UpdateSalesDetailRequest) ProtoMessage() {}
+
+func (x *UpdateSalesDetailRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_crm_aps_proto_msgTypes[14]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use UpdateSalesDetailRequest.ProtoReflect.Descriptor instead.
+func (*UpdateSalesDetailRequest) Descriptor() ([]byte, []int) {
+	return file_crm_aps_proto_rawDescGZIP(), []int{14}
+}
+
+func (x *UpdateSalesDetailRequest) GetNumber() string {
+	if x != nil {
+		return x.Number
+	}
+	return ""
+}
+
+func (x *UpdateSalesDetailRequest) GetStatus() int32 {
+	if x != nil {
+		return x.Status
+	}
+	return 0
+}
+
+type UpdateSalesDetailResponse struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+}
+
+func (x *UpdateSalesDetailResponse) Reset() {
+	*x = UpdateSalesDetailResponse{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_crm_aps_proto_msgTypes[15]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *UpdateSalesDetailResponse) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*UpdateSalesDetailResponse) ProtoMessage() {}
+
+func (x *UpdateSalesDetailResponse) ProtoReflect() protoreflect.Message {
+	mi := &file_crm_aps_proto_msgTypes[15]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use UpdateSalesDetailResponse.ProtoReflect.Descriptor instead.
+func (*UpdateSalesDetailResponse) Descriptor() ([]byte, []int) {
+	return file_crm_aps_proto_rawDescGZIP(), []int{15}
+}
+
+type RemoveSalesDetailRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Number string `protobuf:"bytes,1,opt,name=number,proto3" json:"number,omitempty"` //閿�鍞槑缁嗗崟鍙�
+}
+
+func (x *RemoveSalesDetailRequest) Reset() {
+	*x = RemoveSalesDetailRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_crm_aps_proto_msgTypes[16]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *RemoveSalesDetailRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*RemoveSalesDetailRequest) ProtoMessage() {}
+
+func (x *RemoveSalesDetailRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_crm_aps_proto_msgTypes[16]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use RemoveSalesDetailRequest.ProtoReflect.Descriptor instead.
+func (*RemoveSalesDetailRequest) Descriptor() ([]byte, []int) {
+	return file_crm_aps_proto_rawDescGZIP(), []int{16}
+}
+
+func (x *RemoveSalesDetailRequest) GetNumber() string {
+	if x != nil {
+		return x.Number
+	}
+	return ""
+}
+
+type RemoveSalesDetailResponse struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+}
+
+func (x *RemoveSalesDetailResponse) Reset() {
+	*x = RemoveSalesDetailResponse{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_crm_aps_proto_msgTypes[17]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *RemoveSalesDetailResponse) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*RemoveSalesDetailResponse) ProtoMessage() {}
+
+func (x *RemoveSalesDetailResponse) ProtoReflect() protoreflect.Message {
+	mi := &file_crm_aps_proto_msgTypes[17]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use RemoveSalesDetailResponse.ProtoReflect.Descriptor instead.
+func (*RemoveSalesDetailResponse) Descriptor() ([]byte, []int) {
+	return file_crm_aps_proto_rawDescGZIP(), []int{17}
+}
+
 var File_crm_aps_proto protoreflect.FileDescriptor
 
 var file_crm_aps_proto_rawDesc = []byte{
@@ -760,35 +1111,75 @@
 	0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74,
 	0x49, 0x64, 0x22, 0x29, 0x0a, 0x27, 0x53, 0x65, 0x6e, 0x64, 0x53, 0x61, 0x6c, 0x65, 0x73, 0x44,
 	0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x41, 0x6e, 0x64, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74,
-	0x54, 0x6f, 0x43, 0x72, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xa8, 0x03,
-	0x0a, 0x14, 0x43, 0x72, 0x6d, 0x41, 0x6e, 0x64, 0x41, 0x70, 0x73, 0x47, 0x72, 0x70, 0x63, 0x53,
-	0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x4c, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x41, 0x70, 0x73,
-	0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x19, 0x2e, 0x47, 0x65,
-	0x74, 0x41, 0x70, 0x73, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x52,
-	0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x70, 0x73, 0x50,
-	0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
-	0x73, 0x65, 0x22, 0x00, 0x12, 0x6d, 0x0a, 0x1c, 0x53, 0x65, 0x6e, 0x64, 0x53, 0x61, 0x6c, 0x65,
-	0x73, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x54, 0x6f, 0x41, 0x70, 0x73, 0x50, 0x72, 0x6f,
-	0x6a, 0x65, 0x63, 0x74, 0x12, 0x24, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x53, 0x61, 0x6c, 0x65, 0x73,
+	0x54, 0x6f, 0x43, 0x72, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x61, 0x0a,
+	0x14, 0x47, 0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65,
+	0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20,
+	0x01, 0x28, 0x03, 0x52, 0x04, 0x70, 0x61, 0x67, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x61, 0x67,
+	0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x70, 0x61,
+	0x67, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6b, 0x65, 0x79, 0x77, 0x6f, 0x72,
+	0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6b, 0x65, 0x79, 0x77, 0x6f, 0x72, 0x64,
+	0x22, 0x4a, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4c, 0x69, 0x73,
+	0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74,
+	0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x12,
+	0x1b, 0x0a, 0x04, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x07, 0x2e,
+	0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x52, 0x04, 0x6c, 0x69, 0x73, 0x74, 0x22, 0x34, 0x0a, 0x06,
+	0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72,
+	0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x12,
+	0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61,
+	0x6d, 0x65, 0x22, 0x4a, 0x0a, 0x18, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x61, 0x6c, 0x65,
+	0x73, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16,
+	0x0a, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06,
+	0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73,
+	0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x1b,
+	0x0a, 0x19, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x61, 0x6c, 0x65, 0x73, 0x44, 0x65, 0x74,
+	0x61, 0x69, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x32, 0x0a, 0x18, 0x52,
+	0x65, 0x6d, 0x6f, 0x76, 0x65, 0x53, 0x61, 0x6c, 0x65, 0x73, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c,
+	0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65,
+	0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22,
+	0x1b, 0x0a, 0x19, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x53, 0x61, 0x6c, 0x65, 0x73, 0x44, 0x65,
+	0x74, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x85, 0x05, 0x0a,
+	0x14, 0x43, 0x72, 0x6d, 0x41, 0x6e, 0x64, 0x41, 0x70, 0x73, 0x47, 0x72, 0x70, 0x63, 0x53, 0x65,
+	0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x4c, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x41, 0x70, 0x73, 0x50,
+	0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x19, 0x2e, 0x47, 0x65, 0x74,
+	0x41, 0x70, 0x73, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65,
+	0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x70, 0x73, 0x50, 0x72,
+	0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
+	0x65, 0x22, 0x00, 0x12, 0x6d, 0x0a, 0x1c, 0x53, 0x65, 0x6e, 0x64, 0x53, 0x61, 0x6c, 0x65, 0x73,
 	0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x54, 0x6f, 0x41, 0x70, 0x73, 0x50, 0x72, 0x6f, 0x6a,
-	0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x53, 0x65, 0x6e,
-	0x64, 0x53, 0x61, 0x6c, 0x65, 0x73, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x54, 0x6f, 0x41,
-	0x70, 0x73, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
-	0x65, 0x22, 0x00, 0x12, 0x5b, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x43, 0x72, 0x6d, 0x53, 0x61, 0x6c,
-	0x65, 0x73, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x1e, 0x2e,
-	0x47, 0x65, 0x74, 0x43, 0x72, 0x6d, 0x53, 0x61, 0x6c, 0x65, 0x73, 0x44, 0x65, 0x74, 0x61, 0x69,
-	0x6c, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e,
-	0x47, 0x65, 0x74, 0x43, 0x72, 0x6d, 0x53, 0x61, 0x6c, 0x65, 0x73, 0x44, 0x65, 0x74, 0x61, 0x69,
-	0x6c, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00,
-	0x12, 0x76, 0x0a, 0x1f, 0x53, 0x65, 0x6e, 0x64, 0x53, 0x61, 0x6c, 0x65, 0x73, 0x44, 0x65, 0x74,
-	0x61, 0x69, 0x6c, 0x73, 0x41, 0x6e, 0x64, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x54, 0x6f,
-	0x43, 0x72, 0x6d, 0x12, 0x27, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x53, 0x61, 0x6c, 0x65, 0x73, 0x44,
-	0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x41, 0x6e, 0x64, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74,
-	0x54, 0x6f, 0x43, 0x72, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x53,
-	0x65, 0x6e, 0x64, 0x53, 0x61, 0x6c, 0x65, 0x73, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x41,
-	0x6e, 0x64, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x54, 0x6f, 0x43, 0x72, 0x6d, 0x52, 0x65,
-	0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x0b, 0x5a, 0x09, 0x2e, 0x2f, 0x63, 0x72,
-	0x6d, 0x5f, 0x61, 0x70, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+	0x65, 0x63, 0x74, 0x12, 0x24, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x53, 0x61, 0x6c, 0x65, 0x73, 0x44,
+	0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x54, 0x6f, 0x41, 0x70, 0x73, 0x50, 0x72, 0x6f, 0x6a, 0x65,
+	0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x53, 0x65, 0x6e, 0x64,
+	0x53, 0x61, 0x6c, 0x65, 0x73, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x54, 0x6f, 0x41, 0x70,
+	0x73, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
+	0x22, 0x00, 0x12, 0x5b, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x43, 0x72, 0x6d, 0x53, 0x61, 0x6c, 0x65,
+	0x73, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x1e, 0x2e, 0x47,
+	0x65, 0x74, 0x43, 0x72, 0x6d, 0x53, 0x61, 0x6c, 0x65, 0x73, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c,
+	0x73, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x47,
+	0x65, 0x74, 0x43, 0x72, 0x6d, 0x53, 0x61, 0x6c, 0x65, 0x73, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c,
+	0x73, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12,
+	0x76, 0x0a, 0x1f, 0x53, 0x65, 0x6e, 0x64, 0x53, 0x61, 0x6c, 0x65, 0x73, 0x44, 0x65, 0x74, 0x61,
+	0x69, 0x6c, 0x73, 0x41, 0x6e, 0x64, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x54, 0x6f, 0x43,
+	0x72, 0x6d, 0x12, 0x27, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x53, 0x61, 0x6c, 0x65, 0x73, 0x44, 0x65,
+	0x74, 0x61, 0x69, 0x6c, 0x73, 0x41, 0x6e, 0x64, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x54,
+	0x6f, 0x43, 0x72, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x53, 0x65,
+	0x6e, 0x64, 0x53, 0x61, 0x6c, 0x65, 0x73, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x41, 0x6e,
+	0x64, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x54, 0x6f, 0x43, 0x72, 0x6d, 0x52, 0x65, 0x73,
+	0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x40, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x43, 0x6c,
+	0x69, 0x65, 0x6e, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x15, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6c,
+	0x69, 0x65, 0x6e, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
+	0x16, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x52,
+	0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x4c, 0x0a, 0x11, 0x55, 0x70, 0x64,
+	0x61, 0x74, 0x65, 0x53, 0x61, 0x6c, 0x65, 0x73, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x12, 0x19,
+	0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x61, 0x6c, 0x65, 0x73, 0x44, 0x65, 0x74, 0x61,
+	0x69, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x55, 0x70, 0x64, 0x61,
+	0x74, 0x65, 0x53, 0x61, 0x6c, 0x65, 0x73, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x73,
+	0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x4b, 0x0a, 0x11, 0x52, 0x65, 0x6d, 0x6f, 0x76,
+	0x65, 0x53, 0x61, 0x6c, 0x65, 0x73, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x12, 0x19, 0x2e, 0x52,
+	0x65, 0x6d, 0x6f, 0x76, 0x65, 0x53, 0x61, 0x6c, 0x65, 0x73, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c,
+	0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65,
+	0x53, 0x61, 0x6c, 0x65, 0x73, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65,
+	0x73, 0x74, 0x22, 0x00, 0x42, 0x0b, 0x5a, 0x09, 0x2e, 0x2f, 0x63, 0x72, 0x6d, 0x5f, 0x61, 0x70,
+	0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
 }
 
 var (
@@ -803,7 +1194,7 @@
 	return file_crm_aps_proto_rawDescData
 }
 
-var file_crm_aps_proto_msgTypes = make([]protoimpl.MessageInfo, 11)
+var file_crm_aps_proto_msgTypes = make([]protoimpl.MessageInfo, 18)
 var file_crm_aps_proto_goTypes = []interface{}{
 	(*GetApsProjectListRequest)(nil),                // 0: GetApsProjectListRequest
 	(*ApsProject)(nil),                              // 1: ApsProject
@@ -816,24 +1207,38 @@
 	(*GetCrmSalesDetailsListResponse)(nil),          // 8: GetCrmSalesDetailsListResponse
 	(*SendSalesDetailsAndProjectToCrmRequest)(nil),  // 9: SendSalesDetailsAndProjectToCrmRequest
 	(*SendSalesDetailsAndProjectToCrmResponse)(nil), // 10: SendSalesDetailsAndProjectToCrmResponse
+	(*GetClientListRequest)(nil),                    // 11: GetClientListRequest
+	(*GetClientListResponse)(nil),                   // 12: GetClientListResponse
+	(*Client)(nil),                                  // 13: Client
+	(*UpdateSalesDetailRequest)(nil),                // 14: UpdateSalesDetailRequest
+	(*UpdateSalesDetailResponse)(nil),               // 15: UpdateSalesDetailResponse
+	(*RemoveSalesDetailRequest)(nil),                // 16: RemoveSalesDetailRequest
+	(*RemoveSalesDetailResponse)(nil),               // 17: RemoveSalesDetailResponse
 }
 var file_crm_aps_proto_depIdxs = []int32{
 	1,  // 0: GetApsProjectListResponse.List:type_name -> ApsProject
 	3,  // 1: SendSalesDetailsToApsProjectRequest.Products:type_name -> SalesDetailsProduct
 	7,  // 2: GetCrmSalesDetailsListResponse.SalesDetails:type_name -> CrmSalesDetails
-	0,  // 3: CrmAndApsGrpcService.GetApsProjectList:input_type -> GetApsProjectListRequest
-	4,  // 4: CrmAndApsGrpcService.SendSalesDetailsToApsProject:input_type -> SendSalesDetailsToApsProjectRequest
-	6,  // 5: CrmAndApsGrpcService.GetCrmSalesDetailsList:input_type -> GetCrmSalesDetailsListRequest
-	9,  // 6: CrmAndApsGrpcService.SendSalesDetailsAndProjectToCrm:input_type -> SendSalesDetailsAndProjectToCrmRequest
-	2,  // 7: CrmAndApsGrpcService.GetApsProjectList:output_type -> GetApsProjectListResponse
-	5,  // 8: CrmAndApsGrpcService.SendSalesDetailsToApsProject:output_type -> SendSalesDetailsToApsProjectResponse
-	8,  // 9: CrmAndApsGrpcService.GetCrmSalesDetailsList:output_type -> GetCrmSalesDetailsListResponse
-	10, // 10: CrmAndApsGrpcService.SendSalesDetailsAndProjectToCrm:output_type -> SendSalesDetailsAndProjectToCrmResponse
-	7,  // [7:11] is the sub-list for method output_type
-	3,  // [3:7] is the sub-list for method input_type
-	3,  // [3:3] is the sub-list for extension type_name
-	3,  // [3:3] is the sub-list for extension extendee
-	0,  // [0:3] is the sub-list for field type_name
+	13, // 3: GetClientListResponse.list:type_name -> Client
+	0,  // 4: CrmAndApsGrpcService.GetApsProjectList:input_type -> GetApsProjectListRequest
+	4,  // 5: CrmAndApsGrpcService.SendSalesDetailsToApsProject:input_type -> SendSalesDetailsToApsProjectRequest
+	6,  // 6: CrmAndApsGrpcService.GetCrmSalesDetailsList:input_type -> GetCrmSalesDetailsListRequest
+	9,  // 7: CrmAndApsGrpcService.SendSalesDetailsAndProjectToCrm:input_type -> SendSalesDetailsAndProjectToCrmRequest
+	11, // 8: CrmAndApsGrpcService.GetClientList:input_type -> GetClientListRequest
+	14, // 9: CrmAndApsGrpcService.UpdateSalesDetail:input_type -> UpdateSalesDetailRequest
+	16, // 10: CrmAndApsGrpcService.RemoveSalesDetail:input_type -> RemoveSalesDetailRequest
+	2,  // 11: CrmAndApsGrpcService.GetApsProjectList:output_type -> GetApsProjectListResponse
+	5,  // 12: CrmAndApsGrpcService.SendSalesDetailsToApsProject:output_type -> SendSalesDetailsToApsProjectResponse
+	8,  // 13: CrmAndApsGrpcService.GetCrmSalesDetailsList:output_type -> GetCrmSalesDetailsListResponse
+	10, // 14: CrmAndApsGrpcService.SendSalesDetailsAndProjectToCrm:output_type -> SendSalesDetailsAndProjectToCrmResponse
+	12, // 15: CrmAndApsGrpcService.GetClientList:output_type -> GetClientListResponse
+	15, // 16: CrmAndApsGrpcService.UpdateSalesDetail:output_type -> UpdateSalesDetailResponse
+	16, // 17: CrmAndApsGrpcService.RemoveSalesDetail:output_type -> RemoveSalesDetailRequest
+	11, // [11:18] is the sub-list for method output_type
+	4,  // [4:11] is the sub-list for method input_type
+	4,  // [4:4] is the sub-list for extension type_name
+	4,  // [4:4] is the sub-list for extension extendee
+	0,  // [0:4] is the sub-list for field type_name
 }
 
 func init() { file_crm_aps_proto_init() }
@@ -974,6 +1379,90 @@
 				return nil
 			}
 		}
+		file_crm_aps_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*GetClientListRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_crm_aps_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*GetClientListResponse); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_crm_aps_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*Client); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_crm_aps_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*UpdateSalesDetailRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_crm_aps_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*UpdateSalesDetailResponse); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_crm_aps_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*RemoveSalesDetailRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_crm_aps_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*RemoveSalesDetailResponse); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
 	}
 	type x struct{}
 	out := protoimpl.TypeBuilder{
@@ -981,7 +1470,7 @@
 			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
 			RawDescriptor: file_crm_aps_proto_rawDesc,
 			NumEnums:      0,
-			NumMessages:   11,
+			NumMessages:   18,
 			NumExtensions: 0,
 			NumServices:   1,
 		},
diff --git a/proto/crm_aps/crm_aps_grpc.pb.go b/proto/crm_aps/crm_aps_grpc.pb.go
index b5e0c95..718cf76 100644
--- a/proto/crm_aps/crm_aps_grpc.pb.go
+++ b/proto/crm_aps/crm_aps_grpc.pb.go
@@ -1,4 +1,8 @@
 // Code generated by protoc-gen-go-grpc. DO NOT EDIT.
+// versions:
+// - protoc-gen-go-grpc v1.3.0
+// - protoc             v3.19.0
+// source: crm_aps.proto
 
 package crm_aps
 
@@ -14,6 +18,16 @@
 // Requires gRPC-Go v1.32.0 or later.
 const _ = grpc.SupportPackageIsVersion7
 
+const (
+	CrmAndApsGrpcService_GetApsProjectList_FullMethodName               = "/CrmAndApsGrpcService/GetApsProjectList"
+	CrmAndApsGrpcService_SendSalesDetailsToApsProject_FullMethodName    = "/CrmAndApsGrpcService/SendSalesDetailsToApsProject"
+	CrmAndApsGrpcService_GetCrmSalesDetailsList_FullMethodName          = "/CrmAndApsGrpcService/GetCrmSalesDetailsList"
+	CrmAndApsGrpcService_SendSalesDetailsAndProjectToCrm_FullMethodName = "/CrmAndApsGrpcService/SendSalesDetailsAndProjectToCrm"
+	CrmAndApsGrpcService_GetClientList_FullMethodName                   = "/CrmAndApsGrpcService/GetClientList"
+	CrmAndApsGrpcService_UpdateSalesDetail_FullMethodName               = "/CrmAndApsGrpcService/UpdateSalesDetail"
+	CrmAndApsGrpcService_RemoveSalesDetail_FullMethodName               = "/CrmAndApsGrpcService/RemoveSalesDetail"
+)
+
 // CrmAndApsGrpcServiceClient is the client API for CrmAndApsGrpcService service.
 //
 // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
@@ -22,6 +36,9 @@
 	SendSalesDetailsToApsProject(ctx context.Context, in *SendSalesDetailsToApsProjectRequest, opts ...grpc.CallOption) (*SendSalesDetailsToApsProjectResponse, error)
 	GetCrmSalesDetailsList(ctx context.Context, in *GetCrmSalesDetailsListRequest, opts ...grpc.CallOption) (*GetCrmSalesDetailsListResponse, error)
 	SendSalesDetailsAndProjectToCrm(ctx context.Context, in *SendSalesDetailsAndProjectToCrmRequest, opts ...grpc.CallOption) (*SendSalesDetailsAndProjectToCrmResponse, error)
+	GetClientList(ctx context.Context, in *GetClientListRequest, opts ...grpc.CallOption) (*GetClientListResponse, error)
+	UpdateSalesDetail(ctx context.Context, in *UpdateSalesDetailRequest, opts ...grpc.CallOption) (*UpdateSalesDetailResponse, error)
+	RemoveSalesDetail(ctx context.Context, in *RemoveSalesDetailRequest, opts ...grpc.CallOption) (*RemoveSalesDetailRequest, error)
 }
 
 type crmAndApsGrpcServiceClient struct {
@@ -34,7 +51,7 @@
 
 func (c *crmAndApsGrpcServiceClient) GetApsProjectList(ctx context.Context, in *GetApsProjectListRequest, opts ...grpc.CallOption) (*GetApsProjectListResponse, error) {
 	out := new(GetApsProjectListResponse)
-	err := c.cc.Invoke(ctx, "/CrmAndApsGrpcService/GetApsProjectList", in, out, opts...)
+	err := c.cc.Invoke(ctx, CrmAndApsGrpcService_GetApsProjectList_FullMethodName, in, out, opts...)
 	if err != nil {
 		return nil, err
 	}
@@ -43,7 +60,7 @@
 
 func (c *crmAndApsGrpcServiceClient) SendSalesDetailsToApsProject(ctx context.Context, in *SendSalesDetailsToApsProjectRequest, opts ...grpc.CallOption) (*SendSalesDetailsToApsProjectResponse, error) {
 	out := new(SendSalesDetailsToApsProjectResponse)
-	err := c.cc.Invoke(ctx, "/CrmAndApsGrpcService/SendSalesDetailsToApsProject", in, out, opts...)
+	err := c.cc.Invoke(ctx, CrmAndApsGrpcService_SendSalesDetailsToApsProject_FullMethodName, in, out, opts...)
 	if err != nil {
 		return nil, err
 	}
@@ -52,7 +69,7 @@
 
 func (c *crmAndApsGrpcServiceClient) GetCrmSalesDetailsList(ctx context.Context, in *GetCrmSalesDetailsListRequest, opts ...grpc.CallOption) (*GetCrmSalesDetailsListResponse, error) {
 	out := new(GetCrmSalesDetailsListResponse)
-	err := c.cc.Invoke(ctx, "/CrmAndApsGrpcService/GetCrmSalesDetailsList", in, out, opts...)
+	err := c.cc.Invoke(ctx, CrmAndApsGrpcService_GetCrmSalesDetailsList_FullMethodName, in, out, opts...)
 	if err != nil {
 		return nil, err
 	}
@@ -61,7 +78,34 @@
 
 func (c *crmAndApsGrpcServiceClient) SendSalesDetailsAndProjectToCrm(ctx context.Context, in *SendSalesDetailsAndProjectToCrmRequest, opts ...grpc.CallOption) (*SendSalesDetailsAndProjectToCrmResponse, error) {
 	out := new(SendSalesDetailsAndProjectToCrmResponse)
-	err := c.cc.Invoke(ctx, "/CrmAndApsGrpcService/SendSalesDetailsAndProjectToCrm", in, out, opts...)
+	err := c.cc.Invoke(ctx, CrmAndApsGrpcService_SendSalesDetailsAndProjectToCrm_FullMethodName, in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *crmAndApsGrpcServiceClient) GetClientList(ctx context.Context, in *GetClientListRequest, opts ...grpc.CallOption) (*GetClientListResponse, error) {
+	out := new(GetClientListResponse)
+	err := c.cc.Invoke(ctx, CrmAndApsGrpcService_GetClientList_FullMethodName, in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *crmAndApsGrpcServiceClient) UpdateSalesDetail(ctx context.Context, in *UpdateSalesDetailRequest, opts ...grpc.CallOption) (*UpdateSalesDetailResponse, error) {
+	out := new(UpdateSalesDetailResponse)
+	err := c.cc.Invoke(ctx, CrmAndApsGrpcService_UpdateSalesDetail_FullMethodName, in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *crmAndApsGrpcServiceClient) RemoveSalesDetail(ctx context.Context, in *RemoveSalesDetailRequest, opts ...grpc.CallOption) (*RemoveSalesDetailRequest, error) {
+	out := new(RemoveSalesDetailRequest)
+	err := c.cc.Invoke(ctx, CrmAndApsGrpcService_RemoveSalesDetail_FullMethodName, in, out, opts...)
 	if err != nil {
 		return nil, err
 	}
@@ -76,6 +120,9 @@
 	SendSalesDetailsToApsProject(context.Context, *SendSalesDetailsToApsProjectRequest) (*SendSalesDetailsToApsProjectResponse, error)
 	GetCrmSalesDetailsList(context.Context, *GetCrmSalesDetailsListRequest) (*GetCrmSalesDetailsListResponse, error)
 	SendSalesDetailsAndProjectToCrm(context.Context, *SendSalesDetailsAndProjectToCrmRequest) (*SendSalesDetailsAndProjectToCrmResponse, error)
+	GetClientList(context.Context, *GetClientListRequest) (*GetClientListResponse, error)
+	UpdateSalesDetail(context.Context, *UpdateSalesDetailRequest) (*UpdateSalesDetailResponse, error)
+	RemoveSalesDetail(context.Context, *RemoveSalesDetailRequest) (*RemoveSalesDetailRequest, error)
 	mustEmbedUnimplementedCrmAndApsGrpcServiceServer()
 }
 
@@ -94,6 +141,15 @@
 }
 func (UnimplementedCrmAndApsGrpcServiceServer) SendSalesDetailsAndProjectToCrm(context.Context, *SendSalesDetailsAndProjectToCrmRequest) (*SendSalesDetailsAndProjectToCrmResponse, error) {
 	return nil, status.Errorf(codes.Unimplemented, "method SendSalesDetailsAndProjectToCrm not implemented")
+}
+func (UnimplementedCrmAndApsGrpcServiceServer) GetClientList(context.Context, *GetClientListRequest) (*GetClientListResponse, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method GetClientList not implemented")
+}
+func (UnimplementedCrmAndApsGrpcServiceServer) UpdateSalesDetail(context.Context, *UpdateSalesDetailRequest) (*UpdateSalesDetailResponse, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method UpdateSalesDetail not implemented")
+}
+func (UnimplementedCrmAndApsGrpcServiceServer) RemoveSalesDetail(context.Context, *RemoveSalesDetailRequest) (*RemoveSalesDetailRequest, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method RemoveSalesDetail not implemented")
 }
 func (UnimplementedCrmAndApsGrpcServiceServer) mustEmbedUnimplementedCrmAndApsGrpcServiceServer() {}
 
@@ -118,7 +174,7 @@
 	}
 	info := &grpc.UnaryServerInfo{
 		Server:     srv,
-		FullMethod: "/CrmAndApsGrpcService/GetApsProjectList",
+		FullMethod: CrmAndApsGrpcService_GetApsProjectList_FullMethodName,
 	}
 	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
 		return srv.(CrmAndApsGrpcServiceServer).GetApsProjectList(ctx, req.(*GetApsProjectListRequest))
@@ -136,7 +192,7 @@
 	}
 	info := &grpc.UnaryServerInfo{
 		Server:     srv,
-		FullMethod: "/CrmAndApsGrpcService/SendSalesDetailsToApsProject",
+		FullMethod: CrmAndApsGrpcService_SendSalesDetailsToApsProject_FullMethodName,
 	}
 	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
 		return srv.(CrmAndApsGrpcServiceServer).SendSalesDetailsToApsProject(ctx, req.(*SendSalesDetailsToApsProjectRequest))
@@ -154,7 +210,7 @@
 	}
 	info := &grpc.UnaryServerInfo{
 		Server:     srv,
-		FullMethod: "/CrmAndApsGrpcService/GetCrmSalesDetailsList",
+		FullMethod: CrmAndApsGrpcService_GetCrmSalesDetailsList_FullMethodName,
 	}
 	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
 		return srv.(CrmAndApsGrpcServiceServer).GetCrmSalesDetailsList(ctx, req.(*GetCrmSalesDetailsListRequest))
@@ -172,10 +228,64 @@
 	}
 	info := &grpc.UnaryServerInfo{
 		Server:     srv,
-		FullMethod: "/CrmAndApsGrpcService/SendSalesDetailsAndProjectToCrm",
+		FullMethod: CrmAndApsGrpcService_SendSalesDetailsAndProjectToCrm_FullMethodName,
 	}
 	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
 		return srv.(CrmAndApsGrpcServiceServer).SendSalesDetailsAndProjectToCrm(ctx, req.(*SendSalesDetailsAndProjectToCrmRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _CrmAndApsGrpcService_GetClientList_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(GetClientListRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(CrmAndApsGrpcServiceServer).GetClientList(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: CrmAndApsGrpcService_GetClientList_FullMethodName,
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(CrmAndApsGrpcServiceServer).GetClientList(ctx, req.(*GetClientListRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _CrmAndApsGrpcService_UpdateSalesDetail_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(UpdateSalesDetailRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(CrmAndApsGrpcServiceServer).UpdateSalesDetail(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: CrmAndApsGrpcService_UpdateSalesDetail_FullMethodName,
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(CrmAndApsGrpcServiceServer).UpdateSalesDetail(ctx, req.(*UpdateSalesDetailRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _CrmAndApsGrpcService_RemoveSalesDetail_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(RemoveSalesDetailRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(CrmAndApsGrpcServiceServer).RemoveSalesDetail(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: CrmAndApsGrpcService_RemoveSalesDetail_FullMethodName,
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(CrmAndApsGrpcServiceServer).RemoveSalesDetail(ctx, req.(*RemoveSalesDetailRequest))
 	}
 	return interceptor(ctx, in, info, handler)
 }
@@ -203,6 +313,18 @@
 			MethodName: "SendSalesDetailsAndProjectToCrm",
 			Handler:    _CrmAndApsGrpcService_SendSalesDetailsAndProjectToCrm_Handler,
 		},
+		{
+			MethodName: "GetClientList",
+			Handler:    _CrmAndApsGrpcService_GetClientList_Handler,
+		},
+		{
+			MethodName: "UpdateSalesDetail",
+			Handler:    _CrmAndApsGrpcService_UpdateSalesDetail_Handler,
+		},
+		{
+			MethodName: "RemoveSalesDetail",
+			Handler:    _CrmAndApsGrpcService_RemoveSalesDetail_Handler,
+		},
 	},
 	Streams:  []grpc.StreamDesc{},
 	Metadata: "crm_aps.proto",
diff --git a/proto/crm_aps/server.go b/proto/crm_aps/server.go
index fd51bc1..1a45676 100644
--- a/proto/crm_aps/server.go
+++ b/proto/crm_aps/server.go
@@ -4,8 +4,14 @@
 	"aps_crm/constvar"
 	"aps_crm/model"
 	"aps_crm/model/grpc_init"
+	"aps_crm/pkg/ecode"
+	"aps_crm/proto/product_inventory"
+	"aps_crm/service"
 	"context"
+	"errors"
+	"fmt"
 	"github.com/shopspring/decimal"
+	"gorm.io/gorm"
 )
 
 type Server struct {
@@ -70,6 +76,41 @@
 			return nil, err
 		}
 
+		//鎺ㄩ�佸埌wms
+		clientName := ""
+		if detail.ClientId > 0 {
+			first, err := model.NewClientSearch(nil).SetId(detail.ClientId).First()
+			if err == nil {
+				clientName = first.Name
+			}
+		}
+		wmsProducts := make([]*product_inventory.InventoryProduct, 0)
+		for _, product := range detail.Products {
+			var p product_inventory.InventoryProduct
+			p.Id = product.Number
+			p.Amount = product.Amount.String()
+			wmsProducts = append(wmsProducts, &p)
+		}
+		clientWms := product_inventory.NewProductInventoryServiceClient(grpc_init.ProductInventoryServiceConn)
+		_, err = clientWms.CreateOperation(ctx, &product_inventory.CreateOperationRequest{
+			Number:      detail.Number,
+			Addressee:   detail.Addressee,
+			Address:     detail.Address,
+			Phone:       detail.Phone,
+			DeliverType: int32(detail.DeliverType),
+			Source:      "CRM",
+			ClientId:    int64(detail.ClientId),
+			ClientName:  clientName,
+			ProductList: wmsProducts,
+		})
+		if err != nil {
+			//鐘舵�佽繕鍘�
+			m["status"] = constvar.WaitConfirmed
+			_ = model.NewSalesDetailsSearch().SetNumber(detail.Number).UpdateByMap(m)
+			return nil, err
+		}
+
+		//鎺ㄩ�佸埌aps
 		products := make([]*SalesDetailsProduct, 0)
 		var total decimal.Decimal
 		for _, product := range detail.Products {
@@ -87,14 +128,86 @@
 			MemberName:   detail.Member.Username,
 			SignTime:     detail.SignTime,
 			DeliveryDate: detail.DeliveryDate,
-			Source:       detail.Source,
+			Source:       "CRM",
 			ProductTotal: total.IntPart(),
 			ProjectId:    req.ProjectId,
 			Products:     products,
 		})
 		if err != nil {
+			//鐘舵�佽繕鍘�
+			m["status"] = constvar.WaitConfirmed
+			_ = model.NewSalesDetailsSearch().SetNumber(detail.Number).UpdateByMap(m)
 			return nil, err
 		}
 	}
 	return new(SendSalesDetailsAndProjectToCrmResponse), nil
 }
+
+func (s *Server) GetClientList(ctx context.Context, req *GetClientListRequest) (*GetClientListResponse, error) {
+	if req.Page <= 0 || req.PageSize == 0 {
+		return nil, errors.New("鍙傛暟閿欒")
+	}
+	clientService := new(service.ClientService)
+	params := map[string]interface{}{}
+	if req.Keyword != "" {
+		params["name"] = req.Keyword
+	}
+	clients, total, errCode := clientService.GetClientList(int(req.Page), int(req.PageSize), params)
+	if errCode != ecode.OK {
+		return nil, errors.New(fmt.Sprintf("鍐呴儴閿欒, code:%v", errCode))
+	}
+	resp := new(GetClientListResponse)
+	resp.Total = total
+	resp.List = make([]*Client, 0, len(clients))
+	for _, client := range clients {
+		resp.List = append(resp.List, &Client{
+			Number: client.Number,
+			Name:   client.Name,
+		})
+	}
+	return resp, nil
+}
+func (s *Server) UpdateSalesDetail(ctx context.Context, req *UpdateSalesDetailRequest) (*UpdateSalesDetailResponse, error) {
+	if req.Number == "" {
+		return nil, errors.New("閿�鍞槑缁嗙紪鍙蜂负绌�")
+	}
+	if req.Status == 0 {
+		return nil, errors.New("閿�鍞槑缁嗙姸鎬佷负绌�")
+	}
+
+	status := constvar.SalesDetailsStatus(int(req.Status))
+	if !status.Valid() {
+		return nil, errors.New("閿�鍞槑缁嗙姸鎬佷笉姝g‘")
+	}
+
+	salesDetail, err := model.NewSalesDetailsSearch().SetNumber(req.Number).First()
+	if err == gorm.ErrRecordNotFound {
+		return nil, errors.New("閿�鍞槑缁嗕笉瀛樺湪")
+	}
+
+	salesDetail.Status = status
+	err = model.NewSalesDetailsSearch().Update(salesDetail)
+	if err != nil {
+		return nil, errors.New("鏇存敼CRM閿�鍞槑缁嗗け璐�")
+	}
+
+	return &UpdateSalesDetailResponse{}, nil
+}
+
+func (s *Server) RemoveSalesDetail(ctx context.Context, req *RemoveSalesDetailRequest) (*RemoveSalesDetailRequest, error) {
+	if req.Number == "" {
+		return nil, errors.New("閿�鍞槑缁嗙紪鍙蜂负绌�")
+	}
+
+	_, err := model.NewSalesDetailsSearch().SetNumber(req.Number).First()
+	if err == gorm.ErrRecordNotFound {
+		return nil, errors.New("閿�鍞槑缁嗕笉瀛樺湪")
+	}
+
+	err = model.NewSalesDetailsSearch().SetNumber(req.Number).Delete()
+	if err == gorm.ErrRecordNotFound {
+		return nil, errors.New("閿�鍞槑缁嗗垹闄ゅけ璐�")
+	}
+
+	return &RemoveSalesDetailRequest{}, nil
+}
diff --git a/proto/product.proto b/proto/product.proto
index 9022c7f..0cb50ec 100644
--- a/proto/product.proto
+++ b/proto/product.proto
@@ -63,8 +63,17 @@
   string EndTime = 7;
 }
 
+message CrmGetPurchaseInfo {
+  string PurchaseNumber = 1;
+  string PurchaseName = 2;
+  string SupplierName = 3;
+  int64 Amount = 4;
+  int64 Status = 5;
+}
+
 message GetProductOrderResponse{
   int32   Code = 1;
   string  Msg = 2;
-  repeated WorkOrderInfo List = 3;
+  repeated WorkOrderInfo List = 3;//鍒堕�犱俊鎭�
+  repeated CrmGetPurchaseInfo PurchaseList = 4;//閲囪喘淇℃伅
 }
\ No newline at end of file
diff --git a/proto/product/product.pb.go b/proto/product/product.pb.go
index adcad64..ba02bd1 100644
--- a/proto/product/product.pb.go
+++ b/proto/product/product.pb.go
@@ -557,20 +557,100 @@
 	return ""
 }
 
+type CrmGetPurchaseInfo struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	PurchaseNumber string `protobuf:"bytes,1,opt,name=PurchaseNumber,proto3" json:"PurchaseNumber,omitempty"`
+	PurchaseName   string `protobuf:"bytes,2,opt,name=PurchaseName,proto3" json:"PurchaseName,omitempty"`
+	SupplierName   string `protobuf:"bytes,3,opt,name=SupplierName,proto3" json:"SupplierName,omitempty"`
+	Amount         int64  `protobuf:"varint,4,opt,name=Amount,proto3" json:"Amount,omitempty"`
+	Status         int64  `protobuf:"varint,5,opt,name=Status,proto3" json:"Status,omitempty"`
+}
+
+func (x *CrmGetPurchaseInfo) Reset() {
+	*x = CrmGetPurchaseInfo{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_product_proto_msgTypes[7]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *CrmGetPurchaseInfo) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*CrmGetPurchaseInfo) ProtoMessage() {}
+
+func (x *CrmGetPurchaseInfo) ProtoReflect() protoreflect.Message {
+	mi := &file_product_proto_msgTypes[7]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use CrmGetPurchaseInfo.ProtoReflect.Descriptor instead.
+func (*CrmGetPurchaseInfo) Descriptor() ([]byte, []int) {
+	return file_product_proto_rawDescGZIP(), []int{7}
+}
+
+func (x *CrmGetPurchaseInfo) GetPurchaseNumber() string {
+	if x != nil {
+		return x.PurchaseNumber
+	}
+	return ""
+}
+
+func (x *CrmGetPurchaseInfo) GetPurchaseName() string {
+	if x != nil {
+		return x.PurchaseName
+	}
+	return ""
+}
+
+func (x *CrmGetPurchaseInfo) GetSupplierName() string {
+	if x != nil {
+		return x.SupplierName
+	}
+	return ""
+}
+
+func (x *CrmGetPurchaseInfo) GetAmount() int64 {
+	if x != nil {
+		return x.Amount
+	}
+	return 0
+}
+
+func (x *CrmGetPurchaseInfo) GetStatus() int64 {
+	if x != nil {
+		return x.Status
+	}
+	return 0
+}
+
 type GetProductOrderResponse struct {
 	state         protoimpl.MessageState
 	sizeCache     protoimpl.SizeCache
 	unknownFields protoimpl.UnknownFields
 
-	Code int32            `protobuf:"varint,1,opt,name=Code,proto3" json:"Code,omitempty"`
-	Msg  string           `protobuf:"bytes,2,opt,name=Msg,proto3" json:"Msg,omitempty"`
-	List []*WorkOrderInfo `protobuf:"bytes,3,rep,name=List,proto3" json:"List,omitempty"`
+	Code         int32                 `protobuf:"varint,1,opt,name=Code,proto3" json:"Code,omitempty"`
+	Msg          string                `protobuf:"bytes,2,opt,name=Msg,proto3" json:"Msg,omitempty"`
+	List         []*WorkOrderInfo      `protobuf:"bytes,3,rep,name=List,proto3" json:"List,omitempty"`                 //鍒堕�犱俊鎭�
+	PurchaseList []*CrmGetPurchaseInfo `protobuf:"bytes,4,rep,name=PurchaseList,proto3" json:"PurchaseList,omitempty"` //閲囪喘淇℃伅
 }
 
 func (x *GetProductOrderResponse) Reset() {
 	*x = GetProductOrderResponse{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_product_proto_msgTypes[7]
+		mi := &file_product_proto_msgTypes[8]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -583,7 +663,7 @@
 func (*GetProductOrderResponse) ProtoMessage() {}
 
 func (x *GetProductOrderResponse) ProtoReflect() protoreflect.Message {
-	mi := &file_product_proto_msgTypes[7]
+	mi := &file_product_proto_msgTypes[8]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -596,7 +676,7 @@
 
 // Deprecated: Use GetProductOrderResponse.ProtoReflect.Descriptor instead.
 func (*GetProductOrderResponse) Descriptor() ([]byte, []int) {
-	return file_product_proto_rawDescGZIP(), []int{7}
+	return file_product_proto_rawDescGZIP(), []int{8}
 }
 
 func (x *GetProductOrderResponse) GetCode() int32 {
@@ -616,6 +696,13 @@
 func (x *GetProductOrderResponse) GetList() []*WorkOrderInfo {
 	if x != nil {
 		return x.List
+	}
+	return nil
+}
+
+func (x *GetProductOrderResponse) GetPurchaseList() []*CrmGetPurchaseInfo {
+	if x != nil {
+		return x.PurchaseList
 	}
 	return nil
 }
@@ -692,28 +779,43 @@
 	0x74, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x53, 0x74, 0x61,
 	0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x45, 0x6e, 0x64, 0x54, 0x69, 0x6d,
 	0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x45, 0x6e, 0x64, 0x54, 0x69, 0x6d, 0x65,
-	0x22, 0x63, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x4f, 0x72,
-	0x64, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x43,
-	0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x43, 0x6f, 0x64, 0x65, 0x12,
-	0x10, 0x0a, 0x03, 0x4d, 0x73, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x4d, 0x73,
-	0x67, 0x12, 0x22, 0x0a, 0x04, 0x4c, 0x69, 0x73, 0x74, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32,
-	0x0e, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52,
-	0x04, 0x4c, 0x69, 0x73, 0x74, 0x32, 0xe2, 0x01, 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63,
-	0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x43, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x50,
-	0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x16, 0x2e, 0x47, 0x65, 0x74,
-	0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65,
-	0x73, 0x74, 0x1a, 0x17, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x49,
-	0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x43, 0x0a,
-	0x0e, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x12,
-	0x16, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x4c, 0x69, 0x73, 0x74,
-	0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f,
-	0x64, 0x75, 0x63, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
-	0x22, 0x00, 0x12, 0x46, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74,
-	0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x17, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x64, 0x75,
-	0x63, 0x74, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18,
-	0x2e, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x4f, 0x72, 0x64, 0x65, 0x72,
-	0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x0b, 0x5a, 0x09, 0x2e, 0x2f,
-	0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+	0x22, 0xb4, 0x01, 0x0a, 0x12, 0x43, 0x72, 0x6d, 0x47, 0x65, 0x74, 0x50, 0x75, 0x72, 0x63, 0x68,
+	0x61, 0x73, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x26, 0x0a, 0x0e, 0x50, 0x75, 0x72, 0x63, 0x68,
+	0x61, 0x73, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
+	0x0e, 0x50, 0x75, 0x72, 0x63, 0x68, 0x61, 0x73, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12,
+	0x22, 0x0a, 0x0c, 0x50, 0x75, 0x72, 0x63, 0x68, 0x61, 0x73, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18,
+	0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x50, 0x75, 0x72, 0x63, 0x68, 0x61, 0x73, 0x65, 0x4e,
+	0x61, 0x6d, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x53, 0x75, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x72, 0x4e,
+	0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x53, 0x75, 0x70, 0x70, 0x6c,
+	0x69, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x41, 0x6d, 0x6f, 0x75, 0x6e,
+	0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12,
+	0x16, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52,
+	0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x9c, 0x01, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x50,
+	0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f,
+	0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x43, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28,
+	0x05, 0x52, 0x04, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x4d, 0x73, 0x67, 0x18, 0x02,
+	0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x4d, 0x73, 0x67, 0x12, 0x22, 0x0a, 0x04, 0x4c, 0x69, 0x73,
+	0x74, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x4f, 0x72,
+	0x64, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x04, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x37, 0x0a,
+	0x0c, 0x50, 0x75, 0x72, 0x63, 0x68, 0x61, 0x73, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x18, 0x04, 0x20,
+	0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x43, 0x72, 0x6d, 0x47, 0x65, 0x74, 0x50, 0x75, 0x72, 0x63,
+	0x68, 0x61, 0x73, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0c, 0x50, 0x75, 0x72, 0x63, 0x68, 0x61,
+	0x73, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x32, 0xe2, 0x01, 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x64, 0x75,
+	0x63, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x43, 0x0a, 0x0e, 0x47, 0x65, 0x74,
+	0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x16, 0x2e, 0x47, 0x65,
+	0x74, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75,
+	0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74,
+	0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x43,
+	0x0a, 0x0e, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x4c, 0x69, 0x73, 0x74,
+	0x12, 0x16, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x4c, 0x69, 0x73,
+	0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x72,
+	0x6f, 0x64, 0x75, 0x63, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
+	0x65, 0x22, 0x00, 0x12, 0x46, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63,
+	0x74, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x17, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x64,
+	0x75, 0x63, 0x74, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
+	0x18, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x4f, 0x72, 0x64, 0x65,
+	0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x0b, 0x5a, 0x09, 0x2e,
+	0x2f, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
 }
 
 var (
@@ -728,7 +830,7 @@
 	return file_product_proto_rawDescData
 }
 
-var file_product_proto_msgTypes = make([]protoimpl.MessageInfo, 8)
+var file_product_proto_msgTypes = make([]protoimpl.MessageInfo, 9)
 var file_product_proto_goTypes = []interface{}{
 	(*GetProductInfoRequest)(nil),   // 0: GetProductInfoRequest
 	(*GetProductInfoResponse)(nil),  // 1: GetProductInfoResponse
@@ -737,23 +839,25 @@
 	(*GetProductListResponse)(nil),  // 4: GetProductListResponse
 	(*GetProductOrderRequest)(nil),  // 5: GetProductOrderRequest
 	(*WorkOrderInfo)(nil),           // 6: WorkOrderInfo
-	(*GetProductOrderResponse)(nil), // 7: GetProductOrderResponse
+	(*CrmGetPurchaseInfo)(nil),      // 7: CrmGetPurchaseInfo
+	(*GetProductOrderResponse)(nil), // 8: GetProductOrderResponse
 }
 var file_product_proto_depIdxs = []int32{
 	2, // 0: GetProductInfoResponse.Data:type_name -> Product
 	2, // 1: GetProductListResponse.List:type_name -> Product
 	6, // 2: GetProductOrderResponse.List:type_name -> WorkOrderInfo
-	0, // 3: productService.GetProductInfo:input_type -> GetProductInfoRequest
-	3, // 4: productService.GetProductList:input_type -> GetProductListRequest
-	5, // 5: productService.GetProductOrder:input_type -> GetProductOrderRequest
-	1, // 6: productService.GetProductInfo:output_type -> GetProductInfoResponse
-	4, // 7: productService.GetProductList:output_type -> GetProductListResponse
-	7, // 8: productService.GetProductOrder:output_type -> GetProductOrderResponse
-	6, // [6:9] is the sub-list for method output_type
-	3, // [3:6] is the sub-list for method input_type
-	3, // [3:3] is the sub-list for extension type_name
-	3, // [3:3] is the sub-list for extension extendee
-	0, // [0:3] is the sub-list for field type_name
+	7, // 3: GetProductOrderResponse.PurchaseList:type_name -> CrmGetPurchaseInfo
+	0, // 4: productService.GetProductInfo:input_type -> GetProductInfoRequest
+	3, // 5: productService.GetProductList:input_type -> GetProductListRequest
+	5, // 6: productService.GetProductOrder:input_type -> GetProductOrderRequest
+	1, // 7: productService.GetProductInfo:output_type -> GetProductInfoResponse
+	4, // 8: productService.GetProductList:output_type -> GetProductListResponse
+	8, // 9: productService.GetProductOrder:output_type -> GetProductOrderResponse
+	7, // [7:10] is the sub-list for method output_type
+	4, // [4:7] is the sub-list for method input_type
+	4, // [4:4] is the sub-list for extension type_name
+	4, // [4:4] is the sub-list for extension extendee
+	0, // [0:4] is the sub-list for field type_name
 }
 
 func init() { file_product_proto_init() }
@@ -847,6 +951,18 @@
 			}
 		}
 		file_product_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*CrmGetPurchaseInfo); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_product_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {
 			switch v := v.(*GetProductOrderResponse); i {
 			case 0:
 				return &v.state
@@ -865,7 +981,7 @@
 			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
 			RawDescriptor: file_product_proto_rawDesc,
 			NumEnums:      0,
-			NumMessages:   8,
+			NumMessages:   9,
 			NumExtensions: 0,
 			NumServices:   1,
 		},
diff --git a/proto/product_inventory.proto b/proto/product_inventory.proto
index 4c6552f..66cab98 100644
--- a/proto/product_inventory.proto
+++ b/proto/product_inventory.proto
@@ -15,7 +15,9 @@
   string Phone = 4;
   int32 DeliverType = 5;//浜や粯绫诲瀷
   string Source = 6;
-  repeated InventoryProduct ProductList = 7;
+  int64 ClientId = 7;
+  string ClientName = 8;
+  repeated InventoryProduct ProductList = 9;
 }
 
 message InventoryProduct{
@@ -35,7 +37,7 @@
 }
 
 message ProductInfo{
-  string Id = 1;
+  string Number = 1;
   string Name = 2;
   string OrderAmount = 3;//璁㈠崟鏁伴噺
   string Unit = 4;
diff --git a/proto/product_inventory/product_inventory.pb.go b/proto/product_inventory/product_inventory.pb.go
index d9473c7..82e965a 100644
--- a/proto/product_inventory/product_inventory.pb.go
+++ b/proto/product_inventory/product_inventory.pb.go
@@ -31,7 +31,9 @@
 	Phone       string              `protobuf:"bytes,4,opt,name=Phone,proto3" json:"Phone,omitempty"`
 	DeliverType int32               `protobuf:"varint,5,opt,name=DeliverType,proto3" json:"DeliverType,omitempty"` //浜や粯绫诲瀷
 	Source      string              `protobuf:"bytes,6,opt,name=Source,proto3" json:"Source,omitempty"`
-	ProductList []*InventoryProduct `protobuf:"bytes,7,rep,name=ProductList,proto3" json:"ProductList,omitempty"`
+	ClientId    int64               `protobuf:"varint,7,opt,name=ClientId,proto3" json:"ClientId,omitempty"`
+	ClientName  string              `protobuf:"bytes,8,opt,name=ClientName,proto3" json:"ClientName,omitempty"`
+	ProductList []*InventoryProduct `protobuf:"bytes,9,rep,name=ProductList,proto3" json:"ProductList,omitempty"`
 }
 
 func (x *CreateOperationRequest) Reset() {
@@ -104,6 +106,20 @@
 func (x *CreateOperationRequest) GetSource() string {
 	if x != nil {
 		return x.Source
+	}
+	return ""
+}
+
+func (x *CreateOperationRequest) GetClientId() int64 {
+	if x != nil {
+		return x.ClientId
+	}
+	return 0
+}
+
+func (x *CreateOperationRequest) GetClientName() string {
+	if x != nil {
+		return x.ClientName
 	}
 	return ""
 }
@@ -277,7 +293,7 @@
 	sizeCache     protoimpl.SizeCache
 	unknownFields protoimpl.UnknownFields
 
-	Id              string `protobuf:"bytes,1,opt,name=Id,proto3" json:"Id,omitempty"`
+	Number          string `protobuf:"bytes,1,opt,name=Number,proto3" json:"Number,omitempty"`
 	Name            string `protobuf:"bytes,2,opt,name=Name,proto3" json:"Name,omitempty"`
 	OrderAmount     string `protobuf:"bytes,3,opt,name=OrderAmount,proto3" json:"OrderAmount,omitempty"` //璁㈠崟鏁伴噺
 	Unit            string `protobuf:"bytes,4,opt,name=Unit,proto3" json:"Unit,omitempty"`
@@ -323,9 +339,9 @@
 	return file_product_inventory_proto_rawDescGZIP(), []int{4}
 }
 
-func (x *ProductInfo) GetId() string {
+func (x *ProductInfo) GetNumber() string {
 	if x != nil {
-		return x.Id
+		return x.Number
 	}
 	return ""
 }
@@ -584,7 +600,7 @@
 
 var file_product_inventory_proto_rawDesc = []byte{
 	0x0a, 0x17, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x5f, 0x69, 0x6e, 0x76, 0x65, 0x6e, 0x74,
-	0x6f, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xed, 0x01, 0x0a, 0x16, 0x43, 0x72,
+	0x6f, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xa9, 0x02, 0x0a, 0x16, 0x43, 0x72,
 	0x65, 0x61, 0x74, 0x65, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71,
 	0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01,
 	0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x1c, 0x0a, 0x09,
@@ -596,81 +612,86 @@
 	0x6c, 0x69, 0x76, 0x65, 0x72, 0x54, 0x79, 0x70, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52,
 	0x0b, 0x44, 0x65, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x54, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06,
 	0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x53, 0x6f,
-	0x75, 0x72, 0x63, 0x65, 0x12, 0x33, 0x0a, 0x0b, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x4c,
-	0x69, 0x73, 0x74, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x49, 0x6e, 0x76, 0x65,
-	0x6e, 0x74, 0x6f, 0x72, 0x79, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x52, 0x0b, 0x50, 0x72,
-	0x6f, 0x64, 0x75, 0x63, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x22, 0x3a, 0x0a, 0x10, 0x49, 0x6e, 0x76,
-	0x65, 0x6e, 0x74, 0x6f, 0x72, 0x79, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x12, 0x0e, 0x0a,
-	0x02, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x49, 0x64, 0x12, 0x16, 0x0a,
-	0x06, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x41,
-	0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x3f, 0x0a, 0x17, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4f,
+	0x75, 0x72, 0x63, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x64,
+	0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x64,
+	0x12, 0x1e, 0x0a, 0x0a, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x08,
+	0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4e, 0x61, 0x6d, 0x65,
+	0x12, 0x33, 0x0a, 0x0b, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x18,
+	0x09, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x49, 0x6e, 0x76, 0x65, 0x6e, 0x74, 0x6f, 0x72,
+	0x79, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x52, 0x0b, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63,
+	0x74, 0x4c, 0x69, 0x73, 0x74, 0x22, 0x3a, 0x0a, 0x10, 0x49, 0x6e, 0x76, 0x65, 0x6e, 0x74, 0x6f,
+	0x72, 0x79, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x64, 0x18,
+	0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x41, 0x6d, 0x6f,
+	0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x41, 0x6d, 0x6f, 0x75, 0x6e,
+	0x74, 0x22, 0x3f, 0x0a, 0x17, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4f, 0x70, 0x65, 0x72, 0x61,
+	0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04,
+	0x43, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x43, 0x6f, 0x64, 0x65,
+	0x12, 0x10, 0x0a, 0x03, 0x4d, 0x73, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x4d,
+	0x73, 0x67, 0x22, 0x38, 0x0a, 0x1e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x76, 0x65, 0x6e, 0x74, 0x6f,
+	0x72, 0x79, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71,
+	0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01,
+	0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, 0xd5, 0x02, 0x0a,
+	0x0b, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x16, 0x0a, 0x06,
+	0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x4e, 0x75,
+	0x6d, 0x62, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01,
+	0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x4f, 0x72, 0x64, 0x65,
+	0x72, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x4f,
+	0x72, 0x64, 0x65, 0x72, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x55, 0x6e,
+	0x69, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x55, 0x6e, 0x69, 0x74, 0x12, 0x18,
+	0x0a, 0x07, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52,
+	0x07, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x43, 0x61, 0x72, 0x72,
+	0x69, 0x65, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x43, 0x61, 0x72, 0x72, 0x69,
+	0x65, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x57, 0x61, 0x79, 0x62, 0x69, 0x6c, 0x6c, 0x18, 0x07, 0x20,
+	0x01, 0x28, 0x09, 0x52, 0x07, 0x57, 0x61, 0x79, 0x62, 0x69, 0x6c, 0x6c, 0x12, 0x1c, 0x0a, 0x09,
+	0x53, 0x61, 0x6c, 0x65, 0x50, 0x72, 0x69, 0x63, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52,
+	0x09, 0x53, 0x61, 0x6c, 0x65, 0x50, 0x72, 0x69, 0x63, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x56, 0x61,
+	0x6c, 0x6f, 0x72, 0x65, 0x6d, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x56, 0x61, 0x6c,
+	0x6f, 0x72, 0x65, 0x6d, 0x12, 0x1c, 0x0a, 0x09, 0x57, 0x61, 0x72, 0x65, 0x68, 0x6f, 0x75, 0x73,
+	0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x57, 0x61, 0x72, 0x65, 0x68, 0x6f, 0x75,
+	0x73, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x0b, 0x20, 0x01,
+	0x28, 0x09, 0x52, 0x06, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x28, 0x0a, 0x0f, 0x41, 0x76,
+	0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x0c, 0x20,
+	0x01, 0x28, 0x09, 0x52, 0x0f, 0x41, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x4e, 0x75,
+	0x6d, 0x62, 0x65, 0x72, 0x22, 0x77, 0x0a, 0x1f, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x76, 0x65, 0x6e,
+	0x74, 0x6f, 0x72, 0x79, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52,
+	0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x43, 0x6f, 0x64, 0x65, 0x18,
+	0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x4d,
+	0x73, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x4d, 0x73, 0x67, 0x12, 0x2e, 0x0a,
+	0x0b, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x18, 0x03, 0x20, 0x03,
+	0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x49, 0x6e, 0x66, 0x6f,
+	0x52, 0x0b, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x22, 0x66, 0x0a,
+	0x1e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x61, 0x6c, 0x65, 0x73, 0x44, 0x65, 0x74, 0x61,
+	0x69, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
+	0x16, 0x0a, 0x06, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
+	0x06, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x2c, 0x0a, 0x11, 0x53, 0x61, 0x6c, 0x65, 0x73,
+	0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01,
+	0x28, 0x09, 0x52, 0x11, 0x53, 0x61, 0x6c, 0x65, 0x73, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x53,
+	0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x47, 0x0a, 0x1f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53,
+	0x61, 0x6c, 0x65, 0x73, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73,
+	0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x43, 0x6f, 0x64, 0x65,
+	0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x10, 0x0a, 0x03,
+	0x4d, 0x73, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x4d, 0x73, 0x67, 0x32, 0xa1,
+	0x02, 0x0a, 0x17, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x49, 0x6e, 0x76, 0x65, 0x6e, 0x74,
+	0x6f, 0x72, 0x79, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x46, 0x0a, 0x0f, 0x43, 0x72,
+	0x65, 0x61, 0x74, 0x65, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x17, 0x2e,
+	0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52,
+	0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4f,
 	0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
-	0x12, 0x12, 0x0a, 0x04, 0x43, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04,
-	0x43, 0x6f, 0x64, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x4d, 0x73, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28,
-	0x09, 0x52, 0x03, 0x4d, 0x73, 0x67, 0x22, 0x38, 0x0a, 0x1e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x76,
-	0x65, 0x6e, 0x74, 0x6f, 0x72, 0x79, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x49, 0x6e, 0x66,
-	0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x4e, 0x75, 0x6d, 0x62,
-	0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72,
-	0x22, 0xcd, 0x02, 0x0a, 0x0b, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x49, 0x6e, 0x66, 0x6f,
-	0x12, 0x0e, 0x0a, 0x02, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x49, 0x64,
-	0x12, 0x12, 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04,
-	0x4e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x41, 0x6d, 0x6f,
-	0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x4f, 0x72, 0x64, 0x65, 0x72,
-	0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x55, 0x6e, 0x69, 0x74, 0x18, 0x04,
-	0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x55, 0x6e, 0x69, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x49, 0x6e,
-	0x76, 0x6f, 0x69, 0x63, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x49, 0x6e, 0x76,
-	0x6f, 0x69, 0x63, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x43, 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, 0x18,
-	0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x43, 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, 0x12, 0x18,
-	0x0a, 0x07, 0x57, 0x61, 0x79, 0x62, 0x69, 0x6c, 0x6c, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52,
-	0x07, 0x57, 0x61, 0x79, 0x62, 0x69, 0x6c, 0x6c, 0x12, 0x1c, 0x0a, 0x09, 0x53, 0x61, 0x6c, 0x65,
-	0x50, 0x72, 0x69, 0x63, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x53, 0x61, 0x6c,
-	0x65, 0x50, 0x72, 0x69, 0x63, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x56, 0x61, 0x6c, 0x6f, 0x72, 0x65,
-	0x6d, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x56, 0x61, 0x6c, 0x6f, 0x72, 0x65, 0x6d,
-	0x12, 0x1c, 0x0a, 0x09, 0x57, 0x61, 0x72, 0x65, 0x68, 0x6f, 0x75, 0x73, 0x65, 0x18, 0x0a, 0x20,
-	0x01, 0x28, 0x09, 0x52, 0x09, 0x57, 0x61, 0x72, 0x65, 0x68, 0x6f, 0x75, 0x73, 0x65, 0x12, 0x16,
-	0x0a, 0x06, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06,
-	0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x28, 0x0a, 0x0f, 0x41, 0x76, 0x61, 0x69, 0x6c, 0x61,
-	0x62, 0x6c, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52,
-	0x0f, 0x41, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72,
-	0x22, 0x77, 0x0a, 0x1f, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x76, 0x65, 0x6e, 0x74, 0x6f, 0x72, 0x79,
-	0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f,
-	0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x43, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28,
-	0x05, 0x52, 0x04, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x4d, 0x73, 0x67, 0x18, 0x02,
-	0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x4d, 0x73, 0x67, 0x12, 0x2e, 0x0a, 0x0b, 0x50, 0x72, 0x6f,
-	0x64, 0x75, 0x63, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c,
-	0x2e, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0b, 0x50, 0x72,
-	0x6f, 0x64, 0x75, 0x63, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x22, 0x66, 0x0a, 0x1e, 0x55, 0x70, 0x64,
-	0x61, 0x74, 0x65, 0x53, 0x61, 0x6c, 0x65, 0x73, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x53, 0x74,
-	0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x4e,
-	0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x4e, 0x75, 0x6d,
-	0x62, 0x65, 0x72, 0x12, 0x2c, 0x0a, 0x11, 0x53, 0x61, 0x6c, 0x65, 0x73, 0x44, 0x65, 0x74, 0x61,
-	0x69, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11,
-	0x53, 0x61, 0x6c, 0x65, 0x73, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x75,
-	0x73, 0x22, 0x47, 0x0a, 0x1f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x61, 0x6c, 0x65, 0x73,
-	0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70,
-	0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x43, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01,
-	0x28, 0x05, 0x52, 0x04, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x4d, 0x73, 0x67, 0x18,
-	0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x4d, 0x73, 0x67, 0x32, 0xa1, 0x02, 0x0a, 0x17, 0x70,
-	0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x49, 0x6e, 0x76, 0x65, 0x6e, 0x74, 0x6f, 0x72, 0x79, 0x53,
-	0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x46, 0x0a, 0x0f, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65,
-	0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x17, 0x2e, 0x43, 0x72, 0x65, 0x61,
-	0x74, 0x65, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65,
-	0x73, 0x74, 0x1a, 0x18, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4f, 0x70, 0x65, 0x72, 0x61,
-	0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x5e,
-	0x0a, 0x17, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x76, 0x65, 0x6e, 0x74, 0x6f, 0x72, 0x79, 0x50, 0x72,
-	0x6f, 0x64, 0x75, 0x63, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1f, 0x2e, 0x47, 0x65, 0x74, 0x49,
-	0x6e, 0x76, 0x65, 0x6e, 0x74, 0x6f, 0x72, 0x79, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x49,
-	0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x47, 0x65, 0x74,
-	0x49, 0x6e, 0x76, 0x65, 0x6e, 0x74, 0x6f, 0x72, 0x79, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74,
-	0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x5e,
-	0x0a, 0x17, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x61, 0x6c, 0x65, 0x73, 0x44, 0x65, 0x74,
-	0x61, 0x69, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1f, 0x2e, 0x55, 0x70, 0x64, 0x61,
-	0x74, 0x65, 0x53, 0x61, 0x6c, 0x65, 0x73, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x53, 0x74, 0x61,
-	0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x55, 0x70, 0x64,
-	0x61, 0x74, 0x65, 0x53, 0x61, 0x6c, 0x65, 0x73, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x53, 0x74,
-	0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x15,
-	0x5a, 0x13, 0x2e, 0x2f, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x5f, 0x69, 0x6e, 0x76, 0x65,
-	0x6e, 0x74, 0x6f, 0x72, 0x79, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+	0x22, 0x00, 0x12, 0x5e, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x76, 0x65, 0x6e, 0x74, 0x6f,
+	0x72, 0x79, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1f, 0x2e,
+	0x47, 0x65, 0x74, 0x49, 0x6e, 0x76, 0x65, 0x6e, 0x74, 0x6f, 0x72, 0x79, 0x50, 0x72, 0x6f, 0x64,
+	0x75, 0x63, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20,
+	0x2e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x76, 0x65, 0x6e, 0x74, 0x6f, 0x72, 0x79, 0x50, 0x72, 0x6f,
+	0x64, 0x75, 0x63, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
+	0x22, 0x00, 0x12, 0x5e, 0x0a, 0x17, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x61, 0x6c, 0x65,
+	0x73, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1f, 0x2e,
+	0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x61, 0x6c, 0x65, 0x73, 0x44, 0x65, 0x74, 0x61, 0x69,
+	0x6c, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20,
+	0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x61, 0x6c, 0x65, 0x73, 0x44, 0x65, 0x74, 0x61,
+	0x69, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
+	0x22, 0x00, 0x42, 0x15, 0x5a, 0x13, 0x2e, 0x2f, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x5f,
+	0x69, 0x6e, 0x76, 0x65, 0x6e, 0x74, 0x6f, 0x72, 0x79, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+	0x33,
 }
 
 var (
diff --git a/router/index.go b/router/index.go
index 8d1ef47..07621ea 100644
--- a/router/index.go
+++ b/router/index.go
@@ -200,5 +200,15 @@
 		codeGroup.GET("getCodeList", codeApi.GetCodeList)  //鑾峰彇缂栫爜鍒楄〃
 		codeGroup.POST("getAutoCode", codeApi.GetAutoCode) //鑾峰彇缂栫爜鍒楄〃
 	}
+
+	//绯荤粺璁剧疆
+	systemSetGroup := PrivateGroup.Group("system")
+	systemSetApi := v1.SystemSetApi{}
+	{
+		systemSetGroup.GET("getSystemSet", systemSetApi.GetSystemSet)
+		systemSetGroup.POST("saveSystemSet", systemSetApi.SaveSystemSet)
+		systemSetGroup.GET("useSystemSet/:modeType", systemSetApi.UseSystemSet)
+	}
+
 	return Router
 }
diff --git a/router/quotation.go b/router/quotation.go
index 83068cd..06f98df 100644
--- a/router/quotation.go
+++ b/router/quotation.go
@@ -11,9 +11,10 @@
 	quotationRouter := router.Group("quotation")
 	quotationApi := v1.ApiGroup.QuotationApi
 	{
-		quotationRouter.POST("add", quotationApi.Add)         // 娣诲姞鎶ヤ环鍗�
-		quotationRouter.DELETE("delete", quotationApi.Delete) // 鍒犻櫎鎶ヤ环鍗�
-		quotationRouter.PUT("update", quotationApi.Update)    // 鏇存柊鎶ヤ环鍗�
-		quotationRouter.POST("list", quotationApi.List)       // 鑾峰彇鎶ヤ环鍗曞垪琛�
+		quotationRouter.POST("add", quotationApi.Add)              // 娣诲姞鎶ヤ环鍗�
+		quotationRouter.DELETE("delete", quotationApi.Delete)      // 鍒犻櫎鎶ヤ环鍗�
+		quotationRouter.PUT("update", quotationApi.Update)         // 鏇存柊鎶ヤ环鍗�
+		quotationRouter.POST("list", quotationApi.List)            // 鑾峰彇鎶ヤ环鍗曞垪琛�
+		quotationRouter.GET("statistics", quotationApi.Statistics) // 鎶ヤ环鍗曠粺璁�
 	}
 }
diff --git a/service/system_set_service.go b/service/system_set_service.go
new file mode 100644
index 0000000..924e7aa
--- /dev/null
+++ b/service/system_set_service.go
@@ -0,0 +1,20 @@
+package service
+
+import (
+	"aps_crm/constvar"
+	"aps_crm/model"
+)
+
+func GetSystemSet() (map[string]interface{}, error) {
+	all, err := model.NewSystemSetSearch().FindAll()
+	if err != nil {
+		return nil, err
+	}
+	crmMap := constvar.SystemSet[`CRM`].(map[string]interface{})
+	for _, set := range all {
+		if _, ok := crmMap[set.Name]; ok {
+			crmMap[set.Name].(map[string]interface{})["value"] = set.Value
+		}
+	}
+	return crmMap, nil
+}

--
Gitblit v1.8.0