material_manage_system/internal/repository/partner.go

180 lines
6.5 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package repository
import (
"database/sql"
"errors"
"fmt"
"strings"
"github.com/wmms/wmms/internal/model"
"github.com/wmms/wmms/pkg/database"
)
type PartnerRepository struct{}
func NewPartnerRepository() *PartnerRepository { return &PartnerRepository{} }
func (r *PartnerRepository) List(organizationID int64, role string, limit, offset int, category string) ([]model.BusinessPartner, int64, error) {
// 角色过滤写成一份,由计数和取数共用:两处各写一遍,改一处漏一处就会让
// 总数和列表对不上(总数算的是全部,列表却只有供应商)。
filter := `FROM organization_partners op
JOIN business_partners bp ON bp.id = op.business_partner_id
WHERE op.organization_id = ?`
args := []interface{}{organizationID}
if role == "supplier" {
filter += ` AND op.is_supplier = TRUE`
}
if role == "customer" {
filter += ` AND op.is_customer = TRUE`
}
if category != "" {
// 字段名仅由已知角色选择,筛选值始终使用参数绑定。
field := "op.supplier_categories"
if role == "customer" {
field = "op.customer_categories"
} else if role != "supplier" {
return nil, 0, errors.New("业务分类筛选需要指定客户或供应商")
}
if category == "unclassified" {
filter += ` AND ` + field + ` = ''`
} else if category == "material" || category == "finished_product" {
filter += ` AND FIND_IN_SET(?, ` + field + `) > 0`
args = append(args, category)
} else {
return nil, 0, errors.New("invalid partner category")
}
}
var total int64
if err := database.DB.QueryRow(`SELECT COUNT(*) `+filter, args...).Scan(&total); err != nil {
return nil, 0, err
}
query := `SELECT op.id, op.organization_id, bp.id, op.partner_code, bp.legal_name,
COALESCE(bp.unified_credit_code, ''), COALESCE(bp.contact_name, ''),
COALESCE(bp.contact_phone, ''), COALESCE(bp.address, ''),
op.is_supplier, op.is_customer, COALESCE(op.supplier_status, ''),
COALESCE(op.customer_status, ''), COALESCE(op.settlement_currency, ''),
COALESCE(op.payment_terms, ''), op.supplier_categories, op.customer_categories
` + filter + `
ORDER BY op.partner_code
LIMIT ? OFFSET ?`
// 计数查询已经用完 args,这里追加分页参数不会再影响到它
rows, err := database.DB.Query(query, append(args, limit, offset)...)
if err != nil {
return nil, 0, err
}
defer rows.Close()
items := make([]model.BusinessPartner, 0)
for rows.Next() {
var item model.BusinessPartner
var supplierCategories, customerCategories string
if err := rows.Scan(&item.ID, &item.OrganizationID, &item.BusinessPartnerID, &item.PartnerCode,
&item.LegalName, &item.UnifiedCreditCode, &item.ContactName, &item.ContactPhone,
&item.Address, &item.IsSupplier, &item.IsCustomer, &item.SupplierStatus,
&item.CustomerStatus, &item.SettlementCurrency, &item.PaymentTerms, &supplierCategories, &customerCategories); err != nil {
return nil, 0, err
}
item.SupplierCategories = splitPartnerCategories(supplierCategories)
item.CustomerCategories = splitPartnerCategories(customerCategories)
items = append(items, item)
}
return items, total, rows.Err()
}
func (r *PartnerRepository) Create(item *model.BusinessPartner) (err error) {
tx, err := database.DB.Begin()
if err != nil {
return err
}
defer func() {
if err != nil {
_ = tx.Rollback()
}
}()
result, err := tx.Exec(`INSERT INTO business_partners
(legal_name, unified_credit_code, contact_name, contact_phone, address)
VALUES (?, NULLIF(?, ''), NULLIF(?, ''), NULLIF(?, ''), NULLIF(?, ''))`,
item.LegalName, item.UnifiedCreditCode, item.ContactName, item.ContactPhone, item.Address)
if err != nil {
return err
}
item.BusinessPartnerID, err = result.LastInsertId()
if err != nil {
return err
}
result, err = tx.Exec(`INSERT INTO organization_partners
(organization_id, business_partner_id, partner_code, is_supplier, is_customer,
supplier_status, customer_status, settlement_currency, payment_terms, supplier_categories, customer_categories)
VALUES (?, ?, ?, ?, ?, NULLIF(?, ''), NULLIF(?, ''), NULLIF(?, ''), NULLIF(?, ''), ?, ?)`,
item.OrganizationID, item.BusinessPartnerID, item.PartnerCode, item.IsSupplier, item.IsCustomer,
item.SupplierStatus, item.CustomerStatus, item.SettlementCurrency, item.PaymentTerms,
strings.Join(item.SupplierCategories, ","), strings.Join(item.CustomerCategories, ","))
if err != nil {
return err
}
item.ID, err = result.LastInsertId()
if err != nil {
return err
}
return tx.Commit()
}
func (r *PartnerRepository) Update(item *model.BusinessPartner) (err error) {
tx, err := database.DB.Begin()
if err != nil {
return err
}
defer func() {
if err != nil {
_ = tx.Rollback()
}
}()
// 这一句兼任存在性检查:查不到就说明伙伴不存在或不属于当前组织,
// 不能让它以 sql.ErrNoRows 一路冒到接口变成 500。
var businessPartnerID int64
if err = tx.QueryRow(`SELECT business_partner_id FROM organization_partners WHERE id = ? AND organization_id = ? FOR UPDATE`, item.ID, item.OrganizationID).Scan(&businessPartnerID); err != nil {
if errors.Is(err, sql.ErrNoRows) {
return ErrRecordNotFound
}
return err
}
if _, err = tx.Exec(`UPDATE business_partners SET legal_name = ?, unified_credit_code = NULLIF(?, ''),
contact_name = NULLIF(?, ''), contact_phone = NULLIF(?, ''), address = NULLIF(?, '') WHERE id = ?`,
item.LegalName, item.UnifiedCreditCode, item.ContactName, item.ContactPhone, item.Address, businessPartnerID); err != nil {
return err
}
if _, err = tx.Exec(`UPDATE organization_partners SET is_supplier = ?, is_customer = ?,
supplier_status = NULLIF(?, ''), customer_status = NULLIF(?, ''),
settlement_currency = NULLIF(?, ''), payment_terms = NULLIF(?, ''),
supplier_categories = COALESCE(?, supplier_categories), customer_categories = COALESCE(?, customer_categories)
WHERE id = ? AND organization_id = ?`,
item.IsSupplier, item.IsCustomer, item.SupplierStatus, item.CustomerStatus,
item.SettlementCurrency, item.PaymentTerms, optionalPartnerCategories(item.SupplierCategories),
optionalPartnerCategories(item.CustomerCategories), item.ID, item.OrganizationID); err != nil {
return err
}
if err = tx.Commit(); err != nil {
return fmt.Errorf("commit partner update: %w", err)
}
return nil
}
func splitPartnerCategories(value string) []string {
if value == "" {
return []string{}
}
return strings.Split(value, ",")
}
func optionalPartnerCategories(categories []string) interface{} {
if categories == nil {
return nil
}
return strings.Join(categories, ",")
}