aditya.siregar c642c5c61b update
2025-04-05 11:28:06 +08:00

308 lines
8.5 KiB
Go

package repository
import (
"enaklo-pos-be/internal/common/logger"
"enaklo-pos-be/internal/common/mycontext"
"enaklo-pos-be/internal/entity"
"enaklo-pos-be/internal/repository/models"
"github.com/pkg/errors"
"go.uber.org/zap"
"gorm.io/gorm"
"time"
)
type OrderRepository interface {
Create(ctx mycontext.Context, order *entity.Order) (*entity.Order, error)
FindByID(ctx mycontext.Context, id int64) (*entity.Order, error)
CreateInquiry(ctx mycontext.Context, inquiry *entity.OrderInquiry) (*entity.OrderInquiry, error)
FindInquiryByID(ctx mycontext.Context, id string) (*entity.OrderInquiry, error)
UpdateInquiryStatus(ctx mycontext.Context, id string, status string) error
}
type orderRepository struct {
db *gorm.DB
}
func NeworderRepository(db *gorm.DB) *orderRepository {
return &orderRepository{db: db}
}
func (r *orderRepository) Create(ctx mycontext.Context, order *entity.Order) (*entity.Order, error) {
orderDB := r.toOrderDBModel(order)
tx := r.db.Begin()
if tx.Error != nil {
return nil, errors.Wrap(tx.Error, "failed to begin transaction")
}
defer func() {
if r := recover(); r != nil {
tx.Rollback()
}
}()
if err := tx.Create(&orderDB).Error; err != nil {
tx.Rollback()
return nil, errors.Wrap(err, "failed to insert order")
}
order.ID = orderDB.ID
for i := range order.OrderItems {
item := &order.OrderItems[i]
item.OrderID = orderDB.ID
itemDB := r.toOrderItemDBModel(item)
if err := tx.Create(&itemDB).Error; err != nil {
tx.Rollback()
return nil, errors.Wrap(err, "failed to insert order item")
}
item.ID = itemDB.ID
}
if order.InProgressOrderID != "" {
if err := tx.Where("in_progress_order_id = ?", order.InProgressOrderID).Delete(&models.InProgressOrderItemDB{}).Error; err != nil {
tx.Rollback()
return nil, errors.Wrap(err, "failed to delete in-progress order items")
}
if err := tx.Where("id = ?", order.InProgressOrderID).Delete(&models.InProgressOrderDB{}).Error; err != nil {
tx.Rollback()
return nil, errors.Wrap(err, "failed to delete in-progress order")
}
}
if err := tx.Commit().Error; err != nil {
return nil, errors.Wrap(err, "failed to commit transaction")
}
return order, nil
}
func (r *orderRepository) FindByID(ctx mycontext.Context, id int64) (*entity.Order, error) {
var orderDB models.OrderDB
if err := r.db.Preload("OrderItems").First(&orderDB, id).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, errors.New("order not found")
}
return nil, errors.Wrap(err, "failed to find order")
}
order := r.toDomainOrderModel(&orderDB)
for _, itemDB := range orderDB.OrderItems {
item := r.toDomainOrderItemModel(&itemDB)
order.OrderItems = append(order.OrderItems, *item)
}
return order, nil
}
func (r *orderRepository) CreateInquiry(ctx mycontext.Context, inquiry *entity.OrderInquiry) (*entity.OrderInquiry, error) {
inquiryDB := r.toOrderInquiryDBModel(inquiry)
inquiryItems := make([]models.InquiryItemDB, 0, len(inquiry.OrderItems))
for _, item := range inquiry.OrderItems {
inquiryItems = append(inquiryItems, models.InquiryItemDB{
InquiryID: inquiryDB.ID,
ItemID: item.ItemID,
ItemType: item.ItemType,
Price: item.Price,
Quantity: item.Quantity,
CreatedBy: item.CreatedBy,
CreatedAt: time.Now(),
})
}
tx := r.db.Begin()
if tx.Error != nil {
return nil, errors.Wrap(tx.Error, "failed to begin transaction")
}
defer func() {
if r := recover(); r != nil {
tx.Rollback()
}
}()
if err := tx.Create(&inquiryDB).Error; err != nil {
tx.Rollback()
return nil, errors.Wrap(err, "failed to insert order inquiry")
}
if len(inquiryItems) > 0 {
if err := tx.CreateInBatches(inquiryItems, 100).Error; err != nil {
tx.Rollback()
return nil, errors.Wrap(err, "failed to insert inquiry items")
}
}
if err := tx.Commit().Error; err != nil {
return nil, errors.Wrap(err, "failed to commit transaction")
}
return inquiry, nil
}
func (r *orderRepository) FindInquiryByID(ctx mycontext.Context, id string) (*entity.OrderInquiry, error) {
var inquiryDB models.OrderInquiryDB
if err := r.db.Preload("InquiryItems").First(&inquiryDB, "id = ?", id).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, errors.New("inquiry not found")
}
return nil, errors.Wrap(err, "failed to find inquiry")
}
inquiry := r.toDomainOrderInquiryModel(&inquiryDB)
orderItems := make([]entity.OrderItem, 0, len(inquiryDB.InquiryItems))
for _, itemDB := range inquiryDB.InquiryItems {
orderItems = append(orderItems, entity.OrderItem{
ItemID: itemDB.ItemID,
ItemType: itemDB.ItemType,
Price: itemDB.Price,
Quantity: itemDB.Quantity,
CreatedBy: itemDB.CreatedBy,
CreatedAt: itemDB.CreatedAt,
})
}
inquiry.OrderItems = orderItems
return inquiry, nil
}
func (r *orderRepository) UpdateInquiryStatus(ctx mycontext.Context, id string, status string) error {
now := time.Now()
result := r.db.Model(&models.OrderInquiryDB{}).
Where("id = ?", id).
Updates(map[string]interface{}{
"status": status,
"updated_at": now,
})
if result.Error != nil {
return errors.Wrap(result.Error, "failed to update inquiry status")
}
if result.RowsAffected == 0 {
logger.ContextLogger(ctx).Warn("no inquiry updated", zap.String("id", id))
}
return nil
}
func (r *orderRepository) toOrderDBModel(order *entity.Order) models.OrderDB {
return models.OrderDB{
ID: order.ID,
PartnerID: order.PartnerID,
CustomerID: order.CustomerID,
InquiryID: order.InquiryID,
Status: order.Status,
Amount: order.Amount,
Fee: order.Fee,
Total: order.Total,
PaymentType: order.PaymentType,
Source: order.Source,
CreatedBy: order.CreatedBy,
CreatedAt: order.CreatedAt,
UpdatedAt: order.UpdatedAt,
}
}
func (r *orderRepository) toDomainOrderModel(dbModel *models.OrderDB) *entity.Order {
return &entity.Order{
ID: dbModel.ID,
PartnerID: dbModel.PartnerID,
CustomerID: dbModel.CustomerID,
InquiryID: dbModel.InquiryID,
Status: dbModel.Status,
Amount: dbModel.Amount,
Fee: dbModel.Fee,
Total: dbModel.Total,
PaymentType: dbModel.PaymentType,
Source: dbModel.Source,
CreatedBy: dbModel.CreatedBy,
CreatedAt: dbModel.CreatedAt,
UpdatedAt: dbModel.UpdatedAt,
OrderItems: []entity.OrderItem{},
}
}
func (r *orderRepository) toOrderItemDBModel(item *entity.OrderItem) models.OrderItemDB {
return models.OrderItemDB{
ID: item.ID,
OrderID: item.OrderID,
ItemID: item.ItemID,
ItemType: item.ItemType,
Price: item.Price,
Quantity: item.Quantity,
CreatedBy: item.CreatedBy,
CreatedAt: item.CreatedAt,
}
}
func (r *orderRepository) toDomainOrderItemModel(dbModel *models.OrderItemDB) *entity.OrderItem {
return &entity.OrderItem{
ID: dbModel.ID,
OrderID: dbModel.OrderID,
ItemID: dbModel.ItemID,
ItemType: dbModel.ItemType,
Price: dbModel.Price,
Quantity: dbModel.Quantity,
CreatedBy: dbModel.CreatedBy,
CreatedAt: dbModel.CreatedAt,
}
}
func (r *orderRepository) toOrderInquiryDBModel(inquiry *entity.OrderInquiry) models.OrderInquiryDB {
return models.OrderInquiryDB{
ID: inquiry.ID,
PartnerID: inquiry.PartnerID,
CustomerID: &inquiry.CustomerID,
Status: inquiry.Status,
Amount: inquiry.Amount,
Fee: inquiry.Fee,
Total: inquiry.Total,
PaymentType: inquiry.PaymentType,
Source: inquiry.Source,
CreatedBy: inquiry.CreatedBy,
CreatedAt: inquiry.CreatedAt,
UpdatedAt: inquiry.UpdatedAt,
ExpiresAt: inquiry.ExpiresAt,
CustomerName: inquiry.CustomerName,
CustomerPhoneNumber: inquiry.CustomerPhoneNumber,
CustomerEmail: inquiry.CustomerEmail,
PaymentProvider: inquiry.PaymentProvider,
OrderType: inquiry.OrderType,
TableNumber: inquiry.TableNumber,
}
}
func (r *orderRepository) toDomainOrderInquiryModel(dbModel *models.OrderInquiryDB) *entity.OrderInquiry {
inquiry := &entity.OrderInquiry{
ID: dbModel.ID,
PartnerID: dbModel.PartnerID,
Status: dbModel.Status,
Amount: dbModel.Amount,
Fee: dbModel.Fee,
Total: dbModel.Total,
PaymentType: dbModel.PaymentType,
Source: dbModel.Source,
CreatedBy: dbModel.CreatedBy,
CreatedAt: dbModel.CreatedAt,
ExpiresAt: dbModel.ExpiresAt,
OrderItems: []entity.OrderItem{},
}
if dbModel.CustomerID != nil {
inquiry.CustomerID = *dbModel.CustomerID
}
inquiry.UpdatedAt = dbModel.UpdatedAt
return inquiry
}