You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
130 lines
4.8 KiB
130 lines
4.8 KiB
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
|
|
}
|
|
|