diff --git a/internal/repository/booking/pg_store.go b/internal/repository/booking/pg_store.go new file mode 100644 index 0000000..7bccad2 --- /dev/null +++ b/internal/repository/booking/pg_store.go @@ -0,0 +1,135 @@ +package booking + +import ( + "fmt" + "time" + + "gorm.io/gorm" + "gorm.io/gorm/clause" + + "github.com/rjNemo/rentease/internal/service/booking" +) + +type PgStore struct { + db *gorm.DB +} + +func NewPgStore(db *gorm.DB) *PgStore { + return &PgStore{db} +} + +func (ps *PgStore) All() []*booking.Line { + bookings := make([]*booking.Line, 0) + ps.db.Raw(` + select bookings.id, customer_name, "from", "to", platform, sum(price * quantity) as total, canceled + from bookings + left join items on bookings.id = items.booking_id + group by bookings.id + order by id desc; + `). + Scan(&bookings) + return bookings +} + +func (ps *PgStore) Search(value string) []*booking.Line { + bookings := make([]*booking.Line, 0) + ps.db.Raw(` + select bookings.id, customer_name, "from", "to", platform, sum(price * quantity) as total, canceled + from bookings + left join items on bookings.id = items.booking_id + where customer_name ilike ? + group by bookings.id + order by id desc; + `, fmt.Sprintf("%%%s%%", value)). + Scan(&bookings) + return bookings +} + +func (ps *PgStore) List(from, to time.Time) ([]*booking.Line, error) { + bookings := make([]*booking.Line, 0) + if err := ps.db.Raw(` + select bookings.id, customer_name, "from", "to", platform, sum(price * quantity) as total, platform_fees + from bookings + join items on bookings.id = items.booking_id + where "to" between ? and ? + group by bookings.id + order by id desc; + `, from, to). + Scan(&bookings).Error; err != nil { + return nil, fmt.Errorf("failed to list bookings: %w", err) + } + return bookings, nil +} + +func (ps *PgStore) CardTotal(from, to time.Time) (float64, error) { + var total float64 + if err := ps.db.Raw(` + select sum(price * quantity) + from bookings + join items on bookings.id = items.booking_id + join payments on bookings.id = payments.booking_id + where payments.method = 'card' + and "to" between ? and ?; + `, from, to). + Scan(&total).Error; err != nil { + return 0, fmt.Errorf("failed to get card total: %w", err) + } + return total, nil +} + +func (ps *PgStore) Get(id int) *booking.Booking { + var b booking.Booking + ps.db.First(&b, id) + return &b +} + +func (ps *PgStore) Create(b *booking.Booking) error { + return ps.db.Create(b).Error +} + +func (ps *PgStore) Update(b *booking.Booking) error { + return ps.db.Save(b).Error +} + +func (ps *PgStore) Cancel(id int) error { + return ps.db.Model(&booking.Booking{}).Where("id = ?", id).Update("canceled", true).Error +} + +// Item methods +func (ps *PgStore) CreateItem(i *booking.Item) error { + return ps.db.Create(i).Error +} + +func (ps *PgStore) PayItem(id int) (*booking.Item, error) { + i := new(booking.Item) + if err := ps.db.Model(i). + Clauses(clause.Returning{}). + Where("id = ?", id). + Update("payment_status", "Completed"). + Error; err != nil { + return nil, err + } + return i, nil +} + +func (ps *PgStore) GetItem(id int) (*booking.Item, error) { + i := &booking.Item{Id: id} + err := ps.db.First(i).Error + return i, err +} + +func (ps *PgStore) UpdateItem(id int, item string, paymentMethod string, paymentStatus string, qty int, price float64) (*booking.Item, error) { + i := new(booking.Item) + err := ps.db.Model(i). + Clauses(clause.Returning{}). + Where("id = ?", id). + Updates(map[string]any{ + "item": item, + "payment_method": paymentMethod, + "payment_status": paymentStatus, + "quantity": qty, + "price": price, + }). + Error + return i, err +} diff --git a/internal/service/booking/booking_store.go b/internal/service/booking/booking_store.go deleted file mode 100644 index 534724a..0000000 --- a/internal/service/booking/booking_store.go +++ /dev/null @@ -1,104 +0,0 @@ -package booking - -import ( - "fmt" - "time" - - "gorm.io/gorm" -) - -type PgStore struct { - db *gorm.DB -} - -func NewPgStore(db *gorm.DB) *PgStore { - return &PgStore{db} -} - -func (ps *PgStore) All() []*Line { - bookings := make([]*Line, 0) - ps.db.Raw(` - select bookings.id, customer_name, "from", "to", platform, sum(price * quantity) as total, canceled - from bookings - left join items on bookings.id = items.booking_id - group by bookings.id - order by id desc; - `). - Scan(&bookings) - return bookings -} - -func (ps *PgStore) Search(value string) []*Line { - bookings := make([]*Line, 0) - ps.db.Raw(` - select bookings.id, customer_name, "from", "to", platform, sum(price * quantity) as total, canceled - from bookings - left join items on bookings.id = items.booking_id - where customer_name ilike ? - group by bookings.id - order by id desc; - `, fmt.Sprintf("%%%s%%", value)). - Scan(&bookings) - return bookings -} - -func (ps *PgStore) List(from, to time.Time) ([]*Line, error) { - bookings := make([]*Line, 0) - if err := ps.db.Raw(` - select bookings.id, customer_name, "from", "to", platform, sum(price * quantity) as total, platform_fees - from bookings - join items on bookings.id = items.booking_id - where "to" between ? and ? - group by bookings.id - order by bookings.id; - `, - from.Format(time.DateOnly), to.Format(time.DateOnly)). - Scan(&bookings). - Error; err != nil { - return nil, err - } - - return bookings, nil -} - -func (ps *PgStore) CardTotal(from, to time.Time) (float64, error) { - cardTotal := 0.0 - if err := ps.db.Raw(` - select sum(total) - from (select sum(price * quantity) as total - from bookings - join items on bookings.id = items.booking_id - where "to" between ? and ? - and payment_method = 'Card' - group by booking_id) as t; - `, - from.Format(time.DateOnly), to.Format(time.DateOnly)). - Scan(&cardTotal). - Error; err != nil { - return 0.0, err - } - return cardTotal, nil -} - -func (ps *PgStore) Get(id int) *Booking { - b := &Booking{Id: id} - ps.db.Preload("Items", func(db *gorm.DB) *gorm.DB { - return db.Order("item") - }).First(b) - return b -} - -func (ps *PgStore) Create(b *Booking) error { - return ps.db.Create(b).Error -} - -func (ps *PgStore) Update(b *Booking) error { - return ps.db.Save(b).Error -} - -func (ps *PgStore) Cancel(id int) error { - b := &Booking{Id: id} - return ps.db.Model(&b). - Update("canceled", true). - Error -} diff --git a/internal/service/booking/item_store.go b/internal/service/booking/item_store.go deleted file mode 100644 index 4d68841..0000000 --- a/internal/service/booking/item_store.go +++ /dev/null @@ -1,41 +0,0 @@ -package booking - -import "gorm.io/gorm/clause" - -func (ps *PgStore) CreateItem(i *Item) error { - return ps.db.Create(i).Error -} - -func (ps *PgStore) PayItem(id int) (*Item, error) { - i := new(Item) - if err := ps.db.Model(i). - Clauses(clause.Returning{}). - Where("id = ?", id). - Update("payment_status", "Completed"). - Error; err != nil { - return nil, err - } - return i, nil -} - -func (ps *PgStore) GetItem(id int) (*Item, error) { - i := &Item{Id: id} - err := ps.db.First(i).Error - return i, err -} - -func (ps *PgStore) UpdateItem(id int, item string, paymentMethod string, paymentStatus string, qty int, price float64) (*Item, error) { - i := new(Item) - err := ps.db.Model(i). - Clauses(clause.Returning{}). - Where("id = ?", id). - Updates(map[string]any{ - "item": item, - "payment_method": paymentMethod, - "payment_status": paymentStatus, - "quantity": qty, - "price": price, - }). - Error - return i, err -} diff --git a/internal/service/booking/service.go b/internal/service/booking/service.go index 8703d38..b1df108 100644 --- a/internal/service/booking/service.go +++ b/internal/service/booking/service.go @@ -4,22 +4,37 @@ import ( "log" "time" - "gorm.io/gorm" - "github.com/rjNemo/rentease/internal/config" "github.com/rjNemo/rentease/internal/driver/calendar" "github.com/rjNemo/rentease/internal/driver/pdf" ) +type Store interface { + All() []*Line + Search(value string) []*Line + List(from, to time.Time) ([]*Line, error) + CardTotal(from, to time.Time) (float64, error) + Get(id int) *Booking + Create(b *Booking) error + Update(b *Booking) error + Cancel(id int) error + + // Item methods + CreateItem(i *Item) error + PayItem(id int) (*Item, error) + GetItem(id int) (*Item, error) + UpdateItem(id int, item string, paymentMethod string, paymentStatus string, qty int, price float64) (*Item, error) +} + type Service struct { - store *PgStore + store Store calendar calendar.Client pdf pdf.Client } -func NewService(db *gorm.DB, calendar calendar.Client, pdf pdf.Client) (*Service, error) { +func NewService(store Store, calendar calendar.Client, pdf pdf.Client) (*Service, error) { return &Service{ - store: NewPgStore(db), + store: store, calendar: calendar, pdf: pdf, }, nil @@ -81,7 +96,6 @@ func (bs Service) Update(id int, From time.Time, To time.Time, Name string, Phon return b } - func (bs Service) Cancel(id int) { err := bs.store.Cancel(id) if err != nil { diff --git a/main.go b/main.go index 3af060e..c05a0d4 100644 --- a/main.go +++ b/main.go @@ -15,6 +15,7 @@ import ( "github.com/rjNemo/rentease/internal/driver/calendar" "github.com/rjNemo/rentease/internal/driver/database" "github.com/rjNemo/rentease/internal/driver/pdf" + bookingRepo "github.com/rjNemo/rentease/internal/repository/booking" "github.com/rjNemo/rentease/internal/server" "github.com/rjNemo/rentease/internal/service/auth" "github.com/rjNemo/rentease/internal/service/booking" @@ -72,10 +73,10 @@ func run(c context.Context, getEnv func(string) string) error { return fmt.Errorf("error starting pdf client %w", err) } - // build booking service - bs, err := booking.NewService(db, gc, pc) + bookingStore := bookingRepo.NewPgStore(db) + bookingService, err := booking.NewService(bookingStore, gc, pc) if err != nil { - return fmt.Errorf("error starting booking service %w", err) + return fmt.Errorf("error creating booking service: %w", err) } // build authentication service @@ -99,7 +100,7 @@ func run(c context.Context, getEnv func(string) string) error { origins := strings.Split(ogs, ",") srv, err := server.New( - bs, + bookingService, as, config.NewHost(), // TODO: move to the database at some point server.WithPort(port),