From 7f589e6514eb4074d9a558bf4ff7efef3143b9db Mon Sep 17 00:00:00 2001
From: zhangqian <zhangqian@123.com>
Date: 星期五, 11 八月 2023 10:32:04 +0800
Subject: [PATCH] 新增,删除,和修改发票时修改销售明细未开票金额和已开票金额

---
 model/serviceContract.go      |    6 
 service/salesDetails.go       |    4 
 model/salesDetails.go         |   24 ++++-
 model/request/salesDetails.go |   34 ++++----
 model/serviceOrderStatus.go   |   14 +-
 service/invoice.go            |  137 +++++++++++++++++++++++++++++++--
 6 files changed, 174 insertions(+), 45 deletions(-)

diff --git a/model/request/salesDetails.go b/model/request/salesDetails.go
index 1d12f61..7758bf6 100644
--- a/model/request/salesDetails.go
+++ b/model/request/salesDetails.go
@@ -10,23 +10,23 @@
 }
 
 type SalesDetails struct {
-	ClientId            int             `json:"clientId" gorm:"column:client_id;type:int;comment:瀹㈡埛id"`
-	Number              string          `json:"number" gorm:"column:number;type:varchar(255);comment:閿�鍞瓙鍗曞彿"`
-	SaleChanceId        int             `json:"saleChanceId" gorm:"column:sale_chance_id;type:int;comment:閿�鍞満浼歩d"`
-	SaleType            int             `json:"saleType" gorm:"column:sale_type;type:int;comment:閿�鍞被鍨�"`
-	SignTime            string          `json:"signTime" gorm:"column:sign_time;type:datetime;comment:绛惧崟鏃堕棿"`
-	MemberId            int             `json:"memberId" gorm:"column:member_id;type:int;comment:璐熻矗浜篿d"`
-	DeliveryDate        string          `json:"deliveryDate" gorm:"column:delivery_date;type:datetime;comment:浜よ揣鏃ユ湡"`
-	WechatOrderStatusId int             `json:"wechatOrderStatusId" gorm:"column:wechat_order_status_id;type:int;comment:寰俊璁㈠崟鐘舵�乮d"`
-	Address             string          `json:"address" gorm:"column:address;type:varchar(255);comment:鍦板潃"`
-	Phone               string          `json:"phone" gorm:"column:phone;type:varchar(255);comment:鐢佃瘽"`
-	Addressee           string          `json:"addressee" gorm:"column:addressee;type:varchar(255);comment:鏀朵欢浜�"`
-	Conditions          string          `json:"conditions" gorm:"column:conditions;type:text;comment:鏉′欢"`
-	Remark              string          `json:"remark" gorm:"column:remark;type:text;comment:澶囨敞"`
-	Products            []model.Product `json:"products" gorm:"many2many:sales_details_product;"`
-	LogisticCompany     string          `json:"logisticCompany" gorm:"column:logistic_company;type:varchar(255);comment:鐗╂祦鍏徃"`
-	LogisticNumber      string          `json:"logisticNumber" gorm:"column:logistic_number;type:varchar(255);comment:鐗╂祦鍗曞彿"`
-	LogisticCost        float64         `json:"logisticCost" gorm:"column:logistic_cost;type:decimal(10,2);comment:鐗╂祦璐圭敤"`
+	ClientId            int              `json:"clientId" gorm:"column:client_id;type:int;comment:瀹㈡埛id"`
+	Number              string           `json:"number" gorm:"column:number;type:varchar(255);comment:閿�鍞瓙鍗曞彿"`
+	SaleChanceId        int              `json:"saleChanceId" gorm:"column:sale_chance_id;type:int;comment:閿�鍞満浼歩d"`
+	SaleType            int              `json:"saleType" gorm:"column:sale_type;type:int;comment:閿�鍞被鍨�"`
+	SignTime            string           `json:"signTime" gorm:"column:sign_time;type:datetime;comment:绛惧崟鏃堕棿"`
+	MemberId            int              `json:"memberId" gorm:"column:member_id;type:int;comment:璐熻矗浜篿d"`
+	DeliveryDate        string           `json:"deliveryDate" gorm:"column:delivery_date;type:datetime;comment:浜よ揣鏃ユ湡"`
+	WechatOrderStatusId int              `json:"wechatOrderStatusId" gorm:"column:wechat_order_status_id;type:int;comment:寰俊璁㈠崟鐘舵�乮d"`
+	Address             string           `json:"address" gorm:"column:address;type:varchar(255);comment:鍦板潃"`
+	Phone               string           `json:"phone" gorm:"column:phone;type:varchar(255);comment:鐢佃瘽"`
+	Addressee           string           `json:"addressee" gorm:"column:addressee;type:varchar(255);comment:鏀朵欢浜�"`
+	Conditions          string           `json:"conditions" gorm:"column:conditions;type:text;comment:鏉′欢"`
+	Remark              string           `json:"remark" gorm:"column:remark;type:text;comment:澶囨敞"`
+	Products            []*model.Product `json:"products" gorm:"many2many:sales_details_product;"`
+	LogisticCompany     string           `json:"logisticCompany" gorm:"column:logistic_company;type:varchar(255);comment:鐗╂祦鍏徃"`
+	LogisticNumber      string           `json:"logisticNumber" gorm:"column:logistic_number;type:varchar(255);comment:鐗╂祦鍗曞彿"`
+	LogisticCost        float64          `json:"logisticCost" gorm:"column:logistic_cost;type:decimal(10,2);comment:鐗╂祦璐圭敤"`
 }
 
 type UpdateSalesDetails struct {
diff --git a/model/salesDetails.go b/model/salesDetails.go
index b318ab7..ff92423 100644
--- a/model/salesDetails.go
+++ b/model/salesDetails.go
@@ -28,14 +28,14 @@
 		Addressee           string            `json:"addressee" gorm:"column:addressee;type:varchar(255);comment:鏀朵欢浜�"`
 		Conditions          string            `json:"conditions" gorm:"column:conditions;type:text;comment:鏉′欢"`
 		Remark              string            `json:"remark" gorm:"column:remark;type:text;comment:澶囨敞"`
-		Products            []Product         `json:"products" gorm:"many2many:sales_details_product;"`
+		Products            []*Product        `json:"products" gorm:"many2many:sales_details_product;"`
 		LogisticCompany     string            `json:"logisticCompany" gorm:"column:logistic_company;type:varchar(255);comment:鐗╂祦鍏徃"`
 		LogisticNumber      string            `json:"logisticNumber" gorm:"column:logistic_number;type:varchar(255);comment:鐗╂祦鍗曞彿"`
 		LogisticCost        float64           `json:"logisticCost" gorm:"column:logistic_cost;type:decimal(10,2);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"`                 // 鏈紑绁ㄩ噾棰�
+		AmountReceivable    decimal.Decimal   `gorm:"column:amount_receivable;type:decimal(12,2);comment:搴旀敹閲戦" json:"amountReceivable"`    // 搴旀敹閲戦
+		AmountReceived      decimal.Decimal   `gorm:"column:amount_received;type:decimal(12,2);comment:宸叉敹閲戦" json:"amountReceived"`        // 宸叉敹閲戦
+		AmountInvoiced      decimal.Decimal   `gorm:"column:amount_invoiced;type:decimal(12,2);comment:宸插紑绁ㄩ噾棰�" json:"amountInvoiced"`       // 宸插紑绁ㄩ噾棰�
+		AmountUnInvoiced    decimal.Decimal   `gorm:"column:amount_not_invoiced;type:decimal(12,2);comment:鏈紑绁ㄩ噾棰�" json:"amountUnInvoiced"` // 鏈紑绁ㄩ噾棰�
 		gorm.Model          `json:"-"`
 	}
 
@@ -111,7 +111,7 @@
 	return slf
 }
 
-func (slf *SalesDetailsSearch) Find() (*SalesDetails, error) {
+func (slf *SalesDetailsSearch) First() (*SalesDetails, error) {
 	var db = slf.build()
 	var record = new(SalesDetails)
 	err := db.First(record).Error
@@ -161,3 +161,15 @@
 	slf.OrderBy = order
 	return slf
 }
+
+func (slf *SalesDetailsSearch) UpdateByMap(upMap map[string]interface{}) error {
+	var (
+		db = slf.build()
+	)
+
+	if err := db.Updates(upMap).Error; err != nil {
+		return fmt.Errorf("update by map err: %v, upMap: %+v", err, upMap)
+	}
+
+	return nil
+}
diff --git a/model/serviceContract.go b/model/serviceContract.go
index 1d789f7..ccdb08f 100644
--- a/model/serviceContract.go
+++ b/model/serviceContract.go
@@ -34,9 +34,9 @@
 		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:"column:amount_receivable;type:decimal(12,2);comment:鏈紑绁ㄩ噾棰�" json:"amountReceivable"`   // 搴旀敹閲戦
-		AmountReceived          decimal.Decimal       `gorm:"column:amount_received;type:decimal(12,2);comment:鏈紑绁ㄩ噾棰�" json:"amountReceived"`       // 宸叉敹閲戦
-		AmountInvoiced          decimal.Decimal       `gorm:"column:amount_invoiced;type:decimal(12,2);comment:鏈紑绁ㄩ噾棰�" json:"amountInvoiced"`       // 宸插紑绁ㄩ噾棰�
+		AmountReceivable        decimal.Decimal       `gorm:"column:amount_receivable;type:decimal(12,2);comment:搴旀敹閲戦" json:"amountReceivable"`    // 搴旀敹閲戦
+		AmountReceived          decimal.Decimal       `gorm:"column:amount_received;type:decimal(12,2);comment:宸叉敹閲戦" json:"amountReceived"`        // 宸叉敹閲戦
+		AmountInvoiced          decimal.Decimal       `gorm:"column:amount_invoiced;type:decimal(12,2);comment:宸插紑绁ㄩ噾棰�" json:"amountInvoiced"`       // 宸插紑绁ㄩ噾棰�
 		AmountUnInvoiced        decimal.Decimal       `gorm:"column:amount_not_invoiced;type:decimal(12,2);comment:鏈紑绁ㄩ噾棰�" json:"amountUnInvoiced"` // 鏈紑绁ㄩ噾棰�
 		Products                []*Product            `json:"products" gorm:"many2many:service_contract_product;"`
 		gorm.Model              `json:"-"`
diff --git a/model/serviceOrderStatus.go b/model/serviceOrderStatus.go
index b4b4046..4697fe2 100644
--- a/model/serviceOrderStatus.go
+++ b/model/serviceOrderStatus.go
@@ -12,18 +12,18 @@
 	// ServiceOrderStatus 鏈嶅姟鍗曠姸鎬�
 	ServiceOrderStatus struct {
 		Id   int    `json:"id" gorm:"column:id;type:int;primary_key;AUTO_INCREMENT"`
-	    Name string `json:"name" gorm:"column:name;type:varchar(255);not null;default:'';comment:鍚嶇О"`
+		Name string `json:"name" gorm:"column:name;type:varchar(255);not null;default:'';comment:鍚嶇О"`
 	}
 
 	// ServiceOrderStatusSearch 鏈嶅姟鍗曠姸鎬佹悳绱㈡潯浠�
 	ServiceOrderStatusSearch struct {
 		ServiceOrderStatus
-		Orm *gorm.DB
-        QueryClass  constvar.ServiceOrderStatusQueryClass
-        KeywordType constvar.ServiceOrderStatusKeywordType
-        Keyword     string
-        PageNum  int
-        PageSize int
+		Orm         *gorm.DB
+		QueryClass  constvar.ServiceOrderStatusQueryClass
+		KeywordType constvar.ServiceOrderStatusKeywordType
+		Keyword     string
+		PageNum     int
+		PageSize    int
 	}
 )
 
diff --git a/service/invoice.go b/service/invoice.go
index 203d8a8..d1500f1 100644
--- a/service/invoice.go
+++ b/service/invoice.go
@@ -17,7 +17,7 @@
 
 func (InvoiceService) AddInvoice(invoice *model.Invoice) int {
 
-	if invoice.SourceType == constvar.InvoiceSourceTypeServiceContract {
+	if invoice.SourceType == constvar.InvoiceSourceTypeServiceContract { //鏇存柊鏈嶅姟鍚堝悓宸插紑绁ㄩ噾棰�
 		serviceContract, err := model.NewServiceContractSearch().SetId(invoice.SourceId).SetPreload(true).First()
 		if err != nil {
 			return ecode.DBErr
@@ -30,9 +30,6 @@
 		}
 		amountInvoiced = amountInvoiced.Round(2)
 		amountNotInvoiced = amountNotInvoiced.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 {
@@ -46,13 +43,96 @@
 		if err != nil {
 			return ecode.DBErr
 		}
+	} else if invoice.SourceType == constvar.InvoiceSourceTypeServiceContract { //鏇存柊閿�鍞槑缁嗗凡寮�绁ㄩ噾棰�
+		salesDetails, err := model.NewSalesDetailsSearch().SetId(invoice.SourceId).SetPreload(true).First()
+		if err != nil {
+			return ecode.DBErr
+		}
+		var amountInvoiced, amountNotInvoiced decimal.Decimal
+		rightProducts := NewProductsService().PickRightProducts(invoice.Products, salesDetails.Products)
+		for _, product := range rightProducts {
+			amountInvoiced = salesDetails.AmountInvoiced.Add(product.Amount.Mul(product.Price))
+			amountNotInvoiced = salesDetails.AmountUnInvoiced.Sub(product.Amount.Mul(product.Price))
+		}
+		amountInvoiced = amountInvoiced.Round(2)
+		amountNotInvoiced = amountNotInvoiced.Round(2)
+		err = model.WithTransaction(func(db *gorm.DB) error {
+			err = model.NewInvoiceSearch().Create(invoice)
+			if err != nil {
+				return err
+			}
+			return model.NewSalesDetailsSearch().SetId(invoice.SourceId).UpdateByMap(map[string]interface{}{
+				"amount_invoiced":     amountInvoiced,
+				"amount_not_invoiced": amountNotInvoiced,
+			})
+		})
+		if err != nil {
+			return ecode.DBErr
+		}
 	}
 
 	return ecode.OK
 }
 
 func (InvoiceService) DeleteInvoice(id int) int {
-	err := model.NewInvoiceSearch().SetId(id).Delete()
+	invoice, err := model.NewInvoiceSearch().SetId(id).First()
+	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, amountNotInvoiced decimal.Decimal
+		rightProducts := NewProductsService().PickRightProducts(invoice.Products, serviceContract.Products)
+		for _, product := range rightProducts {
+			amountInvoiced = serviceContract.AmountInvoiced.Sub(product.Amount.Mul(product.Price))
+			amountNotInvoiced = serviceContract.AmountUnInvoiced.Add(product.Amount.Mul(product.Price))
+		}
+		amountInvoiced = amountInvoiced.Round(2)
+		amountNotInvoiced = amountNotInvoiced.Round(2)
+		err = model.WithTransaction(func(db *gorm.DB) error {
+			err := model.NewInvoiceSearch().SetId(id).Delete()
+			if err != nil {
+				return err
+			}
+			return model.NewServiceContractSearch().SetId(invoice.SourceId).UpdateByMap(map[string]interface{}{
+				"amount_invoiced":     amountInvoiced,
+				"amount_not_invoiced": amountNotInvoiced,
+			})
+		})
+		if err != nil {
+			return ecode.DBErr
+		}
+	} else if invoice.SourceType == constvar.InvoiceSourceTypeServiceContract { //鏇存柊閿�鍞槑缁嗗凡寮�绁ㄩ噾棰�
+		salesDetails, err := model.NewSalesDetailsSearch().SetId(invoice.SourceId).SetPreload(true).First()
+		if err != nil {
+			return ecode.DBErr
+		}
+		var amountInvoiced, amountNotInvoiced decimal.Decimal
+		rightProducts := NewProductsService().PickRightProducts(invoice.Products, salesDetails.Products)
+		for _, product := range rightProducts {
+			amountInvoiced = salesDetails.AmountInvoiced.Sub(product.Amount.Mul(product.Price))
+			amountNotInvoiced = salesDetails.AmountUnInvoiced.Add(product.Amount.Mul(product.Price))
+		}
+		amountInvoiced = amountInvoiced.Round(2)
+		amountNotInvoiced = amountNotInvoiced.Round(2)
+		err = model.WithTransaction(func(db *gorm.DB) error {
+			err := model.NewInvoiceSearch().SetId(id).Delete()
+			if err != nil {
+				return err
+			}
+			return model.NewSalesDetailsSearch().SetId(invoice.SourceId).UpdateByMap(map[string]interface{}{
+				"amount_invoiced":     amountInvoiced,
+				"amount_not_invoiced": amountNotInvoiced,
+			})
+		})
+		if err != nil {
+			return ecode.DBErr
+		}
+	}
+
 	if err != nil {
 		return ecode.DBErr
 	}
@@ -91,20 +171,19 @@
 		if err != nil {
 			return ecode.DBErr
 		}
-		var amountInvoiced decimal.Decimal
+		var amountInvoiced, amountNotInvoiced decimal.Decimal
 		newProducts, removedProducts := NewProductsService().PickDiffProducts(invoice.Products, serviceContract.Products)
 		for _, product := range newProducts {
 			amountInvoiced = serviceContract.AmountInvoiced.Add(product.Amount.Mul(product.Price))
+			amountNotInvoiced = serviceContract.AmountUnInvoiced.Sub(product.Amount.Mul(product.Price))
 		}
 		removedProductIds := make([]uint, 0, len(removedProducts))
 		for _, product := range removedProducts {
 			amountInvoiced = serviceContract.AmountInvoiced.Sub(product.Amount.Mul(product.Price))
+			amountNotInvoiced = serviceContract.AmountUnInvoiced.Add(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 {
@@ -117,7 +196,45 @@
 				}
 			}
 			return model.NewServiceContractSearch().SetId(invoice.SourceId).UpdateByMap(map[string]interface{}{
-				"amount_invoiced": amountInvoiced,
+				"amount_invoiced":     amountInvoiced,
+				"amount_not_invoiced": amountNotInvoiced,
+			})
+		})
+		if err != nil {
+			return ecode.DBErr
+		}
+	} else if invoice.SourceType == constvar.InvoiceSourceTypeServiceContract { //鏇存柊閿�鍞槑缁嗗凡寮�绁ㄩ噾棰�
+		salesDetails, err := model.NewSalesDetailsSearch().SetId(invoice.SourceId).SetPreload(true).First()
+		if err != nil {
+			return ecode.DBErr
+		}
+		var amountInvoiced, amountNotInvoiced decimal.Decimal
+		newProducts, removedProducts := NewProductsService().PickDiffProducts(invoice.Products, salesDetails.Products)
+		for _, product := range newProducts {
+			amountInvoiced = salesDetails.AmountInvoiced.Add(product.Amount.Mul(product.Price))
+			amountNotInvoiced = salesDetails.AmountUnInvoiced.Sub(product.Amount.Mul(product.Price))
+		}
+		removedProductIds := make([]uint, 0, len(removedProducts))
+		for _, product := range removedProducts {
+			amountInvoiced = salesDetails.AmountInvoiced.Sub(product.Amount.Mul(product.Price))
+			amountNotInvoiced = salesDetails.AmountUnInvoiced.Add(product.Amount.Mul(product.Price))
+			removedProductIds = append(removedProductIds, product.Id)
+		}
+		amountInvoiced = amountInvoiced.Round(2)
+		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.NewSalesDetailsSearch().SetId(invoice.SourceId).UpdateByMap(map[string]interface{}{
+				"amount_invoiced":     amountInvoiced,
+				"amount_not_invoiced": amountNotInvoiced,
 			})
 		})
 		if err != nil {
diff --git a/service/salesDetails.go b/service/salesDetails.go
index d504748..906fc2e 100644
--- a/service/salesDetails.go
+++ b/service/salesDetails.go
@@ -18,7 +18,7 @@
 }
 
 func (SalesDetailsService) DeleteSalesDetails(id int) int {
-	_, err := model.NewSalesDetailsSearch().SetId(id).Find()
+	_, err := model.NewSalesDetailsSearch().SetId(id).First()
 	if err != nil {
 		return ecode.SalesDetailsNotExist
 	}
@@ -32,7 +32,7 @@
 
 func (SalesDetailsService) UpdateSalesDetails(salesDetails *model.SalesDetails) int {
 	// check salesDetails exist
-	_, err := model.NewSalesDetailsSearch().SetId(salesDetails.Id).Find()
+	_, err := model.NewSalesDetailsSearch().SetId(salesDetails.Id).First()
 	if err != nil {
 		return ecode.SalesDetailsNotExist
 	}

--
Gitblit v1.8.0