561 lines
16 KiB
Go
561 lines
16 KiB
Go
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
|
||
}
|