From 96a29ea598d7d5f05e1b0f9109bbd3eac5dcb9a1 Mon Sep 17 00:00:00 2001 From: Santo Cariotti Date: Thu, 13 Jun 2024 17:47:21 +0200 Subject: [PATCH] Save rent for an offer --- bpmn/acmesky.bpmn | 685 +++++++++--------- ...nt_company.go => st_sort_rent_services.go} | 35 +- internal/handlers/acmesky/tm_ask_for_rent.go | 39 +- .../acmesky/tm_search_flight_on_airline.go | 7 + internal/http/soap.go | 7 +- internal/models/offer.go | 2 + main.go | 2 +- 7 files changed, 419 insertions(+), 358 deletions(-) rename internal/handlers/acmesky/{tm_find_nearest_available_rent_company.go => st_sort_rent_services.go} (79%) diff --git a/bpmn/acmesky.bpmn b/bpmn/acmesky.bpmn index 7305a88..8359ff9 100644 --- a/bpmn/acmesky.bpmn +++ b/bpmn/acmesky.bpmn @@ -17,77 +17,81 @@ - - - - - - + + + + + + Check if token timestamp is not expired and not used Payment is more or less than 1000 - - No rent - - - Start_Flight_Manager_New_Offer - ST_Save_Last_Minute_Offer - Event_0q1gics TS_Check_Airline - ST_Get_User_Interests + Event_0q1gics + ST_Save_Last_Minute_Offer + Start_Flight_Manager_New_Offer Activity_Foreach_AirlineService + ST_Get_User_Interests End_Check_Airline - End_Check_Interests Activity_Foreach_Journey + End_Check_Interests ST_Create_Journeys TS_Check_Interests - TM_Ack_Flight_Request_Save - ST_Save_Flight - End_ACME_UserProfile - ST_Retrieve_Offer - EG_Price_Greater_Than_1000 TM_Journey + EG_Price_Greater_Than_1000 + ST_Retrieve_Offer + ST_Sort_Rent_Services + EG_Loop_Rent + TM_Compute_Distance_User_Airport + EG_Distance_Less_Than_30km + TE_30s_Distance_Airport + Gateway_1o1urwx + End_ACME_UserProfile + ST_Save_Flight + TM_Ack_Flight_Request_Save Activity_Check_Offer - EB_Check_Offer TM_Error_On_Check_Offer Event_0a5pqyi Activity_Book_Journey - Event_0jl8r24 Start_ACME_UserProfile TM_Error_On_Book_Journey Event_0i80v8b ST_Offer_Still_Valid Event_0wi1mfd - Activity_Rent_Service - Event_13jciaj CM_Check_Offer + Event_0em1zuc Event_1vdq7fa Activity_0caef9i - Event_0em1zuc + Activity_0gchv60 + Event_0jl8r24 + EB_Check_Offer + Event_078zn83 + TM_Journey_Rent_Error + Event_0x77suf @@ -101,9 +105,6 @@ - - =flight_price > 1000 - =flight_price <= 1000 @@ -120,7 +121,7 @@ Flow_0vvq016 Flow_1liyfs9 - Flow_1lwcjk0 + Flow_010wexv @@ -206,7 +207,7 @@ Flow_1qmul68 - + @@ -385,110 +386,6 @@ Flow_1ydsmn9 - - Flow_1lwcjk0 - Flow_06i0avx - - - - - Flow_1ru03hf - Flow_133dj9l - - - - - - Flow_1gep2yl - Flow_1ru03hf - - - - - Flow_08h7gb2 - Flow_0i9j9hr - Flow_1gep2yl - Flow_0bb5s9s - - - =distance < 30 - - - Flow_05e47ko - Flow_1i8vff5 - - =PT30S - - - - - - - Flow_1ajjpq1 - Flow_08h7gb2 - - - - - Flow_05e47ko - - - - - Flow_1i8vff5 - Flow_0ye5jwj - Flow_1ajjpq1 - - - - Flow_0ye5jwj - - - - Flow_133dj9l - Flow_08kjq9l - Flow_0vy5zmq - - - Flow_08kjq9l - Flow_0i9j9hr - Flow_1vsmgg6 - - - =rent_status != "Ok" - - - =next_rent_company_to_check != 0 - - - =rent_status = "Ok" - - - - - - Flow_0vy5zmq - - - - =next_rent_company_to_check = 0 - - - =distance >= 30 - - - - - - Flow_1vsmgg6 - Flow_0bb5s9s - - - - - Flow_06i0avx - - Flow_0rlehj8 Flow_0uv1725 @@ -582,6 +479,10 @@ Flow_0ckkzu4 + + + Flow_0hvq3dy + Flow_0epiiu9 @@ -593,11 +494,124 @@ Flow_0epiiu9 Flow_0hvq3dy - - Flow_0hvq3dy - - + + + + + Flow_1gep2yl + Flow_14kp621 + + + Flow_1i8vff5 + Flow_010wexv + Flow_1ajjpq1 + + + + + + Flow_1ajjpq1 + Flow_08h7gb2 + + + Flow_05e47ko + + + + Flow_08h7gb2 + Flow_1gep2yl + Flow_0bb5s9s + + + =distance < 30 + + + + + + + =flight_price >1000 + + + Flow_05e47ko + Flow_1i8vff5 + + =PT30S + + + + Flow_14kp621 + Flow_1oy8dyj + + + + + + + Flow_1nh7ck1 + + + + + + Flow_07cdseq + Flow_07otk5v + + + + Flow_1nh7ck1 + Flow_07cdseq + Flow_09bvvwa + + + Flow_09bvvwa + Flow_07otk5v + Flow_034emku + + + Flow_034emku + + + + =rent_status != "Ok" + + + =rent_status = "Ok" + + + + + + =distance >= 30 + + + Flow_1oy8dyj + Flow_1bf28rv + Flow_05szqe1 + + + + =rent_status != "Ok" + + + =rent_status = "Ok" + + + + + + Flow_1bf28rv + Flow_0bb5s9s + + + + + + + Flow_05szqe1 + + @@ -1079,19 +1093,19 @@ - + - + - + - + @@ -1164,6 +1178,7 @@ + @@ -1342,142 +1357,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1552,21 +1431,113 @@ + + + + + + + + + - - + + + - - + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1617,10 +1588,6 @@ - - - - @@ -1657,10 +1624,6 @@ - - - - @@ -1681,6 +1644,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1736,7 +1760,7 @@ - + @@ -1760,7 +1784,7 @@ - + @@ -1916,10 +1940,6 @@ - - - - @@ -1972,10 +1992,6 @@ - - - - @@ -2005,28 +2021,12 @@ - - + + - - - - - - - - - - - - - - - - - - + + @@ -2054,23 +2054,10 @@ - - - - - - - - - - - - - @@ -2099,6 +2086,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/internal/handlers/acmesky/tm_find_nearest_available_rent_company.go b/internal/handlers/acmesky/st_sort_rent_services.go similarity index 79% rename from internal/handlers/acmesky/tm_find_nearest_available_rent_company.go rename to internal/handlers/acmesky/st_sort_rent_services.go index 3d3c877..1de5122 100644 --- a/internal/handlers/acmesky/tm_find_nearest_available_rent_company.go +++ b/internal/handlers/acmesky/st_sort_rent_services.go @@ -2,6 +2,7 @@ package handlers import ( "context" + "sort" "time" "github.com/charmbracelet/log" @@ -17,8 +18,9 @@ import ( "google.golang.org/grpc/credentials/insecure" ) -// Task used to find the nearest rent company to the user' address -func TMFindNearestAvailableRentCompany(client worker.JobClient, job entities.Job) { +// Service task used to sort all rent services with key the distance between +// user and rent geolocalizations. +func STSortRentServices(client worker.JobClient, job entities.Job) { jobKey := job.GetKey() variables, err := job.GetVariablesAsMap() @@ -70,7 +72,12 @@ func TMFindNearestAvailableRentCompany(client worker.JobClient, job entities.Job acmejob.FailJob(client, job) return } - var distances []int + + type RentDistance struct { + Id uint + Distance int + } + var distances []RentDistance for _, rent := range rents { distance, err := c.FindDistance(ctx, &pb.DistanceRequest{ @@ -78,29 +85,25 @@ func TMFindNearestAvailableRentCompany(client worker.JobClient, job entities.Job Destination: &pb.MapPosition{Latitude: rent.Latitude, Longitude: rent.Longitude}, }) if err != nil { - log.Warn("[%s] [%d] Can't find distance for %s: %s", job.Type, jobKey, rent.Name, err.Error()) - distances = append(distances, 9999999) + log.Warnf("[%s] [%d] Can't find distance for %s: %s", job.Type, jobKey, rent.Name, err.Error()) + distances = append(distances, RentDistance{Id: rent.Id, Distance: 999999}) continue } - distances = append(distances, int(distance.GetDistance())) + distances = append(distances, RentDistance{Id: rent.Id, Distance: int(distance.GetDistance())}) } - if len(distances) == 0 { + if len(rents) == 0 { log.Errorf("[%s] [%d] There is no available rent company: %s", job.Type, jobKey, err.Error()) acmejob.FailJob(client, job) return } - var selectRentIndex = 0 - var minRentDistance = distances[0] - for i := 1; i < len(distances); { - if distances[i] < minRentDistance { - minRentDistance = distances[i] - selectRentIndex = i - } - } + sort.Slice(distances, func(i, j int) bool { + return distances[i].Distance > distances[j].Distance + }) - variables["rent_company"] = rents[selectRentIndex] + variables["rent_companies"] = distances + variables["rent_status"] = "No" request, err := client.NewCompleteJobCommand().JobKey(jobKey).VariablesFromMap(variables) if err != nil { diff --git a/internal/handlers/acmesky/tm_ask_for_rent.go b/internal/handlers/acmesky/tm_ask_for_rent.go index 0613b32..dac63a2 100644 --- a/internal/handlers/acmesky/tm_ask_for_rent.go +++ b/internal/handlers/acmesky/tm_ask_for_rent.go @@ -6,6 +6,7 @@ import ( "github.com/charmbracelet/log" "github.com/acme-sky/workers/internal/db" + "github.com/acme-sky/workers/internal/http" acmejob "github.com/acme-sky/workers/internal/job" "github.com/acme-sky/workers/internal/models" "github.com/camunda/zeebe/clients/go/v8/pkg/entities" @@ -25,20 +26,50 @@ func TMAskForRent(client worker.JobClient, job entities.Job) { db, _ := db.GetDb() var rent models.Rent - if variables["rent_company"] == nil { + rentCompanies := variables["rent_companies"].([]interface{}) + index := int(variables["loopCounter"].(float64)) - 1 + + if len(rentCompanies) == 0 { log.Infof("[%s] [%d] You must define a rent_company object", job.Type, jobKey) acmejob.FailJob(client, job) return } + rentCompany := rentCompanies[index].(map[string]interface{}) + rentCompanyId := int(rentCompany["Id"].(float64)) - rentCompany := variables["rent_company"].(map[string]interface{}) - rentCompanyId := int(rentCompany["id"].(float64)) if err := db.Where("id = ?", rentCompanyId).First(&rent).Error; err != nil { log.Errorf("[%s] [%d] Rent not found %s", job.Type, jobKey, err.Error()) acmejob.FailJob(client, job) return } - variables["next_rent_company_to_check"] = 42 + + var offer models.Offer + if err := db.Where("id = ?", variables["offer_id"]).Preload("Journey").Preload("Journey.Flight1").Preload("Journey.Flight2").Preload("User").First(&offer).Error; err != nil { + log.Errorf("[%s] [%d] Journey not found", job.Type, jobKey) + acmejob.FailJob(client, job) + return + } + + response, err := http.MakeRentRequest(rent, offer) + + if err != nil { + log.Errorf("[%s] [%d] Error for rent `%s`: %s", job.Type, jobKey, rent.Name, err.Error()) + acmejob.FailJob(client, job) + return + } else { + if response.Status == "OK" { + variables["rent_status"] = "Ok" + offer.RentId = response.RentId + if err := db.Save(&offer).Error; err != nil { + log.Errorf("[%s] [%d] Error on saving offer %s", job.Type, jobKey, err.Error()) + acmejob.FailJob(client, job) + return + } + log.Infof("[%s] [%d] Rent `%s` is OK with ID `%s`", job.Type, jobKey, rent.Name, response.RentId) + } else { + log.Errorf("[%s] [%d] Rent `%s` is not OK", job.Type, jobKey, rent.Name) + } + } request, err := client.NewCompleteJobCommand().JobKey(jobKey).VariablesFromMap(variables) if err != nil { diff --git a/internal/handlers/acmesky/tm_search_flight_on_airline.go b/internal/handlers/acmesky/tm_search_flight_on_airline.go index b996bf3..59a4c6d 100644 --- a/internal/handlers/acmesky/tm_search_flight_on_airline.go +++ b/internal/handlers/acmesky/tm_search_flight_on_airline.go @@ -32,6 +32,13 @@ func TMSearchFlightsOnAirline(client worker.JobClient, job entities.Job) { airline := airlines[index] interests := variables["interests"].([]interface{}) + + if len(interests) == 0 { + log.Warnf("Error for airline `%s`: there is no interest", airline) + acmejob.FailJob(client, job) + return + } + if index < 0 || index >= len(interests) { log.Errorf("Error for airline `%s`: index out of range %d", airline, index) acmejob.FailJob(client, job) diff --git a/internal/http/soap.go b/internal/http/soap.go index 3705337..15fd4a9 100644 --- a/internal/http/soap.go +++ b/internal/http/soap.go @@ -32,9 +32,10 @@ func MakeRentRequest(rent models.Rent, offer models.Offer) (*BookRentResponse, e params := gosoap.Params{ "PickupAddress": *offer.User.Address, - "Address": offer.Journey.Flight1.DepartureAirport, - "CustomerName": offer.User.Name, - "PickupDate": offer.Journey.Flight1.DepartureTime.Add(-2 * time.Hour), + // FIXME: add "address" field to airport with string + "Address": offer.Journey.Flight1.DepartureAirport, + "CustomerName": offer.User.Name, + "PickupDate": offer.Journey.Flight1.DepartureTime.Add(-2 * time.Hour).Format("02/01/2006 15:04"), } res, err := soap.Call("BookRent", params) diff --git a/internal/models/offer.go b/internal/models/offer.go index 1921a3a..440902b 100644 --- a/internal/models/offer.go +++ b/internal/models/offer.go @@ -21,6 +21,7 @@ type Offer struct { IsUsed bool `gorm:"column:is_used" json:"is_used"` PaymentLink string `gorm:"column:payment_link" json:"payment_link"` PaymentPaid bool `gorm:"column:payment_paid" json:"payment_paid"` + RentId string `gorm:"column:rent_id" json:"rent_id"` JourneyId int `json:"-"` Journey Journey `gorm:"foreignKey:JourneyId" json:"journey"` UserId int `json:"-"` @@ -114,6 +115,7 @@ func NewOffer(in OfferInput) Offer { IsUsed: false, PaymentLink: "", PaymentPaid: false, + RentId: "", JourneyId: in.JourneyId, UserId: in.UserId, } diff --git a/main.go b/main.go index d4838d6..f19b064 100644 --- a/main.go +++ b/main.go @@ -90,7 +90,7 @@ func main() { {Name: "TM_Error_On_Book_Journey", Handler: acmeskyHandlers.TMErrorOnBookJourney, Message: &acmejob.MessageCommand{Name: "CM_Received_Bank_Error", CorrelationKey: "0"}}, {Name: "TM_Journey", Handler: acmeskyHandlers.TMJourney, Message: &acmejob.MessageCommand{Name: "CM_Journey", CorrelationKey: "0"}}, {Name: "TM_Compute_Distance_User_Airport", Handler: acmeskyHandlers.TMComputeDistanceUserAirport}, - {Name: "TM_Find_Nearest_Available_Rent_Company", Handler: acmeskyHandlers.TMFindNearestAvailableRentCompany}, + {Name: "ST_Sort_Rent_Services", Handler: acmeskyHandlers.STSortRentServices}, {Name: "TM_Ask_For_Rent", Handler: acmeskyHandlers.TMAskForRent}, {Name: "TM_Journey_And_Rent", Handler: acmeskyHandlers.TMJourneyAndRent, Message: &acmejob.MessageCommand{Name: "CM_Journey_And_Rent", CorrelationKey: "0"}}, {Name: "TM_Journey_Rent_Error", Handler: acmeskyHandlers.TMJourneyRentError, Message: &acmejob.MessageCommand{Name: "CM_Journey", CorrelationKey: "0"}},