zhangqian
2023-08-09 7cc2f77503135e266264eb897e8f688e8ad216d5
增加发票和合同产品的关联,发票新增和修改时更改对应合同已开票金额
2个文件已添加
6个文件已修改
239 ■■■■■ 已修改文件
model/invoice.go 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
model/invoiceProduct.go 131 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
model/product.go 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
model/request/invoice.go 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
model/request/serviceContract.go 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
model/serviceContract.go 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
service/invoice.go 47 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
service/products.go 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
model/invoice.go
@@ -28,7 +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;"`
        Products         []*Product                 `json:"products" gorm:"many2many:invoice_product;"`
    }
    // InvoiceSearch 销售发票搜索条件
model/invoiceProduct.go
New file
@@ -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)
}
model/product.go
@@ -6,7 +6,7 @@
)
type Product struct {
    Id         int             `json:"id" gorm:"column:id;primary_key;AUTO_INCREMENT"`
    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:产品编号"`
model/request/invoice.go
@@ -22,7 +22,7 @@
}
type UpdateInvoice struct {
    Id               int    `json:"id"`
    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"`            // 销售负责人id
@@ -35,6 +35,7 @@
    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 {
model/request/serviceContract.go
@@ -25,7 +25,7 @@
    ServiceTimes   int             `json:"serviceTimes"`
    Terms          string          `json:"terms"`
    Remark         string          `json:"remark"`
    Products       []model.Product `json:"products"`
    Products       []*model.Product `json:"products"`
}
type UpdateServiceContract struct {
model/serviceContract.go
@@ -36,7 +36,7 @@
        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;"`
        Products                []*Product            `json:"products" gorm:"many2many:service_contract_product;"`
        gorm.Model              `json:"-"`
    }
service/invoice.go
@@ -18,12 +18,13 @@
func (InvoiceService) AddInvoice(invoice *model.Invoice) int {
    if invoice.SourceType == constvar.InvoiceSourceTypeServiceContract {
        serviceContract, err := model.NewServiceContractSearch().SetId(invoice.SourceId).First()
        serviceContract, err := model.NewServiceContractSearch().SetId(invoice.SourceId).SetPreload(true).First()
        if err != nil {
            return ecode.DBErr
        }
        var amountInvoiced decimal.Decimal
        for _, product := range invoice.Products {
        rightProducts := NewProductsService().PickRightProducts(invoice.Products, serviceContract.Products)
        for _, product := range rightProducts {
            amountInvoiced = serviceContract.AmountInvoiced.Add(product.Amount.Mul(product.Price))
        }
        amountInvoiced = amountInvoiced.Round(2)
@@ -35,13 +36,9 @@
            if err != nil {
                return err
            }
            err = model.NewServiceContractSearch().SetId(invoice.SourceId).UpdateByMap(map[string]interface{}{
            return model.NewServiceContractSearch().SetId(invoice.SourceId).UpdateByMap(map[string]interface{}{
                "amount_invoiced": amountInvoiced,
            })
            if err != nil {
                return err
            }
            return nil
        })
        if err != nil {
            return ecode.DBErr
@@ -86,9 +83,43 @@
}
func (InvoiceService) UpdateInvoice(invoice *model.Invoice) int {
    err := model.NewInvoiceSearch().SetId(invoice.Id).Save(invoice)
    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
}
service/products.go
New file
@@ -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
}