upodate system
This commit is contained in:
@@ -1,112 +1,116 @@
|
||||
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"
|
||||
"enaklo-pos-be/internal/services/v2/inprogress_order"
|
||||
time2 "time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"gorm.io/gorm"
|
||||
time2 "time"
|
||||
)
|
||||
|
||||
type InProgressOrderRepository interface {
|
||||
CreateOrUpdate(ctx mycontext.Context, order *entity.InProgressOrder) (*entity.InProgressOrder, error)
|
||||
GetListByPartnerID(ctx mycontext.Context, partnerID int64, limit, offset int) ([]*entity.InProgressOrder, error)
|
||||
FindByID(ctx mycontext.Context, id int64) (*entity.Order, error)
|
||||
CreateOrder(ctx mycontext.Context, order *entity.Order, tx *gorm.DB) (*entity.Order, error)
|
||||
CreateOrderItems(ctx mycontext.Context, orderID int64, items []entity.OrderItem, tx *gorm.DB) error
|
||||
GetListByPartnerID(ctx mycontext.Context, partnerID int64, limit, offset int, status string) ([]*entity.Order, error)
|
||||
FindByIDAndPartnerID(ctx mycontext.Context, id int64, partnerID int64) (*entity.Order, error)
|
||||
}
|
||||
|
||||
type inprogressOrderRepository struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
func NewInProgressOrderRepository(db *gorm.DB) *inprogressOrderRepository {
|
||||
func NewInProgressOrderRepository(db *gorm.DB) inprogress_order.OrderRepository {
|
||||
return &inprogressOrderRepository{db: db}
|
||||
}
|
||||
|
||||
func (r *inprogressOrderRepository) CreateOrUpdate(ctx mycontext.Context, order *entity.InProgressOrder) (*entity.InProgressOrder, error) {
|
||||
isUpdate := order.ID != ""
|
||||
func (r *inprogressOrderRepository) FindByID(ctx mycontext.Context, id int64) (*entity.Order, error) {
|
||||
var orderDB models.OrderDB
|
||||
|
||||
tx := r.db.Begin()
|
||||
if tx.Error != nil {
|
||||
return nil, errors.Wrap(tx.Error, "failed to begin transaction")
|
||||
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")
|
||||
}
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
tx.Rollback()
|
||||
}
|
||||
}()
|
||||
|
||||
orderDB := r.toInProgressOrderDBModel(order)
|
||||
order := r.toDomainOrderModel(&orderDB)
|
||||
|
||||
if isUpdate {
|
||||
var existingOrder models.InProgressOrderDB
|
||||
if err := tx.First(&existingOrder, order.ID).Error; err != nil {
|
||||
tx.Rollback()
|
||||
return nil, errors.Wrap(err, "order not found for update")
|
||||
}
|
||||
return order, nil
|
||||
}
|
||||
|
||||
if err := tx.Model(&orderDB).Updates(orderDB).Error; err != nil {
|
||||
tx.Rollback()
|
||||
return nil, errors.Wrap(err, "failed to update order")
|
||||
}
|
||||
func (r *inprogressOrderRepository) CreateOrder(ctx mycontext.Context, order *entity.Order, tx *gorm.DB) (*entity.Order, error) {
|
||||
orderDB := r.toOrderDBModel(order)
|
||||
|
||||
if err := tx.Where("in_progress_order_id = ?", order.ID).Delete(&models.InProgressOrderItemDB{}).Error; err != nil {
|
||||
tx.Rollback()
|
||||
return nil, errors.Wrap(err, "failed to delete existing order items")
|
||||
}
|
||||
// Use provided transaction or create new one
|
||||
var dbTx *gorm.DB
|
||||
if tx != nil {
|
||||
dbTx = tx
|
||||
} else {
|
||||
if err := tx.Create(&orderDB).Error; err != nil {
|
||||
tx.Rollback()
|
||||
return nil, errors.Wrap(err, "failed to insert order")
|
||||
dbTx = r.db.Begin()
|
||||
if dbTx.Error != nil {
|
||||
return nil, errors.Wrap(dbTx.Error, "failed to begin transaction")
|
||||
}
|
||||
|
||||
order.ID = orderDB.ID
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
dbTx.Rollback()
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
var itemIDs []int64
|
||||
for i := range order.OrderItems {
|
||||
itemIDs = append(itemIDs, order.OrderItems[i].ItemID)
|
||||
}
|
||||
|
||||
var products []models.ProductDB
|
||||
if len(itemIDs) > 0 {
|
||||
if err := tx.Where("id IN ?", itemIDs).Find(&products).Error; err != nil {
|
||||
tx.Rollback()
|
||||
return nil, errors.Wrap(err, "failed to fetch products")
|
||||
if err := dbTx.Create(&orderDB).Error; err != nil {
|
||||
if tx == nil {
|
||||
dbTx.Rollback()
|
||||
}
|
||||
return nil, errors.Wrap(err, "failed to insert order")
|
||||
}
|
||||
order.ID = orderDB.ID
|
||||
|
||||
productMap := make(map[int64]models.ProductDB)
|
||||
for _, product := range products {
|
||||
productMap[product.ID] = product
|
||||
}
|
||||
|
||||
for i := range order.OrderItems {
|
||||
item := &order.OrderItems[i]
|
||||
|
||||
itemDB := r.toOrderItemDBModel(item, orderDB.ID)
|
||||
|
||||
if err := tx.Create(&itemDB).Error; err != nil {
|
||||
tx.Rollback()
|
||||
return nil, errors.Wrap(err, "failed to insert order item")
|
||||
// Only commit if we created the transaction
|
||||
if tx == nil {
|
||||
if err := dbTx.Commit().Error; err != nil {
|
||||
return nil, errors.Wrap(err, "failed to commit transaction")
|
||||
}
|
||||
|
||||
item.ID = itemDB.ID
|
||||
|
||||
if product, exists := productMap[item.ItemID]; exists {
|
||||
item.Product = r.toDomainProductModel(&product)
|
||||
}
|
||||
}
|
||||
|
||||
if err := tx.Commit().Error; err != nil {
|
||||
return nil, errors.Wrap(err, "failed to commit transaction")
|
||||
}
|
||||
|
||||
return order, nil
|
||||
}
|
||||
|
||||
func (r *inprogressOrderRepository) GetListByPartnerID(ctx mycontext.Context, partnerID int64, limit, offset int) ([]*entity.InProgressOrder, error) {
|
||||
var ordersDB []models.InProgressOrderDB
|
||||
query := r.db.Where("partner_id = ?", partnerID).Order("created_at DESC")
|
||||
func (r *inprogressOrderRepository) CreateOrderItems(ctx mycontext.Context, orderID int64, items []entity.OrderItem, tx *gorm.DB) error {
|
||||
if len(items) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
itemsDB := make([]models.OrderItemDB, len(items))
|
||||
for i, item := range items {
|
||||
itemDB := r.toOrderItemDBModel(&item)
|
||||
itemDB.OrderID = orderID
|
||||
itemsDB[i] = itemDB
|
||||
}
|
||||
|
||||
if err := tx.Create(&itemsDB).Error; err != nil {
|
||||
return errors.Wrap(err, "failed to bulk insert order items")
|
||||
}
|
||||
|
||||
for i := range items {
|
||||
items[i].ID = itemsDB[i].ID
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
func (r *inprogressOrderRepository) GetListByPartnerID(ctx mycontext.Context, partnerID int64, limit, offset int, status string) ([]*entity.Order, error) {
|
||||
var ordersDB []models.OrderDB
|
||||
query := r.db.Where("partner_id = ?", partnerID)
|
||||
|
||||
if status != "" {
|
||||
query = query.Where("status = ?", status)
|
||||
}
|
||||
|
||||
query = query.Order("created_at DESC")
|
||||
|
||||
if limit > 0 {
|
||||
query = query.Limit(limit)
|
||||
@@ -116,27 +120,39 @@ func (r *inprogressOrderRepository) GetListByPartnerID(ctx mycontext.Context, pa
|
||||
query = query.Offset(offset)
|
||||
}
|
||||
|
||||
if err := query.Preload("OrderItems.Product").Find(&ordersDB).Error; err != nil {
|
||||
if err := query.Find(&ordersDB).Error; err != nil {
|
||||
return nil, errors.Wrap(err, "failed to find orders by partner ID")
|
||||
}
|
||||
|
||||
orders := make([]*entity.InProgressOrder, 0, len(ordersDB))
|
||||
orders := make([]*entity.Order, 0, len(ordersDB))
|
||||
for _, orderDB := range ordersDB {
|
||||
order := r.toDomainOrderModel(&orderDB)
|
||||
order.OrderItems = make([]entity.InProgressOrderItem, 0, len(orderDB.OrderItems))
|
||||
|
||||
for _, itemDB := range orderDB.OrderItems {
|
||||
var orderItems []models.OrderItemDB
|
||||
if err := r.db.Where("order_id = ?", orderDB.ID).Find(&orderItems).Error; err != nil {
|
||||
return nil, errors.Wrap(err, "failed to find order items")
|
||||
}
|
||||
|
||||
order.OrderItems = make([]entity.OrderItem, 0, len(orderItems))
|
||||
|
||||
for _, itemDB := range orderItems {
|
||||
item := r.toDomainOrderItemModel(&itemDB)
|
||||
|
||||
orderItem := entity.InProgressOrderItem{
|
||||
orderItem := entity.OrderItem{
|
||||
ID: item.ID,
|
||||
ItemID: item.ItemID,
|
||||
Quantity: item.Quantity,
|
||||
ItemName: item.ItemName,
|
||||
}
|
||||
|
||||
if itemDB.Product.ID > 0 {
|
||||
productDomain := r.toDomainProductModel(&itemDB.Product)
|
||||
orderItem.Product = productDomain
|
||||
if itemDB.ItemID > 0 {
|
||||
var product models.ProductDB
|
||||
err := r.db.First(&product, itemDB.ItemID).Error
|
||||
|
||||
if err == nil {
|
||||
productDomain := r.toDomainProductModel(&product)
|
||||
orderItem.Product = productDomain
|
||||
}
|
||||
}
|
||||
|
||||
order.OrderItems = append(order.OrderItems, orderItem)
|
||||
@@ -148,106 +164,122 @@ func (r *inprogressOrderRepository) GetListByPartnerID(ctx mycontext.Context, pa
|
||||
return orders, nil
|
||||
}
|
||||
|
||||
func (r *inprogressOrderRepository) toInProgressOrderDBModel(order *entity.InProgressOrder) models.InProgressOrderDB {
|
||||
func (r *inprogressOrderRepository) FindByIDAndPartnerID(ctx mycontext.Context, id int64, partnerID int64) (*entity.Order, error) {
|
||||
var orderDB models.OrderDB
|
||||
|
||||
if err := r.db.Preload("OrderItems").Where("id = ? AND partner_id = ?", id, partnerID).First(&orderDB).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 *inprogressOrderRepository) toOrderDBModel(order *entity.Order) models.OrderDB {
|
||||
now := time2.Now()
|
||||
return models.InProgressOrderDB{
|
||||
ID: order.ID,
|
||||
PartnerID: order.PartnerID,
|
||||
CustomerID: order.CustomerID,
|
||||
CustomerName: order.CustomerName,
|
||||
PaymentType: order.PaymentType,
|
||||
CreatedBy: order.CreatedBy,
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
TableNumber: order.TableNumber,
|
||||
OrderType: order.OrderType,
|
||||
return models.OrderDB{
|
||||
ID: order.ID,
|
||||
PartnerID: order.PartnerID,
|
||||
CustomerID: order.CustomerID,
|
||||
CustomerName: order.CustomerName,
|
||||
PaymentType: order.PaymentType,
|
||||
PaymentProvider: order.PaymentProvider,
|
||||
CreatedBy: order.CreatedBy,
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
TableNumber: order.TableNumber,
|
||||
OrderType: order.OrderType,
|
||||
Status: order.Status,
|
||||
Amount: order.Amount,
|
||||
Total: order.Total,
|
||||
Tax: order.Tax,
|
||||
Source: order.Source,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *inprogressOrderRepository) toDomainOrderModel(dbModel *models.InProgressOrderDB) *entity.InProgressOrder {
|
||||
return &entity.InProgressOrder{
|
||||
ID: dbModel.ID,
|
||||
PartnerID: dbModel.PartnerID,
|
||||
CustomerID: dbModel.CustomerID,
|
||||
CustomerName: dbModel.CustomerName,
|
||||
PaymentType: dbModel.PaymentType,
|
||||
CreatedBy: dbModel.CreatedBy,
|
||||
OrderItems: []entity.InProgressOrderItem{},
|
||||
TableNumber: dbModel.TableNumber,
|
||||
OrderType: dbModel.OrderType,
|
||||
CreatedAt: dbModel.CreatedAt,
|
||||
UpdatedAt: dbModel.UpdatedAt,
|
||||
func (r *inprogressOrderRepository) toDomainOrderModel(dbModel *models.OrderDB) *entity.Order {
|
||||
orderItems := make([]entity.OrderItem, 0, len(dbModel.OrderItems))
|
||||
for _, itemDB := range dbModel.OrderItems {
|
||||
orderItems = append(orderItems, entity.OrderItem{
|
||||
ItemID: itemDB.ItemID,
|
||||
ItemType: itemDB.ItemType,
|
||||
ItemName: itemDB.ItemName,
|
||||
Price: itemDB.Price,
|
||||
Quantity: itemDB.Quantity,
|
||||
Status: itemDB.Status,
|
||||
CreatedBy: itemDB.CreatedBy,
|
||||
CreatedAt: itemDB.CreatedAt,
|
||||
Notes: itemDB.Notes,
|
||||
})
|
||||
}
|
||||
|
||||
return &entity.Order{
|
||||
ID: dbModel.ID,
|
||||
PartnerID: dbModel.PartnerID,
|
||||
CustomerID: dbModel.CustomerID,
|
||||
InquiryID: dbModel.InquiryID,
|
||||
Status: dbModel.Status,
|
||||
Amount: dbModel.Amount,
|
||||
Tax: dbModel.Tax,
|
||||
Total: dbModel.Total,
|
||||
PaymentType: dbModel.PaymentType,
|
||||
Source: dbModel.Source,
|
||||
CreatedBy: dbModel.CreatedBy,
|
||||
CreatedAt: dbModel.CreatedAt,
|
||||
UpdatedAt: dbModel.UpdatedAt,
|
||||
OrderItems: orderItems,
|
||||
CustomerName: dbModel.CustomerName,
|
||||
TableNumber: dbModel.TableNumber,
|
||||
OrderType: dbModel.OrderType,
|
||||
PaymentProvider: dbModel.PaymentProvider,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *inprogressOrderRepository) toOrderItemDBModel(item *entity.InProgressOrderItem, inprogressOrderID string) models.InProgressOrderItemDB {
|
||||
return models.InProgressOrderItemDB{
|
||||
ID: item.ID,
|
||||
InProgressOrderIO: inprogressOrderID,
|
||||
ItemID: item.ItemID,
|
||||
Quantity: item.Quantity,
|
||||
func (r *inprogressOrderRepository) toOrderItemDBModel(item *entity.OrderItem) models.OrderItemDB {
|
||||
return models.OrderItemDB{
|
||||
ID: item.ID,
|
||||
OrderID: item.OrderID,
|
||||
ItemID: item.ItemID,
|
||||
ItemType: item.ItemType,
|
||||
ItemName: item.ItemName,
|
||||
Price: item.Price,
|
||||
Quantity: item.Quantity,
|
||||
Status: item.Status,
|
||||
CreatedBy: item.CreatedBy,
|
||||
CreatedAt: item.CreatedAt,
|
||||
Notes: item.Notes,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *inprogressOrderRepository) toDomainOrderItemModel(dbModel *models.InProgressOrderItemDB) *entity.OrderItem {
|
||||
func (r *inprogressOrderRepository) 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,
|
||||
Status: dbModel.Status,
|
||||
CreatedBy: dbModel.CreatedBy,
|
||||
CreatedAt: dbModel.CreatedAt,
|
||||
ItemName: dbModel.ItemName,
|
||||
Notes: dbModel.Notes,
|
||||
Product: &entity.Product{
|
||||
ID: dbModel.ItemID,
|
||||
Name: dbModel.ItemName,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (r *inprogressOrderRepository) toOrderInquiryDBModel(inquiry *entity.OrderInquiry) models.OrderInquiryDB {
|
||||
return models.OrderInquiryDB{
|
||||
ID: inquiry.ID,
|
||||
PartnerID: inquiry.PartnerID,
|
||||
CustomerID: &inquiry.CustomerID,
|
||||
Status: inquiry.Status,
|
||||
Amount: inquiry.Amount,
|
||||
Tax: inquiry.Tax,
|
||||
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 *inprogressOrderRepository) toDomainOrderInquiryModel(dbModel *models.OrderInquiryDB) *entity.OrderInquiry {
|
||||
inquiry := &entity.OrderInquiry{
|
||||
ID: dbModel.ID,
|
||||
PartnerID: dbModel.PartnerID,
|
||||
Status: dbModel.Status,
|
||||
Amount: dbModel.Amount,
|
||||
Tax: dbModel.Tax,
|
||||
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
|
||||
}
|
||||
|
||||
func (r *inprogressOrderRepository) toDomainProductModel(productDB *models.ProductDB) *entity.Product {
|
||||
if productDB == nil {
|
||||
return nil
|
||||
@@ -264,3 +296,26 @@ func (r *inprogressOrderRepository) toDomainProductModel(productDB *models.Produ
|
||||
Image: productDB.Image,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *inprogressOrderRepository) UpdateOrderTotalsWithTx(ctx mycontext.Context, trx *gorm.DB, orderID int64, amount, tax, total float64) error {
|
||||
now := time2.Now()
|
||||
|
||||
result := trx.Model(&models.OrderDB{}).
|
||||
Where("id = ?", orderID).
|
||||
Updates(map[string]interface{}{
|
||||
"amount": amount,
|
||||
"tax": tax,
|
||||
"total": total,
|
||||
"updated_at": now,
|
||||
})
|
||||
|
||||
if result.Error != nil {
|
||||
return errors.Wrap(result.Error, "failed to update order totals")
|
||||
}
|
||||
|
||||
if result.RowsAffected == 0 {
|
||||
logger.ContextLogger(ctx).Warn("no order updated")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -4,9 +4,10 @@ import (
|
||||
"enaklo-pos-be/internal/common/mycontext"
|
||||
"enaklo-pos-be/internal/entity"
|
||||
"enaklo-pos-be/internal/repository/models"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"gorm.io/gorm"
|
||||
"time"
|
||||
)
|
||||
|
||||
type CashierSessionRepository interface {
|
||||
@@ -15,6 +16,7 @@ type CashierSessionRepository interface {
|
||||
GetOpenSessionByCashierID(ctx mycontext.Context, cashierID int64) (*entity.CashierSession, error)
|
||||
GetSessionByID(ctx mycontext.Context, sessionID int64) (*entity.CashierSession, error)
|
||||
GetPaymentSummaryBySessionID(ctx mycontext.Context, sessionID int64) ([]entity.PaymentSummary, error)
|
||||
GetSessionHistoryByPartnerID(ctx mycontext.Context, partnerID int64, limit, offset int) ([]*entity.CashierSession, int64, error)
|
||||
}
|
||||
|
||||
type cashierSessionRepository struct {
|
||||
@@ -27,6 +29,7 @@ func NewCashierSessionRepository(db *gorm.DB) CashierSessionRepository {
|
||||
|
||||
func (r *cashierSessionRepository) CreateSession(ctx mycontext.Context, session *entity.CashierSession) (*entity.CashierSession, error) {
|
||||
dbModel := models.CashierSessionDB{
|
||||
PartnerID: session.PartnerID,
|
||||
CashierID: session.CashierID,
|
||||
OpenedAt: time.Now(),
|
||||
OpeningAmount: session.OpeningAmount,
|
||||
@@ -94,6 +97,7 @@ func (r *cashierSessionRepository) GetSessionByID(ctx mycontext.Context, session
|
||||
func (r *cashierSessionRepository) toEntity(db *models.CashierSessionDB) *entity.CashierSession {
|
||||
return &entity.CashierSession{
|
||||
ID: db.ID,
|
||||
PartnerID: db.PartnerID,
|
||||
CashierID: db.CashierID,
|
||||
OpenedAt: db.OpenedAt,
|
||||
ClosedAt: db.ClosedAt,
|
||||
@@ -135,3 +139,39 @@ func (r *cashierSessionRepository) GetPaymentSummaryBySessionID(ctx mycontext.Co
|
||||
|
||||
return summary, nil
|
||||
}
|
||||
|
||||
func (r *cashierSessionRepository) GetSessionHistoryByPartnerID(ctx mycontext.Context, partnerID int64, limit, offset int) ([]*entity.CashierSession, int64, error) {
|
||||
var sessionsDB []models.CashierSessionDB
|
||||
var totalCount int64
|
||||
|
||||
// Count total records
|
||||
if err := r.db.Model(&models.CashierSessionDB{}).
|
||||
Where("partner_id = ?", partnerID).
|
||||
Count(&totalCount).Error; err != nil {
|
||||
return nil, 0, errors.Wrap(err, "failed to count cashier sessions")
|
||||
}
|
||||
|
||||
// Get sessions with pagination
|
||||
query := r.db.Where("partner_id = ?", partnerID).
|
||||
Order("opened_at DESC")
|
||||
|
||||
if limit > 0 {
|
||||
query = query.Limit(limit)
|
||||
}
|
||||
|
||||
if offset > 0 {
|
||||
query = query.Offset(offset)
|
||||
}
|
||||
|
||||
if err := query.Find(&sessionsDB).Error; err != nil {
|
||||
return nil, 0, errors.Wrap(err, "failed to get cashier session history")
|
||||
}
|
||||
|
||||
// Convert to entity
|
||||
sessions := make([]*entity.CashierSession, len(sessionsDB))
|
||||
for i, sessionDB := range sessionsDB {
|
||||
sessions[i] = r.toEntity(&sessionDB)
|
||||
}
|
||||
|
||||
return sessions, totalCount, nil
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import "time"
|
||||
|
||||
type CashierSessionDB struct {
|
||||
ID int64 `gorm:"primaryKey"`
|
||||
PartnerID int64 `gorm:"not null"`
|
||||
CashierID int64 `gorm:"not null"`
|
||||
OpenedAt time.Time `gorm:"not null"`
|
||||
ClosedAt *time.Time
|
||||
|
||||
@@ -39,6 +39,7 @@ type OrderItemDB struct {
|
||||
ItemType string `gorm:"column:item_type"`
|
||||
Price float64 `gorm:"column:price"`
|
||||
Quantity int `gorm:"column:quantity"`
|
||||
Status string `gorm:"column:status;default:ACTIVE"`
|
||||
CreatedBy int64 `gorm:"column:created_by"`
|
||||
CreatedAt time.Time `gorm:"column:created_at"`
|
||||
Product ProductDB `gorm:"foreignKey:ItemID;references:ID"`
|
||||
|
||||
+181
-169
@@ -5,10 +5,11 @@ import (
|
||||
"enaklo-pos-be/internal/common/mycontext"
|
||||
"enaklo-pos-be/internal/entity"
|
||||
"enaklo-pos-be/internal/repository/models"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"go.uber.org/zap"
|
||||
"gorm.io/gorm"
|
||||
"time"
|
||||
)
|
||||
|
||||
type OrderRepository interface {
|
||||
@@ -17,32 +18,22 @@ type OrderRepository interface {
|
||||
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
|
||||
GetOrderHistoryByPartnerID(ctx mycontext.Context, partnerID int64, req entity.SearchRequest) ([]*entity.Order, int64, error)
|
||||
CreateOrUpdate(ctx mycontext.Context, order *entity.Order) (*entity.Order, error)
|
||||
GetOrderHistoryByPartnerID(ctx mycontext.Context, partnerID *int64, req entity.SearchRequest) ([]*entity.Order, int64, error)
|
||||
CreateOrder(ctx mycontext.Context, order *entity.Order, tx *gorm.DB) (*entity.Order, error)
|
||||
CreateOrderItems(ctx mycontext.Context, orderID int64, items []entity.OrderItem, tx *gorm.DB) error
|
||||
CreateOrderItem(ctx mycontext.Context, orderID int64, item *entity.OrderItem) error
|
||||
GetListByPartnerID(ctx mycontext.Context, partnerID int64, limit, offset int, status string) ([]*entity.Order, error)
|
||||
GetOrderPaymentMethodBreakdown(
|
||||
ctx mycontext.Context,
|
||||
partnerID int64,
|
||||
req entity.SearchRequest,
|
||||
) ([]entity.PaymentMethodBreakdown, error)
|
||||
GetRevenueOverview(
|
||||
ctx mycontext.Context,
|
||||
req entity.RevenueOverviewRequest,
|
||||
) ([]entity.RevenueOverviewItem, error)
|
||||
GetSalesByCategory(
|
||||
ctx mycontext.Context,
|
||||
req entity.SalesByCategoryRequest,
|
||||
) ([]entity.SalesByCategoryItem, error)
|
||||
GetPopularProducts(
|
||||
ctx mycontext.Context,
|
||||
req entity.PopularProductsRequest,
|
||||
) ([]entity.PopularProductItem, error)
|
||||
GetOrderPaymentMethodBreakdown(ctx mycontext.Context, partnerID int64, req entity.SearchRequest) ([]entity.PaymentMethodBreakdown, error)
|
||||
GetRevenueOverview(ctx mycontext.Context, req entity.RevenueOverviewRequest) ([]entity.RevenueOverviewItem, error)
|
||||
GetSalesByCategory(ctx mycontext.Context, req entity.SalesByCategoryRequest) ([]entity.SalesByCategoryItem, error)
|
||||
GetPopularProducts(ctx mycontext.Context, req entity.PopularProductsRequest) ([]entity.PopularProductItem, error)
|
||||
FindByIDAndPartnerID(ctx mycontext.Context, id int64, partnerID int64) (*entity.Order, error)
|
||||
GetOrderHistoryByUserID(ctx mycontext.Context, userID int64, req entity.SearchRequest) ([]*entity.Order, int64, error)
|
||||
FindByIDAndCustomerID(ctx mycontext.Context, id int64, customerID int64) (*entity.Order, error)
|
||||
UpdateOrder(ctx mycontext.Context, id int64, status string, description string) error
|
||||
UpdateOrderItem(ctx mycontext.Context, orderItemID int64, quantity int) error
|
||||
UpdateOrderTotals(ctx mycontext.Context, orderID int64, amount, tax, total float64) error
|
||||
UpdateOrderTotalsWithTx(ctx mycontext.Context, trx *gorm.DB, orderID int64, amount, tax, total float64) error
|
||||
}
|
||||
|
||||
type orderRepository struct {
|
||||
@@ -129,11 +120,6 @@ func (r *orderRepository) FindByID(ctx mycontext.Context, id int64) (*entity.Ord
|
||||
|
||||
order := r.toDomainOrderModel(&orderDB)
|
||||
|
||||
for _, itemDB := range orderDB.OrderItems {
|
||||
item := r.toDomainOrderItemModel(&itemDB)
|
||||
order.OrderItems = append(order.OrderItems, *item)
|
||||
}
|
||||
|
||||
return order, nil
|
||||
}
|
||||
|
||||
@@ -281,15 +267,16 @@ func (r *orderRepository) toOrderDBModel(order *entity.Order) models.OrderDB {
|
||||
}
|
||||
|
||||
func (r *orderRepository) toDomainOrderModel(dbModel *models.OrderDB) *entity.Order {
|
||||
|
||||
orderItems := make([]entity.OrderItem, 0, len(dbModel.OrderItems))
|
||||
for _, itemDB := range dbModel.OrderItems {
|
||||
orderItems = append(orderItems, entity.OrderItem{
|
||||
ID: itemDB.ID,
|
||||
ItemID: itemDB.ItemID,
|
||||
ItemType: itemDB.ItemType,
|
||||
ItemName: itemDB.ItemName,
|
||||
Price: itemDB.Price,
|
||||
Quantity: itemDB.Quantity,
|
||||
Status: itemDB.Status,
|
||||
CreatedBy: itemDB.CreatedBy,
|
||||
CreatedAt: itemDB.CreatedAt,
|
||||
Notes: itemDB.Notes,
|
||||
@@ -327,6 +314,7 @@ func (r *orderRepository) toOrderItemDBModel(item *entity.OrderItem) models.Orde
|
||||
ItemName: item.ItemName,
|
||||
Price: item.Price,
|
||||
Quantity: item.Quantity,
|
||||
Status: item.Status,
|
||||
CreatedBy: item.CreatedBy,
|
||||
CreatedAt: item.CreatedAt,
|
||||
Notes: item.Notes,
|
||||
@@ -341,9 +329,11 @@ func (r *orderRepository) toDomainOrderItemModel(dbModel *models.OrderItemDB) *e
|
||||
ItemType: dbModel.ItemType,
|
||||
Price: dbModel.Price,
|
||||
Quantity: dbModel.Quantity,
|
||||
Status: dbModel.Status,
|
||||
CreatedBy: dbModel.CreatedBy,
|
||||
CreatedAt: dbModel.CreatedAt,
|
||||
ItemName: dbModel.ItemName,
|
||||
Notes: dbModel.Notes,
|
||||
Product: &entity.Product{
|
||||
ID: dbModel.ItemID,
|
||||
Name: dbModel.ItemName,
|
||||
@@ -406,65 +396,70 @@ func (r *orderRepository) toDomainOrderInquiryModel(dbModel *models.OrderInquiry
|
||||
return inquiry
|
||||
}
|
||||
|
||||
func (r *orderRepository) GetOrderHistoryByPartnerID(ctx mycontext.Context, partnerID int64, req entity.SearchRequest) ([]*entity.Order, int64, error) {
|
||||
var ordersDB []models.OrderDB
|
||||
var totalCount int64
|
||||
func (r *orderRepository) GetOrderHistoryByPartnerID(ctx mycontext.Context, partnerID *int64, req entity.SearchRequest) ([]*entity.Order, int64, error) {
|
||||
queryBuilder := NewQueryBuilder[models.OrderDB](r.db)
|
||||
filters := []Filter{
|
||||
Equal("partner_id", partnerID),
|
||||
}
|
||||
|
||||
// Build the base query
|
||||
baseQuery := r.db.Model(&models.OrderDB{}).Where("partner_id = ?", partnerID)
|
||||
|
||||
// Apply filters to the base query
|
||||
if req.Status != "" {
|
||||
baseQuery = baseQuery.Where("status = ?", req.Status)
|
||||
filters = append(filters, Equal("status", req.Status))
|
||||
}
|
||||
|
||||
if !req.Start.IsZero() {
|
||||
baseQuery = baseQuery.Where("created_at >= ?", req.Start)
|
||||
filters = append(filters, GreaterEqual("created_at", req.Start))
|
||||
}
|
||||
|
||||
if !req.End.IsZero() {
|
||||
baseQuery = baseQuery.Where("created_at <= ?", req.End)
|
||||
filters = append(filters, LessEqual("created_at", req.End))
|
||||
}
|
||||
|
||||
// Get total count with the current filters before pagination
|
||||
if err := baseQuery.Count(&totalCount).Error; err != nil {
|
||||
return nil, 0, errors.Wrap(err, "failed to count total orders")
|
||||
options := QueryOptions{
|
||||
Filters: filters,
|
||||
Limit: req.Limit,
|
||||
Offset: req.Offset,
|
||||
OrderBy: []string{"created_at DESC"},
|
||||
Preloads: []string{"OrderItems"},
|
||||
}
|
||||
|
||||
// Clone the query for fetching the actual data with pagination
|
||||
query := baseQuery.Session(&gorm.Session{})
|
||||
|
||||
// Add ordering and pagination
|
||||
query = query.Order("created_at DESC")
|
||||
|
||||
if req.Limit > 0 {
|
||||
query = query.Limit(req.Limit)
|
||||
baseQuery := queryBuilder.BuildQuery(options)
|
||||
totalCount, err := queryBuilder.Count(baseQuery)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
if req.Offset > 0 {
|
||||
query = query.Offset(req.Offset)
|
||||
query := queryBuilder.ExecuteQuery(baseQuery, options)
|
||||
ordersDB, err := queryBuilder.Find(query)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
// Execute the query with preloading
|
||||
if err := query.Preload("OrderItems").Find(&ordersDB).Error; err != nil {
|
||||
return nil, 0, errors.Wrap(err, "failed to find order history by partner ID")
|
||||
}
|
||||
orders := r.convertOrdersToEntity(ordersDB)
|
||||
|
||||
// Map to domain models
|
||||
return orders, totalCount, nil
|
||||
}
|
||||
|
||||
func (r *orderRepository) convertOrdersToEntity(ordersDB []models.OrderDB) []*entity.Order {
|
||||
orders := make([]*entity.Order, 0, len(ordersDB))
|
||||
|
||||
for _, orderDB := range ordersDB {
|
||||
order := r.toDomainOrderModel(&orderDB)
|
||||
order.OrderItems = make([]entity.OrderItem, 0, len(orderDB.OrderItems))
|
||||
|
||||
for _, itemDB := range orderDB.OrderItems {
|
||||
item := r.toDomainOrderItemModel(&itemDB)
|
||||
order.OrderItems = append(order.OrderItems, *item)
|
||||
}
|
||||
|
||||
order.OrderItems = r.convertOrderItemsToEntity(orderDB.OrderItems)
|
||||
orders = append(orders, order)
|
||||
}
|
||||
|
||||
return orders, totalCount, nil
|
||||
return orders
|
||||
}
|
||||
|
||||
func (r *orderRepository) convertOrderItemsToEntity(itemsDB []models.OrderItemDB) []entity.OrderItem {
|
||||
items := make([]entity.OrderItem, 0, len(itemsDB))
|
||||
|
||||
for _, itemDB := range itemsDB {
|
||||
item := r.toDomainOrderItemModel(&itemDB)
|
||||
items = append(items, *item)
|
||||
}
|
||||
|
||||
return items
|
||||
}
|
||||
|
||||
func (r *orderRepository) GetOrderHistoryByUserID(ctx mycontext.Context, userID int64, req entity.SearchRequest) ([]*entity.Order, int64, error) {
|
||||
@@ -521,126 +516,108 @@ func (r *orderRepository) GetOrderHistoryByUserID(ctx mycontext.Context, userID
|
||||
return orders, totalCount, nil
|
||||
}
|
||||
|
||||
func (r *orderRepository) CreateOrUpdate(ctx mycontext.Context, order *entity.Order) (*entity.Order, error) {
|
||||
isUpdate := order.ID != 0
|
||||
func (r *orderRepository) CreateOrder(ctx mycontext.Context, order *entity.Order, tx *gorm.DB) (*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()
|
||||
}
|
||||
}()
|
||||
|
||||
orderDB := r.toInProgressOrderDBModel(order)
|
||||
|
||||
if isUpdate {
|
||||
var existingOrder models.OrderDB
|
||||
if err := tx.First(&existingOrder, order.ID).Error; err != nil {
|
||||
tx.Rollback()
|
||||
return nil, errors.Wrap(err, "order not found for update")
|
||||
}
|
||||
|
||||
if err := tx.Model(&orderDB).Updates(orderDB).Error; err != nil {
|
||||
tx.Rollback()
|
||||
return nil, errors.Wrap(err, "failed to update order")
|
||||
}
|
||||
|
||||
if err := tx.Where("order_id = ?", order.ID).Delete(&models.OrderItemDB{}).Error; err != nil {
|
||||
tx.Rollback()
|
||||
return nil, errors.Wrap(err, "failed to delete existing order items")
|
||||
}
|
||||
// Use provided transaction or create new one
|
||||
var dbTx *gorm.DB
|
||||
if tx != nil {
|
||||
dbTx = tx
|
||||
} else {
|
||||
if err := tx.Create(&orderDB).Error; err != nil {
|
||||
tx.Rollback()
|
||||
dbTx = r.db.Begin()
|
||||
if dbTx.Error != nil {
|
||||
return nil, errors.Wrap(dbTx.Error, "failed to begin transaction")
|
||||
}
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
dbTx.Rollback()
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
if order.InProgressOrderID != 0 {
|
||||
// Update existing order
|
||||
orderDB.ID = order.InProgressOrderID
|
||||
if err := dbTx.Omit("customer_id", "partner_id", "customer_name", "created_by").Save(&orderDB).Error; err != nil {
|
||||
if tx == nil {
|
||||
dbTx.Rollback()
|
||||
}
|
||||
return nil, errors.Wrap(err, "failed to update in-progress order")
|
||||
}
|
||||
order.ID = order.InProgressOrderID
|
||||
} else {
|
||||
// Create new order
|
||||
if err := dbTx.Create(&orderDB).Error; err != nil {
|
||||
if tx == nil {
|
||||
dbTx.Rollback()
|
||||
}
|
||||
return nil, errors.Wrap(err, "failed to insert order")
|
||||
}
|
||||
|
||||
order.ID = orderDB.ID
|
||||
}
|
||||
|
||||
var itemIDs []int64
|
||||
for i := range order.OrderItems {
|
||||
itemIDs = append(itemIDs, order.OrderItems[i].ItemID)
|
||||
}
|
||||
|
||||
var products []models.ProductDB
|
||||
if len(itemIDs) > 0 {
|
||||
if err := tx.Where("id IN ?", itemIDs).Find(&products).Error; err != nil {
|
||||
tx.Rollback()
|
||||
return nil, errors.Wrap(err, "failed to fetch products")
|
||||
// Only commit if we created the transaction
|
||||
if tx == nil {
|
||||
if err := dbTx.Commit().Error; err != nil {
|
||||
return nil, errors.Wrap(err, "failed to commit transaction")
|
||||
}
|
||||
}
|
||||
|
||||
productMap := make(map[int64]models.ProductDB)
|
||||
for _, product := range products {
|
||||
productMap[product.ID] = product
|
||||
}
|
||||
|
||||
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 product, exists := productMap[item.ItemID]; exists {
|
||||
item.Product = r.toDomainProductModel(&product)
|
||||
}
|
||||
}
|
||||
|
||||
if err := tx.Commit().Error; err != nil {
|
||||
return nil, errors.Wrap(err, "failed to commit transaction")
|
||||
}
|
||||
|
||||
// Return the order with the ID set, but without items (items will be added separately)
|
||||
return order, nil
|
||||
}
|
||||
|
||||
func (r *orderRepository) toInProgressOrderDBModel(order *entity.Order) models.OrderDB {
|
||||
now := time.Now()
|
||||
|
||||
return models.OrderDB{
|
||||
ID: order.ID,
|
||||
PartnerID: order.PartnerID,
|
||||
CustomerID: order.CustomerID,
|
||||
CustomerName: order.CustomerName,
|
||||
PaymentType: order.PaymentType,
|
||||
PaymentProvider: order.PaymentProvider,
|
||||
CreatedBy: order.CreatedBy,
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
TableNumber: order.TableNumber,
|
||||
OrderType: order.OrderType,
|
||||
Status: order.Status,
|
||||
Amount: order.Amount,
|
||||
Total: order.Total,
|
||||
Tax: order.Tax,
|
||||
Source: order.Source,
|
||||
func (r *orderRepository) CreateOrderItems(ctx mycontext.Context, orderID int64, items []entity.OrderItem, tx *gorm.DB) error {
|
||||
// Use provided transaction or create new one
|
||||
var dbTx *gorm.DB
|
||||
if tx != nil {
|
||||
dbTx = tx
|
||||
} else {
|
||||
dbTx = r.db.Begin()
|
||||
if dbTx.Error != nil {
|
||||
return errors.Wrap(dbTx.Error, "failed to begin transaction")
|
||||
}
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
dbTx.Rollback()
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
for _, item := range items {
|
||||
itemDB := r.toOrderItemDBModel(&item)
|
||||
itemDB.OrderID = orderID
|
||||
|
||||
if err := dbTx.Create(&itemDB).Error; err != nil {
|
||||
if tx == nil {
|
||||
dbTx.Rollback()
|
||||
}
|
||||
return errors.Wrap(err, "failed to insert order item")
|
||||
}
|
||||
|
||||
item.ID = itemDB.ID
|
||||
}
|
||||
|
||||
// Only commit if we created the transaction
|
||||
if tx == nil {
|
||||
if err := dbTx.Commit().Error; err != nil {
|
||||
return errors.Wrap(err, "failed to commit transaction")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *orderRepository) toDomainProductModel(productDB *models.ProductDB) *entity.Product {
|
||||
if productDB == nil {
|
||||
return nil
|
||||
func (r *orderRepository) CreateOrderItem(ctx mycontext.Context, orderID int64, item *entity.OrderItem) error {
|
||||
itemDB := r.toOrderItemDBModel(item)
|
||||
itemDB.OrderID = orderID
|
||||
|
||||
if err := r.db.Create(&itemDB).Error; err != nil {
|
||||
return errors.Wrap(err, "failed to insert order item")
|
||||
}
|
||||
|
||||
return &entity.Product{
|
||||
ID: productDB.ID,
|
||||
Name: productDB.Name,
|
||||
Description: productDB.Description,
|
||||
Price: productDB.Price,
|
||||
CreatedAt: productDB.CreatedAt,
|
||||
UpdatedAt: productDB.UpdatedAt,
|
||||
Type: productDB.Type,
|
||||
Image: productDB.Image,
|
||||
}
|
||||
item.ID = itemDB.ID
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *orderRepository) GetListByPartnerID(ctx mycontext.Context, partnerID int64, limit, offset int, status string) ([]*entity.Order, error) {
|
||||
@@ -954,11 +931,6 @@ func (r *orderRepository) FindByIDAndPartnerID(ctx mycontext.Context, id int64,
|
||||
|
||||
order := r.toDomainOrderModel(&orderDB)
|
||||
|
||||
for _, itemDB := range orderDB.OrderItems {
|
||||
item := r.toDomainOrderItemModel(&itemDB)
|
||||
order.OrderItems = append(order.OrderItems, *item)
|
||||
}
|
||||
|
||||
return order, nil
|
||||
}
|
||||
|
||||
@@ -1025,3 +997,43 @@ func (r *orderRepository) UpdateOrderTotals(ctx mycontext.Context, orderID int64
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *orderRepository) UpdateOrderTotalsWithTx(ctx mycontext.Context, trx *gorm.DB, orderID int64, amount, tax, total float64) error {
|
||||
now := time.Now()
|
||||
|
||||
result := trx.Model(&models.OrderDB{}).
|
||||
Where("id = ?", orderID).
|
||||
Updates(map[string]interface{}{
|
||||
"amount": amount,
|
||||
"tax": tax,
|
||||
"total": total,
|
||||
"updated_at": now,
|
||||
})
|
||||
|
||||
if result.Error != nil {
|
||||
return errors.Wrap(result.Error, "failed to update order totals")
|
||||
}
|
||||
|
||||
if result.RowsAffected == 0 {
|
||||
logger.ContextLogger(ctx).Warn("no order updated")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *orderRepository) toDomainProductModel(productDB *models.ProductDB) *entity.Product {
|
||||
if productDB == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &entity.Product{
|
||||
ID: productDB.ID,
|
||||
Name: productDB.Name,
|
||||
Description: productDB.Description,
|
||||
Price: productDB.Price,
|
||||
CreatedAt: productDB.CreatedAt,
|
||||
UpdatedAt: productDB.UpdatedAt,
|
||||
Type: productDB.Type,
|
||||
Image: productDB.Image,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,193 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type QueryBuilder[T any] struct {
|
||||
db *gorm.DB
|
||||
model T
|
||||
}
|
||||
|
||||
func NewQueryBuilder[T any](db *gorm.DB) *QueryBuilder[T] {
|
||||
var model T
|
||||
return &QueryBuilder[T]{
|
||||
db: db,
|
||||
model: model,
|
||||
}
|
||||
}
|
||||
|
||||
type Filter struct {
|
||||
Field string
|
||||
Operator string // "=", "!=", ">", "<", ">=", "<=", "LIKE", "IN", "NOT IN", "IS NULL", "IS NOT NULL"
|
||||
Value interface{}
|
||||
}
|
||||
|
||||
type QueryOptions struct {
|
||||
Filters []Filter
|
||||
Limit int
|
||||
Offset int
|
||||
OrderBy []string
|
||||
Preloads []string
|
||||
GroupBy []string
|
||||
Having []Filter
|
||||
Distinct []string
|
||||
CountOnly bool
|
||||
}
|
||||
|
||||
func (qb *QueryBuilder[T]) BuildQuery(options QueryOptions) *gorm.DB {
|
||||
query := qb.db.Model(&qb.model)
|
||||
|
||||
for _, filter := range options.Filters {
|
||||
query = qb.applyFilter(query, filter)
|
||||
}
|
||||
|
||||
if len(options.Distinct) > 0 {
|
||||
for _, distinct := range options.Distinct {
|
||||
query = query.Distinct(distinct)
|
||||
}
|
||||
}
|
||||
|
||||
if len(options.GroupBy) > 0 {
|
||||
for _, groupBy := range options.GroupBy {
|
||||
query = query.Group(groupBy)
|
||||
}
|
||||
}
|
||||
|
||||
for _, having := range options.Having {
|
||||
query = qb.applyFilter(query, having)
|
||||
}
|
||||
|
||||
return query
|
||||
}
|
||||
|
||||
func (qb *QueryBuilder[T]) applyFilter(query *gorm.DB, filter Filter) *gorm.DB {
|
||||
switch filter.Operator {
|
||||
case "=", "":
|
||||
return query.Where(filter.Field+" = ?", filter.Value)
|
||||
case "!=":
|
||||
return query.Where(filter.Field+" != ?", filter.Value)
|
||||
case ">":
|
||||
return query.Where(filter.Field+" > ?", filter.Value)
|
||||
case "<":
|
||||
return query.Where(filter.Field+" < ?", filter.Value)
|
||||
case ">=":
|
||||
return query.Where(filter.Field+" >= ?", filter.Value)
|
||||
case "<=":
|
||||
return query.Where(filter.Field+" <= ?", filter.Value)
|
||||
case "LIKE":
|
||||
return query.Where(filter.Field+" LIKE ?", filter.Value)
|
||||
case "IN":
|
||||
return query.Where(filter.Field+" IN ?", filter.Value)
|
||||
case "NOT IN":
|
||||
return query.Where(filter.Field+" NOT IN ?", filter.Value)
|
||||
case "IS NULL":
|
||||
return query.Where(filter.Field + " IS NULL")
|
||||
case "IS NOT NULL":
|
||||
return query.Where(filter.Field + " IS NOT NULL")
|
||||
case "BETWEEN":
|
||||
if values, ok := filter.Value.([]interface{}); ok && len(values) == 2 {
|
||||
return query.Where(filter.Field+" BETWEEN ? AND ?", values[0], values[1])
|
||||
}
|
||||
return query
|
||||
default:
|
||||
return query.Where(filter.Field+" = ?", filter.Value)
|
||||
}
|
||||
}
|
||||
|
||||
func (qb *QueryBuilder[T]) ExecuteQuery(baseQuery *gorm.DB, options QueryOptions) *gorm.DB {
|
||||
query := baseQuery.Session(&gorm.Session{})
|
||||
|
||||
if len(options.OrderBy) > 0 {
|
||||
for _, orderBy := range options.OrderBy {
|
||||
query = query.Order(orderBy)
|
||||
}
|
||||
}
|
||||
|
||||
for _, preload := range options.Preloads {
|
||||
query = query.Preload(preload)
|
||||
}
|
||||
|
||||
if options.Limit > 0 {
|
||||
query = query.Limit(options.Limit)
|
||||
}
|
||||
|
||||
if options.Offset > 0 {
|
||||
query = query.Offset(options.Offset)
|
||||
}
|
||||
|
||||
return query
|
||||
}
|
||||
|
||||
func (qb *QueryBuilder[T]) Count(baseQuery *gorm.DB) (int64, error) {
|
||||
var count int64
|
||||
if err := baseQuery.Count(&count).Error; err != nil {
|
||||
return 0, errors.Wrap(err, "failed to count records")
|
||||
}
|
||||
return count, nil
|
||||
}
|
||||
|
||||
func (qb *QueryBuilder[T]) Find(query *gorm.DB) ([]T, error) {
|
||||
var results []T
|
||||
if err := query.Find(&results).Error; err != nil {
|
||||
return nil, errors.Wrap(err, "failed to find records")
|
||||
}
|
||||
return results, nil
|
||||
}
|
||||
|
||||
func (qb *QueryBuilder[T]) First(query *gorm.DB) (*T, error) {
|
||||
var result T
|
||||
if err := query.First(&result).Error; err != nil {
|
||||
return nil, errors.Wrap(err, "failed to find record")
|
||||
}
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
func Equal(field string, value interface{}) Filter {
|
||||
return Filter{Field: field, Operator: "=", Value: value}
|
||||
}
|
||||
|
||||
func NotEqual(field string, value interface{}) Filter {
|
||||
return Filter{Field: field, Operator: "!=", Value: value}
|
||||
}
|
||||
|
||||
func GreaterThan(field string, value interface{}) Filter {
|
||||
return Filter{Field: field, Operator: ">", Value: value}
|
||||
}
|
||||
|
||||
func LessThan(field string, value interface{}) Filter {
|
||||
return Filter{Field: field, Operator: "<", Value: value}
|
||||
}
|
||||
|
||||
func GreaterEqual(field string, value interface{}) Filter {
|
||||
return Filter{Field: field, Operator: ">=", Value: value}
|
||||
}
|
||||
|
||||
func LessEqual(field string, value interface{}) Filter {
|
||||
return Filter{Field: field, Operator: "<=", Value: value}
|
||||
}
|
||||
|
||||
func Like(field string, value string) Filter {
|
||||
return Filter{Field: field, Operator: "LIKE", Value: value}
|
||||
}
|
||||
|
||||
func In(field string, values interface{}) Filter {
|
||||
return Filter{Field: field, Operator: "IN", Value: values}
|
||||
}
|
||||
|
||||
func NotIn(field string, values interface{}) Filter {
|
||||
return Filter{Field: field, Operator: "NOT IN", Value: values}
|
||||
}
|
||||
|
||||
func IsNull(field string) Filter {
|
||||
return Filter{Field: field, Operator: "IS NULL"}
|
||||
}
|
||||
|
||||
func IsNotNull(field string) Filter {
|
||||
return Filter{Field: field, Operator: "IS NOT NULL"}
|
||||
}
|
||||
|
||||
func Between(field string, start, end interface{}) Filter {
|
||||
return Filter{Field: field, Operator: "BETWEEN", Value: []interface{}{start, end}}
|
||||
}
|
||||
@@ -16,7 +16,6 @@ import (
|
||||
"enaklo-pos-be/internal/repository/products"
|
||||
"enaklo-pos-be/internal/repository/sites"
|
||||
transactions "enaklo-pos-be/internal/repository/transaction"
|
||||
"enaklo-pos-be/internal/repository/trx"
|
||||
"enaklo-pos-be/internal/repository/users"
|
||||
repository "enaklo-pos-be/internal/repository/wallet"
|
||||
|
||||
@@ -38,7 +37,7 @@ type RepoManagerImpl struct {
|
||||
OSS OSSRepository
|
||||
Partner PartnerRepository
|
||||
Site SiteRepository
|
||||
Trx TransactionManager
|
||||
Trx Trx
|
||||
Wallet WalletRepository
|
||||
Midtrans Midtrans
|
||||
Payment Payment
|
||||
@@ -70,7 +69,7 @@ func NewRepoManagerImpl(db *gorm.DB, cfg *config.Config) *RepoManagerImpl {
|
||||
OSS: oss.NewOssRepositoryImpl(cfg.OSSConfig),
|
||||
Partner: partners.NewPartnerRepository(db),
|
||||
Site: sites.NewSiteRepository(db),
|
||||
Trx: trx.NewGormTransactionManager(db),
|
||||
Trx: NewTransactionManager(db),
|
||||
Wallet: repository.NewWalletRepository(db),
|
||||
Midtrans: mdtrns.New(&cfg.Midtrans),
|
||||
Payment: payment.NewPaymentRepository(db),
|
||||
@@ -188,12 +187,6 @@ type SiteRepository interface {
|
||||
SearchSites(ctx context.Context, search *entity.DiscoverySearch) ([]entity.SiteProductInfo, int64, error)
|
||||
}
|
||||
|
||||
type TransactionManager interface {
|
||||
Begin(ctx context.Context, opts ...*sql.TxOptions) (*gorm.DB, error)
|
||||
Commit(session *gorm.DB) *gorm.DB
|
||||
Rollback(session *gorm.DB) *gorm.DB
|
||||
}
|
||||
|
||||
type WalletRepository interface {
|
||||
Create(ctx context.Context, tx *gorm.DB, wallet *entity.Wallet) (*entity.Wallet, error)
|
||||
Update(ctx context.Context, db *gorm.DB, wallet *entity.Wallet) (*entity.Wallet, error)
|
||||
@@ -244,3 +237,9 @@ type PaymentGateway interface {
|
||||
CreateQRISPayment(request entity.PaymentRequest) (*entity.PaymentResponse, error)
|
||||
CreatePaymentVA(request entity.PaymentRequest) (*entity.PaymentResponse, error)
|
||||
}
|
||||
|
||||
type Trx interface {
|
||||
Begin(ctx context.Context, opts ...*sql.TxOptions) (*gorm.DB, error)
|
||||
Commit(session *gorm.DB) *gorm.DB
|
||||
Rollback(session *gorm.DB) *gorm.DB
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type TransactionManager struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
func NewTransactionManager(db *gorm.DB) *TransactionManager {
|
||||
return &TransactionManager{db: db}
|
||||
}
|
||||
|
||||
func (tm *TransactionManager) Begin(ctx context.Context, opts ...*sql.TxOptions) (*gorm.DB, error) {
|
||||
tx := tm.db.Begin(opts...)
|
||||
if tx.Error != nil {
|
||||
return nil, tx.Error
|
||||
}
|
||||
return tx, nil
|
||||
}
|
||||
|
||||
func (tm *TransactionManager) Commit(session *gorm.DB) *gorm.DB {
|
||||
return session.Commit()
|
||||
}
|
||||
|
||||
func (tm *TransactionManager) Rollback(session *gorm.DB) *gorm.DB {
|
||||
return session.Rollback()
|
||||
}
|
||||
Reference in New Issue
Block a user