From 12e09639dcbfa63b5a23cde8642b72829d4f3a3b Mon Sep 17 00:00:00 2001 From: zhangqian <zhangqian@123.com> Date: 星期四, 10 八月 2023 11:42:31 +0800 Subject: [PATCH] Merge branch 'zq' --- service/products.go | 50 ++ pkg/ecode/code.go | 15 docs/swagger.yaml | 40 + docs/docs.go | 59 +- pkg/contextx/contextx.go | 203 ++++---- service/invoice.go | 88 +++- docs/swagger.json | 59 +- model/request/invoice.go | 29 model/product.go | 19 model/serviceContract.go | 84 ++- model/invoiceProduct.go | 131 ++++++ api/v1/serviceContract.go | 322 ++++++-------- model/request/serviceContract.go | 90 ++-- model/invoice.go | 1 service/serviceContract.go | 28 + pkg/ecode/msg.go | 3 16 files changed, 748 insertions(+), 473 deletions(-) diff --git a/api/v1/serviceContract.go b/api/v1/serviceContract.go index 38b78f2..d354aa2 100644 --- a/api/v1/serviceContract.go +++ b/api/v1/serviceContract.go @@ -1,176 +1,146 @@ -package v1 - -import ( - "aps_crm/model" - "aps_crm/model/request" - "aps_crm/model/response" - "aps_crm/pkg/contextx" - "aps_crm/pkg/ecode" - "github.com/gin-gonic/gin" -) - -type ServiceContractApi struct{} - -// Add -// -// @Tags ServiceContract -// @Summary 娣诲姞鏈嶅姟鍚堝悓 -// @Produce application/json -// @Param object body request.AddServiceContract true "鏌ヨ鍙傛暟" -// @Success 200 {object} contextx.Response{} -// @Router /api/serviceContract/add [post] -func (s *ServiceContractApi) Add(c *gin.Context) { - var params request.AddServiceContract - ctx, ok := contextx.NewContext(c, ¶ms) - if !ok { - return - } - - errCode, serviceContract := checkServiceContractParams(params.ServiceContract) - if errCode != ecode.OK { - ctx.Fail(errCode) - return - } - - errCode = serviceContractService.AddServiceContract(&serviceContract) - if errCode != ecode.OK { - ctx.Fail(errCode) - return - } - - ctx.Ok() -} - -// Delete -// -// @Tags ServiceContract -// @Summary 鍒犻櫎鏈嶅姟鍚堝悓 -// @Produce application/json -// @Param object body request.DeleteserviceContract true "鏌ヨ鍙傛暟" -// @Success 200 {object} contextx.Response{} -// @Router /api/serviceContract/delete [delete] -func (s *ServiceContractApi) Delete(c *gin.Context) { - var params request.DeleteserviceContract - ctx, ok := contextx.NewContext(c, ¶ms) - if !ok { - return - } - - errCode := serviceContractService.DeleteServiceContract(params.Ids) - if errCode != ecode.OK { - ctx.Fail(errCode) - return - } - - ctx.Ok() -} - -// Update -// -// @Tags ServiceContract -// @Summary 鏇存柊鏈嶅姟鍚堝悓 -// @Produce application/json -// @Param object body request.UpdateServiceContract true "鏌ヨ鍙傛暟" -// @Success 200 {object} contextx.Response{} -// @Router /api/serviceContract/update [put] -func (s *ServiceContractApi) Update(c *gin.Context) { - var params request.UpdateServiceContract - ctx, ok := contextx.NewContext(c, ¶ms) - if !ok { - return - } - - errCode, serviceContract := checkServiceContractParams(params.ServiceContract) - if errCode != ecode.OK { - ctx.Fail(errCode) - return - } - - serviceContract.Id = params.Id - - errCode = serviceContractService.UpdateServiceContract(&serviceContract) - if errCode != ecode.OK { - ctx.Fail(errCode) - return - } - - ctx.Ok() -} - -// check params -func checkServiceContractParams(serviceContract request.ServiceContract) (errCode int, result model.ServiceContract) { - //if serviceContract.SignTime == "" { - // return ecode.InvalidParams, result - //} - // - //if serviceContract.Number == "" { - // return ecode.InvalidParams, result - //} - // - //if serviceContract.MemberId <= 0 { - // return ecode.InvalidParams, result - //} - - t, err := checkTimeFormat(serviceContract.SignTime) - if err != nil { - return ecode.InvalidParams, result - } - - result.SignTime = t - - t, err = checkTimeFormat(serviceContract.StartTime) - if err != nil { - return ecode.InvalidParams, result - } - - result.StartTime = t - - t, err = checkTimeFormat(serviceContract.EndTime) - if err != nil { - return ecode.InvalidParams, result - } - - result.EndTime = t - - result.Number = serviceContract.Number - result.MemberId = serviceContract.MemberId - result.Remark = serviceContract.Remark - result.ClientId = serviceContract.ClientId - result.ContactId = serviceContract.ContactId - result.SaleChanceId = serviceContract.SaleChanceId - result.QuotationId = serviceContract.QuotationId - result.ServiceContractTypeId = serviceContract.TypeId - result.ServiceContractStatusId = serviceContract.StatusId - result.ServiceTimes = serviceContract.ServiceTimes - result.Terms = serviceContract.Terms - result.Products = serviceContract.Products - - return ecode.OK, result -} - -// List -// -// @Tags ServiceContract -// @Summary 鐢熸垚璁″垝鍒楄〃 -// @Produce application/json -// @Param object body request.GetServiceContractList true "鍙傛暟" -// @Success 200 {object} contextx.Response{data=response.ServiceContractsResponse} -// @Router /api/serviceContract/list [post] -func (con *ServiceContractApi) List(c *gin.Context) { - var params request.GetServiceContractList - ctx, ok := contextx.NewContext(c, ¶ms) - if !ok { - return - } - - serviceContracts, total, errCode := serviceContractService.GetServiceContractList(params.Page, params.PageSize, params.QueryClass, params.KeywordType, params.Keyword) - if errCode != ecode.OK { - ctx.Fail(errCode) - return - } - - ctx.OkWithDetailed(response.ServiceContractsResponse{ - List: serviceContracts, - Count: int(total), - }) -} +package v1 + +import ( + "aps_crm/model" + "aps_crm/model/request" + "aps_crm/model/response" + "aps_crm/pkg/contextx" + "aps_crm/pkg/ecode" + "github.com/gin-gonic/gin" +) + +type ServiceContractApi struct{} + +// Add +// +// @Tags ServiceContract +// @Summary 娣诲姞鏈嶅姟鍚堝悓 +// @Produce application/json +// @Param object body request.AddServiceContract true "鏌ヨ鍙傛暟" +// @Success 200 {object} contextx.Response{} +// @Router /api/serviceContract/add [post] +func (s *ServiceContractApi) Add(c *gin.Context) { + var params request.AddServiceContract + ctx, ok := contextx.NewContext(c, ¶ms) + if !ok { + return + } + + errCode, serviceContract := checkServiceContractParams(params.ServiceContract) + if errCode != ecode.OK { + ctx.Fail(errCode) + return + } + + errCode = serviceContractService.AddServiceContract(&serviceContract) + if errCode != ecode.OK { + ctx.Fail(errCode) + return + } + + ctx.Ok() +} + +// Delete +// +// @Tags ServiceContract +// @Summary 鍒犻櫎鏈嶅姟鍚堝悓 +// @Produce application/json +// @Param object body request.DeleteServiceContract true "鏌ヨ鍙傛暟" +// @Success 200 {object} contextx.Response{} +// @Router /api/serviceContract/delete [delete] +func (s *ServiceContractApi) Delete(c *gin.Context) { + var params request.DeleteServiceContract + ctx, ok := contextx.NewContext(c, ¶ms) + if !ok { + return + } + + errCode := serviceContractService.DeleteServiceContract(params.Ids) + if errCode != ecode.OK { + ctx.Fail(errCode) + return + } + + ctx.Ok() +} + +// Update +// +// @Tags ServiceContract +// @Summary 鏇存柊鏈嶅姟鍚堝悓 +// @Produce application/json +// @Param object body request.UpdateServiceContract true "鏌ヨ鍙傛暟" +// @Success 200 {object} contextx.Response{} +// @Router /api/serviceContract/update [put] +func (s *ServiceContractApi) Update(c *gin.Context) { + var params request.UpdateServiceContract + ctx, ok := contextx.NewContext(c, ¶ms) + if !ok { + return + } + + errCode, serviceContract := checkServiceContractParams(params.ServiceContract) + if errCode != ecode.OK { + ctx.Fail(errCode) + return + } + + serviceContract.Id = params.Id + + errCode = serviceContractService.UpdateServiceContract(&serviceContract) + if errCode != ecode.OK { + ctx.Fail(errCode) + return + } + + ctx.Ok() +} + +// check params +func checkServiceContractParams(serviceContract request.ServiceContract) (errCode int, result model.ServiceContract) { + result.Number = serviceContract.Number + result.MemberId = serviceContract.MemberId + result.Remark = serviceContract.Remark + result.ClientId = serviceContract.ClientId + result.SalesDetailsId = serviceContract.SalesDetailsId + result.SaleChanceId = serviceContract.SaleChanceId + result.QuotationId = serviceContract.QuotationId + result.ServiceContractTypeId = serviceContract.TypeId + result.ServiceContractStatusId = serviceContract.StatusId + result.ServiceTimes = serviceContract.ServiceTimes + result.Terms = serviceContract.Terms + result.Products = serviceContract.Products + result.SignTime = serviceContract.SignTime + result.StartTime = serviceContract.StartTime + result.EndTime = serviceContract.EndTime + + return ecode.OK, result +} + +// List +// +// @Tags ServiceContract +// @Summary 鏈嶅姟鍚堝悓鍒楄〃 +// @Produce application/json +// @Param object body request.GetServiceContractList true "鍙傛暟" +// @Success 200 {object} contextx.Response{data=response.ServiceContractsResponse} +// @Router /api/serviceContract/list [post] +func (con *ServiceContractApi) List(c *gin.Context) { + var params request.GetServiceContractList + ctx, ok := contextx.NewContext(c, ¶ms) + if !ok { + return + } + + serviceContracts, total, errCode := serviceContractService.GetServiceContractList(params.Page, params.PageSize, params.QueryClass, params.KeywordType, params.Keyword) + if errCode != ecode.OK { + ctx.Fail(errCode) + return + } + + ctx.OkWithDetailed(response.ServiceContractsResponse{ + List: serviceContracts, + Count: int(total), + }) +} diff --git a/docs/docs.go b/docs/docs.go index 9a17b79..e39c3f4 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -7620,7 +7620,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/request.DeleteserviceContract" + "$ref": "#/definitions/request.DeleteServiceContract" } } ], @@ -7642,7 +7642,7 @@ "tags": [ "ServiceContract" ], - "summary": "鐢熸垚璁″垝鍒楄〃", + "summary": "鏈嶅姟鍚堝悓鍒楄〃", "parameters": [ { "description": "鍙傛暟", @@ -11366,6 +11366,9 @@ "model.ServiceContract": { "type": "object", "properties": { + "SaleChance": { + "$ref": "#/definitions/model.SaleChance" + }, "amountInvoiced": { "description": "宸插紑绁ㄩ噾棰�", "type": "number" @@ -11382,9 +11385,6 @@ "type": "integer" }, "contactId": { - "type": "integer" - }, - "contractId": { "type": "integer" }, "endTime": { @@ -11405,6 +11405,9 @@ "$ref": "#/definitions/model.Product" } }, + "quotation": { + "$ref": "#/definitions/model.Quotation" + }, "quotationId": { "type": "integer" }, @@ -11414,8 +11417,20 @@ "saleChanceId": { "type": "integer" }, + "salesDetails": { + "$ref": "#/definitions/model.SalesDetails" + }, + "salesDetailsId": { + "type": "integer" + }, + "serviceContractStatus": { + "$ref": "#/definitions/model.ServiceContractStatus" + }, "serviceContractStatusId": { "type": "integer" + }, + "serviceContractType": { + "$ref": "#/definitions/model.ServiceContractType" }, "serviceContractTypeId": { "type": "integer" @@ -12889,9 +12904,6 @@ "contactId": { "type": "integer" }, - "contractId": { - "type": "integer" - }, "endTime": { "type": "string" }, @@ -12914,6 +12926,9 @@ "type": "string" }, "saleChanceId": { + "type": "integer" + }, + "salesDetailsId": { "type": "integer" }, "serviceTimes": { @@ -13536,6 +13551,17 @@ } } }, + "request.DeleteServiceContract": { + "type": "object", + "properties": { + "ids": { + "type": "array", + "items": { + "type": "integer" + } + } + } + }, "request.DeleteServiceFeeManage": { "type": "object", "properties": { @@ -13564,17 +13590,6 @@ "userId": { "description": "鐢ㄦ埛ID", "type": "string" - } - } - }, - "request.DeleteserviceContract": { - "type": "object", - "properties": { - "ids": { - "type": "array", - "items": { - "type": "integer" - } } } }, @@ -15888,9 +15903,6 @@ "contactId": { "type": "integer" }, - "contractId": { - "type": "integer" - }, "endTime": { "type": "string" }, @@ -15918,6 +15930,9 @@ "saleChanceId": { "type": "integer" }, + "salesDetailsId": { + "type": "integer" + }, "serviceTimes": { "type": "integer" }, diff --git a/docs/swagger.json b/docs/swagger.json index d95a065..97e2fca 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -7608,7 +7608,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/request.DeleteserviceContract" + "$ref": "#/definitions/request.DeleteServiceContract" } } ], @@ -7630,7 +7630,7 @@ "tags": [ "ServiceContract" ], - "summary": "鐢熸垚璁″垝鍒楄〃", + "summary": "鏈嶅姟鍚堝悓鍒楄〃", "parameters": [ { "description": "鍙傛暟", @@ -11354,6 +11354,9 @@ "model.ServiceContract": { "type": "object", "properties": { + "SaleChance": { + "$ref": "#/definitions/model.SaleChance" + }, "amountInvoiced": { "description": "宸插紑绁ㄩ噾棰�", "type": "number" @@ -11370,9 +11373,6 @@ "type": "integer" }, "contactId": { - "type": "integer" - }, - "contractId": { "type": "integer" }, "endTime": { @@ -11393,6 +11393,9 @@ "$ref": "#/definitions/model.Product" } }, + "quotation": { + "$ref": "#/definitions/model.Quotation" + }, "quotationId": { "type": "integer" }, @@ -11402,8 +11405,20 @@ "saleChanceId": { "type": "integer" }, + "salesDetails": { + "$ref": "#/definitions/model.SalesDetails" + }, + "salesDetailsId": { + "type": "integer" + }, + "serviceContractStatus": { + "$ref": "#/definitions/model.ServiceContractStatus" + }, "serviceContractStatusId": { "type": "integer" + }, + "serviceContractType": { + "$ref": "#/definitions/model.ServiceContractType" }, "serviceContractTypeId": { "type": "integer" @@ -12877,9 +12892,6 @@ "contactId": { "type": "integer" }, - "contractId": { - "type": "integer" - }, "endTime": { "type": "string" }, @@ -12902,6 +12914,9 @@ "type": "string" }, "saleChanceId": { + "type": "integer" + }, + "salesDetailsId": { "type": "integer" }, "serviceTimes": { @@ -13524,6 +13539,17 @@ } } }, + "request.DeleteServiceContract": { + "type": "object", + "properties": { + "ids": { + "type": "array", + "items": { + "type": "integer" + } + } + } + }, "request.DeleteServiceFeeManage": { "type": "object", "properties": { @@ -13552,17 +13578,6 @@ "userId": { "description": "鐢ㄦ埛ID", "type": "string" - } - } - }, - "request.DeleteserviceContract": { - "type": "object", - "properties": { - "ids": { - "type": "array", - "items": { - "type": "integer" - } } } }, @@ -15876,9 +15891,6 @@ "contactId": { "type": "integer" }, - "contractId": { - "type": "integer" - }, "endTime": { "type": "string" }, @@ -15906,6 +15918,9 @@ "saleChanceId": { "type": "integer" }, + "salesDetailsId": { + "type": "integer" + }, "serviceTimes": { "type": "integer" }, diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 632c09c..058fde4 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -1270,6 +1270,8 @@ type: object model.ServiceContract: properties: + SaleChance: + $ref: '#/definitions/model.SaleChance' amountInvoiced: description: 宸插紑绁ㄩ噾棰� type: number @@ -1283,8 +1285,6 @@ type: integer contactId: type: integer - contractId: - type: integer endTime: type: string id: @@ -1297,14 +1297,24 @@ items: $ref: '#/definitions/model.Product' type: array + quotation: + $ref: '#/definitions/model.Quotation' quotationId: type: integer remark: type: string saleChanceId: type: integer + salesDetails: + $ref: '#/definitions/model.SalesDetails' + salesDetailsId: + type: integer + serviceContractStatus: + $ref: '#/definitions/model.ServiceContractStatus' serviceContractStatusId: type: integer + serviceContractType: + $ref: '#/definitions/model.ServiceContractType' serviceContractTypeId: type: integer serviceTimes: @@ -2296,8 +2306,6 @@ type: integer contactId: type: integer - contractId: - type: integer endTime: type: string memberId: @@ -2313,6 +2321,8 @@ remark: type: string saleChanceId: + type: integer + salesDetailsId: type: integer serviceTimes: type: integer @@ -2746,6 +2756,13 @@ type: integer type: array type: object + request.DeleteServiceContract: + properties: + ids: + items: + type: integer + type: array + type: object request.DeleteServiceFeeManage: properties: ids: @@ -2765,13 +2782,6 @@ userId: description: 鐢ㄦ埛ID type: string - type: object - request.DeleteserviceContract: - properties: - ids: - items: - type: integer - type: array type: object request.DownloadFile: properties: @@ -4341,8 +4351,6 @@ type: integer contactId: type: integer - contractId: - type: integer endTime: type: string id: @@ -4360,6 +4368,8 @@ remark: type: string saleChanceId: + type: integer + salesDetailsId: type: integer serviceTimes: type: integer @@ -9980,7 +9990,7 @@ name: object required: true schema: - $ref: '#/definitions/request.DeleteserviceContract' + $ref: '#/definitions/request.DeleteServiceContract' produces: - application/json responses: @@ -10012,7 +10022,7 @@ data: $ref: '#/definitions/response.ServiceContractsResponse' type: object - summary: 鐢熸垚璁″垝鍒楄〃 + summary: 鏈嶅姟鍚堝悓鍒楄〃 tags: - ServiceContract /api/serviceContract/update: diff --git a/model/invoice.go b/model/invoice.go index ef97ed8..9145a6a 100644 --- a/model/invoice.go +++ b/model/invoice.go @@ -28,6 +28,7 @@ CourierNumber string `gorm:"courier_number" json:"courierNumber"` // 鐗╂祦鍗曞彿 CourierCompanyId int `gorm:"courier_company_id" json:"courierCompanyId"` // 鐗╂祦鍏徃 CourierCompany CourierCompany `gorm:"foreignKey:CourierCompanyId"` + Products []*Product `json:"products" gorm:"many2many:invoice_product;"` } // InvoiceSearch 閿�鍞彂绁ㄦ悳绱㈡潯浠� diff --git a/model/invoiceProduct.go b/model/invoiceProduct.go new file mode 100644 index 0000000..6a8bb50 --- /dev/null +++ b/model/invoiceProduct.go @@ -0,0 +1,131 @@ +package model + +import ( + "aps_crm/pkg/mysqlx" + "gorm.io/gorm" +) + +type ( + // InvoiceProduct 鍚堝悓浜у搧 + InvoiceProduct struct { + InvoiceId int `gorm:"invoice_id" json:"invoiceId"` + ProductId int `gorm:"product_id" json:"productId"` + } + + // InvoiceProductSearch 鍚堝悓浜у搧鎼滅储鏉′欢 + InvoiceProductSearch struct { + InvoiceProduct + Orm *gorm.DB + Keyword string + PageNum int + PageSize int + ProductIds []uint + } +) + +func (InvoiceProduct) TableName() string { + return "invoice_product" +} + +func NewInvoiceProductSearch() *InvoiceProductSearch { + return &InvoiceProductSearch{ + Orm: mysqlx.GetDB(), + } +} + +func (slf *InvoiceProductSearch) build() *gorm.DB { + var db = slf.Orm.Model(&InvoiceProduct{}) + if len(slf.ProductIds) != 0 { + db = db.Where("product_id in ?", slf.ProductIds) + } + if slf.InvoiceId != 0 { + db = db.Where("invoice_id = ?", slf.InvoiceId) + } + + return db +} + +func (slf *InvoiceProductSearch) Create(record *InvoiceProduct) error { + var db = slf.build() + return db.Create(record).Error +} + +func (slf *InvoiceProductSearch) CreateBatch(records []*InvoiceProduct) error { + var db = slf.build() + return db.Create(records).Error +} + +func (slf *InvoiceProductSearch) Delete() error { + var db = slf.build() + return db.Delete(&InvoiceProduct{}).Error +} + +func (slf *InvoiceProductSearch) Update(record *InvoiceProduct) error { + var db = slf.build() + return db.Updates(record).Error +} + +func (slf *InvoiceProductSearch) FindAll() ([]*InvoiceProduct, error) { + var db = slf.build() + var record = make([]*InvoiceProduct, 0) + err := db.Find(&record).Error + return record, err +} + +func (slf *InvoiceProductSearch) SetProductIds(ids []uint) *InvoiceProductSearch { + slf.ProductIds = ids + return slf +} + +func (slf *InvoiceProductSearch) SetInvoiceId(id int) *InvoiceProductSearch { + slf.InvoiceId = id + return slf +} + +func (slf *InvoiceProductSearch) SetOrm(tx *gorm.DB) *InvoiceProductSearch { + slf.Orm = tx + return slf +} + +func (slf *InvoiceProductSearch) First() (*InvoiceProduct, error) { + var db = slf.build() + var record = new(InvoiceProduct) + err := db.First(record).Error + return record, err +} + +func (slf *InvoiceProductSearch) Updates(values interface{}) error { + var db = slf.build() + return db.Updates(values).Error +} + +func (slf *InvoiceProductSearch) Find() ([]*InvoiceProduct, int64, error) { + var db = slf.build() + var records = make([]*InvoiceProduct, 0) + var total int64 + if err := db.Count(&total).Error; err != nil { + return records, total, err + } + if slf.PageNum > 0 && slf.PageSize > 0 { + db = db.Limit(slf.PageSize).Offset((slf.PageNum - 1) * slf.PageSize) + } + + err := db.Find(&records).Error + return records, total, err +} + +// InitDefaultData 鍒濆鍖栨暟鎹� +func (slf *InvoiceProductSearch) InitDefaultData() error { + var ( + db = slf.Orm.Table(slf.TableName()) + total int64 = 0 + ) + if err := db.Count(&total).Error; err != nil { + return err + } + if total != 0 { + return nil + } + records := []*InvoiceProduct{} + return slf.CreateBatch(records) +} diff --git a/model/product.go b/model/product.go index 029857b..a61ee23 100644 --- a/model/product.go +++ b/model/product.go @@ -1,15 +1,18 @@ package model -import "gorm.io/gorm" +import ( + "github.com/shopspring/decimal" + "gorm.io/gorm" +) type Product struct { - Id int `json:"id" gorm:"column:id;primary_key;AUTO_INCREMENT"` - Name string `json:"name" gorm:"column:name;type:varchar(255);comment:浜у搧鍚嶇О"` - Price float64 `json:"price" gorm:"column:price;type:decimal(10,2);comment:浜у搧浠锋牸"` - Number string `json:"number" gorm:"column:number;type:varchar(255);comment:浜у搧缂栧彿"` - Amount int `json:"amount" gorm:"column:amount;type:int;comment:浜у搧鏁伴噺"` - Total float64 `json:"total" gorm:"column:total;type:decimal(10,2);comment:浜у搧鎬讳环"` - Desc string `json:"desc" gorm:"column:desc;type:varchar(255);comment:浜у搧鎻忚堪"` + Id uint `json:"id" gorm:"column:id;primary_key;AUTO_INCREMENT"` + Name string `json:"name" gorm:"column:name;type:varchar(255);comment:浜у搧鍚嶇О"` + Price decimal.Decimal `json:"price" gorm:"column:price;type:decimal(10,2);comment:浜у搧浠锋牸"` + Number string `json:"number" gorm:"column:number;type:varchar(255);comment:浜у搧缂栧彿"` + Amount decimal.Decimal `json:"amount" gorm:"column:amount;type:int;comment:浜у搧鏁伴噺"` + Total decimal.Decimal `json:"total" gorm:"column:total;type:decimal(10,2);comment:浜у搧鎬讳环"` + Desc string `json:"desc" gorm:"column:desc;type:varchar(255);comment:浜у搧鎻忚堪"` gorm.Model `json:"-"` } diff --git a/model/request/invoice.go b/model/request/invoice.go index 1b1eddd..526af5f 100644 --- a/model/request/invoice.go +++ b/model/request/invoice.go @@ -2,6 +2,7 @@ import ( "aps_crm/constvar" + "aps_crm/model" ) type AddInvoice struct { @@ -17,22 +18,24 @@ InvoiceDate string `gorm:"invoice_date" json:"invoiceDate"` // 寮�绁ㄦ棩鏈� CourierNumber string `gorm:"courier_number" json:"courierNumber"` // 鐗╂祦鍗曞彿 CourierCompanyId int `gorm:"courier_company_id" json:"courierCompanyId"` // 鐗╂祦鍏徃 + Products []model.Product `json:"products"` //鍙戠エ瀵瑰簲浜у搧锛屼粠鐩稿簲婧愬崟閲岃幏鍙� } type UpdateInvoice struct { - Id int `json:"id"` - ClientId int `gorm:"client_id" json:"clientId"` // 瀹㈡埛id - InvoiceTypeId int `gorm:"invoice_type_id" json:"invoiceTypeId"` // 鍙戠エ绫诲瀷id - PrincipalId int `gorm:"principal_id" json:"principalId"` // 閿�鍞礋璐d汉id - Subject string `gorm:"subject" json:"subject"` // 涓婚 - InvoiceStatusId int `gorm:"invoice_status_id" json:"invoiceStatusId"` // 鍙戠エ鐘舵�乮d - SourceType int `gorm:"source_type" json:"sourceType"` // 婧愬崟绫诲瀷(1閿�鍞槑缁嗗崟2鏈嶅姟鍚堝悓) - SourceId int `gorm:"source_id" json:"sourceId"` // 婧愬崟id - TaxpayerIdNumber string `gorm:"taxpayer_id_number" json:"taxpayerIdNumber"` // 绾崇◣璇嗗埆鍙� - InvoiceNumber string `gorm:"invoice_number" json:"invoiceNumber"` // 鍙戠エ鍙风爜 - InvoiceDate int `gorm:"invoice_date" json:"invoiceDate"` // 寮�绁ㄦ棩鏈� - CourierNumber string `gorm:"courier_number" json:"courierNumber"` // 鐗╂祦鍗曞彿 - CourierCompanyId int `gorm:"courier_company_id" json:"courierCompanyId"` // 鐗╂祦鍏徃 + Id int `json:"id" binding:"required"` + ClientId int `gorm:"client_id" json:"clientId"` // 瀹㈡埛id + InvoiceTypeId int `gorm:"invoice_type_id" json:"invoiceTypeId"` // 鍙戠エ绫诲瀷id + PrincipalId int `gorm:"principal_id" json:"principalId"` // 閿�鍞礋璐d汉id + Subject string `gorm:"subject" json:"subject"` // 涓婚 + InvoiceStatusId int `gorm:"invoice_status_id" json:"invoiceStatusId"` // 鍙戠エ鐘舵�乮d + SourceType int `gorm:"source_type" json:"sourceType"` // 婧愬崟绫诲瀷(1閿�鍞槑缁嗗崟2鏈嶅姟鍚堝悓) + SourceId int `gorm:"source_id" json:"sourceId"` // 婧愬崟id + TaxpayerIdNumber string `gorm:"taxpayer_id_number" json:"taxpayerIdNumber"` // 绾崇◣璇嗗埆鍙� + InvoiceNumber string `gorm:"invoice_number" json:"invoiceNumber"` // 鍙戠エ鍙风爜 + InvoiceDate int `gorm:"invoice_date" json:"invoiceDate"` // 寮�绁ㄦ棩鏈� + CourierNumber string `gorm:"courier_number" json:"courierNumber"` // 鐗╂祦鍗曞彿 + CourierCompanyId int `gorm:"courier_company_id" json:"courierCompanyId"` // 鐗╂祦鍏徃 + Products []model.Product `json:"products"` //鍙戠エ瀵瑰簲浜у搧锛屼粠鐩稿簲婧愬崟閲岃幏鍙� } type GetInvoiceList struct { diff --git a/model/request/serviceContract.go b/model/request/serviceContract.go index 2ad8995..65068e4 100644 --- a/model/request/serviceContract.go +++ b/model/request/serviceContract.go @@ -1,45 +1,45 @@ -package request - -import ( - "aps_crm/constvar" - "aps_crm/model" -) - -type AddServiceContract struct { - ServiceContract -} - -type ServiceContract struct { - ClientId int `json:"clientId"` - Number string `json:"number"` - MemberId int `json:"memberId"` - ContactId int `json:"contactId"` - SaleChanceId int `json:"saleChanceId"` - ContractId int `json:"contractId"` - QuotationId int `json:"quotationId"` - TypeId int `json:"typeId"` - SignTime string `json:"signTime"` - StartTime string `json:"startTime"` - EndTime string `json:"endTime"` - StatusId int `json:"statusId"` - ServiceTimes int `json:"serviceTimes"` - Terms string `json:"terms"` - Remark string `json:"remark"` - Products []model.Product `json:"products"` -} - -type UpdateServiceContract struct { - Id int `json:"id"` - ServiceContract -} - -type GetServiceContractList struct { - PageInfo - QueryClass constvar.ServiceContractQueryClass `json:"queryClass"` - KeywordType constvar.ServiceContractKeywordType `json:"keywordType"` - Keyword string `json:"keyword"` -} - -type DeleteserviceContract struct { - Ids []int `json:"ids"` -} +package request + +import ( + "aps_crm/constvar" + "aps_crm/model" +) + +type AddServiceContract struct { + ServiceContract +} + +type ServiceContract struct { + ClientId int `json:"clientId"` + Number string `json:"number"` + MemberId int `json:"memberId"` + ContactId int `json:"contactId"` + SaleChanceId int `json:"saleChanceId"` + SalesDetailsId int `json:"salesDetailsId"` + QuotationId int `json:"quotationId"` + TypeId int `json:"typeId"` + SignTime string `json:"signTime" binding:"datetime=2006-01-02"` + StartTime string `json:"startTime" binding:"datetime=2006-01-02"` + EndTime string `json:"endTime" binding:"datetime=2006-01-02"` + StatusId int `json:"statusId"` + ServiceTimes int `json:"serviceTimes"` + Terms string `json:"terms"` + Remark string `json:"remark"` + Products []*model.Product `json:"products"` +} + +type UpdateServiceContract struct { + Id int `json:"id"` + ServiceContract +} + +type GetServiceContractList struct { + PageInfo + QueryClass constvar.ServiceContractQueryClass `json:"queryClass"` + KeywordType constvar.ServiceContractKeywordType `json:"keywordType"` + Keyword string `json:"keyword"` +} + +type DeleteServiceContract struct { + Ids []int `json:"ids"` +} diff --git a/model/serviceContract.go b/model/serviceContract.go index 5c5a497..651ad73 100644 --- a/model/serviceContract.go +++ b/model/serviceContract.go @@ -11,26 +11,32 @@ type ( ServiceContract struct { - Id int `json:"id" gorm:"column:id;primary_key;AUTO_INCREMENT"` - ClientId int `json:"clientId" gorm:"column:client_id;type:int;comment:瀹㈡埛id"` - Number string `json:"number" gorm:"column:number;type:varchar(255);comment:鍚堝悓缂栧彿"` - MemberId int `json:"memberId" gorm:"column:member_id;type:int;comment:璐熻矗浜篿d"` - ContactId int `json:"contactId" gorm:"column:contact_id;type:int;comment:鑱旂郴浜篿d"` - SaleChanceId int `json:"saleChanceId" gorm:"column:sale_chance_id;type:int;comment:閿�鍞満浼歩d"` - ContractId int `json:"contractId" gorm:"column:contract_id;type:int;comment:鍚堝悓id"` - QuotationId int `json:"quotationId" gorm:"column:quotation_id;type:int;comment:鎶ヤ环鍗昳d"` - ServiceContractTypeId int `json:"serviceContractTypeId" gorm:"column:service_contract_type_id;type:int;comment:鍚堝悓绫诲瀷id"` - SignTime time.Time `json:"signTime" gorm:"column:sign_time;type:datetime;comment:绛剧害鏃堕棿"` - StartTime time.Time `json:"startTime" gorm:"column:start_time;type:datetime;comment:寮�濮嬫椂闂�"` - EndTime time.Time `json:"endTime" gorm:"column:end_time;type:datetime;comment:缁撴潫鏃堕棿"` - ServiceContractStatusId int `json:"serviceContractStatusId" gorm:"column:service_contract_status_id;type:int;comment:鍚堝悓鐘舵�乮d"` - ServiceTimes int `json:"serviceTimes" gorm:"column:service_times;type:int;comment:鏈嶅姟娆℃暟"` - Terms string `json:"terms" gorm:"column:terms;type:text;comment:鏉℃"` - Remark string `json:"remark" gorm:"column:remark;type:text;comment:澶囨敞"` - AmountReceivable decimal.Decimal `gorm:"amount_receivable" json:"amountReceivable"` // 搴旀敹閲戦 - AmountReceived decimal.Decimal `gorm:"amount_received" json:"amountReceived"` // 宸叉敹閲戦 - AmountInvoiced decimal.Decimal `gorm:"amount_invoiced" json:"amountInvoiced"` // 宸插紑绁ㄩ噾棰� - Products []Product `json:"products" gorm:"many2many:serviceContract_product;"` + Id int `json:"id" gorm:"column:id;primary_key;AUTO_INCREMENT"` + ClientId int `json:"clientId" gorm:"column:client_id;type:int;comment:瀹㈡埛id"` + Number string `json:"number" gorm:"column:number;type:varchar(255);comment:鍚堝悓缂栧彿"` + MemberId int `json:"memberId" gorm:"column:member_id;type:int;comment:璐熻矗浜篿d"` + ContactId int `json:"contactId" gorm:"column:contact_id;type:int;comment:鑱旂郴浜篿d"` + SaleChanceId int `json:"saleChanceId" gorm:"column:sale_chance_id;type:int;comment:閿�鍞満浼歩d"` + SaleChance SaleChance `json:"SaleChance" gorm:"foreignKey:SaleChanceId"` + SalesDetailsId int `json:"salesDetailsId" gorm:"column:sales_details_id;type:int;comment:鍚堝悓璁㈠崟id"` + SalesDetails SalesDetails `json:"salesDetails" gorm:"foreignKey:SalesDetailsId"` + QuotationId int `json:"quotationId" gorm:"column:quotation_id;type:int;comment:鎶ヤ环鍗昳d"` + Quotation Quotation `json:"quotation" gorm:"foreignKey:QuotationId"` + ServiceContractTypeId int `json:"serviceContractTypeId" gorm:"column:service_contract_type_id;type:int;comment:鍚堝悓绫诲瀷id"` + ServiceContractType ServiceContractType `json:"serviceContractType" gorm:"foreignKey:ServiceContractTypeId"` + SignTime string `json:"signTime" gorm:"column:sign_time;type:datetime;comment:绛剧害鏃堕棿"` + StartTime string `json:"startTime" gorm:"column:start_time;type:datetime;comment:寮�濮嬫椂闂�"` + EndTime string `json:"endTime" gorm:"column:end_time;type:datetime;comment:缁撴潫鏃堕棿"` + ServiceContractStatusId int `json:"serviceContractStatusId" gorm:"column:service_contract_status_id;type:int;comment:鍚堝悓鐘舵�乮d"` + ServiceContractStatus ServiceContractStatus `json:"serviceContractStatus" gorm:"foreignKey:ServiceContractStatusId"` + ServiceTimes int `json:"serviceTimes" gorm:"column:service_times;type:int;comment:鏈嶅姟娆℃暟"` + Terms string `json:"terms" gorm:"column:terms;type:text;comment:鏉℃"` + Remark string `json:"remark" gorm:"column:remark;type:text;comment:澶囨敞"` + AmountReceivable decimal.Decimal `gorm:"amount_receivable" json:"amountReceivable"` // 搴旀敹閲戦 + AmountReceived decimal.Decimal `gorm:"amount_received" json:"amountReceived"` // 宸叉敹閲戦 + AmountInvoiced decimal.Decimal `gorm:"amount_invoiced" json:"amountInvoiced"` // 宸插紑绁ㄩ噾棰� + AmountUnInvoiced decimal.Decimal `gorm:"-" json:"amountUnInvoiced"` // 鏈紑绁ㄩ噾棰� + Products []*Product `json:"products" gorm:"many2many:service_contract_product;"` gorm.Model `json:"-"` } @@ -44,6 +50,7 @@ OrderBy string PageNum int PageSize int + Preload bool } ) @@ -64,13 +71,13 @@ } switch slf.QueryClass { case constvar.ServiceContractQueryClassExpireAfter30Day: - db = db.Where("end_time > ?", time.Now(), time.Now().AddDate(0, 0, 30)) + db = db.Where("end_time > ?", time.Now().AddDate(0, 0, 30).Format("2006-01-02")) case constvar.ServiceContractQueryClassExpireAfter60Day: - db = db.Where("end_time > ?", time.Now(), time.Now().AddDate(0, 0, 60)) + db = db.Where("end_time > ?", time.Now().AddDate(0, 0, 60).Format("2006-01-02")) case constvar.ServiceContractQueryClassExpiredBefore15Day: - db = db.Where("end_time < ?", time.Now().AddDate(0, 0, -15)) + db = db.Where("end_time < ?", time.Now().AddDate(0, 0, -15).Format("2006-01-02")) case constvar.ServiceContractQueryClassExpiredBefore60Day: - db = db.Where("end_time < ?", time.Now().AddDate(0, 0, -60)) + db = db.Where("end_time < ?", time.Now().AddDate(0, 0, -60).Format("2006-01-02")) } switch slf.KeywordType { @@ -97,6 +104,15 @@ //todo } + if slf.Preload { + db = db. + Preload("SaleChance"). + Preload("SalesDetails"). + Preload("Quotation"). + Preload("ServiceContractType"). + Preload("ServiceContractStatus"). + Preload("Products") + } return db } @@ -116,14 +132,7 @@ return db.Delete(&ServiceContract{}).Error } -func (slf *ServiceContractSearch) Find() (*ServiceContract, error) { - var db = slf.build() - var record = &ServiceContract{} - err := db.First(record).Error - return record, err -} - -func (slf *ServiceContractSearch) FindAll() ([]*ServiceContract, int64, error) { +func (slf *ServiceContractSearch) Find() ([]*ServiceContract, int64, error) { var db = slf.build() var records = make([]*ServiceContract, 0) var total int64 @@ -134,11 +143,7 @@ db = db.Limit(slf.PageSize).Offset((slf.PageNum - 1) * slf.PageSize) } - if slf.PageNum > 0 && slf.PageSize > 0 { - db = db.Limit(slf.PageSize).Offset((slf.PageNum - 1) * slf.PageSize) - } - - err := db.Preload("Products").Find(&records).Error + err := db.Find(&records).Error return records, total, err } @@ -176,6 +181,11 @@ return slf } +func (slf *ServiceContractSearch) SetPreload(preload bool) *ServiceContractSearch { + slf.Preload = preload + return slf +} + func (slf *ServiceContractSearch) UpdateByMap(upMap map[string]interface{}) error { var ( db = slf.build() diff --git a/pkg/contextx/contextx.go b/pkg/contextx/contextx.go index 95a29c6..77a9b64 100644 --- a/pkg/contextx/contextx.go +++ b/pkg/contextx/contextx.go @@ -1,101 +1,102 @@ -package contextx - -import ( - "aps_crm/pkg/ecode" - "aps_crm/pkg/logx" - "github.com/gin-gonic/gin" - "net/http" -) - -type ( - Context struct { - ctx *gin.Context - paramsMap map[string]interface{} - } - - Response struct { - Code int `json:"code"` - Data interface{} `json:"data"` - Msg string `json:"msg"` - } -) - -func NewContext(ctx *gin.Context, params interface{}) (r *Context, isAllow bool) { - r = &Context{ - ctx: ctx, - } - if r.ctx.Request.Method == "OPTIONS" { - r.ctx.String(http.StatusOK, "") - return - } - - defer func() { - query := r.ctx.Request.URL.RawQuery - if query != "" { - query = "?" + query - } - urlPath := r.ctx.Request.URL.Path - logx.Infof("%s | %s %s | uid: %s | %+v", ctx.ClientIP(), r.ctx.Request.Method, urlPath+query, r.GetUserId(), params) - }() - - // validate params - if params != nil { - if err := r.ctx.ShouldBind(params); err != nil { - r.Fail(ecode.ParamsErr) - return - } - } - isAllow = true - return -} - -func (slf *Context) GetRequestPath() (r string) { - r = slf.ctx.Request.URL.Path - return -} - -func (slf *Context) GetUserId() (r string) { - v := slf.paramsMap["userId"] - switch v.(type) { - case string: - r = v.(string) - } - return -} - -func (slf *Context) Result(code int, data interface{}, msg string) { - slf.ctx.JSON(http.StatusOK, Response{ - Code: code, - Data: data, - Msg: msg, - }) -} - -func (slf *Context) Ok() { - slf.Result(ecode.OK, map[string]interface{}{}, "") -} - -func (slf *Context) OkWithDetailed(data interface{}) { - slf.Result(ecode.OK, data, "") -} - -func (slf *Context) Fail(errCode int) { - slf.Result(errCode, map[string]interface{}{}, ecode.GetMsg(errCode)) -} - -func (slf *Context) FailWithMsg(errCode int, msg string) { - slf.Result(errCode, map[string]interface{}{}, msg) -} - -func (slf *Context) FailWithDetailed(errCode int, data interface{}) { - slf.Result(errCode, data, ecode.GetMsg(errCode)) -} - -func (slf *Context) GetCtx() *gin.Context { - return slf.ctx -} - -func (slf *Context) SetCtx(c *gin.Context) *Context { - slf.ctx = c - return slf -} +package contextx + +import ( + "aps_crm/pkg/ecode" + "aps_crm/pkg/logx" + "github.com/gin-gonic/gin" + "net/http" +) + +type ( + Context struct { + ctx *gin.Context + paramsMap map[string]interface{} + } + + Response struct { + Code int `json:"code"` + Data interface{} `json:"data"` + Msg string `json:"msg"` + } +) + +func NewContext(ctx *gin.Context, params interface{}) (r *Context, isAllow bool) { + r = &Context{ + ctx: ctx, + } + if r.ctx.Request.Method == "OPTIONS" { + r.ctx.String(http.StatusOK, "") + return + } + + defer func() { + query := r.ctx.Request.URL.RawQuery + if query != "" { + query = "?" + query + } + urlPath := r.ctx.Request.URL.Path + logx.Infof("%s | %s %s | uid: %s | %+v", ctx.ClientIP(), r.ctx.Request.Method, urlPath+query, r.GetUserId(), params) + }() + + // validate params + if params != nil { + if err := r.ctx.ShouldBind(params); err != nil { + logx.Errorf("bind param error: %v", err.Error()) + r.Fail(ecode.ParamsErr) + return + } + } + isAllow = true + return +} + +func (slf *Context) GetRequestPath() (r string) { + r = slf.ctx.Request.URL.Path + return +} + +func (slf *Context) GetUserId() (r string) { + v := slf.paramsMap["userId"] + switch v.(type) { + case string: + r = v.(string) + } + return +} + +func (slf *Context) Result(code int, data interface{}, msg string) { + slf.ctx.JSON(http.StatusOK, Response{ + Code: code, + Data: data, + Msg: msg, + }) +} + +func (slf *Context) Ok() { + slf.Result(ecode.OK, map[string]interface{}{}, "") +} + +func (slf *Context) OkWithDetailed(data interface{}) { + slf.Result(ecode.OK, data, "") +} + +func (slf *Context) Fail(errCode int) { + slf.Result(errCode, map[string]interface{}{}, ecode.GetMsg(errCode)) +} + +func (slf *Context) FailWithMsg(errCode int, msg string) { + slf.Result(errCode, map[string]interface{}{}, msg) +} + +func (slf *Context) FailWithDetailed(errCode int, data interface{}) { + slf.Result(errCode, data, ecode.GetMsg(errCode)) +} + +func (slf *Context) GetCtx() *gin.Context { + return slf.ctx +} + +func (slf *Context) SetCtx(c *gin.Context) *Context { + slf.ctx = c + return slf +} diff --git a/pkg/ecode/code.go b/pkg/ecode/code.go index a574c94..6a3d1a2 100644 --- a/pkg/ecode/code.go +++ b/pkg/ecode/code.go @@ -235,12 +235,15 @@ PlanUpdateErr = 3200005 // 鏇存柊璁″垝澶辫触 PlanDeleteErr = 3200006 // 鍒犻櫎璁″垝澶辫触 - SContractExist = 3300001 // 鏈嶅姟鍚堝悓宸插瓨鍦� - SContractNotExist = 3300002 // 鏈嶅姟鍚堝悓涓嶅瓨鍦� - SContractListErr = 3300003 // 鑾峰彇鏈嶅姟鍚堝悓鍒楄〃澶辫触 - SContractSetErr = 3300004 // 璁剧疆鏈嶅姟鍚堝悓澶辫触 - SContractUpdateErr = 3300005 // 鏇存柊鏈嶅姟鍚堝悓澶辫触 - SContractDeleteErr = 3300006 // 鍒犻櫎鏈嶅姟鍚堝悓澶辫触 + SContractExist = 3300001 // 鏈嶅姟鍚堝悓宸插瓨鍦� + SContractNotExist = 3300002 // 鏈嶅姟鍚堝悓涓嶅瓨鍦� + SContractListErr = 3300003 // 鑾峰彇鏈嶅姟鍚堝悓鍒楄〃澶辫触 + SContractSetErr = 3300004 // 璁剧疆鏈嶅姟鍚堝悓澶辫触 + SContractUpdateErr = 3300005 // 鏇存柊鏈嶅姟鍚堝悓澶辫触 + SContractDeleteErr = 3300006 // 鍒犻櫎鏈嶅姟鍚堝悓澶辫触 + SContractProductPriceLowerThanInvoiceAmountErr = 3300007 //浜у搧鎬讳环浣庝簬宸插紑绁ㄩ噾棰� + SContractProductPriceLowerThanReceivedAmountErr = 3300008 //浜у搧鎬讳环浣庝簬宸叉敹閲戦 + SContractInvoiceProductPriceGreaterThanReceivableAmountErr = 3300009 //寮�绁ㄦ�婚楂樹簬搴旀敹閲戦 OrderManageExist = 3400001 // 璁㈠崟绠$悊宸插瓨鍦� OrderManageNotExist = 3400002 // 璁㈠崟绠$悊涓嶅瓨鍦� diff --git a/pkg/ecode/msg.go b/pkg/ecode/msg.go index 5b43237..deeff57 100644 --- a/pkg/ecode/msg.go +++ b/pkg/ecode/msg.go @@ -20,6 +20,9 @@ ChildrenExistErr: "瀛樺湪瀛愯彍鍗�", MenuNotExist: "鑿滃崟涓嶅瓨鍦�", MenuNameExistErr: "鑿滃崟鍚嶅凡瀛樺湪", + SContractProductPriceLowerThanInvoiceAmountErr: "浜у搧鎬讳环浣庝簬宸插紑绁ㄩ噾棰�", + SContractProductPriceLowerThanReceivedAmountErr: "浜у搧鎬讳环浣庝簬宸叉敹閲戦", + SContractInvoiceProductPriceGreaterThanReceivableAmountErr: "寮�绁ㄦ�婚楂樹簬搴旀敹閲戦", } func GetMsg(errCode int) (errMsg string) { diff --git a/service/invoice.go b/service/invoice.go index 9bd1b91..59301a9 100644 --- a/service/invoice.go +++ b/service/invoice.go @@ -1,9 +1,11 @@ package service import ( + "aps_crm/constvar" "aps_crm/model" "aps_crm/model/request" "aps_crm/pkg/ecode" + "github.com/shopspring/decimal" "gorm.io/gorm" ) @@ -15,30 +17,32 @@ func (InvoiceService) AddInvoice(invoice *model.Invoice) int { - err := model.WithTransaction(func(db *gorm.DB) error { - err := model.NewInvoiceSearch().Create(invoice) + if invoice.SourceType == constvar.InvoiceSourceTypeServiceContract { + serviceContract, err := model.NewServiceContractSearch().SetId(invoice.SourceId).SetPreload(true).First() if err != nil { - return err + return ecode.DBErr } - //if invoice.SourceType == constvar.InvoiceSourceTypeServiceContract { - // contract,err := model.NewServiceContractSearch().SetId(invoice.SourceId).First() - // if err != nil { - // return err - // } - // AmountInvoiced := contract.AmountReceived.Add() - // err := model.NewServiceContractSearch().SetId(invoice.SourceId).UpdateByMap(map[string]interface{}{ - // "amount_received" : - // }) - // if err != nil { - // return err - // } - //} - - return nil - }) - - if err != nil { - return ecode.DBErr + var amountInvoiced decimal.Decimal + rightProducts := NewProductsService().PickRightProducts(invoice.Products, serviceContract.Products) + for _, product := range rightProducts { + amountInvoiced = serviceContract.AmountInvoiced.Add(product.Amount.Mul(product.Price)) + } + amountInvoiced = amountInvoiced.Round(2) + if amountInvoiced.GreaterThan(serviceContract.AmountReceivable) { + return ecode.SContractInvoiceProductPriceGreaterThanReceivableAmountErr + } + err = model.WithTransaction(func(db *gorm.DB) error { + err = model.NewInvoiceSearch().Create(invoice) + if err != nil { + return err + } + return model.NewServiceContractSearch().SetId(invoice.SourceId).UpdateByMap(map[string]interface{}{ + "amount_invoiced": amountInvoiced, + }) + }) + if err != nil { + return ecode.DBErr + } } return ecode.OK @@ -79,9 +83,43 @@ } func (InvoiceService) UpdateInvoice(invoice *model.Invoice) int { - err := model.NewInvoiceSearch().SetId(invoice.Id).Save(invoice) - if err != nil { - return ecode.DBErr + if invoice.SourceType == constvar.InvoiceSourceTypeServiceContract { + serviceContract, err := model.NewServiceContractSearch().SetId(invoice.SourceId).SetPreload(true).First() + if err != nil { + return ecode.DBErr + } + var amountInvoiced decimal.Decimal + newProducts, removedProducts := NewProductsService().PickDiffProducts(invoice.Products, serviceContract.Products) + for _, product := range newProducts { + amountInvoiced = serviceContract.AmountInvoiced.Add(product.Amount.Mul(product.Price)) + } + removedProductIds := make([]uint, 0, len(removedProducts)) + for _, product := range removedProducts { + amountInvoiced = serviceContract.AmountInvoiced.Sub(product.Amount.Mul(product.Price)) + removedProductIds = append(removedProductIds, product.Id) + } + amountInvoiced = amountInvoiced.Round(2) + if amountInvoiced.GreaterThan(serviceContract.AmountReceivable) { + return ecode.SContractInvoiceProductPriceGreaterThanReceivableAmountErr + } + err = model.WithTransaction(func(db *gorm.DB) error { + err = model.NewInvoiceSearch().SetId(invoice.Id).Save(invoice) + if err != nil { + return err + } + if len(removedProductIds) > 0 { + err = model.NewInvoiceProductSearch().SetInvoiceId(invoice.Id).SetProductIds(removedProductIds).Delete() + if err != nil { + return err + } + } + return model.NewServiceContractSearch().SetId(invoice.SourceId).UpdateByMap(map[string]interface{}{ + "amount_invoiced": amountInvoiced, + }) + }) + if err != nil { + return ecode.DBErr + } } return ecode.OK } diff --git a/service/products.go b/service/products.go new file mode 100644 index 0000000..e8d46e5 --- /dev/null +++ b/service/products.go @@ -0,0 +1,50 @@ +package service + +import ( + "aps_crm/model" +) + +type ProductsService struct{} + +func NewProductsService() ProductsService { + return ProductsService{} +} + +func (slf ProductsService) PickRightProducts(products, sourceProducts []*model.Product) (rightProducts []*model.Product) { + productIdMap, productNumberMap := slf.getMappedProducts(sourceProducts) + for _, product := range products { + if p, ok := productIdMap[product.Id]; ok { + rightProducts = append(rightProducts, p) + } else if p, ok = productNumberMap[product.Number]; ok { + rightProducts = append(rightProducts, p) + } + } + return +} + +func (slf ProductsService) PickDiffProducts(products, sourceProducts []*model.Product) (newProducts, removedProducts []*model.Product) { + productIdMap, productNumberMap := slf.getMappedProducts(sourceProducts) + productNumberMap2 := make(map[string]*model.Product, len(products)) + for _, product := range products { + if productIdMap[product.Id] == nil && productNumberMap[product.Number] == nil { + newProducts = append(newProducts, product) + } + productNumberMap2[product.Number] = product + } + for productNumber, product := range productNumberMap { + if productNumberMap2[productNumber] == nil { + removedProducts = append(removedProducts, product) + } + } + return +} + +func (slf ProductsService) getMappedProducts(sourceProducts []*model.Product) (map[uint]*model.Product, map[string]*model.Product) { + productIdMap := make(map[uint]*model.Product, len(sourceProducts)) + productNumberMap := make(map[string]*model.Product, len(sourceProducts)) + for _, product := range sourceProducts { + productIdMap[product.Id] = product + productNumberMap[product.Number] = product + } + return productIdMap, productNumberMap +} diff --git a/service/serviceContract.go b/service/serviceContract.go index 45907c8..eb901f2 100644 --- a/service/serviceContract.go +++ b/service/serviceContract.go @@ -4,11 +4,19 @@ "aps_crm/constvar" "aps_crm/model" "aps_crm/pkg/ecode" + "github.com/shopspring/decimal" ) type SContractService struct{} func (SContractService) AddServiceContract(serviceContract *model.ServiceContract) int { + serviceContract.AmountReceivable = decimal.Zero.Round(2) + serviceContract.AmountInvoiced = decimal.Zero.Round(2) + serviceContract.AmountReceived = decimal.Zero.Round(2) + for _, product := range serviceContract.Products { + serviceContract.AmountReceivable = serviceContract.AmountReceivable.Add(product.Amount.Mul(product.Price)) + } + serviceContract.AmountReceivable = serviceContract.AmountReceivable.Round(2) err := model.NewServiceContractSearch().Create(serviceContract) if err != nil { return ecode.SContractExist @@ -19,11 +27,23 @@ func (SContractService) UpdateServiceContract(serviceContract *model.ServiceContract) int { // check serviceContract exist - _, err := model.NewServiceContractSearch().SetId(serviceContract.Id).Find() + old, err := model.NewServiceContractSearch().SetId(serviceContract.Id).First() if err != nil { return ecode.SContractNotExist } - + var amountReceivable decimal.Decimal + for _, product := range serviceContract.Products { + amountReceivable = serviceContract.AmountReceivable.Add(product.Amount.Mul(product.Price)) + } + if amountReceivable.LessThan(serviceContract.AmountInvoiced) { + return ecode.SContractProductPriceLowerThanInvoiceAmountErr + } + if amountReceivable.LessThan(serviceContract.AmountReceived) { + return ecode.SContractProductPriceLowerThanReceivedAmountErr + } + serviceContract.AmountInvoiced = old.AmountReceived + serviceContract.AmountReceived = old.AmountReceived + serviceContract.AmountReceivable = amountReceivable.Round(2) err = model.NewServiceContractSearch().SetId(serviceContract.Id).Update(serviceContract) if err != nil { return ecode.SContractSetErr @@ -56,7 +76,9 @@ SetKeyword(keyword). SetKeywordType(keywordType). SetQueryClass(queryClass). - SetPage(page, pageSize).FindAll() + SetPage(page, pageSize). + SetPreload(true). + Find() if err != nil { return nil, 0, ecode.SContractListErr } -- Gitblit v1.8.0