rentease/internal/server/handlers.go
2024-02-16 12:38:03 +01:00

279 lines
7.9 KiB
Go

package server
import (
"fmt"
"net/http"
"strconv"
"time"
"github.com/a-h/templ"
"github.com/labstack/echo/v4"
"github.com/labstack/gommon/log"
u "github.com/rjNemo/underscore"
"github.com/rjNemo/rentease/constants"
"github.com/rjNemo/rentease/internal/domains/booking"
"github.com/rjNemo/rentease/internal/pdf"
"github.com/rjNemo/rentease/internal/views"
myTime "github.com/rjNemo/rentease/pkg/time"
)
func (s Server) handleHomePage() echo.HandlerFunc {
return func(ctx echo.Context) error {
component := views.Index()
return s.renderTempl(ctx, http.StatusOK, component)
}
}
func (s Server) handleListBookingPage() echo.HandlerFunc {
return func(c echo.Context) error {
bookings := make([]*booking.Booking, 0)
_ = s.db.Order("id desc").Find(&bookings)
bvm := u.Map(bookings, func(b *booking.Booking) *views.ListBookingsViewModel {
return &views.ListBookingsViewModel{
Id: strconv.Itoa(b.Id),
Url: templ.SafeURL(fmt.Sprintf("%s/%d", constants.RouteBooking, b.Id)),
From: b.From.Format("2006-01-02"),
To: b.To.Format("2006-01-02"),
Platform: b.Platform,
Name: b.Name,
}
})
component := views.ListBookings(bvm)
return s.renderTempl(c, http.StatusOK, component)
}
}
func (s Server) handleNewBookingPage() echo.HandlerFunc {
return func(c echo.Context) error {
component := views.NewBooking(constants.Platforms)
return s.renderTempl(c, http.StatusOK, component)
}
}
func (s Server) handleCreateBooking() echo.HandlerFunc {
return func(c echo.Context) error {
type NewBooking struct {
From time.Time `json:"from"`
To time.Time `from:"to"`
Name string `form:"name"`
PhoneNumber string `form:"phone_number"`
Email string `form:"email"`
Platform string `form:"platform"`
CustomerNumber int `form:"customer_number"`
PlatformFees float64 `form:"platform_fees"`
}
nb := new(NewBooking)
err := c.Bind(nb)
if err != nil {
log.Warn(err)
return err
}
ts, _ := myTime.ParseFromForm(c.FormValue("from"))
nb.From = ts
ts, _ = myTime.ParseFromForm(c.FormValue("to"))
nb.To = ts
b := &booking.Booking{
Name: nb.Name,
PhoneNumber: nb.PhoneNumber,
CustomerNumber: nb.CustomerNumber,
Email: nb.Email,
From: nb.From,
To: nb.To,
Platform: nb.Platform,
PlatformFees: nb.PlatformFees,
}
_ = s.db.Create(b)
return c.Redirect(http.StatusSeeOther, fmt.Sprintf("%s/%d", constants.RouteBooking, b.Id))
}
}
func (s Server) handleBookingPage() echo.HandlerFunc {
return func(c echo.Context) error {
idStr := c.Param("id")
id, err := strconv.Atoi(idStr)
if err != nil {
return err
}
b := &booking.Booking{Id: id}
s.db.Preload("Items").First(b)
bvm := &views.BookingViewModel{
Id: fmt.Sprintf("%04s", strconv.Itoa(b.Id)),
Name: b.Name,
PhoneNumber: b.PhoneNumber,
CustomerNumber: strconv.Itoa(b.CustomerNumber),
Email: b.Email,
From: b.From.Format("2006-01-02"),
To: b.To.Format("2006-01-02"),
Platform: b.Platform,
PlatformFees: strconv.FormatFloat(b.PlatformFees, 'f', 2, 64),
Url: templ.EscapeString(fmt.Sprintf("%s/%d/items", constants.RouteBooking, b.Id)),
Items: u.Map(b.Items, func(i booking.Item) views.ItemViewModel {
return views.ItemViewModel{
Item: i.Item,
Quantity: strconv.Itoa(i.Quantity),
Price: strconv.FormatFloat(i.Price, 'f', 2, 64),
SubTotal: strconv.FormatFloat(i.Price*float64(i.Quantity), 'f', 2, 64),
PaymentMethod: i.PaymentMethod,
PaymentStatus: i.PaymentStatus,
}
}),
Total: strconv.FormatFloat(u.Reduce(b.Items, func(i booking.Item, sum float64) float64 {
return sum + i.Price*float64(i.Quantity)
}, 0.0), 'f', 2, 64),
Platforms: constants.Platforms,
ItemList: constants.Items,
PaymentMethods: constants.PaymentMethods,
}
component := views.BookingById(bvm)
return s.renderTempl(c, http.StatusOK, component)
}
}
func (s Server) handleCreateItem() echo.HandlerFunc {
return func(c echo.Context) error {
bookingIdStr := c.Param("id")
bid, err := strconv.Atoi(bookingIdStr)
if err != nil {
return err
}
type NewItem struct {
Item string `form:"item"`
Quantity int `form:"quantity"`
Price float64 `form:"price"`
PaymentMethod string `form:"method"`
}
ni := new(NewItem)
if err := c.Bind(ni); err != nil {
log.Warn(err)
return err
}
i := &booking.Item{
BookingId: bid,
Item: ni.Item,
Quantity: ni.Quantity,
Price: ni.Price,
PaymentMethod: ni.PaymentMethod,
}
_ = s.db.Create(i)
return s.renderTempl(c, http.StatusCreated, views.LineItem(i))
}
}
func (s Server) handleReportsPage() echo.HandlerFunc {
return func(c echo.Context) error {
period := c.QueryParam("period")
if !u.Contains([]string{"month", "year"}, period) {
period = "month"
}
monthStr := c.QueryParam("month")
month, err := strconv.Atoi(monthStr)
if err != nil || month < 1 || month > 12 {
month = int(time.Now().Month())
}
yearStr := c.QueryParam("year")
_, err = strconv.Atoi(yearStr)
if err != nil {
yearStr = time.Now().Format("2006")
}
return s.renderTempl(c, http.StatusOK, views.Reports(constants.Months, yearStr))
}
}
func (s Server) handleComputeReport() echo.HandlerFunc {
return func(c echo.Context) error {
period := c.FormValue("period")
if !u.Contains([]string{"month", "year"}, period) {
return &echo.HTTPError{
Code: http.StatusBadRequest,
Message: fmt.Sprintf("%q is not a valid period", period),
}
}
monthStr := c.FormValue("month")
month, err := strconv.Atoi(monthStr)
if err != nil || month < 1 || month > 12 {
return &echo.HTTPError{
Code: http.StatusBadRequest,
Message: fmt.Sprintf("%q is not a valid month", month),
}
}
yearStr := c.FormValue("year")
year, err := strconv.Atoi(yearStr)
if err != nil {
return &echo.HTTPError{
Code: http.StatusBadRequest,
Message: fmt.Sprintf("%q is not a valid year", year),
}
}
type Result struct {
From time.Time
To time.Time
Id string
CustomerName string
Platform string
Total float64
PlatformFees float64
}
res := make([]*Result, 0)
var startDate time.Time
var endDate time.Time
if period == "month" {
startDate = time.Date(year, time.Month(month), 1, 0, 0, 0, 0, time.UTC)
endDate = time.Date(year, time.Month(month), 31, 0, 0, 0, 0, time.UTC)
} else {
startDate = time.Date(year, time.January, 1, 0, 0, 0, 0, time.UTC)
endDate = time.Date(year, time.December, 31, 0, 0, 0, 0, time.UTC)
}
s.db.
Raw(`
select id, customer_name, "from", "to", platform, total, platform_fees
from (select sum(price) as total, booking_id
from bookings
join items on bookings.id = items.booking_id
where "from" between ? and ?
group by booking_id) as sbi,
(select * from bookings) as b
where sbi.booking_id = b.id;
`,
startDate.Format("2006-01-02"), endDate.Format("2006-01-02")).
Scan(&res)
reportVm := u.Map(res, func(r *Result) *views.ReportViewModel {
return &views.ReportViewModel{
Id: r.Id,
Url: templ.SafeURL(fmt.Sprintf("%s/%s", constants.RouteBooking, r.Id)),
Total: strconv.FormatFloat(r.Total, 'f', 2, 64),
CustomerName: r.CustomerName,
From: r.From.Format("2006-01-02"),
To: r.To.Format("2006-01-02"),
Platform: r.Platform,
PlatformFees: strconv.FormatFloat(r.PlatformFees, 'f', 2, 64),
}
})
return s.renderTempl(c, http.StatusOK, views.ReportSection(reportVm))
}
}
func handleCreateInvoicePdf(ps *pdf.PdfService) echo.HandlerFunc {
return func(c echo.Context) error {
err := ps.BuildInvoice()
if err != nil {
return err
}
return c.Attachment("tmp.pdf", "tmp.pdf")
}
}