2023-10-08 15:59:42 +07:00
package orders
import (
"context"
"furtuna-be/internal/common/logger"
2024-07-27 16:47:33 +07:00
"furtuna-be/internal/common/mycontext"
2023-10-08 15:59:42 +07:00
"furtuna-be/internal/entity"
2024-07-26 11:37:22 +07:00
"strings"
2024-07-27 16:47:33 +07:00
"time"
2024-07-26 11:37:22 +07:00
2023-10-08 15:59:42 +07:00
"go.uber.org/zap"
"gorm.io/gorm"
)
type OrderRepository struct {
db * gorm . DB
}
func NewOrderRepository ( db * gorm . DB ) * OrderRepository {
return & OrderRepository {
db : db ,
}
}
2024-06-04 02:59:31 +07:00
func ( r * OrderRepository ) Create ( ctx context . Context , order * entity . Order ) ( * entity . Order , error ) {
err := r . db . WithContext ( ctx ) . Create ( order ) . Error
if err != nil {
logger . ContextLogger ( ctx ) . Error ( "error when creating order" , zap . Error ( err ) )
2023-10-08 15:59:42 +07:00
return nil , err
}
2024-06-05 00:24:53 +07:00
return r . FindByID ( ctx , order . ID )
2023-10-08 15:59:42 +07:00
}
2024-06-04 02:59:31 +07:00
func ( r * OrderRepository ) UpdateStatus ( ctx context . Context , orderID int64 , status string ) ( * entity . Order , error ) {
order := new ( entity . Order )
if err := r . db . WithContext ( ctx ) . First ( order , orderID ) . Error ; err != nil {
logger . ContextLogger ( ctx ) . Error ( "error when finding order" , zap . Error ( err ) )
2023-10-08 15:59:42 +07:00
return nil , err
}
2024-06-04 02:59:31 +07:00
order . Status = status
if err := r . db . WithContext ( ctx ) . Save ( order ) . Error ; err != nil {
logger . ContextLogger ( ctx ) . Error ( "error when updating order status" , zap . Error ( err ) )
2023-10-08 15:59:42 +07:00
return nil , err
}
2024-06-04 02:59:31 +07:00
return order , nil
2023-10-08 15:59:42 +07:00
}
2024-06-04 02:59:31 +07:00
func ( r * OrderRepository ) FindByID ( ctx context . Context , id int64 ) ( * entity . Order , error ) {
var order entity . Order
2024-06-05 00:24:53 +07:00
2024-08-04 01:14:59 +07:00
err := r . db . WithContext ( ctx ) .
Preload ( "OrderItems" , func ( db * gorm . DB ) * gorm . DB {
return db . Preload ( "Product" )
} ) .
2024-08-21 22:27:05 +07:00
Preload ( "Site" ) .
2024-08-04 01:14:59 +07:00
Preload ( "User" ) .
Preload ( "Payment" ) .
First ( & order , id ) . Error
2024-06-05 00:24:53 +07:00
if err != nil {
2024-06-04 02:59:31 +07:00
logger . ContextLogger ( ctx ) . Error ( "error when finding order by ID" , zap . Error ( err ) )
return nil , err
2023-10-08 15:59:42 +07:00
}
2024-06-05 00:24:53 +07:00
2024-06-04 02:59:31 +07:00
return & order , nil
2023-10-08 15:59:42 +07:00
}
2024-08-21 15:48:50 +07:00
func ( r * OrderRepository ) FindPrintDetailByID ( ctx context . Context , id int64 ) ( * entity . OrderPrintDetail , error ) {
var printDetail entity . OrderPrintDetail
err := r . db . WithContext ( ctx ) .
Table ( "orders" ) .
2024-08-21 15:51:40 +07:00
Select ( "orders.id, partners.name as partner_name, partners.logo as logo, orders.ref_id as order_id, " +
2024-08-21 15:48:50 +07:00
"orders.visit_date, orders.payment_type, orders.source, " +
"orders.ticket_status, orders.total, orders.fee" ) .
Joins ( "JOIN partners ON partners.id = orders.partner_id" ) .
Where ( "orders.id = ?" , id ) .
Scan ( & printDetail ) . Error
if err == nil {
err = r . db . WithContext ( ctx ) . Where ( "order_id = ?" , id ) . Preload ( "Product" ) . Find ( & printDetail . OrderItems ) . Error
}
if err != nil {
logger . ContextLogger ( ctx ) . Error ( "error when finding print detail by ID" , zap . Error ( err ) )
return nil , err
}
return & printDetail , nil
}
2024-08-13 23:09:05 +07:00
func ( r * OrderRepository ) FindByQRCode ( ctx context . Context , refID string ) ( * entity . Order , error ) {
var order entity . Order
err := r . db . WithContext ( ctx ) .
Preload ( "OrderItems" , func ( db * gorm . DB ) * gorm . DB {
return db . Preload ( "Product" )
} ) .
Preload ( "User" ) .
Preload ( "Payment" ) .
Where ( "ref_id = ?" , refID ) .
First ( & order ) . Error
if err != nil {
logger . ContextLogger ( ctx ) . Error ( "error when finding order by refID" , zap . Error ( err ) )
return nil , err
}
return & order , nil
}
2024-06-05 00:24:53 +07:00
func ( r * OrderRepository ) SetOrderStatus ( ctx context . Context , db * gorm . DB , orderID int64 , status string ) error {
var order entity . Order
if err := db . WithContext ( ctx ) . Preload ( "OrderItems" ) . First ( & order , orderID ) . Error ; err != nil {
logger . ContextLogger ( ctx ) . Error ( "error when finding order by ID" , zap . Error ( err ) )
return err
}
order . Status = status
if err := db . WithContext ( ctx ) . Save ( & order ) . Error ; err != nil {
logger . ContextLogger ( ctx ) . Error ( "error when updating order status" , zap . Error ( err ) )
return err
}
return nil
}
2024-06-04 02:59:31 +07:00
func ( r * OrderRepository ) Update ( ctx context . Context , order * entity . Order ) ( * entity . Order , error ) {
2024-08-05 23:58:15 +07:00
if err := r . db . WithContext ( ctx ) . Model ( & entity . Order { } ) . Where ( "id = ?" , order . ID ) . Updates ( order ) . Error ; err != nil {
2024-06-04 02:59:31 +07:00
logger . ContextLogger ( ctx ) . Error ( "error when updating order" , zap . Error ( err ) )
2023-10-08 15:59:42 +07:00
return nil , err
}
2024-06-04 02:59:31 +07:00
return order , nil
2023-10-08 15:59:42 +07:00
}
2024-07-26 11:37:22 +07:00
2024-07-27 16:47:33 +07:00
func ( b * OrderRepository ) GetAllHystoryOrders ( ctx context . Context , req entity . OrderSearch ) ( entity . HistoryOrderList , int , error ) {
2024-07-26 11:37:22 +07:00
var orders [ ] * entity . HistoryOrderDB
var total int64
query := b . db . Table ( "orders" ) .
2024-08-10 23:21:01 +07:00
Select ( "orders.id as id, users.name as employee, sites.name as site, orders.created_at as timestamp, orders.created_at as booking_time, STRING_AGG(ticket_summary.name || ' x' || ticket_summary.total_qty, ', ') AS tickets, orders.payment_type as payment_type, orders.status as status, orders.amount as amount, orders.visit_date as visit_date, orders.ticket_status as ticket_status, orders.source as source" ) .
2024-07-26 11:37:22 +07:00
Joins ( "left join (SELECT items.order_id, products.name, SUM(items.qty) AS total_qty FROM order_items items LEFT JOIN products ON items.item_id = products.id GROUP BY items.order_id, products.name) AS ticket_summary ON orders.id = ticket_summary.order_id" ) .
Joins ( "left join users on orders.created_by = users.id" ) .
2024-08-15 22:45:07 +07:00
Joins ( "left join sites on orders.site_id = sites.id" ) .
Where ( "orders.payment_type != ?" , "NEW" )
2024-07-30 22:02:36 +07:00
2024-08-13 23:09:05 +07:00
if req . PaymentType != "" {
2024-07-30 22:02:36 +07:00
query = query . Where ( "orders.payment_type = ?" , req . PaymentType )
}
2024-08-04 01:14:59 +07:00
if req . CreatedBy != 0 {
query = query . Where ( "orders.created_by = ?" , req . CreatedBy )
}
2024-07-30 22:02:36 +07:00
if req . Status != "" {
query = query . Where ( "orders.status = ?" , req . Status )
}
2024-07-26 13:39:08 +07:00
2024-08-04 01:14:59 +07:00
if ! req . IsAdmin && ! req . IsCustomer {
2024-07-26 22:32:24 +07:00
query = query . Where ( "orders.partner_id = ?" , req . PartnerID )
2024-07-26 13:39:08 +07:00
}
2024-07-30 22:02:36 +07:00
if req . StartDate != "" && req . EndDate != "" {
// Assuming req.Date and req.EndDate are in string format "YYYY-MM-DD"
2024-08-15 22:17:28 +07:00
startDate := req . StartDate + " 00:00:00"
endDate := req . EndDate + " 23:59:59"
2024-07-30 22:02:36 +07:00
query = query . Where ( "orders.created_at BETWEEN ? AND ?" , startDate , endDate )
}
if req . SiteID != nil {
query = query . Where ( "orders.site_id = ?" , req . SiteID )
}
2024-08-10 23:21:01 +07:00
if req . Source != "" {
query = query . Where ( "orders.source = ?" , req . Source )
}
2024-07-26 13:39:08 +07:00
query = query . Group ( "orders.id, users.name, sites.name, orders.created_at, orders.payment_type, orders.status" )
2024-07-26 11:37:22 +07:00
2024-07-30 22:02:36 +07:00
query = query . Order ( "orders.created_at DESC" )
2024-07-26 11:37:22 +07:00
if err := query . Count ( & total ) . Error ; err != nil {
logger . ContextLogger ( ctx ) . Error ( "error when count history orders" , zap . Error ( err ) )
return nil , 0 , err
}
2024-07-26 22:47:37 +07:00
page := ( req . Offset - 1 ) * req . Limit
2024-07-26 11:37:22 +07:00
if req . Offset > 0 {
2024-07-26 22:47:37 +07:00
query = query . Offset ( page )
2024-07-26 11:37:22 +07:00
}
if req . Limit > 0 {
query = query . Limit ( req . Limit )
}
2024-08-15 22:17:28 +07:00
if err := query . Debug ( ) . Scan ( & orders ) . Error ; err != nil {
2024-07-26 11:37:22 +07:00
logger . ContextLogger ( ctx ) . Error ( "error when get all history orders" , zap . Error ( err ) )
return nil , 0 , err
}
for i , order := range orders {
if order . RawTickets != "" {
orders [ i ] . Tickets = strings . Split ( order . RawTickets , ", " )
}
}
return orders , int ( total ) , nil
}
2024-07-27 16:47:33 +07:00
func ( r * OrderRepository ) CountSoldOfTicket ( ctx mycontext . Context , req entity . OrderSearch ) ( * entity . TicketSoldDB , error ) {
today := time . Now ( ) . Format ( "2006-01-02" )
ticketCount := new ( entity . TicketSoldDB )
query := r . db . Table ( "orders" ) .
Select ( "sum(items.qty) as count" ) .
Joins ( "left join order_items items on orders.id = items.order_id" ) .
Where ( "orders.status = ?" , "PAID" ) .
Where ( "orders.created_at = ?" , today )
if ! req . IsAdmin {
query = query . Where ( "orders.partner_id = ?" , req . PartnerID )
}
if err := query . Scan ( & ticketCount ) . Error ; err != nil {
logger . ContextLogger ( ctx ) . Error ( "error when get count ticket" , zap . Error ( err ) )
return nil , err
}
return ticketCount , nil
}
func ( r * OrderRepository ) SumAmount ( ctx mycontext . Context , req entity . OrderSearch ) ( * entity . OrderDB , error ) {
amount := new ( entity . OrderDB )
today := time . Now ( ) . Format ( "2006-01-02" )
query := r . db . Table ( "orders" ) .
Select ( "sum(amount) as amount" ) .
Where ( "payment_type = ?" , req . PaymentType ) .
Where ( "date(created_at) = ?" , today ) .
Where ( "status = ?" , "PAID" )
2024-08-02 18:35:42 +07:00
if req . PartnerID != nil {
2024-07-27 16:47:33 +07:00
query = query . Where ( "orders.partner_id = ?" , req . PartnerID )
}
2024-08-02 18:35:42 +07:00
if req . SiteID != nil {
query = query . Where ( "orders.site_id = ?" , req . SiteID )
}
2024-07-27 16:47:33 +07:00
if err := query . Scan ( & amount ) . Error ; err != nil {
logger . ContextLogger ( ctx ) . Error ( "error when get cash amount" , zap . Error ( err ) )
return nil , err
}
return amount , nil
}
2024-08-02 02:27:57 +07:00
func ( r * OrderRepository ) GetDailySalesMetrics ( ctx context . Context , req entity . OrderSearch ) ( [ ] entity . ProductDailySales , error ) {
var sales [ ] entity . ProductDailySales
2024-08-02 14:41:41 +07:00
var dateTrunc , periodFilter string
now := time . Now ( )
switch req . Period {
case "1d" :
dateTrunc = "hour"
periodFilter = now . Add ( - 24 * time . Hour ) . Format ( "2006-01-02 15:04:05" )
case "7d" :
dateTrunc = "day"
periodFilter = now . Add ( - 7 * 24 * time . Hour ) . Format ( "2006-01-02 15:04:05" )
case "1m" :
dateTrunc = "day"
periodFilter = now . AddDate ( 0 , - 1 , 0 ) . Format ( "2006-01-02 15:04:05" )
case "1y" :
dateTrunc = "week"
periodFilter = now . AddDate ( - 1 , 0 , 0 ) . Format ( "2006-01-02 15:04:05" )
default :
dateTrunc = "day"
periodFilter = now . AddDate ( 0 , - 1 , 0 ) . Format ( "2006-01-02 15:04:05" ) // Default to last month
}
2024-08-02 02:27:57 +07:00
// Build the query with GORM
query := r . db . WithContext ( ctx ) .
Table ( "orders o" ) .
2024-08-02 15:16:28 +07:00
Select ( ` DATE_TRUNC(?, o.created_at) AS day, s.id AS site_id, s.name AS site_name, o.payment_type, SUM(oi.qty * oi.price) AS total ` , dateTrunc ) .
2024-08-02 14:41:41 +07:00
Joins ( "JOIN order_items oi ON o.id = oi.order_id" ) .
Joins ( "JOIN sites s ON o.site_id = s.id" ) .
2024-08-02 02:27:57 +07:00
Where ( "o.status = ?" , "PAID" ) .
2024-08-02 14:41:41 +07:00
Where ( "o.created_at >= ?" , periodFilter )
2024-08-02 02:27:57 +07:00
if req . PartnerID != nil {
query = query . Where ( "o.partner_id = ?" , * req . PartnerID )
}
2024-08-02 14:41:41 +07:00
2024-08-02 02:27:57 +07:00
if req . SiteID != nil {
query = query . Where ( "o.site_id = ?" , * req . SiteID )
}
2024-08-02 14:41:41 +07:00
query = query . Group ( "day, s.id, s.name, o.payment_type" ) .
Order ( "day" )
2024-08-02 02:27:57 +07:00
if err := query . Find ( & sales ) . Error ; err != nil {
return nil , err
}
return sales , nil
}
2024-08-02 15:16:28 +07:00
func ( r * OrderRepository ) GetPaymentTypeDistribution ( ctx context . Context , req entity . OrderSearch ) ( [ ] entity . PaymentTypeDistribution , error ) {
var distribution [ ] entity . PaymentTypeDistribution
var periodFilter string
now := time . Now ( )
switch req . Period {
case "1d" :
periodFilter = now . Add ( - 24 * time . Hour ) . Format ( "2006-01-02 15:04:05" )
case "7d" :
periodFilter = now . Add ( - 7 * 24 * time . Hour ) . Format ( "2006-01-02 15:04:05" )
case "1m" :
periodFilter = now . AddDate ( 0 , - 1 , 0 ) . Format ( "2006-01-02 15:04:05" )
case "1y" :
periodFilter = now . AddDate ( - 1 , 0 , 0 ) . Format ( "2006-01-02 15:04:05" )
default :
periodFilter = now . AddDate ( 0 , - 1 , 0 ) . Format ( "2006-01-02 15:04:05" ) // Default to last month
}
query := r . db . WithContext ( ctx ) .
Table ( "orders o" ) .
Select ( "payment_type, COUNT(*) as count" ) .
Where ( "status = ?" , "PAID" ) .
Where ( "o.created_at >= ?" , periodFilter )
if req . PartnerID != nil {
query = query . Where ( "o.partner_id = ?" , * req . PartnerID )
}
if req . SiteID != nil {
query = query . Where ( "o.site_id = ?" , * req . SiteID )
}
query = query . Group ( "payment_type" )
if err := query . Scan ( & distribution ) . Error ; err != nil {
return nil , err
}
return distribution , nil
}