package service import ( "errors" "time" "gorm.io/gorm" "laic-backend/common" "laic-backend/model" "laic-backend/tool" "laic-backend/vo" ) type InvoiceService struct{} var DefaultInvoiceService = &InvoiceService{} func (s *InvoiceService) ListProfiles(userID int64) ([]model.InvoiceProfile, *common.BusiError) { var profiles []model.InvoiceProfile if err := common.DB.Where("user_id = ?", userID).Order("is_default DESC, updated_at DESC, id DESC").Find(&profiles).Error; err != nil { return nil, common.ErrInternal } return profiles, nil } func (s *InvoiceService) SaveProfile(userID, profileID int64, req *vo.InvoiceProfileReq) (*model.InvoiceProfile, *common.BusiError) { var profile model.InvoiceProfile if profileID > 0 { if err := common.DB.Where("id = ? AND user_id = ?", profileID, userID).First(&profile).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return nil, common.ErrNotFound } return nil, common.ErrInternal } } else { id, err := tool.NextID() if err != nil { return nil, common.ErrInternal } profile = model.InvoiceProfile{ID: id, UserID: userID, CreatedAt: time.Now()} } profile.Title, profile.TaxpayerNumber, profile.Email, profile.IsDefault, profile.UpdatedAt = req.Title, req.TaxpayerNumber, req.Email, req.IsDefault, time.Now() if err := common.DB.Transaction(func(tx *gorm.DB) error { if req.IsDefault { if err := tx.Model(&model.InvoiceProfile{}).Where("user_id = ?", userID).Update("is_default", false).Error; err != nil { return err } } return tx.Save(&profile).Error }).Error; err != nil { return nil, common.ErrInternal } return &profile, nil } func (s *InvoiceService) DeleteProfile(userID, profileID int64) *common.BusiError { result := common.DB.Where("id = ? AND user_id = ?", profileID, userID).Delete(&model.InvoiceProfile{}) if result.Error != nil { return common.ErrInternal } if result.RowsAffected == 0 { return common.ErrNotFound } return nil } func (s *InvoiceService) ListEligibleOrders(userID int64) ([]model.TrafficOrder, *common.BusiError) { var orders []model.TrafficOrder if err := common.DB.Where("user_id = ? AND pay_status = ? AND NOT EXISTS (SELECT 1 FROM invoice_request WHERE invoice_request.order_id = traffic_order.id)", userID, "paid").Order("paid_at DESC, id DESC").Find(&orders).Error; err != nil { return nil, common.ErrInternal } return orders, nil } func (s *InvoiceService) CreateRequest(userID int64, req *vo.InvoiceRequestCreateReq) (*model.InvoiceRequest, *common.BusiError) { var profile model.InvoiceProfile if err := common.DB.Where("user_id = ? AND is_default = ?", userID, true).First(&profile).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return nil, common.NewBusiError(common.ParamError, "请先设置默认发票资料") } return nil, common.ErrInternal } var order model.TrafficOrder if err := common.DB.Where("id = ? AND user_id = ? AND pay_status = ?", req.OrderID, userID, "paid").First(&order).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return nil, common.ErrOrderNotFound } return nil, common.ErrInternal } id, err := tool.NextID() if err != nil { return nil, common.ErrInternal } request := &model.InvoiceRequest{ID: id, UserID: userID, OrderID: order.ID, Amount: order.TotalPrice, Title: profile.Title, TaxpayerNumber: profile.TaxpayerNumber, Email: profile.Email, Status: "pending", RequestedAt: time.Now()} if err := common.DB.Create(request).Error; err != nil { if code, _ := common.ParseError(err); code == 1062 { return nil, common.NewBusiError(common.ParamError, "该订单已申请发票") } return nil, common.ErrInternal } return request, nil } func (s *InvoiceService) ListRequests(userID int64) ([]model.InvoiceRequest, *common.BusiError) { var requests []model.InvoiceRequest if err := common.DB.Where("user_id = ?", userID).Order("requested_at DESC, id DESC").Find(&requests).Error; err != nil { return nil, common.ErrInternal } return requests, nil } func (s *InvoiceService) ReviewRequest(requestID int64, req *vo.InvoiceReviewReq) (*model.InvoiceRequest, *common.BusiError) { if req.Status != "issued" && req.Status != "rejected" { return nil, common.ErrParam } var request model.InvoiceRequest if err := common.DB.Where("id = ? AND status = ?", requestID, "pending").First(&request).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return nil, common.ErrNotFound } return nil, common.ErrInternal } now := time.Now() if err := common.DB.Model(&request).Updates(map[string]any{"status": req.Status, "invoice_number": req.InvoiceNumber, "admin_remark": req.AdminRemark, "processed_at": now}).Error; err != nil { return nil, common.ErrInternal } request.Status, request.InvoiceNumber, request.AdminRemark, request.ProcessedAt = req.Status, req.InvoiceNumber, req.AdminRemark, &now return &request, nil }