From 5ad104bdd733308029aed33bb4da2ee347209df9 Mon Sep 17 00:00:00 2001 From: Mauve Date: Tue, 22 Sep 2026 16:32:31 +0800 Subject: [PATCH] merge limo to daylight --- crm_mobile_runtime/appconfig.properties | 5 + .../controllers/MobileLoginController.java | 2 + .../services/MgmUserService.java | 2 + .../services/SysGroupPermissionService.java | 21 + .../dtos/response/CompRuleResponse.java | 62 + .../daylight/services/DaylightApiService.java | 2315 +++++++++++++++++ .../mcrm/booking/repositories/BookingDao.java | 2 + .../mcrm/booking/services/BookingService.java | 93 +- .../mgm/mcrm/common/constants/SysCommon.java | 1 + .../mcrm/common/constants/SysConstants.java | 2 + .../mcrm/common/dtos/config/APIConfig.java | 229 +- .../mgm_api/GetLimoAccessTokenRequest.java | 12 + .../mgm_api/GetLimoFlightDetailsRequest.java | 11 + .../dtos/mgm_api/GetLimoOverriderRequest.java | 10 + .../mgm_api/GetLimoTotalAmountRequest.java | 10 + .../dtos/mgm_api/GetPlayerInfoRequest.java | 10 + ...LimoBookingQualificationStatusRequest.java | 15 + .../InternalCreateLimoBookingRequest.java | 150 ++ .../InternalUpdateLimoBookingRequest.java | 148 ++ .../dtos/mgm_api/PlayerProfileApiResult.java | 188 ++ .../RequestPlayerLimoBookerRequest.java | 9 + .../dtos/mgm_api/UserInfoApiRecord.java | 3 + .../mgm/mcrm/common/services/HttpService.java | 4 +- .../mcrm/common/services/MGMApiService.java | 21 + .../common/services/MGMEsbApiService.java | 245 ++ .../common/services/MGMLimoApiService.java | 643 +++++ .../common/utils/mockup/HttpUtilMockup.java | 72 +- .../mcrm/limo/controller/LimoController.java | 312 +++ .../limo/dao/LimoBookingDraftRepository.java | 54 + .../mcrm/limo/dao/LimoBookingsRepository.java | 32 + .../request/CancelLimoBookingRequest.java | 11 + .../request/CreateLimoBookingRequest.java | 69 + .../request/GetLimoAccessTokenRequest.java | 12 + .../GetLimoBookingGetOverriderRequest.java | 8 + .../GetLimoBookingQualificationRequest.java | 10 + .../request/GetLimoEmployeeInfoRequest.java | 8 + .../request/GetLimoFlightDetailsRequest.java | 11 + .../dtos/request/GetLimoOverriderRequest.java | 10 + .../request/GetLimoTotalAmountRequest.java | 10 + .../dtos/request/GetPlayerInfoRequest.java | 10 + ...LimoBookingQualificationStatusRequest.java | 15 + .../InternalCancelLimoBookingRequest.java | 9 + .../InternalCreateLimoBookingRequest.java | 158 ++ .../InternalUpdateLimoBookingRequest.java | 153 ++ .../request/PrepareLimoBookingRequest.java | 15 + .../RequestPlayerEsbBookerRequest.java | 9 + .../request/UpdateLimoBookingRequest.java | 92 + .../response/CancelLimoBookingResponse.java | 29 + .../response/CreateLimoBookingResponse.java | 32 + .../GetLimoBookingFromLegacyResult.java | 14 + .../GetLimoBookingQualificationResponse.java | 38 + .../response/GetLimoEmployeeInfoResponse.java | 46 + .../response/GetOverriderInfoResponse.java | 42 + .../dtos/response/GetPlayerInfoResponse.java | 86 + .../response/LimoBookingFromLegacyItem.java | 137 + .../limo/dtos/response/LimoBookingItem.java | 261 ++ .../limo/dtos/response/LimoCarTypeItem.java | 32 + .../dtos/response/LimoFlightDetailsItem.java | 37 + .../limo/dtos/response/LimoGreetTypeItem.java | 32 + .../response/LimoPointOfInterestItem.java | 44 + .../dtos/response/LimoTotalAmountItem.java | 51 + .../limo/dtos/response/LimoTripPriceItem.java | 49 + .../dtos/response/PlayerEsbBookerItem.java | 29 + .../response/PlayerEsbBookerResponse.java | 27 + .../dtos/response/PrepareLimoBookingData.java | 14 + .../response/UpdateLimoBookingResponse.java | 25 + .../mcrm/limo/models/LimoBookingDraft.java | 61 + .../mgm/mcrm/limo/models/LimoBookings.java | 149 ++ .../mgm/mcrm/limo/services/LimoService.java | 2283 ++++++++++++++++ .../controllers/NotificationController.java | 9 + .../SysLogNotificationRepository.java | 10 + .../services/NotificationService.java | 9 + .../mgm/mcrm/player/services/TodoService.java | 122 +- src/main/resources/application-dev.yml | 12 + .../mockup/http/get_user_info_api_res4.json | 3 +- .../mockup/limo/cancel_booking_1.json | 4 + .../mockup/limo/cancel_booking_2.json | 4 + ...e_limo_booking_qualification_status_1.json | 8 + ...e_limo_booking_qualification_status_2.json | 8 + .../mockup/limo/create_booking_1.json | 1 + .../mockup/limo/create_booking_2.json | 4 + .../mockup/limo/get_booking_list.json | 5 + .../mockup/limo/get_car_type_list.json | 5 + .../mockup/limo/get_employee_info.json | 10 + .../mockup/limo/get_flight_details.json | 5 + .../mockup/limo/get_greet_type_list.json | 5 + .../resources/mockup/limo/get_location_1.json | 5 + .../resources/mockup/limo/get_location_2.json | 5 + .../mockup/limo/get_location_empty.json | 5 + .../resources/mockup/limo/get_overrider.json | 26 + .../mockup/limo/get_player_info.json | 20 + .../mockup/limo/get_player_limo_booker.json | 12 + .../mockup/limo/get_total_amount.json | 5 + .../mockup/limo/get_trip_price_list.json | 5 + .../mockup/limo/update_booking_1.json | 4 + .../mockup/limo/update_booking_2.json | 4 + .../resources/mockup/mgm_api_mockup_def.json | 39 +- .../crm_mobile_runtime/appconfig.properties | 16 + .../import/import_other_booking.json | 197 ++ 99 files changed, 9022 insertions(+), 356 deletions(-) create mode 100644 src/main/java/com/mgm/mcrm/basesetting/daylight/dtos/response/CompRuleResponse.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/daylight/services/DaylightApiService.java create mode 100644 src/main/java/com/mgm/mcrm/common/dtos/mgm_api/GetLimoAccessTokenRequest.java create mode 100644 src/main/java/com/mgm/mcrm/common/dtos/mgm_api/GetLimoFlightDetailsRequest.java create mode 100644 src/main/java/com/mgm/mcrm/common/dtos/mgm_api/GetLimoOverriderRequest.java create mode 100644 src/main/java/com/mgm/mcrm/common/dtos/mgm_api/GetLimoTotalAmountRequest.java create mode 100644 src/main/java/com/mgm/mcrm/common/dtos/mgm_api/GetPlayerInfoRequest.java create mode 100644 src/main/java/com/mgm/mcrm/common/dtos/mgm_api/GetSimpleLimoBookingQualificationStatusRequest.java create mode 100644 src/main/java/com/mgm/mcrm/common/dtos/mgm_api/InternalCreateLimoBookingRequest.java create mode 100644 src/main/java/com/mgm/mcrm/common/dtos/mgm_api/InternalUpdateLimoBookingRequest.java create mode 100644 src/main/java/com/mgm/mcrm/common/dtos/mgm_api/PlayerProfileApiResult.java create mode 100644 src/main/java/com/mgm/mcrm/common/dtos/mgm_api/RequestPlayerLimoBookerRequest.java create mode 100644 src/main/java/com/mgm/mcrm/common/services/MGMEsbApiService.java create mode 100644 src/main/java/com/mgm/mcrm/common/services/MGMLimoApiService.java create mode 100644 src/main/java/com/mgm/mcrm/limo/controller/LimoController.java create mode 100644 src/main/java/com/mgm/mcrm/limo/dao/LimoBookingDraftRepository.java create mode 100644 src/main/java/com/mgm/mcrm/limo/dao/LimoBookingsRepository.java create mode 100644 src/main/java/com/mgm/mcrm/limo/dtos/request/CancelLimoBookingRequest.java create mode 100644 src/main/java/com/mgm/mcrm/limo/dtos/request/CreateLimoBookingRequest.java create mode 100644 src/main/java/com/mgm/mcrm/limo/dtos/request/GetLimoAccessTokenRequest.java create mode 100644 src/main/java/com/mgm/mcrm/limo/dtos/request/GetLimoBookingGetOverriderRequest.java create mode 100644 src/main/java/com/mgm/mcrm/limo/dtos/request/GetLimoBookingQualificationRequest.java create mode 100644 src/main/java/com/mgm/mcrm/limo/dtos/request/GetLimoEmployeeInfoRequest.java create mode 100644 src/main/java/com/mgm/mcrm/limo/dtos/request/GetLimoFlightDetailsRequest.java create mode 100644 src/main/java/com/mgm/mcrm/limo/dtos/request/GetLimoOverriderRequest.java create mode 100644 src/main/java/com/mgm/mcrm/limo/dtos/request/GetLimoTotalAmountRequest.java create mode 100644 src/main/java/com/mgm/mcrm/limo/dtos/request/GetPlayerInfoRequest.java create mode 100644 src/main/java/com/mgm/mcrm/limo/dtos/request/GetSimpleLimoBookingQualificationStatusRequest.java create mode 100644 src/main/java/com/mgm/mcrm/limo/dtos/request/InternalCancelLimoBookingRequest.java create mode 100644 src/main/java/com/mgm/mcrm/limo/dtos/request/InternalCreateLimoBookingRequest.java create mode 100644 src/main/java/com/mgm/mcrm/limo/dtos/request/InternalUpdateLimoBookingRequest.java create mode 100644 src/main/java/com/mgm/mcrm/limo/dtos/request/PrepareLimoBookingRequest.java create mode 100644 src/main/java/com/mgm/mcrm/limo/dtos/request/RequestPlayerEsbBookerRequest.java create mode 100644 src/main/java/com/mgm/mcrm/limo/dtos/request/UpdateLimoBookingRequest.java create mode 100644 src/main/java/com/mgm/mcrm/limo/dtos/response/CancelLimoBookingResponse.java create mode 100644 src/main/java/com/mgm/mcrm/limo/dtos/response/CreateLimoBookingResponse.java create mode 100644 src/main/java/com/mgm/mcrm/limo/dtos/response/GetLimoBookingFromLegacyResult.java create mode 100644 src/main/java/com/mgm/mcrm/limo/dtos/response/GetLimoBookingQualificationResponse.java create mode 100644 src/main/java/com/mgm/mcrm/limo/dtos/response/GetLimoEmployeeInfoResponse.java create mode 100644 src/main/java/com/mgm/mcrm/limo/dtos/response/GetOverriderInfoResponse.java create mode 100644 src/main/java/com/mgm/mcrm/limo/dtos/response/GetPlayerInfoResponse.java create mode 100644 src/main/java/com/mgm/mcrm/limo/dtos/response/LimoBookingFromLegacyItem.java create mode 100644 src/main/java/com/mgm/mcrm/limo/dtos/response/LimoBookingItem.java create mode 100644 src/main/java/com/mgm/mcrm/limo/dtos/response/LimoCarTypeItem.java create mode 100644 src/main/java/com/mgm/mcrm/limo/dtos/response/LimoFlightDetailsItem.java create mode 100644 src/main/java/com/mgm/mcrm/limo/dtos/response/LimoGreetTypeItem.java create mode 100644 src/main/java/com/mgm/mcrm/limo/dtos/response/LimoPointOfInterestItem.java create mode 100644 src/main/java/com/mgm/mcrm/limo/dtos/response/LimoTotalAmountItem.java create mode 100644 src/main/java/com/mgm/mcrm/limo/dtos/response/LimoTripPriceItem.java create mode 100644 src/main/java/com/mgm/mcrm/limo/dtos/response/PlayerEsbBookerItem.java create mode 100644 src/main/java/com/mgm/mcrm/limo/dtos/response/PlayerEsbBookerResponse.java create mode 100644 src/main/java/com/mgm/mcrm/limo/dtos/response/PrepareLimoBookingData.java create mode 100644 src/main/java/com/mgm/mcrm/limo/dtos/response/UpdateLimoBookingResponse.java create mode 100644 src/main/java/com/mgm/mcrm/limo/models/LimoBookingDraft.java create mode 100644 src/main/java/com/mgm/mcrm/limo/models/LimoBookings.java create mode 100644 src/main/java/com/mgm/mcrm/limo/services/LimoService.java create mode 100644 src/main/resources/mockup/limo/cancel_booking_1.json create mode 100644 src/main/resources/mockup/limo/cancel_booking_2.json create mode 100644 src/main/resources/mockup/limo/check_simple_limo_booking_qualification_status_1.json create mode 100644 src/main/resources/mockup/limo/check_simple_limo_booking_qualification_status_2.json create mode 100644 src/main/resources/mockup/limo/create_booking_1.json create mode 100644 src/main/resources/mockup/limo/create_booking_2.json create mode 100644 src/main/resources/mockup/limo/get_booking_list.json create mode 100644 src/main/resources/mockup/limo/get_car_type_list.json create mode 100644 src/main/resources/mockup/limo/get_employee_info.json create mode 100644 src/main/resources/mockup/limo/get_flight_details.json create mode 100644 src/main/resources/mockup/limo/get_greet_type_list.json create mode 100644 src/main/resources/mockup/limo/get_location_1.json create mode 100644 src/main/resources/mockup/limo/get_location_2.json create mode 100644 src/main/resources/mockup/limo/get_location_empty.json create mode 100644 src/main/resources/mockup/limo/get_overrider.json create mode 100644 src/main/resources/mockup/limo/get_player_info.json create mode 100644 src/main/resources/mockup/limo/get_player_limo_booker.json create mode 100644 src/main/resources/mockup/limo/get_total_amount.json create mode 100644 src/main/resources/mockup/limo/get_trip_price_list.json create mode 100644 src/main/resources/mockup/limo/update_booking_1.json create mode 100644 src/main/resources/mockup/limo/update_booking_2.json create mode 100644 target/crm_mobile_runtime/appconfig.properties create mode 100644 target/crm_mobile_runtime/excel_define/import/import_other_booking.json diff --git a/crm_mobile_runtime/appconfig.properties b/crm_mobile_runtime/appconfig.properties index 51acda8..2f2b56e 100644 --- a/crm_mobile_runtime/appconfig.properties +++ b/crm_mobile_runtime/appconfig.properties @@ -8,6 +8,11 @@ esb_request_timeout=30000 ows_server=https://mgpmsdevows45 ows_request_timeout=30000 +#ESB Limo Setting +esb_limo_server=https://mmesbdevapp14/api/limo/v1.0 +esb_limo_app_id=Limotest +esb_limo_app_key=Limotest123 + #SMTP setting mail_port=25 mail_smtp_host=smtp.aliyun.com diff --git a/src/main/java/com/mgm/mcrm/authorization/controllers/MobileLoginController.java b/src/main/java/com/mgm/mcrm/authorization/controllers/MobileLoginController.java index 5fdabe5..0fa0266 100644 --- a/src/main/java/com/mgm/mcrm/authorization/controllers/MobileLoginController.java +++ b/src/main/java/com/mgm/mcrm/authorization/controllers/MobileLoginController.java @@ -157,6 +157,8 @@ public class MobileLoginController { if(SysConstants.PERMISSION_APP_DASHBOARD.equals(per.getId())) userInfo.setCanViewDashboard(true); if(SysConstants.PERMISSION_APP_APPROVAL.equals(per.getId())) userInfo.setCanViewApproval(true); if(SysConstants.PERMISSION_APP_CALENDAR.equals(per.getId())) userInfo.setCanViewCalendar(true); + if(SysConstants.PERMISSION_APP_VIEW_LIMO.equals(per.getId())) userInfo.setCanViewLimo(true); + if(SysConstants.PERMISSION_APP_VIEW_NOTIFICATION.equals(per.getId())) userInfo.setCanViewNotification(true); } } Token accessToken = JwtTokenUtil.generateTokenByLoginUser(request.getRequestURI(),loginUser, SysConstants.MOBILE_TOKEN_TYPE,false); diff --git a/src/main/java/com/mgm/mcrm/authorization/services/MgmUserService.java b/src/main/java/com/mgm/mcrm/authorization/services/MgmUserService.java index 48f6272..67c0396 100644 --- a/src/main/java/com/mgm/mcrm/authorization/services/MgmUserService.java +++ b/src/main/java/com/mgm/mcrm/authorization/services/MgmUserService.java @@ -240,6 +240,8 @@ public class MgmUserService { if(SysConstants.PERMISSION_APP_DASHBOARD.equals(per.getPermissionId())) info.setCanViewDashboard(true); if(SysConstants.PERMISSION_APP_APPROVAL.equals(per.getPermissionId())) info.setCanViewApproval(true); if(SysConstants.PERMISSION_APP_CALENDAR.equals(per.getPermissionId())) info.setCanViewCalendar(true); + if(SysConstants.PERMISSION_APP_VIEW_LIMO.equals(per.getPermissionId())) info.setCanViewLimo(true); + if(SysConstants.PERMISSION_APP_VIEW_NOTIFICATION.equals(per.getPermissionId())) info.setCanViewNotification(true); } } } diff --git a/src/main/java/com/mgm/mcrm/authorization/services/SysGroupPermissionService.java b/src/main/java/com/mgm/mcrm/authorization/services/SysGroupPermissionService.java index b1ee4c5..19266eb 100644 --- a/src/main/java/com/mgm/mcrm/authorization/services/SysGroupPermissionService.java +++ b/src/main/java/com/mgm/mcrm/authorization/services/SysGroupPermissionService.java @@ -1,5 +1,6 @@ package com.mgm.mcrm.authorization.services; +import com.auth0.jwt.JWT; import com.google.gson.Gson; import com.mgm.mcrm.authorization.models.SysGroupPermission; import com.mgm.mcrm.authorization.models.SysRouterPermission; @@ -8,7 +9,9 @@ import com.mgm.mcrm.authorization.repositories.SysGroupPermissionDao; import com.mgm.mcrm.authorization.repositories.SysRouterPermissionDao; import com.mgm.mcrm.booking.services.BookingService; import com.mgm.mcrm.common.utils.LogUtil; +import com.mgm.mcrm.limo.models.LimoBookings; import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletRequest; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.Strings; import org.springframework.stereotype.Service; @@ -87,4 +90,22 @@ public class SysGroupPermissionService { private List getRouterPermissionsByGroupNameList(List groupNameList) { return routerPermissionDao.queryPermssionByGroupNameList(groupNameList); } + + public boolean checkAppPermission(HttpServletRequest request, String permissionId){ + boolean havePermission = false; + List userPermissions = new ArrayList(); + LimoBookings response = new LimoBookings(); + String token = request.getHeader("Authorization"); + String groupName = JWT.decode(token).getClaim("group_name").asString(); + userPermissions = this.getRouterPermissionsByGroupName(groupName); + + if(userPermissions.size()>0) { + for(SysRouterPermission per:userPermissions) { + if(Strings.CS.equals(per.getId(), permissionId) ) havePermission = true; + } + } + + return havePermission; + } + } diff --git a/src/main/java/com/mgm/mcrm/basesetting/daylight/dtos/response/CompRuleResponse.java b/src/main/java/com/mgm/mcrm/basesetting/daylight/dtos/response/CompRuleResponse.java new file mode 100644 index 0000000..960666f --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/daylight/dtos/response/CompRuleResponse.java @@ -0,0 +1,62 @@ +package com.mgm.mcrm.basesetting.daylight.dtos.response; + +import lombok.Data; + +import java.math.BigDecimal; +import java.util.List; + +@Data +public class CompRuleResponse { + + private String id; + private Integer version; + private String accountId; + private String profileId; + private String folioWindowId; + private String complimentaryTypeId; + private List complimentaryAccountingPresetsIds; + private String requestorId; + private String approverId; + private String paymentMethodTransactionCodeId; + private String justification; + private ComplimentaryRuleLimits complimentaryRuleLimits; + private List settledFolioWindowIds; + private Boolean isExecutive; + private Boolean doNotIssueInvoice; + private Boolean isActive; + private Boolean canBeDeleted; + private Integer issuedVouchersCount; + + @Data + public static class ComplimentaryRuleLimits { + + private Amount totalAmountLimit; + private SoftTotalLimit softTotalLimit; + private List limitExcludedPresetIds; + private List limitExcludedTransactionCodeIds; + private TotalLimit totalLimit; + + @Data + public static class SoftTotalLimit { + + private Amount amountLimit; + private Amount remainingLimit; + private Boolean isExceeded; + } + + @Data + public static class TotalLimit { + + private Amount amountLimit; + private Amount remainingLimit; + } + + @Data + public static class Amount { + + private BigDecimal amount; + private String currency; + } + } +} + diff --git a/src/main/java/com/mgm/mcrm/basesetting/daylight/services/DaylightApiService.java b/src/main/java/com/mgm/mcrm/basesetting/daylight/services/DaylightApiService.java new file mode 100644 index 0000000..a99f6a3 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/daylight/services/DaylightApiService.java @@ -0,0 +1,2315 @@ +package com.mgm.mcrm.basesetting.daylight.services; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.mgm.mcrm.basesetting.agebucket.models.SysAgebucket; +import com.mgm.mcrm.basesetting.agebucket.services.AgebucketService; +import com.mgm.mcrm.basesetting.daylight.dtos.request.*; +import com.mgm.mcrm.basesetting.daylight.dtos.response.*; +import com.mgm.mcrm.basesetting.daylight.models.*; +import com.mgm.mcrm.basesetting.daylight.repositories.CompPresetDao; +import com.mgm.mcrm.basesetting.daylight.repositories.DaylightConfigurationDao; +import com.mgm.mcrm.basesetting.daylight.repositories.MarketCodeDao; +import com.mgm.mcrm.basesetting.daylight.repositories.RateCodeDao; +import com.mgm.mcrm.basesetting.property.models.CfgProperties; +import com.mgm.mcrm.basesetting.property.services.PropertyCache; +import com.mgm.mcrm.basesetting.room.models.CfgRoomTypes; +import com.mgm.mcrm.basesetting.room.models.CfgRooms; +import com.mgm.mcrm.basesetting.room.repositories.RoomDao; +import com.mgm.mcrm.booking.dtos.BookingDto; +import com.mgm.mcrm.booking.dtos.daylight.Breakdown; +import com.mgm.mcrm.booking.dtos.daylight.GuestForBreakdown; +import com.mgm.mcrm.booking.dtos.daylight.requests.createReservation.ReservationRequestDTO; +import com.mgm.mcrm.booking.dtos.daylight.responses.DistributionChannelResponse; +import com.mgm.mcrm.booking.dtos.daylight.responses.GuaranteeTypeResponse; +import com.mgm.mcrm.booking.models.Bookings; +import com.mgm.mcrm.booking.repositories.BookingDao; +import com.mgm.mcrm.booking.services.BookingService; +import com.mgm.mcrm.common.dtos.BaseApiResponse; +import com.mgm.mcrm.common.dtos.HttpResult; +import com.mgm.mcrm.common.dtos.mgm_api.PlayerProfileEntry; +import com.mgm.mcrm.common.enums.EnumBookingStatus; +import com.mgm.mcrm.common.httpclient.HttpHeaderBuilder; +import com.mgm.mcrm.common.services.HttpService; +import com.mgm.mcrm.common.utils.DateTimeUtil; +import com.mgm.mcrm.common.utils.LogUtil; +import com.mgm.mcrm.player.dtos.RatePricingDetail; +import com.mgm.mcrm.player.dtos.response.DaylightReservationResponse; +import com.mgm.mcrm.player.services.PlayerService; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.hc.core5.http.Header; +import org.jspecify.annotations.NonNull; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.*; +import java.util.concurrent.TimeUnit; + +@Slf4j +@Service +public class DaylightApiService { + + @Resource + private HttpService httpService; + + @Resource + private PropertyCache propertyCache; + + @Resource + private DaylightConfigurationDao dlConfigurationDao; + + @Resource + private PlayerService playerService; + + @Resource + private BookingDao bookingDao; + + @Resource + private RateCodeDao rateCodeDao; + + @Resource + private MarketCodeDao marketCodeDao; + + @Resource + private AgebucketService agebucketService; + + @Resource + private RoomDao roomDao; + + @Resource + private CompPresetDao compPresetDao; + + @Value("${daylight.system-id}") + private String dlSystemId; + + public BaseApiResponse daylightUpsertReservationNew(ReservationRequestDTO requestDTO, String dlPropertyId) { + BaseApiResponse result = new BaseApiResponse<>(); + + try { + String url = "/api-gateway/aggregator/v1/integrations/reservation/multiroom/upsert"; + + Header[] headers = HttpHeaderBuilder.custom() + .contentType("application/json") + .ac_property_id(dlPropertyId) + .build(); + + log.info("Create daylight booking request body: {}", JSON.toJSONString(requestDTO)); + HttpResult httpResult = httpService.sslPost(url, headers, requestDTO); + + if (httpResult.getStatusCode() == 201) { + // TO'DO by Mauve 2026-07-07 + // 这个完成了 by Mauve 2026-07-21 + + String responseData = httpResult.getResult(); + + JSONObject responseJson = JSON.parseObject(responseData); + + if (responseJson.isEmpty()) { + result.setSuccess(false); + result.setMessage("Failed to create DayLight reservation"); + log.warn("Failed to create DayLight reservation, jsonObject is Empty"); + return result; + } + + String reservationId = responseJson.getJSONArray("reservations").getJSONObject(0).getString("id"); + String confirmationNumber = responseJson.getJSONArray("reservations").getJSONObject(0).getString("confirmationNumber"); + + String profileId = ""; + + JSONArray jsonArray = responseJson.getJSONArray("individuals"); + if (!jsonArray.isEmpty()) { + for (int i = 0; i < jsonArray.size(); i++) { + JSONObject jsonObject = jsonArray.getJSONObject(i); + + String refId = jsonObject.getString("_refId"); + + if (refId.startsWith("gus_")) { + profileId = jsonObject.getString("id"); + break; + } + } + } + + JSONObject temp = new JSONObject(); + temp.put("reservationId", reservationId); + temp.put("confirmationNumber", confirmationNumber); + if (StringUtils.isNotBlank(profileId)) { + temp.put("profileId", profileId); + + result.setMessage("Created dayLight reservation and profile success"); + } + + result.setData(temp); + result.setSuccess(true); + if (StringUtils.isBlank(profileId)) { + result.setMessage("Create DayLight reservation success"); + } + + } else if (httpResult.getStatusCode() == 202) { + String operationUrl = ""; + Header[] createHeader = httpResult.getRespHeaders(); + for (Header header : createHeader) { + if (header.getName().equals("Location")) { + operationUrl = header.getValue(); + break; + } + } + + JSONObject jsonObject = this.daylightCallOperationUrl(operationUrl, dlPropertyId); + + if (jsonObject.isEmpty()) { + result.setSuccess(false); + result.setMessage("Failed to create DayLight reservation, jsonObject is Empty"); + log.warn("Failed to create DayLight reservation, jsonObject is Empty"); + return result; + } + + String status = jsonObject + .getJSONObject("status") + .getString("status"); + + if (!"Completed".equalsIgnoreCase(status)) { + + String errorMessage = getFailMessage(jsonObject.getJSONObject("data")); + + result.setSuccess(false); + result.setMessage("Failed to create DayLight reservation, error message: " + errorMessage); + log.warn("Failed to create DayLight reservation, error message: {}", errorMessage); + + return result; + } + + JSONArray jsonArray = jsonObject + .getJSONObject("data") + .getJSONArray("steps"); + + // 创建 reservation + if (jsonArray.size() == 1) { + JSONObject resId = this.getResIdAndConfNo(jsonArray); + + if (resId.isEmpty()) { + + result.setSuccess(false); + result.setMessage("Failed to create DayLight reservation, reservation id is empty"); + log.warn("Failed to create DayLight reservation, reservation id is empty, json: {}", jsonArray.toJSONString()); + } else { + result.setSuccess(true); + result.setData(resId); + log.info("Create reservation successful, reservation id: {}", resId); + } + + // 创建 reservation 并且创建了 profile + } else if (jsonArray.size() == 2) { + + JSONObject profileIdAndResId = this.getProfileIdAndResIdAndConfNo(jsonArray); + + if (profileIdAndResId.isEmpty()) { + result.setSuccess(false); + result.setMessage("Failed to create DayLight reservation, reservation id or profile id is empty"); + log.warn("Failed to create DayLight reservation, reservation id or profile id is empty, json: {}",profileIdAndResId.toJSONString()); + + return result; + } + + String profileId = profileIdAndResId.getString("profileId"); + String resId = profileIdAndResId.getString("reservationId"); + String confirmationNumber = profileIdAndResId.getString("confirmationNumber"); + + JSONObject temp = new JSONObject(); + + if (StringUtils.isNotBlank(profileId)) { + temp.put("profileId", profileId); + } else { + log.warn("ProfileId is empty, maybe this profile is sharer"); + } + + if (StringUtils.isNotBlank(resId)) { + temp.put("reservationId", resId); + } else { + log.warn("ReservationId is empty"); + } + + if (StringUtils.isNotBlank(confirmationNumber)) { + temp.put("confirmationNumber", confirmationNumber); + } else { + log.warn("ConfirmationNumber is empty"); + } + + result.setData(temp); + result.setSuccess(true); + result.setMessage("Created dayLight reservation and profile success"); + + // TO'DO 应该走不到这里才对 by Mauve 2026-07-07 + } else { + result.setSuccess(true); + result.setMessage("Created dayLight reservation and profile success"); + } + } else { + String json = httpResult.getResult(); + JSONObject jsonObject = JSON.parseObject(json); + + String message = null; + + JSONArray details = jsonObject.getJSONArray("details"); + + if (details != null && !details.isEmpty()) { + JSONObject detail = details.getJSONObject(0); + message = detail.getString("message"); + } + + result.setSuccess(false); + result.setMessage(message); + } + + } catch (Exception e) { + result.setSuccess(false); + result.setMessage("Failed to create DayLight reservation"); + log.error("Failed to create DayLight reservation: ", e); + } + + return result; + } + + private String getFailMessage(JSONObject operationData) { + + if (operationData == null) { + return null; + } + + List messages = new ArrayList<>(); + + findErrorMessages(operationData, messages); + + if (messages.isEmpty()) { + return null; + } + + return String.join("\n", messages); + } + + private void findErrorMessages(Object obj, List messages) { + + if (obj instanceof JSONObject jsonObject) { + + Object errorObject = jsonObject.get("error"); + + if (errorObject instanceof JSONObject errorJSON) { + + String message = errorJSON.getString("message"); + + if (message != null && !message.isBlank()) { + System.out.println("Error message: " + message); + messages.add(message); + } + } + + for (Object value : jsonObject.values()) { + findErrorMessages(value, messages); + } + + } else if (obj instanceof JSONArray jsonArray) { + + for (Object item : jsonArray) { + findErrorMessages(item, messages); + } + } + } + + private JSONObject getResIdAndConfNo(JSONArray jsonArray) { + + JSONObject jsonObject = jsonArray.getJSONObject(0); + + String status = jsonObject.getString("stage"); + + if (!"Completed".equalsIgnoreCase(status)) { + return new JSONObject(); + } + + JSONObject properties = jsonObject.getJSONObject("properties"); + JSONArray reservations = properties.getJSONArray("reservations"); + JSONObject reservation = reservations.getJSONObject(0); + + String id = reservation.getString("id"); + String confirmationNumber = reservation.getString("confirmationNumber"); + + JSONObject result = new JSONObject(); + + result.put("reservationId", id); + result.put("confirmationNumber", confirmationNumber); + + return result; + } + + private JSONObject getProfileIdAndResIdAndConfNo(JSONArray jsonArray) { + + JSONObject result = new JSONObject(); + + for (int i = 0; i < jsonArray.size(); i++) { + + JSONObject jsonObject = jsonArray.getJSONObject(i); + + String name = jsonObject.getString("name"); + String stage = jsonObject.getString("stage"); + + if (!"Completed".equalsIgnoreCase(stage)) { + continue; + } + + if ("CreateProfiles".equalsIgnoreCase(name)) { + + JSONObject properties = jsonObject.getJSONObject("properties"); + JSONArray individuals = properties.getJSONArray("individuals"); + + JSONObject profile = individuals.getJSONObject(0); + + String refId = profile.getString("_refId"); + if (refId.startsWith("sha_")) { + continue; + } + + String id = profile.getString("id"); + + result.put("profileId", id); + + continue; + } + + if ("UpsertReservations".equalsIgnoreCase(name)) { + + JSONArray temp = new JSONArray(); + temp.add(jsonObject); + + JSONObject resId = this.getResIdAndConfNo(temp); + + result.put("reservationId", resId.getString("reservationId")); + result.put("confirmationNumber", resId.getString("confirmationNumber")); + } + } + + return result; + } + + public BaseApiResponse daylightUpdateReservationNote( + String dlPropertyId, + String reservationId, + String dlNoteId, + String content, + Integer version) { + + BaseApiResponse result = new BaseApiResponse<>(); + + try { + String url = "/api-gateway/booking/v1/reservations/" + reservationId + "/notes/" + dlNoteId + "/update-content"; + + Header[] headers = HttpHeaderBuilder.custom() + .contentType("application/json") + .ac_property_id(dlPropertyId) + .ifMatch(String.valueOf(version)) + .build(); + + // 参数设置 + Map map = new HashMap<>(); + map.put("content", content); + + HttpResult httpResult = httpService.sslPost(url, headers, map); + + int responsecode = httpResult.getStatusCode(); + + if (responsecode >= 200 && responsecode < 300) { + result.setSuccess(true); + result.setMessage("Update note success"); + log.info("Update note success, reservation id: {}", reservationId); + } else { + result.setSuccess(false); + result.setMessage("Update note failed"); + log.warn("Update note failed, reservation id: {}", reservationId); + } + + } catch (Exception e) { + result.setSuccess(false); + result.setMessage("Update reservation note error"); + log.error("Update reservation note error: ", e); + } + + return result; + } + + public BaseApiResponse daylightGetNoteListById(String dlPropertyId, String reservationId) { + BaseApiResponse result = new BaseApiResponse<>(); + + try { + String url = "/api-gateway/booking/v1/reservations/" + reservationId + "/notes"; + + Header[] headers = HttpHeaderBuilder.custom() + .contentType("application/json") + .ac_property_id(dlPropertyId) + .build(); + + // 参数设置 + Map map = new HashMap<>(); + + HttpResult httpResult = httpService.sslGetHttpResult(url, headers, map); + + int responsecode = httpResult.getStatusCode(); + + if (responsecode >= 200 && responsecode < 300) { + String responseStr = httpResult.getResult(); + + JSONObject jsonObject = JSONObject.parseObject(responseStr); + + JSONArray jsonArray = jsonObject.getJSONArray("results"); + + if (!jsonArray.isEmpty()) { + ReservationNoteResponse object = jsonArray.getObject(0, ReservationNoteResponse.class); + result.setData(object); + result.setSuccess(true); + } else { + result.setSuccess(false); + result.setMessage("No data found"); + } + } else { + result.setSuccess(false); + result.setMessage("Failed to get reservation note, id: " + reservationId); + } + } catch (Exception e) { + log.error("Get reservation note error, id: {}", reservationId, e); + result.setSuccess(false); + result.setMessage("Get reservation note error, id: " + reservationId); + } + + return result; + } + + public BaseApiResponse daylightCancelReservationNew( + String dlReservationId, + String dlPropertyId, + List dlSharerIds, + Long version) { + BaseApiResponse result = new BaseApiResponse<>(); + + try { + if (CollectionUtils.isNotEmpty(dlSharerIds)) { + daylightRemoveAccompanyingGuest(dlReservationId, dlPropertyId, dlSharerIds, version); + } + + String url = "/api-gateway/aggregator/v1/integrations/reservation/multiroom/cancel"; + + Header[] headers = HttpHeaderBuilder.custom() + .contentType("application/json") + .ac_property_id(dlPropertyId) + .build(); + + JSONObject cancelRequest = buildCancelReservationRequest(dlReservationId, dlPropertyId); + + HttpResult httpResult = httpService.sslPost(url, headers, cancelRequest); + + log.info("Cancel reservation response code: {}", httpResult.getStatusCode()); + + if (httpResult.getStatusCode() == 201) { + + log.info("Cancel reservation response success, response code: {}", httpResult.getStatusCode()); + log.info("Cancel reservation response body: {}", JSON.toJSONString(httpResult.getResult())); + + result.setSuccess(true); + result.setMessage("Cancel reservation response success"); + + } else if (httpResult.getStatusCode() == 202) { + + Header[] respHeaders = httpResult.getRespHeaders(); + String operationUrl = ""; + for (Header header : respHeaders) { + if (header.getName().equals("Location")) { + operationUrl = header.getValue(); + break; + } + } + + JSONObject jsonObject = this.daylightCallOperationUrl(operationUrl, dlPropertyId); + + if (jsonObject.isEmpty()) { + result.setSuccess(false); + result.setMessage("Failed to cancel reservation"); + return result; + } + + String status = jsonObject + .getJSONObject("status") + .getString("status"); + + if ("Completed".equalsIgnoreCase(status)) { + String stepStage = jsonObject + .getJSONObject("data") + .getJSONArray("steps") + .getJSONObject(0) + .getString("stage"); + + if ("Completed".equalsIgnoreCase(stepStage)) { + result.setSuccess(true); + result.setMessage("Cancel reservation successful"); + log.info("Cancel reservation: {} successful", dlReservationId); + } else { + result.setSuccess(false); + result.setMessage("Cancel reservation failed"); + log.warn("Cancel reservation: {} failed", dlReservationId); + } + } else { + result.setSuccess(false); + result.setMessage("Failed to cancel reservation"); + log.warn("Failed to cancel reservation: {} failed", dlReservationId); + } + } else { + result.setSuccess(false); + result.setMessage("Failed to cancel reservation, response code: " + httpResult.getStatusCode()); + log.warn("Failed to cancel reservation: {}, response code: {}", dlReservationId, httpResult.getStatusCode()); + } + } catch (Exception e) { + result.setSuccess(false); + result.setMessage("Failed to cancel reservation"); + log.error("Failed to cancel reservation: {}", e.getMessage()); + } + + return result; + } + + private JSONObject daylightCallOperationUrl(String operationUrl, String dlPropertyId) { + + JSONObject jsonObject = new JSONObject(); + try { + Header[] headers = HttpHeaderBuilder.custom() + .contentType("application/json") + .ac_property_id(dlPropertyId) + .build(); + + String responseData; + + int notRunCount = 0; + int inProgressCount = 0; + do { + responseData = httpService.sslGet(operationUrl, headers, new HashMap<>()); + + JSONObject jsonObject1 = JSON.parseObject(responseData); + + String string = + jsonObject1.getJSONObject("status").getString("status"); + + if (string.contains("Fail")) break; + + if (string.contains("NotRun")) { + notRunCount++; + continue; + } + + if (string.contains("InProgress")) { + inProgressCount++; + } + + // 让进程暂停1.5秒 by Mauve 20260909 + TimeUnit.MILLISECONDS.sleep(1500L); + } while ((responseData.contains("InProgress") || responseData.contains("NotRun")) && notRunCount < 20 && inProgressCount < 50); + + jsonObject = JSON.parseObject(responseData); + + } catch (Exception e) { + log.error("Call operation url failed: {}", operationUrl, e); + } + + return jsonObject; + } + + private JSONObject buildCancelReservationRequest(String dlReservationId, String dlPropertyId) { + + JSONObject json = new JSONObject(); + + json.put( + "identity", + new JSONObject() + .fluentPut("id", dlReservationId) + ); + + BaseApiResponse> listBaseApiResponse + = this.daylightGetCancelReasonList(dlPropertyId); + + List cancelReasonList; + if (listBaseApiResponse.isSuccess()) { + cancelReasonList = listBaseApiResponse.getData(); + } else { + throw new RuntimeException("Can not find cancel reason list, message: " + listBaseApiResponse.getMessage()); + } + + String planId = null; + for (CancelReasonResponse cancelReasonResponse : cancelReasonList) { + String code = cancelReasonResponse.getCode(); + if ("PLAN".equalsIgnoreCase(code)) { + planId = cancelReasonResponse.getId(); + break; + } + } + if (StringUtils.isEmpty(planId)) { + planId = cancelReasonList.getFirst().getId(); + } + + json.put("reasonId", planId); + + String processId = UUID.randomUUID().toString(); + + json.put( + "_flowControl", + new JSONObject() + .fluentPut("processId", processId) + ); + + log.info("Cancel reservation process id: {}", processId); + + return json; + } + + public DaylightReservationResponse getDaylightReservationByDlId( + String dlReservationId, + String dlPropertyId + ) { + DaylightReservationResponse resultResponse; + + try { + String url = "/api-gateway/booking/v1/reservations/" + dlReservationId + + "?extend=PurchaseElements,CustomFields"; + // 获取对应的值 + Header[] headers = HttpHeaderBuilder.custom() + .contentType("application/json") + .ac_property_id(dlPropertyId) + .build(); + // 参数设置 + Map map = new HashMap<>(); + + String responseData = httpService.sslGet(url, headers, map); + resultResponse = JSON.parseObject(responseData, DaylightReservationResponse.class); + + } catch (Exception e) { + throw new RuntimeException(e); + } + + return resultResponse; + } + + public BaseApiResponse getReservationDoorKeyByConfirmationNumber( + String dlPropertyId, + String confirmationNumber + ) { + BaseApiResponse result = new BaseApiResponse<>(); + + try { + String url = "/api-gateway/booking/v1/reservations?pageNumber=1&pageSize=200&extend=DoorKeys&filter=confirmationNumber==" + + confirmationNumber; + Header[] headers = HttpHeaderBuilder.custom() + .contentType("application/json") + .ac_property_id(dlPropertyId) + .build(); + Map map = new HashMap<>(); + + HttpResult httpResult = httpService.sslGetHttpResult(url, headers, map); + if (httpResult.getStatusCode() >= 200 && httpResult.getStatusCode() < 300) { + JSONObject response = JSON.parseObject(httpResult.getResult()); + JSONArray reservations = response.getJSONArray("results"); + ReservationDoorKeyResponse doorKeyResponse = new ReservationDoorKeyResponse(); + if (CollectionUtils.isNotEmpty(reservations)) { + JSONObject reservation = reservations.getJSONObject(0); + doorKeyResponse.setId(reservation.getString("id")); + + String roomId = reservation.getString("roomId"); + doorKeyResponse.setRoomId(roomId); + if (StringUtils.isNotBlank(roomId)) { + CfgDaylightConfiguration roomConfig = dlConfigurationDao.findByDlPropertyIdAndConfigName(dlPropertyId, "Room"); + if (roomConfig != null && StringUtils.isNotBlank(roomConfig.getConfigValue())) { + JSONArray roomArray = JSON.parseArray(roomConfig.getConfigValue()); + if (roomArray != null) { + for (int i = 0; i < roomArray.size(); i++) { + JSONObject roomObj = roomArray.getJSONObject(i); + if (roomId.equals(roomObj.getString("id"))) { + doorKeyResponse.setRoomNumber(roomObj.getString("code")); + break; + } + } + } + } + } + + JSONObject embedded = reservation.getJSONObject("_embedded"); + JSONObject doorKeys = embedded == null ? null : embedded.getJSONObject("doorKeys"); + Integer amount = doorKeys == null ? null : doorKeys.getInteger("doorKeyAmount"); + doorKeyResponse.setHasKey(amount != null && amount > 0); + } + result.setData(doorKeyResponse); + result.setSuccess(true); + } else { + result.setSuccess(false); + result.setMessage("Failed to get reservation door key, confirmationNumber: " + confirmationNumber); + log.error("Failed to get reservation door key, confirmationNumber={}, responseCode={}", confirmationNumber, httpResult.getStatusCode()); + } + } catch (Exception e) { + log.error("Get reservation door key error, confirmationNumber: {}", confirmationNumber, e); + result.setSuccess(false); + result.setMessage("Get reservation door key error, confirmationNumber: " + confirmationNumber); + } + + return result; + } + + public BaseApiResponse getReservationQueueByConfirmationNumber( + String dlPropertyId, + String confirmationNumber + ) { + BaseApiResponse result = new BaseApiResponse<>(); + ReservationQueueResponse queueResponse = new ReservationQueueResponse(); + + try { + BaseApiResponse reservationResult = + getReservationDoorKeyByConfirmationNumber(dlPropertyId, confirmationNumber); + ReservationDoorKeyResponse reservationData = reservationResult.getData(); + if (!reservationResult.isSuccess() || reservationData == null || StringUtils.isBlank(reservationData.getId())) { + result.setSuccess(false); + result.setMessage("Failed to get reservation id by confirmation number"); + return result; + } + + String url = "/api-gateway/housekeeping/v1/room-queues/current/reservation/" + reservationData.getId(); + Header[] headers = HttpHeaderBuilder.custom() + .contentType("application/json") + .ac_property_id(dlPropertyId) + .build(); + + HttpResult httpResult = httpService.sslGetHttpResult(url, headers, new HashMap<>()); + if (httpResult.getStatusCode() >= 200 && httpResult.getStatusCode() < 300) { + JSONObject response = JSON.parseObject(httpResult.getResult()); + queueResponse.setId(reservationData.getId()); + queueResponse.setQueue(response != null && response.getJSONObject("current") != null); + result.setSuccess(true); + result.setData(queueResponse); + } else { + result.setSuccess(false); + result.setMessage("Failed to get reservation queue status"); + } + } catch (Exception e) { + result.setSuccess(false); + result.setMessage("Failed to get reservation queue status"); + log.error("Failed to get reservation queue status", e); + } + + return result; + } + + public List dayLightGetGuaranteeType(String dlPropertyId) { + + CfgDaylightConfiguration guaranteeType = + dlConfigurationDao.findByDlPropertyIdAndConfigName(dlPropertyId, "GuaranteeType"); + + String responseData = guaranteeType.getConfigValue(); + + JSONArray jsonObject = JSON.parseArray(responseData); + + List result = new ArrayList<>(); + + for (int i = 0; i < jsonObject.size(); i++) { + + boolean isActive = jsonObject.getJSONObject(i).getBoolean("isActive"); + + if (!isActive) { + continue; + } + + String id = jsonObject.getJSONObject(i).getString("id"); + String code = jsonObject.getJSONObject(i).getString("code"); + + GuaranteeTypeResponse guaranteeTypeResponse = new GuaranteeTypeResponse(); + guaranteeTypeResponse.setId(id); + guaranteeTypeResponse.setCode(code); + + result.add(guaranteeTypeResponse); + } + + return result; + } + + public List dayLightGetDistributeChannel(String dlPropertyId) { + + CfgDaylightConfiguration distributionChannel = + dlConfigurationDao.findByDlPropertyIdAndConfigName(dlPropertyId, "DistributionChannel"); + + String responseData = distributionChannel.getConfigValue(); + + JSONArray jsonObject = JSON.parseArray(responseData); + + List result = new ArrayList<>(); + + for (int i = 0; i < jsonObject.size(); i++) { + + boolean isActive = jsonObject.getJSONObject(i).getBoolean("isActive"); + + if (!isActive) { + continue; + } + + String id = jsonObject.getJSONObject(i).getString("id"); + String code = jsonObject.getJSONObject(i).getString("code"); + + DistributionChannelResponse distributionChannelResponse = new DistributionChannelResponse(); + distributionChannelResponse.setId(id); + distributionChannelResponse.setCode(code); + + result.add(distributionChannelResponse); + } + + return result; + } + + public BaseApiResponse> dayLightGetProfileByPlayerId(String playerId) { + BaseApiResponse> result = new BaseApiResponse<>(); + + List properties = propertyCache.getProperties(); + if (properties == null || properties.isEmpty()) { + log.error("[dayLightGetProfileByPlayerId] No DAYLIGHT properties configured, playerId={}", playerId); + result.setSuccess(false); + result.setMessage("No DAYLIGHT properties configured"); + return result; + } + CfgProperties cfgProperties = properties.getFirst(); + log.info("[dayLightGetProfileByPlayerId] Using property[0] dlPropertyId={}, totalProperties={}, playerId={}", + cfgProperties.getDlPropertyId(), properties.size(), playerId); + + try { + String url = "/api-gateway/profiles/v1/individual"; + // 获取对应的值 + Header[] headers = HttpHeaderBuilder.custom() + .contentType("application/json") + .ac_property_id(cfgProperties.getDlPropertyId()) + .build(); + // 参数设置 + Map map = new HashMap<>(); + map.put("filter", "membershipDetails.manual.number==" + playerId); + + log.info("[dayLightGetProfileByPlayerId] Calling Daylight API, url={}, filter=membershipDetails.manual.number=={}", url, playerId); + HttpResult responseData = httpService.sslGetHttpResult(url, headers, map); + log.info("[dayLightGetProfileByPlayerId] Daylight API response statusCode={}", responseData.getStatusCode()); + Map mapResult = JSON.parseObject(responseData.getResult(), Map.class); + if (responseData.getStatusCode() >= 200 && responseData.getStatusCode() < 300) { + result.setSuccess(true); + + JSONArray results = mapResult.get("results"); + log.info("[dayLightGetProfileByPlayerId] results array={}, size={}", results != null ? "not null" : "null", results != null ? results.size() : 0); + + if (results == null || results.isEmpty()) { + log.warn("[dayLightGetProfileByPlayerId] Daylight returned empty results for playerId={}", playerId); + result.setSuccess(false); + result.setMessage("Daylight profile not found for playerId=" + playerId); + return result; + } + + ProfileDetailResponse object = results.getObject(0, ProfileDetailResponse.class); + log.info("[dayLightGetProfileByPlayerId] Found profile id={}, playerId={}", object != null ? object.getId() : "null", playerId); + + result.setData(List.of(object)); + } else { + result.setSuccess(false); + result.setMessage(responseData.getResult()); + log.warn("[dayLightGetProfileByPlayerId] Daylight API returned non-success statusCode={}, body={}", responseData.getStatusCode(), responseData.getResult()); + } + + } catch (Exception e) { + result.setSuccess(false); + result.setMessage("Failed to get DayLight Profile"); + log.error("[dayLightGetProfileByPlayerId] Failed to get DayLight Profile, playerId={}, error={}", playerId, e.getMessage(), e); + } + + return result; + } + + public ProfileDetailResponse dayLightGetProfileByProfileId(String profileId) { + ProfileDetailResponse result = new ProfileDetailResponse(); + + List properties = propertyCache.getProperties(); + if (properties == null || properties.isEmpty()) { + log.error("[dayLightGetProfileByProfileId] No DAYLIGHT properties configured, profileId={}", profileId); + return result; + } + CfgProperties cfgProperties = properties.getFirst(); + log.info("[dayLightGetProfileByProfileId] Using property[0] dlPropertyId={}, totalProperties={}, profileId={}", + cfgProperties.getDlPropertyId(), properties.size(), profileId); + + try { + String url = "/api-gateway/profiles/v1/individual/"+profileId; + // 获取对应的值 + Header[] headers = HttpHeaderBuilder.custom() + .contentType("application/json") + .ac_property_id(cfgProperties.getDlPropertyId()) + .build(); + // 参数设置 + Map map = new HashMap<>(); + + log.info("[dayLightGetProfileByProfileId] Calling Daylight API, url={}, filter=id=={}", url, profileId); + HttpResult responseData = httpService.sslGetHttpResult(url, headers, map); + log.info("[dayLightGetProfileByProfileId] Daylight API response statusCode={}", responseData.getStatusCode()); + + if (responseData.getStatusCode() >= 200 && responseData.getStatusCode() < 300) { + result = JSON.parseObject(responseData.getResult(), ProfileDetailResponse.class); + } else { + log.warn("[dayLightGetProfileByProfileId] Daylight API returned non-success statusCode={}, body={}", responseData.getStatusCode(), responseData.getResult()); + } + + } catch (Exception e) { + log.error("[dayLightGetProfileByProfileId] Failed to get DayLight Profile, profileId={}, error={}", profileId, e.getMessage(), e); + } + + return result; + } + +// public List daylightGetProfileList(List dlProfileIdList) { +// +// if (CollectionUtils.isEmpty(dlProfileIdList)) { +// log.warn("Profile id list is empty"); +// return Collections.emptyList(); +// } +// +// List result = new ArrayList<>(); +// +// List properties = propertyCache.getProperties(); +// if (properties == null || properties.isEmpty()) { +// log.error("[daylightGetProfileList] No DAYLIGHT properties configured"); +// return result; +// } +// CfgProperties cfgProperties = properties.getFirst(); +// log.info("[dayLightGetProfileByProfileId] Using property[0] dlPropertyId={}, totalProperties={}, profileIdList={}", +// cfgProperties.getDlPropertyId(), properties.size(), dlProfileIdList); +// +// try { +// String url = "/api-gateway/profiles/v1/individual"; +// // 获取对应的值 +// Header[] headers = HttpHeaderBuilder.custom() +// .contentType("application/json") +// .ac_property_id(cfgProperties.getDlPropertyId()) +// .build(); +// // 参数设置 +// Map map = new HashMap<>(); +// +// String temp = dlProfileIdList.stream() +// .map(id -> "id==" + id) +// .collect(Collectors.joining(",")); +// +// map.put("filter", temp); +// +// HttpResult responseData = httpService.sslGetHttpResult(url, headers, map); +// log.info("[dayLightGetProfileByProfileId] Daylight API response statusCode={}", responseData.getStatusCode()); +// +// if (responseData.getStatusCode() >= 200 && responseData.getStatusCode() < 300) { +// +// } else { +// log.warn("[dayLightGetProfileByProfileId] Daylight API returned non-success statusCode={}, body={}", responseData.getStatusCode(), responseData.getResult()); +// } +// +// } catch (Exception e) { +// log.error("[dayLightGetProfileByProfileId] Failed to get DayLight Profile, profileId={}, error={}", profileId, e.getMessage(), e); +// } +// +// return result; +// } + + public List daylightAgebucketResponseList(String dlPropertyId) { + + CfgDaylightConfiguration daylightConfiguration = dlConfigurationDao.findByDlPropertyIdAndConfigName(dlPropertyId, "Agebucket"); + String responseData = daylightConfiguration.getConfigValue(); + + JSONArray jsonObject = JSON.parseArray(responseData); + + List result = new ArrayList<>(); + + for (int i = 0; i < jsonObject.size(); i++) { + + boolean isActive = jsonObject.getJSONObject(i).getBoolean("isActive"); + + if (!isActive) { + continue; + } + + String id = jsonObject.getJSONObject(i).getString("id"); + String code = jsonObject.getJSONObject(i).getString("code"); + + AgebucketResponse agebucketResponse = new AgebucketResponse(); + agebucketResponse.setId(id); + agebucketResponse.setCode(code); + + result.add(agebucketResponse); + } + + return result; + } + + public List getBookingRecordByProfileId_Optimize(String profileId, String playerId) { + List bookingList = new ArrayList<>(); + + propertyCache.refresh(); + List properties = propertyCache.getProperties(); + if (properties == null || properties.isEmpty()) { + log.warn("[getBookingRecordByProfileId_Optimize] No DAYLIGHT properties found, profileId={}", profileId); + return bookingList; + } + log.info("[getBookingRecordByProfileId_Optimize] totalProperties={}, profileId={}", properties.size(), profileId); + +// String currentDate = DateTimeUtil.getCurrentDate("yyyy-MM-dd"); + + String url = "/api-gateway/aggregator/v1/reservations?pageNumber=1&pageSize=40&filter=profileId==" + profileId + + ";(statusCode.code==DI,statusCode.code==RS,statusCode.code==DO,statusCode.code==IH,statusCode.code==CX)" +// + ";departureDate=ge=" + currentDate + + "&extend=PurchaseElements,CustomFields,Breakdown,DoorKeys&sort=-createdAt"; + Map map = new HashMap<>(); + try { + for (CfgProperties property : properties) { + String dlPropertyId = property.getDlPropertyId(); + if (StringUtils.isBlank(dlPropertyId)) { + log.warn("[getBookingRecordByProfileId_Optimize] Skipping property with null/blank dlPropertyId, propertyName={}", property.getName()); + continue; + } + Header[] headers = HttpHeaderBuilder.custom() + .contentType("application/json") + .ac_property_id(dlPropertyId) + .build(); + log.info("[getBookingRecordByProfileId_Optimize] Querying property dlPropertyId={}", dlPropertyId); + String responseData = httpService.sslGet(url, headers, map); + JSONObject res = JSON.parseObject(responseData); + JSONArray bookings = res.getJSONArray("results"); + log.info("[getBookingRecordByProfileId_Optimize] Property dlPropertyId={}, bookings array size={}", dlPropertyId, bookings != null ? bookings.size() : 0); + bookingList.addAll(convertBookingDtoList(bookings, dlPropertyId, playerId)); + } + } catch (Exception e) { + log.error("[getBookingRecordByProfileId_Optimize] Exception while querying Daylight bookings, profileId={}, error={}", profileId, e.getMessage(), e); + throw new RuntimeException(e); + } + log.info("[getBookingRecordByProfileId_Optimize] Total bookings collected={}", bookingList.size()); + return bookingList; + } + + public List convertBookingDtoList(JSONArray bookings, String dlPropertyId, String playerId){ + List bookingList = new ArrayList<>(); + if(bookings==null || bookings.isEmpty()) { + log.info("[convertBookingDtoList] bookings is null or empty for dlPropertyId={}", dlPropertyId); + return bookingList; + } + log.info("[convertBookingDtoList] Processing {} raw bookings for dlPropertyId={}", bookings.size(), dlPropertyId); + Date currentTime = new Date(); + int skippedByCheckout = 0; + + for (int i = 0; i < bookings.size(); i++) { + + JSONObject bookingRes = bookings.getJSONObject(i); + BookingDto booking = new BookingDto(); + + Date checkinDate = DateTimeUtil.getDateFromString(bookingRes.getString("arrivalDate"),"yyyy-MM-dd"); + Date checkoutDate = DateTimeUtil.getDateFromString(bookingRes.getString("departureDate"),"yyyy-MM-dd"); + + LocalDate checkoutLocalDate = LocalDate.parse( + bookingRes.getString("departureDate"), + DateTimeFormatter.ofPattern("yyyy-MM-dd") + ); + + LocalDate currentDate = LocalDate.now(); + +// if (checkoutLocalDate.isBefore(currentDate)) { +// skippedByCheckout++; +// continue; +// } + + JSONArray jsonArray = bookingRes.getJSONArray("externalIds"); + if (CollectionUtils.isNotEmpty(jsonArray)) { + String dlExternalNo = jsonArray.getJSONObject(0).getString("number"); + booking.setDlExternalNo(dlExternalNo); + } else { + + String dlExternalNo = "UP1-" + UUID.randomUUID().toString().replace("-", ""); + + this.daylightSetExternalNo( + dlPropertyId, + bookingRes.getString("id"), + dlExternalNo, + bookingRes.getInteger("version") + ); + + booking.setDlExternalNo(dlExternalNo); + } + + booking.setPlayerId(playerId); + booking.setConfirmationNo(bookingRes.getString("confirmationNumber")); + booking.setDlReservationId(bookingRes.getString("id")); + booking.setCheckinDate(checkinDate); + booking.setCheckoutDate(checkoutDate); + booking.setDlAccountId(bookingRes.getString("accountId")); + booking.setDlChannelId(bookingRes.getString("channelId")); + booking.setDlSourceId(bookingRes.getString("sourceId")); + booking.setDlPropertyId(dlPropertyId); + booking.setDlRoomTypeId(bookingRes.getString("roomTypeId")); + booking.setDlReservationId(bookingRes.getString("id")); + booking.setDlGuaranteeTypeId(bookingRes.getString("guaranteeTypeId")); + booking.setDlProfileId(bookingRes.getString("profileId")); + booking.setDlBlockId(bookingRes.getString("blockId")); + + JSONObject sc = bookingRes.getJSONObject("statusCode"); + + booking.setLastOperaStatus(EnumBookingStatus.getStatusByDaylightStatus(sc.getString("description").toUpperCase())); + + String approveStatus = "CANCELED".equalsIgnoreCase(booking.getLastOperaStatus()) ? "C" : "N"; + booking.setApproveStatus(approveStatus); + + JSONObject embedded = bookingRes.getJSONObject("_embedded"); + if (embedded == null) { + log.warn("[convertBookingDtoList] _embedded is null for reservation id={}, confirmationNo={}, dlPropertyId={}", + bookingRes.getString("id"), bookingRes.getString("confirmationNumber"), dlPropertyId); + } else { + JSONArray customFields = embedded.getJSONArray("customFields"); + + if (customFields != null) { + for (int j = 0; j < customFields.size(); j++) { + JSONObject jsonObject = customFields.getJSONObject(j); + String value = jsonObject.getString("value"); + JSONObject valueJson = JSON.parseObject(value); + String booker = valueJson.getString("Booker"); + String approver = valueJson.getString("Approver"); + + if (StringUtils.isNotBlank(booker)) { + booking.setCreatedBy(booker); + booking.setBooker(booker); + } + + if (StringUtils.isNotBlank(approver)) { + // TODO 看看是要设置进approver还是approverdBy by Mauve 2026-07-07 + } + } + } + + JSONObject purchaseElementsJSON = embedded.getJSONObject("purchaseElements"); + + if (purchaseElementsJSON != null) { + JSONArray results = purchaseElementsJSON.getJSONArray("results"); + + String purchaseElementsId = null; + if (results != null && !results.isEmpty()) { + purchaseElementsId = results.getJSONObject(0).getString("id"); + } + + booking.setDlPurchaseElementId(purchaseElementsId); + } + + // Extract marketSegmentId and ratePlanId from breakdown, then resolve to code + JSONObject breakdownJSON = embedded.getJSONObject("breakdown"); + if (breakdownJSON != null) { + JSONArray breakdownResults = breakdownJSON.getJSONArray("results"); + if (breakdownResults != null && !breakdownResults.isEmpty()) { + JSONObject firstBreakdown = breakdownResults.getJSONObject(0); + String marketSegmentId = firstBreakdown.getString("marketSegmentId"); + JSONObject ratePricingDetails = firstBreakdown.getJSONObject("ratePricingDetails"); + String ratePlanId = ratePricingDetails != null ? ratePricingDetails.getString("ratePlanId") : null; + + if (StringUtils.isNotBlank(marketSegmentId)) { + CfgMarketCodes marketCode = marketCodeDao.findByDlMarketSegmentId(marketSegmentId); + if (marketCode != null) { + booking.setMarketCode(marketCode.getCode()); + } else { + log.warn("[convertBookingDtoList] MarketCode not found for dlMarketSegmentId={}, dlPropertyId={}", marketSegmentId, dlPropertyId); + } + } + if (StringUtils.isNotBlank(ratePlanId)) { + CfgRateCodes rateCode = rateCodeDao.findByDlRatePlanId(ratePlanId); + if (rateCode != null) { + booking.setRatePlanCode(rateCode.getCode()); + } else { + log.warn("[convertBookingDtoList] RateCode not found for dlRatePlanId={}, dlPropertyId={}", ratePlanId, dlPropertyId); + } + } + } + } + } + + String eta = bookingRes.getString("eta"); + if (eta != null) { + LocalDateTime dateTime = LocalDateTime.parse(eta); + String etaTime = dateTime.format(DateTimeFormatter.ofPattern("HH:mm")); + booking.setEta(etaTime); + } + booking.setDataTime(currentTime); + + JSONArray sharerArray = new JSONArray(); + //share + if(bookingRes.containsKey("accompanyingGuestProfileIds")){ + JSONArray sharerList = bookingRes.getJSONArray("accompanyingGuestProfileIds"); + if(!sharerList.isEmpty()){ + for (Object obj : sharerList) { + String profileId = String.valueOf(obj); + ProfileDetailResponse profileObj = this.dayLightGetProfileByProfileId(profileId); + String sharerPlayerId = ""; + String sharerName = ""; + try{ + sharerPlayerId = profileObj.getMemberships().getFirst().getNumber(); + } catch (Exception e) { + + } + String firstName = profileObj.getDetails().getFirstName(); + String lastName = profileObj.getDetails().getLastName(); + + if (lastName != null && firstName != null) { + sharerName = lastName + firstName; + } else if (lastName != null) { + sharerName = lastName; + } else if (firstName != null) { + sharerName = firstName; + } + if(!sharerPlayerId.isEmpty()){ + BaseApiResponse findPlayerResult = playerService.findPlayerProfileByPlayerIdAndUserId(sharerPlayerId, booking.getCreatedBy()); + if(findPlayerResult.isSuccess()) { + PlayerProfileEntry profile = findPlayerResult.getData(); + JSONObject sharerPlayer = new JSONObject(); + sharerPlayer.put("playerId", sharerPlayerId); + sharerPlayer.put("name", profile.getName()); + sharerPlayer.put("tierName", profile.getTierName()); + sharerArray.add(sharerPlayer); + } + }else if(!sharerName.isEmpty()){ + JSONObject sharerPlayer = new JSONObject(); + sharerPlayer.put("playerId", ""); + sharerPlayer.put("name", sharerName); + sharerPlayer.put("tierName", ""); + sharerArray.add(sharerPlayer); + } + + } + } + } + booking.setSharer(sharerArray.toJSONString()); + + bookingList.add(booking); + } + log.info("[convertBookingDtoList] dlPropertyId={}, raw={}, converted={}, skippedByCheckout={}", + dlPropertyId, bookings.size(), bookingList.size(), skippedByCheckout); + return bookingList; + } + + public BaseApiResponse daylightGetCompRulesByAccount(String dlPropertyId, String dlAccountId) { + BaseApiResponse result = new BaseApiResponse<>(); + JSONArray array = null; + try { + String url = "/api-gateway/cashiering/v1/accounts/" + dlAccountId + "/complimentary-rules"; + // 获取对应的值 + Header[] headers = HttpHeaderBuilder.custom() + .contentType("application/json") + .ac_property_id(dlPropertyId) + .build(); + // 参数设置 + Map map = new HashMap<>(); + + String responseData = httpService.sslGet(url, headers, map); + + array = JSON.parseArray(responseData); + + } catch (Exception e) { + result.setSuccess(false); + result.setMessage("Failed to get dayLight comp rules for account: " + dlAccountId); + log.error("Failed to get dayLight comp rules: ", e); + } + + result.setSuccess(true); + result.setData(array); + + return result; + } + + public BaseApiResponse updateDaylightCompRule( + String dlAccountId, + String dlPropertyId, + String dlCompRuleId, + String version, + UpdateCompRuleRequest request + ) { + try { + String url = "/api-gateway/cashiering/v1/accounts/" + dlAccountId + "/complimentary-rules/" + dlCompRuleId; + + Header[] headers = HttpHeaderBuilder.custom() + .contentType("application/json") + .ac_property_id(dlPropertyId) + .ifMatch(String.valueOf(version)) + .build(); + + return updateCompRule(url, headers, request); + } catch (Exception e) { + BaseApiResponse response = new BaseApiResponse<>(); + response.setSuccess(false); + response.setMessage(e.getMessage()); + LogUtil.error(DaylightApiService.class, e.getMessage()); + + return response; + } + } + + public BaseApiResponse getDaylightCompRule( + String dlPropertyId, + String dlAccountId, + String dlCompRuleId + ) { + BaseApiResponse response = new BaseApiResponse<>(); + + try { + String url = "/api-gateway/cashiering/v1/accounts/" + dlAccountId + "/complimentary-rules/" + dlCompRuleId; + + Header[] headers = HttpHeaderBuilder.custom() + .contentType("application/json") + .ac_property_id(dlPropertyId) + .build(); + + Map map = new HashMap<>(); + + HttpResult httpResult = httpService.sslGetHttpResult(url, headers, map); + + if (httpResult.getStatusCode() == 200) { + CompRuleResponse crr = JSON.parseObject(httpResult.getResult(), CompRuleResponse.class); + response.setSuccess(true); + response.setData(crr); + } + } catch (Exception e) { + response.setSuccess(false); + response.setMessage(e.getMessage()); + LogUtil.error(DaylightApiService.class, e.getMessage()); + } + + return response; + } + + public BaseApiResponse updateDaylightCompRule( + String dlAccountId, + String dlPropertyId, + String startDate, + String endDate, + CfgDaylightView daylightView, + String miscCharge + ) { + BaseApiResponse result = new BaseApiResponse<>(); + + BaseApiResponse compRuleListResponse = daylightGetCompRulesByAccount(dlPropertyId, dlAccountId); + + if (!compRuleListResponse.isSuccess() || compRuleListResponse.getData() == null) { + result.setSuccess(false); + result.setMessage(compRuleListResponse.getMessage()); + return result; + } + + JSONArray compRuleList = compRuleListResponse.getData(); + + boolean foundCompRule = false; + boolean updateFailed = false; + String failedMessage = null; + try { + ComplimentaryRuleLimits crl = getMiscChargeComplimentaryRuleLimits( + startDate, endDate, miscCharge, daylightView.getSoftLimit()); + + for (int i = 0; i < compRuleList.size(); i++) { + JSONObject one = compRuleList.getJSONObject(i); + JSONObject complimentaryRuleLimits = one.getJSONObject("complimentaryRuleLimits"); + JSONObject totalAmountLimit = complimentaryRuleLimits == null + ? null : complimentaryRuleLimits.getJSONObject("totalAmountLimit"); + + if (totalAmountLimit == null) { + continue; + } + + foundCompRule = true; + String needCompRulesId = one.getString("id"); + Long version = one.getLong("version"); + String url = "/api-gateway/cashiering/v1/accounts/" + dlAccountId + "/complimentary-rules/" + needCompRulesId; + Header[] headers = HttpHeaderBuilder.custom() + .contentType("application/json") + .ac_property_id(dlPropertyId) + .ifMatch(String.valueOf(version)) + .build(); + UpdateCompRuleRequest updateCompRuleRequest = new UpdateCompRuleRequest(); + updateCompRuleRequest.setComplimentaryRuleLimits(crl); + + log.info("Update comp rule which has misc charge, compRuleId={}", needCompRulesId); + BaseApiResponse updateResponse = updateCompRule(url, headers, updateCompRuleRequest); + if (!updateResponse.isSuccess()) { + updateFailed = true; + if (failedMessage == null) { + failedMessage = updateResponse.getMessage(); + } + } + } + + if (!foundCompRule) { + result.setSuccess(false); + result.setMessage("Not found comp rule"); + } else if (updateFailed) { + result.setSuccess(false); + result.setMessage(failedMessage); + } else { + result.setSuccess(true); + } + } catch (Exception e) { + result.setSuccess(false); + result.setMessage(e.getMessage()); + log.error("Update comp rule failed", e); + } + + return result; + } + + public BaseApiResponse createDaylightCompRule( + String dlAccountId, + String profileId, + String dlPropertyId, + String userId, + String startDate, + String endDate, + List daylightViewList, + String miscCharge + ) { + + BaseApiResponse result = new BaseApiResponse<>(); + + log.info("Start to create complimentary rule"); + + String dlBookingTypeName = daylightViewList.getFirst().getBookingType().getName(); + + if ("IM".equalsIgnoreCase(dlBookingTypeName)) { + result.setSuccess(false); + result.setMessage("IM booking type don't need to create complimentary rules"); + log.info("IM booking type don't need to create complimentary rules"); + return result; + } + + BaseApiResponse jsonArrayBaseApiResponse = daylightGetCompRulesByAccount(dlPropertyId, dlAccountId); + if (!jsonArrayBaseApiResponse.isSuccess() || jsonArrayBaseApiResponse.getData() == null) { + result.setSuccess(false); + result.setMessage(jsonArrayBaseApiResponse.getMessage()); + return result; + } + + int compRuleCount = jsonArrayBaseApiResponse.getData().size(); + boolean hasMiscCharge = miscCharge != null; + boolean createRoomOnlyCompRule = compRuleCount == 0; + boolean createDaylightViewCompRule = hasMiscCharge && compRuleCount <= 1; + + CfgDaylightView daylightViewRoomOnly = null; + CfgDaylightView daylightView = null; + + for (CfgDaylightView d : daylightViewList) { + if (d.getCompRuleCategory() == 1) { + daylightViewRoomOnly = d; + continue; + } + if (d.getCompRuleCategory() == 2) { + daylightView = d; + } + } + + if (daylightViewRoomOnly == null && daylightView == null) { + result.setSuccess(false); + result.setMessage("Daylight view room only and daylight view are null"); + return result; + } + + if (compRuleCount >= 2) { + try { + return updateDaylightCompRule(dlAccountId, dlPropertyId, startDate, endDate, daylightView, miscCharge); + } catch (Exception e) { + result.setSuccess(false); + result.setMessage(e.getMessage()); + LogUtil.error(DaylightApiService.class, e.getMessage()); + return result; + } + } + + if (!createRoomOnlyCompRule && !createDaylightViewCompRule) { + result.setSuccess(true); + result.setMessage("No CompRule created"); + return result; + } + + try { + String url = "/api-gateway/cashiering/v1/accounts/" + dlAccountId + "/complimentary-rules"; + Header[] headers = HttpHeaderBuilder.custom() + .contentType("application/json") + .ac_property_id(dlPropertyId) + .build(); + + String approver = daylightViewRoomOnly.getApprover(); + + BaseApiResponse requestorApproverByUserId; + if (StringUtils.isNotEmpty(approver)) { + requestorApproverByUserId = getDaylightRequestorApproverByUserId(dlPropertyId, approver); + } else { + requestorApproverByUserId = getDaylightRequestorApproverByUserId(dlPropertyId, userId); + } + + // 如果查不到 requestor/approver 直接返回 false + if (!requestorApproverByUserId.isSuccess()) { + result.setSuccess(false); + result.setMessage(requestorApproverByUserId.getMessage()); + + return result; + } + + RequestorApproverResponse returnData = requestorApproverByUserId.getData(); + + if (createRoomOnlyCompRule && daylightViewRoomOnly != null) { + CreateCompRuleRequest roomOnlyCompRuleRequest = buildRoomOnlyCompRuleRequest( + profileId, startDate, endDate, returnData, daylightViewRoomOnly,false); + BaseApiResponse createDefaultResult = createCompRule(url, headers, roomOnlyCompRuleRequest); + if (!createDefaultResult.isSuccess()) { + return createDefaultResult; + } + } + + if (createDaylightViewCompRule) { + BaseApiResponse daylightViewCompRuleRequest = buildDaylightViewCompRuleRequest( + profileId, startDate, endDate, daylightView, returnData, miscCharge); + if (!daylightViewCompRuleRequest.isSuccess()) { + result.setSuccess(false); + result.setMessage(daylightViewCompRuleRequest.getMessage()); + return result; + } + + BaseApiResponse createDaylightViewResult = createCompRule(url, headers, daylightViewCompRuleRequest.getData()); + if (!createDaylightViewResult.isSuccess()) { + return createDaylightViewResult; + } + } + + result.setSuccess(true); + result.setMessage("Create CompRule success"); + + } catch (Exception e) { + result.setSuccess(false); + result.setMessage(e.getMessage()); + LogUtil.error(DaylightApiService.class, "Error message: " + e.getMessage()); + } + + log.info("End to create complimentary rule, isSuccess={}", result.isSuccess()); + + return result; + } + + public BaseApiResponse createDaylightNewRoomOnlyCompRule( + String dlAccountId, + String profileId, + String dlPropertyId, + String userId, + String startDate, + String endDate, + CfgDaylightView daylightViewRoomOnly + ) { + + BaseApiResponse result = new BaseApiResponse<>(); + + log.info("Start to create new room only complimentary rule"); + + String dlBookingTypeName = daylightViewRoomOnly.getBookingType().getName(); + + if ("IM".equalsIgnoreCase(dlBookingTypeName)) { + result.setSuccess(false); + result.setMessage("IM booking type don't need to create complimentary rules"); + log.info("IM booking type don't need to create complimentary rules"); + return result; + } + + try { + String url = "/api-gateway/cashiering/v1/accounts/" + dlAccountId + "/complimentary-rules"; + Header[] headers = HttpHeaderBuilder.custom() + .contentType("application/json") + .ac_property_id(dlPropertyId) + .build(); + + String approver = daylightViewRoomOnly.getApprover(); + + BaseApiResponse requestorApproverByUserId; + if (StringUtils.isNotEmpty(approver)) { + requestorApproverByUserId = getDaylightRequestorApproverByUserId(dlPropertyId, approver); + } else { + requestorApproverByUserId = getDaylightRequestorApproverByUserId(dlPropertyId, userId); + } + + // 如果查不到 requestor/approver 直接返回 false + if (!requestorApproverByUserId.isSuccess()) { + result.setSuccess(false); + result.setMessage(requestorApproverByUserId.getMessage()); + + return result; + } + + RequestorApproverResponse returnData = requestorApproverByUserId.getData(); + + CreateCompRuleRequest roomOnlyCompRuleRequest = buildRoomOnlyCompRuleRequest( + profileId, startDate, endDate, returnData, daylightViewRoomOnly,true); + BaseApiResponse createDefaultResult = createCompRule(url, headers, roomOnlyCompRuleRequest); + if (!createDefaultResult.isSuccess()) { + return createDefaultResult; + } + + result.setSuccess(true); + result.setMessage("Create CompRule success"); + + } catch (Exception e) { + result.setSuccess(false); + result.setMessage(e.getMessage()); + LogUtil.error(DaylightApiService.class, "Error message: " + e.getMessage()); + } + + log.info("End to create complimentary rule, isSuccess={}", result.isSuccess()); + + return result; + } + + private CreateCompRuleRequest buildRoomOnlyCompRuleRequest( + String profileId, + String startDate, + String endDate, + RequestorApproverResponse requestorApprover, + CfgDaylightView daylightView, + boolean setRuleLimits) { + CreateCompRuleRequest crr = new CreateCompRuleRequest(); + + crr.setComplimentaryTypeId(daylightView.getDlCompTypeId()); + crr.setPaymentMethodTransactionCodeId(daylightView.getDlPaymentMethodCodeId()); + crr.setExecutive(false); + crr.setDoNotIssueInvoice(false); + crr.setProfileId(profileId); + if(setRuleLimits) crr.setComplimentaryRuleLimits(getComplimentaryRuleLimits(startDate, endDate)); + + List compPresetList = compPresetDao.findAllByDaylightMappingId(daylightView.getId()); + CfgCompPreset compPreset = compPresetList.getFirst(); + + crr.setComplimentaryAccountingPresetsIds(List.of(compPreset.getDlCompPresetId())); + crr.setJustification(""); + crr.setRequestorId(requestorApprover.getId()); + crr.setApproverId(requestorApprover.getId()); + + return crr; + } + + private BaseApiResponse buildDaylightViewCompRuleRequest( + String profileId, + String startDate, + String endDate, + CfgDaylightView daylightView, + RequestorApproverResponse requestorApprover, + String miscCharge) { + BaseApiResponse result = new BaseApiResponse<>(); + + if (daylightView == null) { + result.setSuccess(false); + result.setMessage("Daylight config is empty"); + log.error("Daylight config is empty"); + return result; + } + + if (StringUtils.isBlank(daylightView.getDlCompTypeId())) { + result.setSuccess(false); + result.setMessage("Daylight comp type id is empty"); + log.error("Daylight comp type id is empty"); + return result; + } + + if (StringUtils.isBlank(daylightView.getDlPaymentMethodCodeId())) { + result.setSuccess(false); + result.setMessage("Daylight payment method code id is empty"); + log.error("Daylight payment method code id is empty"); + return result; + } + + List capIds = new ArrayList<>(); + if (CollectionUtils.isEmpty(daylightView.getCfgCompPresetList())) { + result.setSuccess(false); + result.setMessage("Daylight comp preset id is empty"); + log.error("Daylight comp preset id is empty"); + return result; + } + + for (CfgCompPreset cfgCompPreset : daylightView.getCfgCompPresetList()) { + if (cfgCompPreset != null && StringUtils.isNotBlank(cfgCompPreset.getDlCompPresetId())) { + capIds.add(cfgCompPreset.getDlCompPresetId()); + } + } + + List distinctCapIds = new ArrayList<>(new HashSet<>(capIds)); + + if (CollectionUtils.isEmpty(capIds)) { + result.setSuccess(false); + result.setMessage("Daylight comp preset id is empty"); + log.error("Daylight comp preset id is empty"); + return result; + } + + CreateCompRuleRequest crr = new CreateCompRuleRequest(); + crr.setComplimentaryTypeId(daylightView.getDlCompTypeId()); + crr.setPaymentMethodTransactionCodeId(daylightView.getDlPaymentMethodCodeId()); + crr.setExecutive(false); + crr.setDoNotIssueInvoice(false); + crr.setProfileId(profileId); + crr.setComplimentaryRuleLimits(getMiscChargeComplimentaryRuleLimits(startDate, endDate, miscCharge, daylightView.getSoftLimit())); + crr.setComplimentaryAccountingPresetsIds(distinctCapIds); + crr.setJustification(""); + crr.setRequestorId(requestorApprover.getId()); + crr.setApproverId(requestorApprover.getId()); + + result.setSuccess(true); + result.setData(crr); + return result; + } + + private BaseApiResponse updateCompRule(String url, Header[] headers, UpdateCompRuleRequest urr) throws Exception { + BaseApiResponse result = new BaseApiResponse<>(); + + log.info("Create comp rule request params: {}", JSON.toJSONString(urr)); + HttpResult httpResult = httpService.sslPatch(url, headers, urr); + + if (httpResult.getStatusCode() == 204) { + result.setSuccess(true); + result.setMessage("Update CompRule success"); + } else { + result.setSuccess(false); + result.setMessage("Update CompRule failed"); + result.setLogMessage(httpResult.getResult()); + + LogUtil.error(BookingService.class, "[recordSearch] updateDaylightCompRule failed: " + httpResult.getResult()); + } + + return result; + } + + private BaseApiResponse createCompRule(String url, Header[] headers, CreateCompRuleRequest crr) throws Exception { + BaseApiResponse result = new BaseApiResponse<>(); + + log.info("Create comp rule request params: {}", JSON.toJSONString(crr)); + HttpResult httpResult = httpService.sslPost(url, headers, crr); + + if (httpResult.getStatusCode() == 201) { + result.setSuccess(true); + result.setMessage("Create CompRule success"); + } else { + result.setSuccess(false); + result.setMessage("Create CompRule failed"); + result.setLogMessage(httpResult.getResult()); + + LogUtil.error(BookingService.class, "[recordSearch] createDaylightCompRule failed: " + httpResult.getResult()); + } + + return result; + } + + /** + * TODO 暂时写死, 之后参数可能需要多加几个 by Mauve + * @param startDate + * @param endDate + * @return + */ + private static @NonNull ComplimentaryRuleLimits getComplimentaryRuleLimits(String startDate, String endDate) { + + CompRuleDateRange dateRange = new CompRuleDateRange(); + dateRange.setStart(startDate); + dateRange.setEnd(endDate); + + ComplimentaryRuleLimits complimentaryRuleLimits = new ComplimentaryRuleLimits(); + complimentaryRuleLimits.setDateRanges(List.of(dateRange)); + + return complimentaryRuleLimits; + } + + private static @NonNull ComplimentaryRuleLimits getMiscChargeComplimentaryRuleLimits( + String startDate, + String endDate, + String miscCharge, + String daylightPercentage + ) { + CompRuleDateRange dateRange = new CompRuleDateRange(); + dateRange.setStart(startDate); + dateRange.setEnd(endDate); + + AmountLimit totalAmountLimit = new AmountLimit(); + totalAmountLimit.setCurrency("MOP"); + totalAmountLimit.setAmount(new BigDecimal(miscCharge.trim())); + + AmountLimit softTotalAmountLimit = new AmountLimit(); + softTotalAmountLimit.setCurrency("MOP"); + softTotalAmountLimit.setAmount(calculateAmount(miscCharge.trim(), daylightPercentage)); + + ComplimentaryRuleLimits complimentaryRuleLimits = new ComplimentaryRuleLimits(); +// complimentaryRuleLimits.setDateRanges(List.of(dateRange)); + + complimentaryRuleLimits.setTotalAmountLimit(totalAmountLimit); + + complimentaryRuleLimits.setSoftTotalAmountLimit(softTotalAmountLimit); + + return complimentaryRuleLimits; + } + + // 使用BigDecimal来计算金额以保留精度 by Mauve 2026-07-22 + private static BigDecimal calculateAmount(String amountStr, String percentStr) { + + BigDecimal amount = new BigDecimal(amountStr); + + BigDecimal percent = new BigDecimal(percentStr) + .divide(BigDecimal.valueOf(100), 4, RoundingMode.HALF_UP); + + return amount.multiply(percent) + .setScale(2, RoundingMode.HALF_UP); + } + + public BaseApiResponse getDaylightRequestorApproverByUserId(final String propertyId, final String userId) { + BaseApiResponse serviceResult = new BaseApiResponse<>(); + + try { + String url = "/api-gateway/resource-management/v1/resource?filter=code==" + userId + ";isActive==true"; + // 获取对应的值 + Header[] headers = HttpHeaderBuilder.custom() + .contentType("application/json") + .ac_property_id(propertyId) + .build(); + // 参数设置 + Map map = new HashMap<>(); + String responseData = httpService.sslGet(url, headers, map); + JSONObject res = JSON.parseObject(responseData); + JSONArray raJson = res.getJSONArray("results"); + + RequestorApproverResponse result = convertRequestorApprover(raJson); + + if (result != null) { + serviceResult.setSuccess(true); + serviceResult.setData(result); + } else { + serviceResult.setSuccess(false); + serviceResult.setMessage("Convert failed"); + } + } catch (Exception e) { + serviceResult.setSuccess(false); + serviceResult.setMessage("Get requestor approver by userId failed"); + LogUtil.error(DaylightApiService.class, e.getMessage()); + } + + return serviceResult; + } + + private RequestorApproverResponse convertRequestorApprover(JSONArray raJson) { + + if (raJson == null || raJson.isEmpty()) return null; + + RequestorApproverResponse result = new RequestorApproverResponse(); + + // TODO 正常来讲应该只有一条数据在 raJson 中,而不会有多条数据 by Mauve + JSONObject jsonObject = raJson.getJSONObject(0); + + result.setId(jsonObject.getString("id")); + result.setFirstName(jsonObject.getString("firstName")); + result.setLastName(jsonObject.getString("lastName")); + result.setCode(jsonObject.getString("code")); + result.setVersion(jsonObject.getInteger("version")); + + return result; + } + + @Deprecated + public BaseApiResponse daylightReservationSetBlock( + String reservationId, + String propertyId, + String blockId) { + BaseApiResponse serviceResult = new BaseApiResponse<>(); + + try { + String url = "/api-gateway/booking/v1/reservations/" + reservationId + "/move-to-block"; + // 获取对应的值 + Header[] headers = HttpHeaderBuilder.custom() + .contentType("application/json") + .ac_property_id(propertyId) + .build(); + + DaylightReservationResponse daylightReservationByDlId = getDaylightReservationByDlId(reservationId, propertyId); + Long version = daylightReservationByDlId.getVersion(); + + Map map = new HashMap<>(); + map.put("blockId", blockId); + map.put("version", version); + + HttpResult httpResult = httpService.sslPost(url, headers, map); + + if (httpResult.getStatusCode() >= 200 && httpResult.getStatusCode() < 300) { + serviceResult.setSuccess(true); + + LogUtil.info(DaylightApiService.class, "Set block Success"); + } else { + serviceResult.setSuccess(false); + serviceResult.setMessage("Set block failed"); + serviceResult.setLogMessage(httpResult.getResult()); + + LogUtil.error(DaylightApiService.class, "Set block failure"); + } + } catch (Exception e) { + serviceResult.setSuccess(false); + serviceResult.setMessage("Set block failed"); + LogUtil.error(DaylightApiService.class, e.getMessage()); + } + + return serviceResult; + } + + public BaseApiResponse daylightRemoveAccompanyingGuest( + String reservationId, + String dlPropertyId, + List dlSharerIds, + Long verion) { + BaseApiResponse serviceResult = new BaseApiResponse<>(); + + if (CollectionUtils.isEmpty(dlSharerIds)) { + serviceResult.setSuccess(true); + serviceResult.setMessage("Sharer does not exist"); + return serviceResult; + } + + try { + String url = "/api-gateway/booking/v1/reservations/" + reservationId + "/remove-accompanying-guest"; + Header[] headers = HttpHeaderBuilder.custom() + .contentType("application/json") + .ac_property_id(dlPropertyId) + .ifMatch(verion.toString()) + .build(); + + // 第三方接口对同一预订加锁,必须串行调用;两次请求之间等待上一笔完成后再发下一笔 + final long requestIntervalMs = 1500L; + + for (int i = 0; i < dlSharerIds.size(); i++) { + if (i > 0) { + try { + TimeUnit.MILLISECONDS.sleep(requestIntervalMs); + } catch (InterruptedException ie) { + Thread.currentThread().interrupt(); + serviceResult.setSuccess(false); + serviceResult.setMessage("Remove accompanying guest interrupted"); + LogUtil.error(DaylightApiService.class, ie.getMessage()); + return serviceResult; + } + } + + String profileId = dlSharerIds.get(i); + Map body = new HashMap<>(2); + body.put("profileId", profileId); + + HttpResult httpResult = httpService.sslPost(url, headers, body); + int statusCode = httpResult.getStatusCode(); + if (statusCode < 200 || statusCode >= 300) { + serviceResult.setSuccess(false); + serviceResult.setMessage(String.format( + "Remove accompanying guest failed for profileId %s: HTTP %d", profileId, statusCode)); + LogUtil.error(DaylightApiService.class, httpResult.getResult()); + return serviceResult; + } + } + + serviceResult.setSuccess(true); + serviceResult.setMessage("Removed accompanying guest successfully"); + } catch (Exception e) { + serviceResult.setSuccess(false); + serviceResult.setMessage("Remove accompanying guest failed"); + LogUtil.error(DaylightApiService.class, e.getMessage()); + } + + return serviceResult; + } + + // 先留着不要删,可能后面会用上 by Mauve 2026-07-20 + public BaseApiResponse> daylightGetCancelReasonList(String dlPropertyId) { + + BaseApiResponse> response = new BaseApiResponse<>(); + + CfgDaylightConfiguration cancellationReason = + dlConfigurationDao.findByDlPropertyIdAndConfigName(dlPropertyId, "CancellationReason"); + + String configValue = cancellationReason.getConfigValue(); + + JSONArray list = JSON.parseArray(configValue); + + List result = new ArrayList<>(); + + for (int i = 0; i < list.size(); i++) { + JSONObject temp = list.getJSONObject(i); + + boolean isActive = temp.getBoolean("isActive"); + + if (!isActive) { + continue; + } + + String id = temp.getString("id"); + String code = temp.getString("code"); + String enContent = null; + + JSONArray descriptions = temp.getJSONArray("description"); + + for (int j = 0; j < descriptions.size(); j++) { + String languageCode = descriptions.getJSONObject(j).getString("languageCode"); + + if ("EN".equals(languageCode)) { + enContent = descriptions.getJSONObject(j).getString("content"); + break; + } + } + + if (StringUtils.isEmpty(enContent)) { + enContent = descriptions.getJSONObject(0).getString("content"); + } + + CancelReasonResponse cancelReasonResponse = + new CancelReasonResponse(); + + cancelReasonResponse.setId(id); + cancelReasonResponse.setCode(code); + cancelReasonResponse.setEnContent(enContent); + + result.add(cancelReasonResponse); + + if (CollectionUtils.isNotEmpty(result)) { + response.setData(result); + response.setSuccess(true); + } else { + response.setSuccess(false); + response.setMessage("No result"); + } + } + + return response; + } + + public BaseApiResponse daylightSetPost(String dlPropertyId, String dlAccountId) { + + BaseApiResponse response = new BaseApiResponse<>(); + + BaseApiResponse accountResponse = + daylightGetByAccountId(dlPropertyId, dlAccountId); + + if (!accountResponse.isSuccess()) { + response.setSuccess(false); + response.setMessage(accountResponse.getMessage()); + return response; + } + + AccountResponse accountData = accountResponse.getData(); + + try { + String url = "/api-gateway/cashiering/v1/reservation-accounts/" + dlAccountId; + // 获取对应的值 + Header[] headers = HttpHeaderBuilder.custom() + .contentType("application/json") + .ac_property_id(dlPropertyId) + .ifMatch(String.valueOf(accountData.getVersion())) + .build(); + // 参数设置 + Map map = new HashMap<>(); + + map.put("noPost", false); + + HttpResult responseData = httpService.sslPatch(url, headers, map); + + if (responseData.getStatusCode() >= 200 && responseData.getStatusCode() < 300) { + response.setSuccess(true); + response.setMessage("Set post success"); + } else { + response.setSuccess(false); + response.setMessage("Set post failed"); + } + + } catch (Exception e) { + throw new RuntimeException(e); + } + + return response; + } + + public BaseApiResponse daylightGetByAccountId(String dlPropertyId, String dlAccountId) { + + BaseApiResponse response = new BaseApiResponse<>(); + + try { + String url = "/api-gateway/cashiering/v1/accounts/" + dlAccountId; + // 获取对应的值 + Header[] headers = HttpHeaderBuilder.custom() + .contentType("application/json") + .ac_property_id(dlPropertyId) + .build(); + // 参数设置 + Map map = new HashMap<>(); + + HttpResult responseData = httpService.sslGetHttpResult(url, headers, map); + + if (responseData.getStatusCode() >= 200 && responseData.getStatusCode() < 300) { + response.setSuccess(true); + response.setMessage("Get account success"); + AccountResponse accountResponse = JSON.parseObject(responseData.getResult(), AccountResponse.class); + response.setData(accountResponse); + } else { + response.setSuccess(false); + response.setMessage("Get account failed"); + } + + } catch (Exception e) { + throw new RuntimeException(e); + } + + return response; + } + + public BaseApiResponse daylightChangeReservationByDlId( + Long bookingId, + String checkInDate, + String checkOutDate, + String dlPropertyId + ) { + try { + BaseApiResponse result = new BaseApiResponse<>(); + Bookings bookings = bookingDao.findById(bookingId).get(); + List cfgMarketCodes = marketCodeDao.findByCodeAndCategory(bookings.getMarketCode(), "DAYLIGHT"); + List rateCodes = rateCodeDao.findByCodeAndCategory(bookings.getRatePlanCode(), "DAYLIGHT"); + String marketCodeId = cfgMarketCodes.getFirst().getDlMarketSegmentId(); + String ratePlanId = rateCodes.getFirst().getDlRatePlanId(); + + String dlRoomTypeId = null; + CfgRooms room = roomDao.findById(bookings.getRoomId()).orElse(null); + List roomRoomType = room.getRoomRoomType(); + for(CfgRoomTypes type:roomRoomType) { + dlRoomTypeId = type.getDlRoomTypeId(); + if (dlRoomTypeId!=null) break; + } + + String dlReservationId = bookings.getDlReservationId(); + String url = "/api-gateway/booking/v1/reservations/" + dlReservationId + "/change-dates"; + + DaylightReservationResponse daylightReservationByDlId = getDaylightReservationByDlId(dlReservationId, dlPropertyId); + Long version = daylightReservationByDlId.getVersion(); + + Breakdown breakdown = new Breakdown(); + GuestForBreakdown guest = new GuestForBreakdown(); + RatePricingDetail ratePricingDetail = new RatePricingDetail(); + + SysAgebucket sysAgebucket = agebucketService.getSysAgebucket(dlPropertyId); + guest.setAgeBucketId(sysAgebucket.getDlAgeBucketId()); + + guest.setCount(1L); + List guests = new ArrayList<>(); + guests.add(guest); + ratePricingDetail.setRatePlanId(ratePlanId); + ratePricingDetail.setRoomTypeToChargeId(dlRoomTypeId); + breakdown.setRatePricingDetails(ratePricingDetail); + breakdown.setGuests(guests); + breakdown.setFromDate(checkInDate); + breakdown.setToDate(checkOutDate); + breakdown.setMarketSegmentId(marketCodeId); + List breakdowns = new ArrayList<>(); + breakdowns.add(breakdown); + Map params = new HashMap<>(); + + String etaStr = bookings.getEta() != null ? bookings.getEta() : ""; + + if (StringUtils.isNotBlank(etaStr) && etaStr.length() <= 5) + etaStr += ":00"; + + if (StringUtils.isNotBlank(etaStr)) + etaStr = checkInDate + "T" + etaStr; + + params.put("eta", etaStr); + + params.put("breakdown", breakdowns); + params.put("arrivalDate", checkInDate); + params.put("departureDate", checkOutDate); + params.put("blockId", bookings.getDlBlockId()); +// params.put("keepOriginalPrice",true); + // 获取对应的值 + Header[] headers = HttpHeaderBuilder.custom() + .contentType("application/json") + .ac_property_id(dlPropertyId) + .ifMatch(String.valueOf(version)) + .build(); + + log.info("Change-date params: {}", JSON.toJSONString(params)); + + HttpResult submitResult = httpService.sslPost(url, headers,params); + String responseBody = submitResult.getResult(); + if (submitResult.getStatusCode() == 200 || submitResult.getStatusCode() == 201 || submitResult.getStatusCode() == 202) { + result.setSuccess(true); + result.setData(bookings); + }else{ + JSONObject rootNode = JSON.parseObject(responseBody); + String errorStr; + + JSONArray detailsNode = rootNode.getJSONArray("details"); + if (detailsNode != null && !detailsNode.isEmpty()) { + // 获取第一个 details 元素的 message + JSONObject firstDetail = detailsNode.getJSONObject(0); + String detailMessage = firstDetail.getString("message"); + + // 获取详细信息 + String errorCode = rootNode.getString("code"); + String correlationId = rootNode.getString("correlationId"); + + errorStr = String.format("Error: %s, Detail: %s, CorrelationId: %s", + errorCode, detailMessage, correlationId); + + } else { + errorStr = rootNode.getString("message"); + } + result.setSuccess(false); + result.setMessage(errorStr); + } + return result; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public BaseApiResponse daylightSetExternalNo( + String dlPropertyId, + String dlReservationId, + String dlExternalNo, + Number version) { + + BaseApiResponse response = new BaseApiResponse<>(); + + try { + String url = "/api-gateway/booking/v1/reservations/" + dlReservationId; + // 获取对应的值 + Header[] headers = HttpHeaderBuilder.custom() + .contentType("application/json") + .ac_property_id(dlPropertyId) + .ifMatch(String.valueOf(version)) + .build(); + // 参数设置 + Map map = new HashMap<>(); + + ReservationRequestDTO.ExternalIdDTO externalIdDTO + = new ReservationRequestDTO.ExternalIdDTO(); + + externalIdDTO.setSystemId(dlSystemId); + externalIdDTO.setNumber(dlExternalNo); + + map.put("externalIds", List.of(externalIdDTO)); + + HttpResult responseData = httpService.sslPatch(url, headers, map); + + if (responseData.getStatusCode() >= 200 && responseData.getStatusCode() < 300) { + response.setSuccess(true); + response.setMessage("Set external number success"); + } else { + response.setSuccess(false); + response.setMessage("Set external number failed"); + } + + } catch (Exception e) { + throw new RuntimeException(e); + } + + return response; + } +} diff --git a/src/main/java/com/mgm/mcrm/booking/repositories/BookingDao.java b/src/main/java/com/mgm/mcrm/booking/repositories/BookingDao.java index 56dc23e..039a4fa 100644 --- a/src/main/java/com/mgm/mcrm/booking/repositories/BookingDao.java +++ b/src/main/java/com/mgm/mcrm/booking/repositories/BookingDao.java @@ -92,4 +92,6 @@ public interface BookingDao extends JpaRepository { @Query(value = "select Top(1) * from bookings where dl_external_no is not null and ltrim(rtrim(dl_external_no)) = ltrim(rtrim(?1)) order by id asc", nativeQuery = true) Bookings getByDlExternalNo(String dlExternalNo); + @Query(value = "select Top(1) * from bookings where property_id is not null and confirmation_no = ?1 order by id asc", nativeQuery = true) + Bookings findFirstByConfirmationNoAndPropertyIdIsNotNull(String confirmationNo); } diff --git a/src/main/java/com/mgm/mcrm/booking/services/BookingService.java b/src/main/java/com/mgm/mcrm/booking/services/BookingService.java index ca53c1d..215dd6c 100644 --- a/src/main/java/com/mgm/mcrm/booking/services/BookingService.java +++ b/src/main/java/com/mgm/mcrm/booking/services/BookingService.java @@ -1220,8 +1220,8 @@ public class BookingService { reservationDTO.setSourceId(sourceCode.getDlSourceId()); booking.setDlSourceId(sourceCode.getDlSourceId()); - if ("IM".equalsIgnoreCase(bookingTypeName) && isPostIM == 0) { - reservationDTO.setNoPost(true); + if ("IM".equalsIgnoreCase(bookingTypeName)) { + reservationDTO.setNoPost(Objects.equals(isPostIM, 0)); } else { reservationDTO.setNoPost(StringUtils.isBlank(booking.getMiscCharge())); } @@ -1259,18 +1259,6 @@ public class BookingService { breakdownDTO.setRatePricingDetails(ratePricingDetailsDTO); reservationDTO.setBreakdown(List.of(breakdownDTO)); - Map customFields = new HashMap<>(); - customFields.put("Booker", userId); - - if ("IM".equalsIgnoreCase(bookingTypeName) && depositTypeIM == 0) { - customFields.put("WAIVEDEPOSIT", true); - } - - if (booking.getWaitlistId() != null) { - customFields.put("App_Rea", "APP"); - customFields.put("Approver", booking.getApprovedBy()); - } - String sharerString = booking.getSharer(); JSONArray sharers = JSONArray.parseArray(sharerString); @@ -1307,17 +1295,24 @@ public class BookingService { IndividualDTO individualDTO; if (StringUtils.isEmpty(sharerId)) { + log.info("Sharer={} does not exist playerId", sharerName); + individualDTO = IndividualDTO.buildNewProfileWithoutPlayerId( sharerName, "sha_" + i ); } else { + log.info("Sharer={} exists the playerId={}, tierName={}", sharerName, sharerId, sharer.getString("tierName")); + + BaseApiResponse sharerDetail = + playerService.findPlayerProfileByPlayerIdAndUserId(sharerId, userId); + individualDTO = IndividualDTO.buildNewProfileWithPlayerId( sharerId, sharerName, "shamem_" + i, "sha_" + i, - sharer.getString("tierName") + sharerDetail.getData().getTierName() ); } @@ -1352,6 +1347,18 @@ public class BookingService { ReservationDTO.CustomFieldDTO customFieldDTO = new ReservationDTO.CustomFieldDTO(); + Map customFields = new HashMap<>(); + customFields.put("Booker", userId); + + if ("IM".equalsIgnoreCase(bookingTypeName) && Objects.equals(depositTypeIM, 0)) { + customFields.put("WAIVEDEPOSIT", true); + } + + if (booking.getWaitlistId() != null) { + customFields.put("App_Rea", "APP"); + customFields.put("Approver", booking.getApprovedBy()); + } + customFieldDTO.setLocation("ReservationHeader"); customFieldDTO.setValue(JSON.toJSONString(customFields)); reservationDTO.setCustomFields(List.of(customFieldDTO)); @@ -1444,7 +1451,7 @@ public class BookingService { dlService.getDaylightReservationByDlId(reservationId, property.getDlPropertyId()); booking.setDlAccountId(daylightReservationByDlId.getAccountId()); -// booking.setDlReservationId(reservationId); + booking.setDlReservationId(reservationId); // booking.setConfirmationNo(confirmationNumber); // booking.setLastOperaStatus("RESERVED"); // booking.setApproveStatus("N"); @@ -1481,14 +1488,18 @@ public class BookingService { //2.循环Comp rule ids 插入每一条comp rule for (String compRuleId :compRuleIds){ - Date now = new Date(); - CfgCompRule cfgCompRule = new CfgCompRule(); - cfgCompRule.setCompRuleId(compRuleId); - cfgCompRule.setDlReservationId(reservationId); - cfgCompRule.setAccountId(daylightReservationByDlId.getAccountId()); - cfgCompRule.setCreatedAt(now); + try { + Date now = new Date(); + CfgCompRule cfgCompRule = new CfgCompRule(); + cfgCompRule.setCompRuleId(compRuleId); + cfgCompRule.setDlReservationId(reservationId); + cfgCompRule.setAccountId(daylightReservationByDlId.getAccountId()); + cfgCompRule.setCreatedAt(now); - cfgCompRuleDao.save(cfgCompRule); + cfgCompRuleDao.save(cfgCompRule); + } catch (Exception e) { + log.warn("Insert duplicated compRuleId: {}", compRuleId); + } } //Create Reservation 后处理WaitListBooking @@ -3514,6 +3525,13 @@ public class BookingService { view.setDlSharerIds(daylightResultBooking.getAccompanyingGuestProfileIds()); view.setDlVersion(daylightResultBooking.getVersion()); + boolean hasSharer = StringUtils.isNotBlank(view.getSharer()) + && !"[]".equals(view.getSharer()); + if (hasSharer) { + JSONArray sharerList = JSONArray.parseArray(view.getSharer()); + view.setSharerList(sharerList); + } + BaseApiResponse> profileResult = dlService.dayLightGetProfileByPlayerId(view.getPlayerId()); @@ -3528,8 +3546,8 @@ public class BookingService { } else { JSONObject json = JSONObject.parseObject(profile.getCustomFieldContainerJson()); String mainExpDate = json.getString("CanStayUntil"); - if (mainExpDate == null) { - // 主 guest 的 CanStayUntil 为 null,expDate 直接置空 + if (StringUtils.isBlank(mainExpDate)) { + // 主 guest 的 CanStayUntil 为空,expDate 直接置空 expDate = null; } else { expDate = mainExpDate; @@ -3537,10 +3555,9 @@ public class BookingService { } } - if (StringUtils.isNotBlank(view.getSharer()) && !"[]".equals(view.getSharer())) { - JSONArray sharerList = JSONArray.parseArray(view.getSharer()); - view.setSharerList(sharerList); - + if (StringUtils.isNotBlank(expDate) + && hasSharer + && CollectionUtils.isNotEmpty(view.getDlSharerIds())) { for (String dlSharerId : view.getDlSharerIds()) { ProfileDetailResponse profileDetailResponse = dlService.dayLightGetProfileByProfileId(dlSharerId); @@ -3553,20 +3570,16 @@ public class BookingService { JSONObject json = JSONObject.parseObject(profileDetailResponse.getCustomFieldContainerJson()); String shareExpDate = json.getString("CanStayUntil"); - if (shareExpDate == null) { - // CanStayUntil 为 null,expDate 直接置空并跳出 + if (StringUtils.isBlank(shareExpDate)) { + // CanStayUntil 为空,expDate 直接置空并跳出 expDate = null; break; } - if (StringUtils.isBlank(expDate)) { + Date current = DateTimeUtil.getDateFromString(expDate, "yyyy-MM-dd"); + Date share = DateTimeUtil.getDateFromString(shareExpDate, "yyyy-MM-dd"); + if (share.before(current)) { expDate = shareExpDate; - } else { - Date current = DateTimeUtil.getDateFromString(expDate, "yyyy-MM-dd"); - Date share = DateTimeUtil.getDateFromString(shareExpDate, "yyyy-MM-dd"); - if (share.before(current)) { - expDate = shareExpDate; - } } } } @@ -4866,7 +4879,7 @@ public class BookingService { || "CHECKED_IN".equalsIgnoreCase(mergedDaylightStatus) || "DUE_IN".equalsIgnoreCase(mergedDaylightStatus) ) - && "PN".equalsIgnoreCase(daylightBooking.getApproveStatus()) + && "PN".equalsIgnoreCase(dbBooking.getApproveStatus()) && dbBooking.getRevisionOf() == null) { daylightBooking.setApproveStatus("N"); } @@ -6222,7 +6235,7 @@ public class BookingService { if (data != null) { String comment = data.getContent(); - if (comment != null) { + if (StringUtils.isNotBlank(comment)) { Matcher miscChargeMatcher = Pattern .compile("(?:\\$|$)\\s*([0-9]+(?:\\.[0-9]+)?)", Pattern.CASE_INSENSITIVE) .matcher(comment); diff --git a/src/main/java/com/mgm/mcrm/common/constants/SysCommon.java b/src/main/java/com/mgm/mcrm/common/constants/SysCommon.java index 73fc7af..a21e071 100644 --- a/src/main/java/com/mgm/mcrm/common/constants/SysCommon.java +++ b/src/main/java/com/mgm/mcrm/common/constants/SysCommon.java @@ -42,6 +42,7 @@ public class SysCommon { public static String defaultRouter = "welcome"; public static String runtimeName="crm_mobile_runtime"; public static int postTimeOut = 20; + //for stress test public static int tokenExpMin = 5; public static int refreshTokenExpDay = 30; diff --git a/src/main/java/com/mgm/mcrm/common/constants/SysConstants.java b/src/main/java/com/mgm/mcrm/common/constants/SysConstants.java index 77c32bd..826a664 100644 --- a/src/main/java/com/mgm/mcrm/common/constants/SysConstants.java +++ b/src/main/java/com/mgm/mcrm/common/constants/SysConstants.java @@ -24,6 +24,8 @@ public class SysConstants { public static final String PERMISSION_APP_TODO_LIST="10001_03"; public static final String PERMISSION_APP_DASHBOARD="10001_04"; public static final String PERMISSION_APP_APPROVAL="10001_05"; + public static final String PERMISSION_APP_VIEW_NOTIFICATION="10001_06"; public static final String PERMISSION_APP_CALENDAR="10001_07"; + public static final String PERMISSION_APP_VIEW_LIMO="10001_08"; } diff --git a/src/main/java/com/mgm/mcrm/common/dtos/config/APIConfig.java b/src/main/java/com/mgm/mcrm/common/dtos/config/APIConfig.java index c87dfc2..8c221e7 100644 --- a/src/main/java/com/mgm/mcrm/common/dtos/config/APIConfig.java +++ b/src/main/java/com/mgm/mcrm/common/dtos/config/APIConfig.java @@ -1,5 +1,8 @@ package com.mgm.mcrm.common.dtos.config; +import lombok.Data; + +@Data public class APIConfig { private boolean isLoaded = false; @@ -9,6 +12,11 @@ public class APIConfig { private String apiSecret_ESB=""; private int timeout_ESB=0; + + private String limoService_ESB=""; + private String limoApp_id=""; + private String limoApp_key=""; + private String serverUrl_ESB_Daylight=""; private String apiKey_ESB_Daylight=""; private String apiSecret_ESB_Daylight=""; @@ -52,225 +60,4 @@ public class APIConfig { private String password_SMTP= ""; private String send_to_SMTP= ""; - - public boolean isLoaded() { - return isLoaded; - } - public void setLoaded(boolean isLoaded) { - this.isLoaded = isLoaded; - } - - public String getServerUrl_ESB() { - return serverUrl_ESB; - } - public void setServerUrl_ESB(String serverUrl_ESB) { - this.serverUrl_ESB = serverUrl_ESB; - } - public String getApiKey_ESB() { - return apiKey_ESB; - } - public void setApiKey_ESB(String apiKey_ESB) { - this.apiKey_ESB = apiKey_ESB; - } - public String getApiSecret_ESB() { - return apiSecret_ESB; - } - public void setApiSecret_ESB(String apiSecret_ESB) { - this.apiSecret_ESB = apiSecret_ESB; - } - public int getTimeout_ESB() { - return timeout_ESB; - } - public void setTimeout_ESB(int timeout_ESB) { - this.timeout_ESB = timeout_ESB; - } - public String getServerLoginUrl_RPA() { - return serverLoginUrl_RPA; - } - public void setServerLoginUrl_RPA(String serverLoginUrl_RPA) { - this.serverLoginUrl_RPA = serverLoginUrl_RPA; - } - public String getApiAccessName_RPA() { - return apiAccessName_RPA; - } - public void setApiAccessName_RPA(String apiAccessName_RPA) { - this.apiAccessName_RPA = apiAccessName_RPA; - } - public String getApiAccessPassword_RPA() { - return apiAccessPassword_RPA; - } - public void setApiAccessPassword_RPA(String apiAccessPassword_RPA) { - this.apiAccessPassword_RPA = apiAccessPassword_RPA; - } - public String getApiAccessKey_RPA() { - return apiAccessKey_RPA; - } - public void setApiAccessKey_RPA(String apiAccessKey_RPA) { - this.apiAccessKey_RPA = apiAccessKey_RPA; - } - public String getServerAddUrl_RPA() { - return serverAddUrl_RPA; - } - public void setServerAddUrl_RPA(String serverAddUrl_RPA) { - this.serverAddUrl_RPA = serverAddUrl_RPA; - } - public String getServerExtensionUrl_RPA() { - return serverExtensionUrl_RPA; - } - public void setServerExtensionUrl_RPA(String serverExtensionUrl_RPA) { - this.serverExtensionUrl_RPA = serverExtensionUrl_RPA; - } - public int getTimeout_RPA() { - return timeout_RPA; - } - public void setTimeout_RPA(int timeout_RPA) { - this.timeout_RPA = timeout_RPA; - } - public String getServerUrl_SSO() { - return serverUrl_SSO; - } - public void setServerUrl_SSO(String serverUrl_SSO) { - this.serverUrl_SSO = serverUrl_SSO; - } - - public String getClientId_SSO() { - return clientId_SSO; - } - public void setClientId_SSO(String clientId_SSO) { - this.clientId_SSO = clientId_SSO; - } - public String getClientSecret_SSO() { - return clientSecret_SSO; - } - public void setClientSecret_SSO(String clientSecret_SSO) { - this.clientSecret_SSO = clientSecret_SSO; - } - public int getTimeout_SSO() { - return timeout_SSO; - } - public void setTimeout_SSO(int timeout_SSO) { - this.timeout_SSO = timeout_SSO; - } - public String getServerUrl_CallCenter() { - return serverUrl_CallCenter; - } - public void setServerUrl_CallCenter(String serverUrl_CallCenter) { - this.serverUrl_CallCenter = serverUrl_CallCenter; - } - public int getTimeout_CallCenter() { - return timeout_CallCenter; - } - public void setTimeout_CallCenter(int timeout_CallCenter) { - this.timeout_CallCenter = timeout_CallCenter; - } - public String getTokenUrl_SMS() { - return tokenUrl_SMS; - } - public void setTokenUrl_SMS(String tokenUrl_SMS) { - this.tokenUrl_SMS = tokenUrl_SMS; - } - public String getSendUrl_SMS() { - return sendUrl_SMS; - } - public void setSendUrl_SMS(String sendUrl_SMS) { - this.sendUrl_SMS = sendUrl_SMS; - } - public String getUsername_SMS() { - return username_SMS; - } - public void setUsername_SMS(String username_SMS) { - this.username_SMS = username_SMS; - } - public String getPassword_SMS() { - return password_SMS; - } - public void setPassword_SMS(String password_SMS) { - this.password_SMS = password_SMS; - } - public String getAccount_SMS() { - return account_SMS; - } - public void setAccount_SMS(String account_SMS) { - this.account_SMS = account_SMS; - } - public String getPriority_SMS() { - return priority_SMS; - } - public void setPriority_SMS(String priority_SMS) { - this.priority_SMS = priority_SMS; - } - public String getServerUrl_OWS() { - return serverUrl_OWS; - } - public void setServerUrl_OWS(String serverUrl_OWS) { - this.serverUrl_OWS = serverUrl_OWS; - } - public int getTimeout_OWS() { - return timeout_OWS; - } - public void setTimeout_OWS(int timeout_OWS) { - this.timeout_OWS = timeout_OWS; - } - public String getPort_SMTP() { - return port_SMTP; - } - public void setPort_SMTP(String port_SMTP) { - this.port_SMTP = port_SMTP; - } - public String getHost_SMTP() { - return host_SMTP; - } - public void setHost_SMTP(String host_SMTP) { - this.host_SMTP = host_SMTP; - } - public String getUsername_SMTP() { - return username_SMTP; - } - public void setUsername_SMTP(String username_SMTP) { - this.username_SMTP = username_SMTP; - } - public String getPassword_SMTP() { - return password_SMTP; - } - public void setPassword_SMTP(String password_SMTP) { - this.password_SMTP = password_SMTP; - } - public String getSend_to_SMTP() { - return send_to_SMTP; - } - public void setSend_to_SMTP(String send_to_SMTP) { - this.send_to_SMTP = send_to_SMTP; - } - - public String getServerUrl_ESB_Daylight() { - return serverUrl_ESB_Daylight; - } - - public void setServerUrl_ESB_Daylight(String serverUrl_ESB_Daylight) { - this.serverUrl_ESB_Daylight = serverUrl_ESB_Daylight; - } - - public String getApiKey_ESB_Daylight() { - return apiKey_ESB_Daylight; - } - - public void setApiKey_ESB_Daylight(String apiKey_ESB_Daylight) { - this.apiKey_ESB_Daylight = apiKey_ESB_Daylight; - } - - public String getApiSecret_ESB_Daylight() { - return apiSecret_ESB_Daylight; - } - - public void setApiSecret_ESB_Daylight(String apiSecret_ESB_Daylight) { - this.apiSecret_ESB_Daylight = apiSecret_ESB_Daylight; - } - - public int getTimeout_ESB_Daylight() { - return timeout_ESB_Daylight; - } - - public void setTimeout_ESB_Daylight(int timeout_ESB_Daylight) { - this.timeout_ESB_Daylight = timeout_ESB_Daylight; - } } diff --git a/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/GetLimoAccessTokenRequest.java b/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/GetLimoAccessTokenRequest.java new file mode 100644 index 0000000..5bf60d5 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/GetLimoAccessTokenRequest.java @@ -0,0 +1,12 @@ +package com.mgm.mcrm.common.dtos.mgm_api; + +import lombok.Data; + +@Data +public class GetLimoAccessTokenRequest { + + private String LoginId; + + private String password; + +} \ No newline at end of file diff --git a/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/GetLimoFlightDetailsRequest.java b/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/GetLimoFlightDetailsRequest.java new file mode 100644 index 0000000..4aec774 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/GetLimoFlightDetailsRequest.java @@ -0,0 +1,11 @@ +package com.mgm.mcrm.common.dtos.mgm_api; + +import lombok.Data; + +@Data +public class GetLimoFlightDetailsRequest { + private String flightNo; + private String pickupDateTime; + private String pickupAirportCode; + private String dropOffAirportCode; +} diff --git a/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/GetLimoOverriderRequest.java b/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/GetLimoOverriderRequest.java new file mode 100644 index 0000000..8175d14 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/GetLimoOverriderRequest.java @@ -0,0 +1,10 @@ +package com.mgm.mcrm.common.dtos.mgm_api; + +import lombok.Data; + +@Data +public class GetLimoOverriderRequest { + + private String OverriderIdOrName; + +} diff --git a/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/GetLimoTotalAmountRequest.java b/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/GetLimoTotalAmountRequest.java new file mode 100644 index 0000000..368d3b0 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/GetLimoTotalAmountRequest.java @@ -0,0 +1,10 @@ +package com.mgm.mcrm.common.dtos.mgm_api; + +import lombok.Data; + +@Data +public class GetLimoTotalAmountRequest { + private String pickupPOIId; + private String dropoffPOIIds; + private String singleTripPrices; +} diff --git a/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/GetPlayerInfoRequest.java b/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/GetPlayerInfoRequest.java new file mode 100644 index 0000000..6f44d19 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/GetPlayerInfoRequest.java @@ -0,0 +1,10 @@ +package com.mgm.mcrm.common.dtos.mgm_api; + +import lombok.Data; + +@Data +public class GetPlayerInfoRequest { + + private String playerId; + +} diff --git a/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/GetSimpleLimoBookingQualificationStatusRequest.java b/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/GetSimpleLimoBookingQualificationStatusRequest.java new file mode 100644 index 0000000..273966e --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/GetSimpleLimoBookingQualificationStatusRequest.java @@ -0,0 +1,15 @@ +package com.mgm.mcrm.common.dtos.mgm_api; + +import lombok.Data; + +@Data +public class GetSimpleLimoBookingQualificationStatusRequest { + + private String playerId; + + private String bookingType; + + private String bookingDate; + + +} diff --git a/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/InternalCreateLimoBookingRequest.java b/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/InternalCreateLimoBookingRequest.java new file mode 100644 index 0000000..a46d51c --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/InternalCreateLimoBookingRequest.java @@ -0,0 +1,150 @@ +package com.mgm.mcrm.common.dtos.mgm_api; + +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +public class InternalCreateLimoBookingRequest { + + private int createNotConfirmBooking; + private String bookingType; + private String greetType; + private String otherGreetType; + private String guestType; + private String tripType; + + private String playerId; + private String ranking; + private String overrideBy; + private String complexOverrider; + + private String roomNo; + private String employeeId; + + private String lastName; + private String salution; + private String chineseLastName; + + private String bookerContact; + private String tripContact; + + private int adHoc; + + private LocalDateTime pickupDatetime; + + private Long carTypeId; + private Integer passengerNo; + + private Long pickupPOIID; + private String pickup; + private Long pickupTripPriceId; + private String pickupRegion; + + private Long dropoffPOIID; + private String dropoff; + private Long dropoffTripPriceId; + private String dropoffRegion; + + private Long extraDropoffPOIID1; + private String extraDropoff1; + private Long extraDropoffTripPriceID1; + private String extraDropoffRegion1; + + private Long extraDropoffPOIID2; + private String extraDropoff2; + private Long extraDropoffTripPriceID2; + private String extraDropoffRegion2; + + private Long extraDropoffPOIID3; + private String extraDropoff3; + private Long extraDropoffTripPriceID3; + private String extraDropoffRegion3; + + private Long extraDropoffPOIID4; + private String extraDropoff4; + private Long extraDropoffTripPriceID4; + private String extraDropoffRegion4; + + private Long extraDropoffPOIID5; + private String extraDropoff5; + private Long extraDropoffTripPriceID5; + private String extraDropoffRegion5; + + private Long extraDropoffPOIID6; + private String extraDropoff6; + private Long extraDropoffTripPriceID6; + private String extraDropoffRegion6; + + private Long extraDropoffPOIID7; + private String extraDropoff7; + private Long extraDropoffTripPriceID7; + private String extraDropoffRegion7; + + private Long extraDropoffPOIID8; + private String extraDropoff8; + private Long extraDropoffTripPriceID8; + private String extraDropoffRegion8; + + private Long extraDropoffPOIID9; + private String extraDropoff9; + private Long extraDropoffTripPriceID9; + private String extraDropoffRegion9; + + private Long extraDropoffPOIID10; + private String extraDropoff10; + private Long extraDropoffTripPriceID10; + private String extraDropoffRegion10; + + private BigDecimal singleTripPrice; + private BigDecimal defaultTripPrice; + private BigDecimal defaultPublishTripPrice; + + private BigDecimal hourlyRate; + private BigDecimal hourlyWaitingFee; + + private Integer hour; + private Integer hourlyWaiting; + + private BigDecimal extraDropoffPrice1; + private BigDecimal extraDropoffPrice2; + private BigDecimal extraDropoffPrice3; + private BigDecimal extraDropoffPrice4; + private BigDecimal extraDropoffPrice5; + private BigDecimal extraDropoffPrice6; + private BigDecimal extraDropoffPrice7; + private BigDecimal extraDropoffPrice8; + private BigDecimal extraDropoffPrice9; + private BigDecimal extraDropoffPrice10; + + private String otherPriceRemark; + private BigDecimal otherPrice; + + private String paymentMethod; + private BigDecimal totalAmount; + + private Boolean highImportance; + private Boolean tenOut; + private Boolean butlerGreet; + + private String bookedBy; + private String approvedBy; + + private String bookingRemark; + private String driverRemark; + private String limoInternalRemark; + private String systemRemark; + + private Boolean limoGreet; + private Boolean hostGreet; + private Boolean vipMeetNGreet; + + private String otherGreet; + private String flightDetails; + private String signage; + + public int getCreateNotConfirmBooking() { + return createNotConfirmBooking; + } +} diff --git a/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/InternalUpdateLimoBookingRequest.java b/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/InternalUpdateLimoBookingRequest.java new file mode 100644 index 0000000..8476b76 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/InternalUpdateLimoBookingRequest.java @@ -0,0 +1,148 @@ +package com.mgm.mcrm.common.dtos.mgm_api; + +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +public class InternalUpdateLimoBookingRequest { + + private Long id; + + private Boolean createNotConfirmBooking; + private String bookingType; + private String greetType; + private String otherGreetType; + private String guestType; + private String tripType; + + private String playerId; + private String ranking; + private String overrideBy; + private String complexOverrider; + + private String roomNo; + private String employeeId; + + private String lastName; + private String salution; + private String chineseLastName; + + private String bookerContact; + private String tripContact; + + private String adHoc; + + private LocalDateTime pickupDatetime; + + private Long carTypeId; + private Integer passengerNo; + + private Long pickupPOIID; + private String pickup; + private Long pickupTripPriceID; + private String pickupRegion; + + private Long dropoffPOIID; + private String dropoff; + private Long dropoffTripPriceID; + private String dropoffRegion; + + private Long extraDropoffPOIID1; + private String extraDropoff1; + private Long extraDropoffTripPriceID1; + private String extraDropoffRegion1; + + private Long extraDropoffPOIID2; + private String extraDropoff2; + private Long extraDropoffTripPriceID2; + private String extraDropoffRegion2; + + private Long extraDropoffPOIID3; + private String extraDropoff3; + private Long extraDropoffTripPriceID3; + private String extraDropoffRegion3; + + private Long extraDropoffPOIID4; + private String extraDropoff4; + private Long extraDropoffTripPriceID4; + private String extraDropoffRegion4; + + private Long extraDropoffPOIID5; + private String extraDropoff5; + private Long extraDropoffTripPriceID5; + private String extraDropoffRegion5; + + private Long extraDropoffPOIID6; + private String extraDropoff6; + private Long extraDropoffTripPriceID6; + private String extraDropoffRegion6; + + private Long extraDropoffPOIID7; + private String extraDropoff7; + private Long extraDropoffTripPriceID7; + private String extraDropoffRegion7; + + private Long extraDropoffPOIID8; + private String extraDropoff8; + private Long extraDropoffTripPriceID8; + private String extraDropoffRegion8; + + private Long extraDropoffPOIID9; + private String extraDropoff9; + private Long extraDropoffTripPriceID9; + private String extraDropoffRegion9; + + private Long extraDropoffPOIID10; + private String extraDropoff10; + private Long extraDropoffTripPriceID10; + private String extraDropoffRegion10; + + private BigDecimal singleTripPrice; + private BigDecimal defaultTripPrice; + private BigDecimal defaultPublishTripPrice; + + private BigDecimal hourlyRate; + private BigDecimal hourlyWaitingFee; + + private Integer hour; + private Integer hourlyWaiting; + + private BigDecimal extraDropoffPrice1; + private BigDecimal extraDropoffPrice2; + private BigDecimal extraDropoffPrice3; + private BigDecimal extraDropoffPrice4; + private BigDecimal extraDropoffPrice5; + private BigDecimal extraDropoffPrice6; + private BigDecimal extraDropoffPrice7; + private BigDecimal extraDropoffPrice8; + private BigDecimal extraDropoffPrice9; + private BigDecimal extraDropoffPrice10; + + private String otherPriceRemark; + private BigDecimal otherPrice; + + private String paymentMethod; + private BigDecimal totalAmount; + + private Boolean highImportance; + private Boolean tenOut; + private Boolean butlerGreet; + + private String bookedBy; + private String approvedBy; + + private String bookingRemark; + private String driverRemark; + private String limoInternalRemark; + private String systemRemark; + + private Boolean limoGreet; + private Boolean hostGreet; + private Boolean vipMeetNGreet; + + private String otherGreet; + private String flightDetails; + private String signage; +} diff --git a/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/PlayerProfileApiResult.java b/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/PlayerProfileApiResult.java new file mode 100644 index 0000000..31de108 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/PlayerProfileApiResult.java @@ -0,0 +1,188 @@ +package com.mgm.mcrm.common.dtos.mgm_api; + +import java.util.ArrayList; +import java.util.List; + + +public class PlayerProfileApiResult { + + private String statusCode = null; + private String statusDescription=""; + private String playerId; + private String userId; + private String tierName; + private String tierId; + private String chineseName; + private String englishName; + private String salutation; + private Integer codedFlag; + private String name; + private String playerPhone; + private String phoneType; + private String birthday; + private String country; + private String state; + private String passport; + private String language; + private List nameIds=new ArrayList(); + + public PlayerProfileApiResult() { + + } + + public String getStatusCode() { + return statusCode; + } + + public void setStatusCode(String statusCode) { + this.statusCode = statusCode; + } + + public String getStatusDescription() { + return statusDescription; + } + + public void setStatusDescription(String statusDescription) { + this.statusDescription = statusDescription; + } + + public String getPlayerId() { + return playerId; + } + + public void setPlayerId(String playerId) { + this.playerId = playerId; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public String getTierName() { + return tierName; + } + + public void setTierName(String tierName) { + this.tierName = tierName; + } + + public String getTierId() { + return tierId; + } + + public void setTierId(String tierId) { + this.tierId = tierId; + } + + public String getChineseName() { + return chineseName; + } + + public void setChineseName(String chineseName) { + this.chineseName = chineseName; + } + + public String getEnglishName() { + return englishName; + } + + public void setEnglishName(String englishName) { + this.englishName = englishName; + } + + public String getSalutation() { + return salutation; + } + + public void setSalutation(String salutation) { + this.salutation = salutation; + } + + public List getNameIds() { + return nameIds; + } + + public void setNameIds(List nameIds) { + this.nameIds = nameIds; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getCodedFlag() { + return codedFlag; + } + + public void setCodedFlag(Integer codedFlag) { + this.codedFlag = codedFlag; + } + + public String getPlayerPhone() { + return playerPhone; + } + + public void setPlayerPhone(String playerPhone) { + this.playerPhone = playerPhone; + } + + public String getPhoneType() { + return phoneType; + } + + public void setPhoneType(String phoneType) { + this.phoneType = phoneType; + } + + public String getBirthday() { + return birthday; + } + + public void setBirthday(String birthday) { + this.birthday = birthday; + } + + public String getCountry() { + return country; + } + + public void setCountry(String country) { + this.country = country; + } + + public String getState() { + return state; + } + + public void setState(String state) { + this.state = state; + } + + public String getPassport() { + return passport; + } + + public void setPassport(String passport) { + this.passport = passport; + } + + public String getLanguage() { + return language; + } + + public void setLanguage(String language) { + this.language = language; + } + + + + +} diff --git a/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/RequestPlayerLimoBookerRequest.java b/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/RequestPlayerLimoBookerRequest.java new file mode 100644 index 0000000..e6212ac --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/RequestPlayerLimoBookerRequest.java @@ -0,0 +1,9 @@ +package com.mgm.mcrm.common.dtos.mgm_api; + +import lombok.Data; + +@Data +public class RequestPlayerLimoBookerRequest { + private String playerId; + private String userId; +} diff --git a/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/UserInfoApiRecord.java b/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/UserInfoApiRecord.java index f505ffb..0962d5b 100644 --- a/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/UserInfoApiRecord.java +++ b/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/UserInfoApiRecord.java @@ -21,12 +21,15 @@ public class UserInfoApiRecord { private Long sectionId; private Long blockId; private Long teamStructureId; + private String paymentMethod; private boolean canViewBooking=false; private boolean canNewBooking=false; private boolean canViewTodoList=false; private boolean canViewDashboard=false; private boolean canViewApproval=false; private boolean canViewCalendar=false; + private boolean canViewNotification=false; + private boolean canViewLimo=false; private String groupName; private String phone; private boolean loginTag; diff --git a/src/main/java/com/mgm/mcrm/common/services/HttpService.java b/src/main/java/com/mgm/mcrm/common/services/HttpService.java index a40bc3a..625c220 100644 --- a/src/main/java/com/mgm/mcrm/common/services/HttpService.java +++ b/src/main/java/com/mgm/mcrm/common/services/HttpService.java @@ -56,7 +56,7 @@ public class HttpService { .client(httpClient); String result = HttpClientExecutor.get(getConfig, headers); - log.info("GET request result size={}", result); + log.info("GET request result size={}", result.length()); return result; } @@ -144,7 +144,7 @@ public class HttpService { .client(httpClient); HttpResult result = HttpClientExecutor.sendAndPostResp(postConfig, headers); // System.out.println("POST 请求结果:\n" + result); - log.info("POST request result={}", result); + log.info("POST request result size={}", result.getResult().length()); return result; } diff --git a/src/main/java/com/mgm/mcrm/common/services/MGMApiService.java b/src/main/java/com/mgm/mcrm/common/services/MGMApiService.java index b714420..3ab1a45 100644 --- a/src/main/java/com/mgm/mcrm/common/services/MGMApiService.java +++ b/src/main/java/com/mgm/mcrm/common/services/MGMApiService.java @@ -43,6 +43,7 @@ public class MGMApiService { private static final String API_GET_APPROVER="/RequestRoomBookingApprovalRouting"; private static final String API_GET_TODO_LIST = "/GetTodolist"; private static final String API_REQUEST_ROOM_CALENDAR = "/RequestRoomCalendar"; + private static final String API_GET_LIMO_BOOKING_FROM_LEGACY = "/GetLimoBookingFromLegacy"; public HttpResponseResult invokeRequestRoomCalendar( @@ -339,6 +340,26 @@ public class MGMApiService { return result; } + public HttpResponseResult invokeGetLimoBookingFromLegacy( + String playerId + ) throws Exception { + HttpResponseResult result = null; + String apiLink = API_GET_LIMO_BOOKING_FROM_LEGACY; + + JSONObject requestObj = new JSONObject(); + Map requestHeader = new HashMap<>(); + + String token = getAccessToken(); + + requestHeader.put("Authorization", token); + + requestObj.put("PlayerId", playerId); + + result = this.invokeESBAPI(ESB_Server, apiLink, requestObj, "POST", requestHeader); + return result; + } + + public HttpResponseResult invokeGetTodoList( String userId, String category, diff --git a/src/main/java/com/mgm/mcrm/common/services/MGMEsbApiService.java b/src/main/java/com/mgm/mcrm/common/services/MGMEsbApiService.java new file mode 100644 index 0000000..1615916 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/services/MGMEsbApiService.java @@ -0,0 +1,245 @@ +package com.mgm.mcrm.common.services; + +import com.alibaba.fastjson.JSONObject; +import com.google.gson.Gson; +import com.mgm.mcrm.common.constants.SysCommon; +import com.mgm.mcrm.common.dtos.http_util.HttpRequestDefine; +import com.mgm.mcrm.common.dtos.http_util.HttpResponseResult; +import com.mgm.mcrm.common.utils.DateTimeUtil; +import com.mgm.mcrm.common.utils.HttpUtil; +import com.mgm.mcrm.common.utils.LogUtil; +import com.mgm.mcrm.common.utils.mockup.HttpUtilMockup; +import com.mgm.mcrm.limo.dtos.request.RequestPlayerEsbBookerRequest; +import org.apache.commons.lang3.Strings; +import org.springframework.stereotype.Service; + +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +@Service +public class MGMEsbApiService { + + public static String LIMO_ESB_APP_ID = ""; + public static String LIMO_ESB_APP_SECRET = ""; + public static String LIMO_ESB_SERVER = ""; + public static String LIMO_ESB_ACCESS_TOKEN = ""; + public static Date LIMO_ESB_EXPIRED_TIME = new Date(); + + private static final String API_GET_ACCESS_TOKEN = "/RequestAccessToken"; + private static final String API_GET_LIMO_OVERRIDER = "/RequestLimoOverrider"; + private static final String API_CHECK_SIMPLE_LIMO_BOOKING_QUALIFICATION_STATUS = "/RequestSimpleLimoBookingQualificationStatus"; + private static final String API_CHECK_COMPLEX_LIMO_BOOKING_QUALIFICATION_STATUS = "/RequestComplexLimoBookingQualificationStatus"; + private static final String API_REQUEST_EMPLOYEE_INFO = "/RequestEmployeeInfo"; + private static final String API_REQUEST_PLAYER_LIMO_BOOKER = "/RequestPlayerLimoBooker"; + private static final String API_REQUEST_PLAYER_INFO = "/RequestPlayerInfo"; + + + public HttpResponseResult invokeRequestPlayerLimoBooker(RequestPlayerEsbBookerRequest request) throws Exception { + + String apiLink = API_REQUEST_PLAYER_LIMO_BOOKER; + + JSONObject requestObj = new JSONObject(); + Map requestHeader = new HashMap<>(); + + String token = getLimoAccessToken(); + + requestHeader.put("Authorization", token); + + requestObj.put("EmployeeIdOrName", request.getUserId()); + requestObj.put("PlayerId", request.getPlayerId()); + + return this.invokeESBAPI(LIMO_ESB_SERVER, apiLink, requestObj, "POST", requestHeader); + + } + + public String getLimoAccessToken() throws Exception { + + String token = LIMO_ESB_ACCESS_TOKEN; + + if (SysCommon.mgmApiMockup) + return token; + + LIMO_ESB_APP_ID = SysCommon.apiConfig.getLimoApp_id(); + LIMO_ESB_APP_SECRET = SysCommon.apiConfig.getLimoApp_key(); + LIMO_ESB_SERVER = SysCommon.apiConfig.getLimoService_ESB(); + + + if (token == null || LIMO_ESB_EXPIRED_TIME.getTime() < new Date().getTime()) { + + String apiLink = API_GET_ACCESS_TOKEN; + + JSONObject requestObj = new JSONObject(); + Map requestHeader = new HashMap<>(); + + requestObj.put("AppId", LIMO_ESB_APP_ID); + requestObj.put("AppSecret", LIMO_ESB_APP_SECRET); + + HttpResponseResult result = + this.invokeESBAPI(LIMO_ESB_SERVER, apiLink, requestObj, "POST", requestHeader); + + if (result.getStatusCode() == 200) { + JSONObject resultObj = JSONObject.parseObject(result.getResponseContent()); + String status = resultObj.getString("StatusCode"); + + if (Strings.CI.equals("OK", status)) { + token = resultObj.getString("Token"); + LIMO_ESB_EXPIRED_TIME = + DateTimeUtil.getDateFromString(resultObj.getString("ExpireTime"), "yyyy-MM-dd HH:mm:ss"); + LIMO_ESB_ACCESS_TOKEN = token; + } else { + token = null; + LIMO_ESB_ACCESS_TOKEN = null; + LIMO_ESB_EXPIRED_TIME = new Date(); + } + } + } + + return token; + } + + public HttpResponseResult invokeLimoOverrider( + String overriderIdOrName + ) throws Exception { + + String apiLink = API_GET_LIMO_OVERRIDER; + + JSONObject requestObj = new JSONObject(); + Map requestHeader = new HashMap<>(); + + String token = getLimoAccessToken(); + + requestHeader.put("Authorization", token); + + requestObj.put("OverriderIdOrName", "%"); + + return this.invokeESBAPI(LIMO_ESB_SERVER, apiLink, requestObj, "POST", requestHeader); + } + + public HttpResponseResult invokeLimoPlayerInfo( + Integer playerId + ) throws Exception { + + String apiLink = API_REQUEST_PLAYER_INFO; + + JSONObject requestObj = new JSONObject(); + Map requestHeader = new HashMap<>(); + + String token = getLimoAccessToken(); + + requestHeader.put("Authorization", token); + + requestObj.put("PlayerId", playerId); + + return this.invokeESBAPI(LIMO_ESB_SERVER, apiLink, requestObj, "POST", requestHeader); + } + + public HttpResponseResult invokeSimpleLimoBookingQualificationStatus( + Integer playerId, + String bookingType, + String bookingDate + ) throws Exception { + + String apiLink = API_CHECK_SIMPLE_LIMO_BOOKING_QUALIFICATION_STATUS; + + JSONObject requestObj = new JSONObject(); + Map requestHeader = new HashMap<>(); + + String token = getLimoAccessToken(); + + requestHeader.put("Authorization", token); + + requestObj.put("PlayerId", playerId); + requestObj.put("BookingType", bookingType); + requestObj.put("BookingDate", bookingDate); + + return this.invokeESBAPI(LIMO_ESB_SERVER, apiLink, requestObj, "POST", requestHeader); + } + + + public HttpResponseResult invokeRequestEmployeeInfo(String employeeId) throws Exception { + + String apiLink = API_REQUEST_EMPLOYEE_INFO; + + JSONObject requestObj = new JSONObject(); + Map requestHeader = new HashMap<>(); + + String token = getLimoAccessToken(); + + requestHeader.put("Authorization", token); + + requestObj.put("EmployeeId", employeeId); + + return this.invokeESBAPI(LIMO_ESB_SERVER, apiLink, requestObj, "POST", requestHeader); + } + + public HttpResponseResult invokeESBAPI( + String serverType, + String requestLink, + JSONObject requestContent, + String requestMethod, + Map requestHeader) throws Exception { + + String serverUrl; + int timeoutTime; + + //Get Spend Time + Gson gson = new Gson(); + + HttpRequestDefine requestDef = new HttpRequestDefine(); + + LogUtil.info(MGMEsbApiService.class,"Request Url = "+gson.toJson(requestDef.getRequestUrl())+"serverType: " + serverType+"LIMO_ESB_SERVER"+LIMO_ESB_SERVER); + + if (Strings.CS.equals(serverType, LIMO_ESB_SERVER)) { + serverUrl = SysCommon.apiConfig.getLimoService_ESB(); + timeoutTime = SysCommon.apiConfig.getTimeout_ESB(); + } else { + throw new Exception("Invalid server type"); + } + + String requestUrl = serverUrl + requestLink; + + requestDef.setRequestUrl(requestUrl); + requestDef.setRequestMethod(requestMethod); + requestDef.setTimeout(timeoutTime); + + requestHeader.put("Content-type", "application/json;charset=utf-8"); + + requestDef.setHeaders(requestHeader); + + if (requestContent != null) + requestDef.setEntityContent(requestContent.toString()); + else + requestDef.setEntityContent(""); + + //Get Start,EndTime + long spanTime; + Date startTime = new Date(); + + LogUtil.info(MGMEsbApiService.class, "[invokeESBAPI] start request:"); + + HttpResponseResult httpResult = (SysCommon.mgmApiMockup ? + HttpUtilMockup.processHttpRequest(requestDef) + : HttpUtil.processHttpRequest(requestDef)); + + httpResult.setRequestContent(requestDef.getEntityContent()); + + //RefreshEndTime + Date endTime = new Date(); + + spanTime = DateTimeUtil.getTimeSpanSSS(startTime, endTime); + + LogUtil.info(MGMEsbApiService.class, "[invokeLimoESBAPI]getRequestUrl:" + gson.toJson(requestDef.getRequestUrl())); + LogUtil.info(MGMEsbApiService.class, "[invokeLimoESBAPI]getHeaders:" + gson.toJson(requestDef.getHeaders())); + LogUtil.info(MGMEsbApiService.class, "[invokeLimoESBAPI]getRequestMethod:" + gson.toJson(requestDef.getRequestMethod())); + LogUtil.info(MGMEsbApiService.class, "[invokeLimoESBAPI]getEntityContent:" + gson.toJson(requestContent)); + LogUtil.info(MGMEsbApiService.class, "[invokeLimoESBAPI]getStatusCode:" + gson.toJson(httpResult.getStatusCode())); + LogUtil.info(MGMEsbApiService.class, "[invokeLimoESBAPI]getErrorMessage:" + gson.toJson(httpResult.getErrorMessage())); + LogUtil.info(MGMEsbApiService.class, "[invokeLimoESBAPI]getResponseContent:" + gson.toJson(httpResult.getResponseContent())); + + //Log Spend Time + LogUtil.info(MGMEsbApiService.class, "[invokeLimoESBAPI]SpendTime:" + spanTime + "ms"); + + return httpResult; + } +} \ No newline at end of file diff --git a/src/main/java/com/mgm/mcrm/common/services/MGMLimoApiService.java b/src/main/java/com/mgm/mcrm/common/services/MGMLimoApiService.java new file mode 100644 index 0000000..f3fd79c --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/services/MGMLimoApiService.java @@ -0,0 +1,643 @@ +package com.mgm.mcrm.common.services; + +import com.alibaba.fastjson.JSONObject; +import com.mgm.mcrm.common.constants.SysCommon; +import com.mgm.mcrm.common.dtos.http_util.HttpRequestDefine; +import com.mgm.mcrm.common.dtos.http_util.HttpResponseResult; +import com.mgm.mcrm.common.utils.HttpUtil; +import com.mgm.mcrm.common.utils.LogUtil; +import com.mgm.mcrm.common.utils.mockup.HttpUtilMockup; +import com.mgm.mcrm.limo.dtos.request.*; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.time.format.DateTimeFormatter; +import java.util.*; +import java.util.stream.Collectors; + +@Service +public class MGMLimoApiService { + + public static String ESB_LIMO_SERVER = ""; + public static String ESB_LIMO_ACCESS_TOKEN = null; + public static String ESB_LIMO_APP_ID; + public static String ESB_LIMO_APP_SECRET; + public static Date ESB_LIMO_EXPIRED_TIME = new Date(); + + private static final String API_GET_ACCESS_TOKEN = "GetAccessToken"; + private static final String API_GET_TRIP_PRICE = "GetTripPrice"; + private static final String API_GET_LOCATION = "GetLocation"; + private static final String API_GET_CAR_TYPE = "GetCarType"; + private static final String API_GET_GREET_TYPE = "GetGreetType"; + private static final String API_GET_BOOKING = "GetBooking"; + private static final String API_CREATE_BOOKING = "CreateBooking"; + private static final String API_UPDATE_BOOKING = "UpdateBooking"; + private static final String API_UPDATE_BOOKING_STATUS = "UpdateBookingStatus"; + private static final String API_GET_FLIGHT_DETAILS= "GetFlightDetails"; + private static final String API_GET_TOTAL_AMOUNT = "GetTotalAmount"; + +// private static final String API_MAIN_HANDLER_HANDLER = "http://mmlimodevapp01/MCRMAPI/API/MainHandler.ashx "; + + + @Value("${limo_address}") + private String API_MAIN_HANDLER; + @Value("${limo_getAccessToken_Id}") + private String apiGetAccessTokenId; + @Value("${limo_getAccessToken_pwd}") + private String apiGetAccessTokenPwd; + + + public HttpResponseResult invokeGetTripPrice() throws Exception { + + Map requestObj = new HashMap<>(); + + String token = getLimoAccessToken(); + + requestObj.put("action", API_GET_TRIP_PRICE); + requestObj.put("token", token); + + return this.invokeESBFormUrlEncodedAPI(ESB_LIMO_SERVER, API_MAIN_HANDLER, requestObj, "POST", null); + } + + public HttpResponseResult invokeGetLocation(String location) throws Exception { + + Map requestObj = new HashMap<>(); + + String token = getLimoAccessToken(); + + requestObj.put("action", API_GET_LOCATION); + requestObj.put("token", token); + requestObj.put("Location", "%"); + + return this.invokeESBFormUrlEncodedAPI(ESB_LIMO_SERVER, API_MAIN_HANDLER, requestObj, "POST", null); + } + + public HttpResponseResult invokeGetCarType() throws Exception { + + Map requestObj = new HashMap<>(); + + String token = getLimoAccessToken(); + + requestObj.put("action", API_GET_CAR_TYPE); + requestObj.put("token", token); + + return this.invokeESBFormUrlEncodedAPI(ESB_LIMO_SERVER, API_MAIN_HANDLER, requestObj, "POST", null); + + } + + + public HttpResponseResult invokeGetGreetType() throws Exception { + + Map requestObj = new HashMap<>(); + + String token = getLimoAccessToken(); + + requestObj.put("action", API_GET_GREET_TYPE); + requestObj.put("token", token); + + return this.invokeESBFormUrlEncodedAPI(ESB_LIMO_SERVER, API_MAIN_HANDLER, requestObj, "POST", null); + } + + public HttpResponseResult invokeGetBooking(String bookingId) throws Exception { + + Map requestObj = new HashMap<>(); + + String token = getLimoAccessToken(); + + if(bookingId != null) requestObj.put("Id",bookingId); + + requestObj.put("action", API_GET_BOOKING); + requestObj.put("token", token); + + return this.invokeESBFormUrlEncodedAPI(ESB_LIMO_SERVER, API_MAIN_HANDLER, requestObj, "POST", null); + } + public HttpResponseResult getFlightDetails(GetLimoFlightDetailsRequest request) throws Exception { + + Map requestObj = new HashMap<>(); + + String token = getLimoAccessToken(); + + JSONObject itemObject = new JSONObject(); + itemObject.put("FlightNo", request.getFlightNo()); + itemObject.put("PickupDatetime", request.getPickupDateTime()); + itemObject.put("PickupAirportCode", request.getPickupAirportCode()); + itemObject.put("DropoffAirportCode", request.getDropOffAirportCode() != null ? request.getDropOffAirportCode() : ""); + + requestObj.put("action", API_GET_FLIGHT_DETAILS); + requestObj.put("token", token); + requestObj.put("itemObject", itemObject.toJSONString()); + + return this.invokeESBFormUrlEncodedAPI(ESB_LIMO_SERVER, API_MAIN_HANDLER, requestObj, "POST", null); + } + + public HttpResponseResult getTotalAmount(GetLimoTotalAmountRequest request) throws Exception { + + Map requestObj = new HashMap<>(); + + String token = getLimoAccessToken(); + + JSONObject itemObject = new JSONObject(); + itemObject.put("PickupPOIID", blankToZero(request.getPickupPOIId())); + + List dropoffPoiIds = splitSemicolonValues(request.getDropoffPOIIds()); + itemObject.put("DropoffPOIID", valueAtOrZero(dropoffPoiIds, 0)); + for (int i = 1; i <= 10; i++) { + itemObject.put("ExtraDropoffPOIID" + i, valueAtOrZero(dropoffPoiIds, i)); + } + + List tripPrices = splitSemicolonValues(request.getSingleTripPrices()); + itemObject.put("SingleTripPrice", valueAtOrZero(tripPrices, 0)); + for (int i = 1; i <= 10; i++) { + itemObject.put("ExtraDropoffPrice" + i, valueAtOrZero(tripPrices, i)); + } + + requestObj.put("action", API_GET_TOTAL_AMOUNT); + requestObj.put("token", token); + requestObj.put("itemObject", itemObject.toJSONString()); + + return this.invokeESBFormUrlEncodedAPI(ESB_LIMO_SERVER, API_MAIN_HANDLER, requestObj, "POST", null); + } + + /** 按 {@code ;} 拆分,去掉空白段;例如 {@code 1;2;3} → [1,2,3] */ + private static List splitSemicolonValues(String value) { + if (!StringUtils.isNotBlank(value)) { + return List.of(); + } + return Arrays.stream(value.split(";")) + .map(String::trim) + .filter(StringUtils::isNotBlank) + .collect(Collectors.toList()); + } + + private static String valueAtOrZero(List values, int index) { + if (values == null || index >= values.size()) { + return "0"; + } + return values.get(index); + } + + private static String blankToZero(String value) { + return StringUtils.isNotBlank(value) ? value.trim() : "0"; + } + + public HttpResponseResult invokeCreateBooking(InternalCreateLimoBookingRequest r) throws Exception { + + Map requestObj = new HashMap<>(); + String token = getLimoAccessToken(); + + DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + + StringBuilder sb = new StringBuilder(); + sb.append("{'CreateNotConfirmBooking':'").append(r.getCreateNotConfirmBooking()).append("'"); + sb.append(",'BookingType':'").append(s(r.getBookingType())).append("'"); + sb.append(",'GreetType':'").append(s(r.getGreetType())).append("'"); + sb.append(",'OtherGreetType':'").append(s(r.getOtherGreetType())).append("'"); + sb.append(",'GuestType':'").append(s(r.getGuestType())).append("'"); + sb.append(",'TripType':'").append(s(r.getTripType())).append("'"); + + sb.append(",'PlayerID':'").append(s(r.getPlayerId())).append("'"); + sb.append(",'Ranking':'").append(s(r.getRanking())).append("'"); + sb.append(",'MaskedTier':'").append(s(r.getMaskedTier())).append("'"); + sb.append(",'OverrideBy':'").append(s(r.getOverrideBy())).append("'"); + sb.append(",'ComplexOverrider':'").append(s(r.getComplexOverrider())).append("'"); + + sb.append(",'RoomNo':'").append(s(r.getRoomNo())).append("'"); + sb.append(",'EmployeeID':'").append(s(r.getEmployeeId())).append("'"); + sb.append(",'CreateBy':'").append(s(r.getCreateBy())).append("'"); + + sb.append(",'LastName':'").append(s(r.getLastName())).append("'"); + sb.append(",'FirstName':'").append(s(r.getFirstName())).append("'"); + sb.append(",'Salution':'").append(s(r.getSalution())).append("'"); + sb.append(",'ChineseLastName':'").append(s(r.getChineseLastName())).append("'"); + sb.append(",'ChineseFirstName':'").append(s(r.getChineseFirstName())).append("'");; + + sb.append(",'BookerContact':'").append(s(r.getBookerContact())).append("'"); + sb.append(",'BookingContact':'").append(s(r.getBookingContact())).append("'");; + sb.append(",'TenOutContact':'").append(s(r.getTenOutContact())).append("'");; + sb.append(",'GuestContact':'").append(s(r.getGuestContact())).append("'");; + sb.append(",'MAContact':'").append(s(r.getBookerContact())).append("'"); + sb.append(",'TripContact':'").append(s(r.getTripContact())).append("'"); + + sb.append(",'AdHoc':'").append(r.getAdHoc()).append("'"); + sb.append(",'PickupDatetime':'") + .append(r.getPickupDatetime() != null ? r.getPickupDatetime().format(dtf) : "") + .append("'"); + sb.append(",'CarTypeID':").append(n(r.getCarTypeId())); + sb.append(",'PassengerNo':").append(n(r.getPassengerNo())); + + sb.append(",'PickupPOIID':").append(n(r.getPickupPOIID())); + sb.append(",'Pickup':'").append(s(r.getPickup())).append("'"); + sb.append(",'PickupTripPriceId':").append(n(r.getPickupTripPriceId())); + sb.append(",'PickupRegion':'").append(s(r.getPickupRegion())).append("'"); + + sb.append(",'DropoffPOIID':").append(n(r.getDropoffPOIID())); + sb.append(",'Dropoff':'").append(s(r.getDropoff())).append("'"); + sb.append(",'DropoffTripPriceID':").append(n(r.getDropoffTripPriceId())); + sb.append(",'DropoffRegion':'").append(s(r.getDropoffRegion())).append("'"); + + for (int i = 1; i <= 10; i++) { + sb.append(",'ExtraDropoffPOIID").append(i).append("':").append(n(extraDropoffPOIID(r, i))); + sb.append(",'ExtraDropoff").append(i).append("':'").append(s(extraDropoff(r, i))).append("'"); + sb.append(",'ExtraDropoffTripPriceID").append(i).append("':").append(n(extraDropoffTripPriceID(r, i))); + sb.append(",'ExtraDropoffRegion").append(i).append("':'").append(s(extraDropoffRegion(r, i))).append("'"); + } + + sb.append(",'SingleTripPrice':'").append(bd(r.getSingleTripPrice())).append("'"); + sb.append(",'DefaultTripPrice':'").append(bd(r.getDefaultTripPrice())).append("'"); + sb.append(",'DefaultPublishTripPrice':'").append(bd(r.getDefaultPublishTripPrice())).append("'"); + + sb.append(",'HourlyRate':'").append(bd(r.getHourlyRate())).append("'"); + sb.append(",'HourlyWaitingFee':'").append(bd(r.getHourlyWaitingFee())).append("'"); + sb.append(",'Hour':").append(n(r.getHour())); + sb.append(",'HourlyWaiting':").append(n(r.getHourlyWaiting())); + + for (int i = 1; i <= 10; i++) { + sb.append(",'ExtraDropoffPrice").append(i).append("':'").append(bd(extraDropoffPrice(r, i))).append("'"); + } + + sb.append(",'HotelLimoPrice':'0.00'"); + sb.append(",'OtherPriceRemark':'").append(s(r.getOtherPriceRemark())).append("'"); + sb.append(",'OtherPrice':'").append(bd(r.getOtherPrice())).append("'"); + + sb.append(",'PaymentMethod':'").append(s(r.getPaymentMethod())).append("'"); + sb.append(",'TotalAmount':'").append(bd(r.getTotalAmount())).append("'"); + + sb.append(",'HighImportance':").append(b(r.getHighImportance())); + sb.append(",'TenOut':").append(b(r.getTenOut())); + sb.append(",'ButlerGreet':").append(b(r.getButlerGreet())); + + sb.append(",'BookedBy':'").append(s(r.getBookedBy())).append("'"); + sb.append(",'ApprovedBy':'").append(s(r.getApprovedBy())).append("'"); + + sb.append(",'BookingRemark':'").append(s(r.getBookingRemark())).append("'"); + sb.append(",'DriverRemark':'").append(s(r.getDriverRemark())).append("'"); + sb.append(",'LimoInternalRemark':'").append(s(r.getLimoInternalRemark())).append("'"); + sb.append(",'SystemRemark':'").append(s(r.getSystemRemark())).append("'"); + + sb.append(",'LimoGreet':").append(b(r.getLimoGreet())); + sb.append(",'HostGreet':").append(b(r.getHostGreet())); + sb.append(",'VIPMeetNGreet':").append(b(r.getVipMeetNGreet())); + + sb.append(",'OtherGreet':'").append(s(r.getOtherGreet())).append("'"); + sb.append(",'FlightDetails':'").append(s(r.getFlightDetails())).append("'"); + sb.append(",'ETA':'").append(r.getPickupDatetime() != null ? r.getPickupDatetime().format(dtf) : "2000-01-01 00:00:00").append("'"); + sb.append(",'Signage':'").append(s(r.getSignage())).append("'"); + sb.append(",'FlightStatus':''"); + sb.append(",'CancelReason':''}"); + + requestObj.put("action", API_CREATE_BOOKING); + requestObj.put("itemObject", sb.toString()); + requestObj.put("token", token); + + return this.invokeESBFormUrlEncodedAPI(ESB_LIMO_SERVER, API_MAIN_HANDLER, requestObj, "POST", null); + } + + // ---- Limo format helpers: single-quote + PascalCase + 1/0 for booleans ---- + + private static String s(String v) { return v != null ? v : ""; } + private static String n(Integer v) { return v != null ? String.valueOf(v) : "0"; } + private static String n(Long v) { return v != null ? String.valueOf(v) : "0"; } + private static String b(Boolean v) { return v != null && v ? "1" : "0"; } + private static String bd(java.math.BigDecimal v) { + return v != null ? v.toPlainString() : "0.00"; + } + + private static Long extraDropoffPOIID(InternalCreateLimoBookingRequest r, int i) { + return switch (i) { + case 1 -> r.getExtraDropoffPOIID1(); + case 2 -> r.getExtraDropoffPOIID2(); + case 3 -> r.getExtraDropoffPOIID3(); + case 4 -> r.getExtraDropoffPOIID4(); + case 5 -> r.getExtraDropoffPOIID5(); + case 6 -> r.getExtraDropoffPOIID6(); + case 7 -> r.getExtraDropoffPOIID7(); + case 8 -> r.getExtraDropoffPOIID8(); + case 9 -> r.getExtraDropoffPOIID9(); + case 10 -> r.getExtraDropoffPOIID10(); + default -> 0L; + }; + } + private static String extraDropoff(InternalCreateLimoBookingRequest r, int i) { + return switch (i) { + case 1 -> r.getExtraDropoff1(); + case 2 -> r.getExtraDropoff2(); + case 3 -> r.getExtraDropoff3(); + case 4 -> r.getExtraDropoff4(); + case 5 -> r.getExtraDropoff5(); + case 6 -> r.getExtraDropoff6(); + case 7 -> r.getExtraDropoff7(); + case 8 -> r.getExtraDropoff8(); + case 9 -> r.getExtraDropoff9(); + case 10 -> r.getExtraDropoff10(); + default -> ""; + }; + } + private static Long extraDropoffTripPriceID(InternalCreateLimoBookingRequest r, int i) { + return switch (i) { + case 1 -> r.getExtraDropoffTripPriceID1(); + case 2 -> r.getExtraDropoffTripPriceID2(); + case 3 -> r.getExtraDropoffTripPriceID3(); + case 4 -> r.getExtraDropoffTripPriceID4(); + case 5 -> r.getExtraDropoffTripPriceID5(); + case 6 -> r.getExtraDropoffTripPriceID6(); + case 7 -> r.getExtraDropoffTripPriceID7(); + case 8 -> r.getExtraDropoffTripPriceID8(); + case 9 -> r.getExtraDropoffTripPriceID9(); + case 10 -> r.getExtraDropoffTripPriceID10(); + default -> 0L; + }; + } + private static String extraDropoffRegion(InternalCreateLimoBookingRequest r, int i) { + return switch (i) { + case 1 -> r.getExtraDropoffRegion1(); + case 2 -> r.getExtraDropoffRegion2(); + case 3 -> r.getExtraDropoffRegion3(); + case 4 -> r.getExtraDropoffRegion4(); + case 5 -> r.getExtraDropoffRegion5(); + case 6 -> r.getExtraDropoffRegion6(); + case 7 -> r.getExtraDropoffRegion7(); + case 8 -> r.getExtraDropoffRegion8(); + case 9 -> r.getExtraDropoffRegion9(); + case 10 -> r.getExtraDropoffRegion10(); + default -> ""; + }; + } + private static java.math.BigDecimal extraDropoffPrice(InternalCreateLimoBookingRequest r, int i) { + return switch (i) { + case 1 -> r.getExtraDropoffPrice1(); + case 2 -> r.getExtraDropoffPrice2(); + case 3 -> r.getExtraDropoffPrice3(); + case 4 -> r.getExtraDropoffPrice4(); + case 5 -> r.getExtraDropoffPrice5(); + case 6 -> r.getExtraDropoffPrice6(); + case 7 -> r.getExtraDropoffPrice7(); + case 8 -> r.getExtraDropoffPrice8(); + case 9 -> r.getExtraDropoffPrice9(); + case 10 -> r.getExtraDropoffPrice10(); + default -> java.math.BigDecimal.ZERO; + }; + } + + public HttpResponseResult invokeUpdateBooking(InternalUpdateLimoBookingRequest request) throws Exception { + + Map requestObj = new HashMap<>(); + String token = getLimoAccessToken(); + + DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + + StringBuilder sb = new StringBuilder(); + sb.append("{'ID':'").append(s(request.getId())).append("'"); + appendBooleanUpdate(sb, "CreateNotConfirmBooking", request.getCreateNotConfirmBooking()); + + if (request.getPickupDatetime() != null) { + appendStringUpdate(sb, "PickupDatetime", request.getPickupDatetime().format(dateFormat)); + } + appendNumberUpdate(sb, "PickupPOIID", request.getPickupPOIID()); + appendStringUpdate(sb, "Pickup", request.getPickup()); + appendStringUpdate(sb, "BookingType", request.getBookingType()); + appendStringUpdate(sb, "PickupRegion", request.getPickupRegion()); + appendStringUpdate(sb, "EditBy", request.getEditBy()); + + appendNumberUpdate(sb, "DropoffPOIID", request.getDropoffPOIID()); + appendStringUpdate(sb, "Dropoff", request.getDropoff()); + appendStringUpdate(sb, "DropoffRegion", request.getDropoffRegion()); + + appendExtraDropoffLocationUpdate(sb, 1, request.getExtraDropoffPOIID1(), request.getExtraDropoff1()); + appendExtraDropoffLocationUpdate(sb, 2, request.getExtraDropoffPOIID2(), request.getExtraDropoff2()); + appendExtraDropoffLocationUpdate(sb, 3, request.getExtraDropoffPOIID3(), request.getExtraDropoff3()); + appendExtraDropoffLocationUpdate(sb, 4, request.getExtraDropoffPOIID4(), request.getExtraDropoff4()); + appendExtraDropoffLocationUpdate(sb, 5, request.getExtraDropoffPOIID5(), request.getExtraDropoff5()); + appendExtraDropoffLocationUpdate(sb, 6, request.getExtraDropoffPOIID6(), request.getExtraDropoff6()); + appendExtraDropoffLocationUpdate(sb, 7, request.getExtraDropoffPOIID7(), request.getExtraDropoff7()); + appendExtraDropoffLocationUpdate(sb, 8, request.getExtraDropoffPOIID8(), request.getExtraDropoff8()); + appendExtraDropoffLocationUpdate(sb, 9, request.getExtraDropoffPOIID9(), request.getExtraDropoff9()); + appendExtraDropoffLocationUpdate(sb, 10, request.getExtraDropoffPOIID10(), request.getExtraDropoff10()); + + appendDecimalUpdate(sb, "SingleTripPrice", request.getSingleTripPrice()); + appendDecimalUpdate(sb, "DefaultTripPrice", request.getDefaultTripPrice()); + appendDecimalUpdate(sb, "DefaultPublishTripPrice", request.getDefaultPublishTripPrice()); + appendDecimalUpdate(sb, "HourlyRate", request.getHourlyRate()); + appendDecimalUpdate(sb, "HourlyWaitingFee", request.getHourlyWaitingFee()); + appendIntegerUpdate(sb, "Hour", request.getHour()); + appendIntegerUpdate(sb, "HourlyWaiting", request.getHourlyWaiting()); + appendDecimalUpdate(sb, "ExtraDropoffPrice1", request.getExtraDropoffPrice1()); + appendDecimalUpdate(sb, "ExtraDropoffPrice2", request.getExtraDropoffPrice2()); + appendDecimalUpdate(sb, "ExtraDropoffPrice3", request.getExtraDropoffPrice3()); + appendDecimalUpdate(sb, "ExtraDropoffPrice4", request.getExtraDropoffPrice4()); + appendDecimalUpdate(sb, "ExtraDropoffPrice5", request.getExtraDropoffPrice5()); + appendDecimalUpdate(sb, "ExtraDropoffPrice6", request.getExtraDropoffPrice6()); + appendDecimalUpdate(sb, "ExtraDropoffPrice7", request.getExtraDropoffPrice7()); + appendDecimalUpdate(sb, "ExtraDropoffPrice8", request.getExtraDropoffPrice8()); + appendDecimalUpdate(sb, "ExtraDropoffPrice9", request.getExtraDropoffPrice9()); + appendDecimalUpdate(sb, "ExtraDropoffPrice10", request.getExtraDropoffPrice10()); + appendDecimalUpdate(sb, "TotalAmount", request.getTotalAmount()); + + appendStringUpdate(sb, "BookingRemark", request.getBookingRemark()); + sb.append("}"); + + requestObj.put("action", API_UPDATE_BOOKING); + requestObj.put("itemObject", sb.toString()); + requestObj.put("token", token); + + return this.invokeESBFormUrlEncodedAPI(ESB_LIMO_SERVER, API_MAIN_HANDLER, requestObj, "POST", null); + } + + private static void appendStringUpdate(StringBuilder sb, String fieldName, String value) { + if (value != null) { + sb.append(",'").append(fieldName).append("':'").append(s(value)).append("'"); + } + } + + private static void appendNumberUpdate(StringBuilder sb, String fieldName, Long value) { + if (value != null) { + sb.append(",'").append(fieldName).append("':").append(value); + } + } + + private static void appendIntegerUpdate(StringBuilder sb, String fieldName, Integer value) { + if (value != null) { + sb.append(",'").append(fieldName).append("':").append(value); + } + } + + private static void appendDecimalUpdate( + StringBuilder sb, String fieldName, java.math.BigDecimal value) { + if (value != null) { + sb.append(",'").append(fieldName).append("':'").append(value.toPlainString()).append("'"); + } + } + + private static void appendBooleanUpdate(StringBuilder sb, String fieldName, Boolean value) { + if (value != null) { + sb.append(",'").append(fieldName).append("':'").append(value ? "1" : "0").append("'"); + } + } + + private static void appendExtraDropoffLocationUpdate(StringBuilder sb, int i, Long poiId, String name) { + appendNumberUpdate(sb, "ExtraDropoffPOIID" + i, poiId); + appendStringUpdate(sb, "ExtraDropoff" + i, name); + } + + public HttpResponseResult invokeCancelLimoBooking(InternalCancelLimoBookingRequest request) throws Exception{ + + Map requestObj = new HashMap<>(); + + String token = getLimoAccessToken(); + + JSONObject itemObject = new JSONObject(); + + itemObject.put("ID", request.getBookingId()); + itemObject.put("EditBy", request.getEditBy()); + itemObject.put("BookingStatus", "Cancel"); + + requestObj.put("token", token); + requestObj.put("itemObject", itemObject.toJSONString()); + requestObj.put("action", API_UPDATE_BOOKING_STATUS); + + + return this.invokeESBFormUrlEncodedAPI(ESB_LIMO_SERVER, API_MAIN_HANDLER, requestObj, "POST", null); + } + + private String getLimoAccessToken() throws Exception { + + String token = ESB_LIMO_ACCESS_TOKEN; + + if (SysCommon.mgmApiMockup) + return token; + + + ESB_LIMO_APP_ID = SysCommon.apiConfig.getApiKey_ESB(); + ESB_LIMO_APP_SECRET = SysCommon.apiConfig.getApiSecret_ESB(); + ESB_LIMO_SERVER = SysCommon.apiConfig.getServerUrl_ESB(); + + if (token == null || ESB_LIMO_EXPIRED_TIME.getTime() < new Date().getTime()) { + + String itemObject = String.format( + "{'LoginID':'%s','Password':'%s'}", + apiGetAccessTokenId, + apiGetAccessTokenPwd); + + Map formData = new HashMap<>(); + formData.put("action", API_GET_ACCESS_TOKEN); + formData.put("itemObject", itemObject); + + HttpResponseResult result = this.invokeESBFormUrlEncodedAPI( + ESB_LIMO_SERVER, + API_MAIN_HANDLER, + formData, + "POST", + null); + + if (result.getStatusCode() == 200) { + JSONObject resultObj = JSONObject.parseObject(result.getResponseContent()); + String status = resultObj.getString("result"); + + if (Strings.CI.equals("200", status)) { + token = resultObj.getString("token"); + ESB_LIMO_ACCESS_TOKEN = token; + } else { + token = null; + ESB_LIMO_ACCESS_TOKEN = null; + } + } + } + + return token; + } + + public HttpResponseResult invokeESBFormUrlEncodedAPI( + String serverUrl, + String requestLink, + Map formData, + String requestMethod, + Map requestHeader) throws Exception { + + HttpRequestDefine requestDef = new HttpRequestDefine(); + String requestUrl = requestLink; + Map headers = (requestHeader == null ? new HashMap<>() : new HashMap<>(requestHeader)); + String requestBody = buildFormUrlEncodedBody(formData); + + requestDef.setRequestUrl(requestUrl); + requestDef.setRequestMethod(requestMethod); + requestDef.setHeaders(headers); + requestDef.setEntityContent(requestBody); + + headers.put("Content-type", "application/x-www-form-urlencoded;charset=utf-8"); + + LogUtil.info(MGMLimoApiService.class, "[invokeFormUrlEncodedAPI] Limo RequestUrl:" + requestUrl); + LogUtil.info(MGMLimoApiService.class, "[invokeFormUrlEncodedAPI] Limo RequestBody:" + requestBody); + + HttpResponseResult httpResult = (SysCommon.mgmApiMockup ? HttpUtilMockup.processHttpRequest(requestDef) + : HttpUtil.processHttpRequest(requestDef)); + + JSONObject resultObj = JSONObject.parseObject(httpResult.getResponseContent()); + String status = (resultObj == null ? null : resultObj.getString("result")); + + if (Strings.CS.equals("201", status)) { + formData.put("token", this.getLimoAccessToken()); + requestDef.setEntityContent(buildFormUrlEncodedBody(formData)); + + LogUtil.info(MGMLimoApiService.class, "[invokeFormUrlEncodedAPI] Token expired Retry Limo RequestUrl:" + requestUrl); + LogUtil.info(MGMLimoApiService.class, "[invokeFormUrlEncodedAPI] Token expired Retry Limo RequestBody:" + requestBody); + + httpResult = (SysCommon.mgmApiMockup ? HttpUtilMockup.processHttpRequest(requestDef) + : HttpUtil.processHttpRequest(requestDef)); + } + + String responseContent = httpResult.getResponseContent(); + int responseLength = (responseContent == null ? 0 : responseContent.length()); + LogUtil.info(MGMLimoApiService.class, "[invokeFormUrlEncodedAPI] Limo action:" + (formData == null ? null : formData.get("action")) + + " Limo ResponseLength:" + responseLength + + " Status=" + httpResult.getStatusCode()); + + httpResult.setRequestContent(requestBody); + return httpResult; + } + + private String buildFormUrlEncodedBody(Map formData) { + if (formData == null || formData.isEmpty()) + return ""; + + StringBuilder body = new StringBuilder(); + for (Map.Entry entry : formData.entrySet()) { + if (!body.isEmpty()) + body.append("&"); + + body.append(URLEncoder.encode(entry.getKey(), StandardCharsets.UTF_8)); + body.append("="); + body.append(encodeFormValue(entry.getValue())); + } + + return body.toString(); + } + + /** + * 对 form value 做最小化编码,只转义会破坏 form-urlencoded 结构的字符, + * 保留 JSON 结构符号 ({ } " : , [ ]) 原样,与 Postman 行为一致。 + */ + private String encodeFormValue(String value) { + if (value == null) + return ""; + + StringBuilder sb = new StringBuilder(value.length()); + for (int i = 0; i < value.length(); i++) { + char c = value.charAt(i); + switch (c) { + case '&': sb.append("%26"); break; + case '=': sb.append("%3D"); break; +// case ' ': sb.append("+"); break; + case '%': sb.append("%25"); break; + case '\n': sb.append("%0A"); break; + case '\r': sb.append("%0D"); break; + default: sb.append(c); break; + } + } + return sb.toString(); + } + + +} diff --git a/src/main/java/com/mgm/mcrm/common/utils/mockup/HttpUtilMockup.java b/src/main/java/com/mgm/mcrm/common/utils/mockup/HttpUtilMockup.java index 78211d1..0a36b4c 100644 --- a/src/main/java/com/mgm/mcrm/common/utils/mockup/HttpUtilMockup.java +++ b/src/main/java/com/mgm/mcrm/common/utils/mockup/HttpUtilMockup.java @@ -8,6 +8,8 @@ import com.mgm.mcrm.common.dtos.http_util.HttpRequestDefine; import com.mgm.mcrm.common.dtos.http_util.HttpResponseResult; import com.mgm.mcrm.common.utils.LogUtil; +import java.net.URLDecoder; +import java.nio.charset.StandardCharsets; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; @@ -29,6 +31,67 @@ public class HttpUtilMockup { return mockupConfig; } + private static boolean isApiLinkMatch(String requestLink, String requestContent, String apiLink) { + if (apiLink == null || apiLink.isEmpty()) { + return false; + } + if (requestLink != null && requestLink.contains(apiLink)) { + return true; + } + JSONObject formObj = parseFormUrlEncoded(requestContent); + return formObj != null && apiLink.equals(formObj.getString("action")); + } + + private static JSONObject parseRequestObject(String requestContent) { + if (requestContent == null || requestContent.isEmpty()) { + return null; + } + try { + JSONObject requestObj = JSONObject.parseObject(requestContent); + if (requestObj != null) { + return requestObj; + } + } catch (Exception err) { + } + return parseFormUrlEncoded(requestContent); + } + + private static JSONObject parseFormUrlEncoded(String requestContent) { + if (requestContent == null || requestContent.isEmpty() || requestContent.indexOf('=') < 0) { + return null; + } + String trimmed = requestContent.trim(); + if (trimmed.startsWith("{") || trimmed.startsWith("[")) { + return null; + } + JSONObject formObj = new JSONObject(); + String[] pairs = requestContent.split("&"); + for (int i = 0; i < pairs.length; i++) { + String pair = pairs[i]; + int eqIndex = pair.indexOf('='); + if (eqIndex <= 0) { + continue; + } + String key = urlDecode(pair.substring(0, eqIndex)); + String value = urlDecode(pair.substring(eqIndex + 1)); + if (!key.isEmpty()) { + formObj.put(key, value); + } + } + return formObj.isEmpty() ? null : formObj; + } + + private static String urlDecode(String value) { + if (value == null || value.isEmpty()) { + return ""; + } + try { + return URLDecoder.decode(value, StandardCharsets.UTF_8); + } catch (Exception err) { + return value; + } + } + private static String findMockResultByLink(String requestLink,String requestContent) { String result =""; JSONArray configData = getMockupConfig(); @@ -36,13 +99,8 @@ public class HttpUtilMockup { JSONObject checkItem = configData.getJSONObject(i); if(checkItem.containsKey("apiLink") && checkItem.containsKey("resultFiles")) { String apiLink = checkItem.getString("apiLink"); - if(requestLink.contains(apiLink)) { - JSONObject requestObj = null; - try { - requestObj = JSONObject.parseObject(requestContent); - }catch(Exception err) { - - } + if(isApiLinkMatch(requestLink, requestContent, apiLink)) { + JSONObject requestObj = parseRequestObject(requestContent); int resultIndex =0; if(checkItem.containsKey("resultIndex")) { resultIndex=checkItem.getIntValue("resultIndex"); diff --git a/src/main/java/com/mgm/mcrm/limo/controller/LimoController.java b/src/main/java/com/mgm/mcrm/limo/controller/LimoController.java new file mode 100644 index 0000000..b1a56b3 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/limo/controller/LimoController.java @@ -0,0 +1,312 @@ +package com.mgm.mcrm.limo.controller; + +import com.auth0.jwt.JWT; +import com.mgm.mcrm.authorization.models.SysRouterPermission; +import com.mgm.mcrm.authorization.services.MgmUserService; +import com.mgm.mcrm.authorization.services.SysGroupPermissionService; +import com.mgm.mcrm.common.constants.SysCommon; +import com.mgm.mcrm.common.dtos.BaseApiResponse; +import com.mgm.mcrm.common.dtos.mgm_api.PlayerProfileEntry; +import com.mgm.mcrm.common.dtos.mgm_api.UserInfoApiRecord; +import com.mgm.mcrm.limo.dtos.request.GetLimoFlightDetailsRequest; +import com.mgm.mcrm.limo.dtos.request.GetLimoTotalAmountRequest; +import com.mgm.mcrm.limo.dtos.request.RequestPlayerEsbBookerRequest; +import com.mgm.mcrm.limo.dtos.request.*; +import com.mgm.mcrm.limo.dtos.response.*; +import com.mgm.mcrm.limo.models.LimoBookings; +import com.mgm.mcrm.player.services.PlayerService; +import jakarta.annotation.Resource; + +import com.mgm.mcrm.limo.services.LimoService; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.validation.Valid; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.*; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@RestController +@RequestMapping("/api/limo") +public class LimoController { + + @Resource + private LimoService limoService; + @Resource + private SysGroupPermissionService sysGroupPermissionService; + @Resource + private PlayerService playerService; + @Resource + private MgmUserService userService; + + @RequestMapping(value = "/search_limo", method = RequestMethod.POST, produces = "application/json;charset=UTF-8",consumes = MediaType.APPLICATION_JSON_VALUE) + public List limoRecordSearch(HttpServletRequest request, @RequestBody Map params) throws Exception { + HashMap member = (HashMap)params.get("member"); + String playerId = String.valueOf(member.get("playerId")); + List response = new ArrayList<>(); + + boolean havePermission = sysGroupPermissionService.checkAppPermission(request,"10001_08"); + + if (havePermission) { + if(!SysCommon.mgmApiMockup) + limoService.getTodayBooking(playerId); + response = limoService.getBookingsByPlayerId(playerId, request); + } + + + return response; + } + + @GetMapping("/getTripPriceList") + public BaseApiResponse> getTripPriceList() throws Exception { + return limoService.getTripPriceList(); + } + + @GetMapping("/getLocation") + public BaseApiResponse> getLocation(@RequestParam String location) + throws Exception { + return limoService.getLocation(location); + } + + @GetMapping("/getCarType") + public BaseApiResponse> getCarType() throws Exception { + return limoService.getCarType(); + } + + @GetMapping("/getGreetType") + public BaseApiResponse> getGreetType() throws Exception { + return limoService.getGreetType(); + } + + @GetMapping("/getFlightDetails") + public BaseApiResponse> getFlightDetails(GetLimoFlightDetailsRequest request) + throws Exception { + return limoService.getFlightDetails(request); + } + + @GetMapping("/getTotalAmount") + public BaseApiResponse> getTotalAmount(GetLimoTotalAmountRequest request) + throws Exception { + return limoService.getTotalAmount(request); + } + + @PostMapping(value = "/prepareBooking", produces = "application/json;charset=UTF-8", + consumes = MediaType.APPLICATION_JSON_VALUE) + public BaseApiResponse prepareBooking( + HttpServletRequest requestHeader, + @Valid @RequestBody PrepareLimoBookingRequest request) { + String token = requestHeader.getHeader("Authorization"); + String userId = JWT.decode(token).getClaim("login_id").asString(); + String groupName = JWT.decode(token).getClaim("group_name").asString(); + + boolean canCreateBooking = sysGroupPermissionService + .getRouterPermissionsByGroupName(groupName) + .stream() + .anyMatch(permission -> Strings.CS.equals(permission.getId(), "10001_08")); + if (!canCreateBooking) { + return BaseApiResponse.error("NO_PERMISSION", "Have not Permission"); + } + + BaseApiResponse playerProfileByPlayerIdAndUserId = playerService.findPlayerProfileByPlayerIdAndUserId( + String.valueOf(request.getPlayerId()), userId); + if (!playerProfileByPlayerIdAndUserId.isSuccess()) { + return BaseApiResponse.error("API_CALL_FAILED", "Call Api failed"); + } + + PlayerProfileEntry profile = playerProfileByPlayerIdAndUserId.getData(); + if (profile == null || !Integer.valueOf(1).equals(profile.getCodedFlag())) { + return BaseApiResponse.error("NO_PERMISSION", "Have not Permission"); + } + + return limoService.prepareBooking(request, userId); + } + + @RequestMapping(value = "/createBooking" , method = RequestMethod.POST, produces = "application/json;charset=UTF-8",consumes = MediaType.APPLICATION_JSON_VALUE) + public CreateLimoBookingResponse createBooking(HttpServletRequest requestHeader, @RequestBody CreateLimoBookingRequest request) throws Exception { + CreateLimoBookingResponse response = new CreateLimoBookingResponse(); + List userPermissions = new ArrayList(); + + String token = requestHeader.getHeader("Authorization"); + String groupName = JWT.decode(token).getClaim("group_name").asString(); + userPermissions = sysGroupPermissionService.getRouterPermissionsByGroupName(groupName); + boolean createBooking = false; + String playerId = String.valueOf(request.getPlayerId()); + String userId = JWT.decode(token).getClaim("login_id").asString(); + + BaseApiResponse userInfoByUserId = userService.findUserInfoByUserId(userId); + UserInfoApiRecord userInfo = userInfoByUserId.getData(); + + BaseApiResponse playerProfileByPlayerIdAndUserId = playerService.findPlayerProfileByPlayerIdAndUserId(playerId, userId); + if(playerProfileByPlayerIdAndUserId.isSuccess()) { + PlayerProfileEntry profile = playerProfileByPlayerIdAndUserId.getData(); + Integer code = profile.getCodedFlag(); + if(!userPermissions.isEmpty()) { + for(SysRouterPermission per:userPermissions) { + if(Strings.CS.equals(per.getId(), "10001_08")) createBooking = true; + } + } + if(code==1&&createBooking) { + response = limoService.createBooking(request,requestHeader,userInfo); + }else { + response.setSuccess(Boolean.FALSE); + response.setMessage("Have not Permission"); + response.setCode("NO_PERMISSION"); + } + }else{ + response.setSuccess(Boolean.FALSE); + response.setMessage("Call Api failed"); + response.setCode("API_CALL_FAILED"); + } + return response; + } + + @RequestMapping(value = "/updateBooking", method = RequestMethod.POST, produces = "application/json;charset=UTF-8",consumes = MediaType.APPLICATION_JSON_VALUE) + public UpdateLimoBookingResponse updateBooking(HttpServletRequest requestHeader, @RequestBody UpdateLimoBookingRequest request) throws Exception { + UpdateLimoBookingResponse response = new UpdateLimoBookingResponse(); + List userPermissions = new ArrayList(); + + String token = requestHeader.getHeader("Authorization"); +// String userId = JWT.decode(token).getClaim("login_id").asString(); + String groupName = JWT.decode(token).getClaim("group_name").asString(); + userPermissions = sysGroupPermissionService.getRouterPermissionsByGroupName(groupName); + boolean createBooking = false; + String playerId = String.valueOf(request.getPlayerId()); + String userId = JWT.decode(token).getClaim("login_id").asString(); + if(!StringUtils.isEmpty(userId)) { + userId = Strings.CS.replace(userId, "@mgm.mo", ""); + } + BaseApiResponse playerProfileByPlayerIdAndUserId = playerService.findPlayerProfileByPlayerIdAndUserId(playerId, userId); + if(playerProfileByPlayerIdAndUserId.isSuccess()) { + PlayerProfileEntry profile = playerProfileByPlayerIdAndUserId.getData(); + Integer code = profile.getCodedFlag(); + + if (!userPermissions.isEmpty()) { + for (SysRouterPermission per : userPermissions) { + if (Strings.CS.equals(per.getId(), "10001_08")) createBooking = true; + } + } + + if (code == 1 && createBooking) { + response = limoService.updateBooking(request, userId); + }else{ + response.setSuccess(Boolean.FALSE); + response.setMessage("Have not Permission"); + response.setCode("NO_PERMISSION"); + } + }else{ + response.setSuccess(Boolean.FALSE); + response.setMessage("Call Api failed"); + response.setCode("API_CALL_FAILED"); + } + return response; + } + + @RequestMapping( value = "/cancelBooking", method = RequestMethod.POST, produces = "application/json;charset=UTF-8",consumes = MediaType.APPLICATION_JSON_VALUE) + public CancelLimoBookingResponse cancelBooking(HttpServletRequest requestHeader, @RequestBody CancelLimoBookingRequest request) throws Exception { + + CancelLimoBookingResponse response = new CancelLimoBookingResponse(); + List userPermissions = new ArrayList<>(); + + String token = requestHeader.getHeader("Authorization"); + String userId = JWT.decode(token).getClaim("login_id").asString(); + String groupName = JWT.decode(token).getClaim("group_name").asString(); + userPermissions = sysGroupPermissionService.getRouterPermissionsByGroupName(groupName); + boolean createBooking = false; + + if(!StringUtils.isEmpty(userId)) { + userId = Strings.CS.replace(userId, "@mgm.mo", ""); + } + + if(!userPermissions.isEmpty()) { + for(SysRouterPermission per:userPermissions) { + if(Strings.CS.equals(per.getId(), "10001_08") ) createBooking = true; + } + } + + if (createBooking) { + response = limoService.cancelBooking(request,userId); + }else{ + response.setSuccess(Boolean.FALSE); + response.setMessage("Have not Permission"); + response.setCode("NO_PERMISSION"); + } + + return response; + } + + @GetMapping("/checkQualification") + public GetLimoBookingQualificationResponse getLimoBookingQualification( + GetLimoBookingQualificationRequest request) throws Exception { + return limoService.checkBookingQualification(request); + } + + @GetMapping("/getOverrider") + public GetOverriderInfoResponse getLimoOverriderInfo( + GetLimoBookingGetOverriderRequest request) throws Exception { + return limoService.getLimoOverriderData(request); + } + + @GetMapping("/getEmployeeInfo") + public GetLimoEmployeeInfoResponse getLimoEmployeeInfo( + GetLimoEmployeeInfoRequest request)throws Exception { + return limoService.getLimoEmployeeData(request); + } + + @GetMapping("/playerLimoBooker") + public BaseApiResponse> getLimoPlayerLimoBooker( + RequestPlayerEsbBookerRequest request)throws Exception { + return limoService.getPlayerEsbBooker(request); + } + + + @RequestMapping(value = "/get_limo_booking_by_id", method = RequestMethod.POST, produces = "application/json;charset=UTF-8",consumes = MediaType.APPLICATION_JSON_VALUE) + public BaseApiResponse getLimoBookingById(HttpServletRequest request, @RequestBody Map params) throws Exception { + BaseApiResponse response = new BaseApiResponse<>(); + String token = request.getHeader("Authorization"); + String userId = JWT.decode(token).getClaim("login_id").asString(); + boolean havePermission = sysGroupPermissionService.checkAppPermission(request,"10001_08"); + + Long id = Long.valueOf(params.get("id")); + + boolean viewPlayer = limoService.checkViewPlayer(id,null,userId); + if (havePermission && viewPlayer) { + response.setData(limoService.getBookingById(id)); + response.setSuccess(Boolean.TRUE); + }else{ + response.setSuccess(Boolean.FALSE); + response.setMessage("Have not permission"); + response.setCode("NO_PERMISSION"); + } + + return response; + } + + @RequestMapping(value = "/get_limo_booking_by_conf", method = RequestMethod.POST, produces = "application/json;charset=UTF-8",consumes = MediaType.APPLICATION_JSON_VALUE) + public BaseApiResponse getLimoBookingByConf(HttpServletRequest request, @RequestBody Map params) throws Exception { + BaseApiResponse response = new BaseApiResponse<>(); + boolean havePermission = sysGroupPermissionService.checkAppPermission(request,"10001_08"); + String token = request.getHeader("Authorization"); + String userId = JWT.decode(token).getClaim("login_id").asString(); + String confirmationNo = params.get("conf"); + LimoBookings bookingById = limoService.getBookingByConf(confirmationNo); + + boolean viewPlayer = limoService.checkViewPlayer(null,confirmationNo,userId); + + + if (havePermission && viewPlayer) { + response.setData(limoService.getBookingById(bookingById.getId())); + response.setSuccess(Boolean.TRUE); + }else{ + response.setSuccess(false); + response.setMessage("Have not permission"); + response.setCode("NO_PERMISSION"); + } + + return response; + } + +} diff --git a/src/main/java/com/mgm/mcrm/limo/dao/LimoBookingDraftRepository.java b/src/main/java/com/mgm/mcrm/limo/dao/LimoBookingDraftRepository.java new file mode 100644 index 0000000..640de76 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/limo/dao/LimoBookingDraftRepository.java @@ -0,0 +1,54 @@ +package com.mgm.mcrm.limo.dao; + +import com.mgm.mcrm.limo.models.LimoBookingDraft; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; +import org.springframework.transaction.annotation.Transactional; + +import java.time.LocalDateTime; +import java.util.Optional; +import java.util.UUID; + +@Repository +public interface LimoBookingDraftRepository extends JpaRepository { + + Optional findByDraftId(UUID draftId); + + @Modifying(clearAutomatically = true, flushAutomatically = true) + @Transactional(transactionManager = "transactionManager") + @Query(""" + update LimoBookingDraft d + set d.status = 'PROCESSING', d.updatedAt = :now, d.version = d.version + 1 + where d.draftId = :draftId + and d.userId = :userId + and d.playerId = :playerId + and d.status = 'PENDING' + and d.expiresAt > :now + """) + int claimPendingDraft( + @Param("draftId") UUID draftId, + @Param("userId") String userId, + @Param("playerId") Long playerId, + @Param("now") LocalDateTime now); + + @Modifying(clearAutomatically = true, flushAutomatically = true) + @Transactional(transactionManager = "transactionManager") + @Query(""" + update LimoBookingDraft d + set d.status = :status, + d.limoBookingId = :limoBookingId, + d.usedAt = :usedAt, + d.updatedAt = :now, + d.version = d.version + 1 + where d.draftId = :draftId and d.status = 'PROCESSING' + """) + int completeDraft( + @Param("draftId") UUID draftId, + @Param("status") String status, + @Param("limoBookingId") String limoBookingId, + @Param("usedAt") LocalDateTime usedAt, + @Param("now") LocalDateTime now); +} diff --git a/src/main/java/com/mgm/mcrm/limo/dao/LimoBookingsRepository.java b/src/main/java/com/mgm/mcrm/limo/dao/LimoBookingsRepository.java new file mode 100644 index 0000000..e4dd7b5 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/limo/dao/LimoBookingsRepository.java @@ -0,0 +1,32 @@ +package com.mgm.mcrm.limo.dao; + +import org.springframework.data.jpa.repository.JpaRepository; + +import com.mgm.mcrm.limo.models.LimoBookings; +import org.springframework.stereotype.Repository; + +import java.util.Date; +import java.util.List; + +@Repository +public interface LimoBookingsRepository extends JpaRepository { + + List findByPlayerIdAndBookingStatusNot(String playerId, String bookingStatus); + + List findByPlayerIdAndBookingStatusNotAndPickUpDatetimeGreaterThanEqual( + String playerId, String bookingStatus, Date minPickUpDatetime); + + List findByPlayerIdAndBookingStatusNotInAndPickUpDatetimeGreaterThanEqual( + String playerId, List bookingStatuses, Date minPickUpDatetime); + + LimoBookings findByConfirmationNo(String confirmationNo); + + /** PENDING 且创建时间早于 threshold(用于超时自动确认) */ + List findByBookingStatusAndCreatedAtBeforeAndCreatedAtIsNotNull(String bookingStatus, Date createdAtBefore); + + LimoBookings getById(Long id); + + List findByLimoBookingId(String limoBookingId); + + LimoBookings getByLimoBookingId(String limoBookingId); +} diff --git a/src/main/java/com/mgm/mcrm/limo/dtos/request/CancelLimoBookingRequest.java b/src/main/java/com/mgm/mcrm/limo/dtos/request/CancelLimoBookingRequest.java new file mode 100644 index 0000000..7c07cbc --- /dev/null +++ b/src/main/java/com/mgm/mcrm/limo/dtos/request/CancelLimoBookingRequest.java @@ -0,0 +1,11 @@ +package com.mgm.mcrm.limo.dtos.request; + +import lombok.Data; + +@Data +public class CancelLimoBookingRequest { + + private Long id; + + private String updatedBy; +} diff --git a/src/main/java/com/mgm/mcrm/limo/dtos/request/CreateLimoBookingRequest.java b/src/main/java/com/mgm/mcrm/limo/dtos/request/CreateLimoBookingRequest.java new file mode 100644 index 0000000..bb782ae --- /dev/null +++ b/src/main/java/com/mgm/mcrm/limo/dtos/request/CreateLimoBookingRequest.java @@ -0,0 +1,69 @@ +package com.mgm.mcrm.limo.dtos.request; + +import java.util.Date; + +import com.fasterxml.jackson.annotation.JsonAlias; +import com.fasterxml.jackson.annotation.JsonFormat; + +import lombok.Data; + +@Data +public class CreateLimoBookingRequest { + private String draftId; + + private Integer playerId; + private String player; + private String confirmationNo; + private String bookingType; + private String pickUpPoint; + private String pickUpPointId; + + @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss", timezone = "GMT+8") + private Date pickUpDatetime; + private String dropOffPoint; + private String dropOffPointId; + private String serviceType; + private String carType; + private Integer noOfPax; + private String greetType; + private String signage; + private String approver; + private String approverId; + private String paymentMethod; + private String tripContact; + private Integer isHourlyRate; + private String hourlyRate; + private String remarks; + private String flightDetail; + private String flightEta; + private String flightStatus; + private String createdBy; + private String overriderName; + private String overriderId; + private String bookerId; + private String otherPickUpPoint; + private String otherDropOffPoint; + private String hour; + + // --- 前端新增字段,从 Limo API 获取的真实 ID --- + private Long carTypeId; + private String greetTypeId; + private String guestType; + private String tripType; + private String pickupRegion; + private String dropoffRegion; + private String ranking; + private String salution; + private String lastName; + private String bookerContact; + private String employeeId; + private String extraOffPoint; + private String extraOffPointId; + private Integer isHighImportance; + private Integer isContactGuestDirectly; + private String guestContact; + private Integer isTenOut; + private String tenOutContact; + private String bookingContact; + private Integer tripPriceId; +} diff --git a/src/main/java/com/mgm/mcrm/limo/dtos/request/GetLimoAccessTokenRequest.java b/src/main/java/com/mgm/mcrm/limo/dtos/request/GetLimoAccessTokenRequest.java new file mode 100644 index 0000000..820bb05 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/limo/dtos/request/GetLimoAccessTokenRequest.java @@ -0,0 +1,12 @@ +package com.mgm.mcrm.limo.dtos.request; + +import lombok.Data; + +@Data +public class GetLimoAccessTokenRequest { + + private String LoginId; + + private String password; + +} \ No newline at end of file diff --git a/src/main/java/com/mgm/mcrm/limo/dtos/request/GetLimoBookingGetOverriderRequest.java b/src/main/java/com/mgm/mcrm/limo/dtos/request/GetLimoBookingGetOverriderRequest.java new file mode 100644 index 0000000..6ecd605 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/limo/dtos/request/GetLimoBookingGetOverriderRequest.java @@ -0,0 +1,8 @@ +package com.mgm.mcrm.limo.dtos.request; + +import lombok.Data; + +@Data +public class GetLimoBookingGetOverriderRequest { + private String OverriderInfo; +} diff --git a/src/main/java/com/mgm/mcrm/limo/dtos/request/GetLimoBookingQualificationRequest.java b/src/main/java/com/mgm/mcrm/limo/dtos/request/GetLimoBookingQualificationRequest.java new file mode 100644 index 0000000..2bcac7a --- /dev/null +++ b/src/main/java/com/mgm/mcrm/limo/dtos/request/GetLimoBookingQualificationRequest.java @@ -0,0 +1,10 @@ +package com.mgm.mcrm.limo.dtos.request; + +import lombok.Data; + +@Data +public class GetLimoBookingQualificationRequest { + private Integer PlayerId; + private String BookingType; + private String BookingDate; +} diff --git a/src/main/java/com/mgm/mcrm/limo/dtos/request/GetLimoEmployeeInfoRequest.java b/src/main/java/com/mgm/mcrm/limo/dtos/request/GetLimoEmployeeInfoRequest.java new file mode 100644 index 0000000..2a3d1ea --- /dev/null +++ b/src/main/java/com/mgm/mcrm/limo/dtos/request/GetLimoEmployeeInfoRequest.java @@ -0,0 +1,8 @@ +package com.mgm.mcrm.limo.dtos.request; + +import lombok.Data; + +@Data +public class GetLimoEmployeeInfoRequest { + private String EmployeeId; +} diff --git a/src/main/java/com/mgm/mcrm/limo/dtos/request/GetLimoFlightDetailsRequest.java b/src/main/java/com/mgm/mcrm/limo/dtos/request/GetLimoFlightDetailsRequest.java new file mode 100644 index 0000000..6f74269 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/limo/dtos/request/GetLimoFlightDetailsRequest.java @@ -0,0 +1,11 @@ +package com.mgm.mcrm.limo.dtos.request; + +import lombok.Data; + +@Data +public class GetLimoFlightDetailsRequest { + private String flightNo; + private String pickupDateTime; + private String pickupAirportCode; + private String dropOffAirportCode; +} diff --git a/src/main/java/com/mgm/mcrm/limo/dtos/request/GetLimoOverriderRequest.java b/src/main/java/com/mgm/mcrm/limo/dtos/request/GetLimoOverriderRequest.java new file mode 100644 index 0000000..8882747 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/limo/dtos/request/GetLimoOverriderRequest.java @@ -0,0 +1,10 @@ +package com.mgm.mcrm.limo.dtos.request; + +import lombok.Data; + +@Data +public class GetLimoOverriderRequest { + + private String OverriderIdOrName; + +} diff --git a/src/main/java/com/mgm/mcrm/limo/dtos/request/GetLimoTotalAmountRequest.java b/src/main/java/com/mgm/mcrm/limo/dtos/request/GetLimoTotalAmountRequest.java new file mode 100644 index 0000000..87166b8 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/limo/dtos/request/GetLimoTotalAmountRequest.java @@ -0,0 +1,10 @@ +package com.mgm.mcrm.limo.dtos.request; + +import lombok.Data; + +@Data +public class GetLimoTotalAmountRequest { + private String pickupPOIId; + private String dropoffPOIIds; + private String singleTripPrices; +} diff --git a/src/main/java/com/mgm/mcrm/limo/dtos/request/GetPlayerInfoRequest.java b/src/main/java/com/mgm/mcrm/limo/dtos/request/GetPlayerInfoRequest.java new file mode 100644 index 0000000..b42c044 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/limo/dtos/request/GetPlayerInfoRequest.java @@ -0,0 +1,10 @@ +package com.mgm.mcrm.limo.dtos.request; + +import lombok.Data; + +@Data +public class GetPlayerInfoRequest { + + private String playerId; + +} diff --git a/src/main/java/com/mgm/mcrm/limo/dtos/request/GetSimpleLimoBookingQualificationStatusRequest.java b/src/main/java/com/mgm/mcrm/limo/dtos/request/GetSimpleLimoBookingQualificationStatusRequest.java new file mode 100644 index 0000000..a6c6d49 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/limo/dtos/request/GetSimpleLimoBookingQualificationStatusRequest.java @@ -0,0 +1,15 @@ +package com.mgm.mcrm.limo.dtos.request; + +import lombok.Data; + +@Data +public class GetSimpleLimoBookingQualificationStatusRequest { + + private String playerId; + + private String bookingType; + + private String bookingDate; + + +} diff --git a/src/main/java/com/mgm/mcrm/limo/dtos/request/InternalCancelLimoBookingRequest.java b/src/main/java/com/mgm/mcrm/limo/dtos/request/InternalCancelLimoBookingRequest.java new file mode 100644 index 0000000..d0033aa --- /dev/null +++ b/src/main/java/com/mgm/mcrm/limo/dtos/request/InternalCancelLimoBookingRequest.java @@ -0,0 +1,9 @@ +package com.mgm.mcrm.limo.dtos.request; + +import lombok.Data; + +@Data +public class InternalCancelLimoBookingRequest { + private String bookingId; + private String editBy; +} diff --git a/src/main/java/com/mgm/mcrm/limo/dtos/request/InternalCreateLimoBookingRequest.java b/src/main/java/com/mgm/mcrm/limo/dtos/request/InternalCreateLimoBookingRequest.java new file mode 100644 index 0000000..7eed8c9 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/limo/dtos/request/InternalCreateLimoBookingRequest.java @@ -0,0 +1,158 @@ +package com.mgm.mcrm.limo.dtos.request; + +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +public class InternalCreateLimoBookingRequest { + + private int createNotConfirmBooking; + private String bookingType; + private String greetType; + private String otherGreetType; + private String guestType; + private String tripType; + + private String playerId; + private String ranking; + private String overrideBy; + private String complexOverrider; + + private String roomNo; + private String employeeId; + + private String lastName; + private String firstName; + private String salution; + private String chineseLastName; + private String chineseFirstName; + + private String bookerContact; + private String tripContact; + private String MaskedTier; + + private int adHoc; + + private LocalDateTime pickupDatetime; + + private Long carTypeId; + private Integer passengerNo; + + private Long pickupPOIID; + private String pickup; + private Long pickupTripPriceId; + private String pickupRegion; + + private Long dropoffPOIID; + private String dropoff; + private Long dropoffTripPriceId; + private String dropoffRegion; + + private Long extraDropoffPOIID1; + private String extraDropoff1; + private Long extraDropoffTripPriceID1; + private String extraDropoffRegion1; + + private Long extraDropoffPOIID2; + private String extraDropoff2; + private Long extraDropoffTripPriceID2; + private String extraDropoffRegion2; + + private Long extraDropoffPOIID3; + private String extraDropoff3; + private Long extraDropoffTripPriceID3; + private String extraDropoffRegion3; + + private Long extraDropoffPOIID4; + private String extraDropoff4; + private Long extraDropoffTripPriceID4; + private String extraDropoffRegion4; + + private Long extraDropoffPOIID5; + private String extraDropoff5; + private Long extraDropoffTripPriceID5; + private String extraDropoffRegion5; + + private Long extraDropoffPOIID6; + private String extraDropoff6; + private Long extraDropoffTripPriceID6; + private String extraDropoffRegion6; + + private Long extraDropoffPOIID7; + private String extraDropoff7; + private Long extraDropoffTripPriceID7; + private String extraDropoffRegion7; + + private Long extraDropoffPOIID8; + private String extraDropoff8; + private Long extraDropoffTripPriceID8; + private String extraDropoffRegion8; + + private Long extraDropoffPOIID9; + private String extraDropoff9; + private Long extraDropoffTripPriceID9; + private String extraDropoffRegion9; + + private Long extraDropoffPOIID10; + private String extraDropoff10; + private Long extraDropoffTripPriceID10; + private String extraDropoffRegion10; + + private BigDecimal singleTripPrice; + private BigDecimal defaultTripPrice; + private BigDecimal defaultPublishTripPrice; + + private BigDecimal hourlyRate; + private BigDecimal hourlyWaitingFee; + + private Integer hour; + private Integer hourlyWaiting; + + private BigDecimal extraDropoffPrice1; + private BigDecimal extraDropoffPrice2; + private BigDecimal extraDropoffPrice3; + private BigDecimal extraDropoffPrice4; + private BigDecimal extraDropoffPrice5; + private BigDecimal extraDropoffPrice6; + private BigDecimal extraDropoffPrice7; + private BigDecimal extraDropoffPrice8; + private BigDecimal extraDropoffPrice9; + private BigDecimal extraDropoffPrice10; + + private String otherPriceRemark; + private BigDecimal otherPrice; + + private String paymentMethod; + private BigDecimal totalAmount; + + private Boolean highImportance; + private Boolean tenOut; + private Boolean butlerGreet; + + private String bookedBy; + private String approvedBy; + + private String bookingRemark; + private String driverRemark; + private String limoInternalRemark; + private String systemRemark; + + private Boolean limoGreet; + private Boolean hostGreet; + private Boolean vipMeetNGreet; + + private String otherGreet; + private String flightDetails; + private String signage; + + private String guestContact; + private String tenOutContact; + private String bookingContact; + private String createBy; + + public int getCreateNotConfirmBooking() { + return createNotConfirmBooking; + } +} diff --git a/src/main/java/com/mgm/mcrm/limo/dtos/request/InternalUpdateLimoBookingRequest.java b/src/main/java/com/mgm/mcrm/limo/dtos/request/InternalUpdateLimoBookingRequest.java new file mode 100644 index 0000000..197440a --- /dev/null +++ b/src/main/java/com/mgm/mcrm/limo/dtos/request/InternalUpdateLimoBookingRequest.java @@ -0,0 +1,153 @@ +package com.mgm.mcrm.limo.dtos.request; + +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +public class InternalUpdateLimoBookingRequest { + + private String id; + + private Boolean createNotConfirmBooking; + private String bookingType; + private String greetType; + private String otherGreetType; + private String guestType; + private String tripType; + + private String playerId; + private String ranking; + private String MaskedTier; + private String overrideBy; + private String complexOverrider; + + private String roomNo; + private String employeeId; + + private String firstName; + private String lastName; + private String salution; + private String chineseLastName; + private String chineseFirstName; + + private String bookerContact; + private String tripContact; + + private String adHoc; + + private LocalDateTime pickupDatetime; + + private Long carTypeId; + private Integer passengerNo; + + private Long pickupPOIID; + private String pickup; + private Long pickupTripPriceID; + private String pickupRegion; + + private Long dropoffPOIID; + private String dropoff; + private Long dropoffTripPriceID; + private String dropoffRegion; + + private Long extraDropoffPOIID1; + private String extraDropoff1; + private Long extraDropoffTripPriceID1; + private String extraDropoffRegion1; + + private Long extraDropoffPOIID2; + private String extraDropoff2; + private Long extraDropoffTripPriceID2; + private String extraDropoffRegion2; + + private Long extraDropoffPOIID3; + private String extraDropoff3; + private Long extraDropoffTripPriceID3; + private String extraDropoffRegion3; + + private Long extraDropoffPOIID4; + private String extraDropoff4; + private Long extraDropoffTripPriceID4; + private String extraDropoffRegion4; + + private Long extraDropoffPOIID5; + private String extraDropoff5; + private Long extraDropoffTripPriceID5; + private String extraDropoffRegion5; + + private Long extraDropoffPOIID6; + private String extraDropoff6; + private Long extraDropoffTripPriceID6; + private String extraDropoffRegion6; + + private Long extraDropoffPOIID7; + private String extraDropoff7; + private Long extraDropoffTripPriceID7; + private String extraDropoffRegion7; + + private Long extraDropoffPOIID8; + private String extraDropoff8; + private Long extraDropoffTripPriceID8; + private String extraDropoffRegion8; + + private Long extraDropoffPOIID9; + private String extraDropoff9; + private Long extraDropoffTripPriceID9; + private String extraDropoffRegion9; + + private Long extraDropoffPOIID10; + private String extraDropoff10; + private Long extraDropoffTripPriceID10; + private String extraDropoffRegion10; + + private BigDecimal singleTripPrice; + private BigDecimal defaultTripPrice; + private BigDecimal defaultPublishTripPrice; + + private BigDecimal hourlyRate; + private BigDecimal hourlyWaitingFee; + + private Integer hour; + private Integer hourlyWaiting; + + private BigDecimal extraDropoffPrice1; + private BigDecimal extraDropoffPrice2; + private BigDecimal extraDropoffPrice3; + private BigDecimal extraDropoffPrice4; + private BigDecimal extraDropoffPrice5; + private BigDecimal extraDropoffPrice6; + private BigDecimal extraDropoffPrice7; + private BigDecimal extraDropoffPrice8; + private BigDecimal extraDropoffPrice9; + private BigDecimal extraDropoffPrice10; + + private String otherPriceRemark; + private BigDecimal otherPrice; + + private String paymentMethod; + private BigDecimal totalAmount; + + private Boolean highImportance; + private Boolean tenOut; + private Boolean butlerGreet; + + private String bookedBy; + private String approvedBy; + + private String bookingRemark; + private String driverRemark; + private String limoInternalRemark; + private String systemRemark; + + private Boolean limoGreet; + private Boolean hostGreet; + private Boolean vipMeetNGreet; + + private String otherGreet; + private String flightDetails; + private String signage; + + private String editBy; +} diff --git a/src/main/java/com/mgm/mcrm/limo/dtos/request/PrepareLimoBookingRequest.java b/src/main/java/com/mgm/mcrm/limo/dtos/request/PrepareLimoBookingRequest.java new file mode 100644 index 0000000..286da09 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/limo/dtos/request/PrepareLimoBookingRequest.java @@ -0,0 +1,15 @@ +package com.mgm.mcrm.limo.dtos.request; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +@Data +public class PrepareLimoBookingRequest { + + @NotNull(message = "playerId is required") + private Integer playerId; + + @NotBlank(message = "approverId is required") + private String approverId; +} diff --git a/src/main/java/com/mgm/mcrm/limo/dtos/request/RequestPlayerEsbBookerRequest.java b/src/main/java/com/mgm/mcrm/limo/dtos/request/RequestPlayerEsbBookerRequest.java new file mode 100644 index 0000000..3960c14 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/limo/dtos/request/RequestPlayerEsbBookerRequest.java @@ -0,0 +1,9 @@ +package com.mgm.mcrm.limo.dtos.request; + +import lombok.Data; + +@Data +public class RequestPlayerEsbBookerRequest { + private Integer playerId; + private String userId; +} diff --git a/src/main/java/com/mgm/mcrm/limo/dtos/request/UpdateLimoBookingRequest.java b/src/main/java/com/mgm/mcrm/limo/dtos/request/UpdateLimoBookingRequest.java new file mode 100644 index 0000000..c6a95c5 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/limo/dtos/request/UpdateLimoBookingRequest.java @@ -0,0 +1,92 @@ +package com.mgm.mcrm.limo.dtos.request; + +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonAlias; + +import lombok.Data; + +@Data +public class UpdateLimoBookingRequest { + + private Long id; + private String confirmationNo; + private String bookingStatus; + private String playerId; + private String player; + private String playerName; + private String tierName; + private String bookingType; + private String bookingTypeName; + private String serviceType; + private String serviceTypeName; + private String pickUpDate; + private String pickUpTime; + @JsonAlias({ "pickupDatetime" }) + private String pickUpDatetime; + private String carTypeCode; + private String carType; + private Long carTypeId; + private Integer noOfPax; + @JsonAlias({ "pickupPointCode" }) + private String pickUpPointCode; + private String pickUpPoint; + private String pickupPointId; + private String otherPickUpPoint; + @JsonAlias({ "dropoffPointCode" }) + private String dropOffPointCode; + private String dropOffPoint; + @JsonAlias({ "dropOffPointId" }) + private String dropOffPointIds; + private String otherDropOffPoint; + @JsonAlias({ "extraOffPoint" }) + private String extraDropOffPoint; + @JsonAlias({ "extraOffPointId" }) + private String extraDropOffPointId; + private List dropOffPoints; + private String flightDetail; + private String flightEta; + private String flightStatus; + private String greetType; + private String greetTypeId; + private String signage; + private String approverId; + private String approver; + private String paymentMethodCode; + private String paymentMethod; + private Integer isHourlyRate; + private String hourlyRate; + private String tripPrice; + private String totalAmount; + private String tripContact; + private String remarks; + private String createdAt; + private String createdBy; + private String bookerId; + private String tripType; + private String guestType; + private String pickupRegion; + private String dropoffRegion; + private String ranking; + private String salution; + private String lastName; + private String firstName; + private String chineseLastName; + private String chinestFirstName; + private String bookerContact; + private String employeeId; + private Integer hour; + private String overriderName; + private String overrideBy; + private String updatedBy; + private String updatedByName; + private Integer tripPriceId; + + @Data + public static class DropOffPoint { + + private Integer sequence; + private String pointCode; + private String pointName; + } +} diff --git a/src/main/java/com/mgm/mcrm/limo/dtos/response/CancelLimoBookingResponse.java b/src/main/java/com/mgm/mcrm/limo/dtos/response/CancelLimoBookingResponse.java new file mode 100644 index 0000000..523c392 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/limo/dtos/response/CancelLimoBookingResponse.java @@ -0,0 +1,29 @@ +package com.mgm.mcrm.limo.dtos.response; + +import com.mgm.mcrm.common.dtos.BaseApiResponse; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class CancelLimoBookingResponse extends BaseApiResponse { + + /** 新建记录在 limo_bookings 表中的主键 */ + private Long id; + + public static CancelLimoBookingResponse success(Long id) { + CancelLimoBookingResponse cancelLimoBookingResponse = new CancelLimoBookingResponse(); + cancelLimoBookingResponse.setSuccess(true); + cancelLimoBookingResponse.setCode("200"); + cancelLimoBookingResponse.setId(id); + return cancelLimoBookingResponse; + } + + public static CancelLimoBookingResponse failure(String code, String message) { + CancelLimoBookingResponse cancelLimoBookingResponse = new CancelLimoBookingResponse(); + cancelLimoBookingResponse.setSuccess(false); + cancelLimoBookingResponse.setCode(code); + cancelLimoBookingResponse.setMessage(message); + return cancelLimoBookingResponse; + } +} diff --git a/src/main/java/com/mgm/mcrm/limo/dtos/response/CreateLimoBookingResponse.java b/src/main/java/com/mgm/mcrm/limo/dtos/response/CreateLimoBookingResponse.java new file mode 100644 index 0000000..aca5215 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/limo/dtos/response/CreateLimoBookingResponse.java @@ -0,0 +1,32 @@ +package com.mgm.mcrm.limo.dtos.response; + +import com.mgm.mcrm.common.dtos.BaseApiResponse; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class CreateLimoBookingResponse extends BaseApiResponse { + + /** 新建记录在 limo_bookings 表中的主键 */ + private Long id; + private Integer autoConfirm; + + public static CreateLimoBookingResponse success(Long id, Integer autoConfirm) { + CreateLimoBookingResponse createLimoBookingResponse = new CreateLimoBookingResponse(); + createLimoBookingResponse.setSuccess(true); + createLimoBookingResponse.setCode("200"); + createLimoBookingResponse.setId(id); + createLimoBookingResponse.setAutoConfirm(autoConfirm); + return createLimoBookingResponse; + } + + public static CreateLimoBookingResponse failure(String code, String message) { + CreateLimoBookingResponse createLimoBookingResponse = new CreateLimoBookingResponse(); + createLimoBookingResponse.setSuccess(false); + createLimoBookingResponse.setCode(code); + createLimoBookingResponse.setMessage(message); + return createLimoBookingResponse; + } +} diff --git a/src/main/java/com/mgm/mcrm/limo/dtos/response/GetLimoBookingFromLegacyResult.java b/src/main/java/com/mgm/mcrm/limo/dtos/response/GetLimoBookingFromLegacyResult.java new file mode 100644 index 0000000..93cea0f --- /dev/null +++ b/src/main/java/com/mgm/mcrm/limo/dtos/response/GetLimoBookingFromLegacyResult.java @@ -0,0 +1,14 @@ +package com.mgm.mcrm.limo.dtos.response; + + +import lombok.Data; + +import java.util.ArrayList; +import java.util.List; + +@Data +public class GetLimoBookingFromLegacyResult { + private String StatusCode = null; + private String statusDescription=null; + private List Records = new ArrayList<>(); +} diff --git a/src/main/java/com/mgm/mcrm/limo/dtos/response/GetLimoBookingQualificationResponse.java b/src/main/java/com/mgm/mcrm/limo/dtos/response/GetLimoBookingQualificationResponse.java new file mode 100644 index 0000000..e003960 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/limo/dtos/response/GetLimoBookingQualificationResponse.java @@ -0,0 +1,38 @@ +package com.mgm.mcrm.limo.dtos.response; + +import com.alibaba.fastjson.annotation.JSONField; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * Limo 预约资格校验接口返回体(与 ESB 字段名一致,PascalCase)。 + */ +@Data +@Schema(description = "Limo booking qualification check result") +public class GetLimoBookingQualificationResponse { + + @JSONField(name = "StatusCode") + @Schema(description = "状态码,如 OK") + private String statusCode; + + @JSONField(name = "StatusDescription") + @Schema(description = "状态说明") + private String statusDescription; + + @JSONField(name = "PlayerId") + @Schema(description = "玩家编号") + private Long playerId; + + @JSONField(name = "BookingType") + @Schema(description = "预约类型") + private String bookingType; + + @JSONField(name = "BookingDate") + @Schema(description = "预约日期时间") + private String bookingDate; + + @JSONField(name = "QualificationFlag") + @Schema(description = "资格标记,数值含义以业务文档为准") + private Integer qualificationFlag; +} diff --git a/src/main/java/com/mgm/mcrm/limo/dtos/response/GetLimoEmployeeInfoResponse.java b/src/main/java/com/mgm/mcrm/limo/dtos/response/GetLimoEmployeeInfoResponse.java new file mode 100644 index 0000000..44d74be --- /dev/null +++ b/src/main/java/com/mgm/mcrm/limo/dtos/response/GetLimoEmployeeInfoResponse.java @@ -0,0 +1,46 @@ +package com.mgm.mcrm.limo.dtos.response; + +import com.alibaba.fastjson.annotation.JSONField; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * ESB 员工信息接口返回体(RequestEmployeeInfo)。 + */ +@Data +@Schema(description = "Limo employee info response from ESB") +public class GetLimoEmployeeInfoResponse { + + @JSONField(name = "StatusCode") + @Schema(description = "状态码,如 OK") + private String statusCode; + + @JSONField(name = "StatusDescription") + @Schema(description = "状态说明") + private String statusDescription; + + @JSONField(name = "EmployeeId") + @Schema(description = "员工编号") + private Integer employeeId; + + @JSONField(name = "LastName") + @Schema(description = "英文姓氏") + private String lastName; + + @JSONField(name = "ChineseLastName") + @Schema(description = "中文姓氏") + private String chineseLastName; + + @JSONField(name = "Salutation") + @Schema(description = "称谓") + private String salutation; + + @JSONField(name = "Phone") + @Schema(description = "电话") + private String phone; + + @JSONField(name = "PaymentMethod") + @Schema(description = "支付方式") + private String paymentMethod; +} diff --git a/src/main/java/com/mgm/mcrm/limo/dtos/response/GetOverriderInfoResponse.java b/src/main/java/com/mgm/mcrm/limo/dtos/response/GetOverriderInfoResponse.java new file mode 100644 index 0000000..ac04917 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/limo/dtos/response/GetOverriderInfoResponse.java @@ -0,0 +1,42 @@ +package com.mgm.mcrm.limo.dtos.response; + +import java.util.List; + +import com.alibaba.fastjson.annotation.JSONField; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * ESB RequestLimoOverrider(查询 overrider)返回体。 + */ +@Data +@Schema(description = "Limo overrider search response from ESB") +public class GetOverriderInfoResponse { + + @JSONField(name = "StatusCode") + @Schema(description = "状态码,如 OK") + private String statusCode; + + @JSONField(name = "StatusDescription") + @Schema(description = "状态说明") + private String statusDescription; + + @JSONField(name = "Records") + @Schema(description = "匹配的审批人列表") + private List records; + + @Data + @Schema(description = "Overrider 员工一条记录") + public static class OverriderEmployeeRecord { + + @JSONField(name = "EmployeeId") + private Integer employeeId; + + @JSONField(name = "EmployeeName") + private String employeeName; + + @JSONField(name = "EmployeeIdAndName") + private String employeeIdAndName; + } +} diff --git a/src/main/java/com/mgm/mcrm/limo/dtos/response/GetPlayerInfoResponse.java b/src/main/java/com/mgm/mcrm/limo/dtos/response/GetPlayerInfoResponse.java new file mode 100644 index 0000000..2f517d3 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/limo/dtos/response/GetPlayerInfoResponse.java @@ -0,0 +1,86 @@ +package com.mgm.mcrm.limo.dtos.response; + +import com.alibaba.fastjson.annotation.JSONField; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * ESB RequestLimoOverrider(查询 overrider)返回体。 + */ +@Data +@Schema(description = "Limo overrider search response from ESB") +public class GetPlayerInfoResponse { + + @JSONField(name = "StatusCode") + @Schema(description = "状态码,如 OK") + private String statusCode; + + @JSONField(name = "StatusDescription") + @Schema(description = "状态说明") + private String statusDescription; + + @JSONField(name = "PlayerId") + @Schema(description = "玩家 ID") + private Long playerId; + + @JSONField(name = "Tier") + @Schema(description = "真实玩家等级") + private String tier; + + @JSONField(name = "MaskedTier") + @Schema(description = "脱敏玩家等级") + private String maskedTier; + + @JSONField(name = "FirstName") + @Schema(description = "玩家名字") + private String firstName; + + @JSONField(name = "LastName") + @Schema(description = "玩家姓氏") + private String lastName; + + @JSONField(name = "ChineseFirstName") + @Schema(description = "玩家中文名字") + private String chineseFirstName; + + @JSONField(name = "ChineseLastName") + @Schema(description = "玩家中文姓氏") + private String chineseLastName; + + @JSONField(name = "Salutation") + @Schema(description = "玩家称谓") + private String salutation; + + @JSONField(name = "PrimaryMAID") + @Schema(description = "一级 MA ID") + private String primaryMAID; + + @JSONField(name = "PrimaryMAName") + @Schema(description = "一级 MA 名称") + private String primaryMAName; + + @JSONField(name = "PrimaryMAPhone") + @Schema(description = "一级 MA 电话") + private String primaryMAPhone; + + @JSONField(name = "PrimaryMAPaymentMethod") + @Schema(description = "一级 MA 支付方式") + private String primaryMAPaymentMethod; + + @JSONField(name = "SecondaryMAID") + @Schema(description = "二级 MA ID") + private String secondaryMAID; + + @JSONField(name = "SecondaryMAName") + @Schema(description = "二级 MA 名称") + private String secondaryMAName; + + @JSONField(name = "SecondaryMAPhone") + @Schema(description = "二级 MA 电话") + private String secondaryMAPhone; + + @JSONField(name = "SecondaryMAPaymentMethod") + @Schema(description = "二级 MA 支付方式") + private String secondaryMAPaymentMethod; + +} diff --git a/src/main/java/com/mgm/mcrm/limo/dtos/response/LimoBookingFromLegacyItem.java b/src/main/java/com/mgm/mcrm/limo/dtos/response/LimoBookingFromLegacyItem.java new file mode 100644 index 0000000..3de673c --- /dev/null +++ b/src/main/java/com/mgm/mcrm/limo/dtos/response/LimoBookingFromLegacyItem.java @@ -0,0 +1,137 @@ +package com.mgm.mcrm.limo.dtos.response; + +import com.alibaba.fastjson.annotation.JSONField; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Data +@Schema(description = "Limo booking row") +public class LimoBookingFromLegacyItem { + + @JSONField(name = "BookingId") + private String bookingId; + + @JSONField(name = "BookingNo") + private String bookingNo; + + @JSONField(name = "OverrideBy") + private String overrideBy; + + @JSONField(name = "PickupDatetime") + private String pickupDatetime; + + @JSONField(name = "PassengerNo") + private Integer passengerNo; + + @JSONField(name = "PickupPOIID") + private Long pickupPoiid; + + @JSONField(name = "Pickup") + private String pickup; + + @JSONField(name = "PickupRegion") + private String pickupRegion; + + @JSONField(name = "DropoffPOIID") + private Long dropoffPoiid; + + @JSONField(name = "Dropoff") + private String dropoff; + + @JSONField(name = "ExtraDropoffPOIID1") + private Long extraDropoffPoiid1; + + @JSONField(name = "ExtraDropoff1") + private String extraDropoff1; + + @JSONField(name = "ExtraDropoffPOIID2") + private Long extraDropoffPoiid2; + + @JSONField(name = "ExtraDropoff2") + private String extraDropoff2; + + @JSONField(name = "ExtraDropoffPOIID3") + private Long extraDropoffPoiid3; + + @JSONField(name = "ExtraDropoff3") + private String extraDropoff3; + + @JSONField(name = "ExtraDropoffPOIID4") + private Long extraDropoffPoiid4; + + @JSONField(name = "ExtraDropoff4") + private String extraDropoff4; + + @JSONField(name = "ExtraDropoffPOIID5") + private Long extraDropoffPoiid5; + + @JSONField(name = "ExtraDropoff5") + private String extraDropoff5; + + @JSONField(name = "ExtraDropoffPOIID6") + private Long extraDropoffPoiid6; + + @JSONField(name = "ExtraDropoff6") + private String extraDropoff6; + + @JSONField(name = "ExtraDropoffPOIID7") + private Long extraDropoffPoiid7; + + @JSONField(name = "ExtraDropoff7") + private String extraDropoff7; + + @JSONField(name = "ExtraDropoffPOIID8") + private Long extraDropoffPoiid8; + + @JSONField(name = "ExtraDropoff8") + private String extraDropoff8; + + @JSONField(name = "ExtraDropoffPOIID9") + private Long extraDropoffPoiid9; + + @JSONField(name = "ExtraDropoff9") + private String extraDropoff9; + + @JSONField(name = "ExtraDropoffPOIID10") + private Long extraDropoffPoiid10; + + @JSONField(name = "ExtraDropoff10") + private String extraDropoff10; + + @JSONField(name = "SingleTripPrice") + private String singleTripPrice; + + @JSONField(name = "BookedBy") + private String bookedBy; + + @JSONField(name = "ApprovedBy") + private String approvedBy; + + @JSONField(name = "BookingRemark") + private String bookingRemark; + + @JSONField(name = "BookingStatus") + private String bookingStatus; + + @JSONField(name = "DriverEmployeeID") + private String driverEmployeeId; + + @JSONField(name = "Driver") + private String driver; + + @JSONField(name = "CarPlate") + private String carPlate; + + @JSONField(name = "CarType") + private String carType; + + @JSONField(name = "DriverContact") + private String driverContact; + + @JSONField(name = "TotalAmount") + private String totalAmount; + + @JSONField(name = "DriverSource") + private String driverSource; + +} \ No newline at end of file diff --git a/src/main/java/com/mgm/mcrm/limo/dtos/response/LimoBookingItem.java b/src/main/java/com/mgm/mcrm/limo/dtos/response/LimoBookingItem.java new file mode 100644 index 0000000..4463a9a --- /dev/null +++ b/src/main/java/com/mgm/mcrm/limo/dtos/response/LimoBookingItem.java @@ -0,0 +1,261 @@ +package com.mgm.mcrm.limo.dtos.response; + +import com.alibaba.fastjson.annotation.JSONField; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * Limo GetBooking 返回的 itemObject 数组元素。 + */ +@Data +@Schema(description = "Limo booking row") +public class LimoBookingItem { + + @JSONField(name = "ID") + private Long id; + @JSONField(name = "BookingNo") + private String bookingNo; + @JSONField(name = "SubBookingID") + private Long subBookingId; + @JSONField(name = "SubBookingNo") + private String subBookingNo; + @JSONField(name = "BookingType") + private String bookingType; + @JSONField(name = "GreetType") + private String greetType; + @JSONField(name = "OtherGreetType") + private String otherGreetType; + @JSONField(name = "GuestType") + private String guestType; + @JSONField(name = "TripType") + private String tripType; + @JSONField(name = "PlayerID") + private String playerId; + @JSONField(name = "Ranking") + private String ranking; + @JSONField(name = "OverrideBy") + private String overrideBy; + @JSONField(name = "ComplexOverrider") + private String complexOverrider; + @JSONField(name = "RoomNo") + private String roomNo; + @JSONField(name = "EmployeeID") + private String employeeId; + @JSONField(name = "LastName") + private String lastName; + @JSONField(name = "Salution") + private String salution; + @JSONField(name = "ChineseLastName") + private String chineseLastName; + @JSONField(name = "BookerContact") + private String bookerContact; + @JSONField(name = "TripContact") + private String tripContact; + @JSONField(name = "AdHoc") + private String adHoc; + @JSONField(name = "PickupDatetime") + private String pickupDatetime; + @JSONField(name = "CarTypeID") + private Integer carTypeId; + @JSONField(name = "PassengerNo") + private Integer passengerNo; + @JSONField(name = "PickupPOIID") + private Long pickupPoiid; + @JSONField(name = "Pickup") + private String pickup; + @JSONField(name = "PickupTripPriceID") + private Long pickupTripPriceId; + @JSONField(name = "PickupRegion") + private String pickupRegion; + @JSONField(name = "DropoffPOIID") + private Long dropoffPoiid; + @JSONField(name = "Dropoff") + private String dropoff; + @JSONField(name = "DropoffTripPriceID") + private Long dropoffTripPriceId; + @JSONField(name = "DropoffRegion") + private String dropoffRegion; + + @JSONField(name = "ExtraDropoffPOIID1") + private Long extraDropoffPoiid1; + @JSONField(name = "ExtraDropoff1") + private String extraDropoff1; + @JSONField(name = "ExtraDropoffTripPriceID1") + private Long extraDropoffTripPriceId1; + @JSONField(name = "ExtraDropoffRegion1") + private String extraDropoffRegion1; + @JSONField(name = "ExtraDropoffPOIID2") + private Long extraDropoffPoiid2; + @JSONField(name = "ExtraDropoff2") + private String extraDropoff2; + @JSONField(name = "ExtraDropoffTripPriceID2") + private Long extraDropoffTripPriceId2; + @JSONField(name = "ExtraDropoffRegion2") + private String extraDropoffRegion2; + @JSONField(name = "ExtraDropoffPOIID3") + private Long extraDropoffPoiid3; + @JSONField(name = "ExtraDropoff3") + private String extraDropoff3; + @JSONField(name = "ExtraDropoffTripPriceID3") + private Long extraDropoffTripPriceId3; + @JSONField(name = "ExtraDropoffRegion3") + private String extraDropoffRegion3; + @JSONField(name = "ExtraDropoffPOIID4") + private Long extraDropoffPoiid4; + @JSONField(name = "ExtraDropoff4") + private String extraDropoff4; + @JSONField(name = "ExtraDropoffTripPriceID4") + private Long extraDropoffTripPriceId4; + @JSONField(name = "ExtraDropoffRegion4") + private String extraDropoffRegion4; + @JSONField(name = "ExtraDropoffPOIID5") + private Long extraDropoffPoiid5; + @JSONField(name = "ExtraDropoff5") + private String extraDropoff5; + @JSONField(name = "ExtraDropoffTripPriceID5") + private Long extraDropoffTripPriceId5; + @JSONField(name = "ExtraDropoffRegion5") + private String extraDropoffRegion5; + @JSONField(name = "ExtraDropoffPOIID6") + private Long extraDropoffPoiid6; + @JSONField(name = "ExtraDropoff6") + private String extraDropoff6; + @JSONField(name = "ExtraDropoffTripPriceID6") + private Long extraDropoffTripPriceId6; + @JSONField(name = "ExtraDropoffRegion6") + private String extraDropoffRegion6; + @JSONField(name = "ExtraDropoffPOIID7") + private Long extraDropoffPoiid7; + @JSONField(name = "ExtraDropoff7") + private String extraDropoff7; + @JSONField(name = "ExtraDropoffTripPriceID7") + private Long extraDropoffTripPriceId7; + @JSONField(name = "ExtraDropoffRegion7") + private String extraDropoffRegion7; + @JSONField(name = "ExtraDropoffPOIID8") + private Long extraDropoffPoiid8; + @JSONField(name = "ExtraDropoff8") + private String extraDropoff8; + @JSONField(name = "ExtraDropoffTripPriceID8") + private Long extraDropoffTripPriceId8; + @JSONField(name = "ExtraDropoffRegion8") + private String extraDropoffRegion8; + @JSONField(name = "ExtraDropoffPOIID9") + private Long extraDropoffPoiid9; + @JSONField(name = "ExtraDropoff9") + private String extraDropoff9; + @JSONField(name = "ExtraDropoffTripPriceID9") + private Long extraDropoffTripPriceId9; + @JSONField(name = "ExtraDropoffRegion9") + private String extraDropoffRegion9; + @JSONField(name = "ExtraDropoffPOIID10") + private Long extraDropoffPoiid10; + @JSONField(name = "ExtraDropoff10") + private String extraDropoff10; + @JSONField(name = "ExtraDropoffTripPriceID10") + private Long extraDropoffTripPriceId10; + @JSONField(name = "ExtraDropoffRegion10") + private String extraDropoffRegion10; + + @JSONField(name = "SingleTripPrice") + private String singleTripPrice; + @JSONField(name = "DefaultTripPrice") + private String defaultTripPrice; + @JSONField(name = "DefaultPublishTripPrice") + private String defaultPublishTripPrice; + @JSONField(name = "HourlyRate") + private String hourlyRate; + @JSONField(name = "HourlyWaitingFee") + private String hourlyWaitingFee; + @JSONField(name = "Hour") + private Integer hour; + @JSONField(name = "HourlyWaiting") + private Integer hourlyWaiting; + @JSONField(name = "ExtraDropoffPrice1") + private String extraDropoffPrice1; + @JSONField(name = "ExtraDropoffPrice2") + private String extraDropoffPrice2; + @JSONField(name = "ExtraDropoffPrice3") + private String extraDropoffPrice3; + @JSONField(name = "ExtraDropoffPrice4") + private String extraDropoffPrice4; + @JSONField(name = "ExtraDropoffPrice5") + private String extraDropoffPrice5; + @JSONField(name = "ExtraDropoffPrice6") + private String extraDropoffPrice6; + @JSONField(name = "ExtraDropoffPrice7") + private String extraDropoffPrice7; + @JSONField(name = "ExtraDropoffPrice8") + private String extraDropoffPrice8; + @JSONField(name = "ExtraDropoffPrice9") + private String extraDropoffPrice9; + @JSONField(name = "ExtraDropoffPrice10") + private String extraDropoffPrice10; + @JSONField(name = "OtherPriceRemark") + private String otherPriceRemark; + @JSONField(name = "OtherPrice") + private String otherPrice; + @JSONField(name = "PaymentMethod") + private String paymentMethod; + @JSONField(name = "TotalAmount") + private String totalAmount; + @JSONField(name = "BookingContact") + private String bookingContact; + @JSONField(name = "HighImportance") + private Integer highImportance; + @JSONField(name = "TenOut") + private Integer tenOut; + @JSONField(name = "TenOutContact") + private String tenOutContact; + @JSONField(name = "GuestContact") + private String guestContact; + @JSONField(name = "ButlerGreet") + private Integer butlerGreet; + @JSONField(name = "BookedBy") + private String bookedBy; + @JSONField(name = "ApprovedBy") + private String approvedBy; + @JSONField(name = "BookingRemark") + private String bookingRemark; + @JSONField(name = "DriverRemark") + private String driverRemark; + @JSONField(name = "LimoInternalRemark") + private String limoInternalRemark; + @JSONField(name = "SystemRemark") + private String systemRemark; + @JSONField(name = "LimoGreet") + private Integer limoGreet; + @JSONField(name = "HostGreet") + private Integer hostGreet; + @JSONField(name = "VIPMeetNGreet") + private Integer vipMeetNGreet; + @JSONField(name = "FlightDetails") + private String flightDetails; + @JSONField(name = "ETA") + private String eta; + @JSONField(name = "Signage") + private String signage; + @JSONField(name = "FlightStatus") + private String flightStatus; + @JSONField(name = "BookingStatus") + private String bookingStatus; + @JSONField(name = "ConfirmStatus") + private String confirmStatus; + @JSONField(name = "CrossBorderEditAlert") + private Integer crossBorderEditAlert; + @JSONField(name = "FlightEditAlert") + private Integer flightEditAlert; + @JSONField(name = "DriverEmployeeID") + private String driverEmployeeId; + @JSONField(name = "Driver") + private String driver; + @JSONField(name = "DriverContact") + private String driverContact; + @JSONField(name = "CarPlate") + private String carPlate; + @JSONField(name = "CarType") + private String carType; + @JSONField(name = "DriverSource") + private String driverSource; + +} diff --git a/src/main/java/com/mgm/mcrm/limo/dtos/response/LimoCarTypeItem.java b/src/main/java/com/mgm/mcrm/limo/dtos/response/LimoCarTypeItem.java new file mode 100644 index 0000000..71a12a1 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/limo/dtos/response/LimoCarTypeItem.java @@ -0,0 +1,32 @@ +package com.mgm.mcrm.limo.dtos.response; + +import com.alibaba.fastjson.annotation.JSONField; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * Limo GetCarType 返回的 itemObject 数组元素(字段名按 ESB 约定,若对接实网有出入可再对齐)。 + */ +@Data +@Schema(description = "Limo car type option") +public class LimoCarTypeItem { + + @JSONField(name = "ID") + @Schema(description = "Car type id") + private Long id; + + @JSONField(name = "CarType") + private String carType; + + @JSONField(name = "EnglishName") + private String englishName; + + @JSONField(name = "ChineseTradName") + private String chineseTradName; + + @JSONField(name = "ChineseSimpName") + private String chineseSimpName; + + @JSONField(name = "BookingType") + private String bookingType; +} diff --git a/src/main/java/com/mgm/mcrm/limo/dtos/response/LimoFlightDetailsItem.java b/src/main/java/com/mgm/mcrm/limo/dtos/response/LimoFlightDetailsItem.java new file mode 100644 index 0000000..48b20c4 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/limo/dtos/response/LimoFlightDetailsItem.java @@ -0,0 +1,37 @@ +package com.mgm.mcrm.limo.dtos.response; + +import com.alibaba.fastjson.annotation.JSONField; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * Limo GetFlightDetails 返回的 itemObject 数组元素。 + */ +@Data +@Schema(description = "Limo flight details") +public class LimoFlightDetailsItem { + + @JSONField(name = "FlightNo") + @Schema(description = "Flight number") + private String flightNo; + + @JSONField(name = "PickUpAirportCode") + @Schema(description = "Pickup airport code") + private String pickUpAirportCode; + + @JSONField(name = "DropOffAirportCode") + @Schema(description = "Drop-off airport code") + private String dropOffAirportCode; + + @JSONField(name = "PickupDatetime") + @Schema(description = "Pickup datetime, e.g. 2026-04-23 16:00:00") + private String pickupDatetime; + + @JSONField(name = "ETA") + @Schema(description = "Estimated time of arrival") + private String eta; + + @JSONField(name = "FlightStatus") + @Schema(description = "Flight status, e.g. departure") + private String flightStatus; +} diff --git a/src/main/java/com/mgm/mcrm/limo/dtos/response/LimoGreetTypeItem.java b/src/main/java/com/mgm/mcrm/limo/dtos/response/LimoGreetTypeItem.java new file mode 100644 index 0000000..89455e1 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/limo/dtos/response/LimoGreetTypeItem.java @@ -0,0 +1,32 @@ +package com.mgm.mcrm.limo.dtos.response; + +import com.alibaba.fastjson.annotation.JSONField; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * Limo GetGreetType 返回的 itemObject 数组元素。 + */ +@Data +@Schema(description = "Limo greet type option") +public class LimoGreetTypeItem { + + @JSONField(name = "ID") + @Schema(description = "Greet type id") + private Long id; + + @JSONField(name = "BookingType") + private String bookingType; + + @JSONField(name = "GreetType") + private String greetType; + + @JSONField(name = "LimoGreet") + private Integer limoGreet; + + @JSONField(name = "HostGreet") + private Integer hostGreet; + + @JSONField(name = "VIPMeetNGreet") + private Integer vipMeetNGreet; +} diff --git a/src/main/java/com/mgm/mcrm/limo/dtos/response/LimoPointOfInterestItem.java b/src/main/java/com/mgm/mcrm/limo/dtos/response/LimoPointOfInterestItem.java new file mode 100644 index 0000000..c528230 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/limo/dtos/response/LimoPointOfInterestItem.java @@ -0,0 +1,44 @@ +package com.mgm.mcrm.limo.dtos.response; + +import com.alibaba.fastjson.annotation.JSONField; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * Limo GetPointOfInterest 返回的 itemObject 数组元素。 + */ +@Data +@Schema(description = "Limo point of interest / location") +public class LimoPointOfInterestItem { + + @JSONField(name = "ID") + @Schema(description = "POI id") + private Long id; + + @JSONField(name = "EnglishName") + private String englishName; + + @JSONField(name = "ChineseTradName") + private String chineseTradName; + + @JSONField(name = "ChineseSimpName") + private String chineseSimpName; + + @JSONField(name = "AirportCode") + private String airportCode; + + @JSONField(name = "Region") + private String region; + + @JSONField(name = "Area") + private String area; + + @JSONField(name = "TripPriceID") + private Long tripPriceId; + + @JSONField(name = "FreeOfCharge") + private Integer freeOfCharge; + + @JSONField(name = "GreetLocation") + private String greetLocation; +} diff --git a/src/main/java/com/mgm/mcrm/limo/dtos/response/LimoTotalAmountItem.java b/src/main/java/com/mgm/mcrm/limo/dtos/response/LimoTotalAmountItem.java new file mode 100644 index 0000000..fa63486 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/limo/dtos/response/LimoTotalAmountItem.java @@ -0,0 +1,51 @@ +package com.mgm.mcrm.limo.dtos.response; + +import com.alibaba.fastjson.annotation.JSONField; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * Limo GetTotalAmount 返回的 itemObject 数组元素。 + */ +@Data +@Schema(description = "Limo trip total amount breakdown") +public class LimoTotalAmountItem { + + @JSONField(name = "SingleTripPrice") + @Schema(description = "Single trip price") + private String singleTripPrice; + + @JSONField(name = "ExtraDropoffPrice1") + private String extraDropoffPrice1; + + @JSONField(name = "ExtraDropoffPrice2") + private String extraDropoffPrice2; + + @JSONField(name = "ExtraDropoffPrice3") + private String extraDropoffPrice3; + + @JSONField(name = "ExtraDropoffPrice4") + private String extraDropoffPrice4; + + @JSONField(name = "ExtraDropoffPrice5") + private String extraDropoffPrice5; + + @JSONField(name = "ExtraDropoffPrice6") + private String extraDropoffPrice6; + + @JSONField(name = "ExtraDropoffPrice7") + private String extraDropoffPrice7; + + @JSONField(name = "ExtraDropoffPrice8") + private String extraDropoffPrice8; + + @JSONField(name = "ExtraDropoffPrice9") + private String extraDropoffPrice9; + + @JSONField(name = "ExtraDropoffPrice10") + private String extraDropoffPrice10; + + @JSONField(name = "TotalAmount") + @Schema(description = "Total amount") + private String totalAmount; +} diff --git a/src/main/java/com/mgm/mcrm/limo/dtos/response/LimoTripPriceItem.java b/src/main/java/com/mgm/mcrm/limo/dtos/response/LimoTripPriceItem.java new file mode 100644 index 0000000..f1c0264 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/limo/dtos/response/LimoTripPriceItem.java @@ -0,0 +1,49 @@ +package com.mgm.mcrm.limo.dtos.response; + +import com.alibaba.fastjson.annotation.JSONField; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.math.BigDecimal; + +/** + * Limo GetTripPrice 返回的 itemObject 数组元素。 + */ +@Data +@Schema(description = "Limo trip price category") +public class LimoTripPriceItem { + + @JSONField(name = "ID") + @Schema(description = "Trip price row id") + private Long id; + + @JSONField(name = "TripPrice") + private String tripPrice; + + @JSONField(name = "Region") + private String region; + + @JSONField(name = "DefaultTripPrice") + private BigDecimal defaultTripPrice; + + @JSONField(name = "DefaultPHTripPrice") + private BigDecimal defaultPHTripPrice; + + @JSONField(name = "HourlyRate") + private BigDecimal hourlyRate; + + @JSONField(name = "HourlyWaitingFee") + private BigDecimal hourlyWaitingFee; + + @JSONField(name = "ExtraDropoff") + private BigDecimal extraDropoff; + + @JSONField(name = "HourlyPHRate") + private BigDecimal hourlyPHRate; + + @JSONField(name = "HourlyPHWaitingFee") + private BigDecimal hourlyPHWaitingFee; + + @JSONField(name = "ExtraPHDropoff") + private BigDecimal extraPHDropoff; +} diff --git a/src/main/java/com/mgm/mcrm/limo/dtos/response/PlayerEsbBookerItem.java b/src/main/java/com/mgm/mcrm/limo/dtos/response/PlayerEsbBookerItem.java new file mode 100644 index 0000000..3c434e6 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/limo/dtos/response/PlayerEsbBookerItem.java @@ -0,0 +1,29 @@ +package com.mgm.mcrm.limo.dtos.response; + +import com.alibaba.fastjson.annotation.JSONField; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * RequestPlayerEsbBooker 返回的 Records 数组元素。 + */ +@Data +@Schema(description = "Player limo booker employee record") +public class PlayerEsbBookerItem { + + @JSONField(name = "EmployeeId") + @Schema(description = "Employee id") + private Long employeeId; + + @JSONField(name = "EmployeeName") + @Schema(description = "Employee display name") + private String employeeName; + + @JSONField(name = "Phone") + @Schema(description = "Contact phone; may be null") + private String phone; + + @JSONField(name = "EmployeeIdAndName") + @Schema(description = "Combined id and name for display, e.g. Leng Chan(132727)") + private String employeeIdAndName; +} diff --git a/src/main/java/com/mgm/mcrm/limo/dtos/response/PlayerEsbBookerResponse.java b/src/main/java/com/mgm/mcrm/limo/dtos/response/PlayerEsbBookerResponse.java new file mode 100644 index 0000000..eb26d1c --- /dev/null +++ b/src/main/java/com/mgm/mcrm/limo/dtos/response/PlayerEsbBookerResponse.java @@ -0,0 +1,27 @@ +package com.mgm.mcrm.limo.dtos.response; + +import com.alibaba.fastjson.annotation.JSONField; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + +/** + * ESB RequestPlayerLimoBooker 接口原始返回体。 + */ +@Data +@Schema(description = "Player limo booker ESB response") +public class PlayerEsbBookerResponse { + + @JSONField(name = "StatusCode") + @Schema(description = "Status code, e.g. OK") + private String statusCode; + + @JSONField(name = "StatusDescription") + @Schema(description = "Status description, e.g. Success") + private String statusDescription; + + @JSONField(name = "Records") + @Schema(description = "Booker employee list") + private List records; +} diff --git a/src/main/java/com/mgm/mcrm/limo/dtos/response/PrepareLimoBookingData.java b/src/main/java/com/mgm/mcrm/limo/dtos/response/PrepareLimoBookingData.java new file mode 100644 index 0000000..f44f9ba --- /dev/null +++ b/src/main/java/com/mgm/mcrm/limo/dtos/response/PrepareLimoBookingData.java @@ -0,0 +1,14 @@ +package com.mgm.mcrm.limo.dtos.response; + +import lombok.AllArgsConstructor; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.UUID; + +@Data +@AllArgsConstructor +public class PrepareLimoBookingData { + private UUID draftId; + private LocalDateTime expiresAt; +} diff --git a/src/main/java/com/mgm/mcrm/limo/dtos/response/UpdateLimoBookingResponse.java b/src/main/java/com/mgm/mcrm/limo/dtos/response/UpdateLimoBookingResponse.java new file mode 100644 index 0000000..2198c15 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/limo/dtos/response/UpdateLimoBookingResponse.java @@ -0,0 +1,25 @@ +package com.mgm.mcrm.limo.dtos.response; + +import com.mgm.mcrm.common.dtos.BaseApiResponse; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class UpdateLimoBookingResponse extends BaseApiResponse { + + public static UpdateLimoBookingResponse success() { + UpdateLimoBookingResponse response = new UpdateLimoBookingResponse(); + response.setSuccess(true); + response.setCode("200"); + return response; + } + + public static UpdateLimoBookingResponse failure(String code, String message) { + UpdateLimoBookingResponse response = new UpdateLimoBookingResponse(); + response.setSuccess(false); + response.setCode(code); + response.setMessage(message); + return response; + } +} diff --git a/src/main/java/com/mgm/mcrm/limo/models/LimoBookingDraft.java b/src/main/java/com/mgm/mcrm/limo/models/LimoBookingDraft.java new file mode 100644 index 0000000..aae14eb --- /dev/null +++ b/src/main/java/com/mgm/mcrm/limo/models/LimoBookingDraft.java @@ -0,0 +1,61 @@ +package com.mgm.mcrm.limo.models; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import jakarta.persistence.Version; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.UUID; + +@Data +@Entity +@Table(name = "limo_booking_draft") +public class LimoBookingDraft { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private Long id; + + @Column(name = "draft_id", nullable = false, unique = true) + private UUID draftId; + + @Column(name = "user_id", length = 64, nullable = false) + private String userId; + + @Column(name = "player_id", nullable = false) + private Long playerId; + + @Column(name = "approver_id", length = 64, nullable = false) + private String approverId; + + @Column(name = "approver_name", length = 255, nullable = false) + private String approverName; + + @Column(name = "status", length = 20, nullable = false) + private String status; + + @Column(name = "expires_at", nullable = false) + private LocalDateTime expiresAt; + + @Column(name = "used_at") + private LocalDateTime usedAt; + + @Column(name = "created_at", nullable = false) + private LocalDateTime createdAt; + + @Column(name = "updated_at") + private LocalDateTime updatedAt; + + @Column(name = "limo_booking_id", length = 128) + private String limoBookingId; + + @Version + @Column(name = "version", nullable = false) + private Long version = 0L; +} diff --git a/src/main/java/com/mgm/mcrm/limo/models/LimoBookings.java b/src/main/java/com/mgm/mcrm/limo/models/LimoBookings.java new file mode 100644 index 0000000..ed20a3c --- /dev/null +++ b/src/main/java/com/mgm/mcrm/limo/models/LimoBookings.java @@ -0,0 +1,149 @@ +package com.mgm.mcrm.limo.models; + +import java.util.Date; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import jakarta.persistence.Version; +import lombok.Data; + +@Data +@Entity +@Table(name = "limo_bookings") +public class LimoBookings { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private Long id; + @Column(name = "player_id", length = 128, nullable = false) + private String playerId; + @Column(name = "player", length = 512) + private String player; + @Column(name = "confirmation_no", length = 256) + private String confirmationNo; + @Column(name = "booking_type", length = 255) + private String bookingType; + @Column(name = "trip_type", length = 32) + private String tripType; + @Column(name = "pick_up_point", length = 255, nullable = false) + private String pickUpPoint; + @Column(name = "pick_up_point_id", length = 32) + private String pickUpPointId; + @Column(name = "pick_up_datetime", nullable = false) + private Date pickUpDatetime; + @Column(name = "drop_off_point", length = 255, nullable = false) + private String dropOffPoint; + @Column(name = "drop_off_point_ids", length = 255) + private String dropOffPointIds; + @Column(name = "booking_status", length = 255, nullable = false) + private String bookingStatus; + @Column(name = "service_type", length = 255) + private String serviceType; + @Column(name = "car_type", length = 255) + private String carType; + @Column(name = "car_type_id") + private Long carTypeId; + @Column(name = "no_of_pax") + private Integer noOfPax; + @Column(name = "greet_type", length = 255) + private String greetType; + @Column(name = "greet_type_id", length = 64) + private String greetTypeId; + @Column(name = "signage", length = 255) + private String signage; + @Column(name = "approver", length = 255) + private String approver; + @Column(name = "approver_id", length = 255) + private String approverId; + @Column(name = "payment_method", length = 255) + private String paymentMethod; + @Column(name = "trip_price", length = 255) + private String tripPrice; + @Column(name = "total_amount", length = 255) + private String totalAmount; + @Column(name = "trip_contact", length = 255) + private String tripContact; + @Column(name = "is_hourly_rate") + private Integer isHourlyRate; + @Column(name = "hourly_rate", length = 255) + private String hourlyRate; + @Column(name = "remarks", columnDefinition = "NVARCHAR(MAX)") + private String remarks; + @Column(name = "flight_detail", length = 255) + private String flightDetail; + @Column(name = "flight_eta", length = 255) + private String flightEta; + @Column(name = "flight_status", length = 255) + private String flightStatus; + @Version + @Column(name = "version", nullable = false) + private Long version = 0L; + + @Column(name = "created_at") + private Date createdAt; + + @Column(name = "created_by") + private String createdBy; + + @Column(name = "updated_at") + private Date updatedAt; + + @Column(name = "updated_by") + private String updatedBy; + + @Column(name = "override_by") + private String overrideBy; + + @Column(name = "booker_id") + private String bookerId; + + @Column(name = "limo_booking_id") + private String limoBookingId; + + @Column(name = "other_pick_up_point") + private String otherPickUpPoint; + + @Column(name = "other_drop_off_point") + private String otherDropOffPoint; + + @Column(name = "car_no") + private String carNo; + + @Column(name = "extra_drop_off_id") + private String extraDropOffId; + + @Column(name = "extra_drop_off_point") + private String extraDropOffPoint; + + @Column(name = "driver_contact") + private String driverContact; + + @Column(name = "booking_contact") + private String bookingContact; + + @Column(name = "is_high_importance", nullable = false) + private Integer isHighImportance = 0; + + @Column(name = "is_ten_out", nullable = false) + private Integer isTenOut = 0; + + @Column(name = "ten_out_contact") + private String tenOutContact; + + @Column(name = "is_connect_guest_directly", nullable = false) + private Integer isConnectGuestDirectly = 0; + + @Column(name = "guest_contact") + private String guestContact; + + @Column(name = "driver_source") + private String driverSource; + + @Column(name = "limo_platform") + private Integer limoPlatform; +} diff --git a/src/main/java/com/mgm/mcrm/limo/services/LimoService.java b/src/main/java/com/mgm/mcrm/limo/services/LimoService.java new file mode 100644 index 0000000..3b85d22 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/limo/services/LimoService.java @@ -0,0 +1,2283 @@ +package com.mgm.mcrm.limo.services; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.alibaba.fastjson.parser.Feature; +import com.auth0.jwt.JWT; +import com.mgm.mcrm.appsetting.services.SettingService; +import com.mgm.mcrm.common.constants.SysCommon; +import com.mgm.mcrm.common.dtos.BaseApiResponse; +import com.mgm.mcrm.common.dtos.http_util.HttpResponseResult; +import com.mgm.mcrm.common.dtos.mgm_api.PlayerProfileApiResult; +import com.mgm.mcrm.common.dtos.mgm_api.PlayerProfileEntry; +import com.mgm.mcrm.common.dtos.mgm_api.UserInfoApiRecord; +import com.mgm.mcrm.common.services.MGMApiService; +import com.mgm.mcrm.common.utils.LogUtil; +import com.mgm.mcrm.limo.dtos.request.GetLimoFlightDetailsRequest; +import com.mgm.mcrm.limo.dtos.request.GetLimoTotalAmountRequest; +import com.mgm.mcrm.limo.dtos.request.InternalCreateLimoBookingRequest; +import com.mgm.mcrm.limo.dtos.request.InternalUpdateLimoBookingRequest; +import com.mgm.mcrm.limo.dtos.request.RequestPlayerEsbBookerRequest; +import com.mgm.mcrm.limo.dtos.request.*; +import com.mgm.mcrm.limo.dtos.response.*; +import com.mgm.mcrm.common.services.MGMEsbApiService; +import com.mgm.mcrm.common.services.MGMLimoApiService; +import com.mgm.mcrm.player.services.PlayerService; +import jakarta.servlet.http.HttpServletRequest; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.poi.util.StringUtil; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.orm.ObjectOptimisticLockingFailureException; +import org.springframework.stereotype.Service; +import org.springframework.util.StringUtils; + +import org.apache.commons.lang3.Strings; + +import com.mgm.mcrm.limo.dao.LimoBookingDraftRepository; +import com.mgm.mcrm.limo.dao.LimoBookingsRepository; +import com.mgm.mcrm.limo.models.LimoBookingDraft; +import com.mgm.mcrm.limo.models.LimoBookings; + +import jakarta.annotation.Resource; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; +import java.util.*; +import java.util.function.Function; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +@Slf4j +@Service +public class LimoService { + private static final int MAX_BOOKING_SYNC_RETRIES = 5; + private static final String DRAFT_STATUS_PENDING = "PENDING"; + private static final String DRAFT_STATUS_PROCESSING = "PROCESSING"; + private static final String DRAFT_STATUS_USED = "USED"; + private static final String DRAFT_STATUS_FAILED = "FAILED"; + + @Resource + private LimoBookingsRepository limoBookingsRepository; + @Resource + private LimoBookingDraftRepository limoBookingDraftRepository; + @Resource + private MGMEsbApiService mgmEsbApiService; + @Resource + private MGMLimoApiService mgmLimoApiService; + @Resource + private MGMApiService mgmApiService; + @Resource + private SettingService settingService; + @Resource + private PlayerService playerService; + @Value("${limo.booking-draft.expiry-seconds:120}") + private long bookingDraftExpirySeconds; + + private static final List EXCLUDED_GET_BOOKINGS_STATUSES = + List.of("CANCELED", "COMPLETED", "DONE","Cancelled","GUEST_DROPPED"); + + private static final Set ALLOWED_CAR_TYPE_BOOKING_TYPES = + Set.of("LOCAL", "HONGKONG", "HK", "CHINA"); + + private static final DateTimeFormatter ESB_BOOKING_DATE_FORMAT = + DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + + private static final List PICK_UP_DATETIME_FORMATTERS = List.of( + DateTimeFormatter.ISO_LOCAL_DATE_TIME, + ESB_BOOKING_DATE_FORMAT, + DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")); + +// @Transactional(transactionManager = "transactionManager") + public CreateLimoBookingResponse createBooking(CreateLimoBookingRequest request, HttpServletRequest requestHeader, UserInfoApiRecord userInfo) throws Exception { + LimoBookings entity = new LimoBookings(); + String token = requestHeader.getHeader("Authorization"); + String userId = JWT.decode(token).getClaim("login_id").asString(); + String userName = userInfo.getUserName(); + Integer autoConfirm = 0; + + StringBuilder missing = new StringBuilder(); + if (request.getPlayerId() == null) { + missing.append("playerId,"); + } + if (!StringUtils.hasText(request.getPickUpPoint())) { + missing.append("pickUpPoint/pickupPoint,"); + } + if (request.getPickUpDatetime() == null) { + missing.append("pickUpDatetime/pickupDatetime,"); + } + if (!StringUtils.hasText(request.getDropOffPoint())) { + missing.append("dropOffPoint,"); + } + if (!missing.isEmpty()) { + missing.setLength(missing.length() - 1); + return CreateLimoBookingResponse.failure("400", "缺少必填字段: " + missing); + } + if (request.getPickUpDatetime() != null) { + if (request.getPickUpDatetime().before(new Date())) { + return CreateLimoBookingResponse.failure("400", "pickUpDatetime invalid"); + } + // 检查日期是否在当前日期的两个月以内,超过两个月不允许预订 + Calendar calendar = Calendar.getInstance(); + calendar.add(Calendar.MONTH, 2); + calendar.add(Calendar.DATE,1); + Date twoMonthsLater = calendar.getTime(); + if (request.getPickUpDatetime().after(twoMonthsLater)) { + return CreateLimoBookingResponse.failure("400", "pickUpDatetime invalid"); + } + } + + + LimoPricing pricing = calculateLimoPricingSingleTrip( + request.getPickUpPointId(), + request.getDropOffPointId(), + request.getExtraOffPointId(), + parseIntegerOrDefault(request.getHour(), 0), + request.getTripType(), + request.getServiceType(), + request.getIsHourlyRate(), + request.getTripPriceId()); + + UUID draftId; + try { + draftId = UUID.fromString(request.getDraftId()); + } catch (Exception e) { + return CreateLimoBookingResponse.failure("400", "Invalid or missing draftId"); + } + + LimoBookingDraft bookingDraft = limoBookingDraftRepository.findByDraftId(draftId).orElse(null); + if (bookingDraft == null) { + return CreateLimoBookingResponse.failure("400", "Invalid booking draft"); + } + if (!userId.equals(bookingDraft.getUserId())) { + return CreateLimoBookingResponse.failure("403", "Booking draft does not belong to current user"); + } + if (!Long.valueOf(request.getPlayerId()).equals(bookingDraft.getPlayerId())) { + return CreateLimoBookingResponse.failure("403", "Player does not match booking draft"); + } + String requestApproverId = StringUtils.hasText(request.getApproverId()) + ? request.getApproverId().trim() + : ""; + if (!requestApproverId.equals(bookingDraft.getApproverId())) { + return CreateLimoBookingResponse.failure( + "403", "Approver does not match booking draft"); + } + if (!DRAFT_STATUS_PENDING.equals(bookingDraft.getStatus())) { + return CreateLimoBookingResponse.failure("409", "Booking draft is not available"); + } + if (!bookingDraft.getExpiresAt().isAfter(LocalDateTime.now())) { + return CreateLimoBookingResponse.failure("410", "Booking draft has expired"); + } + + String approverId = bookingDraft.getApproverId(); + String overRiderId = request.getOverriderId(); + String validatedApproverName = bookingDraft.getApproverName(); + String buildApprover = validatedApproverName+"("+approverId+")"; + entity.setApproverId(approverId); + entity.setApprover(validatedApproverName); + //check overRiderId invalid + if (StringUtils.hasText(overRiderId)){ + try { + GetLimoBookingGetOverriderRequest overriderRequest = new GetLimoBookingGetOverriderRequest(); + overriderRequest.setOverriderInfo(overRiderId); + GetOverriderInfoResponse overriderResponse = getLimoOverriderData(overriderRequest); + if (Strings.CI.equals("OK", overriderResponse.getStatusCode()) + && CollectionUtils.isNotEmpty(overriderResponse.getRecords())) { + // 查找匹配的 overrider + for (GetOverriderInfoResponse.OverriderEmployeeRecord record : overriderResponse.getRecords()) { + if (overRiderId.equals(String.valueOf(record.getEmployeeId()))) { + entity.setOverrideBy(record.getEmployeeName()); + break; + } + } + } + } catch (Exception e) { + log.warn("Failed to verify overRiderId [{}], skip validation: {}", overRiderId, e.getMessage()); + } + } + + BeanUtils.copyProperties(request, entity, "dropOffPointIds", "pickUpPointId", "carTypeId", + "approverId", "approver", "overriderId"); + entity.setId(null); + entity.setTripPrice(formatAmount(pricing.getSingleTripPrice())); + entity.setTotalAmount(formatAmount(pricing.getTotalAmount())); + entity.setPlayerId(String.valueOf(request.getPlayerId())); + entity.setVersion(0L); + entity.setCreatedAt(new Date()); + entity.setCreatedBy(userInfo.getUserId()); + // 如果overriderId已通过ESB验证设置了overrideBy,则不再覆盖 + if (!StringUtils.hasText(overRiderId)) { + entity.setOverrideBy(request.getOverriderName()); + } + entity.setBookerId(userId); + + entity.setTripType(request.getTripType()); + entity.setPickUpPointId(request.getPickUpPointId()); + entity.setDropOffPointIds(request.getDropOffPointId()); + entity.setExtraDropOffId(request.getExtraOffPointId()); + entity.setExtraDropOffPoint(request.getExtraOffPoint()); + entity.setCarTypeId(request.getCarTypeId()); + entity.setGreetTypeId(request.getGreetTypeId()); + entity.setHourlyRate(formatAmount(pricing.getHourlyRate())); + + + entity.setIsTenOut(integerOrZero(request.getIsTenOut())); + entity.setIsHighImportance(integerOrZero(request.getIsHighImportance())); + entity.setIsConnectGuestDirectly(integerOrZero(request.getIsContactGuestDirectly())); + entity.setTenOutContact(request.getTenOutContact()); + entity.setGuestContact(request.getGuestContact()); + + entity.setBookingContact(request.getBookingContact()); + + Date nowTs = new Date(); + entity.setCreatedAt(nowTs); + entity.setUpdatedAt(nowTs); + + HttpResponseResult httpResponseResult = mgmEsbApiService.invokeSimpleLimoBookingQualificationStatus( + request.getPlayerId(), + request.getBookingType(), + formatEsbBookingDate(request.getPickUpDatetime())); + + LimoBookings saved = new LimoBookings(); + int claimed = limoBookingDraftRepository.claimPendingDraft( + draftId, userId, Long.valueOf(request.getPlayerId()), LocalDateTime.now()); + if (claimed != 1) { + return CreateLimoBookingResponse.failure( + "409", "Booking draft has already been used or is being processed"); + } + + try { + InternalCreateLimoBookingRequest limoCreateRequest = + buildInternalCreateRequest(request, pricing, userId,userName, buildApprover); + + limoCreateRequest.setCreateBy(userId); + + // 第一次尝试: createNotConfirmBooking = 0 + JSONObject createRoot = callLimoCreateAndParse(limoCreateRequest); + if (createRoot == null) { + markDraftFailed(draftId); + return CreateLimoBookingResponse.failure("500", "Limo create failed"); + } + + String apiResult = createRoot.getString("result"); + + // 406 时重试: createNotConfirmBooking = 1 + if (Strings.CI.equals("406", apiResult)) { + limoCreateRequest.setCreateNotConfirmBooking(1); + createRoot = callLimoCreateAndParse(limoCreateRequest); + if (createRoot == null) { + markDraftFailed(draftId); + return CreateLimoBookingResponse.failure("500", "Limo create retry failed"); + } + apiResult = createRoot.getString("result"); + }else if(Strings.CI.equals("200", apiResult)){ + autoConfirm = 1; + } + + if (!Strings.CI.equals("200", apiResult)) { + markDraftFailed(draftId); + String apiError = createRoot.getString("error"); + String message = "result=" + apiResult; + if (StringUtils.hasText(apiError)) { + message = message + ", error=" + apiError; + } + return CreateLimoBookingResponse.failure( + StringUtils.hasText(apiResult) ? apiResult : "System Error", + message); + } + + entity.setBookingStatus(autoConfirm == 1 ? "CONFIRMED" : "PENDING"); + + // 提取 Limo 返回的 BookingNo,回写 limo_booking_id + String itemObject = createRoot.getString("itemObject"); + if (StringUtils.hasText(itemObject)) { + JSONArray items = JSONArray.parseArray(itemObject); + if (!items.isEmpty()) { + String bookingId = items.getJSONObject(0).getString("BookingID"); + + if (SysCommon.mgmApiMockup){ + Date today = new Date(); + bookingId+=today; + } + + if (StringUtils.hasText(bookingId)) { + entity.setLimoBookingId(bookingId); + saved = limoBookingsRepository.save(entity); + } + } + } + if (saved.getId() == null || !StringUtils.hasText(entity.getLimoBookingId())) { + markDraftFailed(draftId); + return CreateLimoBookingResponse.failure("500", "Limo create returned no booking ID"); + } + + LocalDateTime completedAt = LocalDateTime.now(); + limoBookingDraftRepository.completeDraft( + draftId, DRAFT_STATUS_USED, entity.getLimoBookingId(), completedAt, completedAt); + + return CreateLimoBookingResponse.success(saved.getId(),autoConfirm); + } catch (Exception e) { + markDraftFailed(draftId); + throw e; + } + } + + public BaseApiResponse prepareBooking( + PrepareLimoBookingRequest request, String userId) { + try { + RequestPlayerEsbBookerRequest bookerRequest = new RequestPlayerEsbBookerRequest(); + bookerRequest.setPlayerId(request.getPlayerId()); + bookerRequest.setUserId(userId); + BaseApiResponse> bookerResponse = getPlayerEsbBooker(bookerRequest); + if (!bookerResponse.isSuccess()) { + log.error("ESB rejected draft approver validation for approverId [{}]: {}", + request.getApproverId(), bookerResponse.getMessage()); + return BaseApiResponse.error("503", "Unable to validate approver"); + } + + String approverId = request.getApproverId().trim(); + PlayerEsbBookerItem matchedApprover = Optional.ofNullable(bookerResponse.getData()) + .orElseGet(Collections::emptyList) + .stream() + .filter(item -> item.getEmployeeId() != null) + .filter(item -> approverId.equals(String.valueOf(item.getEmployeeId()))) + .findFirst() + .orElse(null); + if (matchedApprover == null) { + log.warn("Unauthorized draft approverId [{}] for playerId [{}] and userId [{}]", + approverId, request.getPlayerId(), userId); + return BaseApiResponse.error( + "403", "The selected approver is not authorized for this booking"); + } + + String approverName = firstText( + matchedApprover.getEmployeeIdAndName(), matchedApprover.getEmployeeName()); + if (!StringUtils.hasText(approverName)) { + return BaseApiResponse.error("503", "Unable to validate approver"); + } + + LocalDateTime now = LocalDateTime.now(); + LimoBookingDraft draft = new LimoBookingDraft(); + draft.setDraftId(UUID.randomUUID()); + draft.setUserId(userId); + draft.setPlayerId(Long.valueOf(request.getPlayerId())); + draft.setApproverId(approverId); + draft.setApproverName(approverName); + draft.setStatus(DRAFT_STATUS_PENDING); + draft.setExpiresAt(now.plusSeconds(bookingDraftExpirySeconds)); + draft.setCreatedAt(now); + draft.setVersion(0L); + LimoBookingDraft savedDraft = limoBookingDraftRepository.save(draft); + + return BaseApiResponse.ok(new PrepareLimoBookingData( + savedDraft.getDraftId(), savedDraft.getExpiresAt())); + } catch (Exception e) { + log.error("Failed to prepare booking draft for playerId [{}] and userId [{}]", + request.getPlayerId(), userId, e); + return BaseApiResponse.error("503", "Unable to prepare booking draft"); + } + } + + private void markDraftFailed(UUID draftId) { + LocalDateTime now = LocalDateTime.now(); + limoBookingDraftRepository.completeDraft( + draftId, DRAFT_STATUS_FAILED, null, null, now); + } + + /** + * 调用 Limo CreateBooking 并解析 JSON 响应。 + * 返回解析后的 JSONObject,若 HTTP 或 JSON 解析失败则返回 null。 + */ + private JSONObject callLimoCreateAndParse(InternalCreateLimoBookingRequest limoCreateRequest) throws Exception { + HttpResponseResult response = mgmLimoApiService.invokeCreateBooking(limoCreateRequest); + + if (response.getStatusCode() != 200) { + LogUtil.error(LimoService.class, + "Limo CreateBooking HTTP error: " + response.getStatusCode()); + return null; + } + + String body = response.getResponseContent(); + if (!StringUtils.hasText(body)) { + LogUtil.error(LimoService.class, "Limo CreateBooking empty response body"); + return null; + } + + JSONObject root = JSONObject.parseObject(body); + if (root == null) { + LogUtil.error(LimoService.class, "Limo CreateBooking invalid JSON response"); + return null; + } + + return root; + } + + public boolean checkViewPlayer(Long bookingId,String confirmNo,String userId) throws Exception { + LimoBookings bookings = new LimoBookings(); + if (bookingId != null) { + bookings = this.getBookingById(bookingId); + }else if (confirmNo != null) { + bookings = limoBookingsRepository.findByConfirmationNo(confirmNo); + }else{ + return false; + } + BaseApiResponse res = null; + if (bookings != null) { + res = playerService.findPlayerProfileByPlayerIdAndUserId(bookings.getPlayerId(), userId); + } + if (res != null && res.isSuccess()) { + PlayerProfileEntry profile = res.getData(); + Integer code = profile.getCodedFlag(); + return code == 1; + } + return false; + } + +// @Transactional(transactionManager = "transactionManager") + public UpdateLimoBookingResponse updateBooking(UpdateLimoBookingRequest request,String userId) throws Exception { + if (request.getId() == null) { + return UpdateLimoBookingResponse.failure("400", "Id is required"); + } + + Optional byId = limoBookingsRepository.findById(request.getId()); + + if (byId.isEmpty()) { + return UpdateLimoBookingResponse.failure("400", "Booking not found"); + } + + LimoBookings limoBookings = byId.get(); + + LimoPricing pricing = calculateLimoPricingSingleTrip( + request.getPickupPointId(), + request.getDropOffPointIds(), + request.getExtraDropOffPointId(), + parseIntegerOrDefault(String.valueOf(request.getHour()), 0), + request.getTripType(), + request.getServiceType(), + request.getIsHourlyRate(), + request.getTripPriceId()); + + try { + applyUpdateRequest(request, limoBookings); + } catch (DateTimeParseException e) { + return UpdateLimoBookingResponse.failure("400", "Invalid pickUpDatetime"); + } + limoBookings.setTripPrice(formatAmount(pricing.getSingleTripPrice())); + limoBookings.setTotalAmount(formatAmount(pricing.getTotalAmount())); + limoBookings.setHourlyRate(formatAmount(pricing.getHourlyRate())); + + limoBookings.setUpdatedAt(new Date()); + limoBookings.setUpdatedBy(request.getUpdatedByName()); + + log.info("Updatebooking Request PickUpId : {},DropOffId : {}",request.getPickupPointId(),request.getDropOffPointIds()); + + InternalUpdateLimoBookingRequest limoUpdateRequest = + buildInternalUpdateRequest(request, limoBookings, pricing); + limoUpdateRequest.setEditBy(userId); + + HttpResponseResult limoUpdateBookingResponse = mgmLimoApiService.invokeUpdateBooking(limoUpdateRequest); + + if (limoUpdateBookingResponse.getStatusCode() != 200) { + return UpdateLimoBookingResponse.failure( + String.valueOf(limoUpdateBookingResponse.getStatusCode()), + "Limo HTTP error: " + limoUpdateBookingResponse.getStatusCode()); + } + + String body = limoUpdateBookingResponse.getResponseContent(); + if (!StringUtils.hasText(body)) { + return UpdateLimoBookingResponse.failure("500", "Limo update empty response body"); + } + + JSONObject root = JSONObject.parseObject(body); + if (root == null) { + return UpdateLimoBookingResponse.failure("500", "Limo update invalid JSON response"); + } + + String apiResult = root.getString("result"); + if (!Strings.CI.equals("200", apiResult)) { + String apiError = root.getString("error"); + String message = "result=" + apiResult; + if (StringUtils.hasText(apiError)) { + message = message + ", error=" + apiError; + } + return UpdateLimoBookingResponse.failure( + StringUtils.hasText(apiResult) ? apiResult : "System Error", + message); + } + + limoBookingsRepository.save(limoBookings); + + return UpdateLimoBookingResponse.success(); + } + + //获取到TodayBooking Merge到当前数据库中,如果ID存在,更新数据库,不存在则作为新数据填入数据库中 + public void getTodayBooking(String playerId) throws Exception { + BaseApiResponse> response = + parseLimoItemObjectList(mgmLimoApiService.invokeGetBooking(null), LimoBookingItem.class); + if (response == null || response.getData() == null || response.getData().isEmpty()) { + return; + } + + List items = response.getData(); + + // 只处理 PlayerId 匹配传入 playerId 的记录,避免对无关订单独查询数据库 + items = items.stream() + .filter(item -> Strings.CS.equals(playerId, item.getPlayerId())) + .toList(); + if (items.isEmpty()) { + return; + } + + Map carTypeNameMap = getCarTypeNameMap(); + Map locationNameMap = getLocationNameMap(); + Map greetTypeNameMap = getGreetTypeNameMap(); + + // 按 BookingNo 分组,同组 sub-bookings 的 Pickup 用 ";" 拼接 + Map> grouped = items.stream() + .collect(Collectors.groupingBy(LimoBookingItem::getBookingNo)); + + for (Map.Entry> entry : grouped.entrySet()) { + String bookingNo = entry.getKey(); + List subItems = entry.getValue(); + LimoBookingItem src = subItems.getFirst(); + + // 拼接所有 Pickup + String pickUpPoint = joinResolvedLocationNames( + subItems, + LimoBookingItem::getPickup, + LimoBookingItem::getPickupPoiid, + locationNameMap); + String dropOffPoint = resolveLocationName( + src.getDropoff(), + src.getDropoffPoiid(), + locationNameMap); + String extraDropOffPoint = joinExtraDropoffNames(subItems, locationNameMap); + String extraDropOffId = joinExtraDropoffIds(subItems); + String bookerEmployeeId = resolveBookerEmployeeId(subItems); + String driverContact = firstNonBlank(subItems, LimoBookingItem::getDriverContact); + String bookingContact = firstNonBlank(subItems, LimoBookingItem::getBookingContact); + String tenOutContact = firstNonBlank(subItems, LimoBookingItem::getTenOutContact); + String guestContact = firstNonBlank(subItems, LimoBookingItem::getGuestContact); + + LogUtil.info(LimoService.class,"DriverContact:"+driverContact); + + // 取第一条作为主数据源 + //LimoBookings existing = limoBookingsRepository.findByLimoBookingId(String.valueOf(src.getId())); + LimoBookings existing = this.getUniqueOneBookingByLimoBookingId(String.valueOf(src.getId())); + LimoBookings entity; + if (existing != null) { + entity = existing; + } else { + entity = new LimoBookings(); + entity.setCreatedAt(new Date()); + entity.setVersion(0L); + } + + entity.setLimoBookingId(String.valueOf(src.getId())); + entity.setConfirmationNo(bookingNo); + entity.setPlayerId(src.getPlayerId()); + entity.setBookingType(src.getBookingType()); + entity.setServiceType(src.getTripType()); + entity.setBookingStatus(mapBookingStatus(src.getBookingStatus())); + entity.setCarNo(src.getCarPlate()); + entity.setTripContact(src.getBookerContact()); + entity.setDriverContact(!Strings.CS.equals(driverContact.trim(), "") ? driverContact : null); + + if (StringUtils.hasText(pickUpPoint) || existing == null) { + entity.setPickUpPoint(defaultString(pickUpPoint, "")); + } + entity.setPickUpPointId(String.valueOf(src.getPickupPoiid())); + if (StringUtils.hasText(dropOffPoint) || existing == null) { + entity.setDropOffPoint(defaultString(dropOffPoint, "")); + } + entity.setDropOffPointIds(String.valueOf(src.getDropoffPoiid())); + entity.setExtraDropOffId(extraDropOffId); + entity.setExtraDropOffPoint(extraDropOffPoint); + Long carTypeId = src.getCarTypeId() != null ? Long.valueOf(src.getCarTypeId()) : null; + entity.setCarType(resolveCarTypeName(src.getCarType(), carTypeId, carTypeNameMap)); + entity.setCarTypeId(carTypeId); + entity.setNoOfPax(src.getPassengerNo()); + String greetTypeIds = defaultString(src.getGreetType(), "").trim(); + String greetTypeNames = resolveGreetTypeNames(greetTypeIds, greetTypeNameMap); + entity.setGreetTypeId(greetTypeIds); + if (StringUtils.hasText(greetTypeNames) || existing == null) { + entity.setGreetType(greetTypeNames); + } + + entity.setSignage(src.getSignage()); + entity.setApprover(src.getApprovedBy()); + entity.setPaymentMethod(src.getPaymentMethod()); + entity.setBookingContact(bookingContact); + entity.setIsHighImportance(integerOrZero(src.getHighImportance())); + entity.setIsTenOut(integerOrZero(src.getTenOut())); + entity.setIsConnectGuestDirectly(StringUtils.hasText(guestContact) ? 1 : 0); + entity.setTenOutContact(tenOutContact); + entity.setGuestContact(guestContact); + entity.setTripPrice(src.getSingleTripPrice()); + entity.setTotalAmount(src.getTotalAmount()); + entity.setHourlyRate(src.getHourlyRate()); + entity.setRemarks(src.getBookingRemark()); + entity.setFlightDetail(src.getFlightDetails()); + entity.setFlightStatus(src.getFlightStatus()); + entity.setOverrideBy(src.getOverrideBy()); + entity.setDriverSource(src.getDriverSource()); + if (StringUtils.hasText(bookerEmployeeId) || existing == null) { + entity.setBookerId(defaultString(bookerEmployeeId, "")); + entity.setCreatedBy(defaultString(bookerEmployeeId, "")); + } + + +// pickupDatetime String → Date + if (StringUtils.hasText(src.getPickupDatetime())) { + try { + LocalDateTime ldt = LocalDateTime.parse(src.getPickupDatetime(), ESB_BOOKING_DATE_FORMAT); + entity.setPickUpDatetime(Date.from(ldt.atZone(ZoneId.systemDefault()).toInstant())); + } catch (DateTimeParseException ignored) { + } + } + + entity.setUpdatedAt(new Date()); + + limoBookingsRepository.save(entity); + } + + } + + public void getLimoBookingByLimoBookingId(String limoBookingId) throws Exception { + for (int attempt = 1; attempt <= MAX_BOOKING_SYNC_RETRIES; attempt++) { + try { + syncLimoBookingByLimoBookingId(limoBookingId); + return; + } catch (ObjectOptimisticLockingFailureException e) { + if (attempt == MAX_BOOKING_SYNC_RETRIES) { + throw new IllegalStateException( + "Unable to synchronize booking after " + MAX_BOOKING_SYNC_RETRIES + + " attempts due to concurrent updates: " + limoBookingId, e); + } + log.warn("Concurrent update while synchronizing booking {}, retry {}/{}", + limoBookingId, attempt, MAX_BOOKING_SYNC_RETRIES); + } + } + } + + private void syncLimoBookingByLimoBookingId(String limoBookingId) throws Exception { + LogUtil.info(LimoService.class,"Start sync Limo Booking from mapking api: " + limoBookingId); + + LimoBookings booking = limoBookingsRepository.getByLimoBookingId(limoBookingId); + + HttpResponseResult httpResponseResult = mgmLimoApiService.invokeGetBooking(limoBookingId); + LimoBookingItem returnLimoBooking = new LimoBookingItem(); + Map carTypeNameMap = getCarTypeNameMap(); + Map locationNameMap = getLocationNameMap(); + Map greetTypeNameMap = getGreetTypeNameMap(); + List extranDropoffNames = new ArrayList<>(); + List extranDropoffIds = new ArrayList<>(); + LimoBookings entity; + + if (httpResponseResult.getStatusCode()==200){ + BaseApiResponse> parsed = + parseLimoItemObjectList(httpResponseResult, LimoBookingItem.class); + if (parsed != null && CollectionUtils.isNotEmpty(parsed.getData())) { + returnLimoBooking = parsed.getData().getFirst(); + LogUtil.info(LimoService.class,"LimoBooking returned from API LIMO BookingID : " + returnLimoBooking.getId()); + } + if (parsed != null && parsed.getData().isEmpty()) return; + } + + if (booking != null) { + LogUtil.info(LimoService.class,"Is exist Limo Booking from mapking,Limo Booking Id :" + limoBookingId); + entity = booking; + } else { + LogUtil.info(LimoService.class,"Is new Limo Booking from mapking,Limo Booking Id :" + limoBookingId); + entity = new LimoBookings(); + entity.setCreatedAt(new Date()); + entity.setVersion(0L); + } + + //拿到Extra DropOff Names + for (int i = 1; i <= 10 ;i++){ + Long poiId = extraDropoffPoiid(returnLimoBooking, i); + String extraDropOffName = extraDropoff(returnLimoBooking,i); + if (!StringUtils.hasText(extraDropOffName) && (poiId == null || poiId == 0)) { + continue; + } + String resolvedName = resolveLocationName(extraDropOffName,poiId,locationNameMap); + if (StringUtils.hasText(resolvedName)) { + extranDropoffNames.add(resolvedName); + } + } + entity.setExtraDropOffPoint(String.join(";", extranDropoffNames)); + + //拿到Extra DropOff Ids + for (int i = 1; i <= 10; i++) { + Long poiId = extraDropoffPoiid(returnLimoBooking, i); + if (poiId != null && poiId != 0L) { + extranDropoffIds.add(String.valueOf(poiId)); + } + } + entity.setExtraDropOffId(String.join(";", extranDropoffIds)); + entity.setPickUpPointId(returnLimoBooking.getPickupPoiid() != null ? String.valueOf(returnLimoBooking.getPickupPoiid()) : null); + entity.setPickUpPoint(defaultString(locationNameMap.get(returnLimoBooking.getPickupPoiid()), "N/A")); + entity.setDropOffPointIds(returnLimoBooking.getDropoffPoiid() != null ? String.valueOf(returnLimoBooking.getDropoffPoiid()) : null); + entity.setDropOffPoint(defaultString(locationNameMap.get(returnLimoBooking.getDropoffPoiid()), "N/A")); + + entity.setBookerId(extractParenthesizedId(returnLimoBooking.getBookedBy())); + entity.setCreatedBy(extractParenthesizedId(returnLimoBooking.getBookedBy())); + + entity.setLimoBookingId(returnLimoBooking.getId() != null ? String.valueOf(returnLimoBooking.getId()) : null); + entity.setConfirmationNo(returnLimoBooking.getBookingNo()); + entity.setPlayerId(returnLimoBooking.getPlayerId()); + entity.setBookingType(returnLimoBooking.getBookingType()); + entity.setServiceType(returnLimoBooking.getTripType()); + entity.setBookingStatus(mapBookingStatus(returnLimoBooking.getBookingStatus())); + entity.setCarNo(returnLimoBooking.getCarPlate()); + entity.setTripContact(returnLimoBooking.getBookerContact()); + entity.setDriverContact(returnLimoBooking.getDriverContact()); + + Long carTypeId = returnLimoBooking.getCarTypeId() != null ? Long.valueOf(returnLimoBooking.getCarTypeId()) : null; + entity.setCarType(resolveCarTypeName(returnLimoBooking.getCarType(), carTypeId, carTypeNameMap)); + entity.setCarTypeId(carTypeId); + entity.setNoOfPax(returnLimoBooking.getPassengerNo()); + String greetTypeIds = defaultString(returnLimoBooking.getGreetType(), "").trim(); + String greetTypeNames = resolveGreetTypeNames(greetTypeIds, greetTypeNameMap); + entity.setGreetTypeId(greetTypeIds); + if (StringUtils.hasText(greetTypeNames) || entity == null) { + entity.setGreetType(greetTypeNames); + } + + entity.setSignage(returnLimoBooking.getSignage()); + entity.setApprover(returnLimoBooking.getApprovedBy()); + entity.setPaymentMethod(returnLimoBooking.getPaymentMethod()); + entity.setBookingContact(returnLimoBooking.getBookingContact()); + entity.setIsHighImportance(integerOrZero(returnLimoBooking.getHighImportance())); + entity.setIsTenOut(integerOrZero(returnLimoBooking.getTenOut())); + entity.setIsConnectGuestDirectly(StringUtils.hasText(returnLimoBooking.getGuestContact()) ? 1 : 0); + entity.setTenOutContact(returnLimoBooking.getTenOutContact()); + entity.setGuestContact(returnLimoBooking.getGuestContact()); + entity.setTripPrice(returnLimoBooking.getSingleTripPrice()); + entity.setTotalAmount(returnLimoBooking.getTotalAmount()); + entity.setHourlyRate(returnLimoBooking.getHourlyRate()); + entity.setRemarks(returnLimoBooking.getBookingRemark()); + entity.setFlightDetail(returnLimoBooking.getFlightDetails()); + entity.setFlightStatus(returnLimoBooking.getFlightStatus()); + entity.setOverrideBy(returnLimoBooking.getOverrideBy()); + entity.setDriverSource(returnLimoBooking.getDriverSource()); + +// pickupDatetime String → Date + if (StringUtils.hasText(returnLimoBooking.getPickupDatetime())) { + try { + LocalDateTime ldt = LocalDateTime.parse(returnLimoBooking.getPickupDatetime(), ESB_BOOKING_DATE_FORMAT); + entity.setPickUpDatetime(Date.from(ldt.atZone(ZoneId.systemDefault()).toInstant())); + } catch (DateTimeParseException ignored) { + return; + } + } else { + return; + } + + entity.setUpdatedAt(new Date()); + limoBookingsRepository.save(entity); + LogUtil.info(LimoService.class,"End sync Limo Booking from mapking api,Limo Booking Id :" + limoBookingId); + } + + + public LimoBookings getBookingById(Long id) throws Exception { + this.getLimoBookingByLimoBookingId(String.valueOf(id)); + + return limoBookingsRepository.findById(id).orElse(null); + } + + public LimoBookings getBookingByConf(String confirmationNo) throws Exception { + + this.getLimoBookingByLimoBookingId(extractBookingId(confirmationNo)); + + return limoBookingsRepository.findByConfirmationNo(confirmationNo); + } + + //通过ESB接口获取到Limo Booker,即为前端Approver中可选信息 + public BaseApiResponse> getPlayerEsbBooker(RequestPlayerEsbBookerRequest request) + throws Exception { + HttpResponseResult httpResponseResult = mgmEsbApiService.invokeRequestPlayerLimoBooker(request); + if (httpResponseResult.getStatusCode() != 200) { + return BaseApiResponse.internalServerError( + "ESB HTTP error: " + httpResponseResult.getStatusCode()); + } + + String body = httpResponseResult.getResponseContent(); + if (!StringUtils.hasText(body)) { + return BaseApiResponse.internalServerError("ESB empty response body"); + } + + PlayerEsbBookerResponse esb = JSONObject.parseObject(body, PlayerEsbBookerResponse.class); + if (esb == null) { + return BaseApiResponse.internalServerError("ESB invalid JSON response"); + } + + if (!Strings.CI.equals("OK", esb.getStatusCode())) { + String code = StringUtils.hasText(esb.getStatusCode()) ? esb.getStatusCode() : "ESB_ERROR"; + String message = StringUtils.hasText(esb.getStatusDescription()) + ? esb.getStatusDescription() + : "Player Limo Booker API error"; + return BaseApiResponse.error(code, message); + } + + List records = esb.getRecords(); + return BaseApiResponse.ok(records == null ? Collections.emptyList() : records); + } + + + //通过ESB接口 获取到当前Booking是否够分,不够分需要填入Overrider + public GetLimoBookingQualificationResponse checkBookingQualification(GetLimoBookingQualificationRequest request) + throws Exception { + HttpResponseResult httpResponseResult = mgmEsbApiService.invokeSimpleLimoBookingQualificationStatus( + request.getPlayerId(), request.getBookingType(), request.getBookingDate()); + + if (httpResponseResult.getStatusCode() != 200) { + throw new IllegalStateException( + "ESB limo qualification HTTP error: " + httpResponseResult.getStatusCode()); + } + + String body = httpResponseResult.getResponseContent(); + if (!StringUtils.hasText(body)) { + throw new IllegalStateException("ESB limo qualification empty response body"); + } + + return JSONObject.parseObject(body, GetLimoBookingQualificationResponse.class); + } + + //通过ESB接口 获取到Overriver,当Booking不够分的时候填入Overrider + public GetOverriderInfoResponse getLimoOverriderData(GetLimoBookingGetOverriderRequest request) + throws Exception { + HttpResponseResult httpResponseResult = mgmEsbApiService.invokeLimoOverrider(request.getOverriderInfo()); + + if (httpResponseResult.getStatusCode() != 200) { + throw new IllegalStateException( + "ESB limo overrider HTTP error: " + httpResponseResult.getStatusCode()); + } + + String body = httpResponseResult.getResponseContent(); + if (!StringUtils.hasText(body)) { + throw new IllegalStateException("ESB limo overrider empty response body"); + } + + return JSONObject.parseObject(body, GetOverriderInfoResponse.class); + } + + + //通过ESB接口 获取到LimoEmployeeInfo + public GetLimoEmployeeInfoResponse getLimoEmployeeData(GetLimoEmployeeInfoRequest request) + throws Exception { + HttpResponseResult httpResponseResult = mgmEsbApiService.invokeRequestEmployeeInfo(request.getEmployeeId()); + + if (httpResponseResult.getStatusCode() != 200) { + throw new IllegalStateException( + "ESB limo employee HTTP error: " + httpResponseResult.getStatusCode()); + } + + String body = httpResponseResult.getResponseContent(); + if (!StringUtils.hasText(body)) { + throw new IllegalStateException("ESB limo employee empty response body"); + } + + return JSONObject.parseObject(body, GetLimoEmployeeInfoResponse.class); + } + + private LimoBookings getUniqueOneBookingByLimoBookingId(String limoBookingId){ + LimoBookings target = null; + List matchBookings = limoBookingsRepository.findByLimoBookingId(limoBookingId); + if(matchBookings!=null && !matchBookings.isEmpty()){ + target = matchBookings.get(0); + for(int i=1;i getBookingsByPlayerId(String playerId,HttpServletRequest request) throws Exception { + + //获取完Limo today booking之后再去拿到最新的数据 + if (!SysCommon.mgmApiMockup){ + //this.getTodayBooking(); + + HttpResponseResult httpResponseResult = mgmApiService.invokeGetLimoBookingFromLegacy(playerId); + if (httpResponseResult.getStatusCode() == 200) { + String responseContent = httpResponseResult.getResponseContent(); + GetLimoBookingFromLegacyResult resultObj = JSONObject.parseObject(responseContent,GetLimoBookingFromLegacyResult.class,Feature.SupportNonPublicField,Feature.IgnoreNotMatch); + List bookingList = resultObj != null ? resultObj.getRecords() : new ArrayList<>(); + Map upsertBookings = new LinkedHashMap<>(); + //将返回的数据放到bookings中,已存在的LimoBookingId则更新,否则插入 + for (LimoBookingFromLegacyItem booking : bookingList) { + LimoBookings mapped = this.mapToLimoBookings(booking, playerId); + String limoBookingId = mapped.getLimoBookingId(); + LimoBookings target = upsertBookings.get(limoBookingId); + if (target == null) { + //target = limoBookingsRepository.findByLimoBookingId(limoBookingId); + target = this.getUniqueOneBookingByLimoBookingId(limoBookingId); + if (target == null) { + target = mapped; + } else { + BeanUtils.copyProperties(mapped, target, "id", "version", "createdAt"); + } + upsertBookings.put(limoBookingId, target); + } else { + BeanUtils.copyProperties(mapped, target, "id", "version", "createdAt"); + } + } + limoBookingsRepository.saveAll(upsertBookings.values()); + } + } + + ZoneId zone = ZoneId.systemDefault(); + Date startOfToday = Date.from(LocalDate.now(zone).atStartOfDay(zone).toInstant()); + return limoBookingsRepository.findByPlayerIdAndBookingStatusNotInAndPickUpDatetimeGreaterThanEqual( + playerId, EXCLUDED_GET_BOOKINGS_STATUSES, startOfToday); + } + + private LimoBookings mapToLimoBookings(LimoBookingFromLegacyItem booking, String playerId) { + LimoBookings entity = new LimoBookings(); + Date now = new Date(); + + entity.setPlayerId(playerId); + entity.setConfirmationNo(booking.getBookingNo()); + entity.setLimoBookingId(booking.getBookingId()); + entity.setBookingStatus(mapBookingStatus(booking.getBookingStatus())); + + entity.setPickUpPoint(defaultString(booking.getPickup(), "")); + entity.setPickUpPointId(booking.getPickupPoiid() != null ? String.valueOf(booking.getPickupPoiid()) : null); + entity.setDropOffPoint(defaultString(booking.getDropoff(), "")); + entity.setDropOffPointIds(booking.getDropoffPoiid() != null ? String.valueOf(booking.getDropoffPoiid()) : null); + + entity.setExtraDropOffId(joinLegacyExtraDropoffIds(booking)); + entity.setExtraDropOffPoint(joinLegacyExtraDropoffNames(booking)); + + entity.setCarType(booking.getCarType()); + entity.setCarNo(booking.getCarPlate()); + entity.setNoOfPax(booking.getPassengerNo()); + entity.setTripPrice(booking.getSingleTripPrice()); + entity.setTotalAmount(booking.getTotalAmount()); + entity.setTripPrice(booking.getTotalAmount()); + entity.setBookerId(booking.getBookedBy()); + entity.setApprover(booking.getApprovedBy()); + entity.setOverrideBy(booking.getOverrideBy()); + entity.setRemarks(booking.getBookingRemark()); + entity.setDriverContact(booking.getDriverContact()); + + Date pickupDatetime = parsePickUpDatetime(booking.getPickupDatetime()); + if (pickupDatetime != null) { + entity.setPickUpDatetime(pickupDatetime); + } + + entity.setCreatedAt(now); + entity.setUpdatedAt(now); + entity.setCreatedBy(booking.getBookedBy()); + entity.setVersion(0L); + + return entity; + } + + private static Date parsePickUpDatetime(String value) { + if (!StringUtils.hasText(value)) { + return null; + } + String trimmed = value.trim(); + for (DateTimeFormatter formatter : PICK_UP_DATETIME_FORMATTERS) { + try { + LocalDateTime localDateTime = LocalDateTime.parse(trimmed, formatter); + return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant()); + } catch (DateTimeParseException ignored) { + } + } + return null; + } + + private static String joinLegacyExtraDropoffNames(LimoBookingFromLegacyItem booking) { + List names = new ArrayList<>(); + for (int i = 1; i <= 10; i++) { + String name = legacyExtraDropoff(booking, i); + if (StringUtils.hasText(name)) { + names.add(name.trim()); + } + } + return String.join(";", names); + } + + private static String joinLegacyExtraDropoffIds(LimoBookingFromLegacyItem booking) { + List ids = new ArrayList<>(); + for (int i = 1; i <= 10; i++) { + Long poiId = legacyExtraDropoffPoiid(booking, i); + if (poiId != null && poiId != 0L) { + ids.add(String.valueOf(poiId)); + } + } + return String.join(";", ids); + } + + private static Long legacyExtraDropoffPoiid(LimoBookingFromLegacyItem item, int index) { + return switch (index) { + case 1 -> item.getExtraDropoffPoiid1(); + case 2 -> item.getExtraDropoffPoiid2(); + case 3 -> item.getExtraDropoffPoiid3(); + case 4 -> item.getExtraDropoffPoiid4(); + case 5 -> item.getExtraDropoffPoiid5(); + case 6 -> item.getExtraDropoffPoiid6(); + case 7 -> item.getExtraDropoffPoiid7(); + case 8 -> item.getExtraDropoffPoiid8(); + case 9 -> item.getExtraDropoffPoiid9(); + case 10 -> item.getExtraDropoffPoiid10(); + default -> 0L; + }; + } + + private static String legacyExtraDropoff(LimoBookingFromLegacyItem item, int index) { + return switch (index) { + case 1 -> item.getExtraDropoff1(); + case 2 -> item.getExtraDropoff2(); + case 3 -> item.getExtraDropoff3(); + case 4 -> item.getExtraDropoff4(); + case 5 -> item.getExtraDropoff5(); + case 6 -> item.getExtraDropoff6(); + case 7 -> item.getExtraDropoff7(); + case 8 -> item.getExtraDropoff8(); + case 9 -> item.getExtraDropoff9(); + case 10 -> item.getExtraDropoff10(); + default -> ""; + }; + } + + public CancelLimoBookingResponse cancelBooking(CancelLimoBookingRequest request,String userId) throws Exception { + + InternalCancelLimoBookingRequest internalCancelLimoBookingRequest = new InternalCancelLimoBookingRequest(); + + if (request == null) + return CancelLimoBookingResponse.failure("500", "No parameters."); + + Long id = request.getId(); + if (id == null) + return CancelLimoBookingResponse.failure("500", "No ID parameter."); + + LimoBookings limoBookings = limoBookingsRepository.findById(id).orElse(null); + if (limoBookings == null) + return CancelLimoBookingResponse.failure("500", "Limo Booking not found."); + + if(!Strings.CS.equals(limoBookings.getCreatedBy(),userId)) + return CancelLimoBookingResponse.failure("500", "Only the creator can cancel this booking."); + + limoBookings.setBookingStatus("CANCELED"); + limoBookings.setUpdatedBy(request.getUpdatedBy()); + limoBookings.setUpdatedAt(new Date()); + + internalCancelLimoBookingRequest.setBookingId(limoBookings.getLimoBookingId()); + internalCancelLimoBookingRequest.setEditBy(userId); + + limoBookingsRepository.save(limoBookings); + mgmLimoApiService.invokeCancelLimoBooking(internalCancelLimoBookingRequest); + + return CancelLimoBookingResponse.success(id); + } + + + public BaseApiResponse> getTripPriceList() throws Exception { + return parseLimoItemObjectList(mgmLimoApiService.invokeGetTripPrice(), LimoTripPriceItem.class); + } + + public BaseApiResponse> getLocation(String location) throws Exception { + BaseApiResponse> response = + parseLimoItemObjectList(mgmLimoApiService.invokeGetLocation(location), LimoPointOfInterestItem.class); + if (response.getData() != null) { + response.setData(response.getData().stream() + .filter(item -> !isInvalidLocation(item)) + .collect(Collectors.toList())); + } + return response; + } + + private static boolean isInvalidLocation(LimoPointOfInterestItem item) { + if (item == null) { + return true; + } + return isPlaceholderLocationName(item.getEnglishName()) + && isPlaceholderLocationName(item.getChineseTradName()) + && isPlaceholderLocationName(item.getChineseSimpName()); + } + + private static boolean isPlaceholderLocationName(String value) { + return !StringUtils.hasText(value) || "---".equals(value.trim()); + } + + public BaseApiResponse> getCarType() throws Exception { + BaseApiResponse> response = + parseLimoItemObjectList(mgmLimoApiService.invokeGetCarType(), LimoCarTypeItem.class); + if (response.getData() != null) { + response.setData(response.getData().stream() + .filter(LimoService::hasAllowedCarTypeBookingType) + .collect(Collectors.toList())); + } + return response; + } + + private static boolean hasAllowedCarTypeBookingType(LimoCarTypeItem item) { + if (item == null || !StringUtils.hasText(item.getBookingType())) { + return false; + } + return Arrays.stream(item.getBookingType().split("[,;/]")) + .map(LimoService::normalizeBookingType) + .anyMatch(ALLOWED_CAR_TYPE_BOOKING_TYPES::contains); + } + + private static String normalizeBookingType(String bookingType) { + return bookingType == null ? "" : bookingType.replace(" ", "").trim().toUpperCase(Locale.ROOT); + } + + public BaseApiResponse> getGreetType() throws Exception { + return parseLimoItemObjectList(mgmLimoApiService.invokeGetGreetType(), LimoGreetTypeItem.class); + } + + public BaseApiResponse> getFlightDetails(GetLimoFlightDetailsRequest request) + throws Exception { + return parseLimoItemObjectList(mgmLimoApiService.getFlightDetails(request), LimoFlightDetailsItem.class); + } + + public BaseApiResponse> getTotalAmount(GetLimoTotalAmountRequest request) + throws Exception { + return parseLimoItemObjectList(mgmLimoApiService.getTotalAmount(request), LimoTotalAmountItem.class); + } + + private InternalCreateLimoBookingRequest buildInternalCreateRequest( + CreateLimoBookingRequest request, LimoPricing pricing, String bookerId,String bookerName, + String validatedApproverName) throws Exception { + InternalCreateLimoBookingRequest limoBookingRequest = new InternalCreateLimoBookingRequest(); + + String buildUserInfo = bookerName+"("+bookerId+")"; + + // --- Booking Information --- + limoBookingRequest.setCreateNotConfirmBooking(0); + limoBookingRequest.setBookingType(defaultString(request.getBookingType(), "0")); + limoBookingRequest.setGreetType(defaultString(request.getGreetTypeId().replace(";",","), "")); + limoBookingRequest.setOtherGreetType(""); + limoBookingRequest.setGuestType(defaultString(request.getGuestType(), "0")); + limoBookingRequest.setTripType(request.getTripType()); + + // --- Guest Information --- + limoBookingRequest.setPlayerId(request.getPlayerId() != null ? String.valueOf(request.getPlayerId()) : ""); + + HttpResponseResult httpResponseResult = mgmEsbApiService.invokeLimoPlayerInfo(request.getPlayerId()); + String responseContent = httpResponseResult.getResponseContent(); + GetPlayerInfoResponse getPlayerInfoResponse = JSONObject.parseObject(responseContent, GetPlayerInfoResponse.class); + if(Strings.CS.equals(getPlayerInfoResponse.getStatusCode(),"OK")) { + try { + limoBookingRequest.setMaskedTier(getPlayerInfoResponse.getMaskedTier()); + limoBookingRequest.setFirstName(getPlayerInfoResponse.getFirstName()); + limoBookingRequest.setLastName(getPlayerInfoResponse.getLastName()); + limoBookingRequest.setChineseLastName(getPlayerInfoResponse.getChineseLastName()); + limoBookingRequest.setChineseFirstName(getPlayerInfoResponse.getChineseFirstName()); + limoBookingRequest.setSalution(getPlayerInfoResponse.getSalutation()); + } catch (Exception e) { + e.printStackTrace(); + } + } + + limoBookingRequest.setOverrideBy(defaultString(request.getOverriderName(), "")); + limoBookingRequest.setComplexOverrider(""); + + // --- Room / Employee --- + limoBookingRequest.setRoomNo(""); + limoBookingRequest.setEmployeeId(defaultString(request.getEmployeeId(), "")); + + // --- Contact --- + limoBookingRequest.setBookerContact(defaultString(request.getBookerContact(), "")); + limoBookingRequest.setTripContact(defaultString(request.getTripContact(), "")); + + // --- Trip Details --- + limoBookingRequest.setAdHoc(0); + if (request.getPickUpDatetime() != null) { + limoBookingRequest.setPickupDatetime(request.getPickUpDatetime().toInstant() + .atZone(ZoneId.systemDefault()).toLocalDateTime()); + } + limoBookingRequest.setCarTypeId(request.getCarTypeId() != null ? request.getCarTypeId() : 0L); + limoBookingRequest.setPassengerNo(request.getNoOfPax() != null ? request.getNoOfPax() : 1); + + // --- Pickup --- + limoBookingRequest.setPickupPOIID(parseLongOrDefault(request.getPickUpPointId(), 0L)); + limoBookingRequest.setPickup(defaultString(request.getOtherPickUpPoint() == null ?request.getPickUpPoint() : request.getOtherPickUpPoint(), "")); + limoBookingRequest.setPickupTripPriceId(0L); + limoBookingRequest.setPickupRegion(defaultString(request.getPickupRegion(), "Local")); + + // --- Dropoff --- + List dropOffPointIdList = splitPointValues(request.getDropOffPointId()); + List dropOffPointList = splitPointValues(request.getDropOffPoint()); + List extraDropOffPointIdList = splitPointValues(request.getExtraOffPointId()); + List extraDropOffPointList = splitPointValues(request.getExtraOffPoint()); + limoBookingRequest.setDropoffPOIID(parseLongOrDefault(valueAt(dropOffPointIdList, 0), 0L)); + limoBookingRequest.setDropoff(defaultString(firstText( + request.getOtherDropOffPoint(), + valueAt(dropOffPointList, 0), + request.getDropOffPoint()), "")); + limoBookingRequest.setDropoffTripPriceId(0L); + limoBookingRequest.setDropoffRegion(defaultString(request.getDropoffRegion(), "Local")); + + // --- Extra Dropoff Locations (1-10) --- + for (int i = 1; i <= 10; i++) { + setExtraDropoff( + limoBookingRequest, + i, + parseLongOrDefault(valueAt(extraDropOffPointIdList, i - 1), 0L), + defaultString(valueAt(extraDropOffPointList, i - 1), "")); + } + + // --- Pricing --- + BigDecimal singleTripPrice = pricing.getSingleTripPrice(); + BigDecimal amount = pricing.getTotalAmount(); + limoBookingRequest.setSingleTripPrice(singleTripPrice); + limoBookingRequest.setDefaultTripPrice(singleTripPrice); + limoBookingRequest.setDefaultPublishTripPrice(singleTripPrice); + + limoBookingRequest.setHourlyRate(pricing.getHourlyRate()); + limoBookingRequest.setHourlyWaitingFee(BigDecimal.ZERO); + limoBookingRequest.setHour(pricing.getHour()); + limoBookingRequest.setHourlyWaiting(0); + + limoBookingRequest.setExtraDropoffPrice1(pricing.getExtraDropoffPrice(1)); + limoBookingRequest.setExtraDropoffPrice2(pricing.getExtraDropoffPrice(2)); + limoBookingRequest.setExtraDropoffPrice3(pricing.getExtraDropoffPrice(3)); + limoBookingRequest.setExtraDropoffPrice4(pricing.getExtraDropoffPrice(4)); + limoBookingRequest.setExtraDropoffPrice5(pricing.getExtraDropoffPrice(5)); + limoBookingRequest.setExtraDropoffPrice6(pricing.getExtraDropoffPrice(6)); + limoBookingRequest.setExtraDropoffPrice7(pricing.getExtraDropoffPrice(7)); + limoBookingRequest.setExtraDropoffPrice8(pricing.getExtraDropoffPrice(8)); + limoBookingRequest.setExtraDropoffPrice9(pricing.getExtraDropoffPrice(9)); + limoBookingRequest.setExtraDropoffPrice10(pricing.getExtraDropoffPrice(10)); + + limoBookingRequest.setOtherPriceRemark(""); + limoBookingRequest.setOtherPrice(BigDecimal.ZERO); + + // --- Payment --- + limoBookingRequest.setPaymentMethod(defaultString(request.getPaymentMethod(), "")); + limoBookingRequest.setTotalAmount(amount); + + // --- Special Services --- + boolean isHighImportance = integerOrZero(request.getIsHighImportance()) == 1; + boolean isTenOut = integerOrZero(request.getIsTenOut()) == 1; + limoBookingRequest.setHighImportance(isHighImportance); + limoBookingRequest.setTenOut(isTenOut); + limoBookingRequest.setButlerGreet(false); + + limoBookingRequest.setBookingContact(request.getBookingContact()); + limoBookingRequest.setTenOutContact(request.getTenOutContact()); + limoBookingRequest.setGuestContact(request.getGuestContact()); + + // --- Personnel --- + limoBookingRequest.setBookedBy(defaultString(buildUserInfo, "")); + limoBookingRequest.setApprovedBy(defaultString(validatedApproverName, "")); + + // --- Remarks --- + limoBookingRequest.setBookingRemark(defaultString(request.getRemarks(), "")); + limoBookingRequest.setDriverRemark(""); + limoBookingRequest.setLimoInternalRemark(""); + limoBookingRequest.setSystemRemark(""); + + // --- Greet Services --- + limoBookingRequest.setLimoGreet(false); + limoBookingRequest.setHostGreet(false); + limoBookingRequest.setVipMeetNGreet(false); + + limoBookingRequest.setOtherGreet(""); + limoBookingRequest.setFlightDetails(defaultString(request.getFlightDetail(), "")); + limoBookingRequest.setSignage(defaultString(request.getSignage(), "")); + + return limoBookingRequest; + } + + private InternalUpdateLimoBookingRequest buildInternalUpdateRequest( + UpdateLimoBookingRequest request, LimoBookings booking, LimoPricing pricing) throws Exception { + InternalUpdateLimoBookingRequest limoBookingRequest = new InternalUpdateLimoBookingRequest(); + + limoBookingRequest.setId(defaultString(booking.getLimoBookingId(), "")); + limoBookingRequest.setBookingType(defaultString(request.getBookingType(), "")); + limoBookingRequest.setCreateNotConfirmBooking(true); + + if (hasPickUpDatetime(request) && booking.getPickUpDatetime() != null) { + limoBookingRequest.setPickupDatetime(booking.getPickUpDatetime().toInstant() + .atZone(ZoneId.systemDefault()).toLocalDateTime()); + } + + if (hasPickUpLocation(request)) { + if (request.getPickupPointId() != null || request.getPickUpPointCode() != null) { + String pickupPointId = firstText(request.getPickupPointId(), request.getPickUpPointCode()); + limoBookingRequest.setPickupPOIID(parseLongOrDefault(pickupPointId, 0L)); + } + if (request.getOtherPickUpPoint() != null || request.getPickUpPoint() != null) { + limoBookingRequest.setPickup(defaultString(firstText(request.getOtherPickUpPoint(), request.getPickUpPoint()), "")); + } + if (request.getPickupRegion() != null) { + limoBookingRequest.setPickupRegion(defaultString(request.getPickupRegion(), "")); + } + } + + List dropOffPoints = sortedDropOffPoints(request); + boolean requestHasDropOffLocation = hasDropOffLocation(request); + String dropOffPointIds = requestHasDropOffLocation + ? firstText(resolveRequestDropOffPointIds(request, dropOffPoints), booking.getDropOffPointIds()) + : defaultString(booking.getDropOffPointIds(), ""); + List dropOffPointIdList = splitPointIds(dropOffPointIds); + List dropOffPointList = splitPointValues(firstText(request.getDropOffPoint(), booking.getDropOffPoint())); + List extraDropOffPointIdList = splitPointValues(firstText(request.getExtraDropOffPointId(), booking.getExtraDropOffId())); + List extraDropOffPointList = splitPointValues(firstText(request.getExtraDropOffPoint(), booking.getExtraDropOffPoint())); + + limoBookingRequest.setDropoffPOIID(parseLongOrDefault(valueAt(dropOffPointIdList, 0), 0L)); + limoBookingRequest.setDropoff(defaultString( + firstText( + request.getOtherDropOffPoint(), + pointNameAt(dropOffPoints, 0), + valueAt(dropOffPointList, 0), + booking.getOtherDropOffPoint()), + "")); + if (requestHasDropOffLocation && request.getDropoffRegion() != null) { + limoBookingRequest.setDropoffRegion(defaultString(request.getDropoffRegion(), "")); + } + + for (int i = 1; i <= 10; i++) { + String extraId = StringUtils.hasText(request.getExtraDropOffPointId()) + || (!requestHasDropOffLocation && StringUtils.hasText(booking.getExtraDropOffId())) + ? valueAt(extraDropOffPointIdList, i - 1) + : valueAt(dropOffPointIdList, i); + String extraName = StringUtils.hasText(request.getExtraDropOffPoint()) + || (!requestHasDropOffLocation && StringUtils.hasText(booking.getExtraDropOffPoint())) + ? valueAt(extraDropOffPointList, i - 1) + : firstText(pointNameAt(dropOffPoints, i), valueAt(dropOffPointList, i)); + setExtraDropoffLocation( + limoBookingRequest, + i, + parseLongOrDefault(extraId, 0L), + defaultString(extraName, "")); + } + + // Price fields are calculated by the backend and must not be taken from the client request. + limoBookingRequest.setSingleTripPrice(pricing.getSingleTripPrice()); + limoBookingRequest.setDefaultTripPrice(pricing.getSingleTripPrice()); + limoBookingRequest.setDefaultPublishTripPrice(pricing.getSingleTripPrice()); + limoBookingRequest.setHourlyRate(pricing.getHourlyRate()); + limoBookingRequest.setHourlyWaitingFee(BigDecimal.ZERO); + limoBookingRequest.setHour(pricing.getHour()); + limoBookingRequest.setHourlyWaiting(0); + limoBookingRequest.setExtraDropoffPrice1(pricing.getExtraDropoffPrice(1)); + limoBookingRequest.setExtraDropoffPrice2(pricing.getExtraDropoffPrice(2)); + limoBookingRequest.setExtraDropoffPrice3(pricing.getExtraDropoffPrice(3)); + limoBookingRequest.setExtraDropoffPrice4(pricing.getExtraDropoffPrice(4)); + limoBookingRequest.setExtraDropoffPrice5(pricing.getExtraDropoffPrice(5)); + limoBookingRequest.setExtraDropoffPrice6(pricing.getExtraDropoffPrice(6)); + limoBookingRequest.setExtraDropoffPrice7(pricing.getExtraDropoffPrice(7)); + limoBookingRequest.setExtraDropoffPrice8(pricing.getExtraDropoffPrice(8)); + limoBookingRequest.setExtraDropoffPrice9(pricing.getExtraDropoffPrice(9)); + limoBookingRequest.setExtraDropoffPrice10(pricing.getExtraDropoffPrice(10)); + limoBookingRequest.setTotalAmount(pricing.getTotalAmount()); + + if (request.getRemarks() != null) { + limoBookingRequest.setBookingRemark(defaultString(request.getRemarks(), "")); + } + + return limoBookingRequest; + } + + private static String formatEsbBookingDate(Date date) { + if (date == null) { + return null; + } + return date.toInstant() + .atZone(ZoneId.systemDefault()) + .format(ESB_BOOKING_DATE_FORMAT); + } + + private Date parsePickUpDatetime(UpdateLimoBookingRequest request) { + String pickUpDatetime = request.getPickUpDatetime(); + if (!StringUtils.hasText(pickUpDatetime) + && StringUtils.hasText(request.getPickUpDate()) + && StringUtils.hasText(request.getPickUpTime())) { + pickUpDatetime = request.getPickUpDate() + " " + request.getPickUpTime(); + } + + if (!StringUtils.hasText(pickUpDatetime)) { + return null; + } + + String value = pickUpDatetime.trim(); + try { + return Date.from(Instant.parse(value)); + } catch (DateTimeParseException ignored) { + } + + for (DateTimeFormatter formatter : PICK_UP_DATETIME_FORMATTERS) { + try { + LocalDateTime localDateTime = LocalDateTime.parse(value, formatter); + return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant()); + } catch (DateTimeParseException ignored) { + } + } + + throw new DateTimeParseException("Invalid pickUpDatetime", value, 0); + } + + private static String defaultString(String value, String defaultValue) { + return StringUtils.hasText(value) ? value : defaultValue; + } + + private static Integer integerOrZero(Integer value) { + return value != null ? value : 0; + } + + private static String firstText(String... values) { + if (values == null) { + return ""; + } + for (String value : values) { + if (StringUtils.hasText(value)) { + return value.trim(); + } + } + return ""; + } + + private static boolean hasPickUpDatetime(UpdateLimoBookingRequest request) { + return request != null && (StringUtils.hasText(request.getPickUpDatetime()) + || (StringUtils.hasText(request.getPickUpDate()) && StringUtils.hasText(request.getPickUpTime()))); + } + + private static boolean hasPickUpLocation(UpdateLimoBookingRequest request) { + return request != null && (request.getPickupPointId() != null + || request.getPickUpPointCode() != null + || request.getPickUpPoint() != null + || request.getOtherPickUpPoint() != null); + } + + private static boolean hasDropOffLocation(UpdateLimoBookingRequest request) { + return request != null && (request.getDropOffPointIds() != null + || request.getDropOffPointCode() != null + || request.getDropOffPoint() != null + || request.getOtherDropOffPoint() != null + || request.getExtraDropOffPointId() != null + || request.getExtraDropOffPoint() != null + || !CollectionUtils.isEmpty(request.getDropOffPoints())); + } + + private static Long resolveCarTypeId(UpdateLimoBookingRequest request, LimoBookings booking) { + if (request.getCarTypeId() != null) { + return request.getCarTypeId(); + } + Long parsedCarTypeCode = parseLongOrDefault(request.getCarTypeCode(), null); + if (parsedCarTypeCode != null) { + return parsedCarTypeCode; + } + return booking.getCarTypeId() != null ? booking.getCarTypeId() : 0L; + } + + private static List sortedDropOffPoints(UpdateLimoBookingRequest request) { + if (CollectionUtils.isEmpty(request.getDropOffPoints())) { + return Collections.emptyList(); + } + return request.getDropOffPoints().stream() + .filter(Objects::nonNull) + .sorted(Comparator.comparing( + UpdateLimoBookingRequest.DropOffPoint::getSequence, + Comparator.nullsLast(Integer::compareTo))) + .collect(Collectors.toList()); + } + + private static String resolveDropOffPointIds( + UpdateLimoBookingRequest request, + LimoBookings booking, + List dropOffPoints) { + String requestDropOffPointIds = firstText(request.getDropOffPointIds(), request.getDropOffPointCode()); + if (StringUtils.hasText(requestDropOffPointIds)) { + return requestDropOffPointIds; + } + if (!CollectionUtils.isEmpty(dropOffPoints)) { + String joined = dropOffPoints.stream() + .map(UpdateLimoBookingRequest.DropOffPoint::getPointCode) + .filter(StringUtils::hasText) + .map(String::trim) + .collect(Collectors.joining(",")); + if (StringUtils.hasText(joined)) { + return joined; + } + } + return defaultString(booking.getDropOffPointIds(), ""); + } + + private static String resolveRequestDropOffPointIds( + UpdateLimoBookingRequest request, + List dropOffPoints) { + String requestDropOffPointIds = firstText(request.getDropOffPointIds(), request.getDropOffPointCode()); + if (StringUtils.hasText(requestDropOffPointIds)) { + return requestDropOffPointIds; + } + if (!CollectionUtils.isEmpty(dropOffPoints)) { + return dropOffPoints.stream() + .map(UpdateLimoBookingRequest.DropOffPoint::getPointCode) + .filter(StringUtils::hasText) + .map(String::trim) + .collect(Collectors.joining(",")); + } + return ""; + } + + private static List splitPointIds(String value) { + if (!StringUtils.hasText(value)) { + return Collections.emptyList(); + } + return splitPointValues(value); + } + + private static List splitPointValues(String value) { + if (!StringUtils.hasText(value)) { + return Collections.emptyList(); + } + return Arrays.stream(value.split("[,;\\uFF1B]")) + .map(String::trim) + .filter(StringUtils::hasText) + .collect(Collectors.toList()); + } + + private static String joinPointValues(String... values) { + if (values == null || values.length == 0) { + return ""; + } + return Arrays.stream(values) + .filter(StringUtils::hasText) + .flatMap(value -> splitPointValues(value).stream()) + .collect(Collectors.joining(";")); + } + + private static String valueAt(List values, int index) { + if (values == null || index < 0 || index >= values.size()) { + return ""; + } + return values.get(index); + } + + private static String pointNameAt(List points, int index) { + if (points == null || index < 0 || index >= points.size()) { + return ""; + } + return points.get(index).getPointName(); + } + + private static void setExtraDropoff( + InternalCreateLimoBookingRequest request, int index, Long poiId, String name) { + switch (index) { + case 1 -> { + request.setExtraDropoffPOIID1(poiId); + request.setExtraDropoff1(name); + request.setExtraDropoffTripPriceID1(0L); + request.setExtraDropoffRegion1(""); + } + case 2 -> { + request.setExtraDropoffPOIID2(poiId); + request.setExtraDropoff2(name); + request.setExtraDropoffTripPriceID2(0L); + request.setExtraDropoffRegion2(""); + } + case 3 -> { + request.setExtraDropoffPOIID3(poiId); + request.setExtraDropoff3(name); + request.setExtraDropoffTripPriceID3(0L); + request.setExtraDropoffRegion3(""); + } + case 4 -> { + request.setExtraDropoffPOIID4(poiId); + request.setExtraDropoff4(name); + request.setExtraDropoffTripPriceID4(0L); + request.setExtraDropoffRegion4(""); + } + case 5 -> { + request.setExtraDropoffPOIID5(poiId); + request.setExtraDropoff5(name); + request.setExtraDropoffTripPriceID5(0L); + request.setExtraDropoffRegion5(""); + } + case 6 -> { + request.setExtraDropoffPOIID6(poiId); + request.setExtraDropoff6(name); + request.setExtraDropoffTripPriceID6(0L); + request.setExtraDropoffRegion6(""); + } + case 7 -> { + request.setExtraDropoffPOIID7(poiId); + request.setExtraDropoff7(name); + request.setExtraDropoffTripPriceID7(0L); + request.setExtraDropoffRegion7(""); + } + case 8 -> { + request.setExtraDropoffPOIID8(poiId); + request.setExtraDropoff8(name); + request.setExtraDropoffTripPriceID8(0L); + request.setExtraDropoffRegion8(""); + } + case 9 -> { + request.setExtraDropoffPOIID9(poiId); + request.setExtraDropoff9(name); + request.setExtraDropoffTripPriceID9(0L); + request.setExtraDropoffRegion9(""); + } + case 10 -> { + request.setExtraDropoffPOIID10(poiId); + request.setExtraDropoff10(name); + request.setExtraDropoffTripPriceID10(0L); + request.setExtraDropoffRegion10(""); + } + default -> { + } + } + } + + private static void setExtraDropoffLocation( + InternalUpdateLimoBookingRequest request, int index, Long poiId, String name) { + switch (index) { + case 1 -> { + request.setExtraDropoffPOIID1(poiId); + request.setExtraDropoff1(name); + } + case 2 -> { + request.setExtraDropoffPOIID2(poiId); + request.setExtraDropoff2(name); + } + case 3 -> { + request.setExtraDropoffPOIID3(poiId); + request.setExtraDropoff3(name); + } + case 4 -> { + request.setExtraDropoffPOIID4(poiId); + request.setExtraDropoff4(name); + } + case 5 -> { + request.setExtraDropoffPOIID5(poiId); + request.setExtraDropoff5(name); + } + case 6 -> { + request.setExtraDropoffPOIID6(poiId); + request.setExtraDropoff6(name); + } + case 7 -> { + request.setExtraDropoffPOIID7(poiId); + request.setExtraDropoff7(name); + } + case 8 -> { + request.setExtraDropoffPOIID8(poiId); + request.setExtraDropoff8(name); + } + case 9 -> { + request.setExtraDropoffPOIID9(poiId); + request.setExtraDropoff9(name); + } + case 10 -> { + request.setExtraDropoffPOIID10(poiId); + request.setExtraDropoff10(name); + } + default -> { + } + } + } + + private static String firstNonBlank(List items, Function extractor) { + if (CollectionUtils.isEmpty(items)) { + return ""; + } + return items.stream() + .map(extractor) + .filter(StringUtils::hasText) + .map(String::trim) + .findFirst() + .orElse(""); + } + + private static String resolveBookerEmployeeId(List items) { + String employeeId = firstNonBlank(items, LimoBookingItem::getEmployeeId); + String bookedById = extractParenthesizedId(firstNonBlank(items, LimoBookingItem::getBookedBy)); + if (StringUtils.hasText(bookedById) && !Strings.CS.equals(bookedById, employeeId)) { + return bookedById; + } + return employeeId; + } + + private static String extractParenthesizedId(String value) { + if (!StringUtils.hasText(value)) { + return ""; + } + int closeIndex = value.lastIndexOf(')'); + int openIndex = value.lastIndexOf('(', closeIndex); + if (openIndex < 0 || closeIndex <= openIndex) { + return ""; + } + return value.substring(openIndex + 1, closeIndex).trim(); + } + + private static String joinNonBlank(List items, Function extractor) { + if (CollectionUtils.isEmpty(items)) { + return ""; + } + return items.stream() + .map(extractor) + .filter(StringUtils::hasText) + .map(String::trim) + .collect(Collectors.joining(";")); + } + + private static String joinResolvedLocationNames( + List items, + Function locationNameExtractor, + Function poiIdExtractor, + Map locationNameMap) { + if (CollectionUtils.isEmpty(items)) { + return ""; + } + return items.stream() + .map(item -> resolveLocationName( + locationNameExtractor.apply(item), + poiIdExtractor.apply(item), + locationNameMap)) + .filter(StringUtils::hasText) + .map(String::trim) + .collect(Collectors.joining(";")); + } + + private static String joinExtraDropoffNames(List items, Map locationNameMap) { + if (CollectionUtils.isEmpty(items)) { + return ""; + } + List extraDropoffNames = new ArrayList<>(); + for (LimoBookingItem item : items) { + if (item == null) { + continue; + } + for (int i = 1; i <= 10; i++) { + Long poiId = extraDropoffPoiid(item, i); + String extraDropoffName = extraDropoff(item, i); + if (!StringUtils.hasText(extraDropoffName) && (poiId == null || poiId == 0L)) { + continue; + } + String resolvedName = resolveLocationName(extraDropoffName, poiId, locationNameMap); + if (StringUtils.hasText(resolvedName)) { + extraDropoffNames.add(resolvedName.trim()); + } + } + } + return String.join(";", extraDropoffNames); + } + + private static String joinExtraDropoffIds(List items) { + if (CollectionUtils.isEmpty(items)) { + return ""; + } + List extraDropoffIds = new ArrayList<>(); + for (LimoBookingItem item : items) { + if (item == null) { + continue; + } + for (int i = 1; i <= 10; i++) { + Long poiId = extraDropoffPoiid(item, i); + if (poiId != null && poiId != 0L) { + extraDropoffIds.add(String.valueOf(poiId)); + } + } + } + return String.join(";", extraDropoffIds); + } + + private static String extraDropoff(LimoBookingItem item, int index) { + return switch (index) { + case 1 -> item.getExtraDropoff1(); + case 2 -> item.getExtraDropoff2(); + case 3 -> item.getExtraDropoff3(); + case 4 -> item.getExtraDropoff4(); + case 5 -> item.getExtraDropoff5(); + case 6 -> item.getExtraDropoff6(); + case 7 -> item.getExtraDropoff7(); + case 8 -> item.getExtraDropoff8(); + case 9 -> item.getExtraDropoff9(); + case 10 -> item.getExtraDropoff10(); + default -> ""; + }; + } + + private static Long extraDropoffPoiid(LimoBookingItem item, int index) { + return switch (index) { + case 1 -> item.getExtraDropoffPoiid1(); + case 2 -> item.getExtraDropoffPoiid2(); + case 3 -> item.getExtraDropoffPoiid3(); + case 4 -> item.getExtraDropoffPoiid4(); + case 5 -> item.getExtraDropoffPoiid5(); + case 6 -> item.getExtraDropoffPoiid6(); + case 7 -> item.getExtraDropoffPoiid7(); + case 8 -> item.getExtraDropoffPoiid8(); + case 9 -> item.getExtraDropoffPoiid9(); + case 10 -> item.getExtraDropoffPoiid10(); + default -> null; + }; + } + + private Map getCarTypeNameMap() throws Exception { + BaseApiResponse> response = + parseLimoItemObjectList(mgmLimoApiService.invokeGetCarType(), LimoCarTypeItem.class); + if (response.getData() == null || response.getData().isEmpty()) { + return Collections.emptyMap(); + } + return response.getData().stream() + .filter(item -> item.getId() != null && StringUtils.hasText(item.getCarType())) + .collect(Collectors.toMap( + LimoCarTypeItem::getId, + item -> item.getCarType().trim(), + (first, second) -> first)); + } + + private Map getLocationNameMap() throws Exception { + BaseApiResponse> response = getLocation("%"); + if (response.getData() == null || response.getData().isEmpty()) { + return Collections.emptyMap(); + } + return response.getData().stream() + .filter(item -> item.getId() != null && StringUtils.hasText(formatLocationName(item))) + .collect(Collectors.toMap( + LimoPointOfInterestItem::getId, + LimoService::formatLocationName, + (first, second) -> first)); + } + + private Map getGreetTypeNameMap() throws Exception { + BaseApiResponse> response = + parseLimoItemObjectList(mgmLimoApiService.invokeGetGreetType(), LimoGreetTypeItem.class); + if (response.getData() == null || response.getData().isEmpty()) { + return Collections.emptyMap(); + } + return response.getData().stream() + .filter(item -> item.getId() != null && StringUtils.hasText(item.getGreetType())) + .collect(Collectors.toMap( + LimoGreetTypeItem::getId, + item -> item.getGreetType().trim(), + (first, second) -> first)); + } + + private static String resolveGreetTypeNames(String greetTypeIds, Map greetTypeNameMap) { + if (!StringUtils.hasText(greetTypeIds) || greetTypeNameMap == null || greetTypeNameMap.isEmpty()) { + return ""; + } + return Arrays.stream(greetTypeIds.split("[;,]")) + .map(String::trim) + .filter(StringUtils::hasText) + .map(id -> parseLongOrDefault(id, null)) + .filter(Objects::nonNull) + .map(greetTypeNameMap::get) + .filter(StringUtils::hasText) + .collect(Collectors.joining(", ")); + } + + private static String resolveCarTypeName(String bookingCarType, Long carTypeId, Map carTypeNameMap) { + if (StringUtils.hasText(bookingCarType)) { + return bookingCarType.trim(); + } + if (carTypeId == null || carTypeNameMap == null) { + return bookingCarType; + } + return carTypeNameMap.getOrDefault(carTypeId, bookingCarType); + } + + private static String resolveLocationName(String bookingLocationName, Long poiId, Map locationNameMap) { +// if (StringUtils.hasText(bookingLocationName)) { +// return bookingLocationName.trim(); +// } + if (poiId == null || locationNameMap == null) { + return ""; + } + return defaultString(locationNameMap.get(poiId), ""); + } + + private static String formatLocationName(LimoPointOfInterestItem item) { + if (item == null) { + return ""; + } + String chineseTradName = item.getChineseTradName(); + String englishName = item.getEnglishName(); + if (StringUtils.hasText(chineseTradName) && StringUtils.hasText(englishName)) { + return chineseTradName.trim() + "/" + englishName.trim(); + } + if (StringUtils.hasText(chineseTradName)) { + return chineseTradName.trim(); + } + if (StringUtils.hasText(englishName)) { + return englishName.trim(); + } + return defaultString(item.getChineseSimpName(), ""); + } + + private static Long parseLongOrDefault(String value, Long defaultValue) { + if (!StringUtils.hasText(value)) { + return defaultValue; + } + try { + return Long.parseLong(value.trim()); + } catch (NumberFormatException e) { + return defaultValue; + } + } + + private static String extraDropoffPrice(LimoTotalAmountItem item, int index) { + if (item == null) { + return ""; + } + return switch (index) { + case 1 -> item.getExtraDropoffPrice1(); + case 2 -> item.getExtraDropoffPrice2(); + case 3 -> item.getExtraDropoffPrice3(); + case 4 -> item.getExtraDropoffPrice4(); + case 5 -> item.getExtraDropoffPrice5(); + case 6 -> item.getExtraDropoffPrice6(); + case 7 -> item.getExtraDropoffPrice7(); + case 8 -> item.getExtraDropoffPrice8(); + case 9 -> item.getExtraDropoffPrice9(); + case 10 -> item.getExtraDropoffPrice10(); + default -> ""; + }; + } + + private LimoPricing calculateLimoPricingSingleTrip( + String pickupPoiId, + String dropOffPointIds, + String extraDropOffPointIds, + Integer hour, + String tripType, + String serviceType, + Integer isHourlyRate, + Integer tripPriceId) throws Exception { + GetLimoTotalAmountRequest request = new GetLimoTotalAmountRequest(); + request.setPickupPOIId(pickupPoiId); + request.setDropoffPOIIds(joinPointValues(dropOffPointIds, extraDropOffPointIds)); + + LimoTotalAmountItem totalAmountItem = getTotalAmountItem(request); + BigDecimal singleTripPrice = parseBigDecimal(totalAmountItem.getSingleTripPrice()); + BigDecimal hourlyRate = BigDecimal.ZERO; + int resolvedHour = hour != null ? Math.max(hour, 0) : 0; + boolean hourlyTrip = isHourlyTrip(isHourlyRate, tripType, serviceType); + + if (hourlyTrip) { + hourlyRate = getHourlyRateByTripPriceId(tripPriceId); + singleTripPrice = hourlyRate.multiply(BigDecimal.valueOf(resolvedHour)); + } + + List extraDropoffPrices = new ArrayList<>(); + for (int i = 1; i <= 10; i++) { + BigDecimal price = parseBigDecimal(extraDropoffPrice(totalAmountItem, i)); + extraDropoffPrices.add(price); + } + BigDecimal totalAmount = hourlyTrip + ? singleTripPrice + : StringUtils.hasText(totalAmountItem.getTotalAmount()) + ? parseBigDecimal(totalAmountItem.getTotalAmount()) + : singleTripPrice; + + return new LimoPricing( + singleTripPrice, + extraDropoffPrices, + totalAmount, + hourlyRate, + resolvedHour); + } + + private BigDecimal getHourlyRateByTripPriceId(Integer tripPriceId) throws Exception { + if (tripPriceId == null) { + throw new IllegalArgumentException("TripPriceId is required for an hourly trip"); + } + + BaseApiResponse> response = + parseLimoItemObjectList(mgmLimoApiService.invokeGetTripPrice(), LimoTripPriceItem.class); + if (response.checkFailed()) { + throw new IllegalStateException("Limo GetTripPrice error: " + + defaultString(response.getMessage(), response.getCode())); + } + + return Optional.ofNullable(response.getData()).orElseGet(Collections::emptyList).stream() + .filter(item -> item.getId() != null && item.getId().longValue() == tripPriceId.longValue()) + .map(LimoTripPriceItem::getHourlyRate) + .filter(Objects::nonNull) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException( + "No HourlyRate found for TripPriceId: " + tripPriceId)); + } + + private LimoTotalAmountItem getTotalAmountItem(GetLimoTotalAmountRequest request) throws Exception { + HttpResponseResult totalAmount = mgmLimoApiService.getTotalAmount(request); + if (totalAmount.getStatusCode() != 200) { + throw new IllegalStateException("Limo total amount error: " + totalAmount.getResponseContent()); + } + String totalAmountJson = totalAmount.getResponseContent(); + JSONObject totalAmountObj = JSONObject.parseObject(totalAmountJson); + if (totalAmountObj == null) { + throw new IllegalStateException("Limo total amount invalid JSON response"); + } + JSONArray amountArray = totalAmountObj.getJSONArray("itemObject"); + if (amountArray == null) { + String totalAmountStr = totalAmountObj.getString("itemObject"); + if (StringUtils.hasText(totalAmountStr)) { + amountArray = JSONArray.parseArray(totalAmountStr); + } + } + if (amountArray == null || amountArray.isEmpty()) { + throw new IllegalStateException("Limo Check Total amount error"); + } + return amountArray.getJSONObject(0).toJavaObject(LimoTotalAmountItem.class); + } + + private static boolean isHourlyTrip(Integer isHourlyRate, String tripType, String serviceType) { + if (isHourlyRate != null && isHourlyRate == 1) { + return true; + } + String normalizedTripType = normalizeToken(tripType); + String normalizedServiceType = normalizeToken(serviceType); + return "2".equals(normalizedTripType) + || "HOURLY".equals(normalizedTripType) + || "ONHIRE".equals(normalizedTripType) + || "ONHIRE".equals(normalizedServiceType) + || "HOURLY".equals(normalizedServiceType); + } + + private static String normalizeToken(String value) { + return value == null ? "" : value.replace("_", "").replace(" ", "").trim().toUpperCase(Locale.ROOT); + } + + private static Integer parseIntegerOrDefault(String value, Integer defaultValue) { + if (!StringUtils.hasText(value)) { + return defaultValue; + } + try { + return Integer.parseInt(value.trim()); + } catch (NumberFormatException e) { + return defaultValue; + } + } + + private static String formatAmount(BigDecimal amount) { + if (amount == null) { + return "0.00"; + } + return amount.setScale(2, RoundingMode.HALF_UP).toPlainString(); + } + + private static BigDecimal parseBigDecimal(String value) { + if (!StringUtils.hasText(value)) { + return BigDecimal.ZERO; + } + try { + return new BigDecimal(value.trim()); + } catch (NumberFormatException e) { + return BigDecimal.ZERO; + } + } + + private static class LimoPricing { + private final BigDecimal singleTripPrice; + private final List extraDropoffPrices; + private final BigDecimal totalAmount; + private final BigDecimal hourlyRate; + private final Integer hour; + + private LimoPricing( + BigDecimal singleTripPrice, + List extraDropoffPrices, + BigDecimal totalAmount, + BigDecimal hourlyRate, + Integer hour) { + this.singleTripPrice = singleTripPrice; + this.extraDropoffPrices = extraDropoffPrices; + this.totalAmount = totalAmount; + this.hourlyRate = hourlyRate; + this.hour = hour; + } + + private BigDecimal getSingleTripPrice() { + return singleTripPrice; + } + + private BigDecimal getExtraDropoffPrice(int index) { + if (index < 1 || index > extraDropoffPrices.size()) { + return BigDecimal.ZERO; + } + return extraDropoffPrices.get(index - 1); + } + + private BigDecimal getTotalAmount() { + return totalAmount; + } + + private BigDecimal getHourlyRate() { + return hourlyRate; + } + + private Integer getHour() { + return hour; + } + } + + private static final Map LIMO_BOOKING_STATUS_MAP = new HashMap<>(); + static { + LIMO_BOOKING_STATUS_MAP.put("Not Yet Confirmed", "PENDING"); + LIMO_BOOKING_STATUS_MAP.put("Unconfirmed", "PENDING"); + + LIMO_BOOKING_STATUS_MAP.put("Confirmed", "CONFIRMED"); + LIMO_BOOKING_STATUS_MAP.put("Driver Yet to Confirm", "CONFIRMED"); + LIMO_BOOKING_STATUS_MAP.put("Driver Assigned", "DRIVER_ASSIGNED"); + LIMO_BOOKING_STATUS_MAP.put("Driver Arrived", "DRIVER_ARRIVED"); + LIMO_BOOKING_STATUS_MAP.put("Guest Picked", "GUEST_PICKED"); + LIMO_BOOKING_STATUS_MAP.put("Guest Dropped", "GUEST_DROPPED"); + LIMO_BOOKING_STATUS_MAP.put("Dispatched", "DRIVER_ASSIGNED"); + LIMO_BOOKING_STATUS_MAP.put("Received", "DRIVER_ASSIGNED"); + LIMO_BOOKING_STATUS_MAP.put("Acknowledged", "DRIVER_ASSIGNED"); + LIMO_BOOKING_STATUS_MAP.put("To_Pickup", "DRIVER_DEPARTED"); + LIMO_BOOKING_STATUS_MAP.put("Wait_pickup", "DRIVER_ARRIVED"); + LIMO_BOOKING_STATUS_MAP.put("To_Destination", "GUEST_PICKED"); + + LIMO_BOOKING_STATUS_MAP.put("Cancel", "CANCELED"); + LIMO_BOOKING_STATUS_MAP.put("Cancelled", "CANCELED"); + LIMO_BOOKING_STATUS_MAP.put("Done", "DONE"); + LIMO_BOOKING_STATUS_MAP.put("Completed", "COMPLETED"); + LIMO_BOOKING_STATUS_MAP.put("Trips during Stay", "DURING_STAY"); + + } + + private static String mapBookingStatus(String limoStatus) { + if (!StringUtils.hasText(limoStatus)) { + return "PENDING"; + } + return LIMO_BOOKING_STATUS_MAP.getOrDefault(limoStatus.trim(), limoStatus.trim()); + } + + + private void applyUpdateRequest(UpdateLimoBookingRequest request, LimoBookings limoBookings) { + + if (request.getConfirmationNo() != null) limoBookings.setConfirmationNo(request.getConfirmationNo()); + if (request.getBookingStatus() != null) limoBookings.setBookingStatus(request.getBookingStatus()); + if (request.getPlayerId() != null) limoBookings.setPlayerId(request.getPlayerId()); + String player = firstText(request.getPlayer(), request.getPlayerName()); + if (StringUtils.hasText(player)) limoBookings.setPlayer(player); + if (request.getBookingType() != null) limoBookings.setBookingType(request.getBookingType()); + if (request.getTripType() != null) limoBookings.setTripType(request.getTripType()); + if (request.getServiceType() != null) limoBookings.setServiceType(request.getServiceType()); + if (request.getCarType() != null) limoBookings.setCarType(request.getCarType()); + if (request.getCarTypeId() != null) limoBookings.setCarTypeId(request.getCarTypeId()); + else if (request.getCarTypeCode() != null) limoBookings.setCarTypeId(parseLongOrDefault(request.getCarTypeCode(), limoBookings.getCarTypeId())); + if (request.getNoOfPax() != null) limoBookings.setNoOfPax(request.getNoOfPax()); + if (request.getPickUpPoint() != null) limoBookings.setPickUpPoint(request.getPickUpPoint()); + if (request.getPickupPointId() != null) limoBookings.setPickUpPointId(request.getPickupPointId()); + else if (request.getPickUpPointCode() != null) limoBookings.setPickUpPointId(request.getPickUpPointCode()); + if (request.getOtherPickUpPoint() != null) limoBookings.setOtherPickUpPoint(request.getOtherPickUpPoint()); + if (request.getDropOffPoint() != null) limoBookings.setDropOffPoint(request.getDropOffPoint()); + if (request.getDropOffPointIds() != null) limoBookings.setDropOffPointIds(request.getDropOffPointIds()); + else if (request.getDropOffPointCode() != null) limoBookings.setDropOffPointIds(request.getDropOffPointCode()); + else if (!CollectionUtils.isEmpty(request.getDropOffPoints())) { + limoBookings.setDropOffPointIds(resolveDropOffPointIds(request, limoBookings, sortedDropOffPoints(request))); + } + if (request.getExtraDropOffPointId() != null) limoBookings.setExtraDropOffId(request.getExtraDropOffPointId()); + if (request.getExtraDropOffPoint() != null) limoBookings.setExtraDropOffPoint(request.getExtraDropOffPoint()); + if (request.getOtherDropOffPoint() != null) limoBookings.setOtherDropOffPoint(request.getOtherDropOffPoint()); + if (request.getGreetType() != null) limoBookings.setGreetType(request.getGreetType()); + if (request.getGreetTypeId() != null) limoBookings.setGreetTypeId(request.getGreetTypeId()); + if (request.getSignage() != null) limoBookings.setSignage(request.getSignage()); + if (request.getApproverId() != null) limoBookings.setApproverId(request.getApproverId()); + if (request.getApprover() != null) limoBookings.setApprover(request.getApprover()); + if (request.getPaymentMethod() != null) limoBookings.setPaymentMethod(request.getPaymentMethod()); + if (request.getIsHourlyRate() != null) limoBookings.setIsHourlyRate(request.getIsHourlyRate()); + if (request.getHourlyRate() != null) limoBookings.setHourlyRate(request.getHourlyRate()); + if (request.getTripPrice() != null) limoBookings.setTripPrice(request.getTripPrice()); + if (request.getTotalAmount() != null) limoBookings.setTotalAmount(request.getTotalAmount()); + if (request.getTripContact() != null) limoBookings.setTripContact(request.getTripContact()); + if (request.getRemarks() != null) limoBookings.setRemarks(request.getRemarks()); + if (request.getFlightDetail() != null) limoBookings.setFlightDetail(request.getFlightDetail()); + if (request.getFlightEta() != null) limoBookings.setFlightEta(request.getFlightEta()); + if (request.getFlightStatus() != null) limoBookings.setFlightStatus(request.getFlightStatus()); + if (request.getCreatedBy() != null) limoBookings.setCreatedBy(request.getCreatedBy()); + String overrideBy = firstText(request.getOverriderName(), request.getOverrideBy()); + if (StringUtils.hasText(overrideBy)) limoBookings.setOverrideBy(overrideBy); + if (request.getBookerId() != null) limoBookings.setBookerId(request.getBookerId()); + else if (request.getEmployeeId() != null) limoBookings.setBookerId(request.getEmployeeId()); + + Date pickUpDatetime = parsePickUpDatetime(request); + if (pickUpDatetime != null) limoBookings.setPickUpDatetime(pickUpDatetime); + } + + /** + * 解析 Limo 网关返回的 JSON:外层有业务码 {@code result},列表数据在 {@code itemObject} 里(多为 JSON 数组字符串)。 + * + * @param httpResponseResult 已执行完的 HTTP 调用结果 + * @param itemClass itemObject 数组中每条记录要反序列化成的类型(如 {@link LimoTripPriceItem}) + * @return 统一 {@link BaseApiResponse}:成功时 {@code data} 为列表;失败时带错误码与文案 + */ + private BaseApiResponse> parseLimoItemObjectList(HttpResponseResult httpResponseResult, Class itemClass) + throws Exception { + // 1) 传输层:非 200 说明网络/网关层异常,直接 500 + if (httpResponseResult.getStatusCode() != 200) { + return BaseApiResponse.internalServerError( + "Limo HTTP error: " + httpResponseResult.getStatusCode()); + } + + String body = httpResponseResult.getResponseContent(); + // 2) 响应体不能为空,否则无法解析 + if (!StringUtils.hasText(body)) { + return BaseApiResponse.internalServerError("Limo empty response body"); + } + + JSONObject root = JSONObject.parseObject(body); + if (root == null) { + return BaseApiResponse.internalServerError("Limo invalid JSON response"); + } + + // 3) 业务层:Limo 约定 result 为 "200"(字符串)表示成功;否则读 error 作说明 + String result = root.getString("result"); + if (!Strings.CI.equals("200", result)) { + String err = root.getString("error"); + return BaseApiResponse.error(result, StringUtils.hasText(err) ? err : "Limo API returned error"); + } + + // 4) 列表在 itemObject:可能是 JSON 数组,也可能是 JSON 数组字符串 + JSONArray itemArray = root.getJSONArray("itemObject"); + if (itemArray != null) { + return BaseApiResponse.ok(itemArray.toJavaList(itemClass)); + } + + String itemObject = root.getString("itemObject"); + if (!StringUtils.hasText(itemObject)) { + return BaseApiResponse.ok(Collections.emptyList()); + } + + // 5) 按具体 DTO 类型解析每一条,封装进通用 BaseApiResponse + List list = JSONArray.parseArray(itemObject, itemClass); + return BaseApiResponse.ok(list); + } + + public static String extractBookingId(String confirmationNo) { + if (org.apache.commons.lang3.StringUtils.isBlank(confirmationNo)) { + return null; + } + + String value = confirmationNo.trim(); + int suffixIndex = org.apache.commons.lang3.StringUtils.indexOfIgnoreCase(value, "-S"); + String bookingPart = suffixIndex >= 0 ? value.substring(0, suffixIndex) : value; + + int firstDigitIndex = 0; + while (firstDigitIndex < bookingPart.length() + && !Character.isDigit(bookingPart.charAt(firstDigitIndex))) { + firstDigitIndex++; + } + if (firstDigitIndex == bookingPart.length()) { + return null; + } + + String bookingId = bookingPart.substring(firstDigitIndex); + return bookingId.chars().allMatch(Character::isDigit) ? bookingId : null; + } + +} diff --git a/src/main/java/com/mgm/mcrm/notification/controllers/NotificationController.java b/src/main/java/com/mgm/mcrm/notification/controllers/NotificationController.java index b47350f..822ba6d 100644 --- a/src/main/java/com/mgm/mcrm/notification/controllers/NotificationController.java +++ b/src/main/java/com/mgm/mcrm/notification/controllers/NotificationController.java @@ -22,6 +22,7 @@ import jakarta.servlet.http.HttpServletRequest; import jakarta.validation.Valid; import org.apache.commons.lang3.StringUtils; import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @@ -77,6 +78,14 @@ public class NotificationController { return notificationService.changeStatus(id); } + @RequestMapping(value = "/read_all", method = RequestMethod.POST, produces = "application/json;charset=UTF-8",consumes = MediaType.APPLICATION_JSON_VALUE) + public BaseApiResponse readAll(HttpServletRequest request) { + String token = request.getHeader("Authorization"); + String userId = JWT.decode(token).getClaim("login_id").asString(); + return notificationService.readAllNotifications(userId); + } + + @OperationLog(actionName = "Send Notification", eventCode = "send_notification") @Operation( summary = "Send Notification", diff --git a/src/main/java/com/mgm/mcrm/notification/repositories/SysLogNotificationRepository.java b/src/main/java/com/mgm/mcrm/notification/repositories/SysLogNotificationRepository.java index c8877fb..7828987 100644 --- a/src/main/java/com/mgm/mcrm/notification/repositories/SysLogNotificationRepository.java +++ b/src/main/java/com/mgm/mcrm/notification/repositories/SysLogNotificationRepository.java @@ -2,7 +2,12 @@ package com.mgm.mcrm.notification.repositories; import com.mgm.mcrm.notification.models.SysLogNotification; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import org.springframework.transaction.annotation.Transactional; +import java.time.LocalDateTime; import java.util.List; public interface SysLogNotificationRepository extends JpaRepository { @@ -11,4 +16,9 @@ public interface SysLogNotificationRepository extends JpaRepository findAllByDeviceTokenAndTransactionId(String deviceToken, String transactionId); long countByUserIdAndStatus(String userId, Integer status); + + @Transactional + @Modifying + @Query("UPDATE SysLogNotification n SET n.status = 1, n.updatedAt = :now WHERE n.userId = :userId AND n.status = 0") + int markAllAsReadByUserId(@Param("userId") String userId, @Param("now") LocalDateTime now); } diff --git a/src/main/java/com/mgm/mcrm/notification/services/NotificationService.java b/src/main/java/com/mgm/mcrm/notification/services/NotificationService.java index 31ea395..0b71aac 100644 --- a/src/main/java/com/mgm/mcrm/notification/services/NotificationService.java +++ b/src/main/java/com/mgm/mcrm/notification/services/NotificationService.java @@ -115,4 +115,13 @@ public class NotificationService { return response; } + public BaseApiResponse readAllNotifications(String userId) { + BaseApiResponse response = new BaseApiResponse<>(); + int updated = sysLogNotificationRepository.markAllAsReadByUserId(userId, LocalDateTime.now()); + response.setSuccess(true); + response.setCode("200"); + response.setData(updated); + return response; + } + } diff --git a/src/main/java/com/mgm/mcrm/player/services/TodoService.java b/src/main/java/com/mgm/mcrm/player/services/TodoService.java index 80b532c..8b63683 100644 --- a/src/main/java/com/mgm/mcrm/player/services/TodoService.java +++ b/src/main/java/com/mgm/mcrm/player/services/TodoService.java @@ -183,9 +183,11 @@ public class TodoService { if (StringUtils.isNotBlank(confNum)) { if ("Inhouse".equalsIgnoreCase(todoCategory) || "Arrival".equalsIgnoreCase(todoCategory)) { - List daylightProperties = propertyDao.findByCategory("DAYLIGHT"); - if (CollectionUtils.isNotEmpty(daylightProperties)) { - CfgProperties property = daylightProperties.get(0); + Bookings bookings = bookingDao.findFirstByConfirmationNoAndPropertyIdIsNotNull(confNum); + + CfgProperties property = propertyDao.findById(bookings.getPropertyId()).orElse(null); + + if (Objects.nonNull(property)) { if ("Inhouse".equalsIgnoreCase(todoCategory)) { // Parse checkinDate from recordDesc (e.g., "Jun 25 – Jul 1 ...") @@ -504,81 +506,81 @@ public class TodoService { List dateList = new ArrayList<>(dateMap.values()); // TODO daylight专用,后面要改 by Mauve - if (1 == 1) { - for (TodoDateListRecord todoDateListRecord : dateList) { - List dateRecords = todoDateListRecord.getDateRecords(); + for (TodoDateListRecord todoDateListRecord : dateList) { - for (TodoListRecord record : dateRecords) { - List descriptions = record.getDescriptions(); - if (CollectionUtils.isEmpty(descriptions)) { - continue; - } + List dateRecords = todoDateListRecord.getDateRecords(); - try { - for (String description : descriptions) { - if (StringUtils.isBlank(description)) { - continue; - } + for (TodoListRecord record : dateRecords) { + List descriptions = record.getDescriptions(); + if (CollectionUtils.isEmpty(descriptions)) { + continue; + } - int confIndex = description.indexOf("Conf#"); - if (confIndex == -1) { - continue; - } + try { + for (String description : descriptions) { + if (StringUtils.isBlank(description)) { + continue; + } - String confPart = description.substring(confIndex + 5); - int pipeIndex = confPart.indexOf("|"); - String confNum = (pipeIndex == -1 ? confPart : confPart.substring(0, pipeIndex)).trim(); + int confIndex = description.indexOf("Conf#"); + if (confIndex == -1) { + continue; + } - if (StringUtils.isNotBlank(confNum)) { - if ("Inhouse".equalsIgnoreCase(category) || "Arrival".equalsIgnoreCase(category)) { - List daylightProperties = propertyDao.findByCategory("DAYLIGHT"); - if (CollectionUtils.isNotEmpty(daylightProperties)) { - CfgProperties property = daylightProperties.get(0); - if ("Inhouse".equalsIgnoreCase(category)) { - BaseApiResponse doorKeyResult = - dlService.getReservationDoorKeyByConfirmationNumber(property.getDlPropertyId(), confNum); - ReservationDoorKeyResponse doorKeyData = doorKeyResult.getData(); - boolean isRoomReady = doorKeyResult.isSuccess() - && doorKeyData != null - && StringUtils.isNotBlank(doorKeyData.getId()) - && !doorKeyData.isHasKey(); - if (isRoomReady) { - record.setRoomReady(true); - updateTodoRecordDescription(record, confNum, "[Rm Ready]"); - } - } else { - BaseApiResponse queueResult = - dlService.getReservationQueueByConfirmationNumber(property.getDlPropertyId(), confNum); - ReservationQueueResponse queueData = queueResult.getData(); - boolean isQueue = queueResult.isSuccess() - && queueData != null - && queueData.isQueue(); - if (isQueue) { - record.setIsQueue(true); - updateTodoRecordDescription(record, confNum, "[In Queue]"); - } + String confPart = description.substring(confIndex + 5); + int pipeIndex = confPart.indexOf("|"); + String confNum = (pipeIndex == -1 ? confPart : confPart.substring(0, pipeIndex)).trim(); + + if (StringUtils.isNotBlank(confNum)) { + if ("Inhouse".equalsIgnoreCase(category) || "Arrival".equalsIgnoreCase(category)) { + List daylightProperties = propertyDao.findByCategory("DAYLIGHT"); + if (CollectionUtils.isNotEmpty(daylightProperties)) { + CfgProperties property = daylightProperties.get(0); + if ("Inhouse".equalsIgnoreCase(category)) { + BaseApiResponse doorKeyResult = + dlService.getReservationDoorKeyByConfirmationNumber(property.getDlPropertyId(), confNum); + ReservationDoorKeyResponse doorKeyData = doorKeyResult.getData(); + boolean isRoomReady = doorKeyResult.isSuccess() + && doorKeyData != null + && StringUtils.isNotBlank(doorKeyData.getId()) + && !doorKeyData.isHasKey(); + if (isRoomReady) { + record.setRoomReady(true); + updateTodoRecordDescription(record, confNum, "[Rm Ready]"); + } + } else { + BaseApiResponse queueResult = + dlService.getReservationQueueByConfirmationNumber(property.getDlPropertyId(), confNum); + ReservationQueueResponse queueData = queueResult.getData(); + boolean isQueue = queueResult.isSuccess() + && queueData != null + && queueData.isQueue(); + if (isQueue) { + record.setIsQueue(true); + updateTodoRecordDescription(record, confNum, "[In Queue]"); } } } } + } - List bookingByConfirmationNo = bookingService.getBookingByDaylightConf(confNum); + List bookingByConfirmationNo = bookingService.getBookingByDaylightConf(confNum); - for (BookingsView bookingsView : bookingByConfirmationNo) { - if (StringUtils.isNotBlank(bookingsView.getEta())) { - String[] split2 = bookingsView.getEta().split(":"); - record.setETA(split2[0] + ":" + split2[1]); - } + for (BookingsView bookingsView : bookingByConfirmationNo) { + if (StringUtils.isNotBlank(bookingsView.getEta())) { + String[] split2 = bookingsView.getEta().split(":"); + record.setETA(split2[0] + ":" + split2[1]); } } - } catch (Exception e) { - log.warn("Failed to process todo descriptions={}", descriptions, e); } + } catch (Exception e) { + log.warn("Failed to process todo descriptions={}", descriptions, e); } } - dateResult.setRecords(dateList); } + dateResult.setRecords(dateList); + result.setSuccess(true); result.setData(dateResult); diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml index 529920b..3156df8 100644 --- a/src/main/resources/application-dev.yml +++ b/src/main/resources/application-dev.yml @@ -167,3 +167,15 @@ calendar: # Temporary team testing defaults. Disable both before formal delivery. permission-mock-enabled: true data-mock-enabled: true + +#==================APP Config=================== +limo_address: http://mmlimodevapp01/MCRMAPI/API/MainHandler.ashx +limo_getAccessToken_Id: test100 +limo_getAccessToken_pwd: 1234567 + +notification: + recent-hours: 6 + +limo: + booking-draft: + expiry-seconds: 120 \ No newline at end of file diff --git a/src/main/resources/mockup/http/get_user_info_api_res4.json b/src/main/resources/mockup/http/get_user_info_api_res4.json index 260de8e..d4e2a1a 100644 --- a/src/main/resources/mockup/http/get_user_info_api_res4.json +++ b/src/main/resources/mockup/http/get_user_info_api_res4.json @@ -10,7 +10,8 @@ "Department": "Global Marketing", "Section": "Global Marketing", "Block": "CM", - "Phone": "85366988316" + "Phone": "85366988316", + "PaymentMethod": "CM Comp,Point Deduction" } ] } \ No newline at end of file diff --git a/src/main/resources/mockup/limo/cancel_booking_1.json b/src/main/resources/mockup/limo/cancel_booking_1.json new file mode 100644 index 0000000..9b72a85 --- /dev/null +++ b/src/main/resources/mockup/limo/cancel_booking_1.json @@ -0,0 +1,4 @@ +{ + "result": "200", + "error": "" +} diff --git a/src/main/resources/mockup/limo/cancel_booking_2.json b/src/main/resources/mockup/limo/cancel_booking_2.json new file mode 100644 index 0000000..f582d50 --- /dev/null +++ b/src/main/resources/mockup/limo/cancel_booking_2.json @@ -0,0 +1,4 @@ +{ + "result": "500", + "error": "Mock: cancel booking failed for test booking" +} diff --git a/src/main/resources/mockup/limo/check_simple_limo_booking_qualification_status_1.json b/src/main/resources/mockup/limo/check_simple_limo_booking_qualification_status_1.json new file mode 100644 index 0000000..06dd6a3 --- /dev/null +++ b/src/main/resources/mockup/limo/check_simple_limo_booking_qualification_status_1.json @@ -0,0 +1,8 @@ +{ + "StatusCode": "OK", + "StatusDescription": "Success", + "PlayerId": 12345678, + "BookingType": "Hong Kong Limo", + "BookingDate": "2026-02-15 23:00:00", + "QualificationFlag": 0 +} \ No newline at end of file diff --git a/src/main/resources/mockup/limo/check_simple_limo_booking_qualification_status_2.json b/src/main/resources/mockup/limo/check_simple_limo_booking_qualification_status_2.json new file mode 100644 index 0000000..01b27b2 --- /dev/null +++ b/src/main/resources/mockup/limo/check_simple_limo_booking_qualification_status_2.json @@ -0,0 +1,8 @@ +{ + "StatusCode": "OK", + "StatusDescription": "Success", + "PlayerId": 12345678, + "BookingType": "Hong Kong Limo", + "BookingDate": "2026-02-15 23:00:00", + "QualificationFlag": 1 +} \ No newline at end of file diff --git a/src/main/resources/mockup/limo/create_booking_1.json b/src/main/resources/mockup/limo/create_booking_1.json new file mode 100644 index 0000000..d61ff3d --- /dev/null +++ b/src/main/resources/mockup/limo/create_booking_1.json @@ -0,0 +1 @@ +{"itemObject":"[{\"BookingNo\":\"L202606080007-S00\",\"BookingID\":\"ForCorsoTest\"}]","result":"200","error":""} \ No newline at end of file diff --git a/src/main/resources/mockup/limo/create_booking_2.json b/src/main/resources/mockup/limo/create_booking_2.json new file mode 100644 index 0000000..fc1fdf2 --- /dev/null +++ b/src/main/resources/mockup/limo/create_booking_2.json @@ -0,0 +1,4 @@ +{ + "result": "500", + "error": "Mock: create booking failed for test player" +} diff --git a/src/main/resources/mockup/limo/get_booking_list.json b/src/main/resources/mockup/limo/get_booking_list.json new file mode 100644 index 0000000..f600ecb --- /dev/null +++ b/src/main/resources/mockup/limo/get_booking_list.json @@ -0,0 +1,5 @@ +{ + "result": "200", + "error": "", + "itemObject": "" +} diff --git a/src/main/resources/mockup/limo/get_car_type_list.json b/src/main/resources/mockup/limo/get_car_type_list.json new file mode 100644 index 0000000..13a2d52 --- /dev/null +++ b/src/main/resources/mockup/limo/get_car_type_list.json @@ -0,0 +1,5 @@ +{ + "result": "200", + "error": "", + "itemObject": "[{\"ID\":0,\"CarType\":\"Any\",\"EnglishName\":\"Any\",\"ChineseSimpName\":\"????\",\"ChineseTradName\":\"????\",\"BookingType\":\"Local,HK,China\"},{\"ID\":2,\"CarType\":\"Lexus LM350\",\"EnglishName\":\"Lexus LM350\",\"ChineseSimpName\":\"\",\"ChineseTradName\":\"LM350\",\"BookingType\":\"Local,HK,China\"},{\"ID\":3,\"CarType\":\"ALPHARD 40\",\"EnglishName\":\"ALPHARD 40\",\"ChineseSimpName\":\"\",\"ChineseTradName\":\"ALPHARD 40\",\"BookingType\":\"Local,HK,China\"},{\"ID\":4,\"CarType\":\"DENZA D9\",\"EnglishName\":\"DENZA D9\",\"ChineseSimpName\":\"\",\"ChineseTradName\":\"DENZA D9\",\"BookingType\":\"Local,HK,China\"},{\"ID\":5,\"CarType\":\"MAYBACH\",\"EnglishName\":\"MAYBACH\",\"ChineseSimpName\":\"\",\"ChineseTradName\":\"MAYBACH\",\"BookingType\":\"Local,HK,China\"},{\"ID\":6,\"CarType\":\"VELLFIRE 30\",\"EnglishName\":\"VELLFIRE 30\",\"ChineseSimpName\":\"\",\"ChineseTradName\":\"VELLFIRE 30\",\"BookingType\":\"Local,HK,China\"},{\"ID\":7,\"CarType\":\"ALPHARD 30\",\"EnglishName\":\"ALPHARD 30\",\"ChineseSimpName\":\"\",\"ChineseTradName\":\"ALPHARD 30\",\"BookingType\":\"Local,HK,China\"},{\"ID\":8,\"CarType\":\"Alphard 7-seat\",\"EnglishName\":\"Toyota Alphard 7 seat\",\"ChineseSimpName\":\"Toyota Alphard 7 seat\",\"ChineseTradName\":\"Toyota Alphard 7 seat\",\"BookingType\":\"Local,HK,China\"},{\"ID\":9,\"CarType\":\"Rolls\",\"EnglishName\":\"Rolls Royce\",\"ChineseSimpName\":\"Rolls Royce\",\"ChineseTradName\":\"Rolls Royce\",\"BookingType\":\"Local\"},{\"ID\":10,\"CarType\":\"Maybach 4-seat\",\"EnglishName\":\"Mercedes Maybach 4 seat\",\"ChineseSimpName\":\"Mercedes Maybach 4 seat\",\"ChineseTradName\":\"Mercedes Maybach 4 seat\",\"BookingType\":\"Local\"},{\"ID\":11,\"CarType\":\"Bus 16-seat\",\"EnglishName\":\"Bus 16-seat\",\"ChineseSimpName\":\"Bus 16-seat\",\"ChineseTradName\":\"Bus 16-seat\",\"BookingType\":\"Bus\"},{\"ID\":12,\"CarType\":\"Bus 28-seat\",\"EnglishName\":\"Bus 28-seat\",\"ChineseSimpName\":\"Bus 28-seat\",\"ChineseTradName\":\"Bus 28-seat\",\"BookingType\":\"Bus\"},{\"ID\":13,\"CarType\":\"Bus 50-seat\",\"EnglishName\":\"Bus 50-seat\",\"ChineseSimpName\":\"Bus 50-seat\",\"ChineseTradName\":\"Bus 50-seat\",\"BookingType\":\"Bus\"}]" +} diff --git a/src/main/resources/mockup/limo/get_employee_info.json b/src/main/resources/mockup/limo/get_employee_info.json new file mode 100644 index 0000000..bd22d21 --- /dev/null +++ b/src/main/resources/mockup/limo/get_employee_info.json @@ -0,0 +1,10 @@ +{ + "StatusCode": "OK", + "StatusDescription": "Success", + "EmployeeId": 123456, + "LastName": "Chen", + "ChineseLastName": "陳", + "Salutation": "Mr.", + "Phone": "123456789", + "PaymentMethod": "CM Comp" +} \ No newline at end of file diff --git a/src/main/resources/mockup/limo/get_flight_details.json b/src/main/resources/mockup/limo/get_flight_details.json new file mode 100644 index 0000000..1fd9d31 --- /dev/null +++ b/src/main/resources/mockup/limo/get_flight_details.json @@ -0,0 +1,5 @@ +{ + "result": "200", + "error": "", + "itemObject": "[{\"FlightNo\":\"NX331 \",\"PickUpAirportCode\":\"MFM\",\"DropOffAirportCode\":\"\",\"PickupDatetime\":\"2026-04-23 16:00:00\",\"ETA\":\"2026-04-23 17:22:00\",\"FlightStatus\":\"departure\"}]" +} diff --git a/src/main/resources/mockup/limo/get_greet_type_list.json b/src/main/resources/mockup/limo/get_greet_type_list.json new file mode 100644 index 0000000..66be360 --- /dev/null +++ b/src/main/resources/mockup/limo/get_greet_type_list.json @@ -0,0 +1,5 @@ +{ + "result": "200", + "error": "", + "itemObject": "[{\"ID\":1,\"BookingType\":\"Local\",\"GreetType\":\"Limo Greet\",\"LimoGreet\":1,\"HostGreet\":0,\"VIPMeetNGreet\":0},{\"ID\":3,\"BookingType\":\"Local\",\"GreetType\":\"Host Greet Macau\",\"LimoGreet\":0,\"HostGreet\":0,\"VIPMeetNGreet\":0},{\"ID\":4,\"BookingType\":\"Local\",\"GreetType\":\"Host Greet Cotai\",\"LimoGreet\":0,\"HostGreet\":0,\"VIPMeetNGreet\":0},{\"ID\":5,\"BookingType\":\"Local\",\"GreetType\":\"Other\",\"LimoGreet\":0,\"HostGreet\":0,\"VIPMeetNGreet\":0},{\"ID\":6,\"BookingType\":\"Local\",\"GreetType\":\"PPL Macau Airport MnG\",\"LimoGreet\":0,\"HostGreet\":0,\"VIPMeetNGreet\":1},{\"ID\":7,\"BookingType\":\"HK\",\"GreetType\":\"Limo Greet\",\"LimoGreet\":1,\"HostGreet\":0,\"VIPMeetNGreet\":0},{\"ID\":8,\"BookingType\":\"HK\",\"GreetType\":\"Host Greet\",\"LimoGreet\":0,\"HostGreet\":1,\"VIPMeetNGreet\":0},{\"ID\":9,\"BookingType\":\"HK\",\"GreetType\":\"PPL HK Airport MnG\",\"LimoGreet\":0,\"HostGreet\":0,\"VIPMeetNGreet\":1},{\"ID\":10,\"BookingType\":\"HK\",\"GreetType\":\"Shun Tak Greet\",\"LimoGreet\":0,\"HostGreet\":0,\"VIPMeetNGreet\":0},{\"ID\":11,\"BookingType\":\"HK\",\"GreetType\":\"Turbojet Meet and Greet\",\"LimoGreet\":0,\"HostGreet\":0,\"VIPMeetNGreet\":0},{\"ID\":12,\"BookingType\":\"China\",\"GreetType\":\"Shenzhen AP VIP Meet and Greet\",\"LimoGreet\":0,\"HostGreet\":0,\"VIPMeetNGreet\":1},{\"ID\":13,\"BookingType\":\"China\",\"GreetType\":\"Zhuhai AP VIP Meet and Greet\",\"LimoGreet\":0,\"HostGreet\":0,\"VIPMeetNGreet\":1},{\"ID\":14,\"BookingType\":\"Local\",\"GreetType\":\"Butler Greet\",\"LimoGreet\":0,\"HostGreet\":0,\"VIPMeetNGreet\":0}]" +} diff --git a/src/main/resources/mockup/limo/get_location_1.json b/src/main/resources/mockup/limo/get_location_1.json new file mode 100644 index 0000000..01788ea --- /dev/null +++ b/src/main/resources/mockup/limo/get_location_1.json @@ -0,0 +1,5 @@ +{ + "result": "200", + "error": "", + "itemObject": "[{\"ID\":0,\"EnglishName\":\"---\",\"ChineseTradName\":\"---\",\"ChineseSimpName\":\"---\",\"AirportCode\":\"\",\"Region\":\"---\",\"Area\":\"\",\"TripPriceID\":0,\"FreeOfCharge\":0,\"GreetLocation\":0},{\"ID\":1,\"EnglishName\":\"Altira Casino\",\"ChineseTradName\":\"新濠鋒娛樂場\",\"ChineseSimpName\":\"新濠锋娱乐场\",\"AirportCode\":\"1\",\"Region\":\"Local\",\"Area\":\"Cotai Urban Area\",\"TripPriceID\":6,\"FreeOfCharge\":0,\"GreetLocation\":0},{\"ID\":2,\"EnglishName\":\"Altira Hotel Restaurant\",\"ChineseTradName\":\"新濠鋒酒店餐廳\",\"ChineseSimpName\":\"新濠锋酒店餐厅\",\"AirportCode\":\"\",\"Region\":\"Local\",\"Area\":\"Cotai Urban Area\",\"TripPriceID\":6,\"FreeOfCharge\":0,\"GreetLocation\":0},{\"ID\":3,\"EnglishName\":\"Anglican School in Taipa\",\"ChineseTradName\":\"氹仔聖公會學校\",\"ChineseSimpName\":\"凼仔圣公会学校\",\"AirportCode\":\"\",\"Region\":\"Local\",\"Area\":\"Cotai Urban Area\",\"TripPriceID\":6,\"FreeOfCharge\":0,\"GreetLocation\":0},{\"ID\":4,\"EnglishName\":\"Galaxy Resort - Banyan Tree\",\"ChineseTradName\":\"銀河 - 悅榕莊\",\"ChineseSimpName\":\"银河 - 悦榕庄\",\"AirportCode\":\"\",\"Region\":\"Local\",\"Area\":\"Cotai Urban Area\",\"TripPriceID\":6,\"FreeOfCharge\":0,\"GreetLocation\":0},{\"ID\":5,\"EnglishName\":\"Barcelona Tapas and Rice Spanish Restaurant\",\"ChineseTradName\":\"巴賽隆納餐廳\",\"ChineseSimpName\":\"巴塞罗那餐厅\",\"AirportCode\":\"\",\"Region\":\"Local\",\"Area\":\"Cotai Urban Area\",\"TripPriceID\":6,\"FreeOfCharge\":0,\"GreetLocation\":0},{\"ID\":6,\"EnglishName\":\"Macau International Golf (MIG)\",\"ChineseTradName\":\"澳門國際高爾夫(前凱撒)\",\"ChineseSimpName\":\"澳门国际高尔夫(前凯撒)\",\"AirportCode\":\"\",\"Region\":\"Local\",\"Area\":\"Cotai Urban Area\",\"TripPriceID\":6,\"FreeOfCharge\":0,\"GreetLocation\":0},{\"ID\":7,\"EnglishName\":\"Chan Shing Kee Restaurant\",\"ChineseTradName\":\"路環陳勝記\",\"ChineseSimpName\":\"路环陈胜记\",\"AirportCode\":\"\",\"Region\":\"Local\",\"Area\":\"Cotai Urban Area\",\"TripPriceID\":6,\"FreeOfCharge\":0,\"GreetLocation\":0},{\"ID\":8,\"EnglishName\":\"City of Dreams - Casino Main Entrance\",\"ChineseTradName\":\"新濠天地 - 娛樂場正門\",\"ChineseSimpName\":\"新濠天地 - 娱乐场正门\",\"AirportCode\":\"\",\"Region\":\"Local\",\"Area\":\"Cotai Urban Area\",\"TripPriceID\":6,\"FreeOfCharge\":0,\"GreetLocation\":0},{\"ID\":9,\"EnglishName\":\"The Londoner - Conrad Hotel\",\"ChineseTradName\":\"倫敦人 - 康萊德酒店\",\"ChineseSimpName\":\"伦敦人 - 康莱德酒店\",\"AirportCode\":\"\",\"Region\":\"Local\",\"Area\":\"Cotai Urban Area\",\"TripPriceID\":6,\"FreeOfCharge\":0,\"GreetLocation\":0},{\"ID\":10,\"EnglishName\":\"City of Dream - Nuwa Hotel\",\"ChineseTradName\":\"新濠天地 - 頤居酒店\",\"ChineseSimpName\":\"新濠天地 - 颐居酒店\",\"AirportCode\":\"\",\"Region\":\"Local\",\"Area\":\"Cotai Urban Area\",\"TripPriceID\":6,\"FreeOfCharge\":0,\"GreetLocation\":0},{\"ID\":11,\"EnglishName\":\"Fernando Restaurant\",\"ChineseTradName\":\"黑沙法蘭度餐廳\",\"ChineseSimpName\":\"黑沙法兰度餐厅\",\"AirportCode\":\"\",\"Region\":\"Local\",\"Area\":\"Cotai Urban Area\",\"TripPriceID\":6,\"FreeOfCharge\":0,\"GreetLocation\":0},{\"ID\":12,\"EnglishName\":\"Four Season Hotel - Main Entrance\",\"ChineseTradName\":\"四季酒店 - 正門\",\"ChineseSimpName\":\"四季酒店 - 正门\",\"AirportCode\":\"\",\"Region\":\"Local\",\"Area\":\"Cotai Urban Area\",\"TripPriceID\":6,\"FreeOfCharge\":0,\"GreetLocation\":0},{\"ID\":13,\"EnglishName\":\"Four Season - Shopping Mall\",\"ChineseTradName\":\"四季酒店 - 購物區\",\"ChineseSimpName\":\"四季酒店 - 购物区\",\"AirportCode\":\"\",\"Region\":\"Local\",\"Area\":\"Cotai Urban Area\",\"TripPriceID\":6,\"FreeOfCharge\":0,\"GreetLocation\":0},{\"ID\":14,\"EnglishName\":\"Galaxy Resort - Broadway Casino\",\"ChineseTradName\":\"銀河 - 百老匯娛樂場\",\"ChineseSimpName\":\"银河 - 百老汇娱乐场\",\"AirportCode\":\"\",\"Region\":\"Local\",\"Area\":\"Cotai Urban Area\",\"TripPriceID\":6,\"FreeOfCharge\":0,\"GreetLocation\":0},{\"ID\":15,\"EnglishName\":\"Galaxy Resort - Diamond Entrance\",\"ChineseTradName\":\"銀河 - 酒店正門 (鑽石大堂)\",\"ChineseSimpName\":\"银河 - 酒店正门 (钻石大堂)\",\"AirportCode\":\"\",\"Region\":\"Local\",\"Area\":\"Cotai Urban Area\",\"TripPriceID\":6,\"FreeOfCharge\":0,\"GreetLocation\":0},{\"ID\":16,\"EnglishName\":\"Galaxy Resort - VIP East\",\"ChineseTradName\":\"銀河 - 東翼貴賓會入口(舊金門)\",\"ChineseSimpName\":\"银河 - 东翼贵宾会入口(旧金门)\",\"AirportCode\":\"\",\"Region\":\"Local\",\"Area\":\"Cotai Urban Area\",\"TripPriceID\":6,\"FreeOfCharge\":0,\"GreetLocation\":0},{\"ID\":17,\"EnglishName\":\"Test\",\"ChineseTradName\":\"測試GreetType,Flight,FreeOfCharge\",\"ChineseSimpName\":\"測試GreetType,Flight,FreeOfCharge\",\"AirportCode\":\"1\",\"Region\":\"Local\",\"Area\":\"Cotai Urban Area\",\"TripPriceID\":6,\"FreeOfCharge\":1,\"GreetLocation\":1}]" +} diff --git a/src/main/resources/mockup/limo/get_location_2.json b/src/main/resources/mockup/limo/get_location_2.json new file mode 100644 index 0000000..c51709b --- /dev/null +++ b/src/main/resources/mockup/limo/get_location_2.json @@ -0,0 +1,5 @@ +{ + "result": "200", + "error": "", + "itemObject": "[{\"ID\":2,\"EnglishName\":\"Zhuhai\",\"ChineseTradName\":\"珠海\",\"ChineseSimpName\":\"珠海\",\"AirportCode\":\"\",\"Region\":\"Local\",\"Area\":\"Zhuhai China Area\",\"TripPriceID\":6,\"FreeOfCharge\":1}]" +} diff --git a/src/main/resources/mockup/limo/get_location_empty.json b/src/main/resources/mockup/limo/get_location_empty.json new file mode 100644 index 0000000..f9e0733 --- /dev/null +++ b/src/main/resources/mockup/limo/get_location_empty.json @@ -0,0 +1,5 @@ +{ + "result": "200", + "error": "", + "itemObject": "[]" +} diff --git a/src/main/resources/mockup/limo/get_overrider.json b/src/main/resources/mockup/limo/get_overrider.json new file mode 100644 index 0000000..0f26eaa --- /dev/null +++ b/src/main/resources/mockup/limo/get_overrider.json @@ -0,0 +1,26 @@ +{ + "StatusCode": "OK", + "StatusDescription": "Success", + "Records": [ + { + "EmployeeId": 80001, + "EmployeeName": "Steven Lei", + "EmployeeIdAndName": "Steven Lei(80001)" + }, + { + "EmployeeId": 80002, + "EmployeeName": "Andy Leu", + "EmployeeIdAndName": "Andy Leu(80002)" + }, + { + "EmployeeId": 80003, + "EmployeeName": "Feng Cai", + "EmployeeIdAndName": "Feng Cai(80003)" + }, + { + "EmployeeId": 80004, + "EmployeeName": "Eason Yan", + "EmployeeIdAndName": "Eason Yan(80004)" + } + ] +} \ No newline at end of file diff --git a/src/main/resources/mockup/limo/get_player_info.json b/src/main/resources/mockup/limo/get_player_info.json new file mode 100644 index 0000000..c525934 --- /dev/null +++ b/src/main/resources/mockup/limo/get_player_info.json @@ -0,0 +1,20 @@ +{ + "StatusCode": "OK", + "StatusDescription": "Success", + "PlayerId": 12345678, + "Tier": "APLPHA", + "MaskedTier": "VVIP", + "FirstName": "SEVEN", + "LastName": "Chen", + "ChineseFirstName": "七", + "ChineseLastName": "陳", + "Salutation": "Mr.", + "PrimaryMAID": 103906, + "PrimaryMAName": "Lo Chio Ieong", + "PrimaryMAPhone": "12345678", + "PrimaryMAPaymentMethod": "CM Comp 1,CM Comp 2", + "SecondaryMAID": 137292, + "SecondaryMAName": "Sou Wai Kit", + "SecondaryMAPhone": "87654321", + "SecondaryMAPaymentMethod": "IM Comp 1, IM Comp 2" +} \ No newline at end of file diff --git a/src/main/resources/mockup/limo/get_player_limo_booker.json b/src/main/resources/mockup/limo/get_player_limo_booker.json new file mode 100644 index 0000000..9bb556f --- /dev/null +++ b/src/main/resources/mockup/limo/get_player_limo_booker.json @@ -0,0 +1,12 @@ +{ + "StatusCode": "OK", + "StatusDescription": "Success", + "Records": [ + { + "EmployeeId": 80001, + "EmployeeName": "Corso Wong", + "Phone": "85312345678", + "EmployeeIdAndName": "Corso Wong(80001)" + } + ] +} diff --git a/src/main/resources/mockup/limo/get_total_amount.json b/src/main/resources/mockup/limo/get_total_amount.json new file mode 100644 index 0000000..d891b2a --- /dev/null +++ b/src/main/resources/mockup/limo/get_total_amount.json @@ -0,0 +1,5 @@ +{ + "result": "200", + "error": "", + "itemObject": "[{\"SingleTripPrice\":\"100\",\"ExtraDropoffPrice1\":\"300\",\"ExtraDropoffPrice2\":\"200\",\"ExtraDropoffPrice3\":\"0\",\"ExtraDropoffPrice4\":\"0\",\"ExtraDropoffPrice5\":\"0\",\"ExtraDropoffPrice6\":\"0\",\"ExtraDropoffPrice7\":\"0\",\"ExtraDropoffPrice8\":\"0\",\"ExtraDropoffPrice9\":\"0\",\"ExtraDropoffPrice10\":\"0\",\"TotalAmount\":\"600\"}]" +} diff --git a/src/main/resources/mockup/limo/get_trip_price_list.json b/src/main/resources/mockup/limo/get_trip_price_list.json new file mode 100644 index 0000000..ab0bb2f --- /dev/null +++ b/src/main/resources/mockup/limo/get_trip_price_list.json @@ -0,0 +1,5 @@ +{ + "result": "200", + "error": "", + "itemObject": "[{\"ID\":0,\"TripPrice\":\"NoPrice\",\"DefaultPHTripPrice\":\"150.00\",\"DefaultTripPrice\":\"100.00\",\"HourlyRate\":\"100.00\",\"ExtraDropoff\":\"150.00\",\"HourlyPHRate\":\"0.00\",\"ExtraPHDropoff\":\"0.00\"},{\"ID\":2,\"TripPrice\":\"HK Urban\",\"DefaultPHTripPrice\":\"2500.00\",\"DefaultTripPrice\":\"2500.00\",\"HourlyRate\":\"0.00\",\"ExtraDropoff\":\"1000.00\",\"HourlyPHRate\":\"1000.00\",\"ExtraPHDropoff\":\"0.00\"},{\"ID\":4,\"TripPrice\":\"HK Airport\",\"DefaultPHTripPrice\":\"1800.00\",\"DefaultTripPrice\":\"1800.00\",\"HourlyRate\":\"0.00\",\"ExtraDropoff\":\"1000.00\",\"HourlyPHRate\":\"0.00\",\"ExtraPHDropoff\":\"0.00\"},{\"ID\":6,\"TripPrice\":\"Local\",\"DefaultPHTripPrice\":\"380.00\",\"DefaultTripPrice\":\"280.00\",\"HourlyRate\":\"280.00\",\"ExtraDropoff\":\"100.00\",\"HourlyPHRate\":\"380.00\",\"ExtraPHDropoff\":\"0.00\"},{\"ID\":7,\"TripPrice\":\"Zhuhai Airport\",\"DefaultPHTripPrice\":\"2025.00\",\"DefaultTripPrice\":\"1350.00\",\"HourlyRate\":\"400.00\",\"ExtraDropoff\":\"1350.00\",\"HourlyPHRate\":\"600.00\",\"ExtraPHDropoff\":\"0.00\"},{\"ID\":8,\"TripPrice\":\"Zhuhai City / Hengqin\",\"DefaultPHTripPrice\":\"1050.00\",\"DefaultTripPrice\":\"700.00\",\"HourlyRate\":\"400.00\",\"ExtraDropoff\":\"700.00\",\"HourlyPHRate\":\"600.00\",\"ExtraPHDropoff\":\"0.00\"},{\"ID\":11,\"TripPrice\":\"Shenzhen Airport\",\"DefaultPHTripPrice\":\"3300.00\",\"DefaultTripPrice\":\"2200.00\",\"HourlyRate\":\"400.00\",\"ExtraDropoff\":\"2200.00\",\"HourlyPHRate\":\"600.00\",\"ExtraPHDropoff\":\"0.00\"},{\"ID\":12,\"TripPrice\":\"Shenzhen City\",\"DefaultPHTripPrice\":\"3750.00\",\"DefaultTripPrice\":\"2500.00\",\"HourlyRate\":\"400.00\",\"ExtraDropoff\":\"2500.00\",\"HourlyPHRate\":\"600.00\",\"ExtraPHDropoff\":\"0.00\"},{\"ID\":13,\"TripPrice\":\"Guangzhou Airport\",\"DefaultPHTripPrice\":\"3300.00\",\"DefaultTripPrice\":\"2200.00\",\"HourlyRate\":\"400.00\",\"ExtraDropoff\":\"2200.00\",\"HourlyPHRate\":\"600.00\",\"ExtraPHDropoff\":\"0.00\"},{\"ID\":14,\"TripPrice\":\"Guangzhou City\",\"DefaultPHTripPrice\":\"3450.00\",\"DefaultTripPrice\":\"2300.00\",\"HourlyRate\":\"400.00\",\"ExtraDropoff\":\"2300.00\",\"HourlyPHRate\":\"600.00\",\"ExtraPHDropoff\":\"0.00\"},{\"ID\":15,\"TripPrice\":\"Zhongshan \",\"DefaultPHTripPrice\":\"1950.00\",\"DefaultTripPrice\":\"1300.00\",\"HourlyRate\":\"400.00\",\"ExtraDropoff\":\"1300.00\",\"HourlyPHRate\":\"600.00\",\"ExtraPHDropoff\":\"0.00\"}]" +} diff --git a/src/main/resources/mockup/limo/update_booking_1.json b/src/main/resources/mockup/limo/update_booking_1.json new file mode 100644 index 0000000..9b72a85 --- /dev/null +++ b/src/main/resources/mockup/limo/update_booking_1.json @@ -0,0 +1,4 @@ +{ + "result": "200", + "error": "" +} diff --git a/src/main/resources/mockup/limo/update_booking_2.json b/src/main/resources/mockup/limo/update_booking_2.json new file mode 100644 index 0000000..3125220 --- /dev/null +++ b/src/main/resources/mockup/limo/update_booking_2.json @@ -0,0 +1,4 @@ +{ + "result": "500", + "error": "Mock: update booking failed for test player" +} diff --git a/src/main/resources/mockup/mgm_api_mockup_def.json b/src/main/resources/mockup/mgm_api_mockup_def.json index 5e7175b..0cb55ec 100644 --- a/src/main/resources/mockup/mgm_api_mockup_def.json +++ b/src/main/resources/mockup/mgm_api_mockup_def.json @@ -112,16 +112,8 @@ "fileIndex": 27 }, { - "condiction": "playerId==1212121", + "condiction": "playerId==666666", "fileIndex": 28 - }, - { - "condiction": "playerId==12357817", - "fileIndex": 29 - }, - { - "condiction": "playerId==11335577", - "fileIndex": 30 } ], "resultFiles": [ @@ -153,9 +145,7 @@ "/mockup/http/get_player_profile_api_res26.json", "/mockup/http/get_player_profile_api_res27.json", "/mockup/http/get_player_profile_api_res28.json", - "/mockup/http/get_player_profile_api_res29.json", - "/mockup/http/get_player_profile_api_res30.json", - "/mockup/http/get_player_profile_api_res31.json" + "/mockup/http/get_player_profile_api_res29.json" ] }, { @@ -248,7 +238,7 @@ "resultIndex": 0, "mockupRules": [ { - "condiction": "playerId==11010001 || playerId==11010005 || playerId==11010008 || playerId==11010009 || playerId==22020001 || playerId==22020005 || playerId==22020008 || playerId==22020009 || playerId==33030001 || playerId==33030005 || playerId==33030008 || playerId==33030009 || playerId==1212121", + "condiction": "playerId==11010001 || playerId==11010005 || playerId==11010008 || playerId==11010009 || playerId==22020001 || playerId==22020005 || playerId==22020008 || playerId==22020009 || playerId==33030001 || playerId==33030005 || playerId==33030008 || playerId==33030009 || playerId==666666", "fileIndex": 0 }, { @@ -310,22 +300,22 @@ }, { "apiLink": "GetTodolistDetails", - "resultIndex": 0, - "mockupRules": [ + "resultIndex":0, + "mockupRules":[ { - "condiction": "PlayerId==11010001", - "fileIndex": 0 + "condiction":"PlayerId==11010001", + "fileIndex":0 }, { - "condiction": "PlayerId==11010002", - "fileIndex": 1 + "condiction":"PlayerId==11010002", + "fileIndex":1 }, { - "condiction": "PlayerId==11010003", - "fileIndex": 2 + "condiction":"PlayerId==11010003", + "fileIndex":2 } ], - "resultFiles": [ + "resultFiles":[ "/mockup/app/getTodoDetail_1.json", "/mockup/app/getTodoDetail_2.json", "/mockup/app/getTodoDetail_3.json" @@ -337,7 +327,7 @@ "mockupRules": [ { "condiction": "TodoCategory == Arrival && TodoSegment == MASS", - "fileIndex": 8 + "fileIndex": 0 }, { "condiction": "TodoCategory == Others", @@ -372,8 +362,7 @@ "/mockup/app/getTodoList_5.json", "/mockup/app/getTodoList_6.json", "/mockup/app/getTodoList_7.json", - "/mockup/app/getTodoList_8.json", - "/mockup/app/getTodoList_9.json" + "/mockup/app/getTodoList_8.json" ] }, { diff --git a/target/crm_mobile_runtime/appconfig.properties b/target/crm_mobile_runtime/appconfig.properties new file mode 100644 index 0000000..51acda8 --- /dev/null +++ b/target/crm_mobile_runtime/appconfig.properties @@ -0,0 +1,16 @@ +#ESB Setting +esb_app_id=mgmtestuser001 +esb_app_secret=MGM@!666 +esb_server=https://mmesbdevapp14/api/crmapp/v1.0 +esb_request_timeout=30000 + +#OWS Setting +ows_server=https://mgpmsdevows45 +ows_request_timeout=30000 + +#SMTP setting +mail_port=25 +mail_smtp_host=smtp.aliyun.com +mail_sender=linp168@aliyun.com +mail_sender_password=linpeng060504 +mail_send_to=1441170195@qq.com;feng.cai@willtechmacau.com \ No newline at end of file diff --git a/target/crm_mobile_runtime/excel_define/import/import_other_booking.json b/target/crm_mobile_runtime/excel_define/import/import_other_booking.json new file mode 100644 index 0000000..c8805e6 --- /dev/null +++ b/target/crm_mobile_runtime/excel_define/import/import_other_booking.json @@ -0,0 +1,197 @@ +{ + "importName": "IMPORT_OTHER_BOOKING", + "importPages": [{ + "sheetIndx": 0, + "dataElements": [{ + "offsetRow": 1, + "offsetCol": 0, + "objClassName": "com.mgm.mcrm.common.dtos.data_import.booking.OtherBookingImportRow", + "columnDefs": [ + { + "columnHeader":"#", + "checkHeader":false, + "headerRowIdx":0 + }, + { + "columnHeader":"Staff Action", + "checkHeader":true, + "headerRowIdx":0, + "attrName": "otherFollowUpStatusName", + "dataType": "String" + }, + { + "columnHeader":"Room Status", + "checkHeader":true, + "headerRowIdx":0, + "attrName": "otherRoomStatusName", + "dataType": "String" + }, + { + "columnHeader":"Property", + "checkHeader":true, + "headerRowIdx":0, + "attrName": "propertyName", + "dataType": "String" + }, + { + "columnHeader":"Confirmation No.", + "checkHeader":true, + "headerRowIdx":0, + "attrName": "confirmationNo", + "dataType": "String" + }, + { + "columnHeader":"Room Type", + "checkHeader":true, + "headerRowIdx":0, + "attrName": "roomName", + "dataType": "String" + }, + { + "columnHeader":"Check In Date", + "checkHeader":true, + "headerRowIdx":0, + "attrName": "checkinDate", + "dataType": "String" + }, + { + "columnHeader":"Check Out Date", + "checkHeader":true, + "headerRowIdx":0, + "attrName": "checkoutDate", + "dataType": "String" + }, + { + "columnHeader":"Change Check In Date", + "checkHeader":false, + "headerRowIdx":0 + }, + { + "columnHeader":"Change Check Out Date", + "checkHeader":false, + "headerRowIdx":0 + }, + { + "columnHeader":"Requested C/O Date", + "checkHeader":false, + "headerRowIdx":0 + }, + { + "columnHeader":"Player ID", + "checkHeader":true, + "headerRowIdx":0, + "attrName": "playerId", + "dataType": "String" + }, + { + "columnHeader":"Title", + "checkHeader":false, + "headerRowIdx":0 + }, + { + "columnHeader":"Last Name", + "checkHeader":false, + "headerRowIdx":0 + }, + { + "columnHeader":"First Name", + "checkHeader":false, + "headerRowIdx":0, + "attrName": "playerName", + "dataType": "String" + }, + { + "columnHeader":"Tier", + "checkHeader":false, + "headerRowIdx":0 + }, + { + "columnHeader":"Market Code", + "checkHeader":true, + "headerRowIdx":0, + "attrName": "marketCodeName", + "dataType": "String" + }, + { + "columnHeader":"Source Code", + "checkHeader":true, + "headerRowIdx":0, + "attrName": "sourceCodeName", + "dataType": "String" + }, + { + "columnHeader":"Booker", + "checkHeader":false, + "headerRowIdx":0 + }, + { + "columnHeader":"Booker Id", + "checkHeader":true, + "headerRowIdx":0, + "attrName": "bookerId", + "dataType": "String" + }, + { + "columnHeader":"Sharer", + "checkHeader":true, + "headerRowIdx":0, + "attrName": "sharer", + "dataType": "String" + }, + { + "columnHeader":"Sharer Name", + "checkHeader":false, + "headerRowIdx":0 + }, + { + "columnHeader":"Remark", + "checkHeader":true, + "headerRowIdx":0, + "attrName": "remark", + "dataType": "String" + }, + { + "columnHeader":"Approver", + "checkHeader":false, + "headerRowIdx":0 + }, + { + "columnHeader":"Approver ID", + "checkHeader":true, + "headerRowIdx":0, + "attrName": "approverId", + "dataType": "String" + }, + { + "columnHeader":"Approval Remark", + "checkHeader":false, + "headerRowIdx":0 + }, + { + "columnHeader":"Booking Type", + "checkHeader":true, + "headerRowIdx":0, + "attrName": "bookingTypeName", + "dataType": "String" + }, + { + "columnHeader":"Segment", + "checkHeader":true, + "headerRowIdx":0, + "attrName": "segmentName", + "dataType": "String" + }, + { + "columnHeader":"ETA Time", + "checkHeader":false, + "headerRowIdx":0 + }, + { + "columnHeader":"Create Date/Time", + "checkHeader":false, + "headerRowIdx":0 + } + ] + }] + }] +}