核心功能: - 实现 7 级店铺层级体系(Shop 模型 + 层级校验) - 实现企业管理模型(Enterprise 模型) - 实现个人客户管理模型(PersonalCustomer 模型) - 重构 Account 模型关联关系(基于 EnterpriseID 而非 ParentID) - 完整的 Store 层和 Service 层实现 - 递归查询下级店铺功能(含 Redis 缓存) - 全面的单元测试覆盖(Shop/Enterprise/PersonalCustomer Store + Shop Service) 技术要点: - 显式指定所有 GORM 模型的数据库字段名(column: 标签) - 统一的字段命名规范(数据库用 snake_case,Go 用 PascalCase) - 完整的中文字段注释和业务逻辑说明 - 100% 测试覆盖(20+ 测试用例全部通过) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
128 lines
3.8 KiB
Go
128 lines
3.8 KiB
Go
package customer
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/break/junhong_cmp_fiber/internal/model"
|
|
"github.com/break/junhong_cmp_fiber/internal/store"
|
|
"github.com/break/junhong_cmp_fiber/internal/store/postgres"
|
|
"github.com/break/junhong_cmp_fiber/pkg/constants"
|
|
"github.com/break/junhong_cmp_fiber/pkg/errors"
|
|
)
|
|
|
|
// Service 个人客户业务服务
|
|
type Service struct {
|
|
customerStore *postgres.PersonalCustomerStore
|
|
}
|
|
|
|
// New 创建个人客户服务
|
|
func New(customerStore *postgres.PersonalCustomerStore) *Service {
|
|
return &Service{
|
|
customerStore: customerStore,
|
|
}
|
|
}
|
|
|
|
// Create 创建个人客户
|
|
func (s *Service) Create(ctx context.Context, req *model.CreatePersonalCustomerRequest) (*model.PersonalCustomer, error) {
|
|
// 检查手机号唯一性
|
|
if req.Phone != "" {
|
|
existing, err := s.customerStore.GetByPhone(ctx, req.Phone)
|
|
if err == nil && existing != nil {
|
|
return nil, errors.New(errors.CodeCustomerPhoneExists, "手机号已存在")
|
|
}
|
|
}
|
|
|
|
// 创建个人客户
|
|
customer := &model.PersonalCustomer{
|
|
Phone: req.Phone,
|
|
Nickname: req.Nickname,
|
|
AvatarURL: req.AvatarURL,
|
|
WxOpenID: req.WxOpenID,
|
|
WxUnionID: req.WxUnionID,
|
|
Status: constants.StatusEnabled,
|
|
}
|
|
|
|
if err := s.customerStore.Create(ctx, customer); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return customer, nil
|
|
}
|
|
|
|
// Update 更新个人客户信息
|
|
func (s *Service) Update(ctx context.Context, id uint, req *model.UpdatePersonalCustomerRequest) (*model.PersonalCustomer, error) {
|
|
// 查询客户
|
|
customer, err := s.customerStore.GetByID(ctx, id)
|
|
if err != nil {
|
|
return nil, errors.New(errors.CodeCustomerNotFound, "个人客户不存在")
|
|
}
|
|
|
|
// 检查手机号唯一性(如果修改了手机号)
|
|
if req.Phone != nil && *req.Phone != customer.Phone {
|
|
existing, err := s.customerStore.GetByPhone(ctx, *req.Phone)
|
|
if err == nil && existing != nil && existing.ID != id {
|
|
return nil, errors.New(errors.CodeCustomerPhoneExists, "手机号已存在")
|
|
}
|
|
customer.Phone = *req.Phone
|
|
}
|
|
|
|
// 更新字段
|
|
if req.Nickname != nil {
|
|
customer.Nickname = *req.Nickname
|
|
}
|
|
if req.AvatarURL != nil {
|
|
customer.AvatarURL = *req.AvatarURL
|
|
}
|
|
|
|
if err := s.customerStore.Update(ctx, customer); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return customer, nil
|
|
}
|
|
|
|
// BindWeChat 绑定微信信息
|
|
func (s *Service) BindWeChat(ctx context.Context, id uint, wxOpenID, wxUnionID string) error {
|
|
customer, err := s.customerStore.GetByID(ctx, id)
|
|
if err != nil {
|
|
return errors.New(errors.CodeCustomerNotFound, "个人客户不存在")
|
|
}
|
|
|
|
customer.WxOpenID = wxOpenID
|
|
customer.WxUnionID = wxUnionID
|
|
|
|
return s.customerStore.Update(ctx, customer)
|
|
}
|
|
|
|
// GetByID 获取个人客户详情
|
|
func (s *Service) GetByID(ctx context.Context, id uint) (*model.PersonalCustomer, error) {
|
|
customer, err := s.customerStore.GetByID(ctx, id)
|
|
if err != nil {
|
|
return nil, errors.New(errors.CodeCustomerNotFound, "个人客户不存在")
|
|
}
|
|
return customer, nil
|
|
}
|
|
|
|
// GetByPhone 根据手机号获取个人客户
|
|
func (s *Service) GetByPhone(ctx context.Context, phone string) (*model.PersonalCustomer, error) {
|
|
customer, err := s.customerStore.GetByPhone(ctx, phone)
|
|
if err != nil {
|
|
return nil, errors.New(errors.CodeCustomerNotFound, "个人客户不存在")
|
|
}
|
|
return customer, nil
|
|
}
|
|
|
|
// GetByWxOpenID 根据微信 OpenID 获取个人客户
|
|
func (s *Service) GetByWxOpenID(ctx context.Context, wxOpenID string) (*model.PersonalCustomer, error) {
|
|
customer, err := s.customerStore.GetByWxOpenID(ctx, wxOpenID)
|
|
if err != nil {
|
|
return nil, errors.New(errors.CodeCustomerNotFound, "个人客户不存在")
|
|
}
|
|
return customer, nil
|
|
}
|
|
|
|
// List 查询个人客户列表
|
|
func (s *Service) List(ctx context.Context, opts *store.QueryOptions, filters map[string]interface{}) ([]*model.PersonalCustomer, int64, error) {
|
|
return s.customerStore.List(ctx, opts, filters)
|
|
}
|