304 lines
9.5 KiB
Go
304 lines
9.5 KiB
Go
|
|
package orders
|
||
|
|
|
||
|
|
import (
|
||
|
|
"context"
|
||
|
|
"fmt"
|
||
|
|
"furtuna-be/internal/common/logger"
|
||
|
|
"furtuna-be/internal/entity"
|
||
|
|
|
||
|
|
"go.uber.org/zap"
|
||
|
|
"gorm.io/gorm"
|
||
|
|
)
|
||
|
|
|
||
|
|
type OrderRepository struct {
|
||
|
|
db *gorm.DB
|
||
|
|
}
|
||
|
|
|
||
|
|
func NewOrderRepository(db *gorm.DB) *OrderRepository {
|
||
|
|
return &OrderRepository{
|
||
|
|
db: db,
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func (o *OrderRepository) CreateOrder(ctx context.Context, order *entity.OrderDB) (*entity.OrderDB, error) {
|
||
|
|
tx := o.db.Begin()
|
||
|
|
|
||
|
|
if err := tx.Select("branch_id", "status", "customer_name", "customer_phone", "pax", "amount", "created_by").Create(order).Error; err != nil {
|
||
|
|
tx.Rollback()
|
||
|
|
logError(ctx, "creating order", err)
|
||
|
|
return nil, err
|
||
|
|
}
|
||
|
|
|
||
|
|
for i, orditem := range order.OrderItem {
|
||
|
|
orderItem := orditem.ToOrderItemDB()
|
||
|
|
orderItem.OrderID = order.ID
|
||
|
|
|
||
|
|
err := tx.Select("order_id", "item_id", "item_type", "price", "qty", "created_by").Create(orderItem).Error
|
||
|
|
if err != nil {
|
||
|
|
logger.ContextLogger(ctx).Error("error when create order item", zap.Error(err))
|
||
|
|
return nil, err
|
||
|
|
}
|
||
|
|
|
||
|
|
order.OrderItem[i] = *orderItem.ToOrderItem()
|
||
|
|
}
|
||
|
|
|
||
|
|
//insert transaction
|
||
|
|
transaction := order.Transaction.ToTransactionDB()
|
||
|
|
transaction.OrderID = order.ID
|
||
|
|
|
||
|
|
if err := tx.Select("branch_id", "status", "amount", "order_id", "payment_method", "customer_name", "customer_phone", "created_by").Create(transaction).Error; err != nil {
|
||
|
|
tx.Rollback()
|
||
|
|
logError(ctx, "creating transaction", err)
|
||
|
|
return nil, err
|
||
|
|
}
|
||
|
|
|
||
|
|
if err := tx.Commit().Error; err != nil {
|
||
|
|
tx.Rollback()
|
||
|
|
logError(ctx, "committing transaction", err)
|
||
|
|
return nil, err
|
||
|
|
}
|
||
|
|
|
||
|
|
return order, nil
|
||
|
|
}
|
||
|
|
|
||
|
|
func (b *OrderRepository) UpdateOrder(ctx context.Context, order *entity.OrderDB) (*entity.OrderDB, error) {
|
||
|
|
|
||
|
|
if err := b.db.Select("status", "updated_at", "updated_by").Save(order).Error; err != nil {
|
||
|
|
logError(ctx, "update order", err)
|
||
|
|
return nil, err
|
||
|
|
}
|
||
|
|
|
||
|
|
return order, nil
|
||
|
|
}
|
||
|
|
|
||
|
|
func (b *OrderRepository) GetAllOrders(ctx context.Context, req entity.OrderSearch) (entity.OrderList, int, error) {
|
||
|
|
var orders []*entity.OrderDB
|
||
|
|
var total int64
|
||
|
|
|
||
|
|
query := b.db.Table("orders").
|
||
|
|
Select("orders.id, orders.branch_id, b.name as branch_name, orders.status, orders.amount, orders.created_at, orders.updated_at, oi.order_item_id, oi.order_id, oi.item_id, oi.item_type, COALESCE(p.name, s.name, '') as item_name, oi.price, oi.qty, oi.created_at, oi.updated_at, COALESCE(t.payment_method, ''), COALESCE(orders.customer_name, ''), COALESCE(orders.customer_phone, ''), COALESCE(orders.pax, 0)").
|
||
|
|
Joins("LEFT JOIN order_items oi ON orders.id = oi.order_id").
|
||
|
|
Joins("LEFT JOIN transactions t ON orders.id = t.order_id").
|
||
|
|
Joins("LEFT JOIN products p ON oi.item_id = p.id AND oi.item_type ='PRODUCT' ").
|
||
|
|
Joins("LEFT JOIN studios s ON oi.item_id = s.id AND oi.item_type ='STUDIO' ").
|
||
|
|
Joins("LEFT JOIN branches b ON orders.branch_id = b.id")
|
||
|
|
|
||
|
|
if req.Search != "" {
|
||
|
|
query = query.Where("b.name ILIKE ? or orders.status ILIKE ? or oi.item_type ILIKE ? or p.name ILIKE ? or orders.customer_name ILIKE ? ", "%"+req.Search+"%", "%"+req.Search+"%", "%"+req.Search+"%", "%"+req.Search+"%", "%"+req.Search+"%")
|
||
|
|
}
|
||
|
|
|
||
|
|
if req.Status != "" {
|
||
|
|
query = query.Where("orders.status = ?", req.Status)
|
||
|
|
}
|
||
|
|
|
||
|
|
if req.BranchID > 0 {
|
||
|
|
query = query.Where("orders.branch_id = ?", req.BranchID)
|
||
|
|
}
|
||
|
|
|
||
|
|
if req.StatusActive.IsActive() {
|
||
|
|
query = query.Joins("INNER JOIN (SELECT o.id, oi.qty, o.created_at FROM orders o INNER JOIN order_items oi ON o.id = oi.order_id AND oi.item_type = 'STUDIO' where o.status != 'CANCEL' and CURRENT_TIMESTAMP > o.created_at AND CURRENT_TIMESTAMP < (o.created_at + (oi.qty || ' hours')::interval)) order_active on order_active.id=orders.id")
|
||
|
|
}
|
||
|
|
|
||
|
|
if req.Limit > 0 {
|
||
|
|
query = query.Limit(req.Limit)
|
||
|
|
}
|
||
|
|
|
||
|
|
if req.Offset > 0 {
|
||
|
|
query = query.Offset(req.Offset)
|
||
|
|
}
|
||
|
|
|
||
|
|
query.Order("orders.created_at DESC")
|
||
|
|
|
||
|
|
rows, err := query.Rows()
|
||
|
|
if err != nil {
|
||
|
|
return nil, 0, err
|
||
|
|
}
|
||
|
|
|
||
|
|
defer rows.Close()
|
||
|
|
|
||
|
|
ordersMap := make(map[int64]*entity.OrderDB) // Map to store orders by ID
|
||
|
|
for rows.Next() {
|
||
|
|
var ordr entity.OrderDB
|
||
|
|
var oi entity.OrderItem
|
||
|
|
|
||
|
|
err := rows.Scan(&ordr.ID, &ordr.BranchID, &ordr.BranchName, &ordr.Status, &ordr.Amount, &ordr.CreatedAt, &ordr.UpdatedAt,
|
||
|
|
&oi.OrderItemID, &oi.OrderID, &oi.ItemID, &oi.ItemType, &oi.ItemName, &oi.Price, &oi.Qty, &oi.CreatedAt, &oi.UpdatedAt,
|
||
|
|
&ordr.Transaction.PaymentMethod, &ordr.CustomerName, &ordr.CustomerPhone, &ordr.Pax)
|
||
|
|
if err != nil {
|
||
|
|
logger.ContextLogger(ctx).Error("error scanning rows", zap.Error(err))
|
||
|
|
return nil, 0, err
|
||
|
|
}
|
||
|
|
|
||
|
|
if order, ok := ordersMap[ordr.ID]; ok {
|
||
|
|
// Order already exists in map, append OrderItem to existing order
|
||
|
|
order.OrderItem = append(order.OrderItem, oi)
|
||
|
|
} else {
|
||
|
|
// Order doesn't exist in map, create a new OrderDB
|
||
|
|
newOrder := ordr
|
||
|
|
newOrder.OrderItem = []entity.OrderItem{oi}
|
||
|
|
ordersMap[ordr.ID] = &newOrder
|
||
|
|
|
||
|
|
orders = append(orders, &ordr)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// assign value order item
|
||
|
|
for _, v := range orders {
|
||
|
|
v.OrderItem = ordersMap[v.ID].OrderItem
|
||
|
|
}
|
||
|
|
|
||
|
|
//reset limit for count total data
|
||
|
|
query = query.Offset(-1).Limit(-1)
|
||
|
|
|
||
|
|
if err := query.Count(&total).Error; err != nil {
|
||
|
|
logger.ContextLogger(ctx).Error("error when count orders", zap.Error(err))
|
||
|
|
return nil, 0, err
|
||
|
|
}
|
||
|
|
|
||
|
|
return orders, int(total), nil
|
||
|
|
}
|
||
|
|
|
||
|
|
func (b *OrderRepository) GetOrderByID(ctx context.Context, id int64) (*entity.OrderDB, error) {
|
||
|
|
var orders *entity.OrderDB
|
||
|
|
|
||
|
|
query := b.db.Table("orders").
|
||
|
|
Select("orders.id, orders.branch_id, b.name as branch_name, orders.status, orders.amount, orders.created_at, orders.updated_at, oi.order_item_id, oi.order_id, oi.item_id, oi.item_type, COALESCE(p.name, s.name, '') as item_name, oi.price, oi.qty, oi.created_at, oi.updated_at, t.payment_method, orders.customer_name, orders.customer_phone, orders.pax").
|
||
|
|
Joins("LEFT JOIN order_items oi ON orders.id = oi.order_id").
|
||
|
|
Joins("LEFT JOIN transactions t ON orders.id = t.order_id").
|
||
|
|
Joins("LEFT JOIN products p ON oi.item_id = p.id AND oi.item_type ='PRODUCT' ").
|
||
|
|
Joins("LEFT JOIN studios s ON oi.item_id = s.id AND oi.item_type ='STUDIO' ").
|
||
|
|
Joins("LEFT JOIN branches b ON orders.branch_id = b.id").
|
||
|
|
Where("orders.id = ?", id)
|
||
|
|
|
||
|
|
rows, err := query.Rows()
|
||
|
|
if err != nil {
|
||
|
|
return nil, err
|
||
|
|
}
|
||
|
|
|
||
|
|
defer rows.Close()
|
||
|
|
|
||
|
|
var ordr entity.OrderDB // Map to store orders by ID
|
||
|
|
for rows.Next() {
|
||
|
|
var oi entity.OrderItem
|
||
|
|
|
||
|
|
err := rows.Scan(&ordr.ID, &ordr.BranchID, &ordr.BranchName, &ordr.Status, &ordr.Amount, &ordr.CreatedAt, &ordr.UpdatedAt,
|
||
|
|
&oi.OrderItemID, &oi.OrderID, &oi.ItemID, &oi.ItemType, &oi.ItemName, &oi.Price, &oi.Qty, &oi.CreatedAt, &oi.UpdatedAt,
|
||
|
|
&ordr.Transaction.PaymentMethod, &ordr.CustomerName, &ordr.CustomerPhone, &ordr.Pax)
|
||
|
|
if err != nil {
|
||
|
|
logger.ContextLogger(ctx).Error("error scanning rows", zap.Error(err))
|
||
|
|
return nil, err
|
||
|
|
}
|
||
|
|
|
||
|
|
ordr.OrderItem = append(ordr.OrderItem, oi)
|
||
|
|
}
|
||
|
|
|
||
|
|
orders = &ordr
|
||
|
|
|
||
|
|
if orders == nil {
|
||
|
|
return nil, fmt.Errorf("order not found")
|
||
|
|
}
|
||
|
|
|
||
|
|
return orders, nil
|
||
|
|
}
|
||
|
|
|
||
|
|
func (b *OrderRepository) GetTotalRevenue(ctx context.Context, req entity.OrderTotalRevenueSearch) (float64, int64, error) {
|
||
|
|
var (
|
||
|
|
totalmonthlyRevenue float64
|
||
|
|
totalmonthlyTrans int64
|
||
|
|
)
|
||
|
|
|
||
|
|
query := b.db.Table("orders").
|
||
|
|
Select("COALESCE(sum(amount),0) as total_amount, COALESCE(count(id),0) as total_transaction").
|
||
|
|
Where("status in ('NEW','PAID') ")
|
||
|
|
|
||
|
|
if req.BranchID > 0 {
|
||
|
|
query = query.Where("branch_id = ?", req.BranchID)
|
||
|
|
}
|
||
|
|
|
||
|
|
if req.Month > 0 {
|
||
|
|
query = query.Where("EXTRACT(MONTH FROM created_at) = ? ", req.Month)
|
||
|
|
}
|
||
|
|
|
||
|
|
if req.Year > 0 {
|
||
|
|
query = query.Where("EXTRACT(YEAR FROM created_at) = ? ", req.Year)
|
||
|
|
}
|
||
|
|
|
||
|
|
if req.DateStart != nil {
|
||
|
|
query = query.Where("created_at >= ? ", req.DateStart)
|
||
|
|
}
|
||
|
|
|
||
|
|
if req.DateEnd != nil {
|
||
|
|
query = query.Where("created_at <= ? ", req.DateEnd)
|
||
|
|
}
|
||
|
|
|
||
|
|
rows, err := query.Rows()
|
||
|
|
if err != nil {
|
||
|
|
return totalmonthlyRevenue, totalmonthlyTrans, err
|
||
|
|
}
|
||
|
|
defer rows.Close()
|
||
|
|
|
||
|
|
for rows.Next() {
|
||
|
|
err := rows.Scan(&totalmonthlyRevenue, &totalmonthlyTrans)
|
||
|
|
if err != nil {
|
||
|
|
logger.ContextLogger(ctx).Error("error scanning rows", zap.Error(err))
|
||
|
|
return totalmonthlyRevenue, totalmonthlyTrans, err
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return totalmonthlyRevenue, totalmonthlyTrans, nil
|
||
|
|
}
|
||
|
|
|
||
|
|
func (b *OrderRepository) GetYearlyRevenue(ctx context.Context, year int) (entity.OrderYearlyRevenueList, error) {
|
||
|
|
var result entity.OrderYearlyRevenueList
|
||
|
|
|
||
|
|
err := b.db.Raw(` SELECT
|
||
|
|
oi.item_type,
|
||
|
|
EXTRACT(MONTH FROM o.created_at) AS month_number,
|
||
|
|
SUM(oi.price ) AS total_amount
|
||
|
|
FROM
|
||
|
|
orders o
|
||
|
|
JOIN
|
||
|
|
order_items oi ON o.id = oi.order_id
|
||
|
|
WHERE
|
||
|
|
EXTRACT(YEAR FROM o.created_at) = ?
|
||
|
|
AND o.status IN ('NEW', 'PAID')
|
||
|
|
GROUP BY
|
||
|
|
EXTRACT(MONTH FROM o.created_at),
|
||
|
|
oi.item_type
|
||
|
|
ORDER BY
|
||
|
|
month_number,
|
||
|
|
oi.item_type`, year).Scan(&result).Error
|
||
|
|
|
||
|
|
return result, err
|
||
|
|
}
|
||
|
|
|
||
|
|
func (b *OrderRepository) GetBranchRevenue(ctx context.Context, req entity.OrderBranchRevenueSearch) (entity.OrderBranchRevenueList, error) {
|
||
|
|
var result entity.OrderBranchRevenueList
|
||
|
|
|
||
|
|
query := b.db.Table("orders o").
|
||
|
|
Joins("JOIN branches ON branches.id = o.branch_id").
|
||
|
|
Select("o.branch_id, branches.name, branches.location, SUM(o.amount) as total_amount, COUNT(o.id) as total_trans").
|
||
|
|
Where("o.status IN ('NEW', 'PAID')").
|
||
|
|
Group("o.branch_id, branches.name, branches.location").
|
||
|
|
Order("total_amount DESC, total_trans DESC")
|
||
|
|
|
||
|
|
if req.DateStart != nil {
|
||
|
|
query = query.Where("o.created_at >= ? ", req.DateStart)
|
||
|
|
}
|
||
|
|
|
||
|
|
if req.DateEnd != nil {
|
||
|
|
query = query.Where("o.created_at <= ? ", req.DateEnd)
|
||
|
|
}
|
||
|
|
|
||
|
|
if err := query.Find(&result).Error; err != nil {
|
||
|
|
logger.ContextLogger(ctx).Error("error when GetBranchRevenue", zap.Error(err))
|
||
|
|
return nil, err
|
||
|
|
}
|
||
|
|
|
||
|
|
return result, nil
|
||
|
|
}
|
||
|
|
|
||
|
|
func logError(ctx context.Context, s string, err error) {
|
||
|
|
panic("unimplemented")
|
||
|
|
}
|