mirror of
https://github.com/rjNemo/rentease.git
synced 2026-06-06 02:36:49 +00:00
344 lines
10 KiB
Go
344 lines
10 KiB
Go
package server
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
"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/config"
|
|
"github.com/rjNemo/rentease/constant"
|
|
"github.com/rjNemo/rentease/internal/booking"
|
|
"github.com/rjNemo/rentease/internal/calendar"
|
|
"github.com/rjNemo/rentease/internal/view"
|
|
myTime "github.com/rjNemo/rentease/pkg/time"
|
|
)
|
|
|
|
func handleBookingListPage(bs *booking.Service, hc *config.Host) echo.HandlerFunc {
|
|
return func(c echo.Context) error {
|
|
bookings := bs.All()
|
|
|
|
bvm := u.Map(bookings, func(b *booking.Line) *view.ListBookingsViewModel {
|
|
return &view.ListBookingsViewModel{
|
|
Id: b.InvoiceNumber(hc),
|
|
Url: templ.SafeURL(fmt.Sprintf("%s/%d", constant.RouteBooking, b.Id)),
|
|
From: b.From.Format(time.DateOnly),
|
|
To: b.To.Format(time.DateOnly),
|
|
Platform: b.Platform,
|
|
Name: b.CustomerName,
|
|
Total: strconv.FormatFloat(b.Total, 'f', 2, 64),
|
|
Canceled: b.Canceled,
|
|
}
|
|
})
|
|
|
|
component := view.ListBookings(bvm)
|
|
return renderTempl(c, http.StatusOK, component)
|
|
}
|
|
}
|
|
|
|
func handleBookingCreatePage(hc *config.Host) echo.HandlerFunc {
|
|
return func(c echo.Context) error {
|
|
return renderTempl(c, http.StatusOK, view.NewBooking(hc.Platforms))
|
|
}
|
|
}
|
|
|
|
func handleBookingCreate(bs *booking.Service) echo.HandlerFunc {
|
|
return func(c echo.Context) error {
|
|
type NewBooking struct {
|
|
From time.Time `json:"from"`
|
|
To time.Time `json:"to"`
|
|
ExternalId *string `form:"external_id"`
|
|
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
|
|
|
|
if *nb.ExternalId == "" {
|
|
nb.ExternalId = nil
|
|
}
|
|
b := bs.Create(nb.From, nb.To, nb.Name, nb.PhoneNumber, nb.Email, nb.Platform, nb.CustomerNumber, nb.PlatformFees, nb.ExternalId)
|
|
return c.Redirect(http.StatusSeeOther, fmt.Sprintf("%s/%d", constant.RouteBooking, b.Id))
|
|
}
|
|
}
|
|
|
|
func handleBookingPage(bs *booking.Service, hc *config.Host) echo.HandlerFunc {
|
|
return func(c echo.Context) error {
|
|
idStr := c.Param("id")
|
|
id, err := strconv.Atoi(idStr)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
b := bs.One(id)
|
|
|
|
var eid string
|
|
if b.ExternalId == nil {
|
|
eid = ""
|
|
} else {
|
|
eid = *b.ExternalId
|
|
}
|
|
bvm := &view.BookingViewModel{
|
|
Id: b.InvoiceNumber(hc),
|
|
Name: b.Name,
|
|
PhoneNumber: b.PhoneNumber,
|
|
CustomerNumber: strconv.Itoa(b.CustomerNumber),
|
|
Email: b.Email,
|
|
From: b.From.Format(time.DateOnly),
|
|
To: b.To.Format(time.DateOnly),
|
|
Platform: b.Platform,
|
|
ExternalId: eid,
|
|
Canceled: b.Canceled,
|
|
PlatformFees: strconv.FormatFloat(b.PlatformFees, 'f', 2, 64),
|
|
Url: templ.EscapeString(fmt.Sprintf("%s/%d", constant.RouteBooking, b.Id)),
|
|
PdfUrl: templ.SafeURL(fmt.Sprintf("%s/pdf/%d", constant.RouteBooking, b.Id)),
|
|
CancelUrl: fmt.Sprintf("%s/%d/cancel", constant.RouteBooking, b.Id),
|
|
Items: u.Map(b.Items, func(i booking.Item) view.ItemViewModel {
|
|
return view.ItemViewModel{
|
|
Id: strconv.Itoa(i.Id),
|
|
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,
|
|
ItemUrl: fmt.Sprintf("%s/%d", constant.RouteItem, i.Id),
|
|
}
|
|
}),
|
|
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: hc.Platforms,
|
|
ItemList: u.OrderBy(func(items map[string]config.HostItem) (out []string) {
|
|
for _, item := range items {
|
|
out = append(out, item.Name)
|
|
}
|
|
return out
|
|
}(hc.Items),
|
|
func(l, r string) bool { return l < r },
|
|
),
|
|
PaymentMethods: hc.PaymentMethods,
|
|
}
|
|
return renderTempl(c, http.StatusOK, view.BookingById(bvm))
|
|
}
|
|
}
|
|
|
|
func handleBookingUpdate(bs *booking.Service, hc *config.Host) echo.HandlerFunc {
|
|
return func(c echo.Context) error {
|
|
type UpdateBooking struct {
|
|
From time.Time `json:"from"`
|
|
To time.Time `json:"to"`
|
|
ExternalId *string `form:"external_id"`
|
|
Name string `form:"name"`
|
|
PhoneNumber string `form:"phone_number"`
|
|
Email string `form:"email"`
|
|
Platform string `form:"platform"`
|
|
Id int `param:"id"`
|
|
CustomerNumber int `form:"customer_number"`
|
|
PlatformFees float64 `form:"platform_fees"`
|
|
}
|
|
nb := new(UpdateBooking)
|
|
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
|
|
|
|
if *nb.ExternalId == "" {
|
|
nb.ExternalId = nil
|
|
}
|
|
|
|
b := bs.Update(nb.Id, nb.From, nb.To, nb.Name, nb.PhoneNumber, nb.Email, nb.Platform, nb.CustomerNumber, nb.PlatformFees, nb.ExternalId)
|
|
|
|
form := view.BookingForm(view.BookingViewModel{
|
|
Id: b.InvoiceNumber(hc),
|
|
Name: b.Name,
|
|
PhoneNumber: b.PhoneNumber,
|
|
CustomerNumber: strconv.Itoa(b.CustomerNumber),
|
|
Email: b.Email,
|
|
From: b.From.Format(time.DateOnly),
|
|
To: b.To.Format(time.DateOnly),
|
|
Canceled: b.Canceled,
|
|
Platform: b.Platform,
|
|
ExternalId: *b.ExternalId,
|
|
Platforms: hc.Platforms,
|
|
PlatformFees: strconv.FormatFloat(b.PlatformFees, 'f', 2, 64),
|
|
PaymentMethods: hc.PaymentMethods,
|
|
Url: templ.EscapeString(fmt.Sprintf("%s/%d", constant.RouteBooking, b.Id)),
|
|
PdfUrl: templ.SafeURL(fmt.Sprintf("%s/pdf/%d", constant.RouteBooking, b.Id)),
|
|
})
|
|
|
|
return renderTempl(c, http.StatusOK, form)
|
|
}
|
|
}
|
|
|
|
func handleLineItemForm(bs *booking.Service) echo.HandlerFunc {
|
|
return func(c echo.Context) error {
|
|
idStr := c.Param("id")
|
|
id, err := strconv.Atoi(idStr)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
i := bs.OneItem(id)
|
|
form := view.LineItemForm(&view.ItemViewModel{
|
|
Id: strconv.Itoa(i.Id),
|
|
Item: i.Item,
|
|
Quantity: strconv.Itoa(i.Quantity),
|
|
Price: strconv.FormatFloat(i.Price, 'f', 2, 64),
|
|
PaymentMethod: i.PaymentMethod,
|
|
PaymentStatus: i.PaymentStatus,
|
|
SubTotal: strconv.FormatFloat(i.Price*float64(i.Quantity), 'f', 2, 64),
|
|
ItemUrl: fmt.Sprintf("%s/%d", constant.RouteItem, i.Id),
|
|
})
|
|
return renderTempl(c, http.StatusOK, form)
|
|
}
|
|
}
|
|
|
|
func handleCreateItem(bs *booking.Service, cs *calendar.Service, hc *config.Host) echo.HandlerFunc {
|
|
type NewItem struct {
|
|
Item string `form:"item"`
|
|
PaymentMethod string `form:"method"`
|
|
Quantity int `form:"quantity"`
|
|
Price float64 `form:"price"`
|
|
}
|
|
|
|
return func(c echo.Context) error {
|
|
bookingIdStr := c.Param("id")
|
|
bid, err := strconv.Atoi(bookingIdStr)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
b := bs.One(bid)
|
|
|
|
ni := new(NewItem)
|
|
if err := c.Bind(ni); err != nil {
|
|
log.Warn(err)
|
|
return err
|
|
}
|
|
|
|
itm, ok := hc.Items[ni.Item]
|
|
if !ok {
|
|
return fmt.Errorf("invalid item name %q", ni.Item)
|
|
}
|
|
|
|
i := bs.CreateItem(b.Id, ni.Item, ni.Quantity, ni.Price, ni.PaymentMethod)
|
|
|
|
if err = cs.Create(
|
|
itm.CalendarId,
|
|
b.Name,
|
|
fmt.Sprintf("Reservation: %s\n %d voyageur(s)\n", b.Name, b.CustomerNumber),
|
|
b.From, b.To,
|
|
); err != nil {
|
|
log.Warnf("could not create event: %s", err)
|
|
captureError(c, err)
|
|
}
|
|
|
|
return renderTempl(c, http.StatusCreated, view.LineItem(&view.ItemViewModel{
|
|
Id: strconv.Itoa(i.Id),
|
|
Item: i.Item,
|
|
Quantity: strconv.Itoa(i.Quantity),
|
|
Price: strconv.FormatFloat(i.Price, 'f', 2, 64),
|
|
PaymentMethod: i.PaymentMethod,
|
|
PaymentStatus: i.PaymentStatus,
|
|
SubTotal: strconv.FormatFloat(i.Price*float64(i.Quantity), 'f', 2, 64),
|
|
ItemUrl: fmt.Sprintf("%s/%d", constant.RouteItem, i.Id),
|
|
}))
|
|
}
|
|
}
|
|
|
|
func handleItemPay(bs *booking.Service) echo.HandlerFunc {
|
|
return func(c echo.Context) error {
|
|
itemIdStr := c.Param("id")
|
|
itemId, err := strconv.Atoi(itemIdStr)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
i := bs.PayItem(itemId)
|
|
return renderTempl(c, http.StatusOK, view.LineItem(&view.ItemViewModel{
|
|
Id: itemIdStr,
|
|
Item: i.Item,
|
|
Quantity: strconv.Itoa(i.Quantity),
|
|
Price: strconv.FormatFloat(i.Price, 'f', 2, 64),
|
|
PaymentMethod: i.PaymentMethod,
|
|
PaymentStatus: i.PaymentStatus,
|
|
SubTotal: strconv.FormatFloat(i.Price*float64(i.Quantity), 'f', 2, 64),
|
|
ItemUrl: fmt.Sprintf("%s/%d", constant.RouteItem, i.Id),
|
|
}))
|
|
}
|
|
}
|
|
|
|
func handleItemUpdate(bs *booking.Service) echo.HandlerFunc {
|
|
return func(c echo.Context) error {
|
|
type updateItem struct {
|
|
Item string `form:"item"`
|
|
PaymentMethod string `form:"paymentMethod"`
|
|
PaymentStatus string `form:"paymentStatus"`
|
|
Id int `param:"id"`
|
|
Quantity int `form:"quantity"`
|
|
Price float64 `form:"price"`
|
|
}
|
|
ui := new(updateItem)
|
|
|
|
if err := c.Bind(ui); err != nil {
|
|
log.Warn(err)
|
|
return err
|
|
}
|
|
|
|
i := bs.UpdateItem(ui.Id, ui.Item, ui.Quantity, ui.Price, ui.PaymentMethod, ui.PaymentStatus)
|
|
|
|
return renderTempl(c, http.StatusCreated, view.LineItem(&view.ItemViewModel{
|
|
Id: strconv.Itoa(ui.Id),
|
|
Item: i.Item,
|
|
Quantity: strconv.Itoa(i.Quantity),
|
|
Price: strconv.FormatFloat(i.Price, 'f', 2, 64),
|
|
PaymentMethod: i.PaymentMethod,
|
|
PaymentStatus: i.PaymentStatus,
|
|
SubTotal: strconv.FormatFloat(i.Price*float64(i.Quantity), 'f', 2, 64),
|
|
ItemUrl: fmt.Sprintf("%s/%d", constant.RouteItem, i.Id),
|
|
}))
|
|
}
|
|
}
|
|
|
|
func handleBookingCancel(bs *booking.Service) echo.HandlerFunc {
|
|
return func(c echo.Context) error {
|
|
idStr := c.Param("id")
|
|
id, err := strconv.Atoi(idStr)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
bs.Cancel(id)
|
|
|
|
return renderTempl(c, http.StatusOK, templ.ComponentFunc(func(ctx context.Context, w io.Writer) error {
|
|
_, err := io.WriteString(w, " <span>Canceled</span>")
|
|
return err
|
|
}))
|
|
}
|
|
}
|