180 lines
6.5 KiB
Go
180 lines
6.5 KiB
Go
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, ",")
|
||
}
|