telco_server/app/admin/service/bus_service/s_cooperative_manage.go

561 lines
16 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 bus_service
import (
"context"
"errors"
"fmt"
log "github.com/go-admin-team/go-admin-core/logger"
"github.com/go-admin-team/go-admin-core/sdk/service"
"go-admin/app/admin/models"
"go-admin/app/admin/models/bus_models"
"go-admin/common/global"
"gorm.io/gorm"
"math/rand"
"time"
)
type CooperativeService struct {
service.Service
}
// GetCooperativeList 获取合作商列表
func (e *CooperativeService) GetCooperativeList(ctx context.Context, req bus_models.CooperativeListReq) (
bus_models.CooperativeListResp, error) {
var cooperativeList []bus_models.BusCooperative
var resp bus_models.CooperativeListResp
page := req.Page - 1
if page < 0 {
page = 0
}
if req.PageSize == 0 {
req.PageSize = 10
}
// 构建查询条件
db := e.Orm.WithContext(ctx)
if req.CooperativeNumber != "" {
db = db.Where("cooperative_number = ?", req.CooperativeNumber)
}
if req.CooperativeName != "" {
db = db.Where("cooperative_name LIKE ?", "%"+req.CooperativeName+"%")
}
if req.Status != 0 {
db = db.Where("status = ?", req.Status)
}
// 查询合作商基本信息
if err := db.Offset(page * req.PageSize).Limit(req.PageSize).Find(&cooperativeList).Error; err != nil {
return resp, errors.New("查询合作商列表失败")
}
// 获取所有合作商ID
var cooperativeIDs []uint64
for _, c := range cooperativeList {
cooperativeIDs = append(cooperativeIDs, c.ID)
}
// 查询所有关联的产品信息
var cooperativeProducts []bus_models.BusCooperativeProduct
if len(cooperativeIDs) > 0 {
err := e.Orm.WithContext(ctx).
Where("cooperative_id IN (?)", cooperativeIDs).
Find(&cooperativeProducts).Error
if err != nil {
return resp, errors.New("查询合作商产品信息失败")
}
}
// 获取所有产品ID
var productIDs []uint64
for _, cp := range cooperativeProducts {
productIDs = append(productIDs, cp.ProductID)
}
// 查询产品详细信息
var products []bus_models.BusProduct
if len(productIDs) > 0 {
err := e.Orm.WithContext(ctx).
Where("id IN (?)", productIDs).
Find(&products).Error
if err != nil {
return resp, errors.New("查询产品信息失败")
}
}
// 构建合作商ID到产品信息的映射
productMap := make(map[uint64][]bus_models.ProductDetail)
for _, cp := range cooperativeProducts {
for _, p := range products {
if p.ID == cp.ProductID {
productMap[cp.CooperativeID] = append(productMap[cp.CooperativeID], bus_models.ProductDetail{
ProductCode: p.ProductCode,
ProductName: p.ProductName,
Discount: cp.Discount,
ProductID: p.ID,
})
break
}
}
}
// 组装返回数据
for i := range cooperativeList {
cooperativeList[i].Products = productMap[cooperativeList[i].ID]
}
resp.List = cooperativeList
resp.Total = len(cooperativeList)
resp.Page = page + 1
resp.PageSize = req.PageSize
return resp, nil
}
// CreateCooperative 新建合作商(使用事务)
func (e *CooperativeService) CreateCooperative(req bus_models.CreateCooperativeReq) (bus_models.CreateCooperativeResp, error) {
var resp bus_models.CreateCooperativeResp
// 开启事务
tx := e.Orm.Begin()
defer func() {
if r := recover(); r != nil {
// 打印 panic 错误信息
log.Error("Panic recovered: %v", r)
tx.Rollback()
}
}()
// 1-新建系统用户
// 查询 role_id
var roleID int
err := tx.Model(&models.SysRole{}).
Select("role_id").
Where("role_name = ?", global.CooperativeRoleName).
Where("status = ?", global.SysRoleStatusOnUse). // 确保角色状态为正常
First(&roleID).Error
if err != nil || roleID == 0 {
tx.Rollback()
return resp, errors.New("系统未创建合作商角色")
}
// **调用创建用户接口**
var userPhone string
if req.Tel == "" {
userPhone = "13966668888"
} else {
userPhone = req.Tel
}
var sysUser models.SysUser
var count int64
// 检查用户名是否已存在
err = tx.Model(&sysUser).Where("username = ?", req.Account).Count(&count).Error
if err != nil {
tx.Rollback() // 出现错误时回滚
return resp, errors.New("数据库错误:" + err.Error())
}
if count > 0 {
tx.Rollback() // 用户名已存在,回滚事务
return resp, errors.New("用户名已存在")
}
// 创建SysUser对象并插入
userReq := models.SysUser{
Username: req.Account, // 使用合作商账户作为用户名
Password: req.Password, // 直接使用合作商密码(前端已加密)
NickName: req.CooperativeName, // 用合作商名称作为昵称
Phone: userPhone, // 绑定手机号
Email: userPhone + "@mail.com", // 默认邮箱
DeptId: global.DefaultDeptId, // 默认部门ID
Status: global.SysUserStatusOnUse, // 默认状态
RoleId: roleID, // 默认角色ID
}
err = tx.Create(&userReq).Error
if err != nil {
tx.Rollback() // 创建用户失败,回滚事务
return resp, errors.New("创建用户失败:" + err.Error())
}
// 2-创建合作商
cooperative := bus_models.BusCooperative{
CooperativeName: req.CooperativeName,
Contact: req.Contact,
Tel: req.Tel,
Status: global.CooperativeStatusOnUse,
Account: req.Account,
Password: req.Password,
Balance: req.Balance,
Free: req.Free,
Bond: req.Bond,
CardHolder: req.CardHolder,
Bank: req.Bank,
CardID: req.CardID,
TaxID: req.TaxID,
UserId: userReq.UserId,
}
cooperative.CooperativeNumber, err = GenerateCooperativeNumber(e.Orm)
if err != nil {
return resp, err
}
if err := tx.Create(&cooperative).Error; err != nil {
tx.Rollback()
return resp, errors.New("创建合作商失败")
}
// 插入合作商产品信息
var cooperativeProducts []bus_models.BusCooperativeProduct
for _, product := range req.Products {
cooperativeProducts = append(cooperativeProducts, bus_models.BusCooperativeProduct{
CooperativeID: cooperative.ID,
ProductID: product.ProductID,
Discount: product.Discount,
})
}
if len(cooperativeProducts) > 0 {
if err := tx.Create(&cooperativeProducts).Error; err != nil {
tx.Rollback()
return resp, errors.New("创建合作商产品失败")
}
}
// 提交事务
if err := tx.Commit().Error; err != nil {
return resp, errors.New("提交事务失败")
}
resp.CooperativeNumber = cooperative.CooperativeNumber
return resp, nil
}
func (e *CooperativeService) EditCooperative(req bus_models.EditCooperativeReq) error {
// 开启事务
tx := e.Orm.Begin()
defer func() {
if r := recover(); r != nil {
tx.Rollback()
}
}()
// 查找合作商
var cooperative bus_models.BusCooperative
if err := tx.Where("cooperative_number = ?", req.CooperativeNumber).First(&cooperative).Error; err != nil {
tx.Rollback()
return errors.New("合作商不存在")
}
// 更新合作商信息
updateData := map[string]interface{}{
"cooperative_name": req.CooperativeName,
"contact": req.Contact,
"tel": req.Tel,
"status": req.Status,
"account": req.Account,
"balance": req.Balance,
"free": req.Free,
"bond": req.Bond,
"card_holder": req.CardHolder,
"bank": req.Bank,
"card_id": req.CardID,
"tax_id": req.TaxID,
}
if req.Password != "" {
updateData["password"] = req.Password
}
if err := tx.Model(&bus_models.BusCooperative{}).Where("cooperative_number = ?", req.CooperativeNumber).
Updates(updateData).Error; err != nil {
tx.Rollback()
return errors.New("更新合作商信息失败")
}
// 获取数据库中的旧产品数据
var existingProducts []bus_models.BusCooperativeProduct
tx.Where("cooperative_id = ?", cooperative.ID).Find(&existingProducts)
// 旧数据转换为 map (ProductID => Discount)
existingMap := make(map[uint64]float64)
for _, p := range existingProducts {
existingMap[p.ProductID] = p.Discount
}
// 计算需要更新、删除、插入的数据
newProductMap := make(map[uint64]float64) // (ProductID => Discount)
var newProducts []bus_models.BusCooperativeProduct
for _, product := range req.Products {
newProductMap[product.ProductID] = product.Discount
// 如果是新产品,或者折扣变化,则需要插入/更新
if discount, exists := existingMap[product.ProductID]; !exists || discount != product.Discount {
newProducts = append(newProducts, bus_models.BusCooperativeProduct{
CooperativeID: cooperative.ID,
ProductID: product.ProductID,
Discount: product.Discount,
})
}
}
// 删除不存在于新数据中的旧产品
var productIDsToDelete []uint64
for oldProductID := range existingMap {
if _, exists := newProductMap[oldProductID]; !exists {
productIDsToDelete = append(productIDsToDelete, oldProductID)
}
}
if len(productIDsToDelete) > 0 {
tx.Where("cooperative_id = ? AND product_id IN ?", cooperative.ID, productIDsToDelete).Delete(&bus_models.BusCooperativeProduct{})
}
// 插入新的或有折扣变化的产品
if len(newProducts) > 0 {
if err := tx.Create(&newProducts).Error; err != nil {
tx.Rollback()
return errors.New("添加/更新合作商产品信息失败")
}
}
// 提交事务
if err := tx.Commit().Error; err != nil {
return errors.New("提交事务失败")
}
return nil
}
// DeleteCooperative 删除合作商
func (e *CooperativeService) DeleteCooperative(req bus_models.DeleteCooperativeReq) error {
// 开始事务
tx := e.Orm.Begin()
// 1. 查询合作商的user_id
var cooperative bus_models.BusCooperative
err := tx.Where("cooperative_number = ?", req.CooperativeNumber).First(&cooperative).Error
if err != nil {
tx.Rollback() // 如果查询失败,回滚事务
return errors.New("查询合作商失败:" + err.Error())
}
// 2. 如果user_id != 0删除sys_user中的用户
if cooperative.UserId != 0 {
var sysUser models.SysUser
err = tx.Where("user_id = ?", cooperative.UserId).Delete(&sysUser).Error
if err != nil {
tx.Rollback() // 删除用户失败,回滚事务
return errors.New("删除用户失败:" + err.Error())
}
}
// 3. 删除合作商
err = tx.Where("cooperative_number = ?", req.CooperativeNumber).Delete(&bus_models.BusCooperative{}).Error
if err != nil {
tx.Rollback() // 删除合作商失败,回滚事务
return errors.New("删除合作商失败:" + err.Error())
}
// 4. 提交事务
err = tx.Commit().Error
if err != nil {
tx.Rollback() // 提交事务失败,回滚
return errors.New("提交事务失败:" + err.Error())
}
return nil
}
// GetCooperativeDetail 获取合作商详细信息,包括产品信息
func (e *CooperativeService) GetCooperativeDetail(ctx context.Context, req bus_models.CooperativeDetailReq) (
bus_models.CooperativeDetailResp, error) {
var resp bus_models.CooperativeDetailResp
var cooperative bus_models.BusCooperative
// 查询合作商基本信息
db := e.Orm.WithContext(ctx).Where("cooperative_number = ?", req.CooperativeNumber)
if err := db.First(&cooperative).Error; err != nil {
return resp, errors.New("查询合作商详情失败")
}
// 查询该合作商的产品信息
var cooperativeProducts []bus_models.BusCooperativeProduct
err := e.Orm.WithContext(ctx).
Where("cooperative_id = ?", cooperative.ID).
Find(&cooperativeProducts).Error
if err != nil {
return resp, errors.New("查询合作商产品信息失败")
}
// 根据产品ID查询产品名称和编码
var productIDs []uint64
for _, cp := range cooperativeProducts {
productIDs = append(productIDs, cp.ProductID)
}
// 查询产品详细信息
var products []bus_models.BusProduct
if len(productIDs) > 0 {
err = e.Orm.WithContext(ctx).
Where("id IN (?)", productIDs).
Find(&products).Error
if err != nil {
return resp, errors.New("查询产品信息失败")
}
}
// 将产品信息填充到响应中
var productDetails []bus_models.ProductDetail
for _, cp := range cooperativeProducts {
// 查找对应产品
for _, p := range products {
if p.ID == cp.ProductID { // 确保ID匹配
productDetails = append(productDetails, bus_models.ProductDetail{
ProductCode: p.ProductCode,
ProductName: p.ProductName,
Discount: cp.Discount,
})
break
}
}
}
// 填充合作商信息
resp.CooperativeNumber = cooperative.CooperativeNumber
resp.CooperativeName = cooperative.CooperativeName
resp.Contact = cooperative.Contact
resp.Tel = cooperative.Tel
resp.Status = cooperative.Status
resp.Account = cooperative.Account
resp.Balance = cooperative.Balance
resp.Free = cooperative.Free
resp.Bond = cooperative.Bond
resp.CardHolder = cooperative.CardHolder
resp.Bank = cooperative.Bank
resp.CardID = cooperative.CardID
resp.TaxID = cooperative.TaxID
resp.Products = productDetails
return resp, nil
}
// GenerateCooperativeNumber 生成唯一的合作商编号,日期 + 10位随机数
func GenerateCooperativeNumber(db *gorm.DB) (string, error) {
// 获取当前日期(年月日)
dateStr := time.Now().Format("20060102") // 格式为YYYYMMDD
// 生成一个10位随机数
rand.Seed(time.Now().UnixNano()) // 设置随机数种子
randomNum := rand.Int63n(10000000000) // 生成一个0到9999999999之间的随机数
// 将随机数转为固定长度的字符串确保10位
randomNumStr := fmt.Sprintf("%010d", randomNum) // 确保为10位不足补零
// 拼接日期和随机数
cooperativeNumber := fmt.Sprintf("%s%s", dateStr, randomNumStr)
// 检查生成的合作商编号是否已存在
var count int64
err := db.Model(&bus_models.BusCooperative{}).Where("cooperative_number = ?", cooperativeNumber).Count(&count).Error
if err != nil {
return "", err
}
// 如果已存在,重新生成
if count > 0 {
return GenerateCooperativeNumber(db) // 递归重新生成
}
return cooperativeNumber, nil
}
// AdjustAccount 账户调整(加款/减款)
func (e *CooperativeService) AdjustAccount(ctx context.Context, req bus_models.AdjustAccountReq) error {
var cooperative bus_models.BusCooperative
db := e.Orm.WithContext(ctx)
// 查询合作商账户信息
if err := db.Where("cooperative_number = ?", req.CooperativeNumber).First(&cooperative).Error; err != nil {
return errors.New("合作商账户不存在")
}
// 确保 transaction_type = 2 (减款) 时,金额是负的
if req.TransactionType == 2 && req.Amount > 0 {
req.Amount = -req.Amount
}
// 加款时需要 SourceFundingType但减款时不需要
if req.TransactionType == 1 && req.SourceFundingType == 0 {
return errors.New("加款时必须填写资金来源")
}
// 计算新的余额
newBalance := cooperative.Balance
newFree := cooperative.Free
if req.TransactionType == 2 { // 处理减款
totalFunds := cooperative.Balance + cooperative.Free
if totalFunds < -req.Amount { // 确保总余额足够扣款
return errors.New("账户余额不足,无法扣款")
}
// 先扣普通余额,再扣赠送余额
if cooperative.Balance >= -req.Amount {
newBalance += req.Amount // 这里 req.Amount 是负数,所以相当于减去
} else {
remaining := -req.Amount - cooperative.Balance
newBalance = 0
newFree -= remaining
}
} else { // 处理加款
newBalance += req.Amount
newFree += req.GiftAmount // 仅加款时可增加赠送金额
}
// 开启事务,确保数据一致性
tx := db.Begin()
defer func() {
if r := recover(); r != nil {
tx.Rollback()
}
}()
// 更新合作商账户余额
if err := tx.Model(&cooperative).Updates(map[string]interface{}{
"balance": newBalance,
"free": newFree,
}).Error; err != nil {
tx.Rollback()
return errors.New("更新账户余额失败")
}
// 记录交易信息
transaction := bus_models.BusCooperativeTransaction{
CooperativeID: cooperative.ID,
Amount: req.Amount, // 直接存入调整后的金额
GiftAmount: req.GiftAmount,
SourceFundingType: req.SourceFundingType,
Remark: req.Remark,
}
if err := tx.Create(&transaction).Error; err != nil {
tx.Rollback()
return errors.New("记录交易失败")
}
tx.Commit()
return nil
}
// SetCooperativeStatus 在服务层更新合作商状态
func (e *CooperativeService) SetCooperativeStatus(req bus_models.SetCooperativeStatusReq) error {
return e.Orm.Model(&bus_models.BusCooperative{}).
Where("cooperative_number = ?", req.CooperativeNumber).
Update("status", req.Status).Error
}